StormByte-Database 2.0.0
C++26 database module of the StormByte suite
 
Loading...
Searching...
No Matches
value.hxx
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024-2026 David C. Manuelda (StormBytePP)
3 *
4 * This file is part of StormByte-Database.
5 *
6 * StormByte-Database original source is dual-licensed:
7 *
8 * 1. GNU Lesser General Public License v3.0 (or later)
9 * You may redistribute and/or modify this file under the terms of the
10 * GNU Lesser General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option)
12 * any later version.
13 *
14 * 2. Commercial license
15 * Alternatively, this file may be used under the terms of a commercial
16 * license agreement with the copyright holder
17 * (David C. Manuelda <StormByte@gmail.com>).
18 *
19 * Both licenses apply only to original StormByte-Database source in this
20 * repository. They do not cover other StormByte modules or any third-party
21 * material shipped with this repository (including everything under
22 * thirdparty/, and in particular the bundled StormByte-Logger tree and
23 * the PostgreSQL, MariaDB and SQLite trees), which remain under their own
24 * licenses.
25 *
26 * Neither license grants any patent rights. Any patent licenses required
27 * to use this software or third-party components must be obtained separately
28 * from the patent holders.
29 *
30 * StormByte-Database is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU Lesser General Public License for more details.
34 *
35 * You should have received a copy of the GNU Lesser General Public License
36 * version 3 along with StormByte-Database. If not, see
37 * <https://www.gnu.org/licenses/lgpl-3.0.html>.
38 *
39 * SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-StormByte-Commercial
40 */
41
42#pragma once
43
48
49#include <cmath>
50#include <limits>
51#include <string_view>
52#include <type_traits>
53
58namespace StormByte {
63 namespace Database {
69 public:
74 enum class Type : unsigned short {
75 Null = 0,
76 Integer,
77 UnsignedInteger,
78 LongInteger,
79 UnsignedLongInteger,
80 Double,
81 Text,
82 Blob,
83 Boolean
84 };
85
93 Value() noexcept : m_value(std::monostate{}), m_type(Type::Null) {}
94
99 Value(int value) noexcept : m_value(value), m_type(Type::Integer) {}
100
105 Value(unsigned int value) noexcept : m_value(value), m_type(Type::UnsignedInteger) {}
106
111 Value(long int value) noexcept : m_value(static_cast<long long int>(value)), m_type(Type::LongInteger) {}
112
117 Value(unsigned long int value) noexcept : m_value(static_cast<unsigned long long int>(value)), m_type(Type::UnsignedLongInteger) {}
118
123 Value(long long int value) noexcept : m_value(value), m_type(Type::LongInteger) {}
124
129 Value(unsigned long long int value) noexcept : m_value(value), m_type(Type::UnsignedLongInteger) {}
130
135 Value(double value) noexcept : m_value(value), m_type(Type::Double) {}
136
141 Value(std::string_view value) noexcept;
142
148
153 Value(StormByte::BinaryData &&value) noexcept;
154
159 template <typename T>
161 Value(T &&value) noexcept : m_value(value), m_type(Type::Boolean) {}
167 Value(const Value &other);
168
172 Value(Value &&other) noexcept;
173
177 Value &operator=(const Value &other);
178
182 Value &operator=(Value &&other) noexcept;
183
189 inline bool operator==(const Value &other) const noexcept {
190 return m_value == other.m_value;
191 }
192
198 inline bool operator!=(const Value &other) const noexcept {
199 return !(*this == other);
200 }
201
205 virtual ~Value() noexcept;
206
213 template <typename T>
214 requires StormByte::Type::VariantHasType<ValuesVariant, std::decay_t<T>>
215 std::decay_t<T> Get() const {
216 using To = std::decay_t<T>;
217 return std::visit([](auto &&val) -> To {
218 using From = std::decay_t<decltype(val)>;
220 throw WrongValueType("Requested type does not match stored type (null).");
221 } else if constexpr (StormByte::Type::SameAs<From, To>) {
222 return val;
224 return convert_numeric<To, From>(val);
225 } else {
226 throw WrongValueType("Requested type does not match stored type.");
227 }
228 },
229 m_value);
230 }
231
236 inline Type Type() const noexcept {
237 return m_type;
238 }
239
244 inline bool IsNull() const noexcept {
245 return m_type == Type::Null;
246 }
247
248 private:
257 template <typename To, typename From>
259 static To convert_numeric(const From &val) {
261 if constexpr (StormByte::Type::Signed<From>) {
262 std::intmax_t from = static_cast<std::intmax_t>(val);
263 if constexpr (StormByte::Type::Signed<To>) {
264 if (from < static_cast<std::intmax_t>(std::numeric_limits<To>::lowest()) || from > static_cast<std::intmax_t>(std::numeric_limits<To>::max()))
265 throw WrongValueType("Integer conversion would overflow/narrow.");
266 return static_cast<To>(from);
267 } else {
268 if (from < 0)
269 throw WrongValueType("Negative value cannot be converted to unsigned.");
270 if (static_cast<std::uintmax_t>(from) > static_cast<std::uintmax_t>(std::numeric_limits<To>::max()))
271 throw WrongValueType("Integer conversion would overflow/narrow.");
272 return static_cast<To>(from);
273 }
274 } else {
275 std::uintmax_t from = static_cast<std::uintmax_t>(val);
276 if constexpr (StormByte::Type::Signed<To>) {
277 if (from > static_cast<std::uintmax_t>(std::numeric_limits<To>::max()))
278 throw WrongValueType("Integer conversion would overflow/narrow.");
279 return static_cast<To>(from);
280 } else {
281 if (from > static_cast<std::uintmax_t>(std::numeric_limits<To>::max()))
282 throw WrongValueType("Integer conversion would overflow/narrow.");
283 return static_cast<To>(from);
284 }
285 }
287 return static_cast<To>(val);
289 long double d = static_cast<long double>(val);
290 if (!std::isfinite(d))
291 throw WrongValueType("Non-finite floating conversion to integer.");
292 if (std::trunc(d) != d)
293 throw WrongValueType("Floating value has fractional part; would lose data.");
294 const long double upper_bound = std::ldexp(1.0L, std::numeric_limits<To>::digits);
295 if constexpr (StormByte::Type::Signed<To>) {
296 if (d < -upper_bound || d >= upper_bound)
297 throw WrongValueType("Floating to integer conversion would overflow/narrow.");
298 } else {
299 if (d < 0)
300 throw WrongValueType("Negative value cannot be converted to unsigned.");
301 if (d >= upper_bound)
302 throw WrongValueType("Floating to integer conversion would overflow/narrow.");
303 }
304 return static_cast<To>(d);
306 return static_cast<To>(val);
307 } else {
308 throw WrongValueType("Unsupported numeric conversion.");
309 }
310 }
311
312 ValuesVariant m_value;
313 enum Type m_type;
314 };
315 }
316}
Type-erased SQL value (NULL, integers, double, text, blob, bool).
Definition value.hxx:68
Value(Value &&other) noexcept
Move constructor.
bool IsNull() const noexcept
Whether the value is SQL NULL.
Definition value.hxx:244
Value(long int value) noexcept
From a signed long int, stored as long long int.
Definition value.hxx:111
Value(int value) noexcept
From a signed int.
Definition value.hxx:99
bool operator==(const Value &other) const noexcept
Equality of the stored alternatives.
Definition value.hxx:189
Value(unsigned long int value) noexcept
From an unsigned long int, stored as unsigned long long int.
Definition value.hxx:117
Value(StormByte::BinaryData &&value) noexcept
Move a blob into this value.
Value(unsigned int value) noexcept
From an unsigned int.
Definition value.hxx:105
Value(std::string_view value) noexcept
Copy UTF-8 text into a String-owned value.
Value(double value) noexcept
From a double.
Definition value.hxx:135
Type
Discriminator for the stored alternative.
Definition value.hxx:74
Value(unsigned long long int value) noexcept
From an unsigned long long int.
Definition value.hxx:129
Value(T &&value) noexcept
From a bool.
Definition value.hxx:161
Value(const Value &other)
Copy constructor.
Type Type() const noexcept
Discriminator of the stored alternative.
Definition value.hxx:236
virtual ~Value() noexcept
Destructor.
Value & operator=(Value &&other) noexcept
Move assignment.
Value & operator=(const Value &other)
Copy assignment.
Value() noexcept
Default constructor.
Definition value.hxx:93
bool operator!=(const Value &other) const noexcept
Inequality.
Definition value.hxx:198
Value(const StormByte::BinaryData &value)
Copy a blob into Base-owned storage.
Value(long long int value) noexcept
From a signed long long int.
Definition value.hxx:123
Value accessed as the wrong type.
Definition exception.hxx:123
std::variant< std::monostate, int, unsigned int, long long int, unsigned long long int, double, StormByte::String::String, bool, StormByte::BinaryData > ValuesVariant
Column alternatives.
Definition typedefs.hxx:76
Root namespace of the StormByte C++ suite.
STL namespace.
#define STORMBYTE_DATABASE_PUBLIC
Definition visibility.h:54