一呼百應, "one call, a hundred responses"
Loading...
Searching...
No Matches
static_string.hpp
Go to the documentation of this file.
1#pragma once
2
11#include <string_view>
12#include <cstring>
13#include <fstream>
14#include <nlohmann/json.hpp>
15#include "attributes/common.hpp"
16#include "types.hpp"
17
18namespace ein {
19
20template <typename T, T...xs>
21struct reify {
22 static constexpr const T value[sizeof...(xs)+1] = {xs..., T() };
23};
24
25// forward declaration
26class static_c_string;
27
35
36template <
37 typename CharT,
38 typename Traits = std::char_traits<CharT>
39>
41 std::basic_string_view<CharT,Traits> view;
42
43public:
44 ein_inline constexpr
45 basic_static_string(std::basic_string_view<CharT,Traits> view)
46 : view(view) {}
47
48 friend class static_c_string;
49 using traits_type = Traits;
50 using value_type = CharT;
51 using pointer = CharT *;
52 using const_pointer = CharT const *;
53 using reference = CharT &;
54 using const_reference = CharT const &;
55 using const_iterator = CharT const *;
57 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
59 using size_type = std::size_t;
60 using difference_type = std::ptrdiff_t;
61
64
65 template <CharT...xs>
66 consteval explicit basic_static_string(std::integer_sequence<CharT,xs...>)
67 : view(reify<CharT,xs...>::value,sizeof...(xs)) {}
68
69 ein_inline constexpr
70 basic_static_string() noexcept = default;
71
72 ein_inline constexpr
73 basic_static_string(basic_static_string const &) noexcept = default;
74
75 ein_inline constexpr
76 basic_static_string(basic_static_string const &&) noexcept = default;
77
81
83 basic_static_string & operator = (basic_static_string const & that) noexcept = default;
84
86 basic_static_string & operator = (basic_static_string && that) noexcept = default;
87
88
92
94 operator CharT const * () const noexcept {
95 return view.data; // an extra invariant that its null terminated is maintained
96 }
97
99 operator std::basic_string_view<CharT,Traits>() const noexcept {
100 return view;
101 }
102
104 operator std::basic_string<CharT,Traits>() const noexcept {
105 return view;
106 }
107
111
114 CharT const & operator [](size_type i) const noexcept { return view[i]; }
115
118 CharT const & at(size_type i) const {
119 if (i >= view.size()) throw std::out_of_range("basic_static_string::at");
120 return view.at(i);
121 }
122
131 const_reference front() const noexcept { return view.front(); }
132
135 const_reference back() const noexcept { return view.back(); }
136
138 const_pointer data() const noexcept { return view.data(); }
139
143
145 size_type size() const noexcept { return view.size(); }
146
148 size_type length() const noexcept { return view.length(); }
149
151 size_type max_size() const noexcept { return view.max_size(); }
152
154 bool empty() const noexcept { return view.empty(); }
155
157 explicit operator bool () const noexcept { return view; }
158
165 if constexpr (std::is_same_v<Traits,std::char_traits<CharT>> && one_of_t<CharT,char,wchar_t,char8_t,char16_t,char32_t>) {
166 return self.view.data() == that.view.data();
167 } else {
168 return (self.view.data() == that.view.data()) || (self.view == that.view); // fallback required
169 }
170 }
171
175 if constexpr (std::is_same_v<Traits,std::char_traits<CharT>> && one_of_t<CharT,char,wchar_t,char8_t,char16_t,char32_t>) {
176 return self.view.data() != that.view.data();
177 } else {
178 return (self.view.data() != that.view.data()) && (self.view != that.view);
179 }
180 }
181
185
187 friend constexpr
188 basic_ostream<CharT, Traits> & operator<<(basic_ostream<CharT, Traits>& os, basic_static_string<CharT, Traits> v) {
189 return os << v.view;
190 }
191
192
196
198 auto begin() const noexcept { return view.begin(); }
199
201 auto end() const noexcept { return view.end(); }
202
204 auto cbegin() const noexcept { return view.cbegin(); }
205
207 auto cend() const noexcept { return view.cend(); }
208
210 auto rbegin() const noexcept { return view.rbegin(); }
211
213 auto rend() const noexcept { return view.rend(); }
214
216 auto crbegin() const noexcept { return view.crbegin(); }
217
219 auto crend() const noexcept { return view.crend(); }
220
222
223 ein_inline constexpr friend
225 using std::swap;
226 swap(x.view,y.view);
227 }
228
229 static constexpr size_type npos = std::basic_string_view<CharT,Traits>::npos;
230};
231
232template <typename CharT, typename Traits>
233void to_json(nlohmann::json& j, const basic_static_string<CharT,Traits>& s) {
234 j = std::string(s);
235}
236
238template <typename CharT, CharT...xs>
239basic_static_string(std::integer_sequence<CharT,xs...>) -> basic_static_string<CharT,std::char_traits<CharT>>;
246
252
254 const char * p;
255public:
256
257 using traits_type = std::char_traits<char>;
258 using value_type = char;
259 using pointer = char *;
260 using const_pointer = char const *;
261 using reference = char &;
262 using const_reference = char const &;
263 using const_iterator = char const *;
265 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
267 using size_type = std::size_t;
268 using difference_type = std::ptrdiff_t;
269
272
273 ein_inline constexpr
274 static_c_string() noexcept = default;
275
276 ein_inline constexpr
277 static_c_string(static_c_string const &) noexcept = default;
278
279 ein_inline constexpr
280 static_c_string(static_c_string &&) noexcept = default;
281
282 ein_inline constexpr
283 static_c_string(static_string x) noexcept : p(x.data()) {}
284
288
290 static_c_string & operator = (static_c_string const &) noexcept = default;
291
294
298
300 operator const char * () const noexcept { return p; }
301
303 operator static_string () const noexcept { return string_view(p); }
304
306 const char * data() const noexcept { return p; }
307
311
313 bool operator == (static_c_string x, static_c_string y) noexcept { return x.p == y.p; }
314
316 bool operator != (static_c_string x, static_c_string y) noexcept { return x.p != y.p; }
317
321
324 auto begin() const noexcept { return p; }
325
327 auto end() const noexcept { return p + strlen(p); }
328
331 auto cbegin() const noexcept { return p; }
332
335 auto cend() const noexcept { return p + strlen(p); }
336
339 auto rbegin() const noexcept { return std::reverse_iterator<const char *>(end()); }
340
343 auto rend() const noexcept { return std::reverse_iterator<const char *>(begin()); }
344
347 auto crbegin() const noexcept { return std::reverse_iterator<const char *>(end()); }
348
351 auto crend() const noexcept { return std::reverse_iterator<const char *>(begin()); }
352
354
355 ein_inline friend
356 void swap(static_c_string & x, static_c_string & y) noexcept {
357 using std::swap;
358 swap(x.p,y.p);
359 }
360 // Standard C++23 string literal operator
361};
362
363#ifdef __GNUC__
364# pragma GCC diagnostic push
365# pragma GCC diagnostic ignored "-Wpedantic"
366
367# ifdef __clang__
368# pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template"
369# endif
370#endif
371
372// this is the only method by which these are initially constructed
373// all other methods just trade them around
374
375template <class T, T ...xs>
376consteval basic_static_string<T,std::char_traits<T>> operator"" _ss() noexcept {
377 return basic_static_string<T,std::char_traits<T>>(std::integer_sequence<T,xs...>{});
378}
379
380template <one_of_t<char> T, T ...xs>
381consteval static_c_string operator"" _scs() noexcept {
382 return static_c_string(basic_static_string<T,std::char_traits<T>>(std::integer_sequence<T,xs...>{}));
383}
384
385#ifdef __GNUC__
386# pragma GCC diagnostic pop
387#endif
388
389inline void to_json(nlohmann::json& j, static_c_string const & s) {
390 j = std::string(s);
391}
392
393
394} // namespace ein
395
396namespace std {
397 template <typename CharT, typename Traits>
398 struct hash<::ein::basic_static_string<CharT,Traits>> {
399 constexpr size_t operator()(::ein::basic_static_string<CharT,Traits> const & s) const noexcept {
400 return reinterpret_cast<size_t>(s.data());
401 }
402 };
403 template <>
404 struct hash<::ein::static_c_string> {
405 constexpr size_t operator()(::ein::static_c_string s) const noexcept {
406 return reinterpret_cast<size_t>(s.data());
407 }
408 };
409 namespace ranges {
410
412 template< class CharT, class Traits >
413 inline constexpr bool enable_borrowed_range<::ein::basic_static_string<CharT, Traits>> = true;
414
415 template< class CharT, class Traits >
416 inline constexpr bool enable_view<::ein::basic_static_string<CharT, Traits>> = true;
417
418 template <>
419 inline constexpr bool enable_borrowed_range<::ein::static_c_string> = true;
420
421 template <>
422 inline constexpr bool enable_view<::ein::static_c_string> = true;
424 }
425} // namespace std
426
427#ifdef EIN_TESTING
428
429#define EIN_STR(name) \
430 (([]<typename CharT> static constexpr { \
431 if constexpr (std::is_same_v<CharT, char>) { \
432 return #name ## _ss; \
433 } else if constexpr (std::is_same_v<CharT, wchar_t>) { \
434 return L## #name ##_ss; \
435 } else if constexpr (std::is_same_v<CharT, char8_t>) { \
436 return u8## #name ##_ss; \
437 } else if constexpr (std::is_same_v<CharT, char16_t>) { \
438 return u## #name ##_ss; \
439 } else if constexpr (std::is_same_v<CharT, char32_t>) { \
440 return U## #name ##_ss; \
441 } \
442 }).template operator()<TestType>())
443
444TEMPLATE_TEST_CASE("static_string","[static_string]",char,wchar_t,char8_t,char16_t,char32_t) {
445 using namespace ein;
446 using string_t = basic_static_string<TestType>;
447
448 SECTION("constructors and conversions") {
449 // Test construction from literal
450 constexpr string_t str = EIN_STR(hello);
451 CHECK(str == EIN_STR(hello));
452 CHECK(str != EIN_STR(world));
453
454 // Data retrieval and null termination
455 CHECK(str.data()[5] == typename string_t::value_type(0));
456 }
457
458 SECTION("element access") {
459 constexpr string_t str = EIN_STR(abcdef);
460 CHECK(str.front() == 'a');
461 CHECK(str.back() == 'f');
462 CHECK(str[1] == 'b');
463 CHECK(str.at(2) == 'c');
464 }
465
466 SECTION("comparisons") {
467 constexpr string_t str1 = EIN_STR(compare);
468 constexpr string_t str2 = EIN_STR(compare);
469 constexpr string_t str3 = EIN_STR(different);
470
471 CHECK(str1 == str2);
472 CHECK(str1 != str3);
473 }
474
475 SECTION("iterators") {
476 constexpr string_t str = EIN_STR(iterate);
477 std::basic_string<TestType> result;
478 for (auto c : str)
479 result += c;
480 CHECK(result == EIN_STR(iterate).data());
481
482 // Reverse iteration
483 std::basic_string<typename string_t::value_type> reverse_result;
484 for (auto it = str.rbegin(); it != str.rend(); ++it)
485 reverse_result += *it;
486 CHECK(reverse_result == EIN_STR(etareti).data());
487 }
488
489 SECTION("I/O operations") {
490 constexpr string_t str = EIN_STR(output);
491 std::basic_ostringstream<TestType> oss;
492 oss << str;
493 CHECK(oss.str()[3] == 'p');
494 }
495}
496
497#undef EIN_STR
498#endif
statically known interned strings these have O(1) comparison for equality
constexpr auto cend() const noexcept
consteval basic_static_string(std::integer_sequence< CharT, xs... >)
constexpr friend void swap(basic_static_string &x, basic_static_string &y) noexcept
constexpr CharT const & at(size_type i) const
access the specified character with bounds checking
std::basic_string_view< CharT, Traits > view
constexpr auto cbegin() const noexcept
constexpr size_type length() const noexcept
constexpr basic_static_string(std::basic_string_view< CharT, Traits > view)
constexpr auto crbegin() const noexcept
friend constexpr bool operator==(basic_static_string self, basic_static_string that) noexcept
constexpr CharT const & operator[](size_type i) const noexcept
access the specified character
std::reverse_iterator< const_iterator > const_reverse_iterator
std::ptrdiff_t difference_type
constexpr const_pointer data() const noexcept
const_reverse_iterator reverse_iterator
constexpr basic_static_string() noexcept=default
constexpr bool empty() const noexcept
constexpr size_type size() const noexcept
constexpr const_reference front() const noexcept
Returns reference to the first character in the static_string.
constexpr auto begin() const noexcept
constexpr const_reference back() const noexcept
constexpr auto rend() const noexcept
constexpr auto end() const noexcept
constexpr auto crend() const noexcept
friend constexpr basic_ostream< CharT, Traits > & operator<<(basic_ostream< CharT, Traits > &os, basic_static_string< CharT, Traits > v)
input/output
static constexpr size_type npos
constexpr size_type max_size() const noexcept
constexpr auto rbegin() const noexcept
friend constexpr bool operator!=(basic_static_string self, basic_static_string that) noexcept
std::ptrdiff_t difference_type
constexpr auto crbegin() const noexcept
O(n)
constexpr friend bool operator!=(static_c_string x, static_c_string y) noexcept
std::reverse_iterator< const_iterator > const_reverse_iterator
constexpr auto end() const noexcept
friend void swap(static_c_string &x, static_c_string &y) noexcept
constexpr auto rbegin() const noexcept
O(n)
constexpr auto crend() const noexcept
O(1)
ein_reinitializes constexpr static_c_string & operator=(static_c_string const &) noexcept=default
constexpr auto begin() const noexcept
O(1)
char const * const_iterator
constexpr auto cend() const noexcept
O(1)
char const & const_reference
std::char_traits< char > traits_type
constexpr friend bool operator==(static_c_string x, static_c_string y) noexcept
constexpr const char * data() const noexcept
const_reverse_iterator reverse_iterator
constexpr auto rend() const noexcept
O(1)
constexpr static_c_string() noexcept=default
constexpr auto cbegin() const noexcept
O(1)
const_iterator iterator
type T is one of the candidates
Definition types.hpp:48
#define ein_reinitializes
[[clang::reinitializes]]
Definition common.hpp:418
#define ein_artificial
[[artificial]].
Definition common.hpp:220
#define ein_inline
inline [[always_inline]]
Definition common.hpp:188
#define ein_nodiscard
C++17 [[nodiscard]].
Definition common.hpp:165
#define ein_const
[[const]] is not const
Definition common.hpp:84
#define ein_pure
[[pure]]
Definition common.hpp:102
Definition cpuid.cpp:16
basic_static_string< char > static_string
void to_json(nlohmann::json &j, const basic_static_string< CharT, Traits > &s)
Definition bf16.cpp:11
static constexpr const T value[sizeof...(xs)+1]
constexpr size_t operator()(::ein::basic_static_string< CharT, Traits > const &s) const noexcept
constexpr size_t operator()(::ein::static_c_string s) const noexcept