From fb107341b4638695dcb9ac895471ef60debd7253 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 16 Apr 2017 15:12:39 +0900 Subject: [PATCH] implement union-based toml::value --- test.cpp | 22 ++++ toml.hpp | 392 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 414 insertions(+) create mode 100644 test.cpp create mode 100644 toml.hpp diff --git a/test.cpp b/test.cpp new file mode 100644 index 0000000..a1d7759 --- /dev/null +++ b/test.cpp @@ -0,0 +1,22 @@ +#include "toml.hpp" + +int main() +{ + bool b = true; + int i=42; + double f = 3.14; + toml::value v1(i); + toml::value v2(b); + toml::value v3(f); + toml::value v4("hoge"); + + std::cout << "v1: " << v1.t() << " = " << v1.cast() << std::endl; + std::cout << "v2: " << v2.t() << " = " << v2.cast() << std::endl; + std::cout << "v3: " << v3.t() << " = " << v3.cast() << std::endl; + std::cout << "v4: " << v4.t() << " = " << v4.cast() << std::endl; + v1.reset(f); + std::cout << "v1: " << v1.t() << " = " << v1.cast() << std::endl; + + + return 0; +} diff --git a/toml.hpp b/toml.hpp new file mode 100644 index 0000000..a69afff --- /dev/null +++ b/toml.hpp @@ -0,0 +1,392 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Toru Niina + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef TOML_FOR_MODERN_CPP +#define TOML_FOR_MODERN_CPP +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace toml +{ + +class value; +using key = std::string; + +using Boolean = bool; +using Integer = std::int64_t; +using Float = double; +using String = std::string; +using Datetime = std::chrono::system_clock::time_point; +using Array = std::vector; +using Table = std::map; + +enum class type +{ + Boolean, + Integer, + Float, + String, + Datetime, + Array, + Table, + Unknown, +}; + +template +inline std::basic_ostream& +operator<<(std::basic_ostream& os, type t) +{ + switch(t) + { + case toml::type::Boolean : os << "Boolean"; return os; + case toml::type::Integer : os << "Integer"; return os; + case toml::type::Float : os << "Float"; return os; + case toml::type::String : os << "String"; return os; + case toml::type::Datetime: os << "Datetime"; return os; + case toml::type::Array : os << "Array"; return os; + case toml::type::Table : os << "Table"; return os; + case toml::type::Unknown : os << "Unknown"; return os; + default : os << "Nothing"; return os; + } +} + +template, + typename alloc = std::allocator> +inline std::basic_string +stringize(type t) +{ + switch(t) + { + case toml::type::Boolean : return "Boolean"; + case toml::type::Integer : return "Integer"; + case toml::type::Float : return "Float"; + case toml::type::String : return "String"; + case toml::type::Datetime: return "Datetime"; + case toml::type::Array : return "Array"; + case toml::type::Table : return "Table"; + case toml::type::Unknown : return "Unknown"; + default : return "Nothing"; + } +} + +namespace detail +{ + +template +using unwrap_t = typename std::decay::type; + +template +struct is_std_array : std::false_type {}; +template +struct is_std_array> : std::true_type{}; +template +struct is_std_vector : std::false_type{}; +template +struct is_std_vector> : std::true_type{}; +template +struct is_array : std::integral_constant::value || + is_std_vector::value || std::is_array::value>{}; + +template +struct is_table : std::false_type {}; +template +struct is_table> : std::true_type{}; +template +struct is_table> : std::true_type{}; + +template +constexpr inline type check_type() +{ + return std::is_same, bool>::value ? type::Boolean : + std::is_integral>::value ? type::Integer : + std::is_floating_point>::value ? type::Float : + std::is_same, std::string>::value ? type::String : + std::is_same, const char*>::value ? type::String : + toml::detail::is_array>::value ? type::Array : + toml::detail::is_table>::value ? type::Table : + type::Unknown; +} + +template +struct toml_default_type{}; +template<> +struct toml_default_type{typedef Boolean type;}; +template<> +struct toml_default_type{typedef Integer type;}; +template<> +struct toml_default_type{typedef Float type;}; +template<> +struct toml_default_type{typedef String type;}; +template<> +struct toml_default_type{typedef Datetime type;}; +template<> +struct toml_default_type{typedef Array type;}; +template<> +struct toml_default_type{typedef Table type;}; +template<> +struct toml_default_type{typedef void type;}; + +} // detail + +struct exception : public std::exception +{ + public: + virtual ~exception() override = default; + virtual const char* what() const noexcept override {return "";} +}; + +struct syntax_error : public toml::exception +{ + public: + explicit syntax_error(const std::string& what_arg) : what_arg_(what_arg){} + explicit syntax_error(const char* what_arg) : what_arg_(what_arg){} + virtual ~syntax_error() override = default; + virtual const char* what() const noexcept override {return what_arg_.c_str();} + + protected: + std::string what_arg_; +}; + +struct type_error : public toml::exception +{ + public: + explicit type_error(const std::string& what_arg) : what_arg_(what_arg){} + explicit type_error(const char* what_arg) : what_arg_(what_arg){} + virtual ~type_error() override = default; + virtual const char* what() const noexcept override {return what_arg_.c_str();} + + protected: + std::string what_arg_; +}; + +struct internal_error : public toml::exception +{ + public: + explicit internal_error(const std::string& what_arg) : what_arg_(what_arg){} + explicit internal_error(const char* what_arg) : what_arg_(what_arg){} + virtual ~internal_error() override = default; + virtual const char* what() const noexcept override {return what_arg_.c_str();} + protected: + std::string what_arg_; +}; + +template +struct value_traits +{ + constexpr static type type_index = detail::check_type(); + constexpr static bool is_toml_value = (type_index != type::Unknown); + typedef typename detail::toml_default_type::type value_type; +}; + +class value +{ + public: + + template::is_toml_value, std::nullptr_t>::type = nullptr> + value(T&& v) + : type_(toml::detail::check_type()) + { + switch_assign()>::invoke( + *this, std::forward(v)); + } + + ~value() + { + switch_clean(this->type_); + } + + type t() const {return type_;} + + template + typename detail::toml_default_type::type const& cast() const + { + if(T != type_) + throw type_error(std::string("value type is ") + + stringize(type_) + std::string(", not ") + + stringize(T)); + return switch_cast::invoke(*this); + } + + template + typename detail::toml_default_type::type& cast() + { + if(T != type_) + throw type_error(std::string("value type is ") + + stringize(type_) + std::string(", not ") + + stringize(T)); + return switch_cast::invoke(*this); + } + + template::is_toml_value, std::nullptr_t>::type = nullptr> + void reset(T&& v) + { + switch_clean(this->type_); + type_ = toml::detail::check_type(); + switch_assign()>::invoke(*this, std::forward(v)); + } + + private: + + void switch_clean(type t) + { + switch(t) + { + case type::Boolean : boolean_.~Boolean(); return; + case type::Integer : integer_.~Integer(); return; + case type::Float : float_.~Float(); return; + case type::String : string_.~String(); return; + case type::Datetime: datetime_.~Datetime(); return; + case type::Array : array_.~Array(); return; + case type::Table : table_.~Table(); return; + case type::Unknown : return; + default: assert(false); + } + } + + template struct switch_assign; + template struct switch_cast; + + private: + + type type_; + union + { + Boolean boolean_; + Integer integer_; + Float float_; + String string_; + Datetime datetime_; + Array array_; + Table table_; + }; +}; + +template<> struct value::switch_assign +{ + template + static void invoke(value& v, valT&& val) + { + v.boolean_ = std::forward(val); + } +}; +template<> struct value::switch_assign +{ + template + static void invoke(value& v, valT&& val) + { + v.integer_ = std::forward(val); + } +}; +template<> struct value::switch_assign +{ + template + static void invoke(value& v, valT&& val) + { + v.float_ = std::forward(val); + } +}; +template<> struct value::switch_assign +{ + template + static void invoke(value& v, valT&& val) + { + new(&v.string_) String(val); + } +}; +template<> struct value::switch_assign +{ + template + static void invoke(value& v, valT&& val) + { + new(&v.datetime_) Datetime(val); + } +}; +template<> struct value::switch_assign +{ + template + static void invoke(value& v, valT&& val) + { + new(&v.array_) Array(val); + } +}; +template<> struct value::switch_assign +{ + template + static void invoke(value& v, valT&& val) + { + new(&v.table_) Table(val); + } +}; + +template<> struct value::switch_cast +{ + static Boolean& invoke(value& v) {return v.boolean_;} + static Boolean const& invoke(value const& v) {return v.boolean_;} +}; +template<> struct value::switch_cast +{ + static Integer& invoke(value& v) {return v.integer_;} + static Integer const& invoke(value const& v) {return v.integer_;} +}; +template<> struct value::switch_cast +{ + static Float& invoke(value& v) {return v.float_;} + static Float const& invoke(value const& v) {return v.float_;} +}; +template<> struct value::switch_cast +{ + static String& invoke(value& v) {return v.string_;} + static String const& invoke(value const& v) {return v.string_;} +}; +template<> struct value::switch_cast +{ + static Datetime& invoke(value& v) {return v.datetime_;} + static Datetime const& invoke(value const& v) {return v.datetime_;} +}; +template<> struct value::switch_cast +{ + static Array& invoke(value& v) {return v.array_;} + static Array const& invoke(value const& v) {return v.array_;} +}; +template<> struct value::switch_cast +{ + static Table& invoke(value& v) {return v.table_;} + static Table const& invoke(value const& v) {return v.table_;} +}; + + + +}// toml +#endif// TOML_FOR_MODERN_CPP