Mercurial > octave
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