From cba2f062aeb67528604f98d64ec4aa103df8261a Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Tue, 28 Jan 2025 01:33:42 +0900 Subject: [PATCH 01/10] feat: add TOML11_ENABLE_ACCESS_CHECK macro --- CMakeLists.txt | 1 + src/CMakeLists.txt | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d3306f..6f215a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ project(toml11 LANGUAGES CXX VERSION "${TOML11_VERSION_MAJOR}.${TOML11_VERSION_M include(CTest) # to use ${BUILD_TESTING} option(TOML11_PRECOMPILE "precompile toml11 library" OFF) +option(TOML11_ENABLE_ACCESS_CHECK "enable access check feature (beta)" OFF) include(CMakeDependentOption) cmake_policy(PUSH) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c65307f..100afd0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -90,7 +90,10 @@ if(TOML11_PRECOMPILE) types.cpp value_t.cpp ) - target_compile_definitions(toml11 PUBLIC -DTOML11_COMPILE_SOURCES) + target_compile_definitions(toml11 PUBLIC + -DTOML11_COMPILE_SOURCES + $<$: -DTOML11_ENABLE_ACCESS_CHECK> + ) target_include_directories(toml11 PUBLIC $ $ @@ -127,6 +130,9 @@ if(TOML11_PRECOMPILE) endif() else() add_library(toml11 INTERFACE) + target_compile_definitions(toml11 INTERFACE + $<$: -DTOML11_ENABLE_ACCESS_CHECK> + ) target_include_directories(toml11 INTERFACE $ $ From bb082bc0bb214f153d3f15345f1acf8fce93ec92 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 29 Jan 2025 01:31:15 +0900 Subject: [PATCH 02/10] feat: add accessed() flag --- include/toml11/value.hpp | 233 +++++++++++++++++++++++++++++++++++---- 1 file changed, 211 insertions(+), 22 deletions(-) diff --git a/include/toml11/value.hpp b/include/toml11/value.hpp index d945fa0..85c2643 100644 --- a/include/toml11/value.hpp +++ b/include/toml11/value.hpp @@ -17,6 +17,10 @@ #include #endif +#ifdef TOML11_ENABLE_ACCESS_CHECK +#include +#endif + #include namespace toml @@ -86,6 +90,9 @@ class basic_value basic_value() noexcept : type_(value_t::empty), empty_('\0'), region_{}, comments_{} +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} ~basic_value() noexcept {this->cleanup();} @@ -93,6 +100,9 @@ class basic_value basic_value(const basic_value& v) : type_(v.type_), region_(v.region_), comments_(v.comments_) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{v.accessed()} +#endif { switch(this->type_) { @@ -112,6 +122,9 @@ class basic_value basic_value(basic_value&& v) : type_(v.type()), region_(std::move(v.region_)), comments_(std::move(v.comments_)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{v.accessed()} +#endif { switch(this->type_) { @@ -137,6 +150,9 @@ class basic_value this->type_ = v.type_; this->region_ = v.region_; this->comments_ = v.comments_; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = v.accessed(); +#endif switch(this->type_) { case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; @@ -161,6 +177,9 @@ class basic_value this->type_ = v.type_; this->region_ = std::move(v.region_); this->comments_ = std::move(v.comments_); +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = v.accessed(); +#endif switch(this->type_) { case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break; @@ -184,6 +203,9 @@ class basic_value basic_value(basic_value v, std::vector com) : type_(v.type()), region_(std::move(v.region_)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{v.accessed()} +#endif { switch(this->type_) { @@ -209,6 +231,9 @@ class basic_value : type_(other.type_), region_(std::move(other.region_)), comments_(std::move(other.comments_)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{other.accessed()} +#endif { switch(other.type_) { @@ -254,6 +279,9 @@ class basic_value : type_(other.type_), region_(std::move(other.region_)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{other.accessed()} +#endif { switch(other.type_) { @@ -300,6 +328,10 @@ class basic_value this->region_ = other.region_; this->comments_ = comment_type(other.comments_); this->type_ = other.type_; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = other.accessed(); +#endif + switch(other.type_) { // use auto-convert in constructor @@ -359,6 +391,9 @@ class basic_value std::vector com, region_type reg) : type_(value_t::boolean), boolean_(boolean_storage(x, fmt)), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(boolean_type x) { @@ -370,6 +405,9 @@ class basic_value this->cleanup(); this->type_ = value_t::boolean; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->boolean_, boolean_storage(x, fmt)); return *this; } @@ -393,6 +431,9 @@ class basic_value basic_value(integer_type x, integer_format_info fmt, std::vector com, region_type reg) : type_(value_t::integer), integer_(integer_storage(std::move(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(integer_type x) { @@ -404,6 +445,9 @@ class basic_value this->cleanup(); this->type_ = value_t::integer; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->integer_, integer_storage(std::move(x), std::move(fmt))); return *this; } @@ -439,6 +483,9 @@ class basic_value basic_value(T x, integer_format_info fmt, std::vector com, region_type reg) : type_(value_t::integer), integer_(integer_storage(std::move(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} template = nullptr> basic_value& operator=(T x) @@ -451,6 +498,9 @@ class basic_value this->cleanup(); this->type_ = value_t::integer; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->integer_, integer_storage(x, std::move(fmt))); return *this; } @@ -474,6 +524,9 @@ class basic_value basic_value(floating_type x, floating_format_info fmt, std::vector com, region_type reg) : type_(value_t::floating), floating_(floating_storage(std::move(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(floating_type x) { @@ -485,6 +538,9 @@ class basic_value this->cleanup(); this->type_ = value_t::floating; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->floating_, floating_storage(std::move(x), std::move(fmt))); return *this; } @@ -523,6 +579,9 @@ class basic_value basic_value(T x, floating_format_info fmt, std::vector com, region_type reg) : type_(value_t::floating), floating_(floating_storage(x, std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} template = nullptr> @@ -536,6 +595,9 @@ class basic_value this->cleanup(); this->type_ = value_t::floating; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->floating_, floating_storage(x, std::move(fmt))); return *this; } @@ -560,6 +622,9 @@ class basic_value std::vector com, region_type reg) : type_(value_t::string), string_(string_storage(std::move(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(string_type x) { @@ -571,6 +636,9 @@ class basic_value this->cleanup(); this->type_ = value_t::string; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->string_, string_storage(x, std::move(fmt))); return *this; } @@ -593,6 +661,9 @@ class basic_value std::vector com, region_type reg) : type_(value_t::string), string_(string_storage(string_type(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(const typename string_type::value_type* x) { @@ -604,6 +675,9 @@ class basic_value this->cleanup(); this->type_ = value_t::string; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->string_, string_storage(string_type(x), std::move(fmt))); return *this; } @@ -628,6 +702,9 @@ class basic_value std::vector com, region_type reg) : type_(value_t::string), string_(string_storage(string_type(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(string_view_type x) { @@ -639,6 +716,9 @@ class basic_value this->cleanup(); this->type_ = value_t::string; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->string_, string_storage(string_type(x), std::move(fmt))); return *this; } @@ -682,6 +762,9 @@ class basic_value : type_(value_t::string), string_(string_storage(detail::string_conv(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} template, string_type>>, @@ -697,6 +780,9 @@ class basic_value this->cleanup(); this->type_ = value_t::string; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->string_, string_storage(detail::string_conv(x), std::move(fmt))); return *this; } @@ -721,6 +807,9 @@ class basic_value std::vector com, region_type reg) : type_(value_t::local_date), local_date_(local_date_storage(x, fmt)), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(local_date_type x) { @@ -732,6 +821,9 @@ class basic_value this->cleanup(); this->type_ = value_t::local_date; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->local_date_, local_date_storage(x, fmt)); return *this; } @@ -756,6 +848,9 @@ class basic_value std::vector com, region_type reg) : type_(value_t::local_time), local_time_(local_time_storage(x, fmt)), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(local_time_type x) { @@ -767,6 +862,9 @@ class basic_value this->cleanup(); this->type_ = value_t::local_time; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->local_time_, local_time_storage(x, fmt)); return *this; } @@ -804,6 +902,9 @@ class basic_value this->cleanup(); this->type_ = value_t::local_time; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->local_time_, local_time_storage(local_time_type(x), std::move(fmt))); return *this; } @@ -828,6 +929,9 @@ class basic_value std::vector com, region_type reg) : type_(value_t::local_datetime), local_datetime_(local_datetime_storage(x, fmt)), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(local_datetime_type x) { @@ -839,6 +943,9 @@ class basic_value this->cleanup(); this->type_ = value_t::local_datetime; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->local_datetime_, local_datetime_storage(x, fmt)); return *this; } @@ -863,6 +970,9 @@ class basic_value std::vector com, region_type reg) : type_(value_t::offset_datetime), offset_datetime_(offset_datetime_storage(x, fmt)), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(offset_datetime_type x) { @@ -874,6 +984,9 @@ class basic_value this->cleanup(); this->type_ = value_t::offset_datetime; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->offset_datetime_, offset_datetime_storage(x, fmt)); return *this; } @@ -906,6 +1019,9 @@ class basic_value this->cleanup(); this->type_ = value_t::offset_datetime; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->offset_datetime_, offset_datetime_storage(offset_datetime_type(x), fmt)); return *this; } @@ -931,6 +1047,9 @@ class basic_value : type_(value_t::array), array_(array_storage( detail::storage(std::move(x)), std::move(fmt) )), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(array_type x) { @@ -942,6 +1061,9 @@ class basic_value this->cleanup(); this->type_ = value_t::array; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->array_, array_storage( detail::storage(std::move(x)), std::move(fmt))); return *this; @@ -988,6 +1110,9 @@ class basic_value std::make_move_iterator(x.end())) ), std::move(fmt) )), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} template = nullptr> basic_value& operator=(T x) @@ -1000,7 +1125,9 @@ class basic_value this->cleanup(); this->type_ = value_t::array; this->region_ = region_type{}; - +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif array_type a(std::make_move_iterator(x.begin()), std::make_move_iterator(x.end())); assigner(this->array_, array_storage( @@ -1029,6 +1156,9 @@ class basic_value : type_(value_t::table), table_(table_storage( detail::storage(std::move(x)), std::move(fmt) )), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} basic_value& operator=(table_type x) { @@ -1040,6 +1170,9 @@ class basic_value this->cleanup(); this->type_ = value_t::table; this->region_ = region_type{}; +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif assigner(this->table_, table_storage( detail::storage(std::move(x)), std::move(fmt))); return *this; @@ -1084,6 +1217,9 @@ class basic_value std::make_move_iterator(x.end()) )), std::move(fmt) )), region_(std::move(reg)), comments_(std::move(com)) +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} template = nullptr> basic_value& operator=(T x) @@ -1096,7 +1232,9 @@ class basic_value this->cleanup(); this->type_ = value_t::table; this->region_ = region_type{}; - +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif table_type t(std::make_move_iterator(x.begin()), std::make_move_iterator(x.end())); assigner(this->table_, table_storage( @@ -1126,6 +1264,9 @@ class basic_value basic_value& operator=(const T& ud) { *this = into>::template into_toml(ud); +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif return *this; } @@ -1149,6 +1290,9 @@ class basic_value basic_value& operator=(const T& ud) { *this = ud.into_toml(); +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif return *this; } @@ -1172,6 +1316,9 @@ class basic_value basic_value& operator=(const T& ud) { *this = ud.template into_toml(); +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif return *this; } // }}} @@ -1181,6 +1328,9 @@ class basic_value // mainly for `null` extension basic_value(detail::none_t, region_type reg) noexcept : type_(value_t::empty), empty_('\0'), region_(std::move(reg)), comments_{} +#ifdef TOML11_ENABLE_ACCESS_CHECK + , accessed_{false} +#endif {} // }}} @@ -1239,36 +1389,38 @@ class basic_value detail::enum_to_type_t> const& as(const std::nothrow_t&) const noexcept { + this->set_accessed(); return detail::getter::get_nothrow(*this); } template detail::enum_to_type_t>& as(const std::nothrow_t&) noexcept { + this->set_accessed(); return detail::getter::get_nothrow(*this); } - boolean_type const& as_boolean (const std::nothrow_t&) const noexcept {return this->boolean_.value;} - integer_type const& as_integer (const std::nothrow_t&) const noexcept {return this->integer_.value;} - floating_type const& as_floating (const std::nothrow_t&) const noexcept {return this->floating_.value;} - string_type const& as_string (const std::nothrow_t&) const noexcept {return this->string_.value;} - offset_datetime_type const& as_offset_datetime(const std::nothrow_t&) const noexcept {return this->offset_datetime_.value;} - local_datetime_type const& as_local_datetime (const std::nothrow_t&) const noexcept {return this->local_datetime_.value;} - local_date_type const& as_local_date (const std::nothrow_t&) const noexcept {return this->local_date_.value;} - local_time_type const& as_local_time (const std::nothrow_t&) const noexcept {return this->local_time_.value;} - array_type const& as_array (const std::nothrow_t&) const noexcept {return this->array_.value.get();} - table_type const& as_table (const std::nothrow_t&) const noexcept {return this->table_.value.get();} + boolean_type const& as_boolean (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->boolean_.value;} + integer_type const& as_integer (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->integer_.value;} + floating_type const& as_floating (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->floating_.value;} + string_type const& as_string (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->string_.value;} + offset_datetime_type const& as_offset_datetime(const std::nothrow_t&) const noexcept {this->set_accessed(); return this->offset_datetime_.value;} + local_datetime_type const& as_local_datetime (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->local_datetime_.value;} + local_date_type const& as_local_date (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->local_date_.value;} + local_time_type const& as_local_time (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->local_time_.value;} + array_type const& as_array (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->array_.value.get();} + table_type const& as_table (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->table_.value.get();} - boolean_type & as_boolean (const std::nothrow_t&) noexcept {return this->boolean_.value;} - integer_type & as_integer (const std::nothrow_t&) noexcept {return this->integer_.value;} - floating_type & as_floating (const std::nothrow_t&) noexcept {return this->floating_.value;} - string_type & as_string (const std::nothrow_t&) noexcept {return this->string_.value;} - offset_datetime_type& as_offset_datetime(const std::nothrow_t&) noexcept {return this->offset_datetime_.value;} - local_datetime_type & as_local_datetime (const std::nothrow_t&) noexcept {return this->local_datetime_.value;} - local_date_type & as_local_date (const std::nothrow_t&) noexcept {return this->local_date_.value;} - local_time_type & as_local_time (const std::nothrow_t&) noexcept {return this->local_time_.value;} - array_type & as_array (const std::nothrow_t&) noexcept {return this->array_.value.get();} - table_type & as_table (const std::nothrow_t&) noexcept {return this->table_.value.get();} + boolean_type & as_boolean (const std::nothrow_t&) noexcept {this->set_accessed(); return this->boolean_.value;} + integer_type & as_integer (const std::nothrow_t&) noexcept {this->set_accessed(); return this->integer_.value;} + floating_type & as_floating (const std::nothrow_t&) noexcept {this->set_accessed(); return this->floating_.value;} + string_type & as_string (const std::nothrow_t&) noexcept {this->set_accessed(); return this->string_.value;} + offset_datetime_type& as_offset_datetime(const std::nothrow_t&) noexcept {this->set_accessed(); return this->offset_datetime_.value;} + local_datetime_type & as_local_datetime (const std::nothrow_t&) noexcept {this->set_accessed(); return this->local_datetime_.value;} + local_date_type & as_local_date (const std::nothrow_t&) noexcept {this->set_accessed(); return this->local_date_.value;} + local_time_type & as_local_time (const std::nothrow_t&) noexcept {this->set_accessed(); return this->local_time_.value;} + array_type & as_array (const std::nothrow_t&) noexcept {this->set_accessed(); return this->array_.value.get();} + table_type & as_table (const std::nothrow_t&) noexcept {this->set_accessed(); return this->table_.value.get();} // }}} @@ -1291,6 +1443,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean); } + this->set_accessed(); return this->boolean_.value; } integer_type const& as_integer() const @@ -1299,6 +1452,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_integer()", value_t::integer); } + this->set_accessed(); return this->integer_.value; } floating_type const& as_floating() const @@ -1307,6 +1461,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_floating()", value_t::floating); } + this->set_accessed(); return this->floating_.value; } string_type const& as_string() const @@ -1315,6 +1470,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_string()", value_t::string); } + this->set_accessed(); return this->string_.value; } offset_datetime_type const& as_offset_datetime() const @@ -1323,6 +1479,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_offset_datetime()", value_t::offset_datetime); } + this->set_accessed(); return this->offset_datetime_.value; } local_datetime_type const& as_local_datetime() const @@ -1331,6 +1488,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_local_datetime()", value_t::local_datetime); } + this->set_accessed(); return this->local_datetime_.value; } local_date_type const& as_local_date() const @@ -1339,6 +1497,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date); } + this->set_accessed(); return this->local_date_.value; } local_time_type const& as_local_time() const @@ -1347,6 +1506,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time); } + this->set_accessed(); return this->local_time_.value; } array_type const& as_array() const @@ -1355,6 +1515,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_array()", value_t::array); } + this->set_accessed(); return this->array_.value.get(); } table_type const& as_table() const @@ -1363,6 +1524,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_table()", value_t::table); } + this->set_accessed(); return this->table_.value.get(); } @@ -1375,6 +1537,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean); } + this->set_accessed(); return this->boolean_.value; } integer_type& as_integer() @@ -1383,6 +1546,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_integer()", value_t::integer); } + this->set_accessed(); return this->integer_.value; } floating_type& as_floating() @@ -1391,6 +1555,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_floating()", value_t::floating); } + this->set_accessed(); return this->floating_.value; } string_type& as_string() @@ -1399,6 +1564,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_string()", value_t::string); } + this->set_accessed(); return this->string_.value; } offset_datetime_type& as_offset_datetime() @@ -1407,6 +1573,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_offset_datetime()", value_t::offset_datetime); } + this->set_accessed(); return this->offset_datetime_.value; } local_datetime_type& as_local_datetime() @@ -1415,6 +1582,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_local_datetime()", value_t::local_datetime); } + this->set_accessed(); return this->local_datetime_.value; } local_date_type& as_local_date() @@ -1423,6 +1591,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date); } + this->set_accessed(); return this->local_date_.value; } local_time_type& as_local_time() @@ -1431,6 +1600,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time); } + this->set_accessed(); return this->local_time_.value; } array_type& as_array() @@ -1439,6 +1609,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_array()", value_t::array); } + this->set_accessed(); return this->array_.value.get(); } table_type& as_table() @@ -1447,6 +1618,7 @@ class basic_value { this->throw_bad_cast("toml::value::as_table()", value_t::table); } + this->set_accessed(); return this->table_.value.get(); } @@ -1856,10 +2028,20 @@ class basic_value comment_type const& comments() const noexcept {return this->comments_;} comment_type& comments() noexcept {return this->comments_;} + bool accessed() const {return this->accessed_.load();} + private: // private helper functions =========================================== {{{ + void set_accessed() const noexcept + { +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_.store(true); +#endif + return; + } + void cleanup() noexcept { switch(this->type_) @@ -1876,6 +2058,9 @@ class basic_value case value_t::table : { table_ .~table_storage (); break; } default : { break; } } +#ifdef TOML11_ENABLE_ACCESS_CHECK + this->accessed_ = false; +#endif this->type_ = value_t::empty; return; } @@ -1942,6 +2127,10 @@ class basic_value }; region_type region_; comment_type comments_; + +#ifdef TOML11_ENABLE_ACCESS_CHECK + mutable std::atomic accessed_; +#endif }; template From 074e3507aa5179bd6e1af8242f3e4d7431efe245 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 30 Jan 2025 00:13:10 +0900 Subject: [PATCH 03/10] feat: consider type check is also `access` --- include/toml11/value.hpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/include/toml11/value.hpp b/include/toml11/value.hpp index 85c2643..3c4729d 100644 --- a/include/toml11/value.hpp +++ b/include/toml11/value.hpp @@ -1342,9 +1342,13 @@ class basic_value std::nullptr_t> = nullptr> bool is() const noexcept { - return detail::type_to_enum::value == this->type_; + return this->is(detail::type_to_enum::value); + } + bool is(value_t t) const noexcept + { + this->set_accessed(); + return t == this->type_; } - bool is(value_t t) const noexcept {return t == this->type_;} bool is_empty() const noexcept {return this->is(value_t::empty );} bool is_boolean() const noexcept {return this->is(value_t::boolean );} @@ -1360,6 +1364,7 @@ class basic_value bool is_array_of_tables() const noexcept { + this->set_accessed(); if( ! this->is_array()) {return false;} const auto& a = this->as_array(std::nothrow); // already checked. @@ -1379,7 +1384,11 @@ class basic_value return true; } - value_t type() const noexcept {return type_;} + value_t type() const noexcept + { + this->set_accessed(); + return type_; + } // }}} From 8ec9257f2647c1f9dcc1dee949d630888973ad08 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 30 Jan 2025 00:13:26 +0900 Subject: [PATCH 04/10] feat: enable to unset flag --- include/toml11/value.hpp | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/include/toml11/value.hpp b/include/toml11/value.hpp index 3c4729d..9d54648 100644 --- a/include/toml11/value.hpp +++ b/include/toml11/value.hpp @@ -59,6 +59,11 @@ void change_region_of_value(basic_value&, const basic_value&); template struct getter; + +#ifdef TOML11_ENABLE_ACCESS_CHECK +template +void unset_access_flag(basic_value&); +#endif } // detail template @@ -2102,6 +2107,12 @@ class basic_value template friend class basic_value; + +#ifdef TOML11_ENABLE_ACCESS_CHECK + template + friend void detail::unset_access_flag(basic_value&); +#endif + // }}} private: @@ -2450,6 +2461,48 @@ void change_region_of_value(basic_value& dst, const basic_value& src) return; } +#ifdef TOML11_ENABLE_ACCESS_CHECK +template +void unset_access_flag(basic_value& v) +{ + v.accessed_.store(false); +} + +template +void unset_access_flag_recursively(basic_value& v) +{ + switch(v.type()) + { + case value_t::empty : { return unset_access_flag(v); } + case value_t::boolean : { return unset_access_flag(v); } + case value_t::integer : { return unset_access_flag(v); } + case value_t::floating : { return unset_access_flag(v); } + case value_t::string : { return unset_access_flag(v); } + case value_t::offset_datetime : { return unset_access_flag(v); } + case value_t::local_datetime : { return unset_access_flag(v); } + case value_t::local_date : { return unset_access_flag(v); } + case value_t::local_time : { return unset_access_flag(v); } + case value_t::array: + { + for(auto& elem : v.as_array()) + { + unset_access_flag_recursively(elem); + } + return unset_access_flag(v); + } + case value_t::table: + { + for(auto& kv : v.as_table()) + { + unset_access_flag_recursively(kv.second); + } + return unset_access_flag(v); + } + default: { return unset_access_flag(v); } + } +} +#endif + } // namespace detail } // namespace toml #endif // TOML11_VALUE_HPP From d2b66ba2e38abc693e5f1b81958c22917314d682 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 30 Jan 2025 00:26:53 +0900 Subject: [PATCH 05/10] feat: unset access flag before returning --- include/toml11/parser.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/toml11/parser.hpp b/include/toml11/parser.hpp index 3915650..5a8e939 100644 --- a/include/toml11/parser.hpp +++ b/include/toml11/parser.hpp @@ -3426,6 +3426,11 @@ parse_file(location& loc, context& ctx) { return err(std::move(ctx.errors())); } + +#ifdef TOML11_ENABLE_ACCESS_CHECK + detail::unset_access_flag_recursively(root); +#endif + return ok(std::move(root)); } From 46f009d25e33f983bbbf65a9ff29f3218b193dcd Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 30 Jan 2025 00:27:13 +0900 Subject: [PATCH 06/10] feat: add test_accessed --- tests/CMakeLists.txt | 1 + tests/test_accessed.cpp | 72 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 tests/test_accessed.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5e323bf..50e086c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -39,6 +39,7 @@ set(TOML11_TEST_NAMES test_utility test_user_defined_conversion test_value + test_accessed test_visit ) diff --git a/tests/test_accessed.cpp b/tests/test_accessed.cpp new file mode 100644 index 0000000..68d48ee --- /dev/null +++ b/tests/test_accessed.cpp @@ -0,0 +1,72 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest.h" + +#include + +TEST_CASE("testing toml::parse(file)") +{ + using namespace toml::literals::toml_literals; + + const std::string spec_example(R"(# This is a TOML document + +title = "TOML Example" + +[owner] +name = "Tom Preston-Werner" +dob = 1979-05-27T07:32:00-08:00 + +[database] +enabled = true +ports = [ 8000, 8001, 8002 ] +data = [ ["delta", "phi"], [3.14] ] +temp_targets = { cpu = 79.5, case = 72.0 } + +[servers] + +[servers.alpha] +ip = "10.0.0.1" +role = "frontend" + +[servers.beta] +ip = "10.0.0.2" +role = "backend" +)"); + + const auto u = toml::parse_str(spec_example); + + CHECK_EQ(u.at("title").as_string(), "TOML Example"); + CHECK_EQ(u.at("owner").at("name").as_string(), "Tom Preston-Werner"); + + CHECK_EQ(u.at("database").at("ports").at(0).as_integer(), 8000); + CHECK_EQ(u.at("database").at("ports").at(1).as_integer(), 8001); + CHECK_EQ(u.at("database").at("data").at(0).at(1).as_string(), "phi"); + + CHECK_EQ(u.at("servers").at("alpha").at("ip" ).as_string(), "10.0.0.1"); + CHECK_EQ(u.at("servers").at("alpha").at("role").as_string(), "frontend"); + + CHECK_UNARY(u.accessed()); + CHECK_UNARY(u.at("title").accessed()); + CHECK_UNARY(u.at("owner").accessed()); + CHECK_UNARY(u.at("owner").at("name").accessed()); + CHECK_UNARY(u.at("servers").accessed()); + CHECK_UNARY(u.at("servers").at("alpha").accessed()); + CHECK_UNARY(u.at("servers").at("alpha").at("ip").accessed()); + CHECK_UNARY(u.at("servers").at("alpha").at("role").accessed()); + CHECK_UNARY(u.at("database").accessed()); + CHECK_UNARY(u.at("database").at("ports").accessed()); + CHECK_UNARY(u.at("database").at("ports").at(0).accessed()); + CHECK_UNARY(u.at("database").at("ports").at(1).accessed()); + + CHECK_UNARY_FALSE(u.at("owner").at("dob").accessed()); + CHECK_UNARY_FALSE(u.at("servers").at("beta").accessed()); + CHECK_UNARY_FALSE(u.at("servers").at("beta").at("ip").accessed()); + CHECK_UNARY_FALSE(u.at("servers").at("beta").at("role").accessed()); + + CHECK_UNARY_FALSE(u.at("database").at("enabled").accessed()); + CHECK_UNARY_FALSE(u.at("database").at("ports").at(2).accessed()); + CHECK_UNARY_FALSE(u.at("database").at("data").at(0).at(0).accessed()); + CHECK_UNARY_FALSE(u.at("database").at("data").at(1).at(0).accessed()); + CHECK_UNARY_FALSE(u.at("database").at("temp_targets").accessed()); + CHECK_UNARY_FALSE(u.at("database").at("temp_targets").at("cpu" ).accessed()); + CHECK_UNARY_FALSE(u.at("database").at("temp_targets").at("case").accessed()); +} From 942eadef5c7cf0211e1f48806b9ed6dcc362af14 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 30 Jan 2025 00:35:36 +0900 Subject: [PATCH 07/10] fix: guard access check funcs by macro --- include/toml11/value.hpp | 2 ++ tests/test_accessed.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/toml11/value.hpp b/include/toml11/value.hpp index 9d54648..7053f35 100644 --- a/include/toml11/value.hpp +++ b/include/toml11/value.hpp @@ -2042,7 +2042,9 @@ class basic_value comment_type const& comments() const noexcept {return this->comments_;} comment_type& comments() noexcept {return this->comments_;} +#ifdef TOML11_ENABLE_ACCESS_CHECK bool accessed() const {return this->accessed_.load();} +#endif private: diff --git a/tests/test_accessed.cpp b/tests/test_accessed.cpp index 68d48ee..c983e43 100644 --- a/tests/test_accessed.cpp +++ b/tests/test_accessed.cpp @@ -3,6 +3,8 @@ #include +#ifdef TOML11_ENABLE_ACCESS_CHECK + TEST_CASE("testing toml::parse(file)") { using namespace toml::literals::toml_literals; @@ -70,3 +72,5 @@ role = "backend" CHECK_UNARY_FALSE(u.at("database").at("temp_targets").at("cpu" ).accessed()); CHECK_UNARY_FALSE(u.at("database").at("temp_targets").at("case").accessed()); } + +#endif // TOML11_ENABLE_ACCESS_CHECK From 067b46d8f595ec9fcbf8a97d9a2757f4c0a9cff8 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 30 Jan 2025 00:39:30 +0900 Subject: [PATCH 08/10] ci: add on/off to TOML11_ENABLE_ACCESS_CHECK --- .github/workflows/main.yml | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 555b26d..862a0c0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,6 +10,7 @@ jobs: compiler: ['g++-12', 'g++-11', 'g++-10', 'g++-9'] standard: ['11', '14', '17', '20'] precompile: ['ON', 'OFF'] + betafeature: ['ON', 'OFF'] steps: - name: Get number of CPU cores uses: SimenB/github-actions-cpu-cores@v2 @@ -25,7 +26,7 @@ jobs: sudo apt-get install ${{ matrix.compiler }} - name: Configure run: | - cmake -B build/ -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} + cmake -B build/ -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} -DTOML11_ENABLE_ACCESS_CHECK=${{ matrix.betafeature }} - name: Build run: | cmake --build build/ -j${{ steps.cpu-cores.outputs.count }} @@ -39,6 +40,7 @@ jobs: compiler: ['15', '14', '13', '12', '11'] standard: ['11', '14', '17', '20'] precompile: ['ON', 'OFF'] + betafeature: ['ON', 'OFF'] exclude: - {compiler: '14', standard: '20'} # to avoid using gcc-13 libstdc++ - {compiler: '13', standard: '20'} # with older clang @@ -59,7 +61,7 @@ jobs: sudo apt-get install clang-${{ matrix.compiler }} - name: Configure run: | - cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} + cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} -DTOML11_ENABLE_ACCESS_CHECK=${{ matrix.betafeature }} - name: Build run: | cmake --build build/ -j${{ steps.cpu-cores.outputs.count }} @@ -73,6 +75,7 @@ jobs: compiler: ['g++-8', 'g++-7'] standard: ['11', '14', '17', '20'] precompile: ['ON', 'OFF'] + betafeature: ['ON', 'OFF'] exclude: - {compiler: 'g++-7', standard: '20'} - {compiler: 'g++-8', standard: '17'} @@ -92,7 +95,7 @@ jobs: sudo apt-get install ${{ matrix.compiler }} - name: Configure run: | - cmake -B build/ -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} + cmake -B build/ -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} -DTOML11_ENABLE_ACCESS_CHECK=${{ matrix.betafeature }} - name: Build run: | cmake --build build/ -j${{ steps.cpu-cores.outputs.count }} @@ -107,6 +110,7 @@ jobs: compiler: ['10', '9', '8', '7', '6.0'] standard: ['11', '14', '17', '20'] precompile: ['ON', 'OFF'] + betafeature: ['ON', 'OFF'] exclude: - {compiler: '6.0', standard: '20'} - {compiler: '7', standard: '20'} @@ -127,7 +131,7 @@ jobs: sudo apt-get install clang-${{ matrix.compiler }} - name: Configure run: | - cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} + cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} -DTOML11_ENABLE_ACCESS_CHECK=${{ matrix.betafeature }} - name: Build run: | cmake --build build/ -j${{ steps.cpu-cores.outputs.count }} @@ -141,6 +145,7 @@ jobs: matrix: standard: ['11', '14', '17', '20'] precompile: ['ON', 'OFF'] + betafeature: ['ON', 'OFF'] steps: - name: Get number of CPU cores uses: SimenB/github-actions-cpu-cores@v2 @@ -151,7 +156,7 @@ jobs: submodules: true - name: Configure run: | - cmake -B build/ -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} + cmake -B build/ -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} -DTOML11_ENABLE_ACCESS_CHECK=${{ matrix.betafeature }} - name: Build run: | cmake --build build/ -j${{ steps.cpu-cores.outputs.count }} @@ -165,6 +170,7 @@ jobs: matrix: standard: ['11', '14', '17', '20'] precompile: ['ON', 'OFF'] + betafeature: ['ON', 'OFF'] steps: - name: Get number of CPU cores uses: SimenB/github-actions-cpu-cores@v2 @@ -175,7 +181,7 @@ jobs: submodules: true - name: Configure run: | - cmake -B build/ -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} + cmake -B build/ -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} -DTOML11_ENABLE_ACCESS_CHECK=${{ matrix.betafeature }} - name: Build run: | cmake --build build/ -j${{ steps.cpu-cores.outputs.count }} @@ -190,6 +196,7 @@ jobs: standard: ['11', '14', '17', '20'] config: ['Release', 'Debug'] precompile: ['ON', 'OFF'] + betafeature: ['ON', 'OFF'] steps: - name: Get number of CPU cores uses: SimenB/github-actions-cpu-cores@v2 @@ -202,7 +209,7 @@ jobs: - name: Configure shell: cmd run: | - cmake -B build/ -G "NMake Makefiles" -DTOML11_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_PRECOMPILE=${{ matrix.precompile }} + cmake -B build/ -G "NMake Makefiles" -DTOML11_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_PRECOMPILE=${{ matrix.precompile }} -DTOML11_ENABLE_ACCESS_CHECK=${{ matrix.betafeature }} - name: Build run: | cmake --build ./build --config "${{ matrix.config }}" -j${{ steps.cpu-cores.outputs.count }} From a1dd0bb6777055bbb775ad070baa219e9f6ae431 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 2 Feb 2025 14:05:46 +0900 Subject: [PATCH 09/10] doc: add accessed() --- docs/content.en/docs/features/value.md | 73 ++++++++++++++++++++++++++ docs/content.ja/docs/features/value.md | 68 ++++++++++++++++++++++++ 2 files changed, 141 insertions(+) diff --git a/docs/content.en/docs/features/value.md b/docs/content.en/docs/features/value.md index 3107688..51fb37b 100644 --- a/docs/content.en/docs/features/value.md +++ b/docs/content.en/docs/features/value.md @@ -834,3 +834,76 @@ struct bar } }; ``` + +# Checking Whether a Value Has Been Accessed + +{{% hint warning %}} + +This feature is not enabled by default. To use it, you need to define `TOML11_ENABLE_ACCESS_CHECK`. +Additionally, since this feature introduces extra processing on parsed values, it may impact runtime performance. + +{{% /hint %}} + +When compiled with the `TOML11_ENABLE_ACCESS_CHECK` macro defined, the `toml::value` class gains an additional method: `bool accessed() const`. +This allows you to check whether a value has been accessed after parsing. + +```console +$ g++ -std=c++17 -O2 -DTOML11_ENABLE_ACCESS_CHECK -I/path/to/toml11/include main.cpp +``` + +or + +```console +$ cmake -B ./build -DTOML11_ENABLE_ACCESS_CHECK=ON +``` + +or + +```cmake +CPMAddPackage( + NAME toml11 + GITHUB_REPOSITORY "ToruNiina/toml11" + VERSION 4.4.0 + OPTIONS "CMAKE_CXX_STANDARD 17" "TOML11_PRECOMPILE ON" "TOML11_ENABLE_ACCESS_CHECK ON" + ) +``` + +This feature allows users to implement code that warns about values defined in a table but never used. + +```cpp +#include + +namespace yours +{ + +Config read_config(const toml::value& input) +{ + const auto cfg = read_your_config(input); + + for (const auto& [k, v] : input.as_table()) + { + if (!v.accessed()) + { + std::cerr << toml::format_error("value defined but not used", + v.source_location(), "not used"); + } + } + return cfg; +} +} // namespace yours +``` + +This feature is useful when a value is mistakenly defined under the wrong name but is never accessed. For example: + +```toml +# The correct key is "reactions" +# reactions = [ ":+1:", "star" ] + +# This key is incorrect and will not be read +reaction = [ ":+1:", "star" ] +``` + +If this file is read using the above code, `read_your_config` will search for `reactions`. Since it is not defined, it will process `reactions` as an empty array. +In this case, `input.at("reaction").accessed()` will be `false`, allowing it to be detected as an error. + + diff --git a/docs/content.ja/docs/features/value.md b/docs/content.ja/docs/features/value.md index 950efcf..771dadd 100644 --- a/docs/content.ja/docs/features/value.md +++ b/docs/content.ja/docs/features/value.md @@ -863,3 +863,71 @@ struct bar } }; ``` + +# 値がアクセス済みかどうかチェックする + +{{% hint warning %}} + +この機能はデフォルトでは有効化されず、使用する際には`TOML11_ENABLE_ACCESS_CHECK`を定義する必要があります。 +また、この機能はパースした値に対して追加の処理を行うため、実行時パフォーマンスが低下する可能性があります。 + +{{% /hint %}} + +`TOML11_ENABLE_ACCESS_CHECK`マクロを定義してコンパイルすると、`toml::value`に`bool accessed() const`メソッドが追加され、パース後にその値にアクセスしたかどうかが確認できるようになります。 + +```console +$ g++ -std=c++17 -O2 -DTOML11_ENABLE_ACCESS_CHECK -I/path/to/toml11/include main.cpp +``` + +```console +$ cmake -B ./build -DTOML11_ENABLE_ACCESS_CHECK=ON +``` + +```cmake +CPMAddPackage( + NAME toml11 + GITHUB_REPOSITORY "ToruNiina/toml11" + VERSION 4.4.0 + OPTIONS "CMAKE_CXX_STANDARD 17" "TOML11_PRECOMPILE ON" "TOML11_ENABLE_ACCESS_CHECK ON" + ) +``` + +この機能によって、テーブル内に定義されているものの使用されなかった値についての警告を表示することが可能になります。 + +```cpp +#include + +namespace yours +{ + +Config read_config(const toml::value& v) +{ + const auto cfg = read_your_config(input); + + for(const auto& [k, v] : input.as_table()) + { + if( ! v.accessed()) + { + std::cerr << toml::format_error("value defined but not used", + v.source_location(), "not used"); + } + } + return cfg; +} +} // yours +``` + +この機能は、必要な場合のみ定義されるような値を、名称を間違えて定義してしまった際に役に立つでしょう。 +例えば、 + +```toml +# 正しくは reactions +# reactions = [ ":+1:", "star" ] + +# 名前が違うので読み込めない +reaction = [ ":+1:", "star" ] +``` + +このファイルを上記のコードで読んだ場合、`read_your_config`は`reactions`を探し、定義されていなかったので空の配列として処理するでしょう。 +その場合、`reaction`は`accessed()`が`true`にならないため、エラーとして検出できます。 + From 8043503961e75ae8802fb770fe9d82dad11a143c Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 2 Feb 2025 15:11:57 +0900 Subject: [PATCH 10/10] ci: run access-check only in the latest env --- .github/workflows/main.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 862a0c0..ef97e88 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,7 +40,6 @@ jobs: compiler: ['15', '14', '13', '12', '11'] standard: ['11', '14', '17', '20'] precompile: ['ON', 'OFF'] - betafeature: ['ON', 'OFF'] exclude: - {compiler: '14', standard: '20'} # to avoid using gcc-13 libstdc++ - {compiler: '13', standard: '20'} # with older clang @@ -61,7 +60,7 @@ jobs: sudo apt-get install clang-${{ matrix.compiler }} - name: Configure run: | - cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} -DTOML11_ENABLE_ACCESS_CHECK=${{ matrix.betafeature }} + cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} - name: Build run: | cmake --build build/ -j${{ steps.cpu-cores.outputs.count }} @@ -75,7 +74,6 @@ jobs: compiler: ['g++-8', 'g++-7'] standard: ['11', '14', '17', '20'] precompile: ['ON', 'OFF'] - betafeature: ['ON', 'OFF'] exclude: - {compiler: 'g++-7', standard: '20'} - {compiler: 'g++-8', standard: '17'} @@ -95,7 +93,7 @@ jobs: sudo apt-get install ${{ matrix.compiler }} - name: Configure run: | - cmake -B build/ -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} -DTOML11_ENABLE_ACCESS_CHECK=${{ matrix.betafeature }} + cmake -B build/ -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} - name: Build run: | cmake --build build/ -j${{ steps.cpu-cores.outputs.count }} @@ -110,7 +108,6 @@ jobs: compiler: ['10', '9', '8', '7', '6.0'] standard: ['11', '14', '17', '20'] precompile: ['ON', 'OFF'] - betafeature: ['ON', 'OFF'] exclude: - {compiler: '6.0', standard: '20'} - {compiler: '7', standard: '20'} @@ -131,7 +128,7 @@ jobs: sudo apt-get install clang-${{ matrix.compiler }} - name: Configure run: | - cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} -DTOML11_ENABLE_ACCESS_CHECK=${{ matrix.betafeature }} + cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} - name: Build run: | cmake --build build/ -j${{ steps.cpu-cores.outputs.count }} @@ -170,7 +167,6 @@ jobs: matrix: standard: ['11', '14', '17', '20'] precompile: ['ON', 'OFF'] - betafeature: ['ON', 'OFF'] steps: - name: Get number of CPU cores uses: SimenB/github-actions-cpu-cores@v2 @@ -181,7 +177,7 @@ jobs: submodules: true - name: Configure run: | - cmake -B build/ -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} -DTOML11_ENABLE_ACCESS_CHECK=${{ matrix.betafeature }} + cmake -B build/ -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }} - name: Build run: | cmake --build build/ -j${{ steps.cpu-cores.outputs.count }}