added insertion operations for tables and arrays

also:
- fixed column numbers being wrong when a value ended at EOF
- fixed some `print_to_stream` overloads for `char8_t`
- fixed a minor preprocessor snafu on MSVC
- fixed '\' not being escaped when printing string values
- added an initializer list constructor for tables
- added `array::flatten`
- added `table::find`
- added `table::is_inline` setter
- added `TOML_SMALL_INT_TYPE`
- added `parse_file`
- added stream operator for source_region
- added proper license notice for the utf8 decoder
- added lots more documentation and tests
This commit is contained in:
Mark Gillard 2020-02-03 11:12:43 +02:00
parent c4f30c2ffa
commit c7483cb92c
54 changed files with 3507 additions and 518 deletions

View File

@ -14,3 +14,5 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SPDX-License-Identifier: MIT

14
LICENSE-utf8-decoder Normal file
View File

@ -0,0 +1,14 @@
Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,5 +1,5 @@
# toml++ (tomlplusplus)
![c++version](https://img.shields.io/badge/c%2B%2B-17%2C%2020-informational)
[![c++version](https://img.shields.io/badge/c%2B%2B-17%2C%2020-informational)][cpp_compilers]
[![tomlversion](https://img.shields.io/badge/TOML-v0.5.0-informational)][v0.5.0]
[![CircleCI](https://circleci.com/gh/marzer/tomlplusplus.svg?style=shield)](https://circleci.com/gh/marzer/tomlplusplus)
[![GitHub](https://img.shields.io/github/license/marzer/tomlplusplus)](https://github.com/marzer/tomlplusplus/blob/master/LICENSE)
@ -10,11 +10,32 @@
# Example
```cpp
/// example goes here.
Given a TOML file `configuration.toml` containing the following:
```toml
[library]
name = "toml++"
version = "0.1.0"
authors = ["Mark Gillard <mark@notarealwebsite.com>"]
[dependencies]
cpp = 17
```
You'll find some more code examples in
`examples` directory and plenty more as part of the [API documentation].
Reading it in C++ is easy with `toml++`:
```cpp
auto config = toml::parse_file( "configuration.toml" );
// get key-value pairs
std::string_view library_name = config["library"]["name"].as_string()->get();
std::string_view library_version = config["library"]["version"].as_string()->get();
std::string_view library_author = config["library"]["authors"][0].as_string()->get();
int64_t depends_on_cpp_version = config["dependencies"]["cpp"].as_integer()->get();
// re-serialize as JSON
std::cout << toml::json_formatter{ config } << std::endl;
```
You'll find some more code examples in the `examples` directory, and plenty more as part of the [API documentation].
<br>
@ -32,9 +53,8 @@ You'll find some more code examples in
The API is the same regardless of how you consume the library.
### Configuration
A number of configurable options are exposed in the form of preprocessor macros. Most likely you
won't need to mess with these at all, but in the event you do, set your overrides prior to including
toml++.
A number of configurable options are exposed in the form of preprocessor `#defines`. Most likely you
won't need to mess with these at all, butif you do, set them before including toml++.
| Option | Type | Default | Description |
|----------------------------|:--------------:|-----------------------------------|----------------------------------------------------------------------------------------------------------|
@ -43,6 +63,7 @@ toml++.
| `TOML_CONFIG_HEADER` | string literal | undefined | Includes the given header file before the rest of the library. |
| `TOML_LARGE_FILES` | boolean | `0` | Uses 32-bit integers for line and column indices (instead of 16-bit). |
| `TOML_SMALL_FLOAT_TYPE` | type name | undefined | If your codebase has an additional 'small' float type (e.g. half-precision), this tells toml++ about it. |
| `TOML_SMALL_INT_TYPE` | type name | undefined | If your codebase has an additional 'small' integer type (e.g. 24-bits), this tells toml++ about it. |
| `TOML_UNDEF_MACROS` | boolean | `1` | `#undefs` the library's internal macros at the end of the header. |
| `TOML_UNRELEASED_FEATURES` | boolean | `1` | Enables support for [unreleased TOML language features] not yet part of a [numbered version]. |
@ -72,7 +93,7 @@ _These can be disabled (and thus strict [TOML v0.5.0] compliance enforced) by sp
`TOML_UNRELEASED_FEATURES = 0` (see [Configuration](#Configuration))._
### **🔹TOML v0.5.0 and earlier:**
- All features as of `<< release date >>`.
- All features supported.
<br>
@ -104,7 +125,7 @@ Install [Visual Studio 2019] and [Test Adapter for Catch2], then open `vs/toml++
projects in the `tests` solution folder. Visual Studio's Test Explorer should pick these up and
allow you to run the tests directly.
If test discovery fails, you can usually fix it by clicking enabling
If test discovery fails you can usually fix it by clicking enabling
`Auto Detect runsettings Files` (settings gear icon > `Configure Run Settings`).
#### Linux
@ -120,12 +141,10 @@ cd ../build-clang && ninja && ninja test
# License and Attribution
`toml++` is licensed under the terms of the MIT license - See [LICENSE].
`toml++` is licensed under the terms of the MIT license - see [LICENSE].
UTF-8 decoding is performed using a state machine based on Bjoern Hoehrmann's '[Flexible and Economical UTF-8 Decoder]',
which is itself subject to the terms of (what appears to be) the MIT license. The license text is included in the
[relevant part](https://github.com/marzer/tomlplusplus/blob/master/include/toml%2B%2B/toml_utf8.h)
of the toml++ source.
which is also subject to the terms of the MIT license - see [LICENSE-utf8-decoder].
[API documentation]: https://marzer.github.io/tomlplusplus/namespacetoml.html
[unreleased TOML language features]: https://github.com/marzer/tomlplusplus#unreleased-features
@ -142,6 +161,7 @@ of the toml++ source.
[Catch2]: https://github.com/catchorg/Catch2
[Test Adapter for Catch2]: https://marketplace.visualstudio.com/items?itemName=JohnnyHendriks.ext01
[Visual Studio 2019]: https://visualstudio.microsoft.com/vs/
[cpp_compilers]: https://en.cppreference.com/w/cpp/compiler_support
[#356]: https://github.com/toml-lang/toml/issues/356
[#516]: https://github.com/toml-lang/toml/issues/516
[#562]: https://github.com/toml-lang/toml/issues/562
@ -152,3 +172,4 @@ of the toml++ source.
[#665]: https://github.com/toml-lang/toml/issues/665
[#671]: https://github.com/toml-lang/toml/issues/671
[#687]: https://github.com/toml-lang/toml/issues/687
[LICENSE-utf8-decoder]: https://github.com/marzer/tomlplusplus/blob/master/LICENSE-utf8-decoder

View File

@ -41,7 +41,6 @@ SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES = "cpp=@code{.cpp}" \
"ecpp=@endcode" \
"epp=@endcode" \
"detail=@details"
TCL_SUBST =
OPTIMIZE_OUTPUT_FOR_C = NO
@ -336,7 +335,8 @@ INCLUDE_FILE_PATTERNS =
PREDEFINED = TOML_DOXYGEN=1 \
__cplusplus=201703L \
TOML_ALWAYS_INLINE=inline \
TOML_MAY_THROW=
TOML_MAY_THROW= \
TOML_NODISCARD_CTOR=
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = NO
#---------------------------------------------------------------------------

View File

@ -11,9 +11,8 @@ HTML_EXTRA_FILES = tomlplusplus.js
SHOW_INCLUDE_FILES = NO
##! M_THEME_COLOR = #22272e
##! M_LINKS_NAVBAR1 = \
##! pages
##! namespaces
##! M_LINKS_NAVBAR2 = \
##! namespaces \
##! annotated \
##! "<a target="_blank" href="https://github.com/marzer/tomlplusplus/">Github</a>"
##! M_SEARCH_DOWNLOAD_BINARY = NO

View File

@ -205,3 +205,9 @@ nav .m-thin {
.m-code .p {
color: rgb(120,120,120);
}
.m-doc-details div table.m-table.m-fullwidth.m-flat thead tr th,
.m-doc-details div table.m-table.m-fullwidth.m-flat tfoot tr th
{
color: #a5c9ea;
}

View File

@ -27,7 +27,10 @@ namespace toml::impl
public:
using reference = std::conditional_t<is_const, const node&, node&>;
using value_type = std::conditional_t<is_const, const node, node>;
using reference = value_type&;
using pointer = value_type*;
using difference_type = ptrdiff_t;
array_iterator() noexcept = default;
@ -58,11 +61,53 @@ namespace toml::impl
}
[[nodiscard]]
reference operator* () const noexcept
reference operator * () const noexcept
{
return *raw_->get();
}
[[nodiscard]]
pointer operator -> () const noexcept
{
return raw_->get();
}
array_iterator& operator += (ptrdiff_t rhs) noexcept
{
raw_ += rhs;
return *this;
}
array_iterator& operator -= (ptrdiff_t rhs) noexcept
{
raw_ -= rhs;
return *this;
}
[[nodiscard]]
friend constexpr array_iterator operator + (const array_iterator& lhs, ptrdiff_t rhs) noexcept
{
return { lhs.raw_ + rhs };
}
[[nodiscard]]
friend constexpr array_iterator operator + (ptrdiff_t lhs, const array_iterator& rhs) noexcept
{
return { rhs.raw_ + lhs };
}
[[nodiscard]]
friend constexpr array_iterator operator - (const array_iterator& lhs, ptrdiff_t rhs) noexcept
{
return { lhs.raw_ - rhs };
}
[[nodiscard]]
friend constexpr ptrdiff_t operator - (const array_iterator& lhs, const array_iterator& rhs) noexcept
{
return lhs.raw_ - rhs.raw_;
}
[[nodiscard]]
friend constexpr bool operator == (const array_iterator& lhs, const array_iterator& rhs) noexcept
{
@ -74,7 +119,60 @@ namespace toml::impl
{
return lhs.raw_ != rhs.raw_;
}
[[nodiscard]]
friend constexpr bool operator < (const array_iterator& lhs, const array_iterator& rhs) noexcept
{
return lhs.raw_ < rhs.raw_;
}
[[nodiscard]]
friend constexpr bool operator <= (const array_iterator& lhs, const array_iterator& rhs) noexcept
{
return lhs.raw_ <= rhs.raw_;
}
[[nodiscard]]
friend constexpr bool operator > (const array_iterator& lhs, const array_iterator& rhs) noexcept
{
return lhs.raw_ > rhs.raw_;
}
[[nodiscard]]
friend constexpr bool operator >= (const array_iterator& lhs, const array_iterator& rhs) noexcept
{
return lhs.raw_ >= rhs.raw_;
}
[[nodiscard]]
reference operator[] (ptrdiff_t idx) const noexcept
{
return *(raw_ + idx)->get();
}
};
template <typename T>
[[nodiscard]] TOML_ALWAYS_INLINE
auto make_node(T&& val) noexcept
{
using type = impl::unwrapped<remove_cvref_t<T>>;
if constexpr (is_one_of<type, array, table>)
{
static_assert(
std::is_rvalue_reference_v<decltype(val)>,
"Tables and arrays may only be moved (not copied)."
);
return new type{ std::forward<T>(val) };
}
else
{
static_assert(
is_value_or_promotable<type>,
"Value initializers must be (or be promotable to) one of the TOML value types"
);
return new value{ std::forward<T>(val) };
}
}
}
namespace toml
@ -83,23 +181,43 @@ namespace toml
[[nodiscard]] bool operator != (const table& lhs, const table& rhs) noexcept;
/// \brief A TOML array.
/// \detail The interface of this type is modeled after std::vector so things
/// mostly work as you'd expect them to: \cpp
///
/// auto table = toml::parse("arr = [1, 2, 3, 4, 'five']"sv);
///
/// \remarks The interface of this type is modeled after std::vector, with some
/// additional considerations made for the heterogeneous nature of a
/// TOML array.
///
/// \detail \cpp
///
/// auto table = toml::parse("arr = [1, 2, 3, 4, 'five']"sv);
/// auto& arr = *table.get_as<toml::array>("arr");
/// std::cout << arr << std::endl;
///
/// for (size_t i = 0; i < arr.size(); i++)
/// {
/// arr[i].visit([=](auto&& el) noexcept
/// {
/// std::cout << el << ", ";
/// if constexpr (toml::is_integer<decltype(el)>)
/// el++;
/// else
/// el = "six"sv;
/// });
/// }
/// std::cout << arr << std::endl;
///
/// // prints: 1, 2, 3, 4, "five"
/// arr.push_back(7);
/// arr.push_back(8.0f);
/// arr.push_back("nine"sv);
/// arr.erase(arr.cbegin());
/// std::cout << arr << std::endl;
///
/// arr.emplace_back<toml::array>(10, 11.0);
/// std::cout << arr << std::endl;
///
/// // output:
/// // [1, 2, 3, 4, "five"]
/// // [2, 3, 4, 5, "six"]
/// // [3, 4, 5, "six", 7, 8.0, "nine"]
/// // [3, 4, 5, "six", 7, 8.0, "nine", [10, 11.0]]
/// \ecpp
class array final
: public node
@ -108,6 +226,18 @@ namespace toml
friend class impl::parser;
std::vector<std::unique_ptr<node>> values;
void preinsertion_resize(size_t idx, size_t count) noexcept
{
const auto new_size = values.size() + count;
const auto inserting_at_end = idx == values.size();
values.resize(new_size);
if (!inserting_at_end)
{
for (size_t r = new_size, e = idx + count, l = e; r --> e; l--)
values[r] = std::move(values[l]);
}
}
public:
using value_type = node;
@ -115,18 +245,58 @@ namespace toml
using difference_type = ptrdiff_t;
using reference = node&;
using const_reference = const node&;
/// \brief A RandomAccessIterator for iterating over the nodes in an array.
using iterator = impl::array_iterator<false>;
/// \brief A const RandomAccessIterator for iterating over the nodes in an array.
using const_iterator = impl::array_iterator<true>;
/// \brief Default constructor.
TOML_NODISCARD_CTOR
array() noexcept = default;
/// \brief Move constructor.
TOML_NODISCARD_CTOR
array(array&& other) noexcept
: node{ std::move(other) },
values{ std::move(other.values) }
{}
/// \brief Constructs an array with one or more initial values.
///
/// \detail \cpp
/// auto arr = toml::array{
/// 1,
/// 2.0,
/// "three"sv,
/// toml::array{ 4, 5 }
/// };
/// std::cout << arr << std::endl;
///
/// // output:
/// // [1, 2.0, "three", [4, 5]]
/// \ecpp
///
/// \tparam U One of the TOML node or value types (or a type promotable to one).
/// \tparam V One of the TOML node or value types (or a type promotable to one).
/// \param val The value used to initialize node 0.
/// \param vals The values used to initialize nodes 1...N.
template <typename U, typename... V>
TOML_NODISCARD_CTOR
explicit array(U&& val, V&&... vals) TOML_MAY_THROW
{
values.reserve(sizeof...(V) + 1_sz);
values.emplace_back(impl::make_node(std::forward<U>(val)));
if constexpr (sizeof...(V) > 0)
{
(
values.emplace_back(impl::make_node(std::forward<V>(vals))),
...
);
}
}
/// \brief Move-assignment operator.
array& operator= (array&& rhs) noexcept
{
node::operator=(std::move(rhs));
@ -134,21 +304,44 @@ namespace toml
return *this;
}
/// \brief Always returns `node_type::array` for array nodes.
[[nodiscard]] node_type type() const noexcept override { return node_type::array; }
/// \brief Always returns `false` for array nodes.
[[nodiscard]] bool is_table() const noexcept override { return false; }
/// \brief Always returns `true` for array nodes.
[[nodiscard]] bool is_array() const noexcept override { return true; }
/// \brief Always returns `false` for array nodes.
[[nodiscard]] bool is_value() const noexcept override { return false; }
[[nodiscard]] array* as_array() noexcept override { return this; }
[[nodiscard]] const array* as_array() const noexcept override { return this; }
/// \brief Checks if the array contains values of only one type.
/// \brief Checks if the array contains nodes of only one type.
///
/// \tparam T A TOML node type. Provide an explicit type for "is every element a T?".
/// Leave it as the default `void` for "is every element the same type?".
/// \detail \cpp
/// auto arr = toml::array{
/// 1,
/// 2,
/// 3
/// };
/// std::cout << "homogenous: "sv << arr.is_homogeneous() << std::endl;
/// std::cout << "all doubles: "sv << arr.is_homogeneous<double>() << std::endl;
/// std::cout << "all arrays: "sv << arr.is_homogeneous<toml::array>() << std::endl;
/// std::cout << "all integers: "sv << arr.is_homogeneous<int64_t>() << std::endl;
///
/// // output:
/// // homogeneous: true
/// // all doubles: false
/// // all arrays: false
/// // all integers: true
/// \ecpp
///
/// \tparam T A TOML node type.
/// - Provide an explicit type for "is every node a T?"
/// - Leave it as `void` for "is every node the same type?"
///
/// \returns True if the array was homogeneous.
///
/// \attention Empty arrays are _not_ regarded as homogeneous.
/// \remarks Always returns `false` for empty arrays.
template <typename T = void>
[[nodiscard]] bool is_homogeneous() const noexcept
{
@ -178,88 +371,362 @@ namespace toml
return is_homogeneous<toml::table>();
}
/// \brief Gets a reference to the node element at a specific index.
/// \brief Gets a reference to the node at a specific index.
[[nodiscard]] node& operator[] (size_t index) noexcept { return *values[index]; }
/// \brief Gets a reference to the node element at a specific index.
/// \brief Gets a reference to the node at a specific index.
[[nodiscard]] const node& operator[] (size_t index) const noexcept { return *values[index]; }
/// \brief Returns a reference to the first element in the array.
/// \brief Returns a reference to the first node in the array.
[[nodiscard]] node& front() noexcept { return *values.front(); }
/// \brief Returns a reference to the first element in the array.
/// \brief Returns a reference to the first node in the array.
[[nodiscard]] const node& front() const noexcept { return *values.front(); }
/// \brief Returns a reference to the last element in the array.
/// \brief Returns a reference to the last node in the array.
[[nodiscard]] node& back() noexcept { return *values.back(); }
/// \brief Returns a reference to the last element in the array.
/// \brief Returns a reference to the last node in the array.
[[nodiscard]] const node& back() const noexcept { return *values.back(); }
/// \brief Returns an iterator to the first element.
/// \brief Returns an iterator to the first node.
[[nodiscard]] iterator begin() noexcept { return { values.begin() }; }
/// \brief Returns an iterator to the first element.
/// \brief Returns an iterator to the first node.
[[nodiscard]] const_iterator begin() const noexcept { return { values.begin() }; }
/// \brief Returns an iterator to the first element.
/// \brief Returns an iterator to the first node.
[[nodiscard]] const_iterator cbegin() const noexcept { return { values.cbegin() }; }
/// \brief Returns an iterator to one-past-the-last element.
/// \brief Returns an iterator to one-past-the-last node.
[[nodiscard]] iterator end() noexcept { return { values.end() }; }
/// \brief Returns an iterator to one-past-the-last element.
/// \brief Returns an iterator to one-past-the-last node.
[[nodiscard]] const_iterator end() const noexcept { return { values.end() }; }
/// \brief Returns an iterator to one-past-the-last element.
/// \brief Returns an iterator to one-past-the-last node.
[[nodiscard]] const_iterator cend() const noexcept { return { values.cend() }; }
/// \brief Returns true if the array is empty.
[[nodiscard]] bool empty() const noexcept { return values.empty(); }
/// \brief Returns the number of elements in the array.
/// \brief Returns the number of nodes in the array.
[[nodiscard]] size_t size() const noexcept { return values.size(); }
/// \brief Reserves internal storage capacity up to a pre-determined number of elements.
/// \brief Reserves internal storage capacity up to a pre-determined number of nodes.
void reserve(size_t new_capacity) TOML_MAY_THROW { values.reserve(new_capacity); }
/// \brief Removes all elements from the array.
/// \brief Removes all nodes from the array.
void clear() noexcept { values.clear(); }
// insert()
// emplace()
/// \brief Inserts a new node at a specific position in the array.
///
/// \detail \cpp
/// auto arr = toml::array{
/// 1,
/// 3
/// };
/// arr.insert(arr.cbegin() + 1, "two");
/// arr.insert(arr.cend(), toml::array{ 4, 5 });
/// std::cout << arr << std::endl;
///
/// // output:
/// // [1, "two", 3, [4, 5]]
/// \ecpp
///
/// \tparam U One of the TOML node or value types (or a type promotable to one).
/// \param pos The insertion position.
/// \param val The value being inserted.
///
/// \returns An iterator to the inserted value.
template <typename U>
iterator insert(const_iterator pos, U&& val) noexcept
{
return { values.emplace(pos.raw_, impl::make_node(std::forward<U>(val))) };
}
/// \brief Removes the specified element from the array.
///
/// \returns The position following the Iterator following the removed element.
/// \brief Repeatedly inserts a value starting at a specific position in the array.
///
/// \detail \cpp
/// auto arr = toml::array{
/// "with an evil twinkle in its eye the goose said",
/// "and immediately we knew peace was never an option."
/// };
/// arr.insert(arr.cbegin() + 1, 3, "honk");
/// std::cout << arr << std::endl;
///
/// // output:
/// // [
/// // "with an evil twinkle in its eye the goose said",
/// // "honk",
/// // "honk",
/// // "honk",
/// // "and immediately we knew peace was never an option."
/// // ]
/// \ecpp
///
/// \tparam U One of the TOML value types (or a type promotable to one).
/// \param pos The insertion position.
/// \param count The number of times the value should be inserted.
/// \param val The value being inserted.
///
/// \returns An iterator to the first inserted value (or a copy of `pos` if count was 0).
template <typename U>
iterator insert(const_iterator pos, size_t count, U&& val) noexcept
{
switch (count)
{
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
case 1: return insert(pos, std::forward<U>(val));
default:
{
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
preinsertion_resize(start_idx, count);
size_t i = start_idx;
for (size_t e = start_idx + count - 1_sz; i < e; i++)
values[i].reset(impl::make_node(val));
//# potentially move the initial value into the last element
values[i].reset(impl::make_node(std::forward<U>(val)));
return { values.begin() + start_idx };
}
}
}
/// \brief Inserts a range of values into the array at a specific position.
///
/// \tparam ITER An iterator type. Must satisfy ForwardIterator.
/// \param pos The insertion position.
/// \param first Iterator to the first value being inserted.
/// \param last Iterator to the one-past-the-last value being inserted.
///
/// \returns An iterator to the first inserted value (or a copy of `pos` if `first` == `last`).
template <typename ITER>
iterator insert(const_iterator pos, ITER first, ITER last) noexcept
{
const auto count = std::distance(first, last);
switch (count)
{
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
case 1: return insert(pos, *first);
default:
{
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
preinsertion_resize(start_idx, count);
size_t i = start_idx;
for (auto it = first; it != last; it++)
values[i].reset(impl::make_node(*it));
return { values.begin() + start_idx };
}
}
}
/// \brief Inserts a range of values into the array at a specific position.
///
/// \tparam U One of the TOML node or value types (or a type promotable to one).
/// \param pos The insertion position.
/// \param ilist An initializer list containing the values to be inserted.
///
/// \returns An iterator to the first inserted value (or a copy of `pos` if `ilist` was empty).
template <typename U>
iterator insert(const_iterator pos, std::initializer_list<U> ilist) noexcept
{
switch (ilist.size())
{
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
case 1: return insert(pos, *ilist.begin());
default:
{
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
preinsertion_resize(start_idx, ilist.size());
size_t i = start_idx;
for (auto& val : ilist)
values[i].reset(impl::make_node(val));
return { values.begin() + start_idx };
}
}
}
/// \brief Emplaces a new value at a specific position in the array.
///
/// \detail \cpp
/// auto arr = toml::array{
/// 1,
/// 2
/// };
///
/// //add a string using std::string's substring constructor
/// arr.emplace<std::string>(arr.cbegin() + 1, "this is not a drill"sv, 14, 5);
/// std::cout << arr << std::endl;
///
/// // output:
/// // [1, "drill" 2]
/// \ecpp
///
/// \tparam U One of the TOML node or value types.
/// \tparam V Value constructor argument types.
/// \param pos The insertion position.
/// \param args Arguments to pass to the value constructor.
///
/// \returns An iterator to the inserted value.
///
/// \remarks There is no difference between insert and emplace
/// For trivial value types (floats, ints, bools).
template <typename U, typename... V>
iterator emplace(const_iterator pos, V&&... args) noexcept
{
using type = impl::unwrapped<U>;
static_assert(
impl::is_value_or_node<type>,
"Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array"
);
return { values.emplace(pos.raw_, new node_of<type>{ std::forward<V>(args)...} ) };
}
/// \brief Removes the specified node from the array.
///
/// \detail \cpp
/// auto arr = toml::array{
/// 1,
/// 2,
/// 3
/// };
/// std::cout << arr << std::endl;
///
/// arr.erase(arr.cbegin() + 1);
/// std::cout << arr << std::endl;
///
/// // output:
/// // [1, 2, 3]
/// // [1, 3]
/// \ecpp
///
/// \param pos Iterator to the node being erased.
///
/// \returns Iterator to the first node immediately following the removed node.
iterator erase(const_iterator pos) noexcept
{
return iterator{ values.erase(pos.raw_) };
return { values.erase(pos.raw_) };
}
/// \brief Removes the specified range of elements elements from the array.
/// \brief Removes the nodes in the range [first, last) from the array.
///
/// \detail \cpp
/// auto arr = toml::array{
/// 1,
/// "bad",
/// "karma"
/// 2,
/// };
/// std::cout << arr << std::endl;
///
/// \returns The position following the Iterator following the last removed element.
/// arr.erase(arr.cbegin() + 1, arr.cbegin() + 3);
/// std::cout << arr << std::endl;
///
/// // output:
/// // [1, "bad", "karma", 3]
/// // [1, 3]
/// \ecpp
///
/// \param first Iterator to the first node being erased.
/// \param last Iterator to the one-past-the-last node being erased.
///
/// \returns Iterator to the first node immediately following the last removed node.
iterator erase(const_iterator first, const_iterator last) noexcept
{
return iterator{ values.erase(first.raw_, last.raw_) };
return { values.erase(first.raw_, last.raw_) };
}
// push_back()
// emplace_back()
/// \brief Removes the last element from the array.
void pop_back() noexcept { values.pop_back(); }
/// \brief Gets an element at a specific index if it is a particular type.
/// \brief Appends a new value to the end of the array.
///
/// \detail \cpp
/// auto arr = toml::array{
/// 1,
/// 2
/// };
/// arr.push_back(3);
/// arr.push_back(4.0);
/// arr.push_back(array{ 5, "six"sv });
/// std::cout << arr << std::endl;
///
/// // output:
/// // [1, 2, 3, 4.0, [5, "six"]]
/// \ecpp
///
/// \tparam U One of the TOML value types (or a type promotable to one).
/// \param val The value being added.
///
/// \returns A reference to the newly-constructed value node.
template <typename U>
decltype(auto) push_back(U&& val) noexcept
{
auto nde = impl::make_node(std::forward<U>(val));
values.emplace_back(nde);
return *nde;
}
/// \brief Emplaces a new value at the end of the array.
///
/// \detail \cpp
/// auto arr = toml::array{
/// 1,
/// 2
/// };
/// arr.emplace_back<array>(3, "four"sv);
/// std::cout << arr << std::endl;
///
/// // output:
/// // [1, 2, [3, "four"]]
/// \ecpp
///
/// \tparam U One of the TOML value types.
/// \tparam V Value constructor argument types.
/// \param args Arguments to pass to the value constructor.
///
/// \returns A reference to the newly-constructed value node.
///
/// \remarks There is no difference between push_back and emplace_back
/// For trivial value types (floats, ints, bools).
template <typename U, typename... V>
decltype(auto) emplace_back(V&&... args) noexcept
{
using type = impl::unwrapped<U>;
static_assert(
impl::is_value_or_node<type>,
"Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array"
);
auto nde = new node_of<type>{ std::forward<V>(args)... };
values.emplace_back(nde);
return *nde;
}
/// \brief Removes the last node from the array.
void pop_back() noexcept
{
values.pop_back();
}
/// \brief Gets the node at a specific index if it is a particular type.
///
/// \detail \cpp
/// auto arr = toml::array{
/// 42,
/// "is the meaning of life, apparently."sv
/// };
/// if (auto val = arr.get_as<int64_t>(0))
/// std::cout << "node [0] was an integer with value "sv << **val << std::endl;
///
/// // output:
/// // node [0] was an integer with value 42
/// \ecpp
///
/// \tparam T The node's type.
/// \param index The element index.
/// \param index The node's index.
///
/// \returns A pointer to the selected element if it was of the specified type, or nullptr.
/// \returns A pointer to the selected node if it was of the specified type, or nullptr.
template <typename T>
[[nodiscard]] node_of<T>* get_as(size_t index) noexcept
{
return values[index]->as<T>();
}
/// \brief Gets an element at a specific index if it is a particular type.
/// \brief Gets the node at a specific index if it is a particular type (const overload).
///
/// \tparam T The node's type.
/// \param index The element index.
/// \param index The node's index.
///
/// \returns A pointer to the selected element if it was of the specified type, or nullptr.
/// \returns A pointer to the selected node if it was of the specified type, or nullptr.
template <typename T>
[[nodiscard]] const node_of<T>* get_as(size_t index) const noexcept
{
@ -307,6 +774,111 @@ namespace toml
return !(lhs == rhs);
}
private:
[[nodiscard]] size_t total_leaf_count() const noexcept
{
size_t leaves{};
for (size_t i = 0, e = values.size(); i < e; i++)
{
auto arr = values[i]->as_array();
leaves += arr ? arr->total_leaf_count() : 1_sz;
}
return leaves;
}
void flatten_child(array&& child, size_t& dest_index) noexcept
{
for (size_t i = 0, e = child.size(); i < e; i++)
{
auto type = child.values[i]->type();
if (type == node_type::array)
{
array& arr = *reinterpret_cast<array*>(child.values[i].get());
if (!arr.empty())
flatten_child(std::move(arr), dest_index);
}
else
values[dest_index++] = std::move(child.values[i]);
}
}
public:
/// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself.
///
/// \detail \cpp
///
/// auto arr = toml::array{
/// 1,
/// 2,
/// toml::array{
/// 3,
/// 4,
/// toml::array{ 5 }
/// },
/// 6,
/// toml::array{}
/// };
/// std::cout << arr << std::endl;
///
/// arr.flatten();
/// std::cout << arr << std::endl;
///
/// // output:
/// // [1, 2, [3, 4, [5]], 6, []]
/// // [1, 2, 3, 4, 5, 6]
///
/// \ecpp
///
/// \remarks Arrays inside child tables are not flattened.
void flatten() TOML_MAY_THROW
{
if (values.empty())
return;
bool requires_flattening = false;
size_t size_after_flattening = values.size();
for (size_t i = values.size(); i --> 0_sz;)
{
auto arr = values[i]->as_array();
if (!arr)
continue;
size_after_flattening--; //discount the array itself
const auto leaf_count = arr->total_leaf_count();
if (leaf_count > 0_sz)
{
requires_flattening = true;
size_after_flattening += leaf_count;
}
else
values.erase(values.cbegin() + i);
}
if (!requires_flattening)
return;
values.reserve(size_after_flattening);
size_t i = 0;
while (i < values.size())
{
auto arr = values[i]->as_array();
if (!arr)
{
i++;
continue;
}
std::unique_ptr<node> arr_storage = std::move(values[i]);
const auto leaf_count = arr->total_leaf_count();
if (leaf_count > 1_sz)
preinsertion_resize(i + 1_sz, leaf_count - 1_sz);
flatten_child(std::move(*arr), i); //increments i
}
}
template <typename CHAR>
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const array&) TOML_MAY_THROW;
};

View File

@ -279,12 +279,6 @@ namespace toml
using namespace std::string_literals;
using namespace std::string_view_literals;
[[nodiscard]] TOML_ALWAYS_INLINE
TOML_CONSTEVAL uint8_t operator"" _u8(unsigned long long n) noexcept
{
return static_cast<uint8_t>(n);
}
[[nodiscard]] TOML_ALWAYS_INLINE
TOML_CONSTEVAL size_t operator"" _sz(unsigned long long n) noexcept
{
@ -301,15 +295,15 @@ namespace toml
#else
/// \brief The base character type for keys and string values.
/// \attention This will be `char8_t` if `TOML_CHAR_8_STRINGS` is `1`.
/// \remarks This will be an alias for char8_t if `TOML_CHAR_8_STRINGS` is `1`.
using string_char = char;
/// \brief The string type for keys and string values.
/// \attention This will be `std::u8string` if `TOML_CHAR_8_STRINGS` is `1`.
/// \remarks This will be an alias for std::u8string if `TOML_CHAR_8_STRINGS` is `1`.
using string = std::string;
/// \brief The string type for keys and string values.
/// \attention This will be `std::u8string_view` if `TOML_CHAR_8_STRINGS` is `1`.
/// \remarks This will be an alias for std::u8string_view if `TOML_CHAR_8_STRINGS` is `1`.
using string_view = std::string_view;
#endif
@ -346,12 +340,32 @@ namespace toml
#else
/// \brief The integer type used to tally line numbers and columns.
/// \attention This will be `uint32_t` if `TOML_LARGE_FILES` is `1`.
/// \remarks This will be an alias for uint32_t if `TOML_LARGE_FILES` is `1`.
using source_index = uint16_t;
#endif
/// \brief A source document line-and-column pair.
///
/// \detail \cpp
/// auto table = toml::parse_file("config.toml"sv);
/// std::cout << "The node 'description' was defined at "sv
/// << table.get("description")->source().begin()
/// << std::endl;
///
/// // possible output:
/// // The value 'description' was defined at line 7, column 15
/// \ecpp
///
/// \remarks toml++'s parser is unicode-aware insofar as it knows how to handle
/// various non-conventional whitespace and newline characters, but it doesn't give
/// much thought to combining marks, grapheme clusters vs. characters, et cetera.
/// If a TOML document contains lots of codepoints outside of the ASCII range
/// you may find that your source_positions don't match those given by a text editor
/// (typically the line numbers will be accurate but column numbers will be too high).
/// <br><br>
/// This Is Not An Error (tm). I've chosen this behaviour as a deliberate trade-off
/// between parser complexity and correctness.
struct source_position
{
/// \brief The line number.
@ -369,6 +383,7 @@ namespace toml
return line > source_index{} && column > source_index{};
}
/// \brief Returns true if two source_positions represent the same line and column.
[[nodiscard]]
friend constexpr bool operator == (const source_position& lhs, const source_position& rhs) noexcept
{
@ -376,6 +391,7 @@ namespace toml
&& lhs.column == rhs.column;
}
/// \brief Returns true if two source_positions do not represent the same line and column.
[[nodiscard]]
friend constexpr bool operator != (const source_position& lhs, const source_position& rhs) noexcept
{
@ -383,6 +399,7 @@ namespace toml
|| lhs.column != rhs.column;
}
/// \brief Returns true if the LHS position is before the RHS position.
[[nodiscard]]
friend constexpr bool operator < (const source_position& lhs, const source_position& rhs) noexcept
{
@ -390,6 +407,7 @@ namespace toml
|| (lhs.line == rhs.line && lhs.column < rhs.column);
}
/// \brief Returns true if the LHS position is before the RHS position or equal to it.
[[nodiscard]]
friend constexpr bool operator <= (const source_position& lhs, const source_position& rhs) noexcept
{
@ -397,18 +415,37 @@ namespace toml
|| (lhs.line == rhs.line && lhs.column <= rhs.column);
}
/// \brief Prints a source_position to a stream.
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const source_position& rhs)
TOML_MAY_THROW
{
return lhs << "line " << rhs.line << ", column " << rhs.column;
}
TOML_MAY_THROW;
};
/// \brief A pointer to a shared string resource containing a source path.
using source_path_ptr = std::shared_ptr<const std::string>;
/// \brief A source document region.
///
/// \detail \cpp
/// auto table = toml::parse_file("config.toml"sv);
/// std::cout << "The node 'server' was defined at "sv
/// << table.get("server")->source()
/// << std::endl;
///
/// // possible output:
/// // The node 'server' was defined at line 3, column 1 - line 10, column 25 of 'config.toml'
/// \ecpp
///
/// \remarks toml++'s parser is unicode-aware insofar as it knows how to handle
/// various non-conventional whitespace and newline characters, but it doesn't give
/// much thought to combining marks, grapheme clusters vs. characters, et cetera.
/// If a TOML document contains lots of codepoints outside of the ASCII range
/// you may find that your source_positions don't match those given by a text editor
/// (typically the line numbers will be accurate but column numbers will be too high).
/// <br><br>
/// This Is Not An Error (tm). I've chosen this behaviour as a deliberate trade-off
/// between parser complexity and correctness.
struct source_region
{
/// \brief The beginning of the region (inclusive).
@ -421,6 +458,11 @@ namespace toml
///
/// \remarks This will be `nullptr` if no path was provided to toml::parse().
source_path_ptr path;
/// \brief Prints a source_region to a stream.
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const source_region& rhs)
TOML_MAY_THROW;
};
TOML_PUSH_WARNINGS
@ -522,7 +564,7 @@ namespace toml::impl
template <typename T>
using string_map = std::map<string, T, std::less<>>; //heterogeneous lookup
#if defined(__cpp_lib_remove_cvref) || (defined(_MSC_VER) && defined(_HAS_CXX20))
#if defined(__cpp_lib_remove_cvref) || (defined(_MSC_VER) && defined(_HAS_CXX20) && _HAS_CXX20)
template <typename T>
using remove_cvref_t = std::remove_cvref_t<T>;
@ -550,7 +592,7 @@ namespace toml::impl
template <typename T>
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr std::underlying_type_t<T> unwrap_enum(T val) noexcept
constexpr std::underlying_type_t<T> unbox_enum(T val) noexcept
{
return static_cast<std::underlying_type_t<T>>(val);
}
@ -584,6 +626,7 @@ namespace toml::impl
template <typename T>
inline constexpr bool is_value_or_promotable =
is_value<T>
|| std::is_same_v<std::decay_t<T>, string_char*>
|| std::is_same_v<T, string_view>
|| std::is_same_v<T, int32_t>
|| std::is_same_v<T, int16_t>
@ -595,7 +638,10 @@ namespace toml::impl
#ifdef TOML_SMALL_FLOAT_TYPE
|| std::is_same_v<T, TOML_SMALL_FLOAT_TYPE>
#endif
;
#ifdef TOML_SMALL_INT_TYPE
|| std::is_same_v<T, TOML_SMALL_INT_TYPE>
#endif
;
template <typename T>
inline constexpr bool is_value_or_node =
@ -615,7 +661,17 @@ namespace toml::impl
template <typename T> struct node_unwrapper { using type = T; };
template <typename T> struct node_unwrapper<value<T>> { using type = T; };
template <typename T> using unwrapped = typename impl::node_unwrapper<T>::type;
template <typename T> struct value_promoter { using type = T; };
template <size_t N> struct value_promoter<const string_char[N]> { using type = string; };
template <size_t N> struct value_promoter<const string_char(&)[N]> { using type = string; };
template <size_t N> struct value_promoter<const string_char(&&)[N]> { using type = string; };
template <> struct value_promoter<const string_char*> { using type = string; };
template <size_t N> struct value_promoter<string_char[N]> { using type = string; };
template <size_t N> struct value_promoter<string_char(&)[N]> { using type = string; };
template <size_t N> struct value_promoter<string_char(&&)[N]> { using type = string; };
template <> struct value_promoter<string_char*> { using type = string; };
template <> struct value_promoter<string_view> { using type = string; };
template <> struct value_promoter<int32_t> { using type = int64_t; };
template <> struct value_promoter<int16_t> { using type = int64_t; };
@ -627,6 +683,9 @@ namespace toml::impl
#ifdef TOML_SMALL_FLOAT_TYPE
template <> struct value_promoter<TOML_SMALL_FLOAT_TYPE> { using type = double; };
#endif
#ifdef TOML_SMALL_INT_TYPE
template <> struct value_promoter<TOML_SMALL_INT_TYPE> { using type = int64_t; };
#endif
template <typename T> using promoted = typename impl::value_promoter<T>::type;
template <typename T> struct node_type_of_;
@ -721,10 +780,6 @@ namespace toml
template <typename T>
using node_of = typename impl::node_wrapper<T>::type;
/// \brief Helper alias that unwraps TOML node type to it's raw value equivalent.
template <typename T>
using value_of = typename impl::node_unwrapper<T>::type;
/// \brief Metafunction for determining if a type is a toml::table.
template <typename T>
inline constexpr bool is_table = std::is_same_v<impl::remove_cvref_t<T>, table>;

View File

@ -13,6 +13,13 @@ namespace toml
/// \brief The day component, from 1 - 31.
uint8_t day;
/// \brief Equality operator.
///
/// \param lhs The LHS date.
/// \param rhs The RHS date.
///
/// \returns True if the dates represented the same value.
[[nodiscard]]
friend constexpr bool operator == (date lhs, date rhs) noexcept
{
@ -21,6 +28,12 @@ namespace toml
&& lhs.day == rhs.day;
}
/// \brief Inequality operator.
///
/// \param lhs The LHS date.
/// \param rhs The RHS date.
///
/// \returns True if the dates did not represent the same value.
[[nodiscard]]
friend constexpr bool operator != (date lhs, date rhs) noexcept
{
@ -29,6 +42,8 @@ namespace toml
|| lhs.day != rhs.day;
}
/// \brief Prints a date out to a stream as `YYYY-MM-DD` (per RFC 3339).
template <typename CHAR>
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date& rhs)
TOML_MAY_THROW
@ -50,6 +65,12 @@ namespace toml
/// \brief The fractional nanoseconds component, from 0 - 999999999.
uint32_t nanosecond;
/// \brief Equality operator.
///
/// \param lhs The LHS time.
/// \param rhs The RHS time.
///
/// \returns True if the times represented the same value.
[[nodiscard]]
friend constexpr bool operator == (const time& lhs, const time& rhs) noexcept
{
@ -59,12 +80,19 @@ namespace toml
&& lhs.nanosecond == rhs.nanosecond;
}
/// \brief Inequality operator.
///
/// \param lhs The LHS time.
/// \param rhs The RHS time.
///
/// \returns True if the times did not represent the same value.
[[nodiscard]]
friend constexpr bool operator != (const time& lhs, const time& rhs) noexcept
{
return !(lhs == rhs);
}
/// \brief Prints a time out to a stream as `HH:MM:SS.FFFFFF` (per RFC 3339).
template <typename CHAR>
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time& rhs)
TOML_MAY_THROW
@ -80,24 +108,56 @@ namespace toml
/// \brief Offset from UTC+0, in minutes.
int16_t minutes;
/// \brief Creates a timezone offset from separate hour and minute totals.
///
/// \detail \cpp
/// std::cout << time_offset::from_hh_mm(2, 30) << std::endl;
/// std::cout << time_offset::from_hh_mm(-2, 30) << std::endl;
/// std::cout << time_offset::from_hh_mm(-2, -30) << std::endl;
/// std::cout << time_offset::from_hh_mm(0,0) << std::endl;
///
/// // output:
/// // +02:30
/// // -01:30
/// // -02:30
/// // Z
/// \ecpp
///
/// \param hours The total hours.
/// \param minutes The total minutes.
///
/// \returns A time_offset.
[[nodiscard]]
static constexpr time_offset from_hh_mm(int8_t hours, int8_t minutes) noexcept
{
return time_offset{ static_cast<int16_t>(hours * 60 + minutes) };
}
/// \brief Equality operator.
///
/// \param lhs The LHS time_offset.
/// \param rhs The RHS time_offset.
///
/// \returns True if the time_offsets represented the same value.
[[nodiscard]]
friend constexpr bool operator == (time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes == rhs.minutes;
}
/// \brief Inequality operator.
///
/// \param lhs The LHS time_offset.
/// \param rhs The RHS time_offset.
///
/// \returns True if the time_offsets did not represent the same value.
[[nodiscard]]
friend constexpr bool operator != (time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes != rhs.minutes;
}
/// \brief Prints a time_offset out to a stream as `+-HH:MM or Z` (per RFC 3339).
template <typename CHAR>
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time_offset& rhs)
TOML_MAY_THROW
@ -115,14 +175,23 @@ namespace toml
/// \brief The time component.
toml::time time;
/// \brief The timezone offset component.
///
/// \remarks The date_time is said to be 'local' if the time_offset is empty.
std::optional<toml::time_offset> time_offset;
/// \brief Returns true if this date_time does not contain timezone offset information.
[[nodiscard]]
constexpr bool is_local() const noexcept
{
return !time_offset.has_value();
}
/// \brief Equality operator.
///
/// \param lhs The LHS date_time.
/// \param rhs The RHS date_time.
///
/// \returns True if the date_times represented the same value.
[[nodiscard]]
friend constexpr bool operator == (const date_time& lhs, const date_time& rhs) noexcept
{
@ -131,6 +200,12 @@ namespace toml
&& lhs.time_offset == rhs.time_offset;
}
/// \brief Inequality operator.
///
/// \param lhs The LHS date_time.
/// \param rhs The RHS date_time.
///
/// \returns True if the date_times did not represent the same value.
[[nodiscard]]
friend constexpr bool operator != (const date_time& lhs, const date_time& rhs) noexcept
{
@ -139,6 +214,7 @@ namespace toml
|| lhs.time_offset != rhs.time_offset;
}
/// \brief Prints a date_time out to a stream in RFC 3339 format.
template <typename CHAR>
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date_time& rhs)
TOML_MAY_THROW

View File

@ -134,6 +134,33 @@ namespace toml::impl
namespace toml
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted TOML.
///
/// \remarks You generally don't need to create an instance of this class explicitly; the stream
/// operators of the TOML node types already print themselves out using this formatter.
///
/// \detail \cpp
/// auto tbl = toml::table{{
/// { "description", "This is some TOML, yo." },
/// { "fruit", toml::array{ "apple", "orange", "pear" } },
/// { "numbers", toml::array{ 1, 2, 3, 4, 5 } },
/// { "table", toml::table{{ { "foo", "bar" } }} }
/// }};
///
/// // these two lines are equivalent:
/// std::cout << toml::default_formatter{ tbl } << std::endl;
/// std::cout << tbl << std::endl;
///
/// // output (twice):
/// // description = "This is some TOML, yo."
/// // fruit = ["apple", "orange", "pear"]
/// // numbers = [1, 2, 3, 4, 5]
/// //
/// // [table]
/// // foo = "bar"
/// \ecpp
///
/// \tparam CHAR The underlying character type of the output stream. Must be 1 byte in size.
template <typename CHAR = char>
class default_formatter final : impl::formatter<CHAR>
{
@ -243,12 +270,20 @@ namespace toml
void print(const table& tbl) TOML_MAY_THROW
{
//values, arrays, and inline tables
static constexpr auto is_non_inline_array_of_tables = [](auto&& nde) noexcept
{
auto arr = nde.as_array();
return arr
&& arr->is_array_of_tables()
&& !arr->template get_as<table>(0_sz)->is_inline();
};
//values, arrays, and inline tables/table arrays
for (auto [k, v] : tbl)
{
const auto type = v.type();
if ((type == node_type::table && !reinterpret_cast<const table*>(&v)->is_inline())
|| (type == node_type::array && reinterpret_cast<const array*>(&v)->is_array_of_tables()))
|| (type == node_type::array && is_non_inline_array_of_tables(v)))
continue;
base::print_newline();
@ -290,7 +325,7 @@ namespace toml
break;
case node_type::array:
if (reinterpret_cast<const array*>(&child_v)->is_array_of_tables())
if (is_non_inline_array_of_tables(child_v))
child_table_array_count++;
else
child_value_count++;
@ -329,8 +364,7 @@ namespace toml
//table arrays
for (auto [k, v] : tbl)
{
const auto type = v.type();
if (type != node_type::array || !reinterpret_cast<const array*>(&v)->is_array_of_tables())
if (!is_non_inline_array_of_tables(v))
continue;
auto& arr = *reinterpret_cast<const array*>(&v);
@ -382,11 +416,16 @@ namespace toml
public:
/// \brief Constructs a default formatter and binds it to a TOML object.
///
/// \param source The source TOML object.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit default_formatter(const toml::node& source, format_flags flags = {}) noexcept
: base{ source, flags }
{}
/// \brief Prints the bound TOML object out to the stream as formatted TOML.
template <typename T>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<T>& lhs, default_formatter& rhs)
TOML_MAY_THROW
@ -398,6 +437,7 @@ namespace toml
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as formatted TOML (rvalue overload).
template <typename T>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<T>& lhs, default_formatter&& rhs)
TOML_MAY_THROW

View File

@ -11,11 +11,11 @@ namespace toml
};
[[nodiscard]] constexpr format_flags operator & (format_flags lhs, format_flags rhs) noexcept
{
return static_cast<format_flags>(impl::unwrap_enum(lhs) & impl::unwrap_enum(rhs));
return static_cast<format_flags>(impl::unbox_enum(lhs) & impl::unbox_enum(rhs));
}
[[nodiscard]] constexpr format_flags operator | (format_flags lhs, format_flags rhs) noexcept
{
return static_cast<format_flags>( impl::unwrap_enum(lhs) | impl::unwrap_enum(rhs) );
return static_cast<format_flags>( impl::unbox_enum(lhs) | impl::unbox_enum(rhs) );
}
}

View File

@ -3,6 +3,36 @@
namespace toml
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted JSON.
///
/// \detail \cpp
/// auto some_toml = toml::parse(R"(
/// [fruit]
/// apple.color = "red"
/// apple.taste.sweet = true
///
/// [fruit.apple.texture]
/// smooth = true
/// )"sv);
/// std::cout << toml::json_formatter{ some_toml } << std::endl;
///
/// // output:
/// // {
/// // "fruit" : {
/// // "apple" : {
/// // "color" : "red",
/// // "taste" : {
/// // "sweet" : true
/// // },
/// // "texture" : {
/// // "smooth" : true
/// // }
/// // }
/// // }
/// // }
/// \ecpp
///
/// \tparam CHAR The underlying character type of the output stream. Must be 1 byte in size.
template <typename CHAR = char>
class json_formatter final : impl::formatter<CHAR>
{
@ -57,6 +87,10 @@ namespace toml
public:
/// \brief Constructs a JSON formatter and binds it to a TOML object.
///
/// \param source The source TOML object.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit json_formatter(
const toml::node& source,
@ -64,6 +98,8 @@ namespace toml
: base{ source, flags }
{}
/// \brief Prints the bound TOML object out to the stream as JSON.
template <typename T>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter& rhs)
TOML_MAY_THROW
@ -74,6 +110,7 @@ namespace toml
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as JSON (rvalue overload).
template <typename T>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<T>& lhs, json_formatter&& rhs)
TOML_MAY_THROW

View File

@ -17,11 +17,16 @@ namespace toml
node(node&& other) noexcept
: source_{ std::move(other.source_) }
{}
{
other.source_.begin = {};
other.source_.end = {};
}
node& operator= (node&& rhs) noexcept
{
source_ = std::move(rhs.source_);
rhs.source_.begin = {};
rhs.source_.end = {};
return *this;
}
@ -84,7 +89,7 @@ namespace toml
[[nodiscard]] TOML_ALWAYS_INLINE
bool is() const noexcept
{
using type = value_of<impl::remove_cvref_t<T>>;
using type = impl::unwrapped<impl::remove_cvref_t<T>>;
static_assert(
impl::is_value_or_node<type>,
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
@ -155,7 +160,7 @@ namespace toml
[[nodiscard]] TOML_ALWAYS_INLINE
node_of<T>* as() noexcept
{
using type = value_of<T>;
using type = impl::unwrapped<T>;
static_assert(
impl::is_value_or_node<type>,
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
@ -177,7 +182,7 @@ namespace toml
[[nodiscard]] TOML_ALWAYS_INLINE
const node_of<T>* as() const noexcept
{
using type = value_of<T>;
using type = impl::unwrapped<T>;
static_assert(
impl::is_value_or_node<type>,
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"

View File

@ -156,7 +156,7 @@ namespace toml
[[nodiscard]] auto as() noexcept
{
static_assert(
impl::is_value_or_node<U>,
impl::is_value_or_node<impl::unwrapped<U>>,
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
);
@ -167,7 +167,7 @@ namespace toml
[[nodiscard]] const node_of<U>* as() const noexcept
{
static_assert(
impl::is_value_or_node<U>,
impl::is_value_or_node<impl::unwrapped<U>>,
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
);
@ -207,10 +207,9 @@ namespace toml
[[nodiscard]] static bool container_equality(const node_view& lhs, const U& rhs) noexcept
{
using elem_t = std::remove_const_t<typename U::value_type>;
static_assert(
impl::is_value_or_promotable<elem_t>,
"Container element type must be (or be promotable to) one of the basic value types"
"Container element type must be (or be promotable to) one of the TOML value types"
);
const array* arr = lhs.as<array>();

View File

@ -10,8 +10,25 @@ namespace toml
/// \brief The result of a parsing operation.
///
/// \remarks This type only exists when exceptions are disabled,
/// otherwise `parse_result` is a simple alias for `toml::table`.
/// \attention This type only exists when exceptions are disabled.
/// When exceptions are enabled parse_result is just an alias for toml::table
/// and parsing failures are indicated by raising a toml::parse_error as an exception.
///
/// \detail A parse_result is effectively a discriminated union containing either a toml::table
/// or a toml::parse_error. Most member functions assume a particular one of these two states,
/// and calling them when in the wrong state will cause errors (e.g. attempting to access the
/// error object when parsing was successful). \cpp
/// parse_result result = toml::parse_file("config.toml");
/// if (result)
/// do_stuff_with_a_table(result); //implicitly converts to table&
/// else
/// std::cerr
/// << "Error parsing file '"sv << *result.error().source().path
/// << "':\n"sv << result.error().description()
/// << "\n ("sv << result.error().source().begin << ")"sv
/// << std::endl;
///
/// \ecpp
class parse_result final
{
private:
@ -31,55 +48,65 @@ namespace toml
public:
/// \brief Returns true if parsing succeeeded.
[[nodiscard]] bool succeeded() const noexcept { return !is_err; }
/// \brief Returns true if parsing failed.
[[nodiscard]] bool failed() const noexcept { return is_err; }
/// \brief Returns true if parsing succeeeded.
[[nodiscard]] explicit operator bool() const noexcept { return !is_err; }
/// \brief Returns the internal toml::table.
[[nodiscard]] table& get() & noexcept
{
TOML_ASSERT(!is_err);
return *std::launder(reinterpret_cast<table*>(&storage));
}
/// \brief Returns the internal toml::table (rvalue overload).
[[nodiscard]] table&& get() && noexcept
{
TOML_ASSERT(!is_err);
return std::move(*std::launder(reinterpret_cast<table*>(&storage)));
}
/// \brief Returns the internal toml::table (const lvalue overload).
[[nodiscard]] const table& get() const& noexcept
{
TOML_ASSERT(!is_err);
return *std::launder(reinterpret_cast<const table*>(&storage));
}
/// \brief Returns the internal toml::parse_error.
[[nodiscard]] parse_error& error() & noexcept
{
TOML_ASSERT(is_err);
return *std::launder(reinterpret_cast<parse_error*>(&storage));
}
/// \brief Returns the internal toml::parse_error (rvalue overload).
[[nodiscard]] parse_error&& error() && noexcept
{
TOML_ASSERT(is_err);
return std::move(*std::launder(reinterpret_cast<parse_error*>(&storage)));
}
/// \brief Returns the internal toml::parse_error (const lvalue overload).
[[nodiscard]] const parse_error& error() const& noexcept
{
TOML_ASSERT(is_err);
return *std::launder(reinterpret_cast<const parse_error*>(&storage));
}
[[nodiscard]] table& operator* () & noexcept { return get(); }
[[nodiscard]] table&& operator* () && noexcept { return std::move(get()); }
[[nodiscard]] const table& operator* () const& noexcept { return get(); }
[[nodiscard]] table* operator-> () noexcept { return &get(); }
[[nodiscard]] const table* operator-> () const noexcept { return &get(); }
/// \brief Returns the internal toml::table.
[[nodiscard]] operator table& () noexcept { return get(); }
/// \brief Returns the internal toml::table (rvalue overload).
[[nodiscard]] operator table&& () noexcept { return std::move(get()); }
/// \brief Returns the internal toml::table (const lvalue overload).
[[nodiscard]] operator const table& () const noexcept { return get(); }
/// \brief Returns the internal toml::parse_error.
[[nodiscard]] explicit operator parse_error& () noexcept { return error(); }
/// \brief Returns the internal toml::parse_error (rvalue overload).
[[nodiscard]] explicit operator parse_error && () noexcept { return std::move(error()); }
/// \brief Returns the internal toml::parse_error (const lvalue overload).
[[nodiscard]] explicit operator const parse_error& () const noexcept { return error(); }
TOML_NODISCARD_CTOR
@ -209,11 +236,11 @@ namespace toml::impl
#endif
[[nodiscard]]
source_position current_position_or_assumed_next() const noexcept
source_position current_position(source_index fallback_offset = 0) const noexcept
{
if (cp)
return cp->position;
return { prev_pos.line, static_cast<source_index>(prev_pos.column + 1u) };
return { prev_pos.line, static_cast<source_index>(prev_pos.column + fallback_offset) };
}
template <typename... T>
@ -223,7 +250,7 @@ namespace toml::impl
TOML_ERROR_CHECK();
if constexpr (sizeof...(T) == 0_sz)
TOML_ERROR( "An unspecified error occurred", current_position_or_assumed_next(), reader.source_path() );
TOML_ERROR( "An unspecified error occurred", current_position(1), reader.source_path() );
else
{
static constexpr auto buf_size = 512_sz;
@ -294,9 +321,9 @@ namespace toml::impl
(concatenator(std::forward<T>(args)), ...);
*ptr = '\0';
#if TOML_EXCEPTIONS
TOML_ERROR( buf, current_position_or_assumed_next(), reader.source_path() );
TOML_ERROR( buf, current_position(1), reader.source_path() );
#else
TOML_ERROR( std::string(buf, ptr - buf), current_position_or_assumed_next(), reader.source_path());
TOML_ERROR( std::string(buf, ptr - buf), current_position(1), reader.source_path());
#endif
}
}
@ -1123,8 +1150,8 @@ namespace toml::impl
}
#else
{
auto parse_result = std::from_chars(chars, chars + length, result);
switch (parse_result.ec)
auto fc_result = std::from_chars(chars, chars + length, result);
switch (fc_result.ec)
{
case std::errc{}: //ok
return result * sign;
@ -1298,8 +1325,8 @@ namespace toml::impl
// convert to double
TOML_GCC_ATTR(uninitialized) double result;
auto parse_result = std::from_chars(chars, chars + length, result, std::chars_format::hex);
switch (parse_result.ec)
auto fc_result = std::from_chars(chars, chars + length, result, std::chars_format::hex);
switch (fc_result.ec)
{
case std::errc{}: //ok
return result;
@ -1469,23 +1496,23 @@ namespace toml::impl
// otherwise invoke charconv
TOML_GCC_ATTR(uninitialized) uint64_t result;
auto parse_result = std::from_chars(chars, chars + length, result, base);
auto fc_result = std::from_chars(chars, chars + length, result, base);
if constexpr (traits::is_signed)
{
if (parse_result.ec == std::errc{} && (
if (fc_result.ec == std::errc{} && (
(sign < 0 && result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1ull)
|| (sign > 0 && result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()))
))
parse_result.ec = std::errc::result_out_of_range;
fc_result.ec = std::errc::result_out_of_range;
}
else
{
if (parse_result.ec == std::errc{} &&
if (fc_result.ec == std::errc{} &&
result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())
)
parse_result.ec = std::errc::result_out_of_range;
fc_result.ec = std::errc::result_out_of_range;
}
switch (parse_result.ec)
switch (fc_result.ec)
{
case std::errc{}: //ok
if constexpr (traits::is_signed)
@ -2286,7 +2313,7 @@ namespace toml::impl
TOML_ERROR_CHECK({});
}
val->source_ = { begin_pos, current_position_or_assumed_next(), reader.source_path() };
val->source_ = { begin_pos, current_position(1), reader.source_path() };
return val;
}
@ -2484,7 +2511,7 @@ namespace toml::impl
);
advance();
}
header_end_pos = current_position_or_assumed_next();
header_end_pos = current_position(1);
// handle the rest of the line after the header
consume_leading_whitespace();
@ -2726,8 +2753,7 @@ namespace toml::impl
}
while (cp);
auto eof_pos = current_position_or_assumed_next();
eof_pos.column++;
auto eof_pos = current_position(1);
root.source_.end = eof_pos;
if (current_table
&& current_table != &root
@ -2873,7 +2899,6 @@ namespace toml::impl
else if (*cp == U']')
{
advance();
arr->source_.end = current_position_or_assumed_next();
break;
}
@ -2976,7 +3001,6 @@ namespace toml::impl
}
advance();
tab->source_.end = current_position_or_assumed_next();
break;
}
@ -3023,12 +3047,29 @@ namespace toml::impl
namespace toml
{
/// \brief Parses a TOML document from a string view.
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns A TOML table if exceptions are in use,
/// or a parse_result detailing the parsing outcome if exceptions are disabled.
[[nodiscard]]
inline parse_result parse(std::string_view doc, std::string_view source_path = {}) TOML_MAY_THROW
{
return impl::parser{ impl::utf8_reader{ doc, source_path } };
}
/// \brief Parses a TOML document from a string view.
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
///
/// \returns A TOML table if exceptions are in use,
/// or a parse_result detailing the parsing outcome if exceptions are disabled.
[[nodiscard]]
inline parse_result parse(std::string_view doc, std::string&& source_path) TOML_MAY_THROW
{
@ -3037,12 +3078,28 @@ namespace toml
#if defined(__cpp_lib_char8_t)
/// \brief Parses a TOML document from a string view.
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns A TOML table if exceptions are in use,
/// or a parse_result detailing the parsing outcome if exceptions are disabled.
[[nodiscard]]
inline parse_result parse(std::u8string_view doc, std::string_view source_path = {}) TOML_MAY_THROW
{
return impl::parser{ impl::utf8_reader{ doc, source_path } };
}
/// \brief Parses a TOML document from a string view.
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
///
/// \returns A TOML table if exceptions are in use,
/// or a parse_result detailing the parsing outcome if exceptions are disabled.
[[nodiscard]]
inline parse_result parse(std::u8string_view doc, std::string&& source_path) TOML_MAY_THROW
{
@ -3051,6 +3108,16 @@ namespace toml
#endif
/// \brief Parses a TOML document from a stream.
///
/// \tparam CHAR The stream's underlying character type. Must be 1 byte in size.
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns A TOML table if exceptions are in use,
/// or a parse_result detailing the parsing outcome if exceptions are disabled.
template <typename CHAR>
[[nodiscard]]
inline parse_result parse(std::basic_istream<CHAR>& doc, std::string_view source_path = {}) TOML_MAY_THROW
@ -3063,6 +3130,14 @@ namespace toml
return impl::parser{ impl::utf8_reader{ doc, source_path } };
}
/// \brief Parses a TOML document from a stream.
///
/// \tparam CHAR The stream's underlying character type. Must be 1 byte in size.
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
///
/// \returns A TOML table if exceptions are in use,
/// or a parse_result detailing the parsing outcome if exceptions are disabled.
template <typename CHAR>
[[nodiscard]]
inline parse_result parse(std::basic_istream<CHAR>& doc, std::string&& source_path) TOML_MAY_THROW
@ -3074,4 +3149,33 @@ namespace toml
return impl::parser{ impl::utf8_reader{ doc, std::move(source_path) } };
}
/// \brief Parses a TOML document from a file.
///
/// \tparam CHAR The path's character type. Must be 1 byte in size.
/// \param file_path The TOML document to parse. Must be valid UTF-8.
///
/// \returns A TOML table if exceptions are in use,
/// or a parse_result detailing the parsing outcome if exceptions are disabled.
///
/// \remarks You must `#include <fstream>` to use this function (toml++
/// does not transitively include it for you).
template <typename CHAR>
inline parse_result parse_file(std::basic_string_view<CHAR> file_path) TOML_MAY_THROW
{
static_assert(
sizeof(CHAR) == 1,
"The path's character type must be 1 byte in size."
);
// Q: "why is this function templated??"
// A: I don't want to force users to drag in <fstream> if they're not going to do
// any parsing directly from files.
auto ifs = std::basic_ifstream<CHAR>{ file_path };
return parse(
ifs,
std::string_view{ reinterpret_cast<const char*>(file_path.data()), file_path.length() }
);
}
}

View File

@ -5,16 +5,23 @@ namespace toml::impl
{
// Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
// A: - I'm supporting C++20's char8_t as well; wrapping streams allows switching string modes transparently.
// - <charconv> is locale-independent.
// - I'm using <charconv> to format numerics. Faster and locale-independent.
// - I can avoid forcing users to drag in <sstream> and <iomanip>.
// Q: "there's a lot of reinterpret_casting here, is any of it UB?"
// A: - If the source string data is char and the output string is char8_t, then technically yes,
// but not in the other direction. I test in both modes on Clang, GCC and MSVC and have yet to
// see it actually causing an issue, but in the event it does present a problem it's not going to
// be a show-stopper since all it means is I need to do duplicate some code.
// - Strings in C++. Honestly.
template <typename CHAR1, typename CHAR2>
TOML_ALWAYS_INLINE
void print_to_stream(std::basic_string_view<CHAR1> str, std::basic_ostream<CHAR2>& stream) TOML_MAY_THROW
{
static_assert(sizeof(CHAR1) == 1);
static_assert(sizeof(CHAR2) == 1);
stream.write(str.data(), str.length());
stream.write(reinterpret_cast<const CHAR2*>(str.data()), str.length());
}
template <typename CHAR1, typename CHAR2>
@ -23,7 +30,7 @@ namespace toml::impl
{
static_assert(sizeof(CHAR1) == 1);
static_assert(sizeof(CHAR2) == 1);
stream.write(str.data(), str.length());
stream.write(reinterpret_cast<const CHAR2*>(str.data()), str.length());
}
template <typename CHAR>
@ -65,14 +72,14 @@ namespace toml::impl
template <typename T> inline constexpr size_t charconv_buffer_length = 0;
template <> inline constexpr size_t charconv_buffer_length<double> = 60;
template <> inline constexpr size_t charconv_buffer_length<float> = 40;
template <> inline constexpr size_t charconv_buffer_length<uint64_t> = 20; //strlen("18446744073709551615")
template <> inline constexpr size_t charconv_buffer_length<int64_t> = 20; //strlen("-9223372036854775808")
template <> inline constexpr size_t charconv_buffer_length<int32_t> = 11; //strlen("-2147483648")
template <> inline constexpr size_t charconv_buffer_length<int16_t> = 6; //strlen("-32768")
template <> inline constexpr size_t charconv_buffer_length<int8_t> = 4; //strlen("-128")
template <> inline constexpr size_t charconv_buffer_length<uint32_t> = 10; //strlen("4294967295")
template <> inline constexpr size_t charconv_buffer_length<uint16_t> = 5; //strlen("65535")
template <> inline constexpr size_t charconv_buffer_length<uint8_t> = 3; //strlen("255")
template <> inline constexpr size_t charconv_buffer_length<uint64_t> = 20; // strlen("18446744073709551615")
template <> inline constexpr size_t charconv_buffer_length<int64_t> = 20; // strlen("-9223372036854775808")
template <> inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")
template <> inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")
template <> inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
template <> inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")
template <> inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")
template <> inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
template <typename T, typename CHAR>
inline void print_integer_to_stream(T val, std::basic_ostream<CHAR>& stream) TOML_MAY_THROW
@ -245,7 +252,6 @@ namespace toml::impl
inline void print_to_stream(const toml::date_time& val, std::basic_ostream<CHAR>& stream) TOML_MAY_THROW
{
static_assert(sizeof(CHAR) == 1);
print_to_stream(val.date, stream);
print_to_stream('T', stream);
print_to_stream(val.time, stream);
@ -268,6 +274,8 @@ namespace toml::impl
print_to_stream(TOML_STRING_PREFIX("\\u007F"sv), stream);
else if (c == TOML_STRING_PREFIX('"')) TOML_UNLIKELY
print_to_stream(TOML_STRING_PREFIX("\\\""sv), stream);
else if (c == TOML_STRING_PREFIX('\\')) TOML_UNLIKELY
print_to_stream(TOML_STRING_PREFIX("\\\\"sv), stream);
else
print_to_stream(c, stream);
}
@ -275,3 +283,45 @@ namespace toml::impl
TOML_POP_WARNINGS
}
namespace toml
{
template <typename CHAR>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const source_position& rhs)
TOML_MAY_THROW
{
static_assert(
sizeof(CHAR) == 1,
"The stream's underlying character type must be 1 byte in size."
);
impl::print_to_stream("line "sv, lhs);
impl::print_to_stream(rhs.line, lhs);
impl::print_to_stream(", column ", lhs);
impl::print_to_stream(rhs.column, lhs);
return lhs;
}
template <typename CHAR>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const source_region& rhs)
TOML_MAY_THROW
{
static_assert(
sizeof(CHAR) == 1,
"The stream's underlying character type must be 1 byte in size."
);
lhs << rhs.begin;
if (rhs.begin < rhs.end
&& (rhs.end.line != rhs.begin.line || rhs.end.column > rhs.begin.column + source_index{1}))
{
impl::print_to_stream(" - "sv, lhs);
lhs << rhs.end;
}
if (rhs.path)
{
impl::print_to_stream(" of '"sv, lhs);
impl::print_to_stream(*rhs.path, lhs);
impl::print_to_stream('\'', lhs);
}
return lhs;
}
}

View File

@ -4,7 +4,7 @@
namespace toml::impl
{
template <bool is_const>
struct table_iterator_ref_proxy final
struct table_proxy_pair final
{
using value_type = std::conditional_t<is_const, const node, node>;
@ -38,7 +38,8 @@ namespace toml::impl
table_iterator() noexcept = default;
using reference = table_iterator_ref_proxy<is_const>;
using reference = table_proxy_pair<is_const>;
using difference_type = ptrdiff_t;
table_iterator& operator++() noexcept // ++pre
{
@ -83,10 +84,46 @@ namespace toml::impl
return lhs.raw_ != rhs.raw_;
}
};
struct table_init_pair final
{
string key;
std::unique_ptr<node> value;
template <typename T>
table_init_pair(string&& k, T && v) noexcept
: key{ std::move(k) },
value{ make_node(std::forward<T>(v)) }
{}
template <typename T>
table_init_pair(string_view k, T&& v) noexcept
: key{ k },
value{ make_node(std::forward<T>(v)) }
{}
template <typename T>
table_init_pair(const string_char* k, T&& v) noexcept
: key{ k },
value{ make_node(std::forward<T>(v)) }
{}
};
}
namespace toml
{
/// \brief A TOML table.
///
/// \remarks The interface of this type is modeled after std::map, with some
/// additional considerations made for the heterogeneous nature of a
/// TOML table, and for the removal of some cruft (the public interface of
/// std::map is, simply, _a hot mess_).
///
/// \detail \cpp
/// // example
/// // code
/// // here
/// \ecpp
class table final
: public node
{
@ -99,12 +136,56 @@ namespace toml
public:
/// \brief A BidirectionalIterator for iterating over the key-value pairs in a table.
using iterator = impl::table_iterator<false>;
/// \brief A const BidirectionalIterator for iterating over the key-value pairs in a table.
using const_iterator = impl::table_iterator<true>;
/// \brief Default constructor.
TOML_NODISCARD_CTOR
table() noexcept {}
/// \brief Constructs a table with one or more initial key-value pairs.
///
/// \detail \cpp
/// auto tbl = toml::table{{ //double braces required :( - see Remarks
/// { "foo", 1 },
/// { "bar", 2.0 },
/// { "kek", "three" }
/// }};
/// std::cout << tbl << std::endl;
///
/// // output:
/// // { foo = 1, bar = 2.0, kek = "three" }
/// \ecpp
///
/// \tparam N Number of key-value pairs used to initialize the table.
/// \param arr An array of key-value pairs used to initialize the table.
///
/// \remarks C++ std::initializer_lists represent their member elements as
/// const even if the list's value type is non-const. This is great for
/// compiler writers, I guess, but pretty annoying for me since
/// TOML key-value pairs are polymorphic. This means that for the
/// human-friendly braced init list syntax to work I can't use
/// std::initializer_list and must instead invent an annoying proxy type,
/// which means an extra level of nesting.
/// <br><br>
/// See https://en.cppreference.com/w/cpp/utility/initializer_list
/// if you'd like to be more annoyed about this.
template <size_t N>
TOML_NODISCARD_CTOR
explicit table(impl::table_init_pair(&& arr)[N]) noexcept
{
for (auto&& kvp : arr)
{
values.insert_or_assign(
std::move(kvp.key),
std::move(kvp.value)
);
}
}
/// \brief Move constructor.
TOML_NODISCARD_CTOR
table(table&& other) noexcept
: node{ std::move(other) },
@ -112,6 +193,7 @@ namespace toml
inline_ { other.inline_ }
{}
/// \brief Move-assignment operator.
table& operator= (table&& rhs) noexcept
{
node::operator=(std::move(rhs));
@ -120,41 +202,268 @@ namespace toml
return *this;
}
/// \brief Always returns `node_type::table` for table nodes.
[[nodiscard]] node_type type() const noexcept override { return node_type::table; }
/// \brief Always returns `true` for table nodes.
[[nodiscard]] bool is_table() const noexcept override { return true; }
/// \brief Always returns `false` for table nodes.
[[nodiscard]] bool is_array() const noexcept override { return false; }
/// \brief Always returns `false` for table nodes.
[[nodiscard]] bool is_value() const noexcept override { return false; }
[[nodiscard]] bool is_inline() const noexcept { return inline_; }
[[nodiscard]] table* as_table() noexcept override { return this; }
[[nodiscard]] const table* as_table() const noexcept override { return this; }
[[nodiscard]] bool empty() const noexcept { return values.empty(); }
[[nodiscard]] size_t size() const noexcept { return values.size(); }
/// \brief Returns true if this table is an inline table.
///
/// \remarks Runtime-constructed tables (i.e. those not created during
/// parsing) are not inline by default.
[[nodiscard]] bool is_inline() const noexcept { return inline_; }
/// \brief Sets whether this table is a TOML inline table.
///
/// \detail \cpp
/// auto tbl = toml::table{{
/// { "a", 1 },
/// { "b", 2 },
/// { "c", 3 },
/// { "d", toml::table{{ { "e", 4 } }} }
/// }};
/// std::cout << "is inline? "sv << tbl.is_inline() << std::endl;
/// std::cout << tbl << std::endl << std::endl;
///
/// tbl.is_inline(!tbl.is_inline());
/// std::cout << "is inline? "sv << tbl.is_inline() << std::endl;
/// std::cout << tbl << std::endl;
///
/// // example output:
/// // is inline? false
/// // a = 1
/// // b = 2
/// // c = 3
/// // [d]
/// // e = 4
/// //
/// // is inline? true
/// // { a = 1, b = 2, c = 3, d = { e = 4 } }
/// \ecpp
///
/// \remarks A table being 'inline' is only relevent during printing;
/// it has no effect on the general functionality of the table
/// object.
///
/// \param val The new value for 'inline'.
void is_inline(bool val) noexcept { inline_ = val; }
/// \brief Gets a node_view for the selected key-value pair.
///
/// \param key The key used for the lookup.
///
/// \returns A node_view.
///
/// \remarks std::map::operator[]'s behaviour of constructing an element at a key if it
/// didn't exist is terribad, so I've deliberately chosen not to emulate that
/// insane bug-factory. This Is Not An Error (tm).
///
/// \see toml::node_view
[[nodiscard]] inline node_view<table> operator[] (string_view key) noexcept;
/// \brief Gets a node_view for the selected key-value pair (const overload).
[[nodiscard]] inline node_view<const table> operator[] (string_view key) const noexcept;
/// \brief Returns an iterator to the first key-value pair.
[[nodiscard]] iterator begin() noexcept { return { values.begin() }; }
/// \brief Returns an iterator to the first key-value pair.
[[nodiscard]] const_iterator begin() const noexcept { return { values.begin() }; }
/// \brief Returns an iterator to the first key-value pair.
[[nodiscard]] const_iterator cbegin() const noexcept { return { values.cbegin() }; }
/// \brief Returns an iterator to one-past-the-last key-value pair.
[[nodiscard]] iterator end() noexcept { return { values.end() }; }
[[nodiscard]] const_iterator end() const noexcept { return { values.end() };}
/// \brief Returns an iterator to one-past-the-last key-value pair.
[[nodiscard]] const_iterator end() const noexcept { return { values.end() }; }
/// \brief Returns an iterator to one-past-the-last key-value pair.
[[nodiscard]] const_iterator cend() const noexcept { return { values.cend() }; }
/// \brief Returns true if the table is empty.
[[nodiscard]] bool empty() const noexcept { return values.empty(); }
/// \brief Returns the number of key-value pairs in the table.
[[nodiscard]] size_t size() const noexcept { return values.size(); }
/// \brief Removes all key-value pairs from the table.
void clear() noexcept { values.clear(); }
template <typename K, typename V, typename = std::enable_if_t<
std::is_convertible_v<K&&, string_view>
>>
std::pair<iterator, bool> insert(K&& key, V&& val) noexcept
{
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
{
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
return { ipos, true };
}
return { ipos, false };
}
template <typename ITER, typename = std::enable_if_t<
!std::is_convertible_v<ITER&&, string_view>
>>
void insert(ITER first, ITER last) noexcept
{
if (first == last)
return;
for (auto it = first; it != last; it++)
{
if constexpr (std::is_rvalue_reference_v<decltype(*it)>)
insert(std::move((*it).first), std::move((*it).second));
else
insert((*it).first, (*it).second);
}
}
template <typename K, typename V>
std::pair<iterator, bool> insert_or_assign(K&& key, V&& val) noexcept
{
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
{
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
return { ipos, true };
}
else
{
(*ipos).second.reset(impl::make_node(std::forward<V>(val)));
return { ipos, false };
}
}
template <typename U, typename K, typename... V>
std::pair<iterator, bool> emplace(K&& key, V&&... args) noexcept
{
using type = impl::unwrapped<U>;
static_assert(
impl::is_value_or_node<type>,
"Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array"
);
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
{
ipos = values.emplace_hint(
ipos,
std::forward<K>(key),
new node_of<type>{ std::forward<V>(args)... }
);
return { ipos, true };
}
return { ipos, false };
}
/// \brief Removes the specified key-value pair from the table.
///
/// \detail \cpp
/// auto tbl = toml::table{{
/// { "a", 1 },
/// { "b", 2 },
/// { "c", 3 }
/// }};
/// std::cout << tbl << std::endl;
///
/// tbl.erase(tbl.begin() + 1);
/// std::cout << tbl << std::endl;
///
/// // output:
/// // { a = 1, b = 2, c = 3 }
/// // { a = 1, c = 3 }
/// \ecpp
///
/// \param pos Iterator to the key-value pair being erased.
///
/// \returns Iterator to the first key-value pair immediately following the removed key-value pair.
iterator erase(iterator pos) noexcept
{
return { values.erase(pos.raw_) };
}
/// \brief Removes the specified key-value pair from the table (const iterator overload).
///
/// \detail \cpp
/// auto tbl = toml::table{{
/// { "a", 1 },
/// { "b", 2 },
/// { "c", 3 }
/// }};
/// std::cout << tbl << std::endl;
///
/// tbl.erase(tbl.cbegin() + 1);
/// std::cout << tbl << std::endl;
///
/// // output:
/// // { a = 1, b = 2, c = 3 }
/// // { a = 1, c = 3 }
/// \ecpp
///
/// \param pos Iterator to the key-value pair being erased.
///
/// \returns Iterator to the first key-value pair immediately following the removed key-value pair.
iterator erase(const_iterator pos) noexcept
{
return { values.erase(pos.raw_) };
}
/// \brief Removes the key-value pairs in the range [first, last) from the table.
///
/// \detail \cpp
/// auto tbl = toml::table{{
/// { "a", 1 },
/// { "b", "bad" },
/// { "c", "karma" },
/// { "d", 2 }
/// }};
/// std::cout << tbl << std::endl;
///
/// tbl.erase(tbl.cbegin() + 1, tbl.cbegin() + 3);
/// std::cout << tbl << std::endl;
///
/// // output:
/// // { a = 1, b = "bad", c = "karma", d = 2 }
/// // { a = 1, d = 2 }
/// \ecpp
///
/// \param first Iterator to the first key-value pair being erased.
/// \param last Iterator to the one-past-the-last key-value pair being erased.
///
/// \returns Iterator to the first key-value pair immediately following the last removed key-value pair.
iterator erase(const_iterator first, const_iterator last) noexcept
{
return { values.erase(first.raw_, last.raw_) };
}
/// \brief Removes the value with the given key from the table.
///
/// \detail \cpp
/// auto tbl = toml::table{{
/// { "a", 1 },
/// { "b", 2 },
/// { "c", 3 }
/// }};
/// std::cout << tbl << std::endl;
///
/// std::cout << tbl.erase("b") << std::endl;
/// std::cout << tbl.erase("not an existing key") << std::endl;
/// std::cout << tbl << std::endl;
///
/// // output:
/// // { a = 1, b = 2, c = 3 }
/// // true
/// // false
/// // { a = 1, c = 3 }
/// \ecpp
///
/// \param key Key to erase.
///
/// \returns True if any values with matching keys were found and erased.
bool erase(string_view key) noexcept
{
if (auto it = values.find(key); it != values.end())
@ -204,16 +513,42 @@ namespace toml
[[nodiscard]] node* get(string_view key) noexcept { return do_get(values, key); }
[[nodiscard]] const node* get(string_view key) const noexcept { return do_get(values, key); }
[[nodiscard]] iterator find(string_view key) noexcept { return { values.find(key) }; }
[[nodiscard]] const_iterator find(string_view key) const noexcept { return { values.find(key) }; }
/// \brief Gets the node at a specific key if it is a particular type.
///
/// \detail \cpp
/// auto tbl = toml::table{{
/// { "a", 42, },
/// { "b", "is the meaning of life, apparently." }
/// }};
/// if (auto val = arr.get_as<int64_t>("a"))
/// std::cout << node [\"a\"] was an integer with value "sv << **val << std::endl;
///
/// // output:
/// // node ["a"] was an integer with value 42
/// \ecpp
///
/// \tparam T The node's type.
/// \param key The node's key.
///
/// \returns A pointer to the selected node if it was of the specified type, or nullptr.
template <typename T>
[[nodiscard]] node_of<T>* get_as(string_view key) noexcept { return do_get_as<T>(values, key); }
/// \brief Gets the node at a specific key if it is a particular type (const overload).
///
/// \tparam T The node's type.
/// \param key The node's key.
///
/// \returns A pointer to the selected node if it was of the specified type, or nullptr.
template <typename T>
[[nodiscard]] const node_of<T>* get_as(string_view key) const noexcept { return do_get_as<T>(values, key); }
/// \brief Returns true if the table contains a node at the given key.
[[nodiscard]] bool contains(string_view key) const noexcept { return do_contains(values, key); }
[[nodiscard]] inline node_view<table> operator[] (string_view) noexcept;
[[nodiscard]] inline node_view<const table> operator[] (string_view) const noexcept;
/// \brief Equality operator.
///
/// \param lhs The LHS table.

View File

@ -6,15 +6,19 @@
namespace toml::impl
{
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept
{
return codepoint == U'\t' || codepoint == U' ';
}
[[nodiscard]]
constexpr bool is_whitespace(char32_t codepoint) noexcept
constexpr bool is_unicode_whitespace(char32_t codepoint) noexcept
{
// see: https://en.wikipedia.org/wiki/Whitespace_character#Unicode
// (characters that don't say "is a line-break")
return codepoint == U'\t'
|| codepoint == U' '
|| codepoint == U'\u00A0' // no-break space
return codepoint == U'\u00A0' // no-break space
|| codepoint == U'\u1680' // ogham space mark
|| (codepoint >= U'\u2000' && codepoint <= U'\u200A') // em quad -> hair space
|| codepoint == U'\u202F' // narrow no-break space
@ -23,22 +27,39 @@ namespace toml::impl
;
}
template <bool CR = true>
[[nodiscard]]
constexpr bool is_line_break(char32_t codepoint) noexcept
constexpr bool is_whitespace(char32_t codepoint) noexcept
{
return is_ascii_whitespace(codepoint) || is_unicode_whitespace(codepoint);
}
template <bool CR = true>
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_ascii_line_break(char32_t codepoint) noexcept
{
constexpr auto low_range_end = CR ? U'\r' : U'\f';
return (codepoint >= U'\n' && codepoint <= low_range_end);
}
[[nodiscard]]
constexpr bool is_unicode_line_break(char32_t codepoint) noexcept
{
// see https://en.wikipedia.org/wiki/Whitespace_character#Unicode
// (characters that say "is a line-break")
constexpr auto low_range_end = CR ? U'\r' : U'\f';
return (codepoint >= U'\n' && codepoint <= low_range_end)
|| codepoint == U'\u0085' // next line
return codepoint == U'\u0085' // next line
|| codepoint == U'\u2028' // line separator
|| codepoint == U'\u2029' // paragraph separator
;
}
template <bool CR = true>
[[nodiscard]]
constexpr bool is_line_break(char32_t codepoint) noexcept
{
return is_ascii_line_break<CR>(codepoint) || is_unicode_line_break(codepoint);
}
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_string_delimiter(char32_t codepoint) noexcept
{
@ -75,7 +96,8 @@ namespace toml::impl
{
return (codepoint >= U'a' && codepoint <= U'f')
|| (codepoint >= U'A' && codepoint <= U'F')
|| is_decimal_digit(codepoint);
|| is_decimal_digit(codepoint)
;
}
[[nodiscard]]
@ -106,38 +128,22 @@ namespace toml::impl
[[nodiscard]]
constexpr bool is_value_terminator(char32_t codepoint) noexcept
{
return is_line_break(codepoint)
|| is_whitespace(codepoint)
return is_ascii_line_break(codepoint)
|| is_ascii_whitespace(codepoint)
|| codepoint == U']'
|| codepoint == U'}'
|| codepoint == U','
|| codepoint == U'#'
|| is_unicode_line_break(codepoint)
|| is_unicode_whitespace(codepoint)
;
}
struct utf8_decoder final
{
// This decoder is based on code from here: http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
//
// License:
//
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies
// or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//# This decoder is based on the 'Flexible and Economical UTF-8 Decoder'
//# Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//# See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
uint_least32_t state{};
char32_t codepoint{};
@ -211,9 +217,9 @@ namespace toml::impl
: source{ sv }
{
if (source.length() >= 3_sz
&& static_cast<uint8_t>(source[0]) == 0xEF_u8
&& static_cast<uint8_t>(source[1]) == 0xBB_u8
&& static_cast<uint8_t>(source[2]) == 0xBF_u8)
&& static_cast<uint8_t>(source[0]) == static_cast<uint8_t>(0xEFu)
&& static_cast<uint8_t>(source[1]) == static_cast<uint8_t>(0xBBu)
&& static_cast<uint8_t>(source[2]) == static_cast<uint8_t>(0xBFu))
{
position += 3_sz;
}
@ -255,9 +261,9 @@ namespace toml::impl
if (*source)
{
static constexpr uint8_t bom[] {
0xEF_u8,
0xBB_u8,
0xBF_u8
0xEF,
0xBB,
0xBF
};
using stream_traits = typename std::remove_pointer_t<decltype(source)>::traits_type;
@ -472,7 +478,6 @@ namespace toml::impl
}
}
#if !TOML_EXCEPTIONS
[[nodiscard]]

View File

@ -124,11 +124,11 @@ namespace toml
[[nodiscard]] const T& operator* () const& noexcept { return val_; }
/// \brief Returns a reference to the underlying value.
[[nodiscard]] operator T& () & noexcept { return val_; }
[[nodiscard]] explicit operator T& () & noexcept { return val_; }
/// \brief Returns a reference to the underlying value (rvalue overload).
[[nodiscard]] operator T&& () && noexcept { return std::move(val_); }
[[nodiscard]] explicit operator T&& () && noexcept { return std::move(val_); }
/// \brief Returns a reference to the underlying value (const overload).
[[nodiscard]] operator const T& () const& noexcept { return val_; }
[[nodiscard]] explicit operator const T& () const& noexcept { return val_; }
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const value& rhs) TOML_MAY_THROW
@ -277,7 +277,12 @@ namespace toml
}
};
template <size_t N> value(const string_char(&)[N]) -> value<string>;
template <size_t N> value(const string_char(&&)[N]) -> value<string>;
value(const string_char*) -> value<string>;
template <size_t N> value(string_char(&)[N]) -> value<string>;
template <size_t N> value(string_char(&&)[N]) -> value<string>;
value(string_char*) -> value<string>;
value(string_view) -> value<string>;
value(string) -> value<string>;
value(bool) -> value<bool>;
@ -293,4 +298,7 @@ namespace toml
#ifdef TOML_SMALL_FLOAT_TYPE
value(TOML_SMALL_FLOAT_TYPE) -> value<double>;
#endif
#ifdef TOML_SMALL_INT_TYPE
value(TOML_SMALL_INT_TYPE) -> value<int64_t>;
#endif
}

View File

@ -235,14 +235,14 @@ class NavBarFix(object):
# changes any links to index.html to link to annotated.html instead (index.html is blank/unused)
# changes any links to index.html to link to namespacetoml.html instead (index.html is blank/unused)
class IndexHrefFix(object):
def __call__(self, file, doc):
links = doc.body('a', href='index.html')
if (len(links) > 0):
for link in links:
link['href'] = 'annotated.html'
link['href'] = 'namespacetoml.html'
return True
return False
@ -496,6 +496,15 @@ class ExtDocLinksFix(object):
(r'std::(?:basic_|w)?stringstreams?', 'https://en.cppreference.com/w/cpp/io/basic_stringstream'),
(r'std::(?:basic_|w|u8)?string_views?', 'https://en.cppreference.com/w/cpp/string/basic_string_view'),
(r'std::(?:basic_|w|u8)?strings?', 'https://en.cppreference.com/w/cpp/string/basic_string'),
(r'(?:<|&lt;)fstream(?:>|&gt;)', 'https://en.cppreference.com/w/cpp/header/fstream'),
(r'(?:<|&lt;)sstream(?:>|&gt;)', 'https://en.cppreference.com/w/cpp/header/sstream'),
(r'(?:<|&lt;)iostream(?:>|&gt;)', 'https://en.cppreference.com/w/cpp/header/iostream'),
(r'(?:<|&lt;)iosfwd(?:>|&gt;)', 'https://en.cppreference.com/w/cpp/header/iosfwd'),
(r'(?:<|&lt;)string(?:>|&gt;)', 'https://en.cppreference.com/w/cpp/header/string'),
(r'(?:<|&lt;)string_view(?:>|&gt;)', 'https://en.cppreference.com/w/cpp/header/string_view'),
(r'char(?:8|16|32)_ts?', 'https://en.cppreference.com/w/cpp/language/types'),
(r'std::is_(?:nothrow_)?convertible(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_convertible'),
(r'std::is_same(?:_v)?', 'https://en.cppreference.com/w/cpp/types/is_same'),
@ -514,6 +523,7 @@ class ExtDocLinksFix(object):
(r'std::remove_cv(?:_t)?', 'https://en.cppreference.com/w/cpp/types/remove_cv'),
(r'std::exceptions?', 'https://en.cppreference.com/w/cpp/error/exception'),
(r'std::runtime_errors?', 'https://en.cppreference.com/w/cpp/error/runtime_error'),
(r'std::initializer_lists?', 'https://en.cppreference.com/w/cpp/utility/initializer_list'),
(
r'(?:L?P)?(?:'
+ r'D?WORD(?:32|64|_PTR)?|HANDLE|HMODULE|BOOL(?:EAN)?'
@ -525,7 +535,14 @@ class ExtDocLinksFix(object):
(
r'(?:__INTELLISENSE__|_MSC_FULL_VER|_MSC_VER|_MSVC_LANG|_WIN32|_WIN64)',
'https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019'
)
),
(r'(?:Legacy)?InputIterators?', 'https://en.cppreference.com/w/cpp/named_req/InputIterator'),
(r'(?:Legacy)?OutputIterators?', 'https://en.cppreference.com/w/cpp/named_req/OutputIterator'),
(r'(?:Legacy)?ForwardIterators?', 'https://en.cppreference.com/w/cpp/named_req/ForwardIterator'),
(r'(?:Legacy)?BidirectionalIterators?', 'https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator'),
(r'(?:Legacy)?RandomAccessIterators?', 'https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator'),
(r'(?:Legacy)?ContiguousIterators?', 'https://en.cppreference.com/w/cpp/named_req/ContiguousIterator'),
(r'(?:Legacy)?Iterators?', 'https://en.cppreference.com/w/cpp/named_req/Iterator')
]
__allowedNames = ['dd', 'p', 'dt', 'h3', 'td']
@ -709,7 +726,7 @@ def main():
fixes = [
CustomTagsFix()
# , NavBarFix()
# , IndexHrefFix()
, IndexHrefFix()
, ModifiersFix1()
, ModifiersFix2()
, InlineNamespaceFix1()
@ -732,6 +749,23 @@ def main():
if _threadError:
sys.exit(1)
# replace index.html with a redirect
index_html_path = path.join(html_dir, 'index.html')
with open(index_html_path,'w', encoding='utf-8', newline='\n') as output_file:
print('''<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Refresh" content="0; url=./namespacetoml.html" />
</head>
<body>
<p>Please follow <a href="namespacetoml.html">this link</a>.</p>
</body>
</html>
''',
file=output_file
)
if __name__ == '__main__':

View File

@ -81,13 +81,27 @@ def main():
source_text = re.sub('(?:///[<].*?)\n', '\n', source_text, 0, re.I | re.M) # remove inline doxy briefs
source_text = re.sub('\n(?:[ \t]*\n[ \t]*)+\n', '\n\n', source_text, 0, re.I | re.M) # remove double newlines
source_text = re.sub('([^ \t])[ \t]+\n', '\\1\n', source_text, 0, re.I | re.M) # remove trailing whitespace
return_type_pattern \
= r'(?:' \
+ r'(?:\[\[nodiscard\]\]\s*)?' \
+ r'(?:(?:friend|explicit|virtual|inline|const|operator)\s+)*' \
+ r'(?:' \
+ r'bool|int64_t|(?:const_)?iterator|double|void' \
+ r'|node(?:_(?:view|of)<.+?>|)?|table|array|value(?:<.+?>)?' \
+ r'|T|U|parse_(?:error|result)' \
+ r')' \
+ r'(?:\s*[&*]+)?' \
+ r'(?:\s*[(]\s*[)])?' \
+ r'\s+' \
+ r')'
blank_lines_between_returns_pattern = '({}[^\n]+)\n\n([ \t]*{})'.format(return_type_pattern, return_type_pattern)
for i in range(0, 5): # remove blank lines between simple one-liner definitions
source_text = re.sub('(using .+?;)\n\n([ \t]*using)', '\\1\n\\2', source_text, 0, re.I | re.M)
source_text = re.sub(
'([a-zA-Z_][a-zA-Z0-9_]*[ \t]+[a-zA-Z_][a-zA-Z0-9_]*[ \t]*;)' \
+ '\n\n([ \t]*[a-zA-Z_][a-zA-Z0-9_]*[ \t]+[a-zA-Z_][a-zA-Z0-9_]*[ \t]*;)', '\\1\n\\2',
source_text, 0, re.I | re.M)
source_text = re.sub('(\[\[nodiscard\]\][^\n]+)\n\n([ \t]*\[\[nodiscard\]\])', '\\1\n\\2', source_text, 0, re.I | re.M)
source_text = re.sub(blank_lines_between_returns_pattern, '\\1\n\\2', source_text, 0, re.I | re.M)
source_text = source_text.strip()
@ -121,6 +135,15 @@ TOML language specification:
Latest: https://github.com/toml-lang/toml/blob/master/README.md
v0.5.0: https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md''')
preamble.append(read_all_text_from_file(path.join(get_script_folder(), '..', 'LICENSE')))
preamble.append('''
UTF-8 decoding is performed using a derivative of Bjoern Hoehrmann's 'Flexible and Economical UTF-8 Decoder'
See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
{}
'''.format(
read_all_text_from_file(path.join(get_script_folder(), '..', 'LICENSE-utf8-decoder'))
))
# write the output file
output_file_path = path.join(get_script_folder(), '..', 'toml.hpp')

View File

@ -1,40 +0,0 @@
#include "tests.h"
TEST_CASE("lifetime - tables")
{
static constexpr auto filename = "foo.toml"sv;
parsing_should_succeed(
S(R"(test = { val1 = "foo" })"sv),
[&](table&& tbl) noexcept
{
CHECK(tbl.source().begin == source_position{ 1, 1 });
CHECK(tbl.source().end == source_position{ 1, 25 });
CHECK(tbl.source().path);
CHECK(*tbl.source().path == filename);
CHECK(tbl.size() == 1_sz);
REQUIRE(tbl[S("test")].as<table>());
CHECK(tbl[S("test")].as<table>()->size() == 1_sz);
CHECK(tbl[S("test")][S("val1")] == S("foo"sv));
table test_table;
CHECK(test_table.source().begin == source_position{});
CHECK(test_table.source().end == source_position{});
CHECK(!test_table.source().path);
CHECK(test_table.size() == 0_sz);
CHECK(!test_table[S("test")].as<table>());
test_table = std::move(tbl);
CHECK(test_table.source().begin == source_position{ 1, 1 });
CHECK(test_table.source().end == source_position{ 1, 25 });
CHECK(test_table.source().path);
CHECK(*test_table.source().path == filename);
CHECK(test_table.size() == 1_sz);
REQUIRE(test_table[S("test")].as<table>());
CHECK(test_table[S("test")].as<table>()->size() == 1_sz);
CHECK(test_table[S("test")][S("val1")] == S("foo"sv));
},
filename
);
}

View File

@ -0,0 +1,214 @@
#include "tests.h"
TEST_CASE("arrays - moving")
{
static constexpr auto filename = "foo.toml"sv;
parsing_should_succeed(
S(R"(test = [ "foo" ])"sv),
[&](table&& tbl) noexcept
{
CHECK(tbl.source().begin == source_position{ 1, 1 });
CHECK(tbl.source().end == source_position{ 1, 17 });
CHECK(tbl.source().path);
CHECK(*tbl.source().path == filename);
CHECK(tbl.size() == 1_sz);
auto arr1 = tbl[S("test")].as<array>();
REQUIRE(arr1);
CHECK(arr1->size() == 1_sz);
CHECK(arr1->source().begin == source_position{ 1, 8 });
CHECK(arr1->source().end == source_position{ 1, 17 });
CHECK(arr1->source().path);
CHECK(*arr1->source().path == filename);
REQUIRE(arr1->get_as<string>(0_sz));
CHECK(*arr1->get_as<string>(0_sz) == S("foo"sv));
array arr2;
CHECK(arr2.source().begin == source_position{});
CHECK(arr2.source().end == source_position{});
CHECK(!arr2.source().path);
CHECK(arr2.size() == 0_sz);
arr2 = std::move(*arr1);
CHECK(arr2.source().begin == source_position{ 1, 8 });
CHECK(arr2.source().end == source_position{ 1, 17 });
CHECK(arr2.source().path);
CHECK(*arr2.source().path == filename);
CHECK(arr2.size() == 1_sz);
REQUIRE(arr2.get_as<string>(0_sz));
CHECK(*arr2.get_as<string>(0_sz) == S("foo"sv));
CHECK(arr1->source().begin == source_position{});
CHECK(arr1->source().end == source_position{});
CHECK(!arr1->source().path);
CHECK(arr1->size() == 0_sz);
},
filename
);
}
TEST_CASE("arrays - construction")
{
{
array arr;
CHECK(arr.size() == 0_sz);
CHECK(arr.empty());
CHECK(arr.begin() == arr.end());
CHECK(arr.cbegin() == arr.cend());
CHECK(arr.source().begin == source_position{});
CHECK(arr.source().end == source_position{});
CHECK(!arr.source().path);
CHECK(!arr.is_homogeneous());
}
{
array arr{ 42 };
CHECK(arr.size() == 1_sz);
CHECK(!arr.empty());
CHECK(arr.begin() != arr.end());
CHECK(arr.cbegin() != arr.cend());
REQUIRE(arr.get_as<int64_t>(0_sz));
CHECK(*arr.get_as<int64_t>(0_sz) == 42);
CHECK(arr.is_homogeneous());
CHECK(arr.is_homogeneous<int64_t>());
}
{
array arr{ 42, S("test"sv), 10.0f, array{}, value{ 3 } };
CHECK(arr.size() == 5_sz);
CHECK(!arr.empty());
REQUIRE(arr.get_as<int64_t>(0_sz));
CHECK(*arr.get_as<int64_t>(0_sz) == 42);
REQUIRE(arr.get_as<string>(1_sz));
CHECK(*arr.get_as<string>(1_sz) == S("test"sv));
REQUIRE(arr.get_as<double>(2_sz));
CHECK(*arr.get_as<double>(2_sz) == 10.0);
REQUIRE(arr.get_as<array>(3_sz));
REQUIRE(arr.get_as<int64_t>(4_sz));
CHECK(*arr.get_as<int64_t>(4_sz) == 3);
CHECK(!arr.is_homogeneous());
}
}
TEST_CASE("arrays - equality")
{
array arr1{ 1, 2, 3 };
CHECK(arr1 == arr1);
array arr2{ 1, 2, 3 };
CHECK(arr1 == arr2);
array arr3{ 1, 2 };
CHECK(arr1 != arr3);
array arr4{ 1, 2, 3, 4 };
CHECK(arr1 != arr4);
array arr5{ 1, 2, 3.0 };
CHECK(arr1 != arr5);
array arr6{};
CHECK(arr1 != arr6);
CHECK(arr6 == arr6);
array arr7{};
CHECK(arr6 == arr7);
}
TEST_CASE("arrays - insertion and erasure")
{
array arr;
auto it = arr.insert(arr.cbegin(), 42);
CHECK(it == arr.begin());
CHECK(arr.size() == 1_sz);
CHECK(!arr.empty());
REQUIRE(arr.get_as<int64_t>(0_sz));
CHECK(*arr.get_as<int64_t>(0_sz) == 42);
REQUIRE(arr == array{ 42 });
it = arr.insert(arr.cend(), 3, 10.0f);
CHECK(it == arr.begin() + 1);
CHECK(arr.size() == 4_sz);
REQUIRE(arr.get_as<double>(1_sz));
CHECK(*arr.get_as<double>(1_sz) == 10.0);
REQUIRE(arr.get_as<double>(2_sz));
CHECK(*arr.get_as<double>(2_sz) == 10.0);
REQUIRE(arr.get_as<double>(3_sz));
CHECK(*arr.get_as<double>(3_sz) == 10.0);
REQUIRE(arr == array{ 42, 10.0, 10.0, 10.0 });
it = arr.emplace<array>(arr.cbegin(), 1, 2, 3);
CHECK(it == arr.begin());
CHECK(arr.size() == 5_sz);
REQUIRE(arr.get_as<array>(0_sz));
CHECK(arr.get_as<array>(0_sz)->size() == 3_sz);
REQUIRE(arr == array{ array{ 1, 2, 3 }, 42, 10.0, 10.0, 10.0 });
{
decltype(auto) val = arr.push_back(S("test"sv));
CHECK(arr.size() == 6_sz);
REQUIRE(arr.get_as<string>(5_sz));
CHECK(*arr.get_as<string>(5_sz) == S("test"sv));
CHECK(val == S("test"sv));
CHECK(&val == &arr.back());
REQUIRE(arr == array{ array{ 1, 2, 3 }, 42, 10.0, 10.0, 10.0, S("test"sv) });
}
{
decltype(auto) val = arr.emplace_back<string>(S("test2"sv));
CHECK(arr.size() == 7_sz);
REQUIRE(arr.get_as<string>(6_sz));
CHECK(*arr.get_as<string>(6_sz) == S("test2"sv));
CHECK(val == S("test2"sv));
CHECK(&val == &arr.back());
REQUIRE(arr == array{ array{ 1, 2, 3 }, 42, 10.0, 10.0, 10.0, S("test"sv), S("test2"sv) });
}
it = arr.erase(arr.cbegin());
REQUIRE(arr == array{ 42, 10.0, 10.0, 10.0, S("test"sv), S("test2"sv) });
CHECK(it == arr.begin());
CHECK(arr.size() == 6_sz);
it = arr.erase(arr.cbegin() + 2, arr.cbegin() + 4);
REQUIRE(arr == array{ 42, 10.0, S("test"sv), S("test2"sv) });
CHECK(it == arr.begin() + 2);
CHECK(arr.size() == 4_sz);
arr.pop_back();
REQUIRE(arr == array{ 42, 10.0, S("test"sv) });
CHECK(arr.size() == 3_sz);
arr.clear();
REQUIRE(arr == array{});
CHECK(arr.size() == 0_sz);
CHECK(arr.empty());
}
TEST_CASE("arrays - flattening")
{
{
array arr{
1, 2, 3,
array{ 4, 5 },
6,
array{},
array{ 7, array{ 8, array{ 9 }, 10, array{}, }, 11 },
};
arr.flatten();
REQUIRE(arr == array{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 });
}
{
array arr{
array{},
array{array{}},
array{array{},array{array{},array{}},array{}},
array{array{array{array{array{array{ 1 }}}}}}
};
arr.flatten();
REQUIRE(arr == array{ 1 });
}
}

View File

@ -0,0 +1,229 @@
#include "tests.h"
TEST_CASE("tables - moving")
{
static constexpr auto filename = "foo.toml"sv;
parsing_should_succeed(
S(R"(test = { val1 = "foo" })"sv),
[&](table&& tbl) noexcept
{
CHECK(tbl.source().begin == source_position{ 1, 1 });
CHECK(tbl.source().end == source_position{ 1, 24 });
CHECK(tbl.source().path);
CHECK(*tbl.source().path == filename);
CHECK(tbl.size() == 1_sz);
REQUIRE(tbl[S("test")].as<table>());
CHECK(tbl[S("test")].as<table>()->size() == 1_sz);
CHECK(tbl[S("test")].as<table>()->source().begin == source_position{ 1, 8 });
CHECK(tbl[S("test")].as<table>()->source().end == source_position{ 1, 24 });
CHECK(tbl[S("test")][S("val1")] == S("foo"sv));
table tbl2 = std::move(tbl);
CHECK(tbl2.source().begin == source_position{ 1, 1 });
CHECK(tbl2.source().end == source_position{ 1, 24 });
CHECK(tbl2.source().path);
CHECK(*tbl2.source().path == filename);
CHECK(tbl2.size() == 1_sz);
REQUIRE(tbl2[S("test")].as<table>());
CHECK(tbl2[S("test")].as<table>()->size() == 1_sz);
CHECK(tbl2[S("test")][S("val1")] == S("foo"sv));
CHECK(tbl.source().begin == source_position{});
CHECK(tbl.source().end == source_position{});
CHECK(!tbl.source().path);
CHECK(tbl.size() == 0_sz);
CHECK(!tbl[S("test")].as<table>());
},
filename
);
}
TEST_CASE("tables - construction")
{
{
table tbl;
CHECK(tbl.size() == 0_sz);
CHECK(tbl.empty());
CHECK(tbl.begin() == tbl.end());
CHECK(tbl.cbegin() == tbl.cend());
CHECK(tbl.source().begin == source_position{});
CHECK(tbl.source().end == source_position{});
CHECK(!tbl.source().path);
}
{
table tbl{{
{ S("foo"sv), 42 }
}};
CHECK(tbl.size() == 1_sz);
CHECK(!tbl.empty());
CHECK(tbl.begin() != tbl.end());
CHECK(tbl.cbegin() != tbl.cend());
REQUIRE(tbl.get_as<int64_t>(S("foo"sv)));
CHECK(*tbl.get_as<int64_t>(S("foo"sv)) == 42);
}
{
table tbl{{
{ S("foo"sv), 42 },
{ S("bar"sv), 10.0 },
{ S("kek"sv), false },
{ S("qux"sv), array{ 1 } }
}};
CHECK(tbl.size() == 4_sz);
CHECK(!tbl.empty());
REQUIRE(tbl.get_as<int64_t>(S("foo"sv)));
CHECK(*tbl.get_as<int64_t>(S("foo"sv)) == 42);
REQUIRE(tbl.get_as<double>(S("bar"sv)));
CHECK(*tbl.get_as<double>(S("bar"sv)) == 10.0);
REQUIRE(tbl.get_as<bool>(S("kek"sv)));
CHECK(*tbl.get_as<bool>(S("kek"sv)) == false);
REQUIRE(tbl.get_as<array>(S("qux"sv)));
CHECK(*tbl.get_as<array>(S("qux"sv)) == array{ 1 });
}
}
TEST_CASE("tables - equality")
{
static constexpr const string_char* one = S("one");
table tbl1{{
{ one, 1 },
{ S("two"), 2 },
{ S("three"), 3 }
}};
CHECK(tbl1 == tbl1);
table tbl2{{
{ S("one"sv), 1 },
{ S("two"sv), 2 },
{ S("three"sv), 3 }
}};
CHECK(tbl1 == tbl2);
table tbl3{{
{ S("one"sv), 1 },
{ S("two"sv), 2 }
}};
CHECK(tbl1 != tbl3);
table tbl4{{
{ S("one"sv), 1 },
{ S("two"sv), 2 },
{ S("three"sv), 3 },
{ S("four"sv), 4 }
}};
CHECK(tbl1 != tbl4);
table tbl5{{
{ S("one"sv), 1 },
{ S("two"sv), 2 },
{ S("three"sv), 3.0 }
}};
CHECK(tbl1 != tbl5);
table tbl6{};
CHECK(tbl1 != tbl6);
CHECK(tbl6 == tbl6);
table tbl7{};
CHECK(tbl6 == tbl7);
}
namespace
{
template <typename T>
static auto advance(T iter, ptrdiff_t offset) noexcept
{
while (offset > 0)
{
iter++;
offset--;
}
while (offset < 0)
{
iter--;
offset++;
}
return iter;
}
}
TEST_CASE("tables - insertion and erasure")
{
table tbl;
auto res = tbl.insert(S("a"), 42);
CHECK(res.first == tbl.begin());
CHECK(res.second == true);
CHECK(tbl.size() == 1_sz);
CHECK(!tbl.empty());
REQUIRE(tbl.get_as<int64_t>(S("a"sv)));
CHECK(*tbl.get_as<int64_t>(S("a"sv)) == 42);
REQUIRE(tbl == table{{ { S("a"sv), 42 } }});
res = tbl.insert(S("a"), 69);
CHECK(res.first == tbl.begin());
CHECK(res.second == false);
CHECK(tbl.size() == 1_sz);
REQUIRE(tbl.get_as<int64_t>(S("a")));
CHECK(*tbl.get_as<int64_t>(S("a")) == 42);
REQUIRE(tbl == table{{ { S("a"sv), 42 } }});
static constexpr const string_char* a = S("a");
res = tbl.insert_or_assign(a, 69);
CHECK(res.first == tbl.begin());
CHECK(res.second == false); //should assign
CHECK(tbl.size() == 1_sz);
REQUIRE(tbl.get_as<int64_t>(S("a")));
CHECK(*tbl.get_as<int64_t>(S("a")) == 69);
REQUIRE(tbl == table{{ { S("a"sv), 69 } }});
res = tbl.insert_or_assign(S("b"), S("kek"));
CHECK(res.first == advance(tbl.begin(), 1));
CHECK(res.second == true); //should insert
CHECK(tbl.size() == 2_sz);
REQUIRE(tbl.get_as<string>(S("b")));
CHECK(*tbl.get_as<string>(S("b")) == S("kek"sv));
REQUIRE(tbl == table{{ { S("a"sv), 69 }, { S("b"sv), S("kek") } }});
res = tbl.emplace<array>(S("c"), 1, 2, 3);
CHECK(res.first == advance(tbl.begin(), 2));
CHECK(res.second == true);
CHECK(tbl.size() == 3_sz);
REQUIRE(tbl.get_as<array>(S("c")));
CHECK(*tbl.get_as<array>(S("c")) == array{ 1, 2, 3 });
REQUIRE(tbl == table{{ { S("a"sv), 69 }, { S("b"sv), S("kek"sv) }, { S("c"sv), array{ 1, 2, 3 } } }});
res = tbl.emplace<int64_t>(S("c"), 1);
CHECK(res.first == advance(tbl.begin(), 2));
CHECK(res.second == false);
CHECK(tbl.size() == 3_sz);
REQUIRE(!tbl.get_as<int64_t>(S("c")));
REQUIRE(tbl.get_as<array>(S("c")));
REQUIRE(tbl == table{{ { S("a"sv), 69 }, { S("b"sv), S("kek"s) }, { S("c"sv), array{ 1, 2, 3 } } }});
auto it = tbl.erase(tbl.cbegin());
REQUIRE(tbl == table{{ { S("b"sv), S("kek") }, { S("c"sv), array{ 1, 2, 3 } } }});
CHECK(it == tbl.begin());
CHECK(tbl.size() == 2_sz);
res = tbl.insert_or_assign(S("a"sv), 69);
CHECK(res.first == tbl.begin());
CHECK(res.second == true); //should insert
CHECK(tbl.size() == 3_sz);
REQUIRE(tbl.get_as<int64_t>(S("a")));
CHECK(*tbl.get_as<int64_t>(S("a")) == 69);
REQUIRE(tbl == table{{ { S("a"sv), 69 }, { S("b"sv), S("kek") }, { S("c"sv), array{ 1, 2, 3 } } }});
it = tbl.erase(advance(tbl.cbegin(), 1), advance(tbl.cbegin(), 3));
REQUIRE(tbl == table{{ { S("a"sv), 69 } }});
CHECK(it == tbl.end());
CHECK(tbl.size() == 1_sz);
tbl.clear();
REQUIRE(tbl == table{});
CHECK(tbl.size() == 0_sz);
CHECK(tbl.empty());
}

View File

@ -1,5 +1,4 @@
test_sources = [
'lifetimes.cpp',
'main.cpp',
'parsing_arrays.cpp',
'parsing_booleans.cpp',
@ -10,7 +9,9 @@ test_sources = [
'parsing_key_value_pairs.cpp',
'parsing_spec_example.cpp',
'parsing_strings.cpp',
'parsing_tables.cpp'
'parsing_tables.cpp',
'manipulating_arrays.cpp',
'manipulating_tables.cpp'
]
disable_exceptions = 'cpp_eh=none'

View File

@ -1,6 +1,6 @@
#include "tests.h"
TEST_CASE("parsing arrays")
TEST_CASE("parsing - arrays")
{
parsing_should_succeed(S(R"(
integers = [ 1, 2, 3 ]

View File

@ -1,6 +1,6 @@
#include "tests.h"
TEST_CASE("parsing booleans")
TEST_CASE("parsing - booleans")
{
parsing_should_succeed(S(R"(
bool1 = true

View File

@ -1,6 +1,6 @@
#include "tests.h"
TEST_CASE("parsing comments")
TEST_CASE("parsing - comments")
{
parsing_should_succeed(S(R"(
# This is a full-line comment

View File

@ -3,7 +3,7 @@
TOML_PUSH_WARNINGS
TOML_DISABLE_INIT_WARNINGS
TEST_CASE("parsing dates and times")
TEST_CASE("parsing - dates and times")
{
parsing_should_succeed(S(R"(
odt1 = 1979-05-27T07:32:00Z

View File

@ -1,6 +1,6 @@
#include "tests.h"
TEST_CASE("parsing floats - normal")
TEST_CASE("parsing - floats")
{
parsing_should_succeed(S(R"(
# fractional
@ -114,7 +114,7 @@ flt8 = 224_617.445_991_228
#endif
}
TEST_CASE("parsing floats - inf and nan")
TEST_CASE("parsing - inf and nan")
{
parsing_should_succeed(S(R"(
# infinity

View File

@ -1,6 +1,6 @@
#include "tests.h"
TEST_CASE("parsing integers - decimal")
TEST_CASE("parsing - integers (decimal)")
{
parsing_should_succeed(S(R"(
int1 = +99
@ -67,7 +67,7 @@ int7 = 1_2_3_4_5 # VALID but discouraged
parse_expected_value( "123_456_789"sv, 123456789 );
}
TEST_CASE("parsing integers - hex, bin, oct")
TEST_CASE("parsing - integers (hex, bin, oct)")
{
parsing_should_succeed(S(R"(
# hexadecimal with prefix `0x`

View File

@ -1,6 +1,6 @@
#include "tests.h"
TEST_CASE("parsing key-value pairs")
TEST_CASE("parsing - key-value pairs")
{
parsing_should_succeed(S(R"(
key = "value"
@ -48,7 +48,7 @@ name = "Pradyun"
}
TEST_CASE("parsing key-value pairs - dotted")
TEST_CASE("parsing - key-value pairs (dotted)")
{
parsing_should_succeed(S(R"(
name = "Orange"

View File

@ -3,7 +3,7 @@
TOML_PUSH_WARNINGS
TOML_DISABLE_INIT_WARNINGS
TEST_CASE("parsing TOML spec example")
TEST_CASE("parsing - TOML spec example")
{
static constexpr auto toml_text =
S(R"(# This is a TOML document.

View File

@ -1,6 +1,6 @@
#include "tests.h"
TEST_CASE("parsing strings")
TEST_CASE("parsing - strings")
{
parsing_should_succeed(S(R"(
str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."

View File

@ -1,6 +1,6 @@
#include "tests.h"
TEST_CASE("parsing tables")
TEST_CASE("parsing - tables")
{
parsing_should_succeed(S(R"(
[table]
@ -158,7 +158,7 @@ apple.taste.sweet = true
);
}
TEST_CASE("parsing inline tables")
TEST_CASE("parsing - inline tables")
{
parsing_should_succeed(S(R"(
name = { first = "Tom", last = "Preston-Werner" }
@ -264,7 +264,7 @@ name = {
}
TEST_CASE("parsing arrays-of-tables")
TEST_CASE("parsing - arrays-of-tables")
{
parsing_should_succeed(S(R"(
points = [ { x = 1, y = 2, z = 3 },

View File

@ -54,7 +54,7 @@ void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func,
{
toml::parse_result result = toml::parse(toml_str, source_path);
if (result)
std::forward<FUNC>(func)(validate_table(*std::move(result), source_path));
std::forward<FUNC>(func)(validate_table(std::move(result), source_path));
else
{
FAIL(
@ -71,7 +71,7 @@ void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func,
ss.write(toml_str.data(), toml_str.length());
toml::parse_result result = toml::parse(ss, source_path);
if (result)
std::forward<FUNC>(func)(validate_table(*std::move(result), source_path));
std::forward<FUNC>(func)(validate_table(std::move(result), source_path));
else
{
FAIL(

790
toml.hpp

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
@ -68,10 +60,11 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />

View File

@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
@ -68,10 +60,11 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />

View File

@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
@ -70,10 +62,11 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />

View File

@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
@ -70,10 +62,11 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />

View File

@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
@ -69,10 +61,11 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />

View File

@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
@ -69,10 +61,11 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />

View File

@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
@ -71,10 +63,11 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />

View File

@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
@ -71,10 +63,11 @@
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\lifetimes.cpp" />
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />

89
vs/test_x86_char.vcxproj Normal file
View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{150FA82E-0E9F-4449-82A6-811BFFE6B5FE}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

89
vs/test_x86_char8.vcxproj Normal file
View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{1ED2F590-1DE8-457D-97BD-38ECF0955F7F}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{BE980D05-770C-4420-B59B-EAD7A63468D2}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{54DD1412-20C0-4700-96D7-3FD445E70996}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{3B05742A-6512-4B11-8842-A1B9D1465B1F}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>TOML_UNRELEASED_FEATURES=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{A4F27C6F-601D-45C0-9F81-7C100BD93B9A}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>TOML_UNRELEASED_FEATURES=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{0CAD095A-C9F2-49FC-9C9F-4508498BE488}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>TOML_UNRELEASED_FEATURES=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{0BBEE569-536D-452C-808C-61843FECCC7E}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<Import Project="toml++.props" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\tests;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>TOML_CHAR_8_STRINGS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>TOML_UNRELEASED_FEATURES=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>tests.h</PrecompiledHeaderFile>
<PreprocessorDefinitions Condition="'%(PrecompiledHeader)'=='Use'">USING_PCH=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>..\tests\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\tests\main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\tests\manipulating_arrays.cpp" />
<ClCompile Include="..\tests\manipulating_tables.cpp" />
<ClCompile Include="..\tests\parsing_arrays.cpp" />
<ClCompile Include="..\tests\parsing_booleans.cpp" />
<ClCompile Include="..\tests\parsing_comments.cpp" />
<ClCompile Include="..\tests\parsing_dates_and_times.cpp" />
<ClCompile Include="..\tests\parsing_floats.cpp" />
<ClCompile Include="..\tests\parsing_integers.cpp" />
<ClCompile Include="..\tests\parsing_key_value_pairs.cpp" />
<ClCompile Include="..\tests\parsing_spec_example.cpp" />
<ClCompile Include="..\tests\parsing_strings.cpp" />
<ClCompile Include="..\tests\parsing_tables.cpp" />
<ClCompile Include="..\tests\tests.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tests\tests.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@ -29,102 +29,104 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "parse_file", "parse_file.vc
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "toml_to_json_transcoder", "toml_to_json_transcoder.vcxproj", "{BE34AA99-BEE6-4B50-B237-217E7C88FCB5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_x86_char", "test_x86_char.vcxproj", "{150FA82E-0E9F-4449-82A6-811BFFE6B5FE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_x86_char_noexcept", "test_x86_char_noexcept.vcxproj", "{54DD1412-20C0-4700-96D7-3FD445E70996}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_x86_char8", "test_x86_char8.vcxproj", "{1ED2F590-1DE8-457D-97BD-38ECF0955F7F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_x86_char8_noexcept", "test_x86_char8_noexcept.vcxproj", "{BE980D05-770C-4420-B59B-EAD7A63468D2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_x86_strict_char", "test_x86_strict_char.vcxproj", "{3B05742A-6512-4B11-8842-A1B9D1465B1F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_x86_strict_char_noexcept", "test_x86_strict_char_noexcept.vcxproj", "{0BBEE569-536D-452C-808C-61843FECCC7E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_x86_strict_char8", "test_x86_strict_char8.vcxproj", "{A4F27C6F-601D-45C0-9F81-7C100BD93B9A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_x86_strict_char8_noexcept", "test_x86_strict_char8_noexcept.vcxproj", "{0CAD095A-C9F2-49FC-9C9F-4508498BE488}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Debug|x64.ActiveCfg = Debug|x64
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Debug|x64.Build.0 = Debug|x64
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Debug|x86.ActiveCfg = Debug|Win32
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Debug|x86.Build.0 = Debug|Win32
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Release|x64.ActiveCfg = Release|x64
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Release|x64.Build.0 = Release|x64
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Release|x86.ActiveCfg = Release|Win32
{0E287B5A-1168-43FD-B067-F6BE8E182A57}.Release|x86.Build.0 = Release|Win32
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Debug|x64.ActiveCfg = Debug|x64
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Debug|x64.Build.0 = Debug|x64
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Debug|x86.ActiveCfg = Debug|Win32
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Debug|x86.Build.0 = Debug|Win32
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Release|x64.ActiveCfg = Release|x64
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Release|x64.Build.0 = Release|x64
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Release|x86.ActiveCfg = Release|Win32
{54532B93-A2F9-49AC-886E-767A6D78E2F2}.Release|x86.Build.0 = Release|Win32
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Debug|x64.ActiveCfg = Debug|x64
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Debug|x64.Build.0 = Debug|x64
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Debug|x86.ActiveCfg = Debug|Win32
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Debug|x86.Build.0 = Debug|Win32
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Release|x64.ActiveCfg = Release|x64
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Release|x64.Build.0 = Release|x64
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Release|x86.ActiveCfg = Release|Win32
{E888E99C-734D-44C4-B917-0AC8D3E2F48F}.Release|x86.Build.0 = Release|Win32
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Debug|x64.ActiveCfg = Debug|x64
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Debug|x64.Build.0 = Debug|x64
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Debug|x86.ActiveCfg = Debug|Win32
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Debug|x86.Build.0 = Debug|Win32
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Release|x64.ActiveCfg = Release|x64
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Release|x64.Build.0 = Release|x64
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Release|x86.ActiveCfg = Release|Win32
{3E4018CE-CCA2-48E6-B11E-732A1B59C672}.Release|x86.Build.0 = Release|Win32
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Debug|x64.ActiveCfg = Debug|x64
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Debug|x64.Build.0 = Debug|x64
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Debug|x86.ActiveCfg = Debug|Win32
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Debug|x86.Build.0 = Debug|Win32
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Release|x64.ActiveCfg = Release|x64
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Release|x64.Build.0 = Release|x64
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Release|x86.ActiveCfg = Release|Win32
{F094F967-42B5-4AD7-AB44-EA044CD9837E}.Release|x86.Build.0 = Release|Win32
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Debug|x64.ActiveCfg = Debug|x64
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Debug|x64.Build.0 = Debug|x64
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Debug|x86.ActiveCfg = Debug|Win32
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Debug|x86.Build.0 = Debug|Win32
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Release|x64.ActiveCfg = Release|x64
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Release|x64.Build.0 = Release|x64
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Release|x86.ActiveCfg = Release|Win32
{89FF67C6-94C0-4C46-8411-7549A36584FB}.Release|x86.Build.0 = Release|Win32
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Debug|x64.ActiveCfg = Debug|x64
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Debug|x64.Build.0 = Debug|x64
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Debug|x86.ActiveCfg = Debug|Win32
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Debug|x86.Build.0 = Debug|Win32
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Release|x64.ActiveCfg = Release|x64
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Release|x64.Build.0 = Release|x64
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Release|x86.ActiveCfg = Release|Win32
{F05F8C1B-7E23-4147-901E-AD91092E5752}.Release|x86.Build.0 = Release|Win32
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Debug|x64.ActiveCfg = Debug|x64
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Debug|x64.Build.0 = Debug|x64
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Debug|x86.ActiveCfg = Debug|Win32
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Debug|x86.Build.0 = Debug|Win32
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Release|x64.ActiveCfg = Release|x64
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Release|x64.Build.0 = Release|x64
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Release|x86.ActiveCfg = Release|Win32
{EAC419E9-0C72-4625-B2B9-E879F697021A}.Release|x86.Build.0 = Release|Win32
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Debug|x64.ActiveCfg = Debug|x64
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Debug|x64.Build.0 = Debug|x64
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Debug|x86.ActiveCfg = Debug|Win32
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Debug|x86.Build.0 = Debug|Win32
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Release|x64.ActiveCfg = Release|x64
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Release|x64.Build.0 = Release|x64
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Release|x86.ActiveCfg = Release|Win32
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6}.Release|x86.Build.0 = Release|Win32
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Debug|x64.ActiveCfg = Debug|x64
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Debug|x64.Build.0 = Debug|x64
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Debug|x86.ActiveCfg = Debug|Win32
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Debug|x86.Build.0 = Debug|Win32
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Release|x64.ActiveCfg = Release|x64
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Release|x64.Build.0 = Release|x64
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Release|x86.ActiveCfg = Release|Win32
{259FCEE5-3442-4076-9547-2BA793ECA1CB}.Release|x86.Build.0 = Release|Win32
{BE34AA99-BEE6-4B50-B237-217E7C88FCB5}.Debug|x64.ActiveCfg = Debug|x64
{BE34AA99-BEE6-4B50-B237-217E7C88FCB5}.Debug|x64.Build.0 = Debug|x64
{BE34AA99-BEE6-4B50-B237-217E7C88FCB5}.Debug|x86.ActiveCfg = Debug|Win32
{BE34AA99-BEE6-4B50-B237-217E7C88FCB5}.Debug|x86.Build.0 = Debug|Win32
{BE34AA99-BEE6-4B50-B237-217E7C88FCB5}.Release|x64.ActiveCfg = Release|x64
{BE34AA99-BEE6-4B50-B237-217E7C88FCB5}.Release|x64.Build.0 = Release|x64
{BE34AA99-BEE6-4B50-B237-217E7C88FCB5}.Release|x86.ActiveCfg = Release|Win32
{BE34AA99-BEE6-4B50-B237-217E7C88FCB5}.Release|x86.Build.0 = Release|Win32
{150FA82E-0E9F-4449-82A6-811BFFE6B5FE}.Debug|x64.ActiveCfg = Debug|Win32
{150FA82E-0E9F-4449-82A6-811BFFE6B5FE}.Debug|x64.Build.0 = Debug|Win32
{150FA82E-0E9F-4449-82A6-811BFFE6B5FE}.Release|x64.ActiveCfg = Release|Win32
{150FA82E-0E9F-4449-82A6-811BFFE6B5FE}.Release|x64.Build.0 = Release|Win32
{54DD1412-20C0-4700-96D7-3FD445E70996}.Debug|x64.ActiveCfg = Debug|Win32
{54DD1412-20C0-4700-96D7-3FD445E70996}.Debug|x64.Build.0 = Debug|Win32
{54DD1412-20C0-4700-96D7-3FD445E70996}.Release|x64.ActiveCfg = Release|Win32
{54DD1412-20C0-4700-96D7-3FD445E70996}.Release|x64.Build.0 = Release|Win32
{1ED2F590-1DE8-457D-97BD-38ECF0955F7F}.Debug|x64.ActiveCfg = Debug|Win32
{1ED2F590-1DE8-457D-97BD-38ECF0955F7F}.Debug|x64.Build.0 = Debug|Win32
{1ED2F590-1DE8-457D-97BD-38ECF0955F7F}.Release|x64.ActiveCfg = Release|Win32
{1ED2F590-1DE8-457D-97BD-38ECF0955F7F}.Release|x64.Build.0 = Release|Win32
{BE980D05-770C-4420-B59B-EAD7A63468D2}.Debug|x64.ActiveCfg = Debug|Win32
{BE980D05-770C-4420-B59B-EAD7A63468D2}.Debug|x64.Build.0 = Debug|Win32
{BE980D05-770C-4420-B59B-EAD7A63468D2}.Release|x64.ActiveCfg = Release|Win32
{BE980D05-770C-4420-B59B-EAD7A63468D2}.Release|x64.Build.0 = Release|Win32
{3B05742A-6512-4B11-8842-A1B9D1465B1F}.Debug|x64.ActiveCfg = Debug|Win32
{3B05742A-6512-4B11-8842-A1B9D1465B1F}.Debug|x64.Build.0 = Debug|Win32
{3B05742A-6512-4B11-8842-A1B9D1465B1F}.Release|x64.ActiveCfg = Release|Win32
{3B05742A-6512-4B11-8842-A1B9D1465B1F}.Release|x64.Build.0 = Release|Win32
{0BBEE569-536D-452C-808C-61843FECCC7E}.Debug|x64.ActiveCfg = Debug|Win32
{0BBEE569-536D-452C-808C-61843FECCC7E}.Debug|x64.Build.0 = Debug|Win32
{0BBEE569-536D-452C-808C-61843FECCC7E}.Release|x64.ActiveCfg = Release|Win32
{0BBEE569-536D-452C-808C-61843FECCC7E}.Release|x64.Build.0 = Release|Win32
{A4F27C6F-601D-45C0-9F81-7C100BD93B9A}.Debug|x64.ActiveCfg = Debug|Win32
{A4F27C6F-601D-45C0-9F81-7C100BD93B9A}.Debug|x64.Build.0 = Debug|Win32
{A4F27C6F-601D-45C0-9F81-7C100BD93B9A}.Release|x64.ActiveCfg = Release|Win32
{A4F27C6F-601D-45C0-9F81-7C100BD93B9A}.Release|x64.Build.0 = Release|Win32
{0CAD095A-C9F2-49FC-9C9F-4508498BE488}.Debug|x64.ActiveCfg = Debug|Win32
{0CAD095A-C9F2-49FC-9C9F-4508498BE488}.Debug|x64.Build.0 = Debug|Win32
{0CAD095A-C9F2-49FC-9C9F-4508498BE488}.Release|x64.ActiveCfg = Release|Win32
{0CAD095A-C9F2-49FC-9C9F-4508498BE488}.Release|x64.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -140,6 +142,14 @@ Global
{9ADB61D3-FDFA-4A9C-A34F-663007BB70F6} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{259FCEE5-3442-4076-9547-2BA793ECA1CB} = {412816A5-9D22-4A30-BCDF-ABFB54BB3735}
{BE34AA99-BEE6-4B50-B237-217E7C88FCB5} = {412816A5-9D22-4A30-BCDF-ABFB54BB3735}
{150FA82E-0E9F-4449-82A6-811BFFE6B5FE} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{54DD1412-20C0-4700-96D7-3FD445E70996} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{1ED2F590-1DE8-457D-97BD-38ECF0955F7F} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{BE980D05-770C-4420-B59B-EAD7A63468D2} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{3B05742A-6512-4B11-8842-A1B9D1465B1F} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{0BBEE569-536D-452C-808C-61843FECCC7E} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{A4F27C6F-601D-45C0-9F81-7C100BD93B9A} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
{0CAD095A-C9F2-49FC-9C9F-4508498BE488} = {4E25CF88-D7D8-4A9C-A52E-0D78281E82EC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0926DDCC-88CD-4839-A82D-D9B99E02A0B1}