3 #include "fly/concepts/concepts.hpp"
4 #include "fly/types/string/concepts.hpp"
5 #include "fly/types/string/detail/classifier.hpp"
6 #include "fly/types/string/detail/converter.hpp"
7 #include "fly/types/string/detail/format_context.hpp"
8 #include "fly/types/string/detail/format_parameters.hpp"
9 #include "fly/types/string/detail/format_parse_context.hpp"
10 #include "fly/types/string/detail/format_specifier.hpp"
11 #include "fly/types/string/detail/format_string.hpp"
12 #include "fly/types/string/detail/traits.hpp"
13 #include "fly/types/string/detail/unicode.hpp"
14 #include "fly/types/string/formatters.hpp"
15 #include "fly/types/string/literals.hpp"
29 #include <type_traits>
34 template <StandardCharacter CharType>
37 using String = BasicString<char>;
38 using WString = BasicString<wchar_t>;
39 using String8 = BasicString<char8_t>;
40 using String16 = BasicString<char16_t>;
41 using String32 = BasicString<char32_t>;
49 template <StandardCharacter CharType>
56 using string_type =
typename traits::string_type;
57 using size_type =
typename traits::size_type;
58 using char_type =
typename traits::char_type;
59 using view_type =
typename traits::view_type;
60 using int_type =
typename traits::int_type;
61 using codepoint_type =
typename traits::codepoint_type;
63 template <
typename... ParameterTypes>
77 template <StandardStringLike T>
78 static constexpr size_type
size(T &&value);
92 static constexpr
bool is_alpha(char_type ch);
106 static constexpr
bool is_upper(char_type ch);
120 static constexpr
bool is_lower(char_type ch);
134 static constexpr char_type
to_upper(char_type ch);
148 static constexpr char_type
to_lower(char_type ch);
161 static constexpr
bool is_digit(char_type ch);
174 static constexpr
bool is_x_digit(char_type ch);
188 static constexpr
bool is_space(char_type ch);
198 static std::vector<string_type>
split(view_type input, char_type delimiter);
210 static std::vector<string_type>
split(view_type input, char_type delimiter, size_type count);
217 static void trim(string_type &target);
226 static void replace_all(string_type &target, view_type search, char_type replace);
235 static void replace_all(string_type &target, view_type search, view_type replace);
243 static void remove_all(string_type &target, view_type search);
262 static bool validate(view_type value);
276 template <
typename IteratorType>
277 static std::optional<codepoint_type>
288 static std::optional<string_type>
encode_codepoint(codepoint_type codepoint);
314 template <
char UnicodePrefix = 'U'>
315 requires fly::UnicodePrefixCharacter<UnicodePrefix>
346 template <
char UnicodePrefix = 'U',
typename IteratorType>
347 requires fly::UnicodePrefixCharacter<UnicodePrefix>
348 static std::optional<string_type>
escape_codepoint(IteratorType &it,
const IteratorType &end);
385 template <
typename IteratorType>
503 template <
typename... ParameterTypes>
522 template <
typename OutputIterator,
typename... ParameterTypes>
524 OutputIterator output,
526 ParameterTypes &&...parameters);
538 template <
typename... Args>
539 static string_type
join(char_type separator, Args &&...args);
552 template <
typename T>
553 static std::optional<T>
convert(
const string_type &value);
559 template <
typename T,
typename... Args>
560 static void join_internal(string_type &result, char_type separator, T &&value, Args &&...args);
565 template <
typename T>
566 static void join_internal(string_type &result, char_type separator, T &&value);
571 static constexpr
const char_type *s_alpha_num =
572 FLY_STR(char_type,
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
574 static constexpr size_type s_alpha_num_length =
575 std::char_traits<char_type>::length(s_alpha_num);
577 static constexpr
const auto s_left_brace = FLY_CHR(char_type,
'{');
578 static constexpr
const auto s_right_brace = FLY_CHR(char_type,
'}');
582 template <StandardCharacter CharType>
583 template <StandardStringLike T>
590 template <StandardCharacter CharType>
597 template <StandardCharacter CharType>
604 template <StandardCharacter CharType>
611 template <StandardCharacter CharType>
618 template <StandardCharacter CharType>
625 template <StandardCharacter CharType>
632 template <StandardCharacter CharType>
639 template <StandardCharacter CharType>
646 template <StandardCharacter CharType>
649 return split(input, delimiter, 0);
653 template <StandardCharacter CharType>
655 -> std::vector<string_type>
657 std::vector<string_type> elements;
661 size_type end = input.find(delimiter);
663 auto push_item = [&elements, &count, &delimiter](view_type str) {
666 if ((count > 0) && (elements.size() == count))
668 elements.back() += delimiter;
669 elements.back() += str;
673 elements.push_back(string_type(str));
678 while (end != string_type::npos)
680 item = input.substr(start, end - start);
684 end = input.find(delimiter, start);
687 item = input.substr(start, end);
694 template <StandardCharacter CharType>
697 auto is_non_space = [](
auto ch) {
698 return !is_space(ch);
702 target.erase(target.begin(), std::find_if(target.begin(), target.end(), is_non_space));
705 target.erase(std::find_if(target.rbegin(), target.rend(), is_non_space).base(), target.end());
709 template <StandardCharacter CharType>
712 size_type index = target.find(search);
714 while (!search.empty() && (index != string_type::npos))
716 target.replace(index, search.size(), 1, replace);
717 index = target.find(search);
722 template <StandardCharacter CharType>
725 size_type index = target.find(search);
727 while (!search.empty() && (index != string_type::npos))
729 target.replace(index, search.size(), replace);
730 index = target.find(search);
735 template <StandardCharacter CharType>
738 replace_all(target, search, view_type {});
742 template <StandardCharacter CharType>
745 static constexpr char_type s_wildcard =
'*';
746 bool result = !search.empty();
748 const std::vector<string_type> segments = split(search, s_wildcard);
751 if (!segments.empty())
753 if (result && (search.front() != s_wildcard))
755 result = source.starts_with(segments.front());
757 if (result && (search.back() != s_wildcard))
759 result = source.ends_with(segments.back());
762 for (
auto it = segments.begin(); result && (it != segments.end()); ++it)
764 index = source.find(*it, index);
766 if (index == string_type::npos)
777 template <StandardCharacter CharType>
780 auto it = value.cbegin();
781 const auto end = value.cend();
783 return unicode::validate_encoding(it, end);
787 template <StandardCharacter CharType>
788 template <
typename IteratorType>
790 -> std::optional<codepoint_type>
792 return unicode::decode_codepoint(it, end);
796 template <StandardCharacter CharType>
798 -> std::optional<string_type>
800 return unicode::encode_codepoint(codepoint);
804 template <StandardCharacter CharType>
805 template <
char UnicodePrefix>
806 requires fly::UnicodePrefixCharacter<UnicodePrefix>
810 result.reserve(value.size());
812 const auto end = value.cend();
814 for (
auto it = value.cbegin(); it != end;)
816 if (
auto escaped = escape_codepoint<UnicodePrefix>(it, end); escaped)
818 result += *std::move(escaped);
830 template <StandardCharacter CharType>
831 template <
char UnicodePrefix,
typename IteratorType>
832 requires fly::UnicodePrefixCharacter<UnicodePrefix>
834 -> std::optional<string_type>
836 return unicode::template escape_codepoint<UnicodePrefix>(it, end);
840 template <StandardCharacter CharType>
844 result.reserve(value.size());
846 const auto end = value.cend();
848 for (
auto it = value.cbegin(); it != end;)
850 if ((*it ==
'\\') && ((it + 1) != end))
854 case FLY_CHR(char_type,
'u'):
855 case FLY_CHR(char_type,
'U'):
857 if (
auto unescaped = unescape_codepoint(it, end); unescaped)
859 result += *std::move(unescaped);
884 template <StandardCharacter CharType>
885 template <
typename IteratorType>
887 -> std::optional<string_type>
889 return unicode::unescape_codepoint(it, end);
893 template <StandardCharacter CharType>
896 using short_distribution = std::uniform_int_distribution<short>;
898 constexpr
auto limit =
static_cast<short_distribution::result_type
>(s_alpha_num_length - 1);
899 static_assert(limit > 0);
901 static thread_local
const auto s_now = std::chrono::system_clock::now().time_since_epoch();
902 static thread_local
const auto s_seed =
static_cast<std::mt19937::result_type
>(s_now.count());
904 static thread_local std::mt19937 s_engine(s_seed);
905 short_distribution distribution(0, limit);
908 result.reserve(length);
910 while (length-- != 0)
912 result.push_back(s_alpha_num[distribution(s_engine)]);
919 template <StandardCharacter CharType>
920 template <
typename... ParameterTypes>
925 string_type formatted;
926 formatted.reserve(fmt.context().view().size() * 2);
929 std::back_inserter(formatted),
931 std::forward<ParameterTypes>(parameters)...);
937 template <StandardCharacter CharType>
938 template <
typename OutputIterator,
typename... ParameterTypes>
940 OutputIterator output,
942 ParameterTypes &&...parameters)
947 FormatParseContext &parse_context = fmt.context();
948 const view_type view = parse_context.
view();
950 if (parse_context.has_error())
954 FLY_ARR(char_type,
"Ignored invalid formatter: {}"),
955 parse_context.error());
961 detail::make_format_parameters<FormatContext>(std::forward<ParameterTypes>(parameters)...);
962 FormatContext context(output, params);
964 for (std::size_t pos = 0; pos < view.size();)
966 switch (
const auto &ch = view[pos])
969 if (view[pos + 1] == s_left_brace)
971 *context.out()++ = ch;
976 auto specifier = *std::move(fmt.next_specifier());
977 pos += specifier.m_size;
979 const auto parameter = context.arg(specifier.m_position);
980 parameter.format(parse_context, context, std::move(specifier));
985 *context.out()++ = ch;
990 *context.out()++ = ch;
998 template <StandardCharacter CharType>
999 template <
typename... Args>
1003 join_internal(result, separator, std::forward<Args>(args)...);
1009 template <StandardCharacter CharType>
1010 template <
typename T,
typename... Args>
1011 inline void BasicString<CharType>::join_internal(
1012 string_type &result,
1013 char_type separator,
1017 result += format(FLY_ARR(char_type,
"{}{}"), std::forward<T>(value), separator);
1018 join_internal(result, separator, std::forward<Args>(args)...);
1022 template <StandardCharacter CharType>
1023 template <
typename T>
1024 inline void BasicString<CharType>::join_internal(string_type &result, char_type, T &&value)
1026 result += format(FLY_ARR(char_type,
"{}"), std::forward<T>(value));
1030 template <StandardCharacter CharType>
1031 template <
typename T>
1034 if constexpr (StandardString<T>)
1036 return unicode::template convert_encoding<T>(value);
1038 else if constexpr (fly::SameAs<char_type, char>)
1044 if (
auto result = unicode::template convert_encoding<std::string>(value); result)
1049 return std::nullopt;
Definition: string.hpp:51
static void remove_all(string_type &target, view_type search)
Definition: string.hpp:736
static string_type format(FormatString< ParameterTypes... > &&fmt, ParameterTypes &&...parameters)
static constexpr bool is_upper(char_type ch)
Definition: string.hpp:598
static std::optional< string_type > unescape_codepoint(IteratorType &it, const IteratorType &end)
static std::optional< T > convert(const string_type &value)
Definition: string.hpp:1032
static void replace_all(string_type &target, view_type search, char_type replace)
Definition: string.hpp:710
requires static fly::UnicodePrefixCharacter< UnicodePrefix > std::optional< string_type > escape_all_codepoints(view_type value)
static constexpr bool is_space(char_type ch)
Definition: string.hpp:640
static constexpr size_type size(T &&value)
static std::optional< string_type > unescape_all_codepoints(view_type value)
Definition: string.hpp:841
static constexpr bool is_alpha(char_type ch)
Definition: string.hpp:591
static string_type generate_random_string(size_type length)
Definition: string.hpp:894
static std::optional< string_type > encode_codepoint(codepoint_type codepoint)
Definition: string.hpp:797
static constexpr char_type to_lower(char_type ch)
Definition: string.hpp:626
static constexpr bool is_digit(char_type ch)
Definition: string.hpp:612
static bool validate(view_type value)
Definition: string.hpp:778
static void trim(string_type &target)
Definition: string.hpp:695
static std::optional< codepoint_type > decode_codepoint(IteratorType &it, const IteratorType &end)
static void format_to(OutputIterator output, FormatString< ParameterTypes... > &&fmt, ParameterTypes &&...parameters)
Definition: string.hpp:939
static constexpr char_type to_upper(char_type ch)
Definition: string.hpp:619
static string_type join(char_type separator, Args &&...args)
static std::vector< string_type > split(view_type input, char_type delimiter)
Definition: string.hpp:647
requires static fly::UnicodePrefixCharacter< UnicodePrefix > std::optional< string_type > escape_codepoint(IteratorType &it, const IteratorType &end)
static constexpr bool is_lower(char_type ch)
Definition: string.hpp:605
static bool wildcard_match(view_type source, view_type search)
Definition: string.hpp:743
static constexpr bool is_x_digit(char_type ch)
Definition: string.hpp:633
static constexpr bool is_digit(CharType ch)
Definition: classifier.hpp:261
static constexpr bool is_lower(CharType ch)
Definition: classifier.hpp:230
static constexpr bool is_space(CharType ch)
Definition: classifier.hpp:276
static constexpr CharType to_upper(CharType ch)
Definition: classifier.hpp:237
static constexpr CharType to_lower(CharType ch)
Definition: classifier.hpp:249
static constexpr bool is_alpha(CharType ch)
Definition: classifier.hpp:216
static constexpr bool is_x_digit(CharType ch)
Definition: classifier.hpp:268
static constexpr size_type size(T &&value)
static constexpr bool is_upper(CharType ch)
Definition: classifier.hpp:223
Definition: format_context.hpp:21
Definition: format_parse_context.hpp:22
constexpr view_type view() const
Definition: format_parse_context.hpp:179
Definition: unicode.hpp:31
Definition: traits.hpp:18
Definition: converter.hpp:26