scnlib  0.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
locale.h
Go to the documentation of this file.
1 // Copyright 2017-2019 Elias Kosunen
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // This file is a part of scnlib:
16 // https://github.com/eliaskosunen/scnlib
17 
18 #ifndef SCN_DETAIL_LOCALE_H
19 #define SCN_DETAIL_LOCALE_H
20 
21 #include "result.h"
22 #include "string_view.h"
23 
24 #include <cwchar>
25 #include <string>
26 
27 namespace scn {
29 
30  namespace detail {
31  template <typename CharT>
33  public:
34  using char_type = CharT;
35  using string_type = std::basic_string<char_type>;
37 
38  truename_falsename_storage(const void* loc);
39 
40  constexpr const string_type& get_true_str() const
41  {
42  return m_truename;
43  }
44  constexpr const string_type& get_false_str() const
45  {
46  return m_falsename;
47  }
48 
49  constexpr string_view_type get_true_view() const
50  {
51  return string_view_type(m_truename.data(), m_truename.size());
52  }
53  constexpr string_view_type get_false_view() const
54  {
55  return string_view_type(m_falsename.data(), m_falsename.size());
56  }
57 
58  private:
59  string_type m_truename;
60  string_type m_falsename;
61  };
62 
63  constexpr bool has_zero(uint64_t v)
64  {
65  return (v - UINT64_C(0x0101010101010101)) & ~v &
66  UINT64_C(0x8080808080808080);
67  }
68 
69  // Hand write to avoid C locales and thus noticeable performance losses
70  inline bool is_space(char ch) noexcept
71  {
72  static constexpr detail::array<bool, 256> lookup = {
73  {false, false, false, false, false, false, false, false, false,
74  true, true, true, true, true, false, false, false, false,
75  false, false, false, false, false, false, false, false, false,
76  false, false, false, false, false, true, false, false, false,
77  false, false, false, false, false, false, false, false, false,
78  false, false, false, false, false, false, false, false, false,
79  false, false, false, false, false, false, false, false, false,
80  false, false, false, false, false, false, false, false, false,
81  false, false, false, false, false, false, false, false, false,
82  false, false, false, false, false, false, false, false, false,
83  false, false, false, false, false, false, false, false, false,
84  false, false, false, false, false, false, false, false, false,
85  false, false, false, false, false, false, false, false, false,
86  false, false, false, false, false, false, false, false, false,
87  false, false, false, false, false, false, false, false, false,
88  false, false, false, false, false, false, false, false, false,
89  false, false, false, false, false, false, false, false, false,
90  false, false, false, false, false, false, false, false, false,
91  false, false, false, false, false, false, false, false, false,
92  false, false, false, false, false, false, false, false, false,
93  false, false, false, false, false, false, false, false, false,
94  false, false, false, false, false, false, false, false, false,
95  false, false, false, false, false, false, false, false, false,
96  false, false, false, false, false, false, false, false, false,
97  false, false, false, false, false, false, false, false, false,
98  false, false, false, false, false, false, false, false, false,
99  false, false, false, false, false, false, false, false, false,
100  false, false, false, false, false, false, false, false, false,
101  false, false, false, false}};
102  return lookup[static_cast<size_t>(ch)];
103  }
104  constexpr inline bool is_space(wchar_t ch) noexcept
105  {
106  return ch == 0x20 || (ch >= 0x09 && ch <= 0x0d);
107  }
108 
109  constexpr inline bool is_digit(char ch) noexcept
110  {
111  return ch >= '0' && ch <= '9';
112  }
113  constexpr inline bool is_digit(wchar_t ch) noexcept
114  {
115  return ch >= L'0' && ch <= L'9';
116  }
117 
118  template <typename CharT>
120  template <>
121  struct default_widen<char> {
122  static constexpr char widen(char ch) noexcept
123  {
124  return ch;
125  }
126  };
127  template <>
128  struct default_widen<wchar_t> {
129  static wchar_t widen(char ch)
130  {
131  auto ret = std::btowc(static_cast<int>(ch));
132  if (ret == WEOF) {
133  return static_cast<wchar_t>(-1);
134  }
135  return static_cast<wchar_t>(ret);
136  }
137  };
138 
139  template <typename CharT>
141  template <>
142  struct default_narrow<char> {
143  static constexpr char narrow(char ch, char) noexcept
144  {
145  return ch;
146  }
147  };
148  template <>
149  struct default_narrow<wchar_t> {
150  static char narrow(wchar_t ch, char def)
151  {
152  auto ret = std::wctob(static_cast<wint_t>(ch));
153  if (ret == EOF) {
154  return def;
155  }
156  return static_cast<char>(ret);
157  }
158  };
159 
160  template <typename CharT>
162  template <>
163  struct locale_defaults<char> {
164  static constexpr string_view truename()
165  {
166  return {"true"};
167  }
168  static constexpr string_view falsename()
169  {
170  return {"false"};
171  }
172  static constexpr char decimal_point() noexcept
173  {
174  return '.';
175  }
176  static constexpr char thousands_separator() noexcept
177  {
178  return ',';
179  }
180  };
181  template <>
182  struct locale_defaults<wchar_t> {
183  static constexpr wstring_view truename()
184  {
185  return {L"true"};
186  }
187  static constexpr wstring_view falsename()
188  {
189  return {L"false"};
190  }
191  static constexpr wchar_t decimal_point() noexcept
192  {
193  return L'.';
194  }
195  static constexpr wchar_t thousands_separator() noexcept
196  {
197  return L',';
198  }
199  };
200  } // namespace detail
201 
203 
205  SCN_CLANG_IGNORE("-Wpadded")
206 
207  template <typename CharT>
209  public:
210  using char_type = CharT;
211  using string_type = std::basic_string<char_type>;
214 
215  constexpr basic_default_locale_ref() = default;
216 
217  constexpr bool is_space(char_type ch) const
218  {
219  return detail::is_space(ch);
220  }
221  constexpr bool is_digit(char_type ch) const
222  {
223  return detail::is_digit(ch);
224  }
225 
226  constexpr char_type decimal_point() const
227  {
228  return defaults::decimal_point();
229  }
230  constexpr char_type thousands_separator() const
231  {
232  return defaults::thousands_separator();
233  }
234 
235  constexpr string_view_type truename() const
236  {
237  return defaults::truename();
238  }
239  constexpr string_view_type falsename() const
240  {
241  return defaults::falsename();
242  }
243 
244  CharT widen(char ch) const
245  {
247  }
248  char narrow(CharT ch, char def) const
249  {
251  }
252 
253  template <typename T>
255  {
257  "No read_num with basic_default_locale_ref");
258  }
259  };
260 
261  template <typename CharT>
263  public:
264  using char_type = CharT;
265  using string_type = std::basic_string<char_type>;
267 
268  basic_locale_ref() = default;
269  basic_locale_ref(std::nullptr_t) : basic_locale_ref() {}
270  explicit basic_locale_ref(const void* loc);
271 
272  constexpr const void* get_ptr() const
273  {
274  return m_locale;
275  }
276 
277  bool is_space(char_type ch) const
278  {
279  if (SCN_LIKELY(is_default())) {
280  return detail::is_space(ch);
281  }
282  return _is_space(ch);
283  }
284  bool is_digit(char_type ch) const
285  {
286  if (SCN_LIKELY(is_default())) {
287  return detail::is_digit(ch);
288  }
289  return _is_digit(ch);
290  }
291 
292  constexpr char_type decimal_point() const
293  {
294  return m_decimal_point;
295  }
296  constexpr char_type thousands_separator() const
297  {
298  return m_thousands_separator;
299  }
300 
301  constexpr string_view_type truename() const
302  {
303  return string_view_type(m_truename.data(), m_truename.size());
304  }
305  constexpr string_view_type falsename() const
306  {
307  return string_view_type(m_falsename.data(), m_falsename.size());
308  }
309 
310  CharT widen(char ch) const
311  {
312  if (SCN_LIKELY(is_default())) {
314  }
315  return _widen(ch);
316  }
317  char narrow(CharT ch, char def) const
318  {
319  if (SCN_LIKELY(is_default())) {
321  }
322  return _narrow(ch, def);
323  }
324 
325  template <typename T>
326  expected<std::ptrdiff_t> read_num(T& val, const string_type& buf);
327 
328  constexpr bool is_default() const noexcept
329  {
330  return m_locale == nullptr;
331  }
332 
333  constexpr static basic_locale_ref get_default()
334  {
335  return basic_locale_ref();
336  }
337 
338  private:
339  bool _is_space(char_type) const;
340  bool _is_digit(char_type) const;
341  CharT _widen(char ch) const;
342  char _narrow(char_type ch, char def) const;
343 
344  using defaults = detail::locale_defaults<char_type>;
345 
346  const void* m_locale{nullptr};
347  detail::unique_ptr<detail::truename_falsename_storage<char_type>>
348  m_truefalse_storage{nullptr};
349  string_view_type m_truename{defaults::truename()};
350  string_view_type m_falsename{defaults::falsename()};
351  char_type m_decimal_point{defaults::decimal_point()};
352  char_type m_thousands_separator{defaults::thousands_separator()};
353  };
354 
358 } // namespace scn
359 
360 #if defined(SCN_HEADER_ONLY) && SCN_HEADER_ONLY && !defined(SCN_LOCALE_CPP)
361 #include "locale.cpp"
362 #endif
363 
364 #endif // SCN_DETAIL_LOCALE_H
constexpr string_view_type truename() const
Definition: locale.h:235
static constexpr char decimal_point() noexcept
Definition: locale.h:172
basic_string_view< char_type > string_view_type
Definition: locale.h:266
constexpr bool is_space(char_type ch) const
Definition: locale.h:217
basic_string_view< char_type > string_view_type
Definition: locale.h:36
static wchar_t widen(char ch)
Definition: locale.h:129
constexpr const_pointer data() const noexcept
Definition: string_view.h:155
#define SCN_END_NAMESPACE
Definition: config.h:406
static constexpr wstring_view truename()
Definition: locale.h:183
static constexpr string_view truename()
Definition: locale.h:164
basic_locale_ref(std::nullptr_t)
Definition: locale.h:269
constexpr string_view_type falsename() const
Definition: locale.h:305
char narrow(CharT ch, char def) const
Definition: locale.h:248
constexpr string_view_type get_true_view() const
Definition: locale.h:49
static constexpr basic_locale_ref get_default()
Definition: locale.h:333
#define SCN_CLANG_IGNORE(x)
Definition: config.h:150
std::basic_string< char_type > string_type
Definition: locale.h:211
CharT widen(char ch) const
Definition: locale.h:310
std::basic_string< char_type > string_type
Definition: locale.h:265
expected-like type.
Definition: result.h:180
bool is_digit(char_type ch) const
Definition: locale.h:284
expected< std::ptrdiff_t > read_num(T &val, const string_type &buf)
constexpr char_type decimal_point() const
Definition: locale.h:292
constexpr char_type thousands_separator() const
Definition: locale.h:296
static constexpr char thousands_separator() noexcept
Definition: locale.h:176
#define SCN_CLANG_POP
Definition: config.h:149
#define SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE
Definition: config.h:152
static constexpr wchar_t thousands_separator() noexcept
Definition: locale.h:195
CharT widen(char ch) const
Definition: locale.h:244
constexpr char_type decimal_point() const
Definition: locale.h:226
std::basic_string< char_type > string_type
Definition: locale.h:35
constexpr string_view_type get_false_view() const
Definition: locale.h:53
constexpr bool is_default() const noexcept
Definition: locale.h:328
Stream does not support the performed operation.
Definition: result.h:46
static constexpr wstring_view falsename()
Definition: locale.h:187
Error class.
Definition: result.h:32
static constexpr char widen(char ch) noexcept
Definition: locale.h:122
#define SCN_BEGIN_NAMESPACE
Definition: config.h:405
constexpr string_view_type truename() const
Definition: locale.h:301
constexpr char_type thousands_separator() const
Definition: locale.h:230
char narrow(CharT ch, char def) const
Definition: locale.h:317
constexpr const string_type & get_false_str() const
Definition: locale.h:44
static constexpr string_view falsename()
Definition: locale.h:168
constexpr bool is_digit(char ch) noexcept
Definition: locale.h:109
bool is_space(char ch) noexcept
Definition: locale.h:70
constexpr size_type size() const noexcept
Definition: string_view.h:160
constexpr const void * get_ptr() const
Definition: locale.h:272
#define SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE
Definition: config.h:151
bool is_space(char_type ch) const
Definition: locale.h:277
expected< std::ptrdiff_t > read_num(T &, const string_type &)
Definition: locale.h:254
constexpr bool has_zero(uint64_t v)
Definition: locale.h:63
constexpr string_view_type falsename() const
Definition: locale.h:239
#define SCN_LIKELY(x)
Definition: config.h:366
basic_locale_ref()=default
static char narrow(wchar_t ch, char def)
Definition: locale.h:150
constexpr const string_type & get_true_str() const
Definition: locale.h:40
constexpr bool is_digit(char_type ch) const
Definition: locale.h:221
static constexpr char narrow(char ch, char) noexcept
Definition: locale.h:143
#define SCN_CLANG_PUSH
Definition: config.h:148
static constexpr wchar_t decimal_point() noexcept
Definition: locale.h:191