Lightweight 0.20260617.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 // Build the view directly over `_value`'s buffer instead of going through
190 // std::basic_string::substr, which would return a temporary std::basic_string
191 // and silently leave us with a dangling string_view at the call site.
192 if (offset > _value.size())
193 return {};
194 auto const remaining = _value.size() - offset;
195 auto const len = (count == (std::numeric_limits<std::size_t>::max)()) ? remaining : (std::min) (count, remaining);
196 return std::basic_string_view<T> { _value.data() + offset, len };
197 }
198
199 /// Retrieves the string as a string_type.
200 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr string_type ToString() const noexcept
201 {
202 return _value;
203 }
204
205 /// Convertion operator to std::basic_string<T>.
206 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr explicit operator std::basic_string<T>() const noexcept
207 {
208 return ToString();
209 }
210
211 /// Retrieves a string view of the string.
212 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view<T> ToStringView() const noexcept
213 {
214 return { _value.data(), _value.size() };
215 }
216
217 /// Element access operator.
218 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr T& operator[](std::size_t index) noexcept
219 {
220 return _value[index];
221 }
222
223 /// Const qulified element access operator.
224 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr T const& operator[](std::size_t index) const noexcept
225 {
226 return _value[index];
227 }
228
229 /// Conversion operator into std::basic_string_view<T>.
230 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr explicit operator std::basic_string_view<T>() const noexcept
231 {
232 return ToStringView();
233 }
234
235 /// Three-way comparison operator for comparing with another SqlDynamicString of possibly different capacity.
236 template <std::size_t OtherSize>
237 LIGHTWEIGHT_FORCE_INLINE std::weak_ordering operator<=>(SqlDynamicString<OtherSize, T> const& other) const noexcept
238 {
239 // Use the public value() accessor so cross-capacity comparisons don't trip private-member
240 // access — SqlDynamicString<OtherSize, T> is a different specialization, so its `_value`
241 // is inaccessible from this scope.
242 return _value <=> other.value();
243 }
244
245 /// Equality comparison operator for comparing with another SqlDynamicString of possibly different capacity.
246 template <std::size_t OtherSize>
247 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator==(SqlDynamicString<OtherSize, T> const& other) const noexcept
248 {
249 return (*this <=> other) == std::weak_ordering::equivalent;
250 }
251
252 /// Inequality comparison operator for comparing with another SqlDynamicString of possibly different capacity.
253 template <std::size_t OtherSize>
254 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!=(SqlDynamicString<OtherSize, T> const& other) const noexcept
255 {
256 return !(*this == other);
257 }
258
259 /// Equality 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 (ToStringView() <=> other) == std::weak_ordering::equivalent;
263 }
264
265 /// Inequality comparison operator for comparing with a string view.
266 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!=(std::basic_string_view<T> other) const noexcept
267 {
268 return !(*this == other);
269 }
270
271 /// Retrieves an iterator to the beginning of the string.
272 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr iterator begin() noexcept
273 {
274 return _value.begin();
275 }
276
277 /// Retrieves an iterator to the end of the string.
278 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr iterator end() noexcept
279 {
280 return _value.end();
281 }
282
283 /// Retrieves a const iterator to the beginning of the string.
284 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator begin() const noexcept
285 {
286 return _value.begin();
287 }
288
289 /// Retrieves a const iterator to the end of the string.
290 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator end() const noexcept
291 {
292 return _value.end();
293 }
294
295 private:
296 string_type _value;
297};
298
299static_assert(SqlStringInterface<SqlDynamicString<10>>);
300
301template <std::size_t N, typename CharT>
302struct detail::SqlViewHelper<SqlDynamicString<N, CharT>>
303{
304 static LIGHTWEIGHT_FORCE_INLINE std::basic_string_view<CharT> View(SqlDynamicString<N, CharT> const& str) noexcept
305 {
306 return { str.data(), str.size() };
307 }
308};
309
310namespace detail
311{
312
313 template <typename>
314 struct IsSqlDynamicStringImpl: std::false_type
315 {
316 };
317
318 template <std::size_t N, typename T>
319 struct IsSqlDynamicStringImpl<SqlDynamicString<N, T>>: std::true_type
320 {
321 };
322
323 template <std::size_t N, typename T>
324 struct IsSqlDynamicStringImpl<std::optional<SqlDynamicString<N, T>>>: std::true_type
325 {
326 };
327
328 template <typename T>
329 consteval size_t SqlMaxNumberOfChars()
330 {
331 // This constant defines the maximal number of bytes that can appear
332 // in single column for types like varchar(max)
333 // see: https://learn.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server
334 // 2GB or 2^31 - 1
335 constexpr size_t numberOfBytes = 2147483647;
336 return numberOfBytes / sizeof(T);
337 }
338
339} // namespace detail
340
341template <typename T>
342constexpr bool IsSqlDynamicString = detail::IsSqlDynamicStringImpl<T>::value;
343
344/// Dynamic-size string of element type `char` with a capacity of `N` characters.
345///
346/// @ingroup DataTypes
347template <std::size_t N>
349
350/// Dynamic-size string of element type `char16_t` with a capacity of `N` characters.
351///
352/// @ingroup DataTypes
353template <std::size_t N>
355
356/// Dynamic-size string of element type `char32_t` with a capacity of `N` characters.
357///
358/// @ingroup DataTypes
359template <std::size_t N>
361
362/// Dynamic-size string of element type `wchar_t` with a capacity of `N` characters.
363///
364/// @ingroup DataTypes
365template <std::size_t N>
367
368/// Dynamic-size string of element type 'char' with a maximum capacity of
369/// `SqlMaxNumberOfChars<char>` characters.
371
372/// Dynamic-size string of element type 'wchar_t' with a maximum capacity of
373/// `SqlMaxNumberOfChars<wchar_t>` characters.
375
376} // namespace Lightweight
377
378template <std::size_t N, typename T>
379struct std::formatter<Lightweight::SqlDynamicString<N, T>>: std::formatter<std::string>
380{
381 using value_type = Lightweight::SqlDynamicString<N, T>;
382
383 auto format(value_type const& text, format_context& ctx) const
384 {
385 if constexpr (Lightweight::detail::OneOf<T, wchar_t, char32_t, char16_t>)
386 return std::formatter<std::string>::format((char const*) Lightweight::ToUtf8(text.ToStringView()).c_str(), ctx);
387 else
388 return std::formatter<std::string>::format((char const*) text.data(), ctx);
389 }
390};
391
392template <std::size_t N, typename T>
393struct std::formatter<std::optional<Lightweight::SqlDynamicString<N, T>>>: std::formatter<string>
394{
395 using value_type = std::optional<Lightweight::SqlDynamicString<N, T>>;
396
397 auto format(value_type const& text, format_context& ctx) const
398 {
399 if (!text.has_value())
400 return std::formatter<std::string>::format("nullopt", ctx);
401 return std::formatter<std::string>::format(std::format("{}", text.value()), ctx);
402 }
403};
404
405namespace Lightweight
406{
407
408template <std::size_t N, typename T>
409struct SqlBasicStringOperations<SqlDynamicString<N, T>>
410{
411 using CharType = T;
412 using ValueType = SqlDynamicString<N, CharType>;
413
414 static constexpr SqlColumnTypeDefinition ColumnType = []() constexpr {
415 if constexpr (std::same_as<CharType, char>)
416 return SqlColumnTypeDefinitions::Varchar { N };
417 else
418 return SqlColumnTypeDefinitions::NVarchar { N };
419 }();
420
421 static CharType const* Data(ValueType const* str) noexcept
422 {
423 return str->data();
424 }
425
426 static CharType* Data(ValueType* str) noexcept
427 {
428 return str->data();
429 }
430
431 static SQLULEN Size(ValueType const* str) noexcept
432 {
433 return str->size();
434 }
435
436 static void Clear(ValueType* str) noexcept
437 {
438 str->value().clear();
439 }
440
441 static void Reserve(ValueType* str, size_t capacity) noexcept
442 {
443 str->value().resize((std::min) (N, capacity));
444 }
445
446 static void Resize(ValueType* str, SQLLEN indicator) noexcept
447 {
448 str->value().resize(static_cast<size_t>(indicator));
449 }
450};
451
452} // 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)