Lightweight 0.20260303.0
Loading...
Searching...
No Matches
SqlDynamicString.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "../SqlColumnTypeDefinitions.hpp"
6#include "../Utils.hpp"
7#include "Core.hpp"
8#include "StringInterface.hpp"
9#include "UnicodeConverter.hpp"
10
11#include <format>
12#include <limits>
13#include <string>
14
15namespace Lightweight
16{
17
18constexpr size_t SqlMaxColumnSize = (std::numeric_limits<uint32_t>::max)();
19
20/// SQL dynamic-capacity string that mimmicks standard library string.
21///
22/// The underlying memory is allocated dynamically and the string can grow up to the maximum size of a specified size.
23///
24/// @ingroup DataTypes
25template <std::size_t N, typename T = char>
27{
28 public:
29 /// constexpr variable with the capacity of the string.
30 static constexpr std::size_t DynamicCapacity = N;
31
32 /// The element type of the string.
33 using value_type = T;
34
35 /// String type used for the internal storage of the string.
36 using string_type = std::basic_string<T>;
37
38 /// Iterator type for the string.
39 using iterator = string_type::iterator;
40 /// Const iterator type for the string.
41 using const_iterator = string_type::const_iterator;
42 /// Pointer type for the string.
43 using pointer_type = T*;
44 /// Const pointer type for the string.
45 using const_pointer_type = T const*;
46
47 /// Constructs a fixed-size string from a string literal.
48 template <std::size_t SourceSize>
49 constexpr LIGHTWEIGHT_FORCE_INLINE SqlDynamicString(T const (&text)[SourceSize]):
50 _value { text, SourceSize - 1 }
51 {
52 static_assert(SourceSize <= N + 1, "RHS string size must not exceed target string's capacity.");
53 }
54
55 /// Constructs a fixed-size string from a string pointer and end pointer.
56 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(T const* s, T const* e) noexcept:
57 _value { s, e }
58 {
59 }
60
61 /// Defaulted default constructor.
62 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString() noexcept = default;
63
64 /// Defaulted copy constructor.
65 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(SqlDynamicString const&) noexcept = default;
66
67 /// Defaulted copy assignment operator.
68 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString& operator=(SqlDynamicString const&) noexcept = default;
69
70 /// Defaulted move constructor.
71 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(SqlDynamicString&&) noexcept = default;
72
73 /// Defaulted move assignment operator.
74 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString& operator=(SqlDynamicString&&) noexcept = default;
75
76 /// Defaulted destructor.
77 LIGHTWEIGHT_FORCE_INLINE constexpr ~SqlDynamicString() noexcept = default;
78
79 /// Constructs a fixed-size string from a string view.
80 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(std::basic_string_view<T> s) noexcept:
81 _value { s }
82 {
83 }
84
85 /// Constructs a fixed-size string from a string.
86 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(std::basic_string<T> const& s) noexcept:
87 _value { s }
88 {
89 }
90
91 /// Returns a string view of the string.
92 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view<T> str() const noexcept
93 {
94 return std::basic_string_view<T> { data(), size() };
95 }
96
97 /// Retrieves the string's inner value (std::basic_string<T>).
98 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE string_type const& value() const noexcept
99 {
100 return _value;
101 }
102
103 /// Retrieves the string's inner value (std::basic_string<T>).
104 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE string_type& value() noexcept
105 {
106 return _value;
107 }
108
109 /// Retrieves the string's inner value (as T const*).
110 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE T const* data() const noexcept
111 {
112 return _value.data();
113 }
114
115 /// Retrieves the string's inner value (as T*).
116 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE T* data() noexcept
117 {
118 return _value.data();
119 }
120
121 /// Retrieves the string's inner value (as T const*).
122 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE T const* c_str() const noexcept
123 {
124 return _value.c_str();
125 }
126
127 /// Retrieves the string's capacity.
128 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE std::size_t capacity() const noexcept
129 {
130 return N;
131 }
132
133 /// Retrieves the string's size.
134 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE std::size_t size() const noexcept
135 {
136 return _value.size();
137 }
138
139 /// Tests if the string is empty.
140 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr bool empty() const noexcept
141 {
142 return _value.empty();
143 }
144
145 /// Clears the string.
146 LIGHTWEIGHT_FORCE_INLINE constexpr void clear() noexcept
147 {
148 _value.clear();
149 }
150
151 /// Reserves capacity for at least the given number of characters.
152 LIGHTWEIGHT_FORCE_INLINE void reserve(std::size_t capacity)
153 {
154 _value.reserve(capacity);
155 }
156
157 /// Appends a character to the end of the string.
158 LIGHTWEIGHT_FORCE_INLINE constexpr void push_back(T c) noexcept
159 {
160 _value += c;
161 }
162
163 /// Removes the last character from the string.
164 LIGHTWEIGHT_FORCE_INLINE constexpr void pop_back() noexcept
165 {
166 _value.pop_back();
167 }
168
169 /// Resizes the string to contain at most n characters. If n is less than the current size of the string,
170 /// the string is reduced to its first n characters. If n is greater than the current size of the string,
171 /// the string is resized to contain N characters, with the new characters being default-inserted (value-initialized).
172 // NOLINTNEXTLINE(readability-identifier-naming)
173 LIGHTWEIGHT_FORCE_INLINE void setsize(std::size_t n) noexcept
174 {
175 auto const newSize = (std::min) (n, N);
176 _value.resize(newSize);
177 }
178
179 /// Resizes the string.
180 LIGHTWEIGHT_FORCE_INLINE constexpr void resize(std::size_t n) noexcept
181 {
182 _value.resize(n);
183 }
184
185 /// Retrieves a string view of the string.
186 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view<T> substr(
187 std::size_t offset = 0, std::size_t count = (std::numeric_limits<std::size_t>::max)()) const noexcept
188 {
189 if (count != (std::numeric_limits<std::size_t>::max)())
190 {
191 return _value.substr(offset, count);
192 }
193 return _value.substr(offset);
194 }
195
196 /// Retrieves the string as a string_type.
197 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr string_type ToString() const noexcept
198 {
199 return _value;
200 }
201
202 /// Convertion operator to std::basic_string<T>.
203 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr explicit operator std::basic_string<T>() const noexcept
204 {
205 return ToString();
206 }
207
208 /// Retrieves a string view of the string.
209 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view<T> ToStringView() const noexcept
210 {
211 return { _value.data(), _value.size() };
212 }
213
214 /// Element access operator.
215 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr T& operator[](std::size_t index) noexcept
216 {
217 return _value[index];
218 }
219
220 /// Const qulified element access operator.
221 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr T const& operator[](std::size_t index) const noexcept
222 {
223 return _value[index];
224 }
225
226 /// Conversion operator into std::basic_string_view<T>.
227 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr explicit operator std::basic_string_view<T>() const noexcept
228 {
229 return ToStringView();
230 }
231
232 /// Three-way comparison operator for comparing with another SqlDynamicString of possibly different capacity.
233 template <std::size_t OtherSize>
234 LIGHTWEIGHT_FORCE_INLINE std::weak_ordering operator<=>(SqlDynamicString<OtherSize, T> const& other) const noexcept
235 {
236 return _value <=> other._value;
237 }
238
239 /// Equality comparison operator for comparing with another SqlDynamicString of possibly different capacity.
240 template <std::size_t OtherSize>
241 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator==(SqlDynamicString<OtherSize, T> const& other) const noexcept
242 {
243 return (*this <=> other) == std::weak_ordering::equivalent;
244 }
245
246 /// Inequality comparison operator for comparing with another SqlDynamicString of possibly different capacity.
247 template <std::size_t OtherSize>
248 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!=(SqlDynamicString<OtherSize, T> const& other) const noexcept
249 {
250 return !(*this == other);
251 }
252
253 /// Equality comparison operator for comparing with a string view.
254 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator==(std::basic_string_view<T> other) const noexcept
255 {
256 return (ToStringView() <=> other) == std::weak_ordering::equivalent;
257 }
258
259 /// Inequality comparison operator for comparing with a string view.
260 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!=(std::basic_string_view<T> other) const noexcept
261 {
262 return !(*this == other);
263 }
264
265 /// Retrieves an iterator to the beginning of the string.
266 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr iterator begin() noexcept
267 {
268 return _value.begin();
269 }
270
271 /// Retrieves an iterator to the end of the string.
272 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr iterator end() noexcept
273 {
274 return _value.end();
275 }
276
277 /// Retrieves a const iterator to the beginning of the string.
278 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator begin() const noexcept
279 {
280 return _value.begin();
281 }
282
283 /// Retrieves a const iterator to the end of the string.
284 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator end() const noexcept
285 {
286 return _value.end();
287 }
288
289 private:
290 string_type _value;
291};
292
293static_assert(SqlStringInterface<SqlDynamicString<10>>);
294
295template <std::size_t N, typename CharT>
296struct detail::SqlViewHelper<SqlDynamicString<N, CharT>>
297{
298 static LIGHTWEIGHT_FORCE_INLINE std::basic_string_view<CharT> View(SqlDynamicString<N, CharT> const& str) noexcept
299 {
300 return { str.data(), str.size() };
301 }
302};
303
304namespace detail
305{
306
307 template <typename>
308 struct IsSqlDynamicStringImpl: std::false_type
309 {
310 };
311
312 template <std::size_t N, typename T>
313 struct IsSqlDynamicStringImpl<SqlDynamicString<N, T>>: std::true_type
314 {
315 };
316
317 template <std::size_t N, typename T>
318 struct IsSqlDynamicStringImpl<std::optional<SqlDynamicString<N, T>>>: std::true_type
319 {
320 };
321
322 template <typename T>
323 consteval size_t SqlMaxNumberOfChars()
324 {
325 // This constant defines the maximal number of bytes that can appear
326 // in single column for types like varchar(max)
327 // see: https://learn.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server
328 // 2GB or 2^31 - 1
329 constexpr size_t numberOfBytes = 2147483647;
330 return numberOfBytes / sizeof(T);
331 }
332
333} // namespace detail
334
335template <typename T>
336constexpr bool IsSqlDynamicString = detail::IsSqlDynamicStringImpl<T>::value;
337
338/// Dynamic-size string of element type `char` with a capacity of `N` characters.
339///
340/// @ingroup DataTypes
341template <std::size_t N>
343
344/// Dynamic-size string of element type `char16_t` with a capacity of `N` characters.
345///
346/// @ingroup DataTypes
347template <std::size_t N>
349
350/// Dynamic-size string of element type `char32_t` with a capacity of `N` characters.
351///
352/// @ingroup DataTypes
353template <std::size_t N>
355
356/// Dynamic-size string of element type `wchar_t` with a capacity of `N` characters.
357///
358/// @ingroup DataTypes
359template <std::size_t N>
361
362/// Dynamic-size string of element type 'char' with a maximum capacity of
363/// `SqlMaxNumberOfChars<char>` characters.
365
366/// Dynamic-size string of element type 'wchar_t' with a maximum capacity of
367/// `SqlMaxNumberOfChars<wchar_t>` characters.
369
370} // namespace Lightweight
371
372template <std::size_t N, typename T>
373struct std::formatter<Lightweight::SqlDynamicString<N, T>>: std::formatter<std::string>
374{
375 using value_type = Lightweight::SqlDynamicString<N, T>;
376
377 auto format(value_type const& text, format_context& ctx) const
378 {
379 if constexpr (Lightweight::detail::OneOf<T, wchar_t, char32_t, char16_t>)
380 return std::formatter<std::string>::format((char const*) Lightweight::ToUtf8(text.ToStringView()).c_str(), ctx);
381 else
382 return std::formatter<std::string>::format((char const*) text.data(), ctx);
383 }
384};
385
386template <std::size_t N, typename T>
387struct std::formatter<std::optional<Lightweight::SqlDynamicString<N, T>>>: std::formatter<string>
388{
389 using value_type = std::optional<Lightweight::SqlDynamicString<N, T>>;
390
391 auto format(value_type const& text, format_context& ctx) const
392 {
393 if (!text.has_value())
394 return std::formatter<std::string>::format("nullopt", ctx);
395 return std::formatter<std::string>::format(std::format("{}", text.value()), ctx);
396 }
397};
398
399namespace Lightweight
400{
401
402template <std::size_t N, typename T>
403struct SqlBasicStringOperations<SqlDynamicString<N, T>>
404{
405 using CharType = T;
406 using ValueType = SqlDynamicString<N, CharType>;
407
408 static constexpr SqlColumnTypeDefinition ColumnType = []() constexpr {
409 if constexpr (std::same_as<CharType, char>)
410 return SqlColumnTypeDefinitions::Varchar { N };
411 else
412 return SqlColumnTypeDefinitions::NVarchar { N };
413 }();
414
415 static CharType const* Data(ValueType const* str) noexcept
416 {
417 return str->data();
418 }
419
420 static CharType* Data(ValueType* str) noexcept
421 {
422 return str->data();
423 }
424
425 static SQLULEN Size(ValueType const* str) noexcept
426 {
427 return str->size();
428 }
429
430 static void Clear(ValueType* str) noexcept
431 {
432 str->value().clear();
433 }
434
435 static void Reserve(ValueType* str, size_t capacity) noexcept
436 {
437 str->value().resize((std::min) (N, capacity));
438 }
439
440 static void Resize(ValueType* str, SQLLEN indicator) noexcept
441 {
442 str->value().resize(static_cast<size_t>(indicator));
443 }
444};
445
446} // namespace Lightweight
LIGHTWEIGHT_FORCE_INLINE void setsize(std::size_t n) noexcept
static constexpr std::size_t DynamicCapacity
constexpr variable with the capacity of the string.
LIGHTWEIGHT_FORCE_INLINE std::weak_ordering operator<=>(SqlDynamicString< OtherSize, T > const &other) const noexcept
Three-way comparison operator for comparing with another SqlDynamicString of possibly different capac...
T value_type
The element type of the string.
LIGHTWEIGHT_FORCE_INLINE std::size_t size() const noexcept
Retrieves the string's size.
LIGHTWEIGHT_FORCE_INLINE std::size_t capacity() const noexcept
Retrieves the string's capacity.
LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator end() const noexcept
Retrieves a const iterator to the end of the string.
string_type::iterator iterator
Iterator type for the string.
string_type::const_iterator const_iterator
Const iterator type for the string.
LIGHTWEIGHT_FORCE_INLINE constexpr T const & operator[](std::size_t index) const noexcept
Const qulified element access operator.
LIGHTWEIGHT_FORCE_INLINE T const * c_str() const noexcept
Retrieves the string's inner value (as T const*).
LIGHTWEIGHT_FORCE_INLINE T const * data() const noexcept
Retrieves the string's inner value (as T const*).
LIGHTWEIGHT_FORCE_INLINE void reserve(std::size_t capacity)
Reserves capacity for at least the given number of characters.
LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view< T > str() const noexcept
Returns a string view of the string.
T * pointer_type
Pointer type for the string.
LIGHTWEIGHT_FORCE_INLINE constexpr bool empty() const noexcept
Tests if the string is empty.
T const * const_pointer_type
Const pointer type for the string.
LIGHTWEIGHT_FORCE_INLINE constexpr void pop_back() noexcept
Removes the last character from the string.
LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view< T > ToStringView() const noexcept
Retrieves a string view of the string.
LIGHTWEIGHT_FORCE_INLINE constexpr iterator end() noexcept
Retrieves an iterator to the end of the string.
LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!=(SqlDynamicString< OtherSize, T > const &other) const noexcept
Inequality comparison operator for comparing with another SqlDynamicString of possibly different capa...
constexpr LIGHTWEIGHT_FORCE_INLINE SqlDynamicString(T const (&text)[SourceSize])
Constructs a fixed-size string from a string literal.
LIGHTWEIGHT_FORCE_INLINE T * data() noexcept
Retrieves the string's inner value (as T*).
LIGHTWEIGHT_FORCE_INLINE constexpr bool operator==(std::basic_string_view< T > other) const noexcept
Equality comparison operator for comparing with a string view.
LIGHTWEIGHT_FORCE_INLINE string_type & value() noexcept
Retrieves the string's inner value (std::basic_string<T>).
LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString() noexcept=default
Defaulted default constructor.
LIGHTWEIGHT_FORCE_INLINE constexpr string_type ToString() const noexcept
Retrieves the string as a string_type.
std::basic_string< T > string_type
String type used for the internal storage of the string.
LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view< T > substr(std::size_t offset=0, std::size_t count=(std::numeric_limits< std::size_t >::max)()) const noexcept
Retrieves a string view of the string.
LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(std::basic_string< T > const &s) noexcept
Constructs a fixed-size string from a string.
LIGHTWEIGHT_FORCE_INLINE string_type const & value() const noexcept
Retrieves the string's inner value (std::basic_string<T>).
LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!=(std::basic_string_view< T > other) const noexcept
Inequality comparison operator for comparing with a string view.
LIGHTWEIGHT_FORCE_INLINE constexpr iterator begin() noexcept
Retrieves an iterator to the beginning of the string.
LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(T const *s, T const *e) noexcept
Constructs a fixed-size string from a string pointer and end pointer.
LIGHTWEIGHT_FORCE_INLINE constexpr void push_back(T c) noexcept
Appends a character to the end of the string.
LIGHTWEIGHT_FORCE_INLINE constexpr void clear() noexcept
Clears the string.
LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator begin() const noexcept
Retrieves a const iterator to the beginning of the string.
LIGHTWEIGHT_FORCE_INLINE constexpr void resize(std::size_t n) noexcept
Resizes the string.
LIGHTWEIGHT_FORCE_INLINE constexpr T & operator[](std::size_t index) noexcept
Element access operator.
LIGHTWEIGHT_FORCE_INLINE constexpr bool operator==(SqlDynamicString< OtherSize, T > const &other) const noexcept
Equality comparison operator for comparing with another SqlDynamicString of possibly different capaci...
LIGHTWEIGHT_API std::u8string ToUtf8(std::u32string_view u32InputString)