mimic++ v2
Loading...
Searching...
No Matches
String.hpp
Go to the documentation of this file.
1// // Copyright Dominic (DNKpp) Koepke 2024 - 2024.
2// // Distributed under the Boost Software License, Version 1.0.
3// // (See accompanying file LICENSE_1_0.txt or copy at
4// // https://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef MIMICPP_STRING_HPP
7#define MIMICPP_STRING_HPP
8
9#pragma once
10
11#include "mimic++/Fwd.hpp"
12#include "mimic++/Utility.hpp"
13
14#include <bit>
15#include <concepts>
16#include <functional>
17#include <ranges>
18#include <string>
19#include <string_view>
20#include <type_traits>
21
22namespace mimicpp
23{
43 template <typename T>
45 : public std::false_type
46 {
47 };
48
53 template <typename T>
54 inline constexpr bool is_character_v{is_character<T>::value};
55
59 template <>
60 struct is_character<char>
61 : public std::true_type
62 {
63 };
64
68 template <>
69 struct is_character<signed char>
70 : public std::true_type
71 {
72 };
73
77 template <>
78 struct is_character<unsigned char>
79 : public std::true_type
80 {
81 };
82
86 template <>
87 struct is_character<wchar_t>
88 : public std::true_type
89 {
90 };
91
95 template <>
96 struct is_character<char8_t>
97 : public std::true_type
98 {
99 };
100
104 template <>
105 struct is_character<char16_t>
106 : public std::true_type
107 {
108 };
109
113 template <>
114 struct is_character<char32_t>
115 : public std::true_type
116 {
117 };
118
136 template <typename T>
137 using string_view_t = decltype(string_traits<std::remove_cvref_t<T>>::view(std::declval<T&>()));
138
143 template <typename T>
145
150 template <typename T>
151 requires std::is_pointer_v<T>
153 struct string_traits<T>
154 {
155 using char_t = std::remove_const_t<std::remove_pointer_t<T>>;
156 using view_t = std::basic_string_view<char_t>;
157
158 [[nodiscard]]
159 static constexpr view_t view(const std::remove_pointer_t<T>* str) noexcept
160 {
161 return view_t{str};
162 }
163 };
164
169 template <typename T>
170 requires std::is_array_v<T>
172 : public string_traits<std::remove_extent_t<T>*>
173 {
174 };
175
180 template <typename Char, typename Traits, typename Allocator>
181 struct string_traits<std::basic_string<Char, Traits, Allocator>>
182 {
183 using char_t = Char;
184 using string_t = std::basic_string<Char, Traits, Allocator>;
185 using view_t = std::basic_string_view<Char, Traits>;
186
187 [[nodiscard]]
188 static constexpr view_t view(const string_t& str) noexcept
189 {
190 return view_t{str};
191 }
192 };
193
198 template <typename Char, typename Traits>
199 struct string_traits<std::basic_string_view<Char, Traits>>
200 {
201 using char_t = Char;
202 using view_t = std::basic_string_view<Char, Traits>;
203
204 [[nodiscard]]
205 static constexpr view_t view(view_t str) noexcept
206 {
207 return str;
208 }
209 };
210
220 template <typename T>
221 concept string = requires
222 {
224 requires std::ranges::contiguous_range<string_view_t<T>>;
225 requires std::ranges::sized_range<string_view_t<T>>;
226 requires std::ranges::borrowed_range<string_view_t<T>>;
227 requires std::same_as<
229 std::ranges::range_value_t<string_view_t<T>>>;
230 };
231
251 template <satisfies<is_character> Char>
253
259 template <typename String>
262 && requires(const string_case_fold_converter<string_char_t<String>> converter, string_view_t<String> view)
263 {
264 { std::invoke(converter, std::move(view)) } -> std::ranges::forward_range;
265 }
266 && requires(std::invoke_result_t<string_case_fold_converter<string_char_t<String>>, string_view_t<String>> normalized)
267 {
268 requires std::same_as<
270 std::ranges::range_value_t<decltype(normalized)>>;
271 };
272}
273
274namespace mimicpp::detail
275{
276 template <typename View, typename Char>
277 concept compatible_string_view_with = is_character_v<Char>
278 && std::ranges::borrowed_range<View>
279 && std::ranges::contiguous_range<View>
280 && std::ranges::sized_range<View>
281 && std::same_as<Char, std::ranges::range_value_t<View>>;
282}
283
284#ifndef MIMICPP_CONFIG_EXPERIMENTAL_UNICODE_STR_MATCHER
285
290template <>
292{
293 template <detail::compatible_string_view_with<char> String>
294 [[nodiscard]]
295 constexpr auto operator ()(String&& str) const
296 {
297 return std::views::all(std::forward<String>(str))
298 | std::views::transform(
299 [](const char c) noexcept
300 {
301 // see notes of https://en.cppreference.com/w/cpp/string/byte/toupper
302 // This approach will fail, str actually contains an utf8-encoded string.
303 return static_cast<char>(
304 static_cast<unsigned char>(std::toupper(c)));
305 });
306 }
307};
308
309#else
310
311// is missing from the unicodelib headers
312#include <cstdint>
313
314#include <unicodelib.h>
315#include <unicodelib_encodings.h>
316
321template <>
323{
324 template <detail::compatible_string_view_with<char> String>
325 [[nodiscard]]
326 constexpr auto operator ()(String&& str) const
327 {
328 return unicode::utf8::encode(
329 unicode::to_case_fold(
330 unicode::utf8::decode(
331 std::string_view{
332 std::ranges::data(str),
333 std::ranges::size(str)
334 })));
335 }
336};
337
342template <>
344{
345 template <detail::compatible_string_view_with<wchar_t> String>
346 [[nodiscard]]
347 constexpr auto operator ()(String&& str) const
348 {
349 return unicode::to_wstring(
350 unicode::to_case_fold(
351 unicode::to_utf32(
352 std::wstring_view{
353 std::ranges::data(str),
354 std::ranges::size(str)
355 })));
356 }
357};
358
363template <>
365{
366 template <detail::compatible_string_view_with<char8_t> String>
367 [[nodiscard]]
368 constexpr auto operator ()(String&& str) const
369 {
370 const std::string caseFolded = std::invoke(
372 std::string_view{
373 std::bit_cast<const char*>(std::ranges::data(str)),
374 std::ranges::size(str)
375 });
376
377 return std::u8string{
378 caseFolded.cbegin(),
379 caseFolded.cend()
380 };
381 }
382};
383
388template <>
390{
391 template <detail::compatible_string_view_with<char16_t> String>
392 [[nodiscard]]
393 constexpr auto operator ()(String&& str) const
394 {
395 return unicode::utf16::encode(
396 unicode::to_case_fold(
397 unicode::utf16::decode(
398 std::u16string_view{
399 std::ranges::data(str),
400 std::ranges::size(str)
401 })));
402 }
403};
404
409template <>
411{
412 template <detail::compatible_string_view_with<char32_t> String>
413 [[nodiscard]]
414 constexpr auto operator ()(String&& str) const
415 {
416 return unicode::to_case_fold(
417 std::u32string_view{
418 std::ranges::data(str),
419 std::ranges::size(str)
420 });
421 }
422};
423
424#endif
425
426#endif
Determines, whether the given type supports string normalization.
Definition String.hpp:260
Determines, whether the given type can be used as a string-type.
Definition String.hpp:221
constexpr bool is_character_v
Convenience boolean-constant to the result of is_character trait.
Definition String.hpp:54
decltype(string_traits< std::remove_cvref_t< T > >::view(std::declval< T & >())) string_view_t
Computes the view type for the given string.
Definition String.hpp:137
typename string_traits< std::remove_cvref_t< T > >::char_t string_char_t
Computes the character type for the given string.
Definition String.hpp:144
Definition BoostTest.hpp:20
Primary template, which always yields false.
Definition String.hpp:46
Primary template, purposely undefined.
Definition String.hpp:252
std::remove_const_t< std::remove_pointer_t< T > > char_t
Definition String.hpp:155
std::basic_string_view< char_t > view_t
Definition String.hpp:156
static constexpr view_t view(const std::remove_pointer_t< T > *str) noexcept
Definition String.hpp:159
std::basic_string_view< Char, Traits > view_t
Definition String.hpp:185
std::basic_string< Char, Traits, Allocator > string_t
Definition String.hpp:184
static constexpr view_t view(const string_t &str) noexcept
Definition String.hpp:188
static constexpr view_t view(view_t str) noexcept
Definition String.hpp:205
std::basic_string_view< Char, Traits > view_t
Definition String.hpp:202
Definition Fwd.hpp:73