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
103 ~Value() noexcept = default;
104
105 template<typename T>
106 requires StormByte::Type::VariantHasType<ValuesVariant, std::decay_t<T>>
107 std::decay_t<T> Get() const {
108 using To = std::decay_t<T>;
109 // visitor handles all stored alternatives and performs safe numeric conversions
110 return std::visit([](auto&& val) -> To {
111 using From = std::decay_t<decltype(val)>;
112 if constexpr (std::is_same_v<From, std::monostate>) {
113 throw WrongValueType("Requested type does not match stored type (null).");
114 } else if constexpr (std::is_same_v<From, To>) {
115 return val;
116 } else if constexpr (std::is_arithmetic_v<From> && std::is_arithmetic_v<To>) {
117 return convert_numeric<To, From>(val);
118 } else {
119 throw WrongValueType("Requested type does not match stored type.");
120 }
121 }, m_value);
122 }
123
128 inline Type Type() const noexcept {
129 return m_type;
130 }
131
136 inline bool IsNull() const noexcept {
137 return m_type == Type::Null;
138 }
139
140 private:
141 // Helper: safe numeric conversion; only instantiated for arithmetic To and From
142 template<typename To, typename From>
143 requires (std::is_arithmetic_v<To> && std::is_arithmetic_v<From>)
144 static To convert_numeric(const From& val) {
145 if constexpr (std::is_integral_v<From> && std::is_integral_v<To>) {
146 if constexpr (std::is_signed_v<From>) {
147 std::intmax_t from = static_cast<std::intmax_t>(val);
148 if constexpr (std::is_signed_v<To>) {
149 if (from < static_cast<std::intmax_t>(std::numeric_limits<To>::lowest()) || from > static_cast<std::intmax_t>(std::numeric_limits<To>::max()))
150 throw WrongValueType("Integer conversion would overflow/narrow.");
151 return static_cast<To>(from);
152 } else {
153 // From signed, To unsigned
154 if (from < 0) throw WrongValueType("Negative value cannot be converted to unsigned.");
155 if (static_cast<std::uintmax_t>(from) > static_cast<std::uintmax_t>(std::numeric_limits<To>::max()))
156 throw WrongValueType("Integer conversion would overflow/narrow.");
157 return static_cast<To>(from);
158 }
159 } else {
160 // From unsigned
161 std::uintmax_t from = static_cast<std::uintmax_t>(val);
162 if constexpr (std::is_signed_v<To>) {
163 if (from > static_cast<std::uintmax_t>(std::numeric_limits<To>::max()))
164 throw WrongValueType("Integer conversion would overflow/narrow.");
165 return static_cast<To>(from);
166 } else {
167 // both unsigned
168 if (from > static_cast<std::uintmax_t>(std::numeric_limits<To>::max()))
169 throw WrongValueType("Integer conversion would overflow/narrow.");
170 return static_cast<To>(from);
171 }
172 }
173 } else if constexpr (std::is_integral_v<From> && std::is_floating_point_v<To>) {
174 return static_cast<To>(val);
175 } else if constexpr (std::is_floating_point_v<From> && std::is_integral_v<To>) {
176 long double d = static_cast<long double>(val);
177 if (!std::isfinite(d)) throw WrongValueType("Non-finite floating conversion to integer.");
178 if (std::trunc(d) != d) throw WrongValueType("Floating value has fractional part; would lose data.");
179 std::intmax_t tmp = static_cast<std::intmax_t>(d);
180 if constexpr (std::is_signed_v<To>) {
181 if (tmp < static_cast<std::intmax_t>(std::numeric_limits<To>::lowest()) || tmp > static_cast<std::intmax_t>(std::numeric_limits<To>::max()))
182 throw WrongValueType("Floating to integer conversion would overflow/narrow.");
183 return static_cast<To>(tmp);
184 } else {
185 // To unsigned
186 if (tmp < 0) throw WrongValueType("Negative value cannot be converted to unsigned.");
187 if (static_cast<std::uintmax_t>(tmp) > static_cast<std::uintmax_t>(std::numeric_limits<To>::max()))
188 throw WrongValueType("Floating to integer conversion would overflow/narrow.");
189 return static_cast<To>(tmp);
190 }
191 } else if constexpr (std::is_floating_point_v<From> && std::is_floating_point_v<To>) {
192 return static_cast<To>(val);
193 } else {
194 throw WrongValueType("Unsupported numeric conversion.");
195 }
196 }
197 ValuesVariant m_value;
198 enum Type m_type;
199 };
200}
Value class for databases.
Definition value.hxx:20
Value(Value &&) noexcept=default
bool IsNull() const noexcept
Definition value.hxx:136
Type
Type of a value.
Definition value.hxx:26
Type Type() const noexcept
Definition value.hxx:128
Value() noexcept
Definition value.hxx:43
Value(const Value &)=default
Exception thrown when value type requested is not correct.
Definition exception.hxx:45