Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-string-utils.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
48#ifndef AH_STRING_UTILS_H
49#define AH_STRING_UTILS_H
50
51#include <algorithm>
52#include <array>
53#include <cctype>
54#include <cerrno>
55#include <cmath>
56#include <cstdlib>
57#include <iomanip>
58#include <limits>
59#include <stdexcept>
60#include <string_view>
61#include <type_traits>
62#include <cstring>
63#include <memory>
64#include <string>
65#include <sstream>
66#include <iterator>
67#include <vector>
68#include <htlist.H>
69#include <tpl_array.H>
70#include <ah-zip.H>
71
72// strtok_r is POSIX; the MSVC runtime (also used by clang-cl) provides the
73// identically-shaped strtok_s instead. Map one onto the other on Windows.
74#if defined(_MSC_VER)
75#define strtok_r strtok_s
76#endif
77
78namespace Aleph {
85template <typename T>
86std::string to_string(const std::vector<T> &v)
87{
88 std::ostringstream s;
89 for (size_t i = 0; i < v.size(); ++i)
90 {
91 s << v[i];
92 if (i < v.size() - 1)
93 s << ", ";
94 }
95 return s.str();
96}
97
104template <typename T>
105std::string to_string(const Array<T> &v)
106{
107 std::ostringstream s;
108 for (auto it = v.get_it(); it.has_curr(); it.next_ne())
109 {
110 s << it.get_curr();
111 if (not it.is_last())
112 s << ", ";
113 }
114 return s.str();
115}
116
117// left trim
124inline void ltrim(std::string &s)
125{
126 auto it = std::find_if(s.begin(), s.end(), [](const unsigned char ch)
127 {
128 return not std::isspace(ch);
129 });
130 s.erase(s.begin(), it);
131}
132
133// trim from end
140inline void rtrim(std::string &s)
141{
142 auto it = std::find_if(s.rbegin(), s.rend(), [](const unsigned char ch)
143 {
144 return not std::isspace(ch);
145 });
146 s.erase(it.base(), s.end());
147}
148
149namespace concat_detail {
150template <typename T>
151inline constexpr bool is_string_like =
152 std::is_convertible_v<T, std::string_view> or std::is_same_v<std::decay_t<T>, char>;
153
154inline size_t piece_size(std::string_view s) noexcept
155{
156 return s.size();
157}
158inline size_t piece_size(char) noexcept
159{
160 return 1;
161}
162
163inline void append_to(std::string &out, std::string_view s)
164{
165 out += s;
166}
167inline void append_to(std::string &out, char c)
168{
169 out += c;
170}
171
179template <typename T>
180std::string stringify(const T &v)
181{
182 if constexpr (std::is_convertible_v<T, std::string_view>)
183 return std::string(std::string_view(v));
184 else if constexpr (std::is_same_v<std::decay_t<T>, char>)
185 return std::string(1, v);
186 else if constexpr (std::is_arithmetic_v<std::decay_t<T>>)
187 return std::to_string(v);
188 else
189 {
190 std::ostringstream s;
191 s << v;
192 return s.str();
193 }
194}
195} // namespace concat_detail
196
212template <class... Args>
213inline std::string concat(const Args &...args)
214{
215 if constexpr (sizeof...(Args) == 0)
216 return {};
217 else if constexpr ((concat_detail::is_string_like<Args> and ...))
218 {
219 std::string result;
220 result.reserve((concat_detail::piece_size(args) + ...));
221 (concat_detail::append_to(result, args), ...);
222 return result;
223 }
224 else
225 {
226 std::array<std::string, sizeof...(Args)> pieces = {concat_detail::stringify(args)...};
227 size_t total = 0;
228 for (const auto &p : pieces)
229 total += p.size();
230 std::string result;
231 result.reserve(total);
232 for (const auto &p : pieces)
233 result += p;
234 return result;
235 }
236}
237
238// trim from both ends (in place)
244inline std::string trim(const std::string &s)
245{
246 std::string ret = s;
247 ltrim(ret);
248 rtrim(ret);
249 return ret;
250}
251
257inline std::string &trim_in_place(std::string &s)
258{
259 ltrim(s);
260 rtrim(s);
261 return s;
262}
263
270inline bool contains(const std::string_view &str, const std::string_view &substr)
271{
272 return str.find(substr) != std::string::npos;
273}
274
281inline std::string to_string(const double d, const size_t precision)
282{
283 std::ostringstream s;
284 s.precision(precision);
285 s << std::fixed << d;
286 return s.str();
287}
288
296inline std::string to_str(const double d)
297{
298 return to_string(d, std::numeric_limits<double>::max_digits10);
299}
300
306inline std::string tolower(const char *str)
307{
308 std::string ret;
309 for (const char *ptr = str; *ptr; ++ptr)
310 ret.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(*ptr))));
311 return ret;
312}
313
319inline std::string toupper(const char *str)
320{
321 std::string ret;
322 for (const char *ptr = str; *ptr; ++ptr)
323 ret.push_back(static_cast<char>(std::toupper(static_cast<unsigned char>(*ptr))));
324 return ret;
325}
326
332inline std::string tolower(const std::string &str)
333{
334 return tolower(str.c_str());
335}
336
342inline std::string toupper(const std::string &str)
343{
344 return toupper(str.c_str());
345}
346
352inline std::string &mutable_tolower(std::string &str)
353{
354 for (auto &c : str)
355 c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
356 return str;
357}
358
364inline std::string &mutable_toupper(std::string &str)
365{
366 for (auto &c : str)
367 c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
368 return str;
369}
370
381inline std::string only_alpha(const std::string &str)
382{
383 std::string ret;
384 ret.reserve(str.size() + 1);
385 // Explicit ASCII ranges rather than GNU case-range labels
386 // (`case 'a'...'z':`), which MSVC does not support. The comparisons are
387 // byte-equivalent and locale-independent.
388 for (const char c : str)
389 if ((c >= '0' and c <= '9') or (c >= 'a' and c <= 'z'))
390 ret.push_back(c);
391 else if (c >= 'A' and c <= 'Z')
392 ret.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
393
394 return ret;
395}
396
404inline std::string remove_spaces(const std::string &str)
405{
406 const size_t n = str.size();
407 std::string ret;
408 ret.reserve(n + 1);
409 for (const auto c : str)
410 if (not std::isspace(static_cast<unsigned char>(c)))
411 ret.push_back(c);
412 return ret;
413}
414
421inline std::string remove_symbols(const std::string &str, const std::string &symbols)
422{
423 const size_t n = str.size();
424 std::string ret;
425 ret.reserve(n + 1);
426 for (const auto c : str)
427 if (symbols.find(c) == std::string::npos)
428 ret.push_back(c);
429
430 return ret;
431}
432
444template <class C>
445inline std::ostream &join(const C &c, const std::string &sep, std::ostream &out)
446{
447 if (c.is_empty())
448 return out;
449
450 auto &last = c.get_last();
451 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
452 {
453 auto &curr = it.get_curr();
454 out << curr;
455 if (&curr != &last)
456 out << sep;
457 }
458 return out;
459}
460
468template <class C>
469inline std::string join(const C &c, const std::string &sep = " ")
470{
471 std::ostringstream s;
472 join(c, sep, s);
473 return s.str();
474}
475
476// return true if str can be converted to a double
485inline bool is_double(const std::string &str)
486{
487 const char *begin = str.c_str();
488 char *endptr = nullptr;
489 errno = 0;
490 const auto val = std::strtod(begin, &endptr);
491 if (endptr == begin or *endptr != '\0')
492 return false;
493 return errno != ERANGE and std::isfinite(val);
494}
495
504inline bool is_float(const std::string &str)
505{
506 const char *begin = str.c_str();
507 char *endptr = nullptr;
508 errno = 0;
509 const auto val = std::strtof(begin, &endptr);
510 if (endptr == begin or *endptr != '\0')
511 return false;
512 return errno != ERANGE and std::isfinite(val);
513}
514
523inline bool is_long(const std::string &str)
524{
525 const char *begin = str.c_str();
526 char *endptr = nullptr;
527 errno = 0;
528 (void) std::strtol(begin, &endptr, 10);
529 if (endptr == begin or *endptr != '\0')
530 return false;
531 return errno != ERANGE;
532}
533
542inline bool is_size_t(const std::string &str)
543{
544 if (str.empty() or str[0] == '-')
545 return false;
546
547 const char *begin = str.c_str();
548 char *endptr = nullptr;
549 errno = 0;
550 const auto val = std::strtoull(begin, &endptr, 10);
551 if (endptr == begin or *endptr != '\0')
552 return false;
553 if (errno == ERANGE)
554 return false;
556}
557
564inline long safe_atol(const std::string &s)
565{
566 errno = 0;
567 char *endptr = nullptr;
568 const auto val = std::strtol(s.c_str(), &endptr, 10);
569 const bool invalid = (errno == ERANGE and (val == LONG_MAX or val == LONG_MIN)) or
570 (errno != 0 and val == 0) or endptr == s.c_str();
571
572 ah_runtime_error_if(invalid) << "invalid std::string for long: " << s;
573 return val;
574}
575
582inline double safe_atof(const std::string &s)
583{
584 errno = 0;
585 char *endptr = nullptr;
586 const auto val = std::strtod(s.c_str(), &endptr);
587 const bool invalid =
588 (errno == ERANGE and (val == HUGE_VAL or val == HUGE_VALF or val == HUGE_VALL)) or
589 (errno != 0 and val == 0) or endptr == s.c_str() or *endptr != '\0' or not std::isfinite(val);
590
591 ah_runtime_error_if(invalid) << "invalid std::string for double: " << s;
592 return val;
593}
594
601inline bool is_prefix(const std::string &str, const std::string &prefix)
602{
603 if (str.size() < prefix.size())
604 return false;
605 return strncmp(str.data(), prefix.data(), prefix.size()) == 0;
606}
607
614inline std::string remove_prefix(std::string &str, const std::string &prefix)
615{
616 if (is_prefix(str, prefix))
617 str = str.substr(prefix.size());
618 return str;
619}
620
626inline std::string to_lower(const std::string &str)
627{
628 std::string ret;
629 for (const char c : str)
630 ret.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
631 return ret;
632}
633
639inline std::string to_upper(const std::string &str)
640{
641 std::string ret;
642 for (const char c : str)
643 ret.push_back(static_cast<char>(std::toupper(static_cast<unsigned char>(c))));
644 return ret;
645}
646
652inline std::string to_name(const std::string &str)
653{
654 if (str.empty())
655 return str;
656
657 std::string ret;
658 ret.push_back(static_cast<char>(std::toupper(static_cast<unsigned char>(str[0]))));
659
660 for (size_t i = 1; i < str.size(); ++i)
661 ret.push_back(str[i]);
662
663 return ret;
664}
665
673inline DynList<std::string> split_camel_case(const char *const str)
674{
676 if (str == nullptr or *str == '\0')
677 return ret;
678 const char *ptr = str;
679 std::string curr(1, *ptr);
680 while (*++ptr)
681 if (std::isupper(static_cast<unsigned char>(*ptr)))
682 {
683 ret.append(curr);
684 curr = std::string(1, *ptr);
685 }
686 else
687 curr.push_back(*ptr);
688
689 if (not curr.empty())
690 ret.append(curr);
691
692 return ret;
693}
694
700inline DynList<std::string> split_camel_case(const std::string &str)
701{
702 return split_camel_case(str.data());
703}
704
710inline void fill_string(std::string &str, char sym)
711{
712 for (char &c : str)
713 c = sym;
714}
715
725inline std::vector<std::string> &split(const std::string &s,
726 const char delim,
727 std::vector<std::string> &elems)
728{
729 std::stringstream ss(s);
730 std::string item;
731 while (getline(ss, item, delim))
732 elems.push_back(item);
733
734 return elems;
735}
736
743inline std::vector<std::string> split(const std::string &s, const char delim)
744{
745 std::vector<std::string> elems;
746 split(s, delim, elems);
747 return elems;
748}
749
761template <template <typename> class Container = DynList>
762inline Container<std::string> split_string(const std::string &s, const std::string &delim)
763{
765 if (s.empty())
766 return elems;
767
768 if (delim.empty())
769 {
770 elems.append(s);
771 return elems;
772 }
773
774 char *saveptr = nullptr;
775 char **p = &saveptr;
776
777 std::string data = s;
778 const char *d = delim.data();
779 const auto str = data.data();
780
781 for (char *token = strtok_r(str, d, p); token; token = strtok_r(nullptr, d, p))
782 elems.append(token);
783
784 return elems;
785}
786
793inline DynList<std::string> split_to_list(const std::string &s, const std::string &delim)
794{
795 return split_string<DynList>(s, delim);
796}
797
806inline std::string to_Pascalcase(const std::string &str)
807{
808 DynList<std::string> tokens = split_to_list(str, " _-");
809
810 tokens.mutable_for_each([](std::string &token)
811 {
812 token[0] = ::toupper(token[0]);
813 });
814
815 return tokens.foldl<std::string>("", [](const std::string &acu, const std::string &token)
816 {
817 return acu + token;
818 });
819}
820
827inline Array<std::string> split_to_array(const std::string &s, const std::string &delim)
828{
829 return split_string<Array>(s, delim);
830}
831
839inline std::pair<std::string, std::string> split_pos(const std::string &str, const size_t pos)
840{
841 ah_range_error_if(pos > str.size()) << "split_pos(" << str << ", " << pos << "): position " << pos
842 << " is larger than std::string size " << str.size();
843
844 const char *ptr = str.data();
845 const char *end1 = ptr + pos;
846
847 std::string s1;
848 while (ptr != end1)
849 s1.push_back(*ptr++);
850
851 std::string s2;
852 while (*ptr)
853 s2.push_back(*ptr++);
854
855 return {s1, s2};
856}
857
868inline DynList<std::string> split_n(const std::string &str, const size_t n)
869{
870 ah_range_error_if(n == 0) << "split_n(): number of parts cannot be 0";
871
872 ah_range_error_if(n > str.size()) << "split_n(" << str << ", " << n << "): number of parts " << n
873 << " is larger than std::string size " << str.size();
874
875 const size_t sz = str.size() / n;
876
877 const char *ptr = str.data();
878
880
881 for (size_t i = 0; i < n; ++i)
882 {
883 std::string s;
884 if (i + 1 == n)
885 while (*ptr)
886 s.push_back(*ptr++);
887 else
888 for (size_t k = 0; k < sz and *ptr; ++k)
889 s.push_back(*ptr++);
890
891 ret.append(s);
892 }
893
894 return ret;
895}
896
906template <typename T>
908{
909 size_t max_sz = 0;
910 DynList<size_t> sizes = m.template maps<size_t>([&max_sz](auto &l)
911 {
912 const size_t sz = l.size();
913 max_sz = std::max(max_sz, sz);
914 return sz;
915 });
916
918 for (auto it = zip_it(m, sizes); it.has_curr(); it.next_ne())
919 {
920 auto t = it.get_curr();
921 DynList<T> &l = get<0>(t);
922 const size_t sz = get<1>(t);
923 const long n = max_sz - sz;
924 for (auto i = 0; i < n; ++i)
925 l.append(T());
926 ret.append(std::move(l));
927 }
928
929 return ret;
930}
931
938 const DynList<DynList<std::string>> &mat)
939{
940 return mat.maps<DynList<std::string>>([&lens](const DynList<std::string> &l)
941 {
942 return zip(lens, l).template maps<std::string>([](const auto &p)
943 {
944 const std::string blanks(p.first > p.second.size() ? p.first - p.second.size() : 0, ' ');
945 return blanks + p.second + " ";
946 });
947 });
948}
949
957inline std::ostream &format_string(std::ostream &out,
958 const DynList<size_t> &lens,
959 const DynList<DynList<std::string>> &mat)
960{
961 for (auto it = mat.get_it(); it.has_curr(); it.next_ne())
962 {
963 const auto &row = it.get_curr();
964 auto line = zip(lens, row).template maps<std::string>([](const auto &p)
965 {
966 const std::string blanks(p.first > p.second.size() ? p.first - p.second.size() : 0, ' ');
967 return blanks + p.second + " ";
968 });
969 line.for_each([&out](const auto &s)
970 {
971 out << s;
972 });
973 out << '\n';
974 }
975
976 return out;
977}
978
985{
986 if (mat.is_empty())
987 return mat;
988
989 const DynList<size_t> ilens = rep<size_t>(mat.nth(0).size(), 0);
990 const DynList<size_t> maxs =
991 mat.foldl(ilens, [](const DynList<size_t> &acu, const DynList<std::string> &l)
992 {
993 return zip(acu, l).maps<size_t>([](const auto &p)
994 {
995 return std::max(p.first, p.second.size());
996 });
997 });
998
999 return format_string(maxs, mat);
1000}
1001
1008{
1010 for (auto row_it = mat.get_it(); row_it.has_curr(); row_it.next_ne())
1011 {
1012 const DynList<std::string> &curr_row = row_it.get_curr();
1013 const std::string &last = curr_row.get_last();
1015 for (auto it = curr_row.get_it(); it.has_curr(); it.next_ne())
1016 {
1017 const std::string &s = it.get_curr();
1018 if (&s == &last)
1019 row.append(s);
1020 else
1021 row.append(s + ",");
1022 }
1023 ret.append(row);
1024 }
1025
1026 return ret;
1027}
1028
1036inline std::string to_string(const DynList<DynList<std::string>> &mat)
1037{
1038 std::ostringstream s;
1039 mat.for_each([&s](const auto &row)
1040 {
1041 row.for_each([&s](const std::string &str)
1042 {
1043 s << str;
1044 });
1045 s << '\n';
1046 });
1047 return s.str();
1048}
1049
1055inline DynList<std::string> split_text_into_words(const std::string &text)
1056{
1058 std::istringstream in(text);
1059 for (std::string word; in >> word;)
1060 words.append(word);
1061 return words;
1062}
1063
1069inline DynList<std::string> split_text_into_lines(const std::string &text)
1070{
1071 return split_to_list(text, "\n");
1072}
1073
1079inline std::string to_string(const DynList<std::string> &lines)
1080{
1081 std::ostringstream s;
1082 for (auto it = lines.get_it(); it.has_curr(); it.next_ne())
1083 {
1084 const auto &line = it.get_curr();
1085 s << line;
1086 if (line != lines.get_last())
1087 s << '\n';
1088 }
1089
1090 return s.str();
1091}
1092
1099inline std::string justify_line(std::string line, const size_t page_width)
1100{
1101 if (size_t pos = line.find_first_of(' '); pos != std::string::npos)
1102 while (line.size() < page_width)
1103 {
1104 pos = line.find_first_not_of(' ', pos);
1105 if (pos == std::string::npos)
1106 break;
1107 line.insert(pos, " ");
1108 pos = line.find_first_of(' ', pos + 1);
1109 if (pos == std::string::npos)
1110 pos = line.find_first_of(' ');
1111 }
1112
1113 return line;
1114}
1115
1123inline std::string justify_text(const std::string &text,
1124 const size_t width,
1125 const size_t left_margin = 0)
1126{
1127 auto words = split_text_into_words(text);
1128
1129 std::ostringstream s;
1130 std::string line;
1131 for (const std::string &word : words)
1132 if (line.size() + word.size() + 1 > width)
1133 {
1134 // next word doesn't fit into the line
1135 if (not line.empty())
1136 {
1137 s << std::string(left_margin, ' ') << justify_line(line, width) << '\n';
1138 line.clear();
1139 }
1140 line = word;
1141 }
1142 else
1143 {
1144 if (not line.empty())
1145 line.append(" ");
1146 line.append(word);
1147 }
1148
1149 s << std::string(left_margin, ' ') << line;
1150
1151 return s.str();
1152}
1153
1161inline std::string justify_line_except_first(const std::string &text,
1162 const size_t width,
1163 const size_t left_margin = 0)
1164{
1165 const auto formatted = justify_text(text, width);
1167 std::ostringstream s;
1168 s << lines.remove_first() << '\n';
1169 s << justify_text(to_string(lines), width, left_margin);
1170 return s.str();
1171}
1172
1180inline std::string align_text_to_left(const std::string &text,
1181 const size_t page_width,
1182 const size_t left_margin = 0)
1183{
1184 auto words = split_text_into_words(text);
1185
1186 const std::string margin(left_margin, ' ');
1187 std::ostringstream s;
1188 std::string line;
1189 for (const std::string &word : words)
1190 if (line.size() + word.size() + 1 > page_width)
1191 {
1192 // next word doesn't fit into the line
1193 if (not line.empty())
1194 {
1195 s << margin << line << '\n';
1196 line.clear();
1197 }
1198 line = word;
1199 }
1200 else
1201 {
1202 if (not line.empty())
1203 line.append(" ");
1204 line.append(word);
1205 }
1206
1207 s << margin << line;
1208
1209 return s.str();
1210}
1211
1219inline std::string align_text_to_left_except_first(const std::string &text,
1220 const size_t width,
1221 const size_t left_margin = 0)
1222{
1223 const auto formatted = align_text_to_left(text, width);
1225 std::ostringstream s;
1226 s << lines.remove_first() << '\n';
1228 return s.str();
1229}
1230
1237inline std::string shift_lines_to_left(const std::string &str, const size_t n)
1238{
1239 std::ostringstream s;
1240 const std::string fill(n, ' ');
1241 const auto lines = split_to_list(str, "\n");
1242 for (auto it = lines.get_it(); it.has_curr(); it.next_ne())
1243 {
1244 const auto &line = it.get_curr();
1245 s << fill << line;
1246 if (line != lines.get_last())
1247 s << '\n';
1248 }
1249 return s.str();
1250}
1251
1256inline void build_pars_list(std::string &unused)
1257{
1258 (void) unused;
1259}
1260
1261template <typename T>
1262 requires requires(std::ostream &out, const T &v) { out << v; }
1263
1270inline void build_pars_list(std::string &str, const T &item)
1271{
1272 std::ostringstream s;
1273 if (not str.empty())
1274 s << ", ";
1275 s << item;
1276 str.append(s.str());
1277}
1278
1287template <class T, class... Args>
1288inline void build_pars_list(std::string &str, const T &item, Args... args)
1289{
1290 build_pars_list(str, item);
1291 build_pars_list(str, args...);
1292}
1293
1297template <class First, class... Rest>
1298 requires(not requires(const std::remove_reference_t<First> &c) {
1299 c.is_empty();
1300 c.get_last();
1301 c.get_it();
1302 })
1313inline std::string build_pars_list(const First &first, const Rest &...rest)
1314{
1315 std::string ret;
1316 build_pars_list(ret, first, rest...);
1317 return ret;
1318}
1319
1320template <class C>
1321 requires requires(const C &c) {
1322 c.is_empty();
1323 c.get_last();
1324 c.get_it();
1325 }
1333inline std::string build_pars_list(const C &c, const std::string &sep = ",")
1334{
1335 if (c.is_empty())
1336 return "";
1337
1338 auto &last = c.get_last();
1339 std::ostringstream s;
1340 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
1341 {
1342 auto &curr = it.get_curr();
1343 s << curr;
1344 if (&curr != &last)
1345 s << sep;
1346 }
1347 return s.str();
1348}
1349} // namespace Aleph
1350
1351#endif // AH_STRING_UTILS_H
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
Definition ah-errors.H:271
#define ah_range_error_if(C)
Throws std::range_error if condition holds.
Definition ah-errors.H:212
Zip iterators and functional operations for multiple containers.
size_t size_t int32_t * out
Definition ca-c-api.h:120
size_t row
Definition ca-c-api.h:115
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
T & get_last() const
Return the last item of the list.
Definition htlist.H:1363
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
__T foldl(const __T &init, Op &op) const
Fold the elements of the container to a specific result.
Definition ah-dry.H:1312
void mutable_for_each(Operation &operation)
Apply a mutable operation to each element of the container.
Definition ah-dry.H:953
Aleph::DynList< __T > maps(Operation &op) const
Map the elements of the container.
Definition ah-dry.H:1090
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:796
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:228
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Singly linked list implementations with head-tail access.
size_t piece_size(std::string_view s) noexcept
std::string stringify(const T &v)
Convert any single value to std::string.
constexpr bool is_string_like
void append_to(std::string &out, std::string_view s)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::string tolower(const char *str)
Convert a C std::string to lower-case.
ZipIterator< Cs... > zip_it(const Cs &...cs)
Alias for get_zip_it.
Definition ah-zip.H:270
bool is_prefix(const std::string &str, const std::string &prefix)
Check whether prefix is a prefix of str.
std::string remove_symbols(const std::string &str, const std::string &symbols)
Remove any character appearing in symbols.
std::string to_upper(const std::string &str)
Convert a std::string to upper-case (byte-wise).
DynList< std::string > split_text_into_lines(const std::string &text)
Split a text into lines by "\n".
std::string justify_line_except_first(const std::string &text, const size_t width, const size_t left_margin=0)
Justify all lines except the first one.
DynList< std::string > split_text_into_words(const std::string &text)
Split a text into whitespace-separated words.
Array< std::string > split_to_array(const std::string &s, const std::string &delim)
Split a std::string into an Aleph::Array<std::string>.
std::pair< std::string, std::string > split_pos(const std::string &str, const size_t pos)
Split a std::string at a fixed position.
long safe_atol(const std::string &s)
Convert a std::string to long and throw on parse errors.
void ltrim(std::string &s)
Remove leading whitespace from a std::string in-place.
std::string remove_prefix(std::string &str, const std::string &prefix)
Remove prefix from str if present.
std::string concat(const Args &...args)
Concatenate multiple arguments into a single std::string.
std::string & trim_in_place(std::string &s)
Trim a std::string in-place (leading + trailing whitespace removed).
std::string align_text_to_left(const std::string &text, const size_t page_width, const size_t left_margin=0)
Align text to the left by wrapping lines at page_width.
DynList< std::pair< typename Container1::Item_Type, typename Container2::Item_Type > > zip(const Container1 &a, const Container2 &b)
Zip two containers into a list of pairs.
void fill(Itor beg, const Itor &end, const T &value)
Fill a range with a value.
Definition ahAlgo.H:707
Container< std::string > split_string(const std::string &s, const std::string &delim)
Split a std::string by a set of delimiter characters.
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
bool contains(const std::string_view &str, const std::string_view &substr)
Check if substr appears inside str.
std::string justify_line(std::string line, const size_t page_width)
Justify a single line by inserting extra spaces.
std::string to_Pascalcase(const std::string &str)
Convert an identifier-like std::string to PascalCase.
DynList< DynList< std::string > > format_string_csv(const DynList< DynList< std::string > > &mat)
Produce a CSV-like matrix (commas added to all but last element in each row).
static void prefix(Node *root, DynList< Node * > &acc)
bool is_long(const std::string &str)
Check whether a std::string fully parses as a long.
DynList< std::string > split_n(const std::string &str, const size_t n)
Split a std::string into n parts.
std::string to_name(const std::string &str)
Uppercase the first character of str and return the resulting copy.
bool is_float(const std::string &str)
Check whether a std::string fully parses as a finite float.
bool is_size_t(const std::string &str)
Check whether a std::string fully parses as a non-negative size_t.
std::string trim(const std::string &s)
Return a trimmed copy of a std::string (leading + trailing whitespace removed).
DynList< std::string > split_camel_case(const char *const str)
Split a camelCase / PascalCase std::string into tokens.
void build_pars_list(std::string &unused)
Base case for build_pars_list(std::string&, ...).
std::string remove_spaces(const std::string &str)
Remove all whitespace characters from a std::string.
std::string to_string(const time_t t, const std::string &format)
Format a time_t value into a string using format.
Definition ah-date.H:140
std::string to_str(const double d)
Convert double to a std::string with maximum round-trip precision.
std::string justify_text(const std::string &text, const size_t width, const size_t left_margin=0)
Justify a text to a target width.
bool is_double(const std::string &str)
Check whether a std::string fully parses as a finite double.
DynList< std::string > split_to_list(const std::string &s, const std::string &delim)
Split a std::string into an Aleph::DynList<std::string>.
std::string shift_lines_to_left(const std::string &str, const size_t n)
Indent every line in a multi-line std::string by n spaces.
DynList< DynList< T > > complete_rows(DynList< DynList< T > > &m)
Pad all rows of a matrix to the maximum row length.
std::string align_text_to_left_except_first(const std::string &text, const size_t width, const size_t left_margin=0)
Align all lines except the first one.
std::string toupper(const char *str)
Convert a C std::string to upper-case.
std::ostream & join(const C &c, const std::string &sep, std::ostream &out)
Join elements of an Aleph-style container into a stream.
void rtrim(std::string &s)
Remove trailing whitespace from a std::string in-place.
std::vector< std::string > & split(const std::string &s, const char delim, std::vector< std::string > &elems)
Split a std::string by a single delimiter character.
DynList< DynList< std::string > > format_string(const DynList< size_t > &lens, const DynList< DynList< std::string > > &mat)
double safe_atof(const std::string &s)
Convert a std::string to double and throw on parse errors.
std::string to_lower(const std::string &str)
Convert a std::string to lower-case (byte-wise).
void fill_string(std::string &str, char sym)
Fill all the content of std::string with a defined char.
std::string & mutable_tolower(std::string &str)
Convert a std::string to lower-case in-place.
std::string & mutable_toupper(std::string &str)
Convert a std::string to upper-case in-place.
std::string only_alpha(const std::string &str)
Extract alphanumeric ASCII characters and normalize letters to lower-case.
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
static int * k
Dynamic array container with automatic resizing.
DynList< int > l