changeset 22280:26109cce022e

New string utility functions to replace caseless_str for liboctave (bug #48726) * oct-string.h, oct-string.cc: new files that implement strcmp, strcmpi, strncmp, and strncmpi functions in the new octave::string namespace. This functions behave like the ones available in the Octave interpreter. * libinterp/corefcn/strfns.cc: make use of the new functions in liboctave. * libgui/graphics/QtHandlesUtils.cc, libgui/graphics/QtHandlesUtils.h, libinterp/corefcn/cellfun.cc, libinterp/dldfcn/chol.cc: make use of the new functions instead of caseless_str. * liboctave/util/module.mk: add new files to build system.
author Carnë Draug <carandraug@octave.org>
date Sat, 13 Aug 2016 15:35:58 +0100
parents 3bb1dc8b723e
children 0f9ab4f1f4b3
files libgui/graphics/QtHandlesUtils.cc libgui/graphics/QtHandlesUtils.h libinterp/corefcn/cellfun.cc libinterp/corefcn/strfns.cc libinterp/dldfcn/chol.cc liboctave/util/module.mk liboctave/util/oct-string.cc liboctave/util/oct-string.h
diffstat 8 files changed, 377 insertions(+), 112 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/graphics/QtHandlesUtils.cc	Sat Aug 13 12:49:58 2016 +0100
+++ b/libgui/graphics/QtHandlesUtils.cc	Sat Aug 13 15:35:58 2016 +0100
@@ -39,6 +39,8 @@
 #include "Object.h"
 #include "QtHandlesUtils.h"
 
+#include "oct-string.h"
+
 namespace QtHandles
 {
 
@@ -249,24 +251,24 @@
 }
 
 Qt::Alignment
-fromHVAlign (const caseless_str& halign, const caseless_str& valign)
+fromHVAlign (const std::string& halign, const std::string& valign)
 {
   Qt::Alignment flags;
 
-  if (halign.compare ("left"))
+  if (octave::string::strcmpi (halign, "left"))
     flags |= Qt::AlignLeft;
-  else if (halign.compare ("center"))
+  else if (octave::string::strcmpi (halign, "center"))
     flags |= Qt::AlignHCenter;
-  else if (halign.compare ("right"))
+  else if (octave::string::strcmpi (halign, "right"))
     flags |= Qt::AlignRight;
   else
     flags |= Qt::AlignLeft;
 
-  if (valign.compare ("middle"))
+  if (octave::string::strcmpi (valign, "middle"))
     flags |= Qt::AlignVCenter;
-  else if (valign.compare ("top"))
+  else if (octave::string::strcmpi (valign, "top"))
     flags |= Qt::AlignTop;
-  else if (valign.compare ("bottom"))
+  else if (octave::string::strcmpi (valign, "bottom"))
     flags |= Qt::AlignBottom;
   else
     flags |= Qt::AlignVCenter;
--- a/libgui/graphics/QtHandlesUtils.h	Sat Aug 13 12:49:58 2016 +0100
+++ b/libgui/graphics/QtHandlesUtils.h	Sat Aug 13 15:35:58 2016 +0100
@@ -55,8 +55,8 @@
   QColor fromRgb (const Matrix& rgb);
   Matrix toRgb (const QColor& c);
 
-  Qt::Alignment fromHVAlign (const caseless_str& halign,
-                             const caseless_str& valign);
+  Qt::Alignment fromHVAlign (const std::string& halign,
+                             const std::string& valign);
 
   std::string figureSelectionType (QMouseEvent* event,
                                    bool isDoubleClick = false);
--- a/libinterp/corefcn/cellfun.cc	Sat Aug 13 12:49:58 2016 +0100
+++ b/libinterp/corefcn/cellfun.cc	Sat Aug 13 15:35:58 2016 +0100
@@ -32,9 +32,9 @@
 #include <list>
 #include <memory>
 
-#include "caseless-str.h"
 #include "lo-mappers.h"
 #include "oct-locbuf.h"
+#include "oct-string.h"
 
 #include "Cell.h"
 #include "oct-map.h"
@@ -224,13 +224,13 @@
 {
   while (nargin > 3 && args(nargin-2).is_string ())
     {
-      caseless_str arg = args(nargin-2).string_value ();
+      std::string arg = args(nargin-2).string_value ();
 
       size_t compare_len = std::max (arg.length (), static_cast<size_t> (2));
 
-      if (arg.compare ("uniformoutput", compare_len))
+      if (octave::string::strncmpi (arg, "uniformoutput", compare_len))
         uniform_output = args(nargin-1).bool_value ();
-      else if (arg.compare ("errorhandler", compare_len))
+      else if (octave::string::strncmpi (arg, "errorhandler", compare_len))
         {
           if (args(nargin-1).is_function_handle ()
               || args(nargin-1).is_inline_function ())
--- a/libinterp/corefcn/strfns.cc	Sat Aug 13 12:49:58 2016 +0100
+++ b/libinterp/corefcn/strfns.cc	Sat Aug 13 15:35:58 2016 +0100
@@ -40,6 +40,8 @@
 #include "unwind-prot.h"
 #include "utils.h"
 
+#include "oct-string.h"
+
 DEFUN (char, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {} char (@var{x})
@@ -311,10 +313,10 @@
 static octave_value
 do_strcmp_fun (const octave_value& arg0, const octave_value& arg1,
                octave_idx_type n, const char *fcn_name,
-               bool (*array_op) (const charNDArray&, const charNDArray&,
+               bool (*array_op) (const Array<char>&, const Array<char>&,
                                  octave_idx_type),
                bool (*str_op) (const std::string&, const std::string&,
-                               octave_idx_type))
+                               std::string::size_type))
 
 {
   octave_value retval;
@@ -514,21 +516,20 @@
   return retval;
 }
 
-// If both args are arrays, dimensions may be significant.
-static bool
-strcmp_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type)
-{
-  return (s1.dims () == s2.dims ()
-          && std::equal (s1.data (), s1.data () + s1.numel (), s2.data ()));
-}
+
+// These are required so that they match the same signature as strncmp
+// and strncmpi and can therefore be used in do_strcmp_fun.
 
-// Otherwise, just use strings.
+template <typename T, typename T_size_type>
 static bool
-strcmp_str_op (const std::string& s1, const std::string& s2,
-               octave_idx_type)
-{
-  return s1 == s2;
-}
+strcmp_ignore_n (const T& s1, const T& s2, T_size_type)
+{ return octave::string::strcmp (s1, s2); }
+
+template <typename T, typename T_size_type>
+static bool
+strcmpi_ignore_n (const T& s1, const T& s2, T_size_type)
+{ return octave::string::strcmpi (s1, s2); }
+
 
 DEFUN (strcmp, args, ,
        doc: /* -*- texinfo -*-
@@ -552,7 +553,7 @@
     print_usage ();
 
   return ovl (do_strcmp_fun (args(0), args(1), 0, "strcmp",
-                             strcmp_array_op, strcmp_str_op));
+                             strcmp_ignore_n, strcmp_ignore_n));
 }
 
 /*
@@ -603,29 +604,6 @@
 %!error strcmp ("foo", "bar", 3)
 */
 
-// Apparently, Matlab ignores the dims with strncmp.
-static bool
-strncmp_array_op (const charNDArray& s1, const charNDArray& s2,
-                  octave_idx_type n)
-{
-  octave_idx_type l1 = s1.numel ();
-  octave_idx_type l2 = s2.numel ();
-  return (n > 0 && n <= l1 && n <= l2
-          && std::equal (s1.data (), s1.data () + n, s2.data ()));
-}
-
-// Otherwise, just use strings.  Note that we neither extract substrings (which
-// would mean a copy, at least in GCC), nor use string::compare (which is a
-// 3-way compare).
-static bool
-strncmp_str_op (const std::string& s1, const std::string& s2, octave_idx_type n)
-{
-  octave_idx_type l1 = s1.length ();
-  octave_idx_type l2 = s2.length ();
-  return (n > 0 && n <= l1 && n <= l2
-          && std::equal (s1.data (), s1.data () + n, s2.data ()));
-}
-
 DEFUN (strncmp, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} strncmp (@var{s1}, @var{s2}, @var{n})
@@ -665,7 +643,8 @@
 
   if (n > 0)
     return ovl (do_strcmp_fun (args(0), args(1), n, "strncmp",
-                               strncmp_array_op, strncmp_str_op));
+                               octave::string::strncmp,
+                               octave::string::strncmp));
   else
     error ("strncmp: N must be greater than 0");
 }
@@ -683,34 +662,6 @@
 %!error strncmp ("abc", "def")
 */
 
-// case-insensitive character equality functor
-struct icmp_char_eq : public std::binary_function<char, char, bool>
-{
-  bool operator () (char x, char y) const
-  {
-    return std::toupper (x) == std::toupper (y);
-  }
-};
-
-// strcmpi is equivalent to strcmp in that it checks all dims.
-static bool
-strcmpi_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type)
-{
-  return (s1.dims () == s2.dims ()
-          && std::equal (s1.data (), s1.data () + s1.numel (), s2.data (),
-                         icmp_char_eq ()));
-}
-
-// Ditto for string.
-static bool
-strcmpi_str_op (const std::string& s1, const std::string& s2,
-                octave_idx_type)
-{
-  return (s1.size () == s2.size ()
-          && std::equal (s1.data (), s1.data () + s1.size (), s2.data (),
-                         icmp_char_eq ()));
-}
-
 DEFUNX ("strcmpi", Fstrcmpi, args, ,
         doc: /* -*- texinfo -*-
 @deftypefn {} {} strcmpi (@var{s1}, @var{s2})
@@ -735,37 +686,13 @@
     print_usage ();
 
   return ovl (do_strcmp_fun (args(0), args(1), 0, "strcmpi",
-                             strcmpi_array_op, strcmpi_str_op));
+                             strcmpi_ignore_n, strcmpi_ignore_n));
 }
 
 /*
 %!assert (strcmpi ("abc123", "ABC123"), true)
 */
 
-// Like strncmp.
-static bool
-strncmpi_array_op (const charNDArray& s1, const charNDArray& s2,
-                   octave_idx_type n)
-{
-  octave_idx_type l1 = s1.numel ();
-  octave_idx_type l2 = s2.numel ();
-  return (n > 0 && n <= l1 && n <= l2
-          && std::equal (s1.data (), s1.data () + n, s2.data (),
-                         icmp_char_eq ()));
-}
-
-// Ditto.
-static bool
-strncmpi_str_op (const std::string& s1, const std::string& s2,
-                 octave_idx_type n)
-{
-  octave_idx_type l1 = s1.length ();
-  octave_idx_type l2 = s2.length ();
-  return (n > 0 && n <= l1 && n <= l2
-          && std::equal (s1.data (), s1.data () + n, s2.data (),
-                         icmp_char_eq ()));
-}
-
 DEFUNX ("strncmpi", Fstrncmpi, args, ,
         doc: /* -*- texinfo -*-
 @deftypefn {} {} strncmpi (@var{s1}, @var{s2}, @var{n})
@@ -793,7 +720,8 @@
 
   if (n > 0)
     return ovl (do_strcmp_fun (args(0), args(1), n, "strncmpi",
-                               strncmpi_array_op, strncmpi_str_op));
+                               octave::string::strncmpi,
+                               octave::string::strncmpi));
   else
     error ("strncmpi: N must be greater than 0");
 }
--- a/libinterp/dldfcn/chol.cc	Sat Aug 13 12:49:58 2016 +0100
+++ b/libinterp/dldfcn/chol.cc	Sat Aug 13 15:35:58 2016 +0100
@@ -33,7 +33,6 @@
 #include "oct-spparms.h"
 #include "sparse-util.h"
 
-#include "caseless-str.h"
 #include "ov-re-sparse.h"
 #include "ov-cx-sparse.h"
 #include "defun-dld.h"
@@ -42,6 +41,8 @@
 #include "ovl.h"
 #include "utils.h"
 
+#include "oct-string.h"
+
 template <typename CHOLT>
 static octave_value
 get_chol (const CHOLT& fact)
@@ -163,13 +164,13 @@
   int n = 1;
   while (n < nargin)
     {
-      caseless_str tmp = args(n++).xstring_value ("chol: optional arguments must be strings");
+      std::string tmp = args(n++).xstring_value ("chol: optional arguments must be strings");
 
-      if (tmp.compare ("vector"))
+      if (octave::string::strcmpi (tmp, "vector"))
         vecout = true;
-      else if (tmp.compare ("lower"))
+      else if (octave::string::strcmpi (tmp, "lower"))
         LLt = true;
-      else if (tmp.compare ("upper"))
+      else if (octave::string::strcmpi (tmp, "upper"))
         LLt = false;
       else
         error ("chol: optional argument must be one of \"vector\", \"lower\", or \"upper\"");
--- a/liboctave/util/module.mk	Sat Aug 13 12:49:58 2016 +0100
+++ b/liboctave/util/module.mk	Sat Aug 13 15:35:58 2016 +0100
@@ -29,6 +29,7 @@
   liboctave/util/oct-refcount.h \
   liboctave/util/oct-rl-edit.h \
   liboctave/util/oct-rl-hist.h \
+  liboctave/util/oct-string.h \
   liboctave/util/oct-shlib.h \
   liboctave/util/oct-sort.h \
   liboctave/util/pathsearch.h \
@@ -67,6 +68,7 @@
   liboctave/util/oct-inttypes.cc \
   liboctave/util/oct-locbuf.cc \
   liboctave/util/oct-mutex.cc \
+  liboctave/util/oct-string.cc \
   liboctave/util/oct-shlib.cc \
   liboctave/util/pathsearch.cc \
   liboctave/util/lo-regexp.cc \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/util/oct-string.cc	Sat Aug 13 15:35:58 2016 +0100
@@ -0,0 +1,206 @@
+/*
+Copyright (C) 2016 Carnë Draug
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "oct-string.h"
+
+#include <cctype>
+#include <cstring>
+
+#include <string>
+
+#include <Array.h>
+
+template <typename T>
+static bool
+str_data_cmp (const typename T::value_type* a, const typename T::value_type* b,
+              const typename T::size_type n)
+{
+  for (typename T::size_type i = 0; i < n; ++i)
+    if (a[i] != b[i])
+      return false;
+  return true;
+}
+
+template <typename T>
+static bool
+str_data_cmpi (const typename T::value_type* a, const typename T::value_type* b,
+               const typename T::size_type n)
+{
+  for (typename T::size_type i = 0; i < n; ++i)
+    if (std::tolower (a[i]) != std::tolower (b[i]))
+      return false;
+  return true;
+}
+
+
+// Templates to handle std::basic_string, std::vector, Array, and char*.
+template <typename T>
+typename T::size_type
+numel (const T& str)
+{
+  return str.size ();
+}
+
+template <>
+octave_idx_type
+numel (const Array<char>& str)
+{
+  return str.numel ();
+}
+
+template <typename T>
+typename T::size_type
+strlen (const typename T::value_type* str)
+{
+  return std::strlen (str);
+}
+
+template <typename T>
+bool
+sizes_cmp (const T& str_a, const T& str_b)
+{
+  return str_a.size () == str_b.size ();
+}
+
+template <>
+bool
+sizes_cmp (const Array<char>& str_a, const Array<char>& str_b)
+{
+  return str_a.dims () == str_b.dims ();
+}
+
+template <typename T>
+bool
+sizes_cmp (const T& str_a, const typename T::value_type* str_b)
+{
+  return str_a.size () == strlen<T> (str_b);
+}
+
+template <>
+bool
+sizes_cmp (const Array<char>& str_a, const char* str_b)
+{
+  return (str_a.is_vector () && str_a.rows () == 1
+          && str_a.numel () == strlen<Array<char>> (str_b));
+}
+
+
+template<typename T>
+bool
+octave::string::strcmp (const T& str_a, const T& str_b)
+{
+  return (sizes_cmp (str_a, str_b)
+          && str_data_cmp<T> (str_a.data (), str_b.data (), numel (str_a)));
+}
+
+template<typename T>
+bool
+octave::string::strcmp (const T& str_a, const typename T::value_type* str_b)
+{
+  return (sizes_cmp (str_a, str_b)
+          && str_data_cmp<T> (str_a.data (), str_b, numel (str_a)));
+}
+
+
+template<typename T>
+bool
+octave::string::strcmpi (const T& str_a, const T& str_b)
+{
+  return (sizes_cmp (str_a, str_b)
+          && str_data_cmpi<T> (str_a.data (), str_b.data (), numel (str_a)));
+}
+
+template<typename T>
+bool
+octave::string::strcmpi (const T& str_a, const typename T::value_type* str_b)
+{
+  return (sizes_cmp (str_a, str_b)
+          && str_data_cmpi<T> (str_a.data (), str_b, numel (str_a)));
+}
+
+
+template<typename T>
+bool
+octave::string::strncmp (const T& str_a, const T& str_b,
+                         const typename T::size_type n)
+{
+  return (numel (str_a) >= n && numel (str_b) >= n
+          && str_data_cmpi<T> (str_a.data (), str_b.data (), n));
+}
+
+template<typename T>
+bool
+octave::string::strncmp (const T& str_a, const typename T::value_type* str_b,
+                         const typename T::size_type n)
+{
+  return (numel (str_a) >= n && strlen<T> (str_b) >= n
+          && str_data_cmpi<T> (str_a.data (), str_b, n));
+}
+
+
+template<typename T>
+bool
+octave::string::strncmpi (const T& str_a, const T& str_b,
+                          const typename T::size_type n)
+{
+  return (numel (str_a) >= n && numel (str_b) >= n
+          && str_data_cmpi<T> (str_a.data (), str_b.data (), n));
+}
+
+template<typename T>
+bool
+octave::string::strncmpi (const T& str_a, const typename T::value_type* str_b,
+                          const typename T::size_type n)
+{
+  return (numel (str_a) >= n && strlen<T> (str_b) >= n
+          && str_data_cmpi<T> (str_a.data (), str_b, n));
+}
+
+
+// Instantiations we need
+#define INSTANTIATE_OCTAVE_STRING(T)                                          \
+  template bool octave::string::strcmp<T> (const T&, const T&);               \
+  template bool octave::string::strcmp<T> (const T&,                          \
+                                           const typename T::value_type*);    \
+  template bool octave::string::strcmpi<T> (const T&, const T&);              \
+  template bool octave::string::strcmpi<T> (const T&,                         \
+                                            const typename T::value_type*);   \
+  template bool octave::string::strncmp<T> (const T&, const T&,               \
+                                            const typename T::size_type);     \
+  template bool octave::string::strncmp<T> (const T&,                         \
+                                            const typename T::value_type*,    \
+                                            const typename T::size_type);     \
+  template bool octave::string::strncmpi<T> (const T&, const T&,              \
+                                             const typename T::size_type n);  \
+  template bool octave::string::strncmpi<T> (const T&,                        \
+                                             const typename T::value_type*,   \
+                                             const typename T::size_type);
+
+// We could also instantiate std::vector<char> but would it be
+// useful for anyone?
+INSTANTIATE_OCTAVE_STRING(std::string)
+INSTANTIATE_OCTAVE_STRING(Array<char>)
+
+#undef INSTANTIATE_OCTAVE_STRING
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/util/oct-string.h	Sat Aug 13 15:35:58 2016 +0100
@@ -0,0 +1,126 @@
+/*
+Copyright (C) 2016 Carnë Draug
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if ! defined (octave_oct_string_h)
+#define octave_oct_string_h 1
+
+#include "octave-config.h"
+
+namespace octave
+{
+  //! Octave string utility functions.
+  /*!
+      This functions provide a C++ interface to most string functions
+      available in the Octave interpreter.
+
+      Specializations for Array may consider its dimensions in addition
+      to the actual string contents.
+
+      @attention
+      Octave's string comparison functions return true when strings are
+      are equal, just the opposite of the corresponding C library functions.
+      In addition, Octave's function only return bool and do not check
+      lexicographical order.
+  */
+  namespace string
+  {
+    //! True if strings are the same.
+    /*!
+        ## Specialization for Array<char>
+
+        When comparing whole Array of chars, the actual Array dimensions
+        are significant.  A column vector and row vector with the same
+        char array, will still return false.
+    */
+    template <typename T>
+    bool strcmp (const T& str_a, const T& str_b);
+
+    //! True if string is the same as character sequence.
+    /*!
+        Compares a string to the null-terminated character sequence
+        beginning at the character pointed to by str_b.
+
+        ## Specialization for Array<char>
+
+        For purposes of comparison of dimensions, the character sequence
+        is considered to be a row vector.
+    */
+    template <typename T>
+    bool strcmp (const T& str_a, const typename T::value_type* str_b);
+
+    //! True if strings are the same, ignoring case.
+    /*!
+        ## Specialization for Array<char>
+
+        When comparing whole Array of chars, the actual Array dimensions
+        are significant.  A column vector and row vector with the same
+        char array, will still return false.
+    */
+    template <typename T>
+    bool strcmpi (const T& str_a, const T& str_b);
+
+    //! True if string is the same as character sequence, ignoring case.
+    /*!
+        ## Specialization for Array<char>
+
+        For purposes of comparison of dimensions, the character sequence
+        is considered to be a row vector.
+    */
+    template <typename T>
+    bool strcmpi (const T& str_a, const typename T::value_type* str_b);
+
+    //! True if the first N characters are the same.
+    /*!
+        ## Specialization for Array<char>
+
+        The comparison is done in the first N characters, the actual
+        dimensions of the Array are irrelevant.  A row vector and
+        a column vector of the same still return true.
+    */
+    template <typename T>
+    bool strncmp (const T& str_a, const T& str_b,
+                  const typename T::size_type n);
+
+    //! True if the first N characters are the same.
+    template <typename T>
+    bool strncmp (const T& str_a, const typename T::value_type* str_b,
+                   const typename T::size_type n);
+
+    //! True if the first N characters are the same, ignoring case.
+    /*!
+        ## Specialization for Array<char>
+
+        The comparison is done in the first N characters, the actual
+        dimensions of the Array are irrelevant.  A row vector and
+        a column vector of the same still return true.
+    */
+    template <typename T>
+    bool strncmpi (const T& str_a, const T& str_b,
+                   const typename T::size_type n);
+
+    //! True if the first N characters are the same, ignoring case.
+    template <typename T>
+    bool strncmpi (const T& str_a, const typename T::value_type* str_b,
+                   const typename T::size_type n);
+  }
+}
+
+#endif