docs
Loading...
Searching...
No Matches
StringSTL.h
Go to the documentation of this file.
1///
2/// Copyright (C) 2026 Ultralight, Inc. All rights reserved.
3/// A license is required for commercial use. https://ultralig.ht
4///
5///
6/// @file StringSTL.h
7///
8/// STL compatibility header for ultralight::String.
9///
10/// `#include <Ultralight/StringSTL.h>`
11///
12/// This optional header provides utility functions for converting between ultralight::String,
13/// std::string, and std::string_view. It also provides support for using ultralight::String
14/// with standard library containers and stream operators.
15///
16/// @pre This header requires C++17 or later.
17///
18/// ## Example
19///
20/// ```cpp
21/// #include <Ultralight/StringSTL.h>
22/// #include <string>
23/// #include <iostream>
24///
25/// ultralight::String myStr("Hello, world!");
26///
27/// // Convert ultralight::String to std::string
28/// std::string stdStr = ultralight::Convert(myStr);
29///
30/// // Convert std::string to ultralight::String
31/// ultralight::String backToUl = ultralight::Convert(stdStr);
32///
33/// // Print ultralight::String to std::cout
34/// std::cout << myStr << std::endl;
35/// ```
36///
37#pragma once
38#include <Ultralight/String.h>
39#include <istream>
40#include <ostream>
41#include <string>
42#include <string_view>
43#include <type_traits>
44
45namespace ultralight {
46
47///
48/// Trait to check if a type is a supported string-like type.
49///
50template <typename T>
51struct is_string_type : std::false_type {};
52
53template <> struct is_string_type<String> : std::true_type {};
54template <> struct is_string_type<std::string> : std::true_type {};
55template <> struct is_string_type<std::string_view> : std::true_type {};
56template <> struct is_string_type<const char*> : std::true_type {};
57
58///
59/// Convert between string types.
60///
61/// This function provides efficient conversion between different string types.
62/// It supports ultralight::String, std::string, std::string_view, and const char*.
63///
64/// The following type conversions are automatically deduced (no template argument needed):
65/// - ultralight::String -> std::string
66/// - std::string -> ultralight::String
67/// - std::string_view -> ultralight::String
68/// - const char* -> ultralight::String
69///
70/// For explicit conversion to std::string_view, use Convert<std::string_view>().
71///
72/// @tparam To The target string type (optional, deduced in common cases)
73/// @tparam From The source string type (optional)
74///
75/// @param from The string to convert
76///
77/// @return The converted string in the target type
78///
79/// ## Example
80///
81/// ```cpp
82/// ultralight::String myStr("Hello, world!");
83///
84/// // ultralight::String -> std::string
85/// std::string stdStr = ultralight::Convert(myStr);
86///
87/// // ultralight::String -> std::string_view
88/// std::string_view svStr = ultralight::Convert<std::string_view>(myStr);
89///
90/// // std::string -> ultralight::String
91/// ultralight::String backToUl = ultralight::Convert(stdStr);
92///
93/// // std::string_view -> ultralight::String
94/// ultralight::String fromView = ultralight::Convert(std::string_view("View"));
95///
96/// // String literal -> ultralight::String
97/// ultralight::String fromLiteral = ultralight::Convert("literal");
98/// ```
99///
100template <typename To = void, typename From>
101auto Convert(const From& from) {
102 // String literals (char[N]) and char* pointers normalize to const char*, so
103 // Convert("literal") works directly.
104 using SourceT = std::remove_cv_t<std::remove_reference_t<From>>;
105 using Src = std::conditional_t<std::is_same_v<std::decay_t<SourceT>, char*>
106 || std::is_same_v<std::decay_t<SourceT>, const char*>,
107 const char*, SourceT>;
108 static_assert(is_string_type<Src>::value,
109 "Convert only supports String, std::string, std::string_view, and const char*");
110
111 if constexpr (std::is_same_v<To, void>) {
112 // Automatic deduction
113 if constexpr (std::is_same_v<Src, String>) {
114 return std::string(from.utf8().data(), from.utf8().length());
115 } else if constexpr (std::is_same_v<Src, std::string> ||
116 std::is_same_v<Src, std::string_view>) {
117 return String(from.data(), from.length());
118 } else if constexpr (std::is_same_v<Src, const char*>) {
119 return String(from); // String constructor handles null-termination
120 } else {
121 // This case should never be reached due to the static_assert
122 return Src{};
123 }
124 } else {
125 // Explicit conversion
126 static_assert(is_string_type<To>::value,
127 "Convert only supports String, std::string, std::string_view, and const char*");
128
129 if constexpr (std::is_same_v<To, Src>) {
130 return To(from);
131 } else if constexpr (std::is_same_v<To, String>) {
132 if constexpr (std::is_same_v<Src, const char*>) {
133 return String(from); // String constructor handles null-termination
134 } else {
135 return String(from.data(), from.length());
136 }
137 } else if constexpr (std::is_same_v<To, std::string>) {
138 if constexpr (std::is_same_v<Src, String>) {
139 return std::string(from.utf8().data(), from.utf8().length());
140 } else if constexpr (std::is_same_v<Src, const char*>) {
141 return std::string(from); // std::string constructor handles null-termination
142 } else {
143 return std::string(from);
144 }
145 } else if constexpr (std::is_same_v<To, std::string_view>) {
146 if constexpr (std::is_same_v<Src, String>) {
147 return std::string_view(from.utf8().data(), from.utf8().length());
148 } else if constexpr (std::is_same_v<Src, const char*>) {
149 return std::string_view(from); // std::string_view constructor handles null-termination
150 } else {
151 return std::string_view(from);
152 }
153 } else if constexpr (std::is_same_v<To, const char*>) {
154 static_assert(!std::is_same_v<To, const char*>,
155 "Direct conversion to const char* is not supported due to ownership issues. "
156 "Convert to String, std::string, or std::string_view instead.");
157 } else {
158 // This case should never be reached due to the static_assert
159 return To{};
160 }
161 }
162}
163
164} // namespace ultralight
165
166namespace std {
167
168///
169/// Hash specialization for ultralight::String
170///
171template<>
172struct hash<ultralight::String> {
173 size_t operator()(const ultralight::String& str) const {
174 return str.Hash();
175 }
176};
177
178} // namespace std
179
180///
181/// Stream output operator for ultralight::String.
182///
183/// @param os The output stream.
184///
185/// @param str The string to output.
186///
187/// @return The output stream.
188///
189inline std::ostream& operator<<(std::ostream& os, const ultralight::String& str) {
190 return os << ultralight::Convert<std::string_view>(str);
191}
192
193///
194/// Stream input operator for ultralight::String.
195///
196/// @param is The input stream.
197///
198/// @param str The string to input into.
199///
200/// @return The input stream.
201///
202inline std::istream& operator>>(std::istream& is, ultralight::String& str) {
203 std::string temp;
204 is >> temp;
206 return is;
207}
std::ostream & operator<<(std::ostream &os, const ultralight::String &str)
Stream output operator for ultralight::String.
Definition StringSTL.h:189
std::istream & operator>>(std::istream &is, ultralight::String &str)
Stream input operator for ultralight::String.
Definition StringSTL.h:202
Unicode string container with conversions for UTF-8, UTF-16, and UTF-32.
Definition String.h:31
String()
Create empty string.
size_t Hash() const
Hash function.
Definition StringSTL.h:166
Root namespace for every public Ultralight type, function, and enumeration.
auto Convert(const From &from)
Convert between string types.
Definition StringSTL.h:101
size_t operator()(const ultralight::String &str) const
Definition StringSTL.h:173
Trait to check if a type is a supported string-like type.
Definition StringSTL.h:51