#pragma once #include #include #include #include #include #include #include namespace util { template class Buffer; } namespace dv { using integer_t = int64_t; using number_t = double; using boolean_t = bool; using byte_t = unsigned char; using key_t = std::string; enum class value_type : uint8_t { none = 0, object, list, bytes, string, number, boolean, integer }; namespace objects { class Object; class List; using Bytes = util::Buffer; } class value; using pair = std::pair; class value { value_type type = value_type::none; union value_u { integer_t integer; number_t number; boolean_t boolean; std::string string; std::shared_ptr object; std::shared_ptr list; std::shared_ptr bytes; value_u() {} ~value_u() {} } val; value& setBoolean(boolean_t v) { this->~value(); type = value_type::boolean; val.boolean = v; return *this; } value& setInteger(integer_t v) { this->~value(); type = value_type::integer; val.integer = v; return *this; } value& setNumber(number_t v) { this->~value(); type = value_type::number; val.number = v; return *this; } value& setNone() { this->~value(); type = value_type::none; return *this; } value& setString(std::string v) { this->~value(); new(&val.string)std::string(); type = value_type::string; val.string = std::move(v); return *this; } value& setList(const std::shared_ptr& ptr) { this->~value(); new(&val.list)std::shared_ptr(); type = value_type::list; val.list = ptr; return *this; } value& setObject(const std::shared_ptr& ptr) { this->~value(); new(&val.object)std::shared_ptr(); type = value_type::object; val.object = ptr; return *this; } value& setBytes(const std::shared_ptr& ptr) { this->~value(); new(&val.bytes)std::shared_ptr(); type = value_type::bytes; val.bytes = ptr; return *this; } public: value() { type = value_type::none; } value(value_type type); template value(T v) { this->operator=(v); } value(const value& v) { this->operator=(v); } ~value() { switch (type) { case value_type::object: val.object.reset(); break; case value_type::list: val.list.reset(); break; case value_type::bytes: val.bytes.reset(); break; case value_type::string: val.string.~basic_string(); break; default: break; } } value& operator=(int8_t v) { return setInteger(v); } value& operator=(int16_t v) { return setInteger(v); } value& operator=(int32_t v) { return setInteger(v); } value& operator=(int64_t v) { return setInteger(v); } value& operator=(uint8_t v) { return setInteger(v); } value& operator=(uint16_t v) { return setInteger(v); } value& operator=(uint32_t v) { return setInteger(v); } value& operator=(uint64_t v) { return setInteger(v); } value& operator=(float v) { return setNumber(v); } value& operator=(double v) { return setNumber(v); } value& operator=(bool v) { return setBoolean(v); } value& operator=(std::string_view v) { return setString(std::string(v)); } value& operator=(std::string v) { return setString(std::move(v)); } value& operator=(const std::shared_ptr& ptr) { return setList(ptr); } value& operator=(const std::shared_ptr& ptr) { return setObject(ptr); } value& operator=(const std::shared_ptr& ptr) { return setBytes(ptr); } value& operator=(const value& v) { switch (v.type) { case value_type::object: setObject(v.val.object); break; case value_type::list: setList(v.val.list); break; case value_type::bytes: setBytes(v.val.bytes); break; case value_type::string: setString(v.val.string); break; case value_type::boolean: setBoolean(val.boolean); break; case value_type::integer: setInteger(val.integer); break; case value_type::number: setNumber(val.number); break; case value_type::none: setNone(); break; } return *this; } value& operator[](const key_t& key); const value& operator[](const key_t& key) const; value& operator[](size_t index); const value& operator[](size_t index) const; }; using reference = value&; using const_reference = const value&; value list(std::initializer_list values); value list() { return list({}); } value object(std::initializer_list pairs); value object() { return object({}); } } #include "util/Buffer.hpp" namespace dv::objects { class Object { public: using map_t = std::unordered_map; private: map_t map; public: Object() = default; Object(std::initializer_list pairs) : map(pairs) {} Object(const Object&) = delete; ~Object() = default; reference operator[](const key_t& key) { return map[key]; } const_reference operator[](const key_t& key) const { return map.at(key); } }; class List { public: using list_t = std::vector; private: list_t list; public: List() = default; List(std::initializer_list values) : list(values) {} List(const List&) = delete; ~List() = default; reference operator[](std::size_t index) { return list.at(index); } const_reference operator[](std::size_t index) const { return list.at(index); } }; } namespace dv { value::value(value_type type) : type(type) { switch (type) { case value_type::object: val.object = std::make_shared(); break; case value_type::list: val.list = std::make_shared(); break; case value_type::bytes: val.bytes = nullptr; // no default size break; case value_type::string: val.string = ""; break; default: break; } } value& value::operator[](const key_t& key) { if (type == value_type::object) { return (*val.object)[key]; } throw std::runtime_error("value is not an object"); } const value& value::operator[](const key_t& key) const { if (type == value_type::object) { return (*val.object)[key]; } throw std::runtime_error("value is not an object"); } value& value::operator[](size_t index) { if (type == value_type::list) { return (*val.list)[index]; } throw std::runtime_error("value is not a list"); } const value& value::operator[](size_t index) const { if (type == value_type::list) { return (*val.list)[index]; } throw std::runtime_error("value is not a list"); } value object(std::initializer_list pairs) { return std::make_shared(pairs); } value list(std::initializer_list values) { return std::make_shared(values); } }