26#if defined (HAVE_CONFIG_H)
35#if defined (OCTAVE_HAVE_STD_FROM_CHARS_DOUBLE)
40#include <unordered_set>
42#if defined (OCTAVE_HAVE_FAST_FLOAT)
43# include <fast_float/fast_float.h>
57str_data_cmp (
const typename T::value_type *a,
const typename T::value_type *b,
58 const typename T::size_type n)
60 for (
typename T::size_type i = 0; i < n; ++i)
68str_data_cmpi (
const typename T::value_type *a,
const typename T::value_type *b,
69 const typename T::size_type n)
71 for (
typename T::size_type i = 0; i < n; ++i)
72 if (std::tolower (a[i]) != std::tolower (b[i]))
95strlen (
const typename T::value_type *str)
97 return std::strlen (str);
104 return str_a.size () == str_b.size ();
111 return str_a.
dims () == str_b.
dims ();
116sizes_cmp (
const T& str_a,
const typename T::value_type *str_b)
118 return str_a.size () == strlen<T> (str_b);
132octave::string::strcmp (
const T& str_a,
const T& str_b)
135 && str_data_cmp<T> (str_a.data (), str_b.data (),
numel (str_a)));
140octave::string::strcmp (
const T& str_a,
const typename T::value_type *str_b)
143 && str_data_cmp<T> (str_a.data (), str_b,
numel (str_a)));
149octave::string::strcmpi (
const T& str_a,
const T& str_b)
152 && str_data_cmpi<T> (str_a.data (), str_b.data (),
numel (str_a)));
157octave::string::strcmpi (
const T& str_a,
const typename T::value_type *str_b)
160 && str_data_cmpi<T> (str_a.data (), str_b,
numel (str_a)));
166octave::string::strncmp (
const T& str_a,
const T& str_b,
167 const typename T::size_type n)
169 typename T::size_type neff;
170 auto len_a =
numel (str_a);
171 auto len_b =
numel (str_b);
172 neff = std::min (std::max (len_a, len_b), n);
174 return (len_a >= neff && len_b >= neff
175 && str_data_cmp<T> (str_a.data (), str_b.data (), neff));
180octave::string::strncmp (
const T& str_a,
const typename T::value_type *str_b,
181 const typename T::size_type n)
183 typename T::size_type neff;
184 auto len_a =
numel (str_a);
185 auto len_b = strlen<T> (str_b);
186 neff = std::min (std::max (len_a, len_b), n);
188 return (len_a >= neff && len_b >= neff
189 && str_data_cmp<T> (str_a.data (), str_b, neff));
195octave::string::strncmpi (
const T& str_a,
const T& str_b,
196 const typename T::size_type n)
198 typename T::size_type neff;
199 auto len_a =
numel (str_a);
200 auto len_b =
numel (str_b);
201 neff = std::min (std::max (len_a, len_b), n);
203 return (len_a >= neff && len_b >= neff
204 && str_data_cmpi<T> (str_a.data (), str_b.data (), neff));
209octave::string::strncmpi (
const T& str_a,
const typename T::value_type *str_b,
210 const typename T::size_type n)
212 typename T::size_type neff;
213 auto len_a =
numel (str_a);
214 auto len_b = strlen<T> (str_b);
215 neff = std::min (std::max (len_a, len_b), n);
217 return (len_a >= neff && len_b >= neff
218 && str_data_cmpi<T> (str_a.data (), str_b, neff));
223#define INSTANTIATE_OCTAVE_STRING(T, API) \
224 template API bool octave::string::strcmp<T> (const T&, const T&); \
226 octave::string::strcmp<T> (const T&, const typename T::value_type*); \
227 template API bool octave::string::strcmpi<T> (const T&, const T&); \
229 octave::string::strcmpi<T> (const T&, const typename T::value_type*); \
231 octave::string::strncmp<T> (const T&, const T&, \
232 const typename T::size_type); \
234 octave::string::strncmp<T> (const T&, const typename T::value_type*, \
235 const typename T::size_type); \
237 octave::string::strncmpi<T> (const T&, const T&, \
238 const typename T::size_type n); \
240 octave::string::strncmpi<T> (const T&, const typename T::value_type*, \
241 const typename T::size_type);
248#undef INSTANTIATE_OCTAVE_STRING
252{
return c ==
'i' || c ==
'j'; }
255single_num (std::istringstream& is)
261 std::streampos start_pos = is.tellg ();
262 std::getline (is, str);
264 const char *first = str.data ();
265 const char *last = first + str.size ();
268 while (first != last && std::isspace (
static_cast<unsigned char> (*first)))
273 is.seekg (start_pos);
274 is.setstate (std::ios::failbit);
279 if (first + 2 <= last && first[0] ==
'N' && first[1] ==
'A' &&
280 (first + 2 == last || std::isspace (
static_cast<unsigned char> (first[2]))))
283 is.seekg (start_pos +
static_cast<std::streamoff
> (first - str.data () + 2));
288#if defined (OCTAVE_HAVE_STD_FROM_CHARS_DOUBLE)
289 auto [ptr, ec] = std::from_chars (first, last, num);
290#elif defined (OCTAVE_HAVE_FAST_FLOAT)
291 auto [ptr, ec] = fast_float::from_chars (first, last, num);
293# error "Cannot convert string to floating-point number. This should be unreachable."
296 if (ec == std::errc {})
299 std::streamoff chars_consumed =
static_cast<std::streamoff
> (ptr - str.data ());
300 is.seekg (start_pos + chars_consumed);
304 is.seekg (0, std::ios::end);
311 case std::errc::invalid_argument:
313 is.seekg (start_pos);
314 is.setstate (std::ios::failbit);
316 case std::errc::result_out_of_range:
321 const char* p = first;
322 while (p < ptr && std::isspace (
static_cast<unsigned char> (*p)))
325 if (p < ptr && *p ==
'-')
326 num = -octave::numeric_limits<double>::Inf ();
328 num = octave::numeric_limits<double>::Inf ();
330 std::streamoff chars_consumed =
static_cast<std::streamoff
> (ptr - str.data ());
331 is.seekg (start_pos + chars_consumed);
337 is.seekg (start_pos);
338 is.setstate (std::ios::failbit);
345static std::istringstream&
346extract_num (std::istringstream& is,
double& num,
bool&
imag,
bool& have_sign)
348 have_sign =
imag =
false;
359 bool negative =
false;
362 if (c ==
'+' || c ==
'-')
388 num = (negative ? -1.0 : 1.0);
393 if (std::tolower (c) !=
'n')
417 num = single_num (is);
427 num = single_num (is);
451 if (is_imag_unit (c))
458 is.setstate (std::ios::failbit);
460 else if (is_imag_unit (c))
488#if defined (HAVE_CXX_COMPLEX_SETTERS)
493#elif defined (HAVE_CXX_COMPLEX_REFERENCE_ACCESSORS)
507octave::string::str2double (
const std::string& str_arg)
511 std::string str = str_arg;
515 str.erase (std::remove (str.begin (), str.end(),
','), str.end ());
516 std::istringstream is (str);
522 val = octave::numeric_limits<double>::NaN ();
523 else if (! extract_num (is, num, i1, s1))
524 val = octave::numeric_limits<double>::NaN ();
527 set_component (val, num, i1);
531 if (! extract_num (is, num, i2, s2) || i1 == i2 || ! s2)
532 val = octave::numeric_limits<double>::NaN ();
534 set_component (val, num, i2);
542octave::string::any_non_ascii_chars (
const std::string &s)
544 for (
unsigned char c : s)
552octave::string::u8_to_encoding (
const std::string& who,
553 const std::string& u8_string,
554 const std::string& encoding)
556 const uint8_t *src =
reinterpret_cast<const uint8_t *
>
557 (u8_string.c_str ());
558 std::size_t srclen = u8_string.length ();
567 (*current_liboctave_error_handler)
568 (
"%s: iconv() is not supported. Installing GNU libiconv and then "
569 "re-compiling Octave could fix this.", who.c_str ());
572 (
"%s: converting from UTF-8 to codepage '%s' failed: %s",
573 who.c_str (), encoding.c_str (), std::strerror (errno));
576 octave::unwind_action free_native_str ([native_str] () {
::free (native_str); });
578 std::string retval = std::string (native_str, length);
584octave::string::u8_from_encoding (
const std::string& who,
585 const std::string& native_string,
586 const std::string& encoding)
588 const char *src = native_string.c_str ();
589 std::size_t srclen = native_string.length ();
597 (*current_liboctave_error_handler)
598 (
"%s: iconv() is not supported. Installing GNU libiconv and then "
599 "re-compiling Octave could fix this.", who.c_str ());
602 (
"%s: converting from codepage '%s' to UTF-8 failed: %s",
603 who.c_str (), encoding.c_str (), std::strerror (errno));
606 octave::unwind_action free_utf8_str ([utf8_str] () {
::free (utf8_str); });
608 std::string retval = std::string (
reinterpret_cast<char *
> (utf8_str), length);
614octave::string::u8_validate (
const std::string& who,
616 const octave::string::u8_fallback_type type)
620 unsigned int num_replacements = 0;
621 const char *in_chr = in_str.c_str ();
622 const char *inv_utf8 = in_chr;
623 const char *
const in_end = in_chr + in_str.length ();
624 while (inv_utf8 && in_chr < in_end)
626 inv_utf8 =
reinterpret_cast<const char *
>
630 if (inv_utf8 ==
nullptr)
631 out_str.append (in_chr, in_end - in_chr);
635 out_str.append (in_chr, inv_utf8 - in_chr);
636 in_chr = inv_utf8 + 1;
639 out_str.append (
"\xef\xbf\xbd");
642 std::string fallback =
"iso-8859-1";
645 (fallback.c_str (), inv_utf8, 1, &lengthp);
648 (*current_liboctave_error_handler)
649 (
"%s: converting from codepage '%s' to UTF-8 failed: %s",
650 who.c_str (), fallback.c_str (), std::strerror (errno));
652 octave::unwind_action free_val_utf8 ([val_utf8] () {
::free (val_utf8); });
654 out_str.append (
reinterpret_cast<const char *
> (val_utf8),
661 return num_replacements;
665octave::string::u16_to_encoding (
const std::string& who,
666 const std::u16string& u16_string,
667 const std::string& encoding)
669 const uint16_t *src =
reinterpret_cast<const uint16_t *
>
670 (u16_string.c_str ());
671 std::size_t srclen = u16_string.length ();
680 (*current_liboctave_error_handler)
681 (
"%s: iconv() is not supported. Installing GNU libiconv and then "
682 "re-compiling Octave could fix this.", who.c_str ());
685 (
"%s: converting from UTF-16 to codepage '%s' failed: %s",
686 who.c_str (), encoding.c_str (), std::strerror (errno));
689 octave::unwind_action free_native_str ([native_str] () {
::free (native_str); });
691 std::string retval = std::string (native_str, length);
696std::vector<std::string>
697octave::string::get_encoding_list ()
699 static std::vector<std::string> encoding_list;
701 if (encoding_list.empty ())
703#if defined (HAVE_ICONVLIST)
705 std::size_t count = 0;
707 [] (
unsigned int num,
const char *
const *,
void *data) ->
int
709 std::size_t *count_ptr =
static_cast<std::size_t *
> (data);
715 if (count ==
static_cast<size_t> (-1))
717 encoding_list.push_back (
"UTF-8");
718 return encoding_list;
721# if defined (HAVE_ICONV_CANONICALIZE)
723 std::unordered_set<std::string> encoding_set;
724 encoding_set.reserve (count);
728 [] (
unsigned int num,
const char *
const *names,
void *data) ->
int
730 std::unordered_set<std::string> *encoding_set_ptr
731 =
static_cast<std::unordered_set<std::string> *
> (data);
732 for (std::size_t i = 0; i < num; i++)
734 const char *canonicalized_enc
736 encoding_set_ptr->insert (canonicalized_enc);
742 encoding_list.assign (encoding_set.begin (), encoding_set.end ());
826 std::sort (encoding_list.begin (), encoding_list.end ());
829 return encoding_list;
832typedef octave::string::codecvt_u8::InternT
InternT;
833typedef octave::string::codecvt_u8::ExternT
ExternT;
834typedef octave::string::codecvt_u8::StateT
StateT;
836typename std::codecvt<InternT, ExternT, StateT>::result
837octave::string::codecvt_u8::do_out
843 if (from_end <= from)
845 from_next = from_end;
846 return std::codecvt<InternT, ExternT, StateT>::noconv;
853 std::size_t pop_end = 0;
854 if ((*(from_end-1) & 0b10000000) == 0b10000000)
859 std::size_t num_bytes_in_buf = 1;
861 while (((*(from_end-num_bytes_in_buf) & 0b11000000) != 0b11000000)
862 && (num_bytes_in_buf < 4)
863 && (from_end-num_bytes_in_buf > from))
870 if ((((*(from_end-num_bytes_in_buf) & 0b11100000) == 0b11000000)
871 && (num_bytes_in_buf < 2))
872 || (((*(from_end-num_bytes_in_buf) & 0b11110000) == 0b11100000)
873 && (num_bytes_in_buf < 3))
874 || (((*(from_end-num_bytes_in_buf) & 0b11111000) == 0b11110000)
875 && (num_bytes_in_buf < 4)))
876 pop_end = num_bytes_in_buf;
878 from_next = from_end - pop_end;
880 std::size_t srclen = (from_end-from-pop_end) *
sizeof (
InternT);
881 std::size_t length = (to_end-to) *
sizeof (
ExternT);
882 if (srclen < 1 || length < 1)
883 return std::codecvt<InternT, ExternT, StateT>::partial;
886 const uint8_t *u8_str =
reinterpret_cast<const uint8_t *
> (from);
891 return std::codecvt<InternT, ExternT, StateT>::partial;
893 size_t max = (to_end - to) *
sizeof (
ExternT);
902 std::copy_n (enc_str,
max, to);
905 from_next = from + srclen;
908 return ((pop_end > 0 ||
max < length)
909 ? std::codecvt<InternT, ExternT, StateT>::partial
910 : std::codecvt<InternT, ExternT, StateT>::ok);
913typename std::codecvt<InternT, ExternT, StateT>::result
914octave::string::codecvt_u8::do_in
920 std::size_t srclen = (from_end-from) *
sizeof (
ExternT);
921 std::size_t lengthp = (to_end-to) *
sizeof (
InternT);
922 const char *enc_str =
reinterpret_cast<const char *
> (from);
924 enc_str, srclen, &lengthp);
926 std::size_t
max = to_end - to;
931 std::copy_n (u8_str,
max, to);
934 from_next = from + srclen;
937 return std::codecvt<InternT, ExternT, StateT>::ok;
940int octave::string::codecvt_u8::do_length
942 std::size_t
max)
const
945 std::size_t srclen = end-src;
947 std::size_t lengthp =
max;
950 std::size_t ext_char;
951 for (ext_char = 0; ext_char < srclen; ext_char++)
953 if (offsets[ext_char] !=
static_cast<size_t> (-1)
954 && offsets[ext_char] >=
max)
971 static constexpr T out_of_range_top
972 =
static_cast<T
> (std::numeric_limits<int>::max ()) + 1.0;
973 static constexpr T out_of_range_bottom
974 =
static_cast<T
> (std::numeric_limits<int>::min ()) - 1.0;
976 if (octave::math::isinf (val))
983 else if (octave::math::isnan (val))
985 else if (val <= out_of_range_bottom || val >= out_of_range_top
986 || octave::math::is_integer (val))
988 std::ostringstream buf;
989 buf.flags (std::ios::fixed);
990 buf << std::setprecision (0) << octave::math::round (val);
997 T n = octave::math::round (val);
1001 std::ostringstream init_buf;
1002 init_buf.flags (std::ios::fixed);
1003 init_buf << std::setprecision (0) << static_cast<int> (n);
1004 s = init_buf.str ();
1009 T step = octave::math::round (flip);
1014 if (std::abs (flip) > out_of_range_top)
1022 n = step * n + lastn;
1023 d = step *
d + lastd;
1027 if (std::abs (n) >= out_of_range_top
1028 || std::abs (
d) >= out_of_range_top)
1031 std::ostringstream buf;
1032 buf.flags (std::ios::fixed);
1033 buf << std::setprecision (0) << static_cast<int> (n)
1034 <<
'/' <<
static_cast<int> (
d);
1039 if (buf.str ().length () >
static_cast<unsigned int> (
len + 2))
1044 if (buf.str ().length () >
static_cast<unsigned int> (
len))
1056 std::ostringstream buf;
1057 buf.flags (std::ios::fixed);
1058 buf << std::setprecision (0) << static_cast<int> (lastn)
1059 <<
'/' <<
static_cast<int> (lastd);
charNDArray max(char d, const charNDArray &m)
N Dimensional Array with copy-on-write semantics.
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
bool isvector() const
Size of the specified dimension.
octave_idx_type rows() const
octave_idx_type numel() const
Number of elements in the array.
ColumnVector imag(const ComplexColumnVector &a)
void octave_iconvlist_wrapper(int(*do_one)(unsigned int namescount, const char *const *names, void *data), void *data)
const char * octave_iconv_canonicalize_wrapper(const char *name)
OCTAVE_NORETURN liboctave_error_handler current_liboctave_error_handler
std::complex< double > Complex
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
template std::string rational_approx< double >(double val, int len)
template std::string rational_approx< float >(float val, int len)
octave::string::codecvt_u8::ExternT ExternT
#define INSTANTIATE_OCTAVE_STRING(T, API)
octave::string::codecvt_u8::InternT InternT
octave::string::codecvt_u8::StateT StateT
T::size_type numel(const T &str)
bool sizes_cmp(const T &str_a, const T &str_b)
T::size_type strlen(const typename T::value_type *str)
std::string rational_approx(T val, int len)
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
char * octave_u8_conv_to_encoding(const char *tocode, const uint8_t *src, size_t srclen, size_t *lengthp)
uint8_t * octave_u8_conv_from_encoding(const char *fromcode, const char *src, size_t srclen, size_t *lengthp)
char * octave_u16_conv_to_encoding(const char *tocode, const uint16_t *src, size_t srclen, size_t *lengthp)
uint8_t * octave_u8_conv_from_encoding_offsets(const char *fromcode, const char *src, size_t srclen, size_t *offsets, size_t *lengthp)
const uint8_t * octave_u8_check_wrapper(const uint8_t *src, size_t n)