diff --git a/README.md b/README.md index ddb93eb..b890733 100644 --- a/README.md +++ b/README.md @@ -633,29 +633,49 @@ if(v.is_integer() && v.as_integer() == 42) } ``` -The complete list of the functions is below. +`as_*` functions internally checks the current contained type for safety and +throws `toml::type_error` if the contained value type is different (after toml11 +v2.4.0). If you already confirmed that the value has the type you will cast +into, you can skip the additional checking by passing `std::nothrow` object to it. + +```cpp +toml::value v = /* ... */; +if(v.is_integer() && v.as_integer(std::nothrow) == 42) // never fail +{ + std::cout << "value is 42" << std::endl; +} +``` + +The full list of the functions is below. ```cpp namespace toml { class value { // ... - const boolean& as_boolean() const& noexcept; - const integer& as_integer() const& noexcept; - const floating& as_floating() const& noexcept; - const string& as_string() const& noexcept; - const offset_datetime& as_offset_datetime() const& noexcept; - const local_datetime& as_local_datetime() const& noexcept; - const local_date& as_local_date() const& noexcept; - const local_time& as_local_time() const& noexcept; - const array& as_array() const& noexcept; - const table& as_table() const& noexcept; + const boolean& as_boolean() const&; + const integer& as_integer() const&; + const floating& as_floating() const&; + const string& as_string() const&; + const offset_datetime& as_offset_datetime() const&; + const local_datetime& as_local_datetime() const&; + const local_date& as_local_date() const&; + const local_time& as_local_time() const&; + const array& as_array() const&; + const table& as_table() const&; // -------------------------------------------------------- // non-const version - boolean& as_boolean() & noexcept; + boolean& as_boolean() &; // ditto... // -------------------------------------------------------- // rvalue version - boolean&& as_boolean() && noexcept; + boolean&& as_boolean() &&; + // ditto... + + // -------------------------------------------------------- + // noexcept versions ... + const boolean& as_boolean(const std::nothrow_t&) const& noexcept; + boolean& as_boolean(const std::nothrow_t&) & noexcept; + boolean&& as_boolean(const std::nothrow_t&) && noexcept; // ditto... }; } // toml diff --git a/tests/test_value.cpp b/tests/test_value.cpp index 8b1afe9..d9cfca3 100644 --- a/tests/test_value.cpp +++ b/tests/test_value.cpp @@ -32,6 +32,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean) BOOST_CHECK_EQUAL(v2.cast(), false); BOOST_CHECK_EQUAL(v1.as_boolean(), true); BOOST_CHECK_EQUAL(v2.as_boolean(), false); + BOOST_CHECK_EQUAL(v1.as_boolean(std::nothrow), true); + BOOST_CHECK_EQUAL(v2.as_boolean(std::nothrow), false); v1 = false; v2 = true; @@ -122,6 +124,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer) BOOST_CHECK_EQUAL(v2.cast(), 42u); BOOST_CHECK_EQUAL(v1.as_integer(), -42); BOOST_CHECK_EQUAL(v2.as_integer(), 42u); + BOOST_CHECK_EQUAL(v1.as_integer(std::nothrow), -42); + BOOST_CHECK_EQUAL(v2.as_integer(std::nothrow), 42u); v1 = 54; v2 = -54; @@ -212,6 +216,8 @@ BOOST_AUTO_TEST_CASE(test_value_float) BOOST_CHECK_CLOSE_FRACTION(v2.cast(), 3.14, 1e-2); BOOST_CHECK_EQUAL (v1.as_floating(), 3.14); BOOST_CHECK_CLOSE_FRACTION(v2.as_floating(), 3.14, 1e-2); + BOOST_CHECK_EQUAL (v1.as_floating(std::nothrow), 3.14); + BOOST_CHECK_CLOSE_FRACTION(v2.as_floating(std::nothrow), 3.14, 1e-2); v1 = 2.718f; v2 = 2.718; @@ -309,7 +315,9 @@ BOOST_AUTO_TEST_CASE(test_value_string) BOOST_CHECK_EQUAL(v1.as_string(), "foo"); BOOST_CHECK_EQUAL(v2.as_string(), "foo"); BOOST_CHECK_EQUAL(v3.as_string(), "foo"); - + BOOST_CHECK_EQUAL(v1.as_string(std::nothrow), "foo"); + BOOST_CHECK_EQUAL(v2.as_string(std::nothrow), "foo"); + BOOST_CHECK_EQUAL(v3.as_string(std::nothrow), "foo"); v1 = "bar"; v2 = "bar"; @@ -439,6 +447,8 @@ BOOST_AUTO_TEST_CASE(test_value_local_date) toml::local_date(2018, toml::month_t::Jan, 31)); BOOST_CHECK_EQUAL(v1.as_local_date(), toml::local_date(2018, toml::month_t::Jan, 31)); + BOOST_CHECK_EQUAL(v1.as_local_date(std::nothrow), + toml::local_date(2018, toml::month_t::Jan, 31)); v1 = toml::local_date(2018, toml::month_t::Apr, 1); @@ -503,6 +513,8 @@ BOOST_AUTO_TEST_CASE(test_value_local_time) v2.cast()); BOOST_CHECK_EQUAL(v1.as_local_time(), v2.as_local_time()); + BOOST_CHECK_EQUAL(v1.as_local_time(std::nothrow), + v2.as_local_time(std::nothrow)); v1 = toml::local_time(1, 30, 0, /*ms*/ 100, /*us*/ 0); @@ -557,6 +569,11 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime) toml::local_datetime( toml::local_date(2018, toml::month_t::Jan, 31), toml::local_time(12, 30, 45))); + BOOST_CHECK_EQUAL(v1.as_local_datetime(std::nothrow), + 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), @@ -628,6 +645,13 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime) toml::local_time(12, 30, 45), toml::time_offset(9, 0) )); + BOOST_CHECK_EQUAL(v1.as_offset_datetime(std::nothrow), + 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), @@ -705,7 +729,11 @@ BOOST_AUTO_TEST_CASE(test_value_array) BOOST_CHECK_EQUAL(v1.as_array().at(2).as_integer(), 3); BOOST_CHECK_EQUAL(v1.as_array().at(3).as_integer(), 4); BOOST_CHECK_EQUAL(v1.as_array().at(4).as_integer(), 5); - + BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(0).as_integer(), 1); + BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(1).as_integer(), 2); + BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(2).as_integer(), 3); + BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(3).as_integer(), 4); + BOOST_CHECK_EQUAL(v1.as_array(std::nothrow).at(4).as_integer(), 5); BOOST_CHECK_EQUAL(v2.cast().at(0).cast(), 6); BOOST_CHECK_EQUAL(v2.cast().at(1).cast(), 7); @@ -794,6 +822,9 @@ BOOST_AUTO_TEST_CASE(test_value_table) BOOST_CHECK_EQUAL(v1.as_table().at("foo").as_integer(), 42); BOOST_CHECK_EQUAL(v1.as_table().at("bar").as_floating(), 3.14); BOOST_CHECK_EQUAL(v1.as_table().at("baz").as_string().str, "qux"); + BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("foo").as_integer(), 42); + BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("bar").as_floating(), 3.14); + BOOST_CHECK_EQUAL(v1.as_table(std::nothrow).at("baz").as_string().str, "qux"); v1 = toml::table{{"foo", 2.71}, {"bar", 54}, {"baz", "quux"}}; @@ -840,4 +871,15 @@ BOOST_AUTO_TEST_CASE(test_value_empty) toml::value v1; BOOST_CHECK(v1.is_uninitialized()); BOOST_CHECK(v1.is(toml::value_t::empty)); + + BOOST_CHECK_THROW(v1.as_boolean(), toml::type_error); + BOOST_CHECK_THROW(v1.as_integer(), toml::type_error); + BOOST_CHECK_THROW(v1.as_floating(), toml::type_error); + BOOST_CHECK_THROW(v1.as_string(), toml::type_error); + BOOST_CHECK_THROW(v1.as_offset_datetime(), toml::type_error); + BOOST_CHECK_THROW(v1.as_local_datetime(), toml::type_error); + BOOST_CHECK_THROW(v1.as_local_date(), toml::type_error); + BOOST_CHECK_THROW(v1.as_local_time(), toml::type_error); + BOOST_CHECK_THROW(v1.as_array(), toml::type_error); + BOOST_CHECK_THROW(v1.as_table(), toml::type_error); } diff --git a/toml/value.hpp b/toml/value.hpp index eaaaf23..7683382 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -944,38 +944,295 @@ class basic_value return detail::switch_cast::invoke(std::move(*this)); } - boolean const& as_boolean() const& noexcept {return this->boolean_;} - integer const& as_integer() const& noexcept {return this->integer_;} - floating const& as_floating() const& noexcept {return this->floating_;} - string const& as_string() const& noexcept {return this->string_;} - offset_datetime const& as_offset_datetime() const& noexcept {return this->offset_datetime_;} - local_datetime const& as_local_datetime() const& noexcept {return this->local_datetime_;} - local_date const& as_local_date() const& noexcept {return this->local_date_;} - local_time const& as_local_time() const& noexcept {return this->local_time_;} - array_type const& as_array() const& noexcept {return this->array_.value();} - table_type const& as_table() const& noexcept {return this->table_.value();} + // ------------------------------------------------------------------------ + // nothrow version - boolean & as_boolean() & noexcept {return this->boolean_;} - integer & as_integer() & noexcept {return this->integer_;} - floating & as_floating() & noexcept {return this->floating_;} - string & as_string() & noexcept {return this->string_;} - offset_datetime& as_offset_datetime() & noexcept {return this->offset_datetime_;} - local_datetime & as_local_datetime() & noexcept {return this->local_datetime_;} - local_date & as_local_date() & noexcept {return this->local_date_;} - local_time & as_local_time() & noexcept {return this->local_time_;} - array_type & as_array() & noexcept {return this->array_.value();} - table_type & as_table() & noexcept {return this->table_.value();} + boolean const& as_boolean (const std::nothrow_t&) const& noexcept {return this->boolean_;} + integer const& as_integer (const std::nothrow_t&) const& noexcept {return this->integer_;} + floating const& as_floating (const std::nothrow_t&) const& noexcept {return this->floating_;} + string const& as_string (const std::nothrow_t&) const& noexcept {return this->string_;} + offset_datetime const& as_offset_datetime(const std::nothrow_t&) const& noexcept {return this->offset_datetime_;} + local_datetime const& as_local_datetime (const std::nothrow_t&) const& noexcept {return this->local_datetime_;} + local_date const& as_local_date (const std::nothrow_t&) const& noexcept {return this->local_date_;} + local_time const& as_local_time (const std::nothrow_t&) const& noexcept {return this->local_time_;} + array_type const& as_array (const std::nothrow_t&) const& noexcept {return this->array_.value();} + table_type const& as_table (const std::nothrow_t&) const& noexcept {return this->table_.value();} - boolean && as_boolean() && noexcept {return std::move(this->boolean_);} - integer && as_integer() && noexcept {return std::move(this->integer_);} - floating && as_floating() && noexcept {return std::move(this->floating_);} - string && as_string() && noexcept {return std::move(this->string_);} - offset_datetime&& as_offset_datetime() && noexcept {return std::move(this->offset_datetime_);} - local_datetime && as_local_datetime() && noexcept {return std::move(this->local_datetime_);} - local_date && as_local_date() && noexcept {return std::move(this->local_date_);} - local_time && as_local_time() && noexcept {return std::move(this->local_time_);} - array_type && as_array() && noexcept {return std::move(this->array_.value());} - table_type && as_table() && noexcept {return std::move(this->table_.value());} + boolean & as_boolean (const std::nothrow_t&) & noexcept {return this->boolean_;} + integer & as_integer (const std::nothrow_t&) & noexcept {return this->integer_;} + floating & as_floating (const std::nothrow_t&) & noexcept {return this->floating_;} + string & as_string (const std::nothrow_t&) & noexcept {return this->string_;} + offset_datetime& as_offset_datetime(const std::nothrow_t&) & noexcept {return this->offset_datetime_;} + local_datetime & as_local_datetime (const std::nothrow_t&) & noexcept {return this->local_datetime_;} + local_date & as_local_date (const std::nothrow_t&) & noexcept {return this->local_date_;} + local_time & as_local_time (const std::nothrow_t&) & noexcept {return this->local_time_;} + array_type & as_array (const std::nothrow_t&) & noexcept {return this->array_.value();} + table_type & as_table (const std::nothrow_t&) & noexcept {return this->table_.value();} + + boolean && as_boolean (const std::nothrow_t&) && noexcept {return std::move(this->boolean_);} + integer && as_integer (const std::nothrow_t&) && noexcept {return std::move(this->integer_);} + floating && as_floating (const std::nothrow_t&) && noexcept {return std::move(this->floating_);} + string && as_string (const std::nothrow_t&) && noexcept {return std::move(this->string_);} + offset_datetime&& as_offset_datetime(const std::nothrow_t&) && noexcept {return std::move(this->offset_datetime_);} + local_datetime && as_local_datetime (const std::nothrow_t&) && noexcept {return std::move(this->local_datetime_);} + local_date && as_local_date (const std::nothrow_t&) && noexcept {return std::move(this->local_date_);} + local_time && as_local_time (const std::nothrow_t&) && noexcept {return std::move(this->local_time_);} + array_type && as_array (const std::nothrow_t&) && noexcept {return std::move(this->array_.value());} + table_type && as_table (const std::nothrow_t&) && noexcept {return std::move(this->table_.value());} + + // ======================================================================== + // throw version + // ------------------------------------------------------------------------ + // const reference + + boolean const& as_boolean() const& + { + if(this->type_ != value_t::boolean) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->boolean_; + } + integer const& as_integer() const& + { + if(this->type_ != value_t::integer) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->integer_; + } + floating const& as_floating() const& + { + if(this->type_ != value_t::floating) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->floating_; + } + string const& as_string() const& + { + if(this->type_ != value_t::string) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->string_; + } + offset_datetime const& as_offset_datetime() const& + { + if(this->type_ != value_t::offset_datetime) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->offset_datetime_; + } + local_datetime const& as_local_datetime() const& + { + if(this->type_ != value_t::local_datetime) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->local_datetime_; + } + local_date const& as_local_date() const& + { + if(this->type_ != value_t::local_date) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->local_date_; + } + local_time const& as_local_time() const& + { + if(this->type_ != value_t::local_time) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->local_time_; + } + array_type const& as_array() const& + { + if(this->type_ != value_t::array) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->array_.value(); + } + table_type const& as_table() const& + { + if(this->type_ != value_t::table) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->table_.value(); + } + + // ------------------------------------------------------------------------ + // nonconst reference + + boolean & as_boolean() & + { + if(this->type_ != value_t::boolean) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->boolean_; + } + integer & as_integer() & + { + if(this->type_ != value_t::integer) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->integer_; + } + floating & as_floating() & + { + if(this->type_ != value_t::floating) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->floating_; + } + string & as_string() & + { + if(this->type_ != value_t::string) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->string_; + } + offset_datetime & as_offset_datetime() & + { + if(this->type_ != value_t::offset_datetime) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->offset_datetime_; + } + local_datetime & as_local_datetime() & + { + if(this->type_ != value_t::local_datetime) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->local_datetime_; + } + local_date & as_local_date() & + { + if(this->type_ != value_t::local_date) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->local_date_; + } + local_time & as_local_time() & + { + if(this->type_ != value_t::local_time) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->local_time_; + } + array_type & as_array() & + { + if(this->type_ != value_t::array) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->array_.value(); + } + table_type & as_table() & + { + if(this->type_ != value_t::table) + { + detail::throw_bad_cast(this->type_, *this); + } + return this->table_.value(); + } + + // ------------------------------------------------------------------------ + // rvalue reference + + boolean && as_boolean() && + { + if(this->type_ != value_t::boolean) + { + detail::throw_bad_cast(this->type_, *this); + } + return std::move(this->boolean_); + } + integer && as_integer() && + { + if(this->type_ != value_t::integer) + { + detail::throw_bad_cast(this->type_, *this); + } + return std::move(this->integer_); + } + floating && as_floating() && + { + if(this->type_ != value_t::floating) + { + detail::throw_bad_cast(this->type_, *this); + } + return std::move(this->floating_); + } + string && as_string() && + { + if(this->type_ != value_t::string) + { + detail::throw_bad_cast(this->type_, *this); + } + return std::move(this->string_); + } + offset_datetime && as_offset_datetime() && + { + if(this->type_ != value_t::offset_datetime) + { + detail::throw_bad_cast(this->type_, *this); + } + return std::move(this->offset_datetime_); + } + local_datetime && as_local_datetime() && + { + if(this->type_ != value_t::local_datetime) + { + detail::throw_bad_cast(this->type_, *this); + } + return std::move(this->local_datetime_); + } + local_date && as_local_date() && + { + if(this->type_ != value_t::local_date) + { + detail::throw_bad_cast(this->type_, *this); + } + return std::move(this->local_date_); + } + local_time && as_local_time() && + { + if(this->type_ != value_t::local_time) + { + detail::throw_bad_cast(this->type_, *this); + } + return std::move(this->local_time_); + } + array_type && as_array() && + { + if(this->type_ != value_t::array) + { + detail::throw_bad_cast(this->type_, *this); + } + return std::move(this->array_.value()); + } + table_type && as_table() && + { + if(this->type_ != value_t::table) + { + detail::throw_bad_cast(this->type_, *this); + } + return std::move(this->table_.value()); + } source_location location() const {