LogIt++
Header-only, macro-first C++ logging library
Loading...
Searching...
No Matches
VariableValue.hpp
Go to the documentation of this file.
1#pragma once
2#ifndef LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_UTILS_VARIABLEVALUE_HPP_INCLUDED
3#define LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_UTILS_VARIABLEVALUE_HPP_INCLUDED
4
7
8#include <time_shield/text/time_formatting.hpp>
9#include <string>
10#include <iostream>
11#include <cstdint>
12#include <type_traits>
13#include <exception>
14#include <iomanip> // std::put_time
15#include <chrono>
16#include <sstream>
17#include <memory>
18#if __cplusplus >= 201703L
19#include <filesystem>
20#include <optional>
21#include <variant>
22#endif
23#ifdef LOGIT_WITH_FMT
24#include <fmt/format.h>
25#endif
26
27namespace logit {
28
33 template <typename EnumType>
34 std::string enum_to_string(EnumType value) {
35 // Convert enum to underlying integral value and then to string.
36 typedef typename std::underlying_type<EnumType>::type UnderlyingType;
37 return std::to_string(static_cast<UnderlyingType>(value));
38 }
39
43 std::string name;
45
75
76 union {
77 int8_t int8_value;
78 uint8_t uint8_value;
79 int16_t int16_value;
80 uint16_t uint16_value;
81 int32_t int32_value;
82 uint32_t uint32_value;
83 int64_t int64_value;
84 uint64_t uint64_value;
89 long double long_double_value;
91
92 std::string string_value;
93 std::error_code error_code_value;
94
95 // Constructors for each type.
96 template <typename T>
97 VariableValue(const std::string& name, T value,
98 typename std::enable_if<std::is_same<T, bool>::value>::type* = nullptr)
100 pod_value.bool_value = value;
101 }
102
103 template <typename T>
104 VariableValue(const std::string& name, T value,
105 typename std::enable_if<std::is_same<T, char>::value>::type* = nullptr)
107 pod_value.char_value = value;
108 }
109
110 explicit VariableValue(const std::string& name, const std::string& value)
112 }
113
114 explicit VariableValue(const std::string& name, const char* value) :
115 VariableValue(name, std::string(value)) {}
116
117 template <typename T>
118 VariableValue(const std::string& name, const T& value,
119 typename std::enable_if<std::is_base_of<std::exception, T>::value>::type* = nullptr)
121 }
122
123 explicit VariableValue(const std::string& name, const std::error_code& ec)
125 }
126
127 template <typename T>
128 VariableValue(const std::string& name, T value,
129 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr)
131 if (std::is_same<T, float>::value) {
133 pod_value.float_value = static_cast<float>(value);
134 } else if (std::is_same<T, double>::value) {
136 pod_value.double_value = static_cast<double>(value);
137 } else if (std::is_same<T, long double>::value) {
139 pod_value.long_double_value = static_cast<long double>(value);
140 }
141 }
142
143#ifdef _MSC_VER
144# pragma warning(push)
145# pragma warning(disable : 4127)
146#endif
147
148 template <typename T>
149 VariableValue(const std::string& name, T value,
150 typename std::enable_if<
151 std::is_integral<T>::value && !std::is_same<T, bool>::value
152 >::type* = nullptr)
154
155 if (std::is_signed<T>::value) {
156 if (sizeof(T) <= sizeof(int8_t)) {
158 pod_value.int8_value = static_cast<int8_t>(value);
159 } else if (sizeof(T) <= sizeof(int16_t)) {
161 pod_value.int16_value = static_cast<int16_t>(value);
162 } else if (sizeof(T) <= sizeof(int32_t)) {
164 pod_value.int32_value = static_cast<int32_t>(value);
165 } else {
167 pod_value.int64_value = static_cast<int64_t>(value);
168 }
169 } else {
170 if (sizeof(T) <= sizeof(uint8_t)) {
172 pod_value.uint8_value = static_cast<uint8_t>(value);
173 } else if (sizeof(T) <= sizeof(uint16_t)) {
175 pod_value.uint16_value = static_cast<uint16_t>(value);
176 } else if (sizeof(T) <= sizeof(uint32_t)) {
178 pod_value.uint32_value = static_cast<uint32_t>(value);
179 } else {
181 pod_value.uint64_value = static_cast<uint64_t>(value);
182 }
183 }
184 }
185
186#ifdef _MSC_VER
187# pragma warning(pop)
188#endif
189
194 template <typename EnumType>
195 VariableValue(const std::string& name, EnumType value,
196 typename std::enable_if<std::is_enum<EnumType>::value>::type* = 0)
199 }
200
201 template <typename Rep, typename Period>
202 VariableValue(const std::string& name, const std::chrono::duration<Rep, Period>& duration)
204 string_value = std::to_string(duration.count()) + " " + duration_units<Period>();
205 }
206
207 template <typename Clock, typename Duration>
208 VariableValue(const std::string& name, const std::chrono::time_point<Clock, Duration>& time_point)
210 auto ts_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_point.time_since_epoch());
211 string_value = time_shield::to_human_readable_ms(ts_ms.count());
212 }
213
214# if __cplusplus >= 201703L
215
216 explicit VariableValue(const std::string& name, const std::filesystem::path& path)
218 }
219
220 template <typename... Ts>
221 explicit VariableValue(const std::string& name, const std::variant<Ts...>& variant)
223 string_value = std::visit([](const auto& value) -> std::string {
224 if constexpr (std::is_arithmetic_v<decltype(value)>) {
225 return std::to_string(value);
226 } else if constexpr (std::is_same_v<decltype(value), std::string>) {
227 return value;
228 } else {
229 std::ostringstream oss;
230 oss << value;
231 return oss.str();
232 }
233 }, variant);
234 }
235
236 template <typename T>
237 explicit VariableValue(const std::string& name, const std::optional<T>& optional)
239 if (optional) {
240 if constexpr (std::is_arithmetic_v<T>) {
241 string_value = std::to_string(*optional);
242 } else if constexpr (std::is_same_v<T, std::string>) {
243 string_value = *optional;
244 } else {
245 std::ostringstream oss;
246 oss << *optional;
247 string_value = oss.str();
248 }
249 } else {
250 string_value = "nullopt";
251 }
252 }
253
254# endif
255
256 explicit VariableValue(const std::string& name, void* ptr)
258 std::ostringstream oss;
259 oss << ptr;
260 string_value = oss.str();
261 }
262
263 template <typename T>
264 explicit VariableValue(const std::string& name, const std::shared_ptr<T>& ptr)
266 std::ostringstream oss;
267 if (ptr) oss << "shared_ptr@" << ptr.get();
268 else oss << "nullptr";
269 string_value = oss.str();
270 }
271
272 template <typename T>
273 explicit VariableValue(const std::string& name, const std::unique_ptr<T>& ptr)
275 std::ostringstream oss;
276 if (ptr) oss << "unique_ptr@" << ptr.get();
277 else oss << "nullptr";
278 string_value = oss.str();
279 }
280
283 : name(other.name), is_literal(other.is_literal), type(other.type),
286 if (is_pod_type(type)) {
287 pod_value = other.pod_value;
288 }
289 }
290
293 if (this == &other) return *this; // Self-assignment check.
294
295 name = other.name;
296 is_literal = other.is_literal;
297 type = other.type;
300
301 if (is_pod_type(type)) {
302 pod_value = other.pod_value;
303 }
304
305 return *this;
306 }
307
309 ~VariableValue() = default;
310
313 std::string to_string() const {
314 switch (type) {
315 case ValueType::INT8_VAL: return std::to_string(pod_value.int8_value);
316 case ValueType::UINT8_VAL: return std::to_string(pod_value.uint8_value);
317 case ValueType::INT16_VAL: return std::to_string(pod_value.int16_value);
318 case ValueType::UINT16_VAL: return std::to_string(pod_value.uint16_value);
319 case ValueType::INT32_VAL: return std::to_string(pod_value.int32_value);
320 case ValueType::UINT32_VAL: return std::to_string(pod_value.uint32_value);
321 case ValueType::INT64_VAL: return std::to_string(pod_value.int64_value);
322 case ValueType::UINT64_VAL: return std::to_string(pod_value.uint64_value);
323 case ValueType::BOOL_VAL: return pod_value.bool_value ? "true" : "false";
324 case ValueType::CHAR_VAL: return std::string(1, pod_value.char_value);
325 case ValueType::FLOAT_VAL: return std::to_string(pod_value.float_value);
326 case ValueType::DOUBLE_VAL: return std::to_string(pod_value.double_value);
327 case ValueType::LONG_DOUBLE_VAL: return std::to_string(static_cast<double>(pod_value.long_double_value));
338 return string_value;
340 return error_code_value.message() + " (" + std::to_string(error_code_value.value()) + ")";
341 default: break;
342 }
343 return "unknown";
344 }
345
349 std::string to_string(const char* fmt) const {
350 switch (type) {
351 case ValueType::INT8_VAL: return logit::format(fmt, pod_value.int8_value);
352 case ValueType::UINT8_VAL: return format(fmt, pod_value.uint8_value);
353 case ValueType::INT16_VAL: return format(fmt, pod_value.int16_value);
354 case ValueType::UINT16_VAL: return format(fmt, pod_value.uint16_value);
355 case ValueType::INT32_VAL: return format(fmt, pod_value.int32_value);
356 case ValueType::UINT32_VAL: return format(fmt, pod_value.uint32_value);
357 case ValueType::INT64_VAL: return format(fmt, pod_value.int64_value);
358 case ValueType::UINT64_VAL: return format(fmt, pod_value.uint64_value);
359 case ValueType::BOOL_VAL: return format(fmt, pod_value.bool_value);
360 case ValueType::CHAR_VAL: return format(fmt, pod_value.char_value);
361 case ValueType::FLOAT_VAL: return format(fmt, pod_value.float_value);
362 case ValueType::DOUBLE_VAL: return format(fmt, pod_value.double_value);
363 case ValueType::LONG_DOUBLE_VAL: return format(fmt, static_cast<double>(pod_value.long_double_value));
374 return format(fmt, string_value.c_str());
376 return format(fmt, error_code_value.message().c_str(), error_code_value.value());
377 default: break;
378 }
379 return "unknown";
380 }
381
382#ifdef LOGIT_WITH_FMT
386 std::string to_string_fmt(const char* fmt) const {
387 switch (type) {
388 case ValueType::INT8_VAL: return fmt::format(fmt, pod_value.int8_value);
389 case ValueType::UINT8_VAL: return fmt::format(fmt, pod_value.uint8_value);
390 case ValueType::INT16_VAL: return fmt::format(fmt, pod_value.int16_value);
391 case ValueType::UINT16_VAL: return fmt::format(fmt, pod_value.uint16_value);
392 case ValueType::INT32_VAL: return fmt::format(fmt, pod_value.int32_value);
393 case ValueType::UINT32_VAL: return fmt::format(fmt, pod_value.uint32_value);
394 case ValueType::INT64_VAL: return fmt::format(fmt, pod_value.int64_value);
395 case ValueType::UINT64_VAL: return fmt::format(fmt, pod_value.uint64_value);
396 case ValueType::BOOL_VAL: return fmt::format(fmt, pod_value.bool_value);
397 case ValueType::CHAR_VAL: return fmt::format(fmt, pod_value.char_value);
398 case ValueType::FLOAT_VAL: return fmt::format(fmt, pod_value.float_value);
399 case ValueType::DOUBLE_VAL: return fmt::format(fmt, pod_value.double_value);
400 case ValueType::LONG_DOUBLE_VAL: return fmt::format(fmt, static_cast<double>(pod_value.long_double_value));
411 return fmt::format(fmt, string_value);
413 return fmt::format(fmt, error_code_value.message(), error_code_value.value());
414 default: break;
415 }
416 return "unknown";
417 }
418#endif
419
420 private:
424 static bool is_valid_literal_name(const std::string& name) {
425 if (name.empty()) return false;
426 return !std::isdigit(static_cast<unsigned char>(name[0]));
427 }
428
433 switch (type) {
447 return true;
448 default:
449 return false;
450 }
451 }
452
456 template <typename Period>
457 static std::string duration_units() {
458 if (std::is_same<Period, std::ratio<1>>::value) {
459 return "s"; // seconds
460 } else if (std::is_same<Period, std::milli>::value) {
461 return "ms"; // milliseconds
462 } else if (std::is_same<Period, std::micro>::value) {
463 return "us"; // microseconds
464 } else if (std::is_same<Period, std::nano>::value) {
465 return "ns"; // nanoseconds
466 } else if (std::is_same<Period, std::ratio<60>>::value) {
467 return "min"; // minutes
468 } else if (std::is_same<Period, std::ratio<3600>>::value) {
469 return "h"; // hours
470 } else {
471 return "custom"; // Custom units
472 }
473 }
474 }; // VariableValue
475
476} // namespace logit
477
478#endif // LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_UTILS_VARIABLEVALUE_HPP_INCLUDED
The primary namespace for the LogIt++ library.
std::string format(const char *fmt,...)
Formats a string according to the specified format.
Definition format.hpp:22
std::string enum_to_string(EnumType value)
Helper function to convert an enumeration to a string.
Structure for storing values of various types, including enumerations.
VariableValue(const std::string &name, const std::chrono::duration< Rep, Period > &duration)
long double long_double_value
std::error_code error_code_value
Variable to store std::error_code.
std::string name
Variable name.
VariableValue & operator=(const VariableValue &other)
Assignment operator.
VariableValue(const std::string &name, const T &value, typename std::enable_if< std::is_base_of< std::exception, T >::value >::type *=nullptr)
static std::string duration_units()
Helper function to get the unit of the duration.
VariableValue(const std::string &name, const std::chrono::time_point< Clock, Duration > &time_point)
VariableValue(const std::string &name, T value, typename std::enable_if< std::is_same< T, bool >::value >::type *=nullptr)
~VariableValue()=default
Destructor.
bool is_literal
Flag indicating if the variable is a literal.
std::string to_string() const
Method to get the value as a string.
enum logit::VariableValue::ValueType type
Specifies the type of the stored value in the VariableValue structure.
std::string string_value
Variable to store string, exception messages, and enums.
VariableValue(const std::string &name, const std::unique_ptr< T > &ptr)
VariableValue(const std::string &name, const std::string &value)
VariableValue(const VariableValue &other)
Copy constructor.
VariableValue(const std::string &name, const std::shared_ptr< T > &ptr)
ValueType
Enumeration of possible value types for VariableValue.
@ BOOL_VAL
Value of type bool.
@ FLOAT_VAL
Value of type float (single-precision floating point).
@ ENUM_VAL
Value of any enumeration type (converted to string or integral value).
@ INT16_VAL
Value of type int16_t (signed 16-bit integer).
@ CHAR_VAL
Value of type char (single character).
@ OPTIONAL_VAL
Value of type std::optional (optional value holder).
@ STRING_VAL
Value of type std::string (dynamic-length string).
@ POINTER_VAL
Value of type void* (raw pointer).
@ UINT64_VAL
Value of type uint64_t (unsigned 64-bit integer).
@ UINT32_VAL
Value of type uint32_t (unsigned 32-bit integer).
@ VARIANT_VAL
Value of type std::variant (type-safe union).
@ SMART_POINTER_VAL
Value of type std::shared_ptr or std::unique_ptr (smart pointers).
@ INT64_VAL
Value of type int64_t (signed 64-bit integer).
@ PATH_VAL
Value of type std::filesystem::path (filesystem path).
@ DURATION_VAL
Value of type std::chrono::duration (time duration).
@ DOUBLE_VAL
Value of type double (double-precision floating point).
@ INT32_VAL
Value of type int32_t (signed 32-bit integer).
@ UINT8_VAL
Value of type uint8_t (unsigned 8-bit integer).
@ LONG_DOUBLE_VAL
Value of type long double (extended-precision floating point).
@ TIME_POINT_VAL
Value of type std::chrono::time_point (specific point in time).
@ INT8_VAL
Value of type int8_t (signed 8-bit integer).
@ UINT16_VAL
Value of type uint16_t (unsigned 16-bit integer).
@ UNKNOWN_VAL
Unknown or unsupported value type.
@ EXCEPTION_VAL
Value representing an exception (derived from std::exception).
@ ERROR_CODE_VAL
Value of type std::error_code (system error code).
union logit::VariableValue::@0 pod_value
Union to store POD types.
VariableValue(const std::string &name, EnumType value, typename std::enable_if< std::is_enum< EnumType >::value >::type *=0)
Constructor for enumerations.
static bool is_valid_literal_name(const std::string &name)
Helper function to check if a name is a valid literal.
VariableValue(const std::string &name, const std::error_code &ec)
static bool is_pod_type(ValueType type)
Helper function to determine if a ValueType represents a POD type.
VariableValue(const std::string &name, T value, typename std::enable_if< std::is_integral< T >::value &&!std::is_same< T, bool >::value >::type *=nullptr)
VariableValue(const std::string &name, T value, typename std::enable_if< std::is_same< T, char >::value >::type *=nullptr)
std::string to_string(const char *fmt) const
Method to get the value as a formatted string.
VariableValue(const std::string &name, T value, typename std::enable_if< std::is_floating_point< T >::value >::type *=nullptr)
VariableValue(const std::string &name, const char *value)
VariableValue(const std::string &name, void *ptr)