feat: Merge branch 'access-check'

This commit is contained in:
ToruNiina
2025-02-02 23:02:17 +09:00
9 changed files with 515 additions and 29 deletions

View File

@@ -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 }}
@@ -141,6 +142,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 +153,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 +192,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 +205,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 }}

View File

@@ -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)

View File

@@ -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 <toml.hpp>
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.

View File

@@ -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 <toml.hpp>
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`にならないため、エラーとして検出できます。

View File

@@ -3426,6 +3426,11 @@ parse_file(location& loc, context<TC>& ctx)
{
return err(std::move(ctx.errors()));
}
#ifdef TOML11_ENABLE_ACCESS_CHECK
detail::unset_access_flag_recursively(root);
#endif
return ok(std::move(root));
}

View File

@@ -17,6 +17,10 @@
#include <string_view>
#endif
#ifdef TOML11_ENABLE_ACCESS_CHECK
#include <atomic>
#endif
#include <cassert>
namespace toml
@@ -55,6 +59,11 @@ void change_region_of_value(basic_value<TC>&, const basic_value<TC>&);
template<typename TC, value_t V>
struct getter;
#ifdef TOML11_ENABLE_ACCESS_CHECK
template<typename TC>
void unset_access_flag(basic_value<TC>&);
#endif
} // detail
template<typename TypeConfig>
@@ -86,6 +95,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 +105,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 +127,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 +155,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 +182,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 +208,9 @@ class basic_value
basic_value(basic_value v, std::vector<std::string> 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 +236,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 +284,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 +333,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 +396,9 @@ class basic_value
std::vector<std::string> 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 +410,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 +436,9 @@ class basic_value
basic_value(integer_type x, integer_format_info fmt, std::vector<std::string> 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 +450,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 +488,9 @@ class basic_value
basic_value(T x, integer_format_info fmt, std::vector<std::string> 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<typename T, enable_if_integer_like_t<T> = nullptr>
basic_value& operator=(T x)
@@ -451,6 +503,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 +529,9 @@ class basic_value
basic_value(floating_type x, floating_format_info fmt, std::vector<std::string> 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 +543,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 +584,9 @@ class basic_value
basic_value(T x, floating_format_info fmt, std::vector<std::string> 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<typename T, enable_if_floating_like_t<T> = nullptr>
@@ -536,6 +600,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 +627,9 @@ class basic_value
std::vector<std::string> 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 +641,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 +666,9 @@ class basic_value
std::vector<std::string> 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 +680,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 +707,9 @@ class basic_value
std::vector<std::string> 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 +721,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 +767,9 @@ class basic_value
: type_(value_t::string),
string_(string_storage(detail::string_conv<string_type>(x), std::move(fmt))),
region_(std::move(reg)), comments_(std::move(com))
#ifdef TOML11_ENABLE_ACCESS_CHECK
, accessed_{false}
#endif
{}
template<typename T, cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,
@@ -697,6 +785,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<string_type>(x), std::move(fmt)));
return *this;
}
@@ -721,6 +812,9 @@ class basic_value
std::vector<std::string> 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 +826,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 +853,9 @@ class basic_value
std::vector<std::string> 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 +867,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 +907,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 +934,9 @@ class basic_value
std::vector<std::string> 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 +948,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 +975,9 @@ class basic_value
std::vector<std::string> 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 +989,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 +1024,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 +1052,9 @@ class basic_value
: type_(value_t::array), array_(array_storage(
detail::storage<array_type>(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 +1066,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<array_type>(std::move(x)), std::move(fmt)));
return *this;
@@ -988,6 +1115,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<typename T, enable_if_array_like_t<T> = nullptr>
basic_value& operator=(T x)
@@ -1000,7 +1130,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 +1161,9 @@ class basic_value
: type_(value_t::table), table_(table_storage(
detail::storage<table_type>(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 +1175,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<table_type>(std::move(x)), std::move(fmt)));
return *this;
@@ -1084,6 +1222,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<typename T, enable_if_table_like_t<T> = nullptr>
basic_value& operator=(T x)
@@ -1096,7 +1237,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 +1269,9 @@ class basic_value
basic_value& operator=(const T& ud)
{
*this = into<cxx::remove_cvref_t<T>>::template into_toml<config_type>(ud);
#ifdef TOML11_ENABLE_ACCESS_CHECK
this->accessed_ = false;
#endif
return *this;
}
@@ -1149,6 +1295,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 +1321,9 @@ class basic_value
basic_value& operator=(const T& ud)
{
*this = ud.template into_toml<TypeConfig>();
#ifdef TOML11_ENABLE_ACCESS_CHECK
this->accessed_ = false;
#endif
return *this;
}
// }}}
@@ -1181,6 +1333,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
{}
// }}}
@@ -1192,9 +1347,13 @@ class basic_value
std::nullptr_t> = nullptr>
bool is() const noexcept
{
return detail::type_to_enum<T, value_type>::value == this->type_;
return this->is(detail::type_to_enum<T, value_type>::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 );}
@@ -1210,6 +1369,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.
@@ -1229,7 +1389,11 @@ class basic_value
return true;
}
value_t type() const noexcept {return type_;}
value_t type() const noexcept
{
this->set_accessed();
return type_;
}
// }}}
@@ -1239,36 +1403,38 @@ class basic_value
detail::enum_to_type_t<T, basic_value<config_type>> const&
as(const std::nothrow_t&) const noexcept
{
this->set_accessed();
return detail::getter<config_type, T>::get_nothrow(*this);
}
template<value_t T>
detail::enum_to_type_t<T, basic_value<config_type>>&
as(const std::nothrow_t&) noexcept
{
this->set_accessed();
return detail::getter<config_type, T>::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 +1457,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 +1466,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 +1475,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 +1484,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 +1493,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 +1502,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 +1511,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 +1520,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 +1529,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 +1538,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 +1551,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 +1560,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 +1569,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 +1578,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 +1587,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 +1596,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 +1605,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 +1614,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 +1623,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 +1632,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 +2042,22 @@ 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:
// 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 +2074,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;
}
@@ -1908,6 +2109,12 @@ class basic_value
template<typename TC>
friend class basic_value;
#ifdef TOML11_ENABLE_ACCESS_CHECK
template<typename TC>
friend void detail::unset_access_flag(basic_value<TC>&);
#endif
// }}}
private:
@@ -1942,6 +2149,10 @@ class basic_value
};
region_type region_;
comment_type comments_;
#ifdef TOML11_ENABLE_ACCESS_CHECK
mutable std::atomic<bool> accessed_;
#endif
};
template<typename TC>
@@ -2252,6 +2463,48 @@ void change_region_of_value(basic_value<TC>& dst, const basic_value<TC>& src)
return;
}
#ifdef TOML11_ENABLE_ACCESS_CHECK
template<typename TC>
void unset_access_flag(basic_value<TC>& v)
{
v.accessed_.store(false);
}
template<typename TC>
void unset_access_flag_recursively(basic_value<TC>& 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

View File

@@ -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
$<$<BOOL:${TOML11_ENABLE_ACCESS_CHECK}>: -DTOML11_ENABLE_ACCESS_CHECK>
)
target_include_directories(toml11 PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
@@ -127,6 +130,9 @@ if(TOML11_PRECOMPILE)
endif()
else()
add_library(toml11 INTERFACE)
target_compile_definitions(toml11 INTERFACE
$<$<BOOL:${TOML11_ENABLE_ACCESS_CHECK}>: -DTOML11_ENABLE_ACCESS_CHECK>
)
target_include_directories(toml11 INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>

View File

@@ -39,6 +39,7 @@ set(TOML11_TEST_NAMES
test_utility
test_user_defined_conversion
test_value
test_accessed
test_visit
)

76
tests/test_accessed.cpp Normal file
View File

@@ -0,0 +1,76 @@
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
#include <toml.hpp>
#ifdef TOML11_ENABLE_ACCESS_CHECK
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());
}
#endif // TOML11_ENABLE_ACCESS_CHECK