#ifndef MATADOR_IDENTIFIER_HPP #define MATADOR_IDENTIFIER_HPP #include "matador/utils/basic_types.hpp" #include "matador/utils/default_type_traits.hpp" #include "matador/utils/error.hpp" #include "matador/utils/field_attributes.hpp" #include "matador/utils/result.hpp" #include "matador/utils/types.hpp" #include #include #include #include #include #include namespace matador::utils { class value; class identifier_serializer { public: virtual ~identifier_serializer() = default; virtual void serialize(int8_t &, const field_attributes &) = 0; virtual void serialize(int16_t &, const field_attributes &) = 0; virtual void serialize(int32_t &, const field_attributes &) = 0; virtual void serialize(int64_t &, const field_attributes &) = 0; virtual void serialize(uint8_t &, const field_attributes &) = 0; virtual void serialize(uint16_t &, const field_attributes &) = 0; virtual void serialize(uint32_t &, const field_attributes &) = 0; virtual void serialize(uint64_t &, const field_attributes &) = 0; virtual void serialize(std::string &, const field_attributes &) = 0; virtual void serialize(null_type_t &, const field_attributes &) = 0; }; template struct identifier_type_traits; template struct identifier_type_traits && std::is_signed_v > > { static bool is_valid(Type value) { return value != 0; } static std::string to_string(const Type value) { return std::to_string(value); } }; template struct identifier_type_traits && !std::is_signed_v > > { static bool is_valid(Type value) { return value > 0; } static std::string to_string(const Type value) { return std::to_string(value); } }; template struct identifier_type_traits > > { static bool is_valid(const Type &value) { return !value.empty(); } static std::string to_string(const Type &value) { return value; } }; template<> struct identifier_type_traits { static bool is_valid() { return false; } static std::string to_string() { return "null"; } }; namespace detail { template size_t hash(const Type &value) { return std::hash()(value); } size_t hash(const std::string &value); } template struct is_identifier_supported : std::false_type {}; template <> struct is_identifier_supported : std::true_type {}; template <> struct is_identifier_supported : std::true_type {}; template <> struct is_identifier_supported : std::true_type {}; template <> struct is_identifier_supported : std::true_type {}; template <> struct is_identifier_supported : std::true_type {}; template <> struct is_identifier_supported : std::true_type {}; template <> struct is_identifier_supported : std::true_type {}; template <> struct is_identifier_supported : std::true_type {}; template <> struct is_identifier_supported : std::true_type {}; template inline constexpr bool is_identifier_supported_v = is_identifier_supported>::value; class identifier { public: using value_type = std::variant< std::monostate, int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t, std::string >; identifier(); template, int> = 0> explicit identifier(Type &&id) : value_(std::forward(id)) { } identifier(const identifier &x) = default; identifier &operator=(const identifier &x); identifier(identifier &&x) noexcept = default; identifier &operator=(identifier &&x) noexcept = default; explicit identifier(std::nullptr_t); explicit identifier(const char *value); identifier& operator=(std::nullptr_t); template> && !std::is_same_v, bool>, int> = 0> identifier& operator=(Type value) { assign_integral(value); return *this; } identifier& operator=(const std::string &value); identifier& operator=(const char *value); template && std::is_same_v, bool>, int> = 0> identifier& operator=(Type &&value) { value_ = std::forward(value); return *this; } ~identifier() = default; result assign(const value &val); static result from_value(const value &val); [[nodiscard]] database_type to_database_type() const; bool operator==(const identifier &x) const; bool operator!=(const identifier &x) const; bool operator<(const identifier &x) const; bool operator<=(const identifier &x) const; bool operator>(const identifier &x) const; bool operator>=(const identifier &x) const; [[nodiscard]] std::string str() const; [[nodiscard]] const std::type_index &type_index() const; [[nodiscard]] basic_type type() const; [[nodiscard]] bool is_integer() const; [[nodiscard]] bool is_varchar() const; [[nodiscard]] bool is_null() const; [[nodiscard]] bool is_valid() const; void clear(); void serialize(identifier_serializer &s) const; [[nodiscard]] size_t hash() const; template , int> = 0> result as() const; template && !std::is_same_v, int> = 0> result convert() const; friend std::ostream &operator<<(std::ostream &out, const identifier &id); private: template void assign_integral(Type value) { if constexpr (std::is_signed_v) { if (sizeof(Type) <= sizeof(int8_t)) { value_ = static_cast(value); } else if (sizeof(Type) <= sizeof(int16_t)) { value_ = static_cast(value); } else if (sizeof(Type) <= sizeof(int32_t)) { value_ = static_cast(value); } else { value_ = static_cast(value); } } else { if (sizeof(Type) <= sizeof(uint8_t)) { value_ = static_cast(value); } else if (sizeof(Type) <= sizeof(uint16_t)) { value_ = static_cast(value); } else if (sizeof(Type) <= sizeof(uint32_t)) { value_ = static_cast(value); } else { value_ = static_cast(value); } } } static size_t type_rank(const value_type &value); static std::type_index type_index_from_value(const value_type &value); static basic_type type_from_value(const value_type &value); private: value_type value_{std::monostate{}}; }; template bool in_range(Source value) { if constexpr (std::is_signed_v == std::is_signed_v) { return value >= static_cast((std::numeric_limits::min)()) && value <= static_cast((std::numeric_limits::max)()); } else if constexpr (std::is_signed_v && !std::is_signed_v) { if (value < 0) { return false; } using UnsignedSource = std::make_unsigned_t; return static_cast(value) <= (std::numeric_limits::max)(); } else { return value <= static_cast>((std::numeric_limits::max)()); } } template , int>> result identifier::as() const { return std::visit([](const auto &v) -> result { using StoredType = std::decay_t; if constexpr (std::is_same_v) { return failure(error{}); } else if constexpr (std::is_same_v) { return ok(v); } else { return failure(error{}); } }, value_); } template && !std::is_same_v, int>> result identifier::convert() const { return std::visit([](const auto &v) -> result { using Stored = std::decay_t; if constexpr (std::is_same_v) { return failure(error{}); } else if constexpr (std::is_integral_v) { if (!in_range(v)) { return failure(error{}); } return ok(static_cast(v)); } else { return failure(error{}); } }, value_); } static identifier null_identifier{}; /// @cond MATADOR_DEV struct id_pk_hash { size_t operator()(const identifier &id) const; }; /// @endcond } template<> struct std::hash { size_t operator()(const matador::utils::identifier &id) const noexcept { return id.hash(); } }; // namespace std #endif //MATADOR_IDENTIFIER_HPP