StormByte C++ Library: Database module 0.0.9999
StormByte-Database is a StormByte library module for handling database connections
Loading...
Searching...
No Matches
value.hxx
1#pragma once
2
3#include <StormByte/database/exception.hxx>
4#include <StormByte/database/typedefs.hxx>
5#include <StormByte/database/visibility.h>
6#include <StormByte/type_traits.hxx>
7#include <cmath>
8#include <limits>
9#include <type_traits>
10
15namespace StormByte::Database {
20 class STORMBYTE_DATABASE_PUBLIC Value {
21 public:
26 enum class Type: unsigned short {
27 Null = 0,
28 Integer,
29 UnsignedInteger,
30 LongInteger,
31 UnsignedLongInteger,
32 Double,
33 Text,
34 Blob,
35 Boolean
36 };
37
43 Value() noexcept:
44 m_value(std::monostate{}), m_type(Type::Null) {}
45
46 Value(int value) noexcept:
47 m_value(value), m_type(Type::Integer) {}
48
49 Value(unsigned int value) noexcept:
50 m_value(value), m_type(Type::UnsignedInteger) {}
51
52 Value(long int value) noexcept:
53 m_value(value), m_type(Type::LongInteger) {}
54
55 Value(unsigned long int value) noexcept:
56 m_value(value), m_type(Type::UnsignedLongInteger) {}
57
58 Value(double value) noexcept:
59 m_value(value), m_type(Type::Double) {}
60
61 Value(const std::string& value) noexcept:
62 m_value(value), m_type(Type::Text) {}
63
64 Value(std::string&& value) noexcept:
65 m_value(std::move(value)), m_type(Type::Text) {}
66
67 Value(const char* value) noexcept:
68 Value(std::string(value)) {}
69
70 Value(const std::vector<std::byte>& value) noexcept:
71 m_value(value), m_type(Type::Blob) {}
72
73 Value(std::vector<std::byte>&& value) noexcept:
74 m_value(std::move(value)), m_type(Type::Blob) {}
75
76 Value(bool value) noexcept:
77 m_value(value), m_type(Type::Boolean) {}
83 Value(const Value&) = default;
84
88 Value(Value&&) noexcept = default;
89
93 Value& operator=(const Value&) = default;
94
98 Value& operator=(Value&&) noexcept = default;
99
105 inline bool operator==(const Value& other) const noexcept {
106 return m_value == other.m_value;
107 }
108
114 inline bool operator!=(const Value& other) const noexcept {
115 return !(*this == other);
116 }
117
121 virtual ~Value() noexcept = default;
122
123 template<typename T>
124 requires StormByte::Type::VariantHasType<ValuesVariant, std::decay_t<T>>
125 std::decay_t<T> Get() const {
126 using To = std::decay_t<T>;
127 // visitor handles all stored alternatives and performs safe numeric conversions
128 return std::visit([](auto&& val) -> To {
129 using From = std::decay_t<decltype(val)>;
130 if constexpr (std::is_same_v<From, std::monostate>) {
131 throw WrongValueType("Requested type does not match stored type (null).");
132 } else if constexpr (std::is_same_v<From, To>) {
133 return val;
134 } else if constexpr (std::is_arithmetic_v<From> && std::is_arithmetic_v<To>) {
135 return convert_numeric<To, From>(val);
136 } else {
137 throw WrongValueType("Requested type does not match stored type.");
138 }
139 }, m_value);
140 }
141
146 inline Type Type() const noexcept {
147 return m_type;
148 }
149
154 inline bool IsNull() const noexcept {
155 return m_type == Type::Null;
156 }
157
158 private:
159 // Helper: safe numeric conversion; only instantiated for arithmetic To and From
160 template<typename To, typename From>
161 requires (std::is_arithmetic_v<To> && std::is_arithmetic_v<From>)
162 static To convert_numeric(const From& val) {
163 if constexpr (std::is_integral_v<From> && std::is_integral_v<To>) {
164 if constexpr (std::is_signed_v<From>) {
165 std::intmax_t from = static_cast<std::intmax_t>(val);
166 if constexpr (std::is_signed_v<To>) {
167 if (from < static_cast<std::intmax_t>(std::numeric_limits<To>::lowest()) || from > static_cast<std::intmax_t>(std::numeric_limits<To>::max()))
168 throw WrongValueType("Integer conversion would overflow/narrow.");
169 return static_cast<To>(from);
170 } else {
171 // From signed, To unsigned
172 if (from < 0) throw WrongValueType("Negative value cannot be converted to unsigned.");
173 if (static_cast<std::uintmax_t>(from) > static_cast<std::uintmax_t>(std::numeric_limits<To>::max()))
174 throw WrongValueType("Integer conversion would overflow/narrow.");
175 return static_cast<To>(from);
176 }
177 } else {
178 // From unsigned
179 std::uintmax_t from = static_cast<std::uintmax_t>(val);
180 if constexpr (std::is_signed_v<To>) {
181 if (from > static_cast<std::uintmax_t>(std::numeric_limits<To>::max()))
182 throw WrongValueType("Integer conversion would overflow/narrow.");
183 return static_cast<To>(from);
184 } else {
185 // both unsigned
186 if (from > static_cast<std::uintmax_t>(std::numeric_limits<To>::max()))
187 throw WrongValueType("Integer conversion would overflow/narrow.");
188 return static_cast<To>(from);
189 }
190 }
191 } else if constexpr (std::is_integral_v<From> && std::is_floating_point_v<To>) {
192 return static_cast<To>(val);
193 } else if constexpr (std::is_floating_point_v<From> && std::is_integral_v<To>) {
194 long double d = static_cast<long double>(val);
195 if (!std::isfinite(d)) throw WrongValueType("Non-finite floating conversion to integer.");
196 if (std::trunc(d) != d) throw WrongValueType("Floating value has fractional part; would lose data.");
197 std::intmax_t tmp = static_cast<std::intmax_t>(d);
198 if constexpr (std::is_signed_v<To>) {
199 if (tmp < static_cast<std::intmax_t>(std::numeric_limits<To>::lowest()) || tmp > static_cast<std::intmax_t>(std::numeric_limits<To>::max()))
200 throw WrongValueType("Floating to integer conversion would overflow/narrow.");
201 return static_cast<To>(tmp);
202 } else {
203 // To unsigned
204 if (tmp < 0) throw WrongValueType("Negative value cannot be converted to unsigned.");
205 if (static_cast<std::uintmax_t>(tmp) > static_cast<std::uintmax_t>(std::numeric_limits<To>::max()))
206 throw WrongValueType("Floating to integer conversion would overflow/narrow.");
207 return static_cast<To>(tmp);
208 }
209 } else if constexpr (std::is_floating_point_v<From> && std::is_floating_point_v<To>) {
210 return static_cast<To>(val);
211 } else {
212 throw WrongValueType("Unsupported numeric conversion.");
213 }
214 }
215 ValuesVariant m_value;
216 enum Type m_type;
217 };
218}
Value class for databases.
Definition value.hxx:20
virtual ~Value() noexcept=default
Value(Value &&) noexcept=default
bool IsNull() const noexcept
Definition value.hxx:154
Type
Type of a value.
Definition value.hxx:26
Type Type() const noexcept
Definition value.hxx:146
Value() noexcept
Definition value.hxx:43
Value(const Value &)=default
bool operator!=(const Value &other) const noexcept
Definition value.hxx:114
Exception thrown when value type requested is not correct.
Definition exception.hxx:45