Ookii.CommandLine for C++  1.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 <ranges>
15 #include <algorithm>
16 
17 namespace ookii
18 {
19 
22  struct string_less
23  {
24  public:
26  using is_transparent = int;
27 
33  string_less(bool case_sensitive = true, std::locale loc = {})
34  : _case_sensitive{case_sensitive},
35  _locale{loc}
36  {
37  }
38 
45  template<typename Range1, typename Range2>
46  bool operator()(Range1 &&left, Range2 &&right) const
47  {
48  // Using enables ADL.
49  using std::begin;
50  using std::end;
51  if (_case_sensitive)
52  {
53  return std::ranges::lexicographical_compare(left, right, std::less<>{});
54  }
55  else
56  {
57  return std::ranges::lexicographical_compare(left, right, [this](auto left, auto right)
58  {
59  return std::toupper(left, _locale) < std::toupper(right, _locale);
60  });
61  }
62  }
63 
64  private:
65  bool _case_sensitive;
66  std::locale _locale;
67  };
68 
76  template<typename CharType, typename Traits>
77  bool string_equal_case_insensitive(std::basic_string_view<CharType, Traits> string1, std::basic_string_view<CharType, Traits> string2, const std::locale &locale = {})
78  {
79  return std::ranges::equal(string1, string2, [&locale](auto left, auto right)
80  {
81  return std::toupper(left, locale) == std::toupper(right, locale);
82  });
83  }
84 
97  template<typename CharType, size_t Length>
98  constexpr const std::array<CharType, Length> literal_cast(const char (&value)[Length])
99  {
100  std::array<CharType, Length> result{};
101  std::ranges::copy(value, result.begin());
102  return result;
103  }
104 
115  template<typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
117  {
122  static std::basic_string<CharType, Traits, Alloc> from_bytes(std::string_view value, const std::locale &loc = {})
123  {
124  std::basic_string<CharType, Traits, Alloc> result;
125  auto &facet = std::use_facet<std::ctype<CharType>>(loc);
126  result.reserve(value.length());
127  std::ranges::transform(value, std::back_inserter(result), [&facet](auto c)
128  {
129  return facet.widen(c);
130  });
131 
132  return result;
133  }
134  };
135 
139  template<typename Traits, typename Alloc>
140  struct string_convert<char, Traits, Alloc>
141  {
145  static std::basic_string<char, Traits, Alloc> from_bytes(std::string_view value, const std::locale & = {})
146  {
147  return std::basic_string<char, Traits, Alloc>{value};
148  }
149  };
150 
161  template<typename T, typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
163  {
168  static std::optional<T> from_string(std::basic_string_view<CharType, Traits> value, const std::locale &loc = {})
169  {
170  std::basic_istringstream<CharType> stream{std::basic_string<CharType, Traits, Alloc>{value}};
171  stream.imbue(loc);
172  // Unsetting all base flags allows the stream to determine the base from the prefix
173  // when converting a string to a number.
174  stream.unsetf(std::ios::dec);
175  stream.unsetf(std::ios::oct);
176  stream.unsetf(std::ios::hex);
177  T result;
178  stream >> result;
179  if (!stream || !stream.eof())
180  return {};
181 
182  return result;
183  }
184  };
185 
194  template<typename CharType, typename Traits, typename Alloc>
195  struct lexical_convert<std::basic_string<CharType, Traits, Alloc>, CharType, Traits, Alloc>
196  {
200  static std::optional<std::basic_string<CharType, Traits, Alloc>> from_string(std::basic_string_view<CharType, Traits> value, const std::locale &)
201  {
202  return {std::basic_string<CharType, Traits, Alloc>{value}};
203  }
204  };
205 
213  template<typename CharType, typename Traits = std::char_traits<CharType>>
214  class tokenize
215  {
216  class iterator
217  {
218  public:
219  using iterator_concept = std::forward_iterator_tag;
220  using value_type = std::basic_string_view<CharType, Traits>;
221  using difference_type = std::ptrdiff_t;
222  using pointer = value_type*;
223  using reference = value_type&;
224 
225  iterator() noexcept = default;
226 
227  iterator(value_type value, CharType separator) noexcept
228  : _remaining{value},
229  _separator{separator}
230  {
231  next_value();
232  }
233 
234  iterator &operator++() noexcept
235  {
236  next_value();
237  return *this;
238  }
239 
240  iterator operator++(int) noexcept
241  {
242  iterator temp = *this;
243  next_value();
244  return temp;
245  }
246 
247  value_type operator*() const noexcept
248  {
249  return _value;
250  }
251 
252  bool operator==(const iterator &other) const noexcept
253  {
254  return _value == other._value && _remaining == other._remaining;
255  }
256 
257  private:
258  void next_value() noexcept
259  {
260  if (_remaining.length() != 0)
261  {
262  auto index = _remaining.find_first_of(_separator);
263  _value = _remaining.substr(0, index);
264  if (index == std::string_view::npos)
265  {
266  _remaining = {};
267  }
268  else
269  {
270  _remaining = _remaining.substr(index + 1);
271  }
272  }
273  else
274  {
275  _value = {};
276  }
277  }
278 
279  value_type _value;
280  value_type _remaining;
281  CharType _separator;
282  };
283 
284  public:
288  tokenize(typename iterator::value_type value, CharType separator) noexcept
289  : _value{value},
290  _separator{separator}
291  {
292  }
293 
295  iterator begin() const noexcept
296  {
297  return iterator{_value, _separator};
298  }
299 
302  iterator end() const noexcept
303  {
304  return iterator{};
305  }
306 
307  private:
308  typename iterator::value_type _value;
309  CharType _separator;
310  };
311 
312 }
313 
314 #endif
A pseudo-range for string tokenization.
Definition: string_helper.h:215
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:302
tokenize(typename iterator::value_type value, CharType separator) noexcept
Initializes a new instance of the tokenize class.
Definition: string_helper.h:288
iterator begin() const noexcept
Gets a forward iterator to the first token.
Definition: string_helper.h:295
Namespace containing the core Ookii.CommandLine.Cpp types.
Definition: command_line_argument.h:16
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:98
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:77
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:200
Template class used to convert strings to strongly typed argument values.
Definition: string_helper.h:163
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:168
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:145
Performs a simple conversion of a narrow character string to a specified character type.
Definition: string_helper.h:117
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:122
A version of the std::less predicate for strings that supports case insensitive comparison.
Definition: string_helper.h:23
int is_transparent
Indicates that this function accepts any type and uses perfect forwarding.
Definition: string_helper.h:26
string_less(bool case_sensitive=true, std::locale loc={})
Initializes a new instance of the StringLess class.
Definition: string_helper.h:33
bool operator()(Range1 &&left, Range2 &&right) const
Compares two strings.
Definition: string_helper.h:46