Ookii.CommandLine for C++  2.0.0
string_helper.h
Go to the documentation of this file.
1 #ifndef OOKII_STRING_HELPER_H_
4 #define OOKII_STRING_HELPER_H_
5 
6 #pragma once
7 
8 #include <locale>
9 #include <sstream>
10 #include <optional>
11 #include <array>
12 #include <string>
13 #include <string_view>
14 #include <algorithm>
15 
16 namespace ookii
17 {
18  namespace details
19  {
20 #ifdef _UNICODE
21  using default_char_type = wchar_t;
22 #else
23  using default_char_type = char;
24 #endif
25  }
26 
29  struct string_less
30  {
31  public:
33  using is_transparent = int;
34 
40  string_less(bool case_sensitive = true, std::locale loc = {})
41  : _case_sensitive{case_sensitive},
42  _locale{loc}
43  {
44  }
45 
52  template<typename Range1, typename Range2>
53  bool operator()(Range1 &&left, Range2 &&right) const
54  {
55  // Using enables ADL.
56  using std::begin;
57  using std::end;
58  if (_case_sensitive)
59  {
60  return std::lexicographical_compare(begin(left), end(left), begin(right), end(right), std::less<>{});
61  }
62  else
63  {
64  return std::lexicographical_compare(begin(left), end(left), begin(right), end(right), [this](auto left, auto right)
65  {
66  return std::toupper(left, _locale) < std::toupper(right, _locale);
67  });
68  }
69  }
70 
71  private:
72  bool _case_sensitive;
73  std::locale _locale;
74  };
75 
78  struct char_less
79  {
80  public:
82  using is_transparent = int;
83 
89  char_less(bool case_sensitive = true, std::locale loc = {})
90  : _case_sensitive{case_sensitive},
91  _locale{loc}
92  {
93  }
94 
100  template<typename CharType>
101  bool operator()(CharType &&left, CharType &&right) const
102  {
103  if (_case_sensitive)
104  {
105  return left < right;
106  }
107  else
108  {
109  return std::toupper(left, _locale) < std::toupper(right, _locale);
110  }
111  }
112 
113  private:
114  bool _case_sensitive;
115  std::locale _locale;
116  };
117 
125  template<typename CharType, typename Traits>
126  bool string_equal_case_insensitive(std::basic_string_view<CharType, Traits> string1, std::basic_string_view<CharType, Traits> string2, const std::locale &locale = {})
127  {
128  return std::equal(string1.begin(), string1.end(), string2.begin(), string2.end(), [&locale](auto left, auto right)
129  {
130  return std::toupper(left, locale) == std::toupper(right, locale);
131  });
132  }
133 
146  template<typename CharType, size_t Length>
147  constexpr const std::array<CharType, Length> literal_cast(const char (&value)[Length])
148  {
149  std::array<CharType, Length> result{};
150  std::copy(std::begin(value), std::end(value), result.begin());
151  return result;
152  }
153 
164  template<typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
166  {
171  static std::basic_string<CharType, Traits, Alloc> from_bytes(std::string_view value, const std::locale &loc = {})
172  {
173  std::basic_string<CharType, Traits, Alloc> result;
174  auto &facet = std::use_facet<std::ctype<CharType>>(loc);
175  result.reserve(value.length());
176  std::transform(value.begin(), value.end(), std::back_inserter(result), [&facet](auto c)
177  {
178  return facet.widen(c);
179  });
180 
181  return result;
182  }
183  };
184 
188  template<typename Traits, typename Alloc>
189  struct string_convert<char, Traits, Alloc>
190  {
194  static std::basic_string<char, Traits, Alloc> from_bytes(std::string_view value, const std::locale & = {})
195  {
196  return std::basic_string<char, Traits, Alloc>{value};
197  }
198  };
199 
210  template<typename T, typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
212  {
217  static std::optional<T> from_string(std::basic_string_view<CharType, Traits> value, const std::locale &loc = {})
218  {
219  std::basic_istringstream<CharType> stream{std::basic_string<CharType, Traits, Alloc>{value}};
220  stream.imbue(loc);
221  // Unsetting all base flags allows the stream to determine the base from the prefix
222  // when converting a string to a number.
223  stream.unsetf(std::ios::dec);
224  stream.unsetf(std::ios::oct);
225  stream.unsetf(std::ios::hex);
226  T result{};
227  stream >> result;
228  if (!stream || !stream.eof())
229  return {};
230 
231  return result;
232  }
233  };
234 
243  template<typename CharType, typename Traits, typename Alloc>
244  struct lexical_convert<std::basic_string<CharType, Traits, Alloc>, CharType, Traits, Alloc>
245  {
249  static std::optional<std::basic_string<CharType, Traits, Alloc>> from_string(std::basic_string_view<CharType, Traits> value, const std::locale &)
250  {
251  return {std::basic_string<CharType, Traits, Alloc>{value}};
252  }
253  };
254 
262  template<typename CharType, typename Traits = std::char_traits<CharType>>
263  class tokenize
264  {
265  class iterator
266  {
267  public:
268  using iterator_concept = std::forward_iterator_tag;
269  using value_type = std::basic_string_view<CharType, Traits>;
270  using difference_type = std::ptrdiff_t;
271  using pointer = value_type*;
272  using reference = value_type&;
273 
274  iterator() noexcept = default;
275 
276  iterator(value_type value, CharType separator) noexcept
277  : _remaining{value},
278  _separator{separator}
279  {
280  next_value();
281  }
282 
283  iterator &operator++() noexcept
284  {
285  next_value();
286  return *this;
287  }
288 
289  iterator operator++(int) noexcept
290  {
291  iterator temp = *this;
292  next_value();
293  return temp;
294  }
295 
296  value_type operator*() const noexcept
297  {
298  return _value;
299  }
300 
301  bool operator==(const iterator &other) const noexcept
302  {
303  return _value == other._value && _remaining == other._remaining;
304  }
305 
306  private:
307  void next_value() noexcept
308  {
309  if (_remaining.length() != 0)
310  {
311  auto index = _remaining.find_first_of(_separator);
312  _value = _remaining.substr(0, index);
313  if (index == std::string_view::npos)
314  {
315  _remaining = {};
316  }
317  else
318  {
319  _remaining = _remaining.substr(index + 1);
320  }
321  }
322  else
323  {
324  _value = {};
325  }
326  }
327 
328  value_type _value;
329  value_type _remaining;
330  CharType _separator{};
331  };
332 
333  public:
337  tokenize(typename iterator::value_type value, CharType separator) noexcept
338  : _value{value},
339  _separator{separator}
340  {
341  }
342 
344  iterator begin() const noexcept
345  {
346  return iterator{_value, _separator};
347  }
348 
351  iterator end() const noexcept
352  {
353  return iterator{};
354  }
355 
356  private:
357  typename iterator::value_type _value;
358  CharType _separator;
359  };
360 
368  template<typename CharType, typename Traits>
369  std::optional<std::basic_string_view<CharType, Traits>> strip_prefix(std::basic_string_view<CharType, Traits> value,
370  std::basic_string_view<CharType, Traits> prefix)
371  {
372  if (value.starts_with(prefix))
373  {
374  return value.substr(prefix.length());
375  }
376 
377  return {};
378  }
379 
388  template<typename CharType, typename Traits>
389  std::tuple<std::basic_string_view<CharType, Traits>, std::optional<std::basic_string_view<CharType, Traits>>> split_once(
390  std::basic_string_view<CharType, Traits> value, CharType separator)
391  {
392  auto index = value.find(separator);
393  if (index == std::basic_string_view<CharType, Traits>::npos)
394  {
395  return {value, {}};
396  }
397 
398  return {value.substr(0, index), value.substr(index + 1)};
399  }
400 }
401 
402 #endif
A pseudo-range for string tokenization.
Definition: string_helper.h:264
iterator end() const noexcept
Gets an iterator that will compare equal once the iterator returned by begin() no longer has any toke...
Definition: string_helper.h:351
tokenize(typename iterator::value_type value, CharType separator) noexcept
Initializes a new instance of the tokenize class.
Definition: string_helper.h:337
iterator begin() const noexcept
Gets a forward iterator to the first token.
Definition: string_helper.h:344
Namespace containing the core Ookii.CommandLine.Cpp types.
Definition: command_line_argument.h:16
std::optional< std::basic_string_view< CharType, Traits > > strip_prefix(std::basic_string_view< CharType, Traits > value, std::basic_string_view< CharType, Traits > prefix)
Removes a prefix from a string.
Definition: string_helper.h:369
constexpr const std::array< CharType, Length > literal_cast(const char(&value)[Length])
Converts a simple ASCII string literal to the specified character type at compile time.
Definition: string_helper.h:147
std::tuple< std::basic_string_view< CharType, Traits >, std::optional< std::basic_string_view< CharType, Traits > > > split_once(std::basic_string_view< CharType, Traits > value, CharType separator)
Splits a string on the first occurrence of a separator.
Definition: string_helper.h:389
bool string_equal_case_insensitive(std::basic_string_view< CharType, Traits > string1, std::basic_string_view< CharType, Traits > string2, const std::locale &locale={})
Compares two strings, ignoring their case.
Definition: string_helper.h:126
A version of the std::less predicate for characters that supports case insensitive comparison.
Definition: string_helper.h:79
bool operator()(CharType &&left, CharType &&right) const
Compares two characters.
Definition: string_helper.h:101
char_less(bool case_sensitive=true, std::locale loc={})
Initializes a new instance of the char_less class.
Definition: string_helper.h:89
int is_transparent
Indicates that this function accepts any type and uses perfect forwarding.
Definition: string_helper.h:82
static std::optional< std::basic_string< CharType, Traits, Alloc > > from_string(std::basic_string_view< CharType, Traits > value, const std::locale &)
Convert a string to the specified type.
Definition: string_helper.h:249
Template class used to convert strings to strongly typed argument values.
Definition: string_helper.h:212
static std::optional< T > from_string(std::basic_string_view< CharType, Traits > value, const std::locale &loc={})
Convert a string to the specified type.
Definition: string_helper.h:217
static std::basic_string< char, Traits, Alloc > from_bytes(std::string_view value, const std::locale &={})
Converts a string to the specified character type.
Definition: string_helper.h:194
Performs a simple conversion of a narrow character string to a specified character type.
Definition: string_helper.h:166
static std::basic_string< CharType, Traits, Alloc > from_bytes(std::string_view value, const std::locale &loc={})
Converts a string to the specified character type.
Definition: string_helper.h:171
A version of the std::less predicate for strings that supports case insensitive comparison.
Definition: string_helper.h:30
int is_transparent
Indicates that this function accepts any type and uses perfect forwarding.
Definition: string_helper.h:33
string_less(bool case_sensitive=true, std::locale loc={})
Initializes a new instance of the string_less class.
Definition: string_helper.h:40
bool operator()(Range1 &&left, Range2 &&right) const
Compares two strings.
Definition: string_helper.h:53