From e24039f4ef4b2bf55b2939b410338a8aa9bfbac3 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 9 Dec 2018 18:03:20 +0900 Subject: [PATCH] update toml::value and improve test_value - enable to store new types - store source string if possible - refactoring --- tests/CMakeLists.txt | 2 +- tests/test_value.cpp | 758 ++++++++++++++++++++++--------- toml/value.hpp | 1016 +++++++++++++++++++++++++----------------- 3 files changed, 1160 insertions(+), 616 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index da45062..e514d4e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,7 @@ set(TEST_NAMES test_utility test_result test_traits -# test_value + test_value # test_to_toml # test_from_toml # test_get diff --git a/tests/test_value.cpp b/tests/test_value.cpp index 1e24088..29f8cd6 100644 --- a/tests/test_value.cpp +++ b/tests/test_value.cpp @@ -5,231 +5,589 @@ #define BOOST_TEST_NO_LIB #include #endif -#include +#include #include #include -BOOST_AUTO_TEST_CASE(test_value_exact_constructor) +BOOST_AUTO_TEST_CASE(test_value_boolean) { - toml::Boolean b(true); - toml::Integer i(42); - toml::Float f(3.14); - toml::String s("hoge"); - toml::Datetime d(std::chrono::system_clock::now()); - toml::Array a; - a.emplace_back(2); - a.emplace_back(7); - a.emplace_back(1); - a.emplace_back(8); - a.emplace_back(2); - toml::Table t; - t.emplace("val1", true); - t.emplace("val2", 42); - t.emplace("val3", 3.14); - t.emplace("val4", "piyo"); - - toml::value v1(b); - toml::value v2(i); - toml::value v3(f); - toml::value v4(s); - toml::value v5(d); - toml::value v6(a); - toml::value v7(t); + toml::value v1(true); + toml::value v2(false); BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Boolean); + BOOST_CHECK(v1.is(toml::value_t::Boolean)); + BOOST_CHECK(v2.is(toml::value_t::Boolean)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); + + BOOST_CHECK_EQUAL(v1.cast(), true); + BOOST_CHECK_EQUAL(v2.cast(), false); + + v1 = false; + v2 = true; + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Boolean); + BOOST_CHECK(v1.is(toml::value_t::Boolean)); + BOOST_CHECK(v2.is(toml::value_t::Boolean)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); + + BOOST_CHECK_EQUAL(v1.cast(), false); + BOOST_CHECK_EQUAL(v2.cast(), true); + + toml::value v3(v1); + toml::value v4(v2); + + BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Boolean); + BOOST_CHECK_EQUAL(v4.type(), toml::value_t::Boolean); + BOOST_CHECK(v3.is(toml::value_t::Boolean)); + BOOST_CHECK(v4.is(toml::value_t::Boolean)); + BOOST_CHECK(v3.is()); + BOOST_CHECK(v4.is()); + + BOOST_CHECK_EQUAL(v3.cast(), false); + BOOST_CHECK_EQUAL(v4.cast(), true); + + toml::value v5(std::move(v1)); + toml::value v6(std::move(v2)); + + BOOST_CHECK_EQUAL(v5.type(), toml::value_t::Boolean); + BOOST_CHECK_EQUAL(v6.type(), toml::value_t::Boolean); + BOOST_CHECK(v5.is(toml::value_t::Boolean)); + BOOST_CHECK(v6.is(toml::value_t::Boolean)); + BOOST_CHECK(v5.is()); + BOOST_CHECK(v6.is()); + + BOOST_CHECK_EQUAL(v5.cast(), false); + BOOST_CHECK_EQUAL(v6.cast(), true); + + v1 = 42; + v2 = 3.14; + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Integer); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Float); + BOOST_CHECK(v1.is(toml::value_t::Integer)); + BOOST_CHECK(v2.is(toml::value_t::Float)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); + + BOOST_CHECK_EQUAL(v1.cast(), 42); + BOOST_CHECK_EQUAL(v2.cast(), 3.14); +} + +BOOST_AUTO_TEST_CASE(test_value_integer) +{ + toml::value v1(-42); + toml::value v2(42u); + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Integer); BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Integer); - BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Float); - BOOST_CHECK_EQUAL(v4.type(), toml::value_t::String); - BOOST_CHECK_EQUAL(v5.type(), toml::value_t::Datetime); - BOOST_CHECK_EQUAL(v6.type(), toml::value_t::Array); - BOOST_CHECK_EQUAL(v7.type(), toml::value_t::Table); + BOOST_CHECK(v1.is(toml::value_t::Integer)); + BOOST_CHECK(v2.is(toml::value_t::Integer)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); - BOOST_CHECK_EQUAL(v1.cast(), b); - BOOST_CHECK_EQUAL(v2.cast(), i); - BOOST_CHECK_EQUAL(v3.cast(), f); - BOOST_CHECK_EQUAL(v4.cast(), s); - const auto& ar = v6.cast(); - BOOST_CHECK_EQUAL(ar.at(0).cast(), a.at(0).cast()); - BOOST_CHECK_EQUAL(ar.at(1).cast(), a.at(1).cast()); - BOOST_CHECK_EQUAL(ar.at(2).cast(), a.at(2).cast()); - BOOST_CHECK_EQUAL(ar.at(3).cast(), a.at(3).cast()); - BOOST_CHECK_EQUAL(ar.at(4).cast(), a.at(4).cast()); -} + BOOST_CHECK_EQUAL(v1.cast(), -42); + BOOST_CHECK_EQUAL(v2.cast(), 42u); -BOOST_AUTO_TEST_CASE(test_value_convertible_constructor) -{ - int i(42); - float f(3.14); - const char* s = "hoge"; - - toml::value v1(i); - toml::value v2(f); - toml::value v3(s); + v1 = 54; + v2 = -54; BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Integer); - BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Float); - BOOST_CHECK_EQUAL(v3.type(), toml::value_t::String); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Integer); + BOOST_CHECK(v1.is(toml::value_t::Integer)); + BOOST_CHECK(v2.is(toml::value_t::Integer)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); - BOOST_CHECK_EQUAL(v1.cast(), i); - BOOST_CHECK_EQUAL(v2.cast(), f); - BOOST_CHECK_EQUAL(v3.cast(), s); + BOOST_CHECK_EQUAL(v1.cast(), 54); + BOOST_CHECK_EQUAL(v2.cast(), -54); + + toml::value v3(v1); + toml::value v4(v2); + + BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Integer); + BOOST_CHECK_EQUAL(v4.type(), toml::value_t::Integer); + BOOST_CHECK(v3.is(toml::value_t::Integer)); + BOOST_CHECK(v4.is(toml::value_t::Integer)); + BOOST_CHECK(v3.is()); + BOOST_CHECK(v4.is()); + + BOOST_CHECK_EQUAL(v3.cast(), 54); + BOOST_CHECK_EQUAL(v4.cast(), -54); + + toml::value v5(std::move(v1)); + toml::value v6(std::move(v2)); + + BOOST_CHECK_EQUAL(v5.type(), toml::value_t::Integer); + BOOST_CHECK_EQUAL(v6.type(), toml::value_t::Integer); + BOOST_CHECK(v5.is(toml::value_t::Integer)); + BOOST_CHECK(v6.is(toml::value_t::Integer)); + BOOST_CHECK(v5.is()); + BOOST_CHECK(v6.is()); + + BOOST_CHECK_EQUAL(v5.cast(), 54); + BOOST_CHECK_EQUAL(v6.cast(), -54); + + v1 = true; + v2 = false; + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Boolean); + BOOST_CHECK(v1.is(toml::value_t::Boolean)); + BOOST_CHECK(v2.is(toml::value_t::Boolean)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); + + BOOST_CHECK_EQUAL(v1.cast(), true); + BOOST_CHECK_EQUAL(v2.cast(), false); } -BOOST_AUTO_TEST_CASE(test_value_copy_move_constructor) +BOOST_AUTO_TEST_CASE(test_value_float) { - toml::Array a; - toml::Table t; - toml::value v1(true); - toml::value v2(42); - toml::value v3(3.14); - toml::value v4("hoge"); - toml::value v5(std::chrono::system_clock::now()); - toml::value v6(a); - toml::value v7(t); - - toml::value u1(v1); - toml::value u2(v2); - toml::value u3(v3); - toml::value u4(v4); - toml::value u5(v5); - toml::value u6(v6); - toml::value u7(v7); - - BOOST_CHECK_EQUAL(u1.type(), toml::value_t::Boolean); - BOOST_CHECK_EQUAL(u2.type(), toml::value_t::Integer); - BOOST_CHECK_EQUAL(u3.type(), toml::value_t::Float); - BOOST_CHECK_EQUAL(u4.type(), toml::value_t::String); - BOOST_CHECK_EQUAL(u5.type(), toml::value_t::Datetime); - BOOST_CHECK_EQUAL(u6.type(), toml::value_t::Array); - BOOST_CHECK_EQUAL(u7.type(), toml::value_t::Table); - - BOOST_CHECK_EQUAL(u1.cast(), true); - BOOST_CHECK_EQUAL(u2.cast(), 42); - BOOST_CHECK_EQUAL(u3.cast(), 3.14); - BOOST_CHECK_EQUAL(u4.cast(), "hoge"); - - toml::value w1(std::move(v1)); - toml::value w2(std::move(v2)); - toml::value w3(std::move(v3)); - toml::value w4(std::move(v4)); - toml::value w5(std::move(v5)); - toml::value w6(std::move(v6)); - toml::value w7(std::move(v7)); - - BOOST_CHECK_EQUAL(w1.type(), toml::value_t::Boolean); - BOOST_CHECK_EQUAL(w2.type(), toml::value_t::Integer); - BOOST_CHECK_EQUAL(w3.type(), toml::value_t::Float); - BOOST_CHECK_EQUAL(w4.type(), toml::value_t::String); - BOOST_CHECK_EQUAL(w5.type(), toml::value_t::Datetime); - BOOST_CHECK_EQUAL(w6.type(), toml::value_t::Array); - BOOST_CHECK_EQUAL(w7.type(), toml::value_t::Table); - - BOOST_CHECK_EQUAL(w1.cast(), true); - BOOST_CHECK_EQUAL(w2.cast(), 42); - BOOST_CHECK_EQUAL(w3.cast(), 3.14); - BOOST_CHECK_EQUAL(w4.cast(), "hoge"); -} - -BOOST_AUTO_TEST_CASE(test_value_copy_move_substitution) -{ - toml::Boolean b(true); - toml::Integer i(42); - toml::Float f(3.14); - toml::String s("hoge"); - toml::Datetime d(std::chrono::system_clock::now()); - toml::Array a; - a.emplace_back(2); - a.emplace_back(7); - a.emplace_back(1); - a.emplace_back(8); - a.emplace_back(2); - toml::Table t; - t.emplace("val1", true); - t.emplace("val2", 42); - t.emplace("val3", 3.14); - t.emplace("val4", "piyo"); - - toml::value v1(b); - toml::value v2(i); - toml::value v3(f); - toml::value v4(s); - toml::value v5(d); - toml::value v6(a); - toml::value v7(t); - - v1 = i; - v2 = f; - v3 = s; - v4 = d; - v5 = a; - v6 = t; - v7 = b; - - BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Integer); - BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Float); - BOOST_CHECK_EQUAL(v3.type(), toml::value_t::String); - BOOST_CHECK_EQUAL(v4.type(), toml::value_t::Datetime); - BOOST_CHECK_EQUAL(v5.type(), toml::value_t::Array); - BOOST_CHECK_EQUAL(v6.type(), toml::value_t::Table); - BOOST_CHECK_EQUAL(v7.type(), toml::value_t::Boolean); - - BOOST_CHECK_EQUAL(v7.cast(), b); - BOOST_CHECK_EQUAL(v1.cast(), i); - BOOST_CHECK_EQUAL(v2.cast(), f); - BOOST_CHECK_EQUAL(v3.cast(), s); - - const auto f_ = f; - const auto s_ = s; - const auto d_ = d; - const auto a_ = a; - const auto t_ = t; - const auto b_ = b; - const auto i_ = i; - - v1 = std::move(f); - v2 = std::move(s); - v3 = std::move(d); - v4 = std::move(a); - v5 = std::move(t); - v6 = std::move(b); - v7 = std::move(i); + toml::value v1(3.14); + toml::value v2(3.14f); BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Float); - BOOST_CHECK_EQUAL(v2.type(), toml::value_t::String); - BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Datetime); - BOOST_CHECK_EQUAL(v4.type(), toml::value_t::Array); - BOOST_CHECK_EQUAL(v5.type(), toml::value_t::Table); - BOOST_CHECK_EQUAL(v6.type(), toml::value_t::Boolean); - BOOST_CHECK_EQUAL(v7.type(), toml::value_t::Integer); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Float); + BOOST_CHECK(v1.is(toml::value_t::Float)); + BOOST_CHECK(v2.is(toml::value_t::Float)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); - BOOST_CHECK_EQUAL(v6.cast(), b_); - BOOST_CHECK_EQUAL(v7.cast(), i_); - BOOST_CHECK_EQUAL(v1.cast(), f_); - BOOST_CHECK_EQUAL(v2.cast(), s_); + BOOST_CHECK_EQUAL(v1.cast(), 3.14); + BOOST_CHECK_CLOSE_FRACTION(v2.cast(), 3.14, 1e-2); + + v1 = 2.718f; + v2 = 2.718; + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Float); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Float); + BOOST_CHECK(v1.is(toml::value_t::Float)); + BOOST_CHECK(v2.is(toml::value_t::Float)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); + + BOOST_CHECK_CLOSE_FRACTION(v1.cast(), 2.718, 1e-3); + BOOST_CHECK_EQUAL(v2.cast(), 2.718); + + toml::value v3(v1); + toml::value v4(v2); + + BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Float); + BOOST_CHECK_EQUAL(v4.type(), toml::value_t::Float); + BOOST_CHECK(v3.is(toml::value_t::Float)); + BOOST_CHECK(v4.is(toml::value_t::Float)); + BOOST_CHECK(v3.is()); + BOOST_CHECK(v4.is()); + + BOOST_CHECK_CLOSE_FRACTION(v3.cast(), 2.718, 1e-3); + BOOST_CHECK_EQUAL(v4.cast(), 2.718); + + toml::value v5(std::move(v1)); + toml::value v6(std::move(v2)); + + BOOST_CHECK_EQUAL(v5.type(), toml::value_t::Float); + BOOST_CHECK_EQUAL(v6.type(), toml::value_t::Float); + BOOST_CHECK(v5.is(toml::value_t::Float)); + BOOST_CHECK(v6.is(toml::value_t::Float)); + BOOST_CHECK(v5.is()); + BOOST_CHECK(v6.is()); + + BOOST_CHECK_CLOSE_FRACTION(v5.cast(), 2.718, 1e-3); + BOOST_CHECK_EQUAL(v6.cast(), 2.718); + + v1 = true; + v2 = false; + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Boolean); + BOOST_CHECK(v1.is(toml::value_t::Boolean)); + BOOST_CHECK(v2.is(toml::value_t::Boolean)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); + + BOOST_CHECK_EQUAL(v1.cast(), true); + BOOST_CHECK_EQUAL(v2.cast(), false); } -BOOST_AUTO_TEST_CASE(test_value_initializer_list) +BOOST_AUTO_TEST_CASE(test_value_string) { - toml::value v1{3,1,4,1,5}; - toml::value v2{{"hoge", 1}, {"piyo", 3.14}, {"fuga", "string"}}; + toml::value v1(std::string("foo")); + toml::value v2(std::string("foo"), toml::string_t::literal); + toml::value v3("foo"); + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::String); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::String); + BOOST_CHECK_EQUAL(v3.type(), toml::value_t::String); + BOOST_CHECK(v1.is(toml::value_t::String)); + BOOST_CHECK(v2.is(toml::value_t::String)); + BOOST_CHECK(v3.is(toml::value_t::String)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); + BOOST_CHECK(v3.is()); + + BOOST_CHECK_EQUAL(v1.cast(), "foo"); + BOOST_CHECK_EQUAL(v2.cast(), "foo"); + BOOST_CHECK_EQUAL(v3.cast(), "foo"); + + v1 = "bar"; + v2 = "bar"; + v3 = "bar"; + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::String); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::String); + BOOST_CHECK_EQUAL(v3.type(), toml::value_t::String); + BOOST_CHECK(v1.is(toml::value_t::String)); + BOOST_CHECK(v2.is(toml::value_t::String)); + BOOST_CHECK(v3.is(toml::value_t::String)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); + BOOST_CHECK(v3.is()); + + BOOST_CHECK_EQUAL(v1.cast(), "bar"); + BOOST_CHECK_EQUAL(v2.cast(), "bar"); + BOOST_CHECK_EQUAL(v3.cast(), "bar"); + + toml::value v4(v1); + toml::value v5(v2); + toml::value v6(v3); + + BOOST_CHECK_EQUAL(v4.type(), toml::value_t::String); + BOOST_CHECK_EQUAL(v5.type(), toml::value_t::String); + BOOST_CHECK_EQUAL(v6.type(), toml::value_t::String); + BOOST_CHECK(v4.is(toml::value_t::String)); + BOOST_CHECK(v5.is(toml::value_t::String)); + BOOST_CHECK(v6.is(toml::value_t::String)); + BOOST_CHECK(v4.is()); + BOOST_CHECK(v5.is()); + BOOST_CHECK(v6.is()); + + BOOST_CHECK_EQUAL(v4.cast(), "bar"); + BOOST_CHECK_EQUAL(v5.cast(), "bar"); + BOOST_CHECK_EQUAL(v6.cast(), "bar"); + + v4.cast().str.at(2) = 'z'; + v5.cast().str.at(2) = 'z'; + v6.cast().str.at(2) = 'z'; + + BOOST_CHECK_EQUAL(v4.type(), toml::value_t::String); + BOOST_CHECK_EQUAL(v5.type(), toml::value_t::String); + BOOST_CHECK_EQUAL(v6.type(), toml::value_t::String); + BOOST_CHECK(v4.is(toml::value_t::String)); + BOOST_CHECK(v5.is(toml::value_t::String)); + BOOST_CHECK(v6.is(toml::value_t::String)); + BOOST_CHECK(v4.is()); + BOOST_CHECK(v5.is()); + BOOST_CHECK(v6.is()); + + BOOST_CHECK_EQUAL(v4.cast(), "baz"); + BOOST_CHECK_EQUAL(v5.cast(), "baz"); + BOOST_CHECK_EQUAL(v6.cast(), "baz"); + + v1 = true; + v2 = true; + v3 = true; + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Boolean); + BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Boolean); + BOOST_CHECK(v1.is(toml::value_t::Boolean)); + BOOST_CHECK(v2.is(toml::value_t::Boolean)); + BOOST_CHECK(v3.is(toml::value_t::Boolean)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); + BOOST_CHECK(v3.is()); + + BOOST_CHECK_EQUAL(v1.cast(), true); + BOOST_CHECK_EQUAL(v2.cast(), true); + BOOST_CHECK_EQUAL(v3.cast(), true); +} + +BOOST_AUTO_TEST_CASE(test_value_local_date) +{ + toml::value v1(toml::local_date(2018, toml::month_t::Jan, 31)); + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate); + BOOST_CHECK(v1.is(toml::value_t::LocalDate)); + BOOST_CHECK(v1.is()); + + BOOST_CHECK_EQUAL(v1.cast(), + toml::local_date(2018, toml::month_t::Jan, 31)); + + v1 = toml::local_date(2018, toml::month_t::Apr, 1); + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate); + BOOST_CHECK(v1.is(toml::value_t::LocalDate)); + BOOST_CHECK(v1.is()); + + BOOST_CHECK_EQUAL(v1.cast(), + toml::local_date(2018, toml::month_t::Apr, 1)); + + toml::value v2(v1); + + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalDate); + BOOST_CHECK(v2.is(toml::value_t::LocalDate)); + BOOST_CHECK(v2.is()); + + BOOST_CHECK_EQUAL(v2.cast(), + toml::local_date(2018, toml::month_t::Apr, 1)); + + v1 = true; + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean); + BOOST_CHECK(v1.is(toml::value_t::Boolean)); + BOOST_CHECK(v1.is()); + BOOST_CHECK_EQUAL(v1.cast(), true); +} + +BOOST_AUTO_TEST_CASE(test_value_local_time) +{ + toml::value v1(toml::local_time(12, 30, 45)); + toml::value v2(std::chrono::hours(12) + std::chrono::minutes(30) + + std::chrono::seconds(45)); + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalTime); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalTime); + BOOST_CHECK(v1.is(toml::value_t::LocalTime)); + BOOST_CHECK(v2.is(toml::value_t::LocalTime)); + BOOST_CHECK(v1.is()); + BOOST_CHECK(v2.is()); + + BOOST_CHECK_EQUAL(v1.cast(), + toml::local_time(12, 30, 45)); + BOOST_CHECK_EQUAL(v2.cast(), + toml::local_time(12, 30, 45)); + BOOST_CHECK_EQUAL(v1.cast(), + v2.cast()); + + v1 = toml::local_time(1, 30, 0, /*ms*/ 100, /*us*/ 0); + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalTime); + BOOST_CHECK(v1.is(toml::value_t::LocalTime)); + BOOST_CHECK(v1.is()); + BOOST_CHECK_EQUAL(v1.cast(), + toml::local_time(1, 30, 0, 100, 0)); + + toml::value v3(v1); + + BOOST_CHECK_EQUAL(v3.type(), toml::value_t::LocalTime); + BOOST_CHECK(v3.is(toml::value_t::LocalTime)); + BOOST_CHECK(v3.is()); + + BOOST_CHECK_EQUAL(v3.cast(), + toml::local_time(1, 30, 0, 100, 0)); + + v1 = true; + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean); + BOOST_CHECK(v1.is(toml::value_t::Boolean)); + BOOST_CHECK(v1.is()); + BOOST_CHECK_EQUAL(v1.cast(), true); +} + +BOOST_AUTO_TEST_CASE(test_value_local_datetime) +{ + toml::value v1(toml::local_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45) + )); + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime); + BOOST_CHECK(v1.is(toml::value_t::LocalDatetime)); + BOOST_CHECK(v1.is()); + + BOOST_CHECK_EQUAL(v1.cast(), + toml::local_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45))); + + v1 = toml::local_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30)); + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime); + BOOST_CHECK(v1.is(toml::value_t::LocalDatetime)); + BOOST_CHECK(v1.is()); + + BOOST_CHECK_EQUAL(v1.cast(), + toml::local_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30))); + + toml::value v2(v1); + + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalDatetime); + BOOST_CHECK(v2.is(toml::value_t::LocalDatetime)); + BOOST_CHECK(v2.is()); + + BOOST_CHECK_EQUAL(v2.cast(), + toml::local_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30))); + + v1 = true; + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean); + BOOST_CHECK(v1.is(toml::value_t::Boolean)); + BOOST_CHECK(v1.is()); + BOOST_CHECK_EQUAL(v1.cast(), true); +} + +BOOST_AUTO_TEST_CASE(test_value_offset_datetime) +{ + toml::value v1(toml::offset_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45), + toml::time_offset(9, 0) + )); + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime); + BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime)); + BOOST_CHECK(v1.is()); + + BOOST_CHECK_EQUAL(v1.cast(), + toml::offset_datetime( + toml::local_date(2018, toml::month_t::Jan, 31), + toml::local_time(12, 30, 45), + toml::time_offset(9, 0) + )); + + v1 = toml::offset_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30), + toml::time_offset(9, 0)); + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime); + BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime)); + BOOST_CHECK(v1.is()); + + BOOST_CHECK_EQUAL(v1.cast(), + toml::offset_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30), + toml::time_offset(9, 0))); + + toml::value v2(v1); + + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::OffsetDatetime); + BOOST_CHECK(v2.is(toml::value_t::OffsetDatetime)); + BOOST_CHECK(v2.is()); + + BOOST_CHECK_EQUAL(v2.cast(), + toml::offset_datetime( + toml::local_date(2018, toml::month_t::Apr, 1), + toml::local_time(1, 15, 30), + toml::time_offset(9, 0))); + v1 = true; + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean); + BOOST_CHECK(v1.is(toml::value_t::Boolean)); + BOOST_CHECK(v1.is()); + BOOST_CHECK_EQUAL(v1.cast(), true); +} + +BOOST_AUTO_TEST_CASE(test_value_array) +{ + std::vector v{1,2,3,4,5}; + toml::value v1(v); + toml::value v2{6,7,8,9,0}; BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array); - BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Table); + BOOST_CHECK(v1.is(toml::value_t::Array)); + BOOST_CHECK(v1.is()); - const auto& ar = v1.cast(); - BOOST_CHECK_EQUAL(ar.at(0).cast(), 3); - BOOST_CHECK_EQUAL(ar.at(1).cast(), 1); - BOOST_CHECK_EQUAL(ar.at(2).cast(), 4); - BOOST_CHECK_EQUAL(ar.at(3).cast(), 1); - BOOST_CHECK_EQUAL(ar.at(4).cast(), 5); + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array); + BOOST_CHECK(v2.is(toml::value_t::Array)); + BOOST_CHECK(v2.is()); - const auto& tb = v2.cast(); + BOOST_CHECK_EQUAL(v1.cast().at(0).cast(), 1); + BOOST_CHECK_EQUAL(v1.cast().at(1).cast(), 2); + BOOST_CHECK_EQUAL(v1.cast().at(2).cast(), 3); + BOOST_CHECK_EQUAL(v1.cast().at(3).cast(), 4); + BOOST_CHECK_EQUAL(v1.cast().at(4).cast(), 5); - BOOST_CHECK_EQUAL(tb.at("hoge").type(), toml::value_t::Integer); - BOOST_CHECK_EQUAL(tb.at("piyo").type(), toml::value_t::Float); - BOOST_CHECK_EQUAL(tb.at("fuga").type(), toml::value_t::String); + BOOST_CHECK_EQUAL(v2.cast().at(0).cast(), 6); + BOOST_CHECK_EQUAL(v2.cast().at(1).cast(), 7); + BOOST_CHECK_EQUAL(v2.cast().at(2).cast(), 8); + BOOST_CHECK_EQUAL(v2.cast().at(3).cast(), 9); + BOOST_CHECK_EQUAL(v2.cast().at(4).cast(), 0); - BOOST_CHECK_EQUAL(tb.at("hoge").cast(), 1); - BOOST_CHECK_CLOSE_FRACTION(tb.at("piyo").cast(), 3.14, 1e-3); - BOOST_CHECK_EQUAL(tb.at("fuga").cast(), "string"); + v1 = {6,7,8,9,0}; + v2 = v; + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array); + BOOST_CHECK(v1.is(toml::value_t::Array)); + BOOST_CHECK(v1.is()); + + BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array); + BOOST_CHECK(v2.is(toml::value_t::Array)); + BOOST_CHECK(v2.is()); + + BOOST_CHECK_EQUAL(v1.cast().at(0).cast(), 6); + BOOST_CHECK_EQUAL(v1.cast().at(1).cast(), 7); + BOOST_CHECK_EQUAL(v1.cast().at(2).cast(), 8); + BOOST_CHECK_EQUAL(v1.cast().at(3).cast(), 9); + BOOST_CHECK_EQUAL(v1.cast().at(4).cast(), 0); + + BOOST_CHECK_EQUAL(v2.cast().at(0).cast(), 1); + BOOST_CHECK_EQUAL(v2.cast().at(1).cast(), 2); + BOOST_CHECK_EQUAL(v2.cast().at(2).cast(), 3); + BOOST_CHECK_EQUAL(v2.cast().at(3).cast(), 4); + BOOST_CHECK_EQUAL(v2.cast().at(4).cast(), 5); + + toml::value v3(v1); + + BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Array); + BOOST_CHECK(v3.is(toml::value_t::Array)); + BOOST_CHECK(v3.is()); + + BOOST_CHECK_EQUAL(v3.cast().at(0).cast(), 6); + BOOST_CHECK_EQUAL(v3.cast().at(1).cast(), 7); + BOOST_CHECK_EQUAL(v3.cast().at(2).cast(), 8); + BOOST_CHECK_EQUAL(v3.cast().at(3).cast(), 9); + BOOST_CHECK_EQUAL(v3.cast().at(4).cast(), 0); + + v1 = true; + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean); + BOOST_CHECK(v1.is(toml::value_t::Boolean)); + BOOST_CHECK(v1.is()); + BOOST_CHECK_EQUAL(v1.cast(), true); +} + +BOOST_AUTO_TEST_CASE(test_value_table) +{ + toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}}; + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table); + BOOST_CHECK(v1.is(toml::value_t::Table)); + BOOST_CHECK(v1.is()); + + BOOST_CHECK_EQUAL(v1.cast().at("foo").cast(), 42); + BOOST_CHECK_EQUAL(v1.cast().at("bar").cast(), 3.14); + BOOST_CHECK_EQUAL(v1.cast().at("baz").cast().str, "qux"); + + v1 = toml::table{{"foo", 2.71}, {"bar", 54}, {"baz", "quux"}}; + + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table); + BOOST_CHECK(v1.is(toml::value_t::Table)); + BOOST_CHECK(v1.is()); + + BOOST_CHECK_EQUAL(v1.cast().at("foo").cast(), 2.71); + BOOST_CHECK_EQUAL(v1.cast().at("bar").cast(), 54); + BOOST_CHECK_EQUAL(v1.cast().at("baz").cast().str, "quux"); + + toml::value v3(v1); + + BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Table); + BOOST_CHECK(v3.is(toml::value_t::Table)); + BOOST_CHECK(v3.is()); + + BOOST_CHECK_EQUAL(v3.cast().at("foo").cast(), 2.71); + BOOST_CHECK_EQUAL(v3.cast().at("bar").cast(), 54); + BOOST_CHECK_EQUAL(v3.cast().at("baz").cast().str, "quux"); + + v1 = true; + BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean); + BOOST_CHECK(v1.is(toml::value_t::Boolean)); + BOOST_CHECK(v1.is()); + BOOST_CHECK_EQUAL(v1.cast(), true); } diff --git a/toml/value.hpp b/toml/value.hpp index 1fe42f8..a2e668b 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -29,482 +29,658 @@ constexpr bool value_traits::is_toml_type; class value { - typedef std::unique_ptr storage_ptr; + template + static void assigner(T& dst, U&& v) + { + const auto tmp = ::new(std::addressof(dst)) T(std::forward(v)); + assert(tmp == std::addressof(dst)); + } + + using region_base = detail::region_base; public: - value() : type_(value_t::Empty){} - ~value(); + value() noexcept + : type_(value_t::Empty), + region_info_(std::make_shared(region_base{})) + {} - value(const value& v); - value(value&& v); - value& operator=(const value& v); - value& operator=(value&& v); + ~value() noexcept {this->cleanup();} + + value(const value& v): type_(v.type()), region_info_(v.region_info_) + { + switch(v.type()) + { + case value_t::Boolean : assigner(boolean_ , v.boolean_ ); break; + case value_t::Integer : assigner(integer_ , v.integer_ ); break; + case value_t::Float : assigner(floating_ , v.floating_ ); break; + case value_t::String : assigner(string_ , v.string_ ); break; + case value_t::OffsetDatetime: assigner(offset_datetime_, v.offset_datetime_); break; + case value_t::LocalDatetime : assigner(local_datetime_ , v.local_datetime_ ); break; + case value_t::LocalDate : assigner(local_date_ , v.local_date_ ); break; + case value_t::LocalTime : assigner(local_time_ , v.local_time_ ); break; + case value_t::Array : assigner(array_ , v.array_ ); break; + case value_t::Table : assigner(table_ , v.table_ ); break; + default: break; + } + } + value(value&& v): type_(v.type()), region_info_(std::move(v.region_info_)) + { + switch(this->type_) + { + case value_t::Boolean : assigner(boolean_ , std::move(v.boolean_ )); break; + case value_t::Integer : assigner(integer_ , std::move(v.integer_ )); break; + case value_t::Float : assigner(floating_ , std::move(v.floating_ )); break; + case value_t::String : assigner(string_ , std::move(v.string_ )); break; + case value_t::OffsetDatetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break; + case value_t::LocalDatetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break; + case value_t::LocalDate : assigner(local_date_ , std::move(v.local_date_ )); break; + case value_t::LocalTime : assigner(local_time_ , std::move(v.local_time_ )); break; + case value_t::Array : assigner(array_ , std::move(v.array_ )); break; + case value_t::Table : assigner(table_ , std::move(v.table_ )); break; + default: break; + } + } + value& operator=(const value& v) + { + this->cleanup(); + this->region_info_ = v.region_info_; + this->type_ = v.type(); + switch(this->type_) + { + case value_t::Boolean : assigner(boolean_ , v.boolean_ ); break; + case value_t::Integer : assigner(integer_ , v.integer_ ); break; + case value_t::Float : assigner(floating_ , v.floating_ ); break; + case value_t::String : assigner(string_ , v.string_ ); break; + case value_t::OffsetDatetime: assigner(offset_datetime_, v.offset_datetime_); break; + case value_t::LocalDatetime : assigner(local_datetime_ , v.local_datetime_ ); break; + case value_t::LocalDate : assigner(local_date_ , v.local_date_ ); break; + case value_t::LocalTime : assigner(local_time_ , v.local_time_ ); break; + case value_t::Array : assigner(array_ , v.array_ ); break; + case value_t::Table : assigner(table_ , v.table_ ); break; + default: break; + } + return *this; + } + value& operator=(value&& v) + { + this->cleanup(); + this->region_info_ = std::move(v.region_info_); + this->type_ = v.type(); + switch(this->type_) + { + case value_t::Boolean : assigner(boolean_ , std::move(v.boolean_ )); break; + case value_t::Integer : assigner(integer_ , std::move(v.integer_ )); break; + case value_t::Float : assigner(floating_ , std::move(v.floating_ )); break; + case value_t::String : assigner(string_ , std::move(v.string_ )); break; + case value_t::OffsetDatetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break; + case value_t::LocalDatetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break; + case value_t::LocalDate : assigner(local_date_ , std::move(v.local_date_ )); break; + case value_t::LocalTime : assigner(local_time_ , std::move(v.local_time_ )); break; + case value_t::Array : assigner(array_ , std::move(v.array_ )); break; + case value_t::Table : assigner(table_ , std::move(v.table_ )); break; + default: break; + } + return *this; + } + + // boolean ============================================================== + + value(boolean b) + : type_(value_t::Boolean), + region_info_(std::make_shared(region_base{})) + { + assigner(this->boolean_, b); + } + + value& operator=(boolean b) + { + this->cleanup(); + this->type_ = value_t::Boolean; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->boolean_, b); + return *this; + } + + template + value(boolean b, detail::region reg) + : type_(value_t::Boolean), + region_info_(std::make_shared(std::move(reg))) + { + assigner(this->boolean_, b); + } + + // integer ============================================================== + + template, detail::negation>>::value, + std::nullptr_t>::type = nullptr> + value(T i) + : type_(value_t::Integer), + region_info_(std::make_shared(region_base{})) + { + assigner(this->integer_, static_cast(i)); + } + + template, + detail::negation> + >::value, std::nullptr_t>::type = nullptr> + value(T i, detail::region reg) + : type_(value_t::Integer), + region_info_(std::make_shared(std::move(reg))) + { + assigner(this->integer_, static_cast(i)); + } + + template, detail::negation>>::value, + std::nullptr_t>::type = nullptr> + value& operator=(T i) + { + this->cleanup(); + this->type_ = value_t::Integer; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->integer_, static_cast(i)); + return *this; + } + + // floating ============================================================= template::is_toml_type, std::nullptr_t>::type = nullptr> - value(T&& v); + std::is_floating_point::value, std::nullptr_t>::type = nullptr> + value(T f) + : type_(value_t::Float), + region_info_(std::make_shared(region_base{})) + { + assigner(this->floating_, f); + } + + template::value, std::nullptr_t>::type = nullptr> + value(T f, detail::region reg) + : type_(value_t::Float), + region_info_(std::make_shared(std::move(reg))) + { + assigner(this->floating_, f); + } template::is_toml_type, std::nullptr_t>::type = nullptr> - value& operator=(T&& v); + std::is_floating_point::value, std::nullptr_t>::type = nullptr> + value& operator=(T f) + { + this->cleanup(); + this->type_ = value_t::Float; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->floating_, f); + return *this; + } - template::is_toml_type, std::nullptr_t>::type = nullptr> - value(std::initializer_list init); + // string =============================================================== - value(std::initializer_list> init); + value(toml::string s) + : type_(value_t::String), + region_info_(std::make_shared(region_base{})) + { + assigner(this->string_, std::move(s)); + } + template + value(toml::string s, detail::region reg) + : type_(value_t::String), + region_info_(std::make_shared(std::move(reg))) + { + assigner(this->string_, std::move(s)); + } + value& operator=(toml::string s) + { + this->cleanup(); + this->type_ = value_t::String; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->string_, s); + return *this; + } + + value(std::string s) + : type_(value_t::String), + region_info_(std::make_shared(region_base{})) + { + assigner(this->string_, toml::string(std::move(s))); + } + value& operator=(std::string s) + { + this->cleanup(); + this->type_ = value_t::String; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->string_, toml::string(std::move(s))); + return *this; + } + value(std::string s, string_t kind) + : type_(value_t::String), + region_info_(std::make_shared(region_base{})) + { + assigner(this->string_, toml::string(std::move(s), kind)); + } + + value(const char* s) + : type_(value_t::String), + region_info_(std::make_shared(region_base{})) + { + assigner(this->string_, toml::string(std::string(s))); + } + value& operator=(const char* s) + { + this->cleanup(); + this->type_ = value_t::String; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->string_, toml::string(std::string(s))); + return *this; + } + value(const char* s, string_t kind) + : type_(value_t::String), + region_info_(std::make_shared(region_base{})) + { + assigner(this->string_, toml::string(std::string(s), kind)); + } + + // local date =========================================================== + + value(const local_date& ld) + : type_(value_t::LocalDate), + region_info_(std::make_shared(region_base{})) + { + assigner(this->local_date_, ld); + } + template + value(const local_date& ld, detail::region reg) + : type_(value_t::LocalDate), + region_info_(std::make_shared(std::move(reg))) + { + assigner(this->local_date_, ld); + } + value& operator=(const local_date& ld) + { + this->cleanup(); + this->type_ = value_t::LocalDate; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->local_date_, ld); + return *this; + } + + // local time =========================================================== + + value(const local_time& lt) + : type_(value_t::LocalTime), + region_info_(std::make_shared(region_base{})) + { + assigner(this->local_time_, lt); + } + template + value(const local_time& lt, detail::region reg) + : type_(value_t::LocalTime), + region_info_(std::make_shared(std::move(reg))) + { + assigner(this->local_time_, lt); + } + value& operator=(const local_time& lt) + { + this->cleanup(); + this->type_ = value_t::LocalTime; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->local_time_, lt); + return *this; + } + template + value(const std::chrono::duration& dur) + : type_(value_t::LocalTime), + region_info_(std::make_shared(region_base{})) + { + assigner(this->local_time_, local_time(dur)); + } + template + value& operator=(const std::chrono::duration& dur) + { + this->cleanup(); + this->type_ = value_t::LocalTime; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->local_time_, local_time(dur)); + return *this; + } + + // local datetime ======================================================= + + value(const local_datetime& ldt) + : type_(value_t::LocalDatetime), + region_info_(std::make_shared(region_base{})) + { + assigner(this->local_datetime_, ldt); + } + template + value(const local_datetime& ldt, detail::region reg) + : type_(value_t::LocalDatetime), + region_info_(std::make_shared(std::move(reg))) + { + assigner(this->local_datetime_, ldt); + } + value& operator=(const local_datetime& ldt) + { + this->cleanup(); + this->type_ = value_t::LocalDatetime; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->local_datetime_, ldt); + return *this; + } + + // offset datetime ====================================================== + + value(const offset_datetime& odt) + : type_(value_t::OffsetDatetime), + region_info_(std::make_shared(region_base{})) + { + assigner(this->offset_datetime_, odt); + } + template + value(const offset_datetime& odt, detail::region reg) + : type_(value_t::OffsetDatetime), + region_info_(std::make_shared(std::move(reg))) + { + assigner(this->offset_datetime_, odt); + } + value& operator=(const offset_datetime& odt) + { + this->cleanup(); + this->type_ = value_t::OffsetDatetime; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->offset_datetime_, odt); + return *this; + } + value(const std::chrono::system_clock::time_point& tp) + : type_(value_t::OffsetDatetime), + region_info_(std::make_shared(region_base{})) + { + assigner(this->offset_datetime_, offset_datetime(tp)); + } + value& operator=(const std::chrono::system_clock::time_point& tp) + { + this->cleanup(); + this->type_ = value_t::OffsetDatetime; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->offset_datetime_, offset_datetime(tp)); + return *this; + } + + // array ================================================================ + + value(const array& ary) + : type_(value_t::Array), + region_info_(std::make_shared(region_base{})) + { + assigner(this->array_, ary); + } + template + value(const array& ary, detail::region reg) + : type_(value_t::Array), + region_info_(std::make_shared(std::move(reg))) + { + assigner(this->array_, ary); + } + value& operator=(const array& ary) + { + this->cleanup(); + this->type_ = value_t::Array; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->array_, ary); + return *this; + } + + template::is_toml_type, + std::nullptr_t>::type = nullptr> + value(std::initializer_list list) + : type_(value_t::Array), + region_info_(std::make_shared(region_base{})) + { + array ary; ary.reserve(list.size()); + for(auto& elem : list) {ary.emplace_back(std::move(elem));} + assigner(this->array_, std::move(ary)); + } + template::is_toml_type, + std::nullptr_t>::type = nullptr> + value& operator=(std::initializer_list list) + { + this->cleanup(); + this->type_ = value_t::Array; + this->region_info_ = std::make_shared(region_base{}); + + array ary; ary.reserve(list.size()); + for(auto& elem : list) {ary.emplace_back(std::move(elem));} + assigner(this->array_, std::move(ary)); + return *this; + } + + template::value, + std::nullptr_t>::type = nullptr> + value(T&& list) + : type_(value_t::Array), + region_info_(std::make_shared(region_base{})) + { + array ary; ary.reserve(list.size()); + for(auto& elem : list) {ary.emplace_back(std::move(elem));} + assigner(this->array_, std::move(ary)); + } + template::value, + std::nullptr_t>::type = nullptr> + value& operator=(T&& list) + { + this->cleanup(); + this->type_ = value_t::Array; + this->region_info_ = std::make_shared(region_base{}); + + array ary; ary.reserve(list.size()); + for(auto& elem : list) {ary.emplace_back(std::move(elem));} + assigner(this->array_, std::move(ary)); + return *this; + } + + // table ================================================================ + + value(const table& tab) + : type_(value_t::Table), + region_info_(std::make_shared(region_base{})) + { + assigner(this->table_, tab); + } + template + value(const table& tab, detail::region reg) + : type_(value_t::Table), + region_info_(std::make_shared(std::move(reg))) + { + assigner(this->table_, tab); + } + value& operator=(const table& tab) + { + this->cleanup(); + this->type_ = value_t::Table; + this->region_info_ = std::make_shared(region_base{}); + assigner(this->table_, tab); + return *this; + } + value(std::initializer_list> list) + : type_(value_t::Table), + region_info_(std::make_shared(region_base{})) + { + table tab; + for(const auto& elem : list) {tab[elem.first] = elem.second;} + assigner(this->table_, std::move(tab)); + } + value& operator=(std::initializer_list> list) + { + this->cleanup(); + this->type_ = value_t::Array; + this->region_info_ = std::make_shared(region_base{}); + + table tab; + for(const auto& elem : list) {tab[elem.first] = elem.second;} + assigner(this->table_, std::move(tab)); + return *this; + } + + template + bool is() const noexcept {return value_traits::type_index == this->type_;} + bool is(value_t t) const noexcept {return t == this->type_;} value_t type() const {return type_;} template - typename detail::toml_default_type::type const& cast() const; + typename detail::toml_default_type::type& cast() &; template - typename detail::toml_default_type::type& cast(); + typename detail::toml_default_type::type const& cast() const&; + template + typename detail::toml_default_type::type&& cast() &&; private: - void switch_clean(value_t t); - template struct switch_assign; - template struct switch_cast; - - static bool should_be_cleaned(value_t vt) + void cleanup() noexcept { - return (vt == value_t::String) || (vt == value_t::Array) || - (vt == value_t::Table) || (vt == value_t::Datetime); + switch(this->type_) + { + case value_t::String : {string_.~string(); return;} + case value_t::Array : {array_.~array_storage(); return;} + case value_t::Table : {table_.~table_storage(); return;} + default : return; + } } + std::string + format_error(const std::string& msg, const std::string& com) const + { + return detail::format_underline(msg, *(this->region_info_), com); + } + + template + struct switch_cast; + private: + using array_storage = detail::storage; + using table_storage = detail::storage; + value_t type_; + + // for error message information. + std::shared_ptr region_info_; + union { - Boolean boolean_; - Integer integer_; - Float float_; - String string_; - Datetime datetime_; - storage_ptr storage_; //ptr to table or array + boolean boolean_; + integer integer_; + floating floating_; + string string_; + offset_datetime offset_datetime_; + local_datetime local_datetime_; + local_date local_date_; + local_time local_time_; + array_storage array_; + table_storage table_; }; }; -template<> struct value::switch_assign -{ - template - static void invoke(value& v, valT&& val) - { - v.boolean_ = static_cast(val); - } -}; -template<> struct value::switch_assign -{ - template - static void invoke(value& v, valT&& val) - { - v.integer_ = static_cast(val); - } -}; -template<> struct value::switch_assign -{ - template - static void invoke(value& v, valT&& val) - { - v.float_ = static_cast(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.storage_) storage_ptr( - toml::make_unique>(val)); - } -}; -template<> struct value::switch_assign -{ - template - static void invoke(value& v, valT&& val) - { - new(&v.storage_) storage_ptr( - toml::make_unique>(val)); - } -}; - template<> struct value::switch_cast { - static Boolean& invoke(value& v) {return v.boolean_;} + static Boolean& invoke(value& v) {return v.boolean_;} static Boolean const& invoke(value const& v) {return v.boolean_;} + static Boolean&& invoke(value&& v) {return std::move(v.boolean_);} }; template<> struct value::switch_cast { - static Integer& invoke(value& v) {return v.integer_;} + static Integer& invoke(value& v) {return v.integer_;} static Integer const& invoke(value const& v) {return v.integer_;} + static Integer&& invoke(value&& v) {return std::move(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_;} + static Float& invoke(value& v) {return v.floating_;} + static Float const& invoke(value const& v) {return v.floating_;} + static Float&& invoke(value&& v) {return std::move(v.floating_);} }; template<> struct value::switch_cast { - static String& invoke(value& v) {return v.string_;} + static String& invoke(value& v) {return v.string_;} static String const& invoke(value const& v) {return v.string_;} + static String&& invoke(value&& v) {return std::move(v.string_);} }; -template<> struct value::switch_cast +template<> struct value::switch_cast { - static Datetime& invoke(value& v) {return v.datetime_;} - static Datetime const& invoke(value const& v) {return v.datetime_;} + static OffsetDatetime& invoke(value& v) {return v.offset_datetime_;} + static OffsetDatetime const& invoke(value const& v) {return v.offset_datetime_;} + static OffsetDatetime&& invoke(value&& v) {return std::move(v.offset_datetime_);} +}; +template<> struct value::switch_cast +{ + static LocalDatetime& invoke(value& v) {return v.local_datetime_;} + static LocalDatetime const& invoke(value const& v) {return v.local_datetime_;} + static LocalDatetime&& invoke(value&& v) {return std::move(v.local_datetime_);} +}; +template<> struct value::switch_cast +{ + static LocalDate& invoke(value& v) {return v.local_date_;} + static LocalDate const& invoke(value const& v) {return v.local_date_;} + static LocalDate&& invoke(value&& v) {return std::move(v.local_date_);} +}; +template<> struct value::switch_cast +{ + static LocalTime& invoke(value& v) {return v.local_time_;} + static LocalTime const& invoke(value const& v) {return v.local_time_;} + static LocalTime&& invoke(value&& v) {return std::move(v.local_time_);} }; template<> struct value::switch_cast { - // switch_cast assumes tmeplate argument is correct. - // if not, the behaviour is undefined. - static Array& invoke(value& v) - { - return static_cast*>(v.storage_.get())->value; - } - static Array const& invoke(value const& v) - { - return static_cast*>(v.storage_.get())->value; - } + static Array& invoke(value& v) {return v.array_.value();} + static Array const& invoke(value const& v) {return v.array_.value();} + static Array&& invoke(value&& v) {return std::move(v.array_.value());} }; template<> struct value::switch_cast { - static Table& invoke(value& v) - { - return static_cast*>(v.storage_.get())->value; - } - static Table const& invoke(value const& v) - { - return static_cast*>(v.storage_.get())->value; - } + static Table& invoke(value& v) {return v.table_.value();} + static Table const& invoke(value const& v) {return v.table_.value();} + static Table&& invoke(value&& v) {return std::move(v.table_.value());} }; -inline void value::switch_clean(value_t t) -{ - switch(t) - { - case value_t::Boolean : {boolean_.~Boolean(); return;} - case value_t::Integer : {integer_.~Integer(); return;} - case value_t::Float : {float_.~Float(); return;} - case value_t::String : {string_.~String(); return;} - case value_t::Datetime : {datetime_.~Datetime(); return;} - case value_t::Array : {storage_.~storage_ptr(); return;} - case value_t::Table : {storage_.~storage_ptr(); return;} - case value_t::Empty : return; - case value_t::Unknown : assert(false); - default : assert(false); - } -} - -inline value::~value() -{ - switch_clean(this->type_); -} - -inline value::value(const value& v) : type_(v.type()) -{ - switch(v.type()) - { - case value_t::Boolean : - { - switch_assign::invoke( - *this, v.cast()); - break; - } - case value_t::Integer : - { - switch_assign::invoke( - *this, v.cast()); - break; - } - case value_t::Float : - { - switch_assign::invoke( - *this, v.cast()); - break; - } - case value_t::String : - { - switch_assign::invoke( - *this, v.cast()); - break; - } - case value_t::Datetime: - { - switch_assign::invoke( - *this, v.cast()); - break; - } - case value_t::Array : - { - switch_assign::invoke( - *this, v.cast()); - break; - } - case value_t::Table : - { - switch_assign::invoke( - *this, v.cast()); - break; - } - case value_t::Empty : break; - case value_t::Unknown : assert(false); - default: assert(false); - } -} - -inline value::value(value&& v) -{ - this->type_ = v.type_; - switch(this->type_) - { - case value_t::Boolean : - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::Integer : - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::Float : - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::String : - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::Datetime: - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::Array : - { - new(&this->storage_) storage_ptr(std::move(v.storage_)); - break; - } - case value_t::Table : - { - new(&this->storage_) storage_ptr(std::move(v.storage_)); - break; - } - case value_t::Empty : break; - case value_t::Unknown : assert(false); - default: assert(false); - } -} - -inline value& value::operator=(const value& v) -{ - if(should_be_cleaned(this->type_)) - { - this->switch_clean(this->type_); - } - this->type_ = v.type(); - - switch(this->type_) - { - case value_t::Boolean : - { - switch_assign::invoke(*this, - v.cast()); - break; - } - case value_t::Integer : - { - switch_assign::invoke(*this, - v.cast()); - break; - } - case value_t::Float : - { - switch_assign::invoke(*this, - v.cast()); - break; - } - case value_t::String : - { - switch_assign::invoke(*this, - v.cast()); - break; - } - case value_t::Datetime: - { - switch_assign::invoke(*this, - v.cast()); - break; - } - case value_t::Array : - { - switch_assign::invoke(*this, - v.cast()); - break; - } - case value_t::Table : - { - switch_assign::invoke(*this, - v.cast()); - break; - } - case value_t::Empty : break; - case value_t::Unknown : assert(false); - default: assert(false); - } - return *this; -} - -inline value& value::operator=(value&& v) -{ - if(should_be_cleaned(this->type_)) - { - this->switch_clean(this->type_); - } - this->type_ = v.type_; - - switch(this->type_) - { - case value_t::Boolean : - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::Integer : - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::Float : - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::String : - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::Datetime: - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::Array : - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::Table : - { - switch_assign::invoke(*this, - std::move(v.cast())); - break; - } - case value_t::Empty : break; - case value_t::Unknown : assert(false); - default: assert(false); - } - return *this; -} - -template::is_toml_type, std::nullptr_t>::type> -value::value(T&& v) : type_(toml::detail::check_type()) -{ - constexpr value_t kind = toml::detail::check_type(); - switch_assign::invoke(*this, std::forward(v)); -} - -template::is_toml_type, std::nullptr_t>::type> -value& value::operator=(T&& v) -{ - constexpr value_t kind = toml::detail::check_type(); - if(should_be_cleaned(this->type_)) - { - switch_clean(this->type_); - } - this->type_ = kind; - switch_assign::invoke(*this, std::forward(v)); - return *this; -} - -template::is_toml_type, std::nullptr_t>::type> -value::value(std::initializer_list init) - : type_(toml::value_t::Array) -{ - toml::Array arr; arr.reserve(init.size()); - for(auto&& item : init) - arr.emplace_back(std::move(item)); - switch_assign::invoke(*this, std::move(arr)); -} - -inline value::value( - std::initializer_list> init) - : type_(toml::value_t::Table) -{ - toml::Table tmp; - for(auto&& item : init) - tmp.emplace(std::move(item.first), std::move(item.second)); - switch_assign::invoke(*this, std::move(tmp)); -} - template -inline typename detail::toml_default_type::type const& -value::cast() const +typename detail::toml_default_type::type& value::cast() & { if(T != this->type_) - throw type_error("current type: " + stringize(this->type_) + - std::string(" is not query type: ") + stringize(T)); + { + throw type_error(this->format_error(concat_to_string( + "[error] toml::value bad_cast type-casting to ", T), + concat_to_string("the actual type is ", this->type_))); + } return switch_cast::invoke(*this); } template -inline typename detail::toml_default_type::type& -value::cast() +typename detail::toml_default_type::type const& value::cast() const& { if(T != this->type_) - throw type_error("current type: " + stringize(this->type_) + - std::string(" is not query type: ") + stringize(T)); + { + throw type_error(this->format_error(concat_to_string( + "[error] toml::value bad_cast type-casting to ", T), + concat_to_string("the actual type is ", this->type_))); + } return switch_cast::invoke(*this); } +template +typename detail::toml_default_type::type&& value::cast() && +{ + if(T != this->type_) + { + throw type_error(this->format_error(concat_to_string( + "[error] toml::value bad_cast type-casting to ", T), + concat_to_string("the actual type is ", this->type_))); + } + return switch_cast::invoke(std::move(*this)); +} inline bool operator==(const toml::value& lhs, const toml::value& rhs) { - if(lhs.type() != rhs.type()) return false; + if(lhs.type() != rhs.type()){return false;} switch(lhs.type()) { case value_t::Boolean : @@ -515,8 +691,14 @@ inline bool operator==(const toml::value& lhs, const toml::value& rhs) return lhs.cast() == rhs.cast(); case value_t::String : return lhs.cast() == rhs.cast(); - case value_t::Datetime: - return lhs.cast() == rhs.cast(); + case value_t::OffsetDatetime: + return lhs.cast() == rhs.cast(); + case value_t::LocalDatetime: + return lhs.cast() == rhs.cast(); + case value_t::LocalDate: + return lhs.cast() == rhs.cast(); + case value_t::LocalTime: + return lhs.cast() == rhs.cast(); case value_t::Array : return lhs.cast() == rhs.cast(); case value_t::Table : @@ -528,7 +710,7 @@ inline bool operator==(const toml::value& lhs, const toml::value& rhs) } inline bool operator<(const toml::value& lhs, const toml::value& rhs) { - if(lhs.type() != rhs.type()) return (lhs.type() < rhs.type()); + if(lhs.type() != rhs.type()){return (lhs.type() < rhs.type());} switch(lhs.type()) { case value_t::Boolean : @@ -539,8 +721,12 @@ inline bool operator<(const toml::value& lhs, const toml::value& rhs) return lhs.cast() < rhs.cast(); case value_t::String : return lhs.cast() < rhs.cast(); - case value_t::Datetime: - return lhs.cast() < rhs.cast(); + case value_t::LocalDatetime: + return lhs.cast() < rhs.cast(); + case value_t::LocalDate: + return lhs.cast() < rhs.cast(); + case value_t::LocalTime: + return lhs.cast() < rhs.cast(); case value_t::Array : return lhs.cast() < rhs.cast(); case value_t::Table :