diff --git a/README.md b/README.md index f2b0d2d..a198c92 100644 --- a/README.md +++ b/README.md @@ -477,6 +477,40 @@ Note that, although `std::string` has `at()` member function, `toml::value::at` throws if the contained type is a string. Because `std::string` does not contain `toml::value`. +### `operator[]` + +You can also access to the element of a table and an array by +`toml::basic_value::operator[]`. + +```cpp +const toml::value v{1,2,3,4,5}; +std::cout << v[2].as_integer() << std::endl; // 3 + +const toml::value v{{"foo", 42}, {"bar", 3.14}}; +std::cout << v["foo"].as_integer() << std::endl; // 42 +``` + +When you access to a `toml::value` that is not initialized yet via +`operator[](const std::string&)`, the `toml::value` will be a table, +just like the `std::map`. + +```cpp +toml::value v; // not initialized as a table. +v["foo"] = 42; // OK. `v` will be a table. +``` + +Contrary, if you access to a `toml::value` that contains an array via `operator[]`, +it does not check anything. It converts `toml::value` without type check and then +access to the n-th element without boundary check, just like the `std::vector::operator[]`. + +```cpp +toml::value v; // not initialized as an array +v[2] = 42; // error! UB +``` + +Please make sure that the `toml::value` has an array inside when you access to +its element via `operator[]`. + ## Checking value type You can check the type of a value by `is_xxx` function. diff --git a/tests/test_value.cpp b/tests/test_value.cpp index 8c8c70c..c2f02db 100644 --- a/tests/test_value.cpp +++ b/tests/test_value.cpp @@ -934,3 +934,35 @@ BOOST_AUTO_TEST_CASE(test_value_at) BOOST_CHECK_THROW(v1.at(5), std::out_of_range); } } + +BOOST_AUTO_TEST_CASE(test_value_bracket) +{ + { + toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}}; + + BOOST_TEST(v1["foo"].as_integer() == 42); + BOOST_TEST(v1["bar"].as_floating() == 3.14); + BOOST_TEST(v1["baz"].as_string() == "qux"); + + v1["qux"] = 54; + BOOST_TEST(v1["qux"].as_integer() == 54); + } + { + toml::value v1; + v1["foo"] = 42; + + BOOST_TEST(v1.is_table()); + BOOST_TEST(v1["foo"].as_integer() == 42); + } + { + toml::value v1{1,2,3,4,5}; + + BOOST_TEST(v1[0].as_integer() == 1); + BOOST_TEST(v1[1].as_integer() == 2); + BOOST_TEST(v1[2].as_integer() == 3); + BOOST_TEST(v1[3].as_integer() == 4); + BOOST_TEST(v1[4].as_integer() == 5); + + BOOST_CHECK_THROW(v1["foo"], toml::type_error); + } +} diff --git a/toml/value.hpp b/toml/value.hpp index e2f5cf8..1b492a4 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -1579,6 +1579,14 @@ class basic_value { return this->as_table().at(k); } + value_type& operator[](const key& k) + { + if(this->is_uninitialized()) + { + *this = table_type{}; + } + return this->as_table()[k]; + } value_type& at(const std::size_t idx) { @@ -1589,6 +1597,15 @@ class basic_value return this->as_array().at(idx); } + value_type& operator[](const std::size_t idx) noexcept + { + return this->as_array(std::nothrow)[idx]; + } + value_type const& operator[](const std::size_t idx) const noexcept + { + return this->as_array(std::nothrow)[idx]; + } + source_location location() const { return source_location(this->region_info_.get());