Lightweight 0.20251202.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 SQL column.
23///
24/// @ingroup DataTypes
25template <std::size_t N, typename T = char>
27{
28 public:
29 static constexpr std::size_t DynamicCapacity = N;
30 using value_type = T;
31 using string_type = std::basic_string<T>;
32 using iterator = string_type::iterator;
33 using const_iterator = string_type::const_iterator;
34 using pointer_type = T*;
35 using const_pointer_type = T const*;
36
37 /// Constructs a fixed-size string from a string literal.
38 template <std::size_t SourceSize>
39 constexpr LIGHTWEIGHT_FORCE_INLINE SqlDynamicString(T const (&text)[SourceSize]):
40 _value { text, SourceSize - 1 }
41 {
42 static_assert(SourceSize <= N + 1, "RHS string size must not exceed target string's capacity.");
43 }
44
45 /// Constructs a fixed-size string from a string pointer and end pointer.
46 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(T const* s, T const* e) noexcept:
47 _value { s, e }
48 {
49 }
50
51 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString() noexcept = default;
52 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(SqlDynamicString const&) noexcept = default;
53 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString& operator=(SqlDynamicString const&) noexcept = default;
54 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(SqlDynamicString&&) noexcept = default;
55 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString& operator=(SqlDynamicString&&) noexcept = default;
56 LIGHTWEIGHT_FORCE_INLINE constexpr ~SqlDynamicString() noexcept = default;
57
58 /// Constructs a fixed-size string from a string view.
59 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(std::basic_string_view<T> s) noexcept:
60 _value { s }
61 {
62 }
63
64 /// Constructs a fixed-size string from a string.
65 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDynamicString(std::basic_string<T> const& s) noexcept:
66 _value { s }
67 {
68 }
69
70 /// Returns a string view of the string.
71 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view<T> str() const noexcept
72 {
73 return std::basic_string_view<T> { data(), size() };
74 }
75
76 /// Retrieves the string's inner value (std::basic_string<T>).
77 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE string_type const& value() const noexcept
78 {
79 return _value;
80 }
81
82 /// Retrieves the string's inner value (std::basic_string<T>).
83 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE string_type& value() noexcept
84 {
85 return _value;
86 }
87
88 /// Retrieves the string's inner value (as T const*).
89 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE T const* data() const noexcept
90 {
91 return _value.data();
92 }
93
94 /// Retrieves the string's inner value (as T*).
95 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE T* data() noexcept
96 {
97 return _value.data();
98 }
99
100 /// Retrieves the string's inner value (as T const*).
101 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE T const* c_str() const noexcept
102 {
103 return _value.c_str();
104 }
105
106 /// Retrieves the string's capacity.
107 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE std::size_t capacity() const noexcept
108 {
109 return N;
110 }
111
112 /// Retrieves the string's size.
113 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE std::size_t size() const noexcept
114 {
115 return _value.size();
116 }
117
118 /// Tests if the string is empty.
119 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr bool empty() const noexcept
120 {
121 return _value.empty();
122 }
123
124 /// Clears the string.
125 LIGHTWEIGHT_FORCE_INLINE constexpr void clear() noexcept
126 {
127 _value.clear();
128 }
129
130 LIGHTWEIGHT_FORCE_INLINE void reserve(std::size_t capacity)
131 {
132 _value.reserve(capacity);
133 }
134
135 LIGHTWEIGHT_FORCE_INLINE constexpr void push_back(T c) noexcept
136 {
137 _value += c;
138 }
139
140 LIGHTWEIGHT_FORCE_INLINE constexpr void pop_back() noexcept
141 {
142 _value.pop_back();
143 }
144
145 // NOLINTNEXTLINE(readability-identifier-naming)
146 LIGHTWEIGHT_FORCE_INLINE void setsize(std::size_t n) noexcept
147 {
148 auto const newSize = (std::min) (n, N);
149 _value.resize(newSize);
150 }
151
152 /// Resizes the string.
153 LIGHTWEIGHT_FORCE_INLINE constexpr void resize(std::size_t n) noexcept
154 {
155 _value.resize(n);
156 }
157
158 /// Retrieves a string view of the string.
159 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view<T> substr(
160 std::size_t offset = 0, std::size_t count = (std::numeric_limits<std::size_t>::max)()) const noexcept
161 {
162 if (count != (std::numeric_limits<std::size_t>::max)())
163 {
164 return _value.substr(offset, count);
165 }
166 return _value.substr(offset);
167 }
168
169 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr string_type ToString() const noexcept
170 {
171 return _value;
172 }
173
174 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr explicit operator std::basic_string<T>() const noexcept
175 {
176 return ToString();
177 }
178
179 /// Retrieves a string view of the string.
180 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view<T> ToStringView() const noexcept
181 {
182 return { _value.data(), _value.size() };
183 }
184
185 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr T& operator[](std::size_t index) noexcept
186 {
187 return _value[index];
188 }
189
190 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr T const& operator[](std::size_t index) const noexcept
191 {
192 return _value[index];
193 }
194
195 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr explicit operator std::basic_string_view<T>() const noexcept
196 {
197 return ToStringView();
198 }
199
200 template <std::size_t OtherSize>
201 LIGHTWEIGHT_FORCE_INLINE std::weak_ordering operator<=>(SqlDynamicString<OtherSize, T> const& other) const noexcept
202 {
203 return _value <=> other._value;
204 }
205
206 template <std::size_t OtherSize>
207 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator==(SqlDynamicString<OtherSize, T> const& other) const noexcept
208 {
209 return (*this <=> other) == std::weak_ordering::equivalent;
210 }
211
212 template <std::size_t OtherSize>
213 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!=(SqlDynamicString<OtherSize, T> const& other) const noexcept
214 {
215 return !(*this == other);
216 }
217
218 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator==(std::basic_string_view<T> other) const noexcept
219 {
220 return (ToStringView() <=> other) == std::weak_ordering::equivalent;
221 }
222
223 LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!=(std::basic_string_view<T> other) const noexcept
224 {
225 return !(*this == other);
226 }
227
228 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr iterator begin() noexcept
229 {
230 return _value.begin();
231 }
232
233 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr iterator end() noexcept
234 {
235 return _value.end();
236 }
237
238 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator begin() const noexcept
239 {
240 return _value.begin();
241 }
242
243 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator end() const noexcept
244 {
245 return _value.end();
246 }
247
248 private:
249 string_type _value;
250};
251
252static_assert(SqlStringInterface<SqlDynamicString<10>>);
253
254template <std::size_t N, typename CharT>
255struct detail::SqlViewHelper<SqlDynamicString<N, CharT>>
256{
257 static LIGHTWEIGHT_FORCE_INLINE std::basic_string_view<CharT> View(SqlDynamicString<N, CharT> const& str) noexcept
258 {
259 return { str.data(), str.size() };
260 }
261};
262
263namespace detail
264{
265
266 template <typename>
267 struct IsSqlDynamicStringImpl: std::false_type
268 {
269 };
270
271 template <std::size_t N, typename T>
272 struct IsSqlDynamicStringImpl<SqlDynamicString<N, T>>: std::true_type
273 {
274 };
275
276 template <std::size_t N, typename T>
277 struct IsSqlDynamicStringImpl<std::optional<SqlDynamicString<N, T>>>: std::true_type
278 {
279 };
280
281 template <typename T>
282 consteval size_t SqlMaxNumberOfChars()
283 {
284 // This constant defines the maximal number of bytes that can appear
285 // in single column for types like varchar(max)
286 // see: https://learn.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server
287 // 2GB or 2^31 - 1
288 constexpr size_t numberOfBytes = 2147483647;
289 return numberOfBytes / sizeof(T);
290 }
291
292} // namespace detail
293
294template <typename T>
295constexpr bool IsSqlDynamicString = detail::IsSqlDynamicStringImpl<T>::value;
296
297/// Dynamic-size string of element type `char` with a capacity of `N` characters.
298///
299/// @ingroup DataTypes
300template <std::size_t N>
302
303/// Dynamic-size string of element type `char16_t` with a capacity of `N` characters.
304///
305/// @ingroup DataTypes
306template <std::size_t N>
308
309/// Dynamic-size string of element type `char32_t` with a capacity of `N` characters.
310///
311/// @ingroup DataTypes
312template <std::size_t N>
314
315/// Dynamic-size string of element type `wchar_t` with a capacity of `N` characters.
316///
317/// @ingroup DataTypes
318template <std::size_t N>
320
321/// Dynamic-size string of element type 'char' with a maximum capacity of
322/// `SqlMaxNumberOfChars<char>` characters.
324
325/// Dynamic-size string of element type 'wchar_t' with a maximum capacity of
326/// `SqlMaxNumberOfChars<wchar_t>` characters.
328
329} // namespace Lightweight
330
331template <std::size_t N, typename T>
332struct std::formatter<Lightweight::SqlDynamicString<N, T>>: std::formatter<std::string>
333{
334 using value_type = Lightweight::SqlDynamicString<N, T>;
335
336 auto format(value_type const& text, format_context& ctx) const
337 {
338 if constexpr (Lightweight::detail::OneOf<T, wchar_t, char32_t, char16_t>)
339 return std::formatter<std::string>::format((char const*) Lightweight::ToUtf8(text.ToStringView()).c_str(), ctx);
340 else
341 return std::formatter<std::string>::format((char const*) text.data(), ctx);
342 }
343};
344
345template <std::size_t N, typename T>
346struct std::formatter<std::optional<Lightweight::SqlDynamicString<N, T>>>: std::formatter<string>
347{
348 using value_type = std::optional<Lightweight::SqlDynamicString<N, T>>;
349
350 auto format(value_type const& text, format_context& ctx) const
351 {
352 if (!text.has_value())
353 return std::formatter<std::string>::format("nullopt", ctx);
354 return std::formatter<std::string>::format(std::format("{}", text.value()), ctx);
355 }
356};
357
358namespace Lightweight
359{
360
361template <std::size_t N, typename T>
362struct SqlBasicStringOperations<SqlDynamicString<N, T>>
363{
364 using CharType = T;
365 using ValueType = SqlDynamicString<N, CharType>;
366
367 static constexpr SqlColumnTypeDefinition ColumnType = []() constexpr {
368 if constexpr (std::same_as<CharType, char>)
369 return SqlColumnTypeDefinitions::Varchar { N };
370 else
371 return SqlColumnTypeDefinitions::NVarchar { N };
372 }();
373
374 static CharType const* Data(ValueType const* str) noexcept
375 {
376 return str->data();
377 }
378
379 static CharType* Data(ValueType* str) noexcept
380 {
381 return str->data();
382 }
383
384 static SQLULEN Size(ValueType const* str) noexcept
385 {
386 return str->size();
387 }
388
389 static void Clear(ValueType* str) noexcept
390 {
391 str->value().clear();
392 }
393
394 static void Reserve(ValueType* str, size_t capacity) noexcept
395 {
396 str->value().resize((std::min) (N, capacity));
397 }
398
399 static void Resize(ValueType* str, SQLLEN indicator) noexcept
400 {
401 str->value().resize(static_cast<size_t>(indicator));
402 }
403};
404
405} // namespace Lightweight
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 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 constexpr std::basic_string_view< T > str() const noexcept
Returns a string view of the string.
LIGHTWEIGHT_FORCE_INLINE constexpr bool empty() const noexcept
Tests if the string is empty.
LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view< T > ToStringView() const noexcept
Retrieves a string view of the string.
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 string_type & value() noexcept
Retrieves the string's inner value (std::basic_string<T>).
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 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 clear() noexcept
Clears the string.
LIGHTWEIGHT_FORCE_INLINE constexpr void resize(std::size_t n) noexcept
Resizes the string.
LIGHTWEIGHT_API std::u8string ToUtf8(std::u32string_view u32InputString)