#ifndef MATADOR_CONVERT_HPP #define MATADOR_CONVERT_HPP #include "matador/utils/types.hpp" #include "matador/utils/result.hpp" #include #include #include #include #include #include /* * Conversion matrix * from> | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | bool | float | double | string | date | time | timestamp | blob | null * to | | | | | | | | | | | | | | | | | * ------------+------+-------+-------+-------+-------+--------+--------+--------+------+-------+--------+--------+------+------+-----------+------+----- * int8 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A * int16 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A * int32 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A * int64 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A * uint8 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A * uint16 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A * uint32 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A * uint64 | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | ok | ok | ok | try | N/A * bool | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | N/A | N/A | ok | try | N/A * float | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | N/A | N/A | ok | try | N/A * double | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | try | N/A | N/A | ok | try | N/A * string | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A * date | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A | N/A | try | ok | ok | ok | N/A | N/A * time | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A | N/A | try | ok | ok | ok | N/A | N/A * timestamp | ok | ok | ok | ok | ok | ok | ok | ok | N/A | N/A | N/A | try | ok | ok | ok | N/A | N/A * blob | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | ok | N/A * null | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | ok | ok * * from integral to date/time works, value is interpreted as std::chrono::timepoint * from integral to blob works, bytes of integral data will converted to blob * from boolean to blob works, byte of bool data will converted to blob * from floating point to blob works, bytes of floating point data will converted to blob * from date to blob works, bytes of date will converted to blob * from time to blob works, bytes of time will converted to blob * from string to blob works, bytes of string data will converted to blob * from floating point to integral works, fractions are truncated * from date/time to integral works, value will be converted from std::chrono::timepoint * from blob to integral works, value will be converted missing is filled with zero, rest is omitted * from blob to floating point works, value will be converted missing is filled with zero, rest is omitted * from blob to boolean works, value will be converted missing is filled with zero, rest is omitted */ namespace matador::utils { enum class conversion_error { Ok, NotConvertable, MissingData }; enum class conversion_policy { Strict, Relax }; // template < typename DestType, typename SourceType > // result to(const SourceType &/*from*/); // result to(const SourceType &/*from*/, conversion_policy /*policy*/ = conversion_policy::Strict); // { // return failure(conversion_error::NotConvertable); // } /* * Integral, Floating point & bool conversion */ template < typename DestType, typename SourceType > result to(const SourceType &source, std::enable_if_t && std::is_arithmetic_v>* = nullptr) { return ok(static_cast(source)); } template < typename DestType, typename SourceType > result to(const SourceType &source, std::enable_if_t && std::is_same_v>* = nullptr) { return ok(source); } template < typename DestType, typename SourceType > result to(const SourceType &source, std::enable_if_t && !std::is_same_v && std::is_same_v>* = nullptr) { std::array buffer{}; auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), source, 10); if (ec == std::errc{}) { return ok(std::string(buffer.data(), ptr)); } return failure(conversion_error::NotConvertable/*, "couldn't convert value to std::string"}*/); } template < typename DestType, typename SourceType > result to(const SourceType &source, std::enable_if_t && std::is_same_v>* = nullptr) { std::array buffer{}; auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), source, std::chars_format::general); if (ec == std::errc{}) { return ok(std::string(buffer.data(), ptr)); } return failure(conversion_error::NotConvertable/*, "couldn't convert value to std::string"}*/); } template < typename DestType > result to(const std::string &source, std::enable_if_t && std::is_signed_v>* = nullptr) { if (source.empty()) { return failure(conversion_error::MissingData/*, "failed to convert empty string"}*/); } char *end; errno = 0; const auto result = strtoll(source.c_str(), &end, 10); if (errno == ERANGE) { return failure(conversion_error::NotConvertable/*, "failed to convert string value"}*/); } return ok(static_cast(result)); } template < typename DestType > result to(const std::string &source, std::enable_if_t && std::is_unsigned_v && !std::is_same_v>* = nullptr) { if (source.empty()) { return failure(conversion_error::MissingData/*, "failed to convert empty string"}*/); } char *end; errno = 0; const auto result = strtoull(source.c_str(), &end, 10); if (errno == ERANGE) { return failure(conversion_error::NotConvertable/*, "failed to convert string value"}*/); } return ok(static_cast(result)); } template < typename DestType > result to(const std::string &source, std::enable_if_t>* = nullptr) { if (source.empty()) { return failure(conversion_error::MissingData/*, "failed to convert empty string"}*/); } char *end; errno = 0; const auto result = strtod(source.c_str(), &end); if (errno == ERANGE) { return failure(conversion_error::NotConvertable/*, "failed to convert string value"}*/); } return ok(static_cast(result)); } template < typename DestType > result to(const blob_type_t &source, std::enable_if_t>* = nullptr) { return ok(source); } // template < typename DestType > // result to(const std::string &source, std::enable_if_t>* = nullptr) { // if (source.empty()) { // return failure(conversion_error::MissingData/*, "failed to convert empty string"}*/); // } // // } // static std::unordered_map string_to_bool_map = { {"true", true}, {"t", true}, {"on", true}, {"1", true}, {"false", false}, {"f", false}, {"off", false}, {"0", false} }; template < typename DestType > result to(const std::string &source, std::enable_if_t>* = nullptr) { if (source.empty()) { return failure(conversion_error::MissingData); } const auto it = string_to_bool_map.find(source); if (it == string_to_bool_map.end()) { return failure(conversion_error::NotConvertable); } return ok(it->second); } template < typename DestType > result to(const char *source, std::enable_if_t>* = nullptr) { if (strlen(source) == 0) { return failure(conversion_error::MissingData); } const auto it = string_to_bool_map.find(source); if (it == string_to_bool_map.end()) { return failure(conversion_error::NotConvertable); } return ok(it->second); } template < typename DestType, typename SourceType > result to(const SourceType &source, std::enable_if_t &&std::is_same_v>* = nullptr) { return ok(std::string(source ? "true" : "false")); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t &&std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &source, std::enable_if_t &&std::is_same_v>* = nullptr) { if (source == nullptr) { return ok(std::string{}); } return ok(std::string(source)); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &source, std::enable_if_t && std::is_same_v>* = nullptr) { DestType result; result.resize(sizeof(source)); std::memcpy(result.data(), &source, sizeof(source)); return ok(result); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType > result to(const std::string &source, std::enable_if_t>* = nullptr) { std::tm result{}; std::istringstream iss(source); iss >> std::get_time(&result, "%Y-%m-%d"); if (iss.fail()) { return failure(conversion_error::NotConvertable); } return ok(date_type_t{result.tm_year + 1900, static_cast(result.tm_mon + 1), static_cast(result.tm_mday)}); } template < typename DestType > result to(const char *source, std::enable_if_t>* = nullptr) { return to(std::string{source}); } template < typename DestType > result to(const std::string &source, std::enable_if_t>* = nullptr) { std::tm result{}; std::istringstream iss(source); iss >> std::get_time(&result, "%H:%M:%S"); if (iss.fail()) { return failure(conversion_error::NotConvertable); } return ok(time_type_t{static_cast(result.tm_hour), static_cast(result.tm_min), static_cast(result.tm_sec)}); } template < typename DestType > result to(const char *source, std::enable_if_t>* = nullptr) { return to(std::string{source}); } template < typename DestType > result to(const std::string &source, std::enable_if_t>* = nullptr) { std::tm result{}; std::istringstream iss(source); iss >> std::get_time(&result, "%Y-%m-%d %H:%M:%S"); if (iss.fail()) { return failure(conversion_error::NotConvertable); } const std::time_t tt = std::mktime(&result); if (tt == -1) { return failure(conversion_error::NotConvertable); } return ok(std::chrono::system_clock::from_time_t(tt)); } template < typename DestType > result to(const char *source, std::enable_if_t>* = nullptr) { return to(std::string{source}); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && !std::is_same_v && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && !std::is_same_v && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && !std::is_same_v && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && !std::is_same_v && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && !std::is_same_v && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && !std::is_same_v && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType, typename SourceType > result to(const SourceType &/*source*/, std::enable_if_t && std::is_same_v>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType> result to(const blob_type_t &/*source*/, std::enable_if_t>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType> result to(const blob_type_t &/*source*/, std::enable_if_t>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType> result to(const blob_type_t &/*source*/, std::enable_if_t>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType> result to(const bool &/*source*/, std::enable_if_t>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType> result to(const bool &/*source*/, std::enable_if_t>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType> result to(const bool &/*source*/, std::enable_if_t>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType> result to(const time_type_t &/*source*/, std::enable_if_t>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType> result to(const time_type_t &source, std::enable_if_t>* = nullptr) { return ok(source); } template < typename DestType> result to(const date_type_t &/*source*/, std::enable_if_t>* = nullptr) { return failure(conversion_error::NotConvertable); } template < typename DestType> result to(const date_type_t &source, std::enable_if_t>* = nullptr) { return ok(source); } template < typename DestType> result to(const timestamp_type_t &source, std::enable_if_t>* = nullptr) { const std::time_t tt = std::chrono::system_clock::to_time_t(source); const std::tm* result = std::localtime(&tt); return ok(time_type_t{static_cast(result->tm_hour), static_cast(result->tm_min), static_cast(result->tm_sec)}); } template < typename DestType> result to(const timestamp_type_t &source, std::enable_if_t>* = nullptr) { const std::time_t tt = std::chrono::system_clock::to_time_t(source); const std::tm* result = std::localtime(&tt); return ok(date_type_t{result->tm_year + 1900, static_cast(result->tm_mon + 1), static_cast(result->tm_mday)}); } } #endif //MATADOR_CONVERT_HPP