Coverage Report

Created: 2025-07-11 06:31

/src/tomlplusplus/include/toml++/impl/node.hpp
Line
Count
Source (jump to first uncovered line)
1
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
2
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
3
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
4
// SPDX-License-Identifier: MIT
5
#pragma once
6
7
#include "std_utility.hpp"
8
#include "forward_declarations.hpp"
9
#include "source_region.hpp"
10
#include "header_start.hpp"
11
12
// workaround for this: https://github.com/marzer/tomlplusplus/issues/220
13
#if TOML_NVCC
14
#define TOML_NVCC_WORKAROUND                                                                                           \
15
  {                                                                                                                  \
16
    return {};                                                                                                     \
17
  }
18
#else
19
#define TOML_NVCC_WORKAROUND = 0
20
#endif
21
22
TOML_NAMESPACE_START
23
{
24
  /// \brief  A TOML node.
25
  ///
26
  /// \detail A parsed TOML document forms a tree made up of tables, arrays and values.
27
  ///     This type is the base of each of those, providing a lot of the polymorphic plumbing.
28
  class TOML_ABSTRACT_INTERFACE TOML_EXPORTED_CLASS node
29
  {
30
    private:
31
    /// \cond
32
33
    friend class TOML_PARSER_TYPENAME;
34
    source_region source_{};
35
36
    template <typename T>
37
    TOML_NODISCARD
38
    decltype(auto) get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>);
39
40
    template <typename T, typename N>
41
    using ref_type_ = std::conditional_t<                         //
42
      std::is_reference_v<T>,                               //
43
      impl::copy_ref<impl::copy_cv<impl::unwrap_node<T>, std::remove_reference_t<N>>, T>, //
44
      impl::copy_cvref<impl::unwrap_node<T>, N>                     //
45
      >;
46
47
    template <typename T, typename N>
48
    using ref_type = std::conditional_t<       //
49
      std::is_reference_v<N>,            //
50
      ref_type_<T, N>,               //
51
      ref_type_<T, std::add_lvalue_reference_t<N>> //
52
      >;
53
54
    template <typename T, typename N>
55
    TOML_PURE_GETTER
56
    static ref_type<T, N&&> do_ref(N&& n) noexcept
57
    {
58
      using unwrapped_type = impl::unwrap_node<T>;
59
      static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
60
              "The template type argument of node::ref() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
61
62
      TOML_ASSERT_ASSUME(
63
        n.template is<unwrapped_type>()
64
        && "template type argument provided to toml::node::ref() didn't match the node's actual type");
65
66
      using node_ref = std::remove_volatile_t<std::remove_reference_t<N>>&;
67
      using val_type = std::remove_volatile_t<unwrapped_type>;
68
      using out_ref  = ref_type<T, N&&>;
69
      static_assert(std::is_reference_v<out_ref>);
70
71
      if constexpr (toml::is_value<unwrapped_type>)
72
        return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>().get());
73
      else
74
        return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>());
75
    }
76
77
    protected:
78
    TOML_EXPORTED_MEMBER_FUNCTION
79
    node() noexcept;
80
81
    TOML_EXPORTED_MEMBER_FUNCTION
82
    node(const node&) noexcept;
83
84
    TOML_EXPORTED_MEMBER_FUNCTION
85
    node(node&&) noexcept;
86
87
    TOML_EXPORTED_MEMBER_FUNCTION
88
    node& operator=(const node&) noexcept;
89
90
    TOML_EXPORTED_MEMBER_FUNCTION
91
    node& operator=(node&&) noexcept;
92
93
    template <typename T, typename N>
94
    using ref_cast_type_ = std::conditional_t<                        //
95
      std::is_reference_v<T>,                               //
96
      impl::copy_ref<impl::copy_cv<impl::wrap_node<T>, std::remove_reference_t<N>>, T>, //
97
      impl::copy_cvref<impl::wrap_node<T>, N>                       //
98
      >;
99
100
    template <typename T, typename N>
101
    using ref_cast_type = std::conditional_t<       //
102
      std::is_reference_v<N>,               //
103
      ref_cast_type_<T, N>,               //
104
      ref_cast_type_<T, std::add_lvalue_reference_t<N>> //
105
      >;
106
107
    template <typename T>
108
    TOML_PURE_INLINE_GETTER
109
    ref_cast_type<T, node&> ref_cast() & noexcept
110
1.76M
    {
111
1.76M
      using out_ref  = ref_cast_type<T, node&>;
112
1.76M
      using out_type = std::remove_reference_t<out_ref>;
113
1.76M
      return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
114
1.76M
    }
_ZNR4toml2v34node8ref_castINS0_5tableEEENSt3__111conditionalILb1ENS5_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS7_8copy_cv_INS7_12node_wrapperIu20__remove_reference_tIS6_EE4typeES1_E4typeES6_E4typeENS8_INS8_INS9_Iu20__remove_reference_tISD_ES1_E4typeESD_E4typeERS1_E4typeEE4typeESR_E4typeEv
Line
Count
Source
110
1.50M
    {
111
1.50M
      using out_ref  = ref_cast_type<T, node&>;
112
1.50M
      using out_type = std::remove_reference_t<out_ref>;
113
1.50M
      return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
114
1.50M
    }
_ZNR4toml2v34node8ref_castINS0_5arrayEEENSt3__111conditionalILb1ENS5_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS7_8copy_cv_INS7_12node_wrapperIu20__remove_reference_tIS6_EE4typeES1_E4typeES6_E4typeENS8_INS8_INS9_Iu20__remove_reference_tISD_ES1_E4typeESD_E4typeERS1_E4typeEE4typeESR_E4typeEv
Line
Count
Source
110
258k
    {
111
258k
      using out_ref  = ref_cast_type<T, node&>;
112
258k
      using out_type = std::remove_reference_t<out_ref>;
113
258k
      return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
114
258k
    }
_ZNR4toml2v34node8ref_castIlEENSt3__111conditionalILb1ENS4_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS6_8copy_cv_INS6_12node_wrapperIu20__remove_reference_tIS5_EE4typeES1_E4typeES5_E4typeENS7_INS7_INS8_Iu20__remove_reference_tISC_ES1_E4typeESC_E4typeERS1_E4typeEE4typeESQ_E4typeEv
Line
Count
Source
110
4.18k
    {
111
4.18k
      using out_ref  = ref_cast_type<T, node&>;
112
4.18k
      using out_type = std::remove_reference_t<out_ref>;
113
4.18k
      return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
114
4.18k
    }
Unexecuted instantiation: _ZNR4toml2v34node8ref_castINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEENS3_11conditionalILb1ENSA_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INSC_8copy_cv_INSC_12node_wrapperIu20__remove_reference_tISB_EE4typeES1_E4typeESB_E4typeENSD_INSD_INSE_Iu20__remove_reference_tISI_ES1_E4typeESI_E4typeERS1_E4typeEE4typeESW_E4typeEv
Unexecuted instantiation: _ZNR4toml2v34node8ref_castIdEENSt3__111conditionalILb1ENS4_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS6_8copy_cv_INS6_12node_wrapperIu20__remove_reference_tIS5_EE4typeES1_E4typeES5_E4typeENS7_INS7_INS8_Iu20__remove_reference_tISC_ES1_E4typeESC_E4typeERS1_E4typeEE4typeESQ_E4typeEv
Unexecuted instantiation: _ZNR4toml2v34node8ref_castIbEENSt3__111conditionalILb1ENS4_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS6_8copy_cv_INS6_12node_wrapperIu20__remove_reference_tIS5_EE4typeES1_E4typeES5_E4typeENS7_INS7_INS8_Iu20__remove_reference_tISC_ES1_E4typeESC_E4typeERS1_E4typeEE4typeESQ_E4typeEv
Unexecuted instantiation: _ZNR4toml2v34node8ref_castINS0_4dateEEENSt3__111conditionalILb1ENS5_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS7_8copy_cv_INS7_12node_wrapperIu20__remove_reference_tIS6_EE4typeES1_E4typeES6_E4typeENS8_INS8_INS9_Iu20__remove_reference_tISD_ES1_E4typeESD_E4typeERS1_E4typeEE4typeESR_E4typeEv
Unexecuted instantiation: _ZNR4toml2v34node8ref_castINS0_4timeEEENSt3__111conditionalILb1ENS5_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS7_8copy_cv_INS7_12node_wrapperIu20__remove_reference_tIS6_EE4typeES1_E4typeES6_E4typeENS8_INS8_INS9_Iu20__remove_reference_tISD_ES1_E4typeESD_E4typeERS1_E4typeEE4typeESR_E4typeEv
Unexecuted instantiation: _ZNR4toml2v34node8ref_castINS0_6stdopt9date_timeEEENSt3__111conditionalILb1ENS6_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS8_8copy_cv_INS8_12node_wrapperIu20__remove_reference_tIS7_EE4typeES1_E4typeES7_E4typeENS9_INS9_INSA_Iu20__remove_reference_tISE_ES1_E4typeESE_E4typeERS1_E4typeEE4typeESS_E4typeEv
115
116
    template <typename T>
117
    TOML_PURE_INLINE_GETTER
118
    ref_cast_type<T, node&&> ref_cast() && noexcept
119
    {
120
      using out_ref  = ref_cast_type<T, node&&>;
121
      using out_type = std::remove_reference_t<out_ref>;
122
      return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
123
    }
124
125
    template <typename T>
126
    TOML_PURE_INLINE_GETTER
127
    ref_cast_type<T, const node&> ref_cast() const& noexcept
128
0
    {
129
0
      using out_ref  = ref_cast_type<T, const node&>;
130
0
      using out_type = std::remove_reference_t<out_ref>;
131
0
      return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
132
0
    }
Unexecuted instantiation: _ZNKR4toml2v34node8ref_castINS0_5tableEEENSt3__111conditionalILb1ENS5_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS7_8copy_cv_INS7_12node_wrapperIu20__remove_reference_tIS6_EE4typeEKS1_E4typeES6_E4typeENS8_INS8_INS9_Iu20__remove_reference_tISD_ESE_E4typeESD_E4typeERSE_E4typeEE4typeESS_E4typeEv
Unexecuted instantiation: _ZNKR4toml2v34node8ref_castINS0_5arrayEEENSt3__111conditionalILb1ENS5_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS7_8copy_cv_INS7_12node_wrapperIu20__remove_reference_tIS6_EE4typeEKS1_E4typeES6_E4typeENS8_INS8_INS9_Iu20__remove_reference_tISD_ESE_E4typeESD_E4typeERSE_E4typeEE4typeESS_E4typeEv
Unexecuted instantiation: _ZNKR4toml2v34node8ref_castINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEENS3_11conditionalILb1ENSA_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INSC_8copy_cv_INSC_12node_wrapperIu20__remove_reference_tISB_EE4typeEKS1_E4typeESB_E4typeENSD_INSD_INSE_Iu20__remove_reference_tISI_ESJ_E4typeESI_E4typeERSJ_E4typeEE4typeESX_E4typeEv
Unexecuted instantiation: _ZNKR4toml2v34node8ref_castIlEENSt3__111conditionalILb1ENS4_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS6_8copy_cv_INS6_12node_wrapperIu20__remove_reference_tIS5_EE4typeEKS1_E4typeES5_E4typeENS7_INS7_INS8_Iu20__remove_reference_tISC_ESD_E4typeESC_E4typeERSD_E4typeEE4typeESR_E4typeEv
Unexecuted instantiation: _ZNKR4toml2v34node8ref_castIdEENSt3__111conditionalILb1ENS4_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS6_8copy_cv_INS6_12node_wrapperIu20__remove_reference_tIS5_EE4typeEKS1_E4typeES5_E4typeENS7_INS7_INS8_Iu20__remove_reference_tISC_ESD_E4typeESC_E4typeERSD_E4typeEE4typeESR_E4typeEv
Unexecuted instantiation: _ZNKR4toml2v34node8ref_castIbEENSt3__111conditionalILb1ENS4_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS6_8copy_cv_INS6_12node_wrapperIu20__remove_reference_tIS5_EE4typeEKS1_E4typeES5_E4typeENS7_INS7_INS8_Iu20__remove_reference_tISC_ESD_E4typeESC_E4typeERSD_E4typeEE4typeESR_E4typeEv
Unexecuted instantiation: _ZNKR4toml2v34node8ref_castINS0_4dateEEENSt3__111conditionalILb1ENS5_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS7_8copy_cv_INS7_12node_wrapperIu20__remove_reference_tIS6_EE4typeEKS1_E4typeES6_E4typeENS8_INS8_INS9_Iu20__remove_reference_tISD_ESE_E4typeESD_E4typeERSE_E4typeEE4typeESS_E4typeEv
Unexecuted instantiation: _ZNKR4toml2v34node8ref_castINS0_4timeEEENSt3__111conditionalILb1ENS5_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS7_8copy_cv_INS7_12node_wrapperIu20__remove_reference_tIS6_EE4typeEKS1_E4typeES6_E4typeENS8_INS8_INS9_Iu20__remove_reference_tISD_ESE_E4typeESD_E4typeERSE_E4typeEE4typeESS_E4typeEv
Unexecuted instantiation: _ZNKR4toml2v34node8ref_castINS0_6stdopt9date_timeEEENSt3__111conditionalILb1ENS6_IXsr3stdE14is_reference_vIT_EENS0_4impl9copy_ref_INS8_8copy_cv_INS8_12node_wrapperIu20__remove_reference_tIS7_EE4typeEKS1_E4typeES7_E4typeENS9_INS9_INSA_Iu20__remove_reference_tISE_ESF_E4typeESE_E4typeERSF_E4typeEE4typeEST_E4typeEv
133
134
    template <typename T>
135
    TOML_PURE_INLINE_GETTER
136
    ref_cast_type<T, const node&&> ref_cast() const&& noexcept
137
    {
138
      using out_ref  = ref_cast_type<T, const node&&>;
139
      using out_type = std::remove_reference_t<out_ref>;
140
      return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
141
    }
142
143
    /// \endcond
144
145
    public:
146
    TOML_EXPORTED_MEMBER_FUNCTION
147
    virtual ~node() noexcept;
148
149
    /// \name Type checks
150
    /// @{
151
152
    /// \brief  Checks if a node contains values/elements of only one type.
153
    ///
154
    /// \detail \cpp
155
    /// auto cfg = toml::parse("arr = [ 1, 2, 3, 4.0 ]");
156
    /// toml::array& arr = *cfg["arr"].as_array();
157
    ///
158
    /// toml::node* nonmatch{};
159
    /// if (arr.is_homogeneous(toml::node_type::integer, nonmatch))
160
    ///   std::cout << "array was homogeneous"sv << "\n";
161
    /// else
162
    ///   std::cout << "array was not homogeneous!\n"
163
    ///   << "first non-match was a "sv << nonmatch->type() << " at " << nonmatch->source() << "\n";
164
    /// \ecpp
165
    ///
166
    /// \out
167
    /// array was not homogeneous!
168
    /// first non-match was a floating-point at line 1, column 18
169
    /// \eout
170
    ///
171
    /// \param  ntype A TOML node type. <br>
172
    ///         \conditional_return{toml::node_type::none}
173
    ///         "is every element the same type?"
174
    ///         \conditional_return{Anything else}
175
    ///         "is every element one of these?"
176
    ///
177
    /// \param first_nonmatch Reference to a pointer in which the address of the first non-matching element
178
    ///             will be stored if the return value is false.
179
    ///
180
    /// \returns  True if the node was homogeneous.
181
    ///
182
    /// \remarks  Always returns `false` for empty tables and arrays.
183
    TOML_NODISCARD
184
    virtual bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept = 0;
185
186
    /// \brief  Checks if a node contains values/elements of only one type (const overload).
187
    TOML_NODISCARD
188
    virtual bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept = 0;
189
190
    /// \brief  Checks if the node contains values/elements of only one type.
191
    ///
192
    /// \detail \cpp
193
    /// auto arr = toml::array{ 1, 2, 3 };
194
    /// std::cout << "homogenous: "sv << arr.is_homogeneous(toml::node_type::none) << "\n";
195
    /// std::cout << "all floats: "sv << arr.is_homogeneous(toml::node_type::floating_point) << "\n";
196
    /// std::cout << "all arrays: "sv << arr.is_homogeneous(toml::node_type::array) << "\n";
197
    /// std::cout << "all ints:   "sv << arr.is_homogeneous(toml::node_type::integer) << "\n";
198
    /// \ecpp
199
    ///
200
    /// \out
201
    /// homogeneous: true
202
    /// all floats:  false
203
    /// all arrays:  false
204
    /// all ints:    true
205
    /// \eout
206
    ///
207
    /// \param  ntype A TOML node type. <br>
208
    ///         \conditional_return{toml::node_type::none}
209
    ///         "is every element the same type?"
210
    ///         \conditional_return{Anything else}
211
    ///         "is every element one of these?"
212
    ///
213
    /// \returns  True if the node was homogeneous.
214
    ///
215
    /// \remarks  Always returns `false` for empty tables and arrays.
216
    TOML_PURE_GETTER
217
    virtual bool is_homogeneous(node_type ntype) const noexcept = 0;
218
219
    /// \brief  Checks if the node contains values/elements of only one type.
220
    ///
221
    /// \detail \cpp
222
    /// auto arr = toml::array{ 1, 2, 3 };
223
    /// std::cout << "homogenous:   "sv << arr.is_homogeneous() << "\n";
224
    /// std::cout << "all doubles:  "sv << arr.is_homogeneous<double>() << "\n";
225
    /// std::cout << "all arrays:   "sv << arr.is_homogeneous<toml::array>() << "\n";
226
    /// std::cout << "all integers: "sv << arr.is_homogeneous<int64_t>() << "\n";
227
    /// \ecpp
228
    ///
229
    /// \out
230
    /// homogeneous: true
231
    /// all floats:  false
232
    /// all arrays:  false
233
    /// all ints:    true
234
    /// \eout
235
    ///
236
    /// \tparam ElemType  A TOML node or value type. <br>
237
    ///           \conditional_return{Left as `void`}
238
    ///           "is every element the same type?" <br>
239
    ///           \conditional_return{Explicitly specified}
240
    ///           "is every element a T?"
241
    ///
242
    /// \returns  True if the node was homogeneous.
243
    ///
244
    /// \remarks  Always returns `false` for empty tables and arrays.
245
    template <typename ElemType = void>
246
    TOML_PURE_GETTER
247
    bool is_homogeneous() const noexcept
248
    {
249
      using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
250
      static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
251
              "The template type argument of node::is_homogeneous() must be void or one "
252
              "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
253
254
      return is_homogeneous(impl::node_type_of<type>);
255
    }
256
257
    /// \brief  Returns the node's type identifier.
258
    TOML_PURE_GETTER
259
    virtual node_type type() const noexcept TOML_NVCC_WORKAROUND;
260
261
    /// \brief  Returns true if this node is a table.
262
    TOML_PURE_GETTER
263
    virtual bool is_table() const noexcept TOML_NVCC_WORKAROUND;
264
265
    /// \brief  Returns true if this node is an array.
266
    TOML_PURE_GETTER
267
    virtual bool is_array() const noexcept = 0;
268
269
    /// \brief  Returns true if this node is an array containing only tables.
270
    TOML_PURE_GETTER
271
    virtual bool is_array_of_tables() const noexcept TOML_NVCC_WORKAROUND;
272
273
    /// \brief  Returns true if this node is a value.
274
    TOML_PURE_GETTER
275
    virtual bool is_value() const noexcept = 0;
276
277
    /// \brief  Returns true if this node is a string value.
278
    TOML_PURE_GETTER
279
    virtual bool is_string() const noexcept = 0;
280
281
    /// \brief  Returns true if this node is an integer value.
282
    TOML_PURE_GETTER
283
    virtual bool is_integer() const noexcept = 0;
284
285
    /// \brief  Returns true if this node is an floating-point value.
286
    TOML_PURE_GETTER
287
    virtual bool is_floating_point() const noexcept = 0;
288
289
    /// \brief  Returns true if this node is an integer or floating-point value.
290
    TOML_PURE_GETTER
291
    virtual bool is_number() const noexcept = 0;
292
293
    /// \brief  Returns true if this node is a boolean value.
294
    TOML_PURE_GETTER
295
    virtual bool is_boolean() const noexcept = 0;
296
297
    /// \brief  Returns true if this node is a local date value.
298
    TOML_PURE_GETTER
299
    virtual bool is_date() const noexcept = 0;
300
301
    /// \brief  Returns true if this node is a local time value.
302
    TOML_PURE_GETTER
303
    virtual bool is_time() const noexcept = 0;
304
305
    /// \brief  Returns true if this node is a date-time value.
306
    TOML_PURE_GETTER
307
    virtual bool is_date_time() const noexcept = 0;
308
309
    /// \brief  Checks if a node is a specific type.
310
    ///
311
    /// \tparam T A TOML node or value type.
312
    ///
313
    /// \returns  Returns true if this node is an instance of the specified type.
314
    template <typename T>
315
    TOML_PURE_INLINE_GETTER
316
    bool is() const noexcept
317
    {
318
      using type = impl::remove_cvref<impl::unwrap_node<T>>;
319
      static_assert(toml::is_value<type> || toml::is_container<type>,
320
              "The template type argument of node::is() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
321
322
      if constexpr (std::is_same_v<type, table>)
323
        return is_table();
324
      else if constexpr (std::is_same_v<type, array>)
325
        return is_array();
326
      else if constexpr (std::is_same_v<type, std::string>)
327
        return is_string();
328
      else if constexpr (std::is_same_v<type, int64_t>)
329
        return is_integer();
330
      else if constexpr (std::is_same_v<type, double>)
331
        return is_floating_point();
332
      else if constexpr (std::is_same_v<type, bool>)
333
        return is_boolean();
334
      else if constexpr (std::is_same_v<type, date>)
335
        return is_date();
336
      else if constexpr (std::is_same_v<type, time>)
337
        return is_time();
338
      else if constexpr (std::is_same_v<type, date_time>)
339
        return is_date_time();
340
341
      TOML_UNREACHABLE;
342
    }
343
344
    /// @}
345
346
    /// \name Type casts
347
    /// @{
348
349
    /// \brief  Returns a pointer to the node as a toml::table, if it is one.
350
    TOML_PURE_GETTER
351
    virtual table* as_table() noexcept = 0;
352
353
    /// \brief  Returns a pointer to the node as a toml::array, if it is one.
354
    TOML_PURE_GETTER
355
    virtual array* as_array() noexcept = 0;
356
357
    /// \brief  Returns a pointer to the node as a toml::value<std::string>, if it is one.
358
    TOML_PURE_GETTER
359
    virtual toml::value<std::string>* as_string() noexcept = 0;
360
361
    /// \brief  Returns a pointer to the node as a toml::value<int64_t>, if it is one.
362
    TOML_PURE_GETTER
363
    virtual toml::value<int64_t>* as_integer() noexcept = 0;
364
365
    /// \brief  Returns a pointer to the node as a toml::value<double>, if it is one.
366
    TOML_PURE_GETTER
367
    virtual toml::value<double>* as_floating_point() noexcept = 0;
368
369
    /// \brief  Returns a pointer to the node as a toml::value<bool>, if it is one.
370
    TOML_PURE_GETTER
371
    virtual toml::value<bool>* as_boolean() noexcept = 0;
372
373
    /// \brief  Returns a pointer to the node as a toml::value<toml::date>, if it is one.
374
    TOML_PURE_GETTER
375
    virtual toml::value<date>* as_date() noexcept = 0;
376
377
    /// \brief  Returns a pointer to the node as a toml::value<toml::time>, if it is one.
378
    TOML_PURE_GETTER
379
    virtual toml::value<time>* as_time() noexcept = 0;
380
381
    /// \brief  Returns a pointer to the node as a toml::value<toml::date_time>, if it is one.
382
    TOML_PURE_GETTER
383
    virtual toml::value<date_time>* as_date_time() noexcept = 0;
384
385
    /// \brief  Returns a const-qualified pointer to the node as a toml::table, if it is one.
386
    TOML_PURE_GETTER
387
    virtual const table* as_table() const noexcept = 0;
388
389
    /// \brief  Returns a const-qualified pointer to the node as a toml::array, if it is one.
390
    TOML_PURE_GETTER
391
    virtual const array* as_array() const noexcept = 0;
392
393
    /// \brief  Returns a const-qualified pointer to the node as a toml::value<std::string>, if it is one.
394
    TOML_PURE_GETTER
395
    virtual const toml::value<std::string>* as_string() const noexcept = 0;
396
397
    /// \brief  Returns a const-qualified pointer to the node as a toml::value<int64_t>, if it is one.
398
    TOML_PURE_GETTER
399
    virtual const toml::value<int64_t>* as_integer() const noexcept = 0;
400
401
    /// \brief  Returns a const-qualified pointer to the node as a toml::value<double>, if it is one.
402
    TOML_PURE_GETTER
403
    virtual const toml::value<double>* as_floating_point() const noexcept = 0;
404
405
    /// \brief  Returns a const-qualified pointer to the node as a toml::value<bool>, if it is one.
406
    TOML_PURE_GETTER
407
    virtual const toml::value<bool>* as_boolean() const noexcept = 0;
408
409
    /// \brief  Returns a const-qualified pointer to the node as a toml::value<toml::date>, if it is one.
410
    TOML_PURE_GETTER
411
    virtual const toml::value<date>* as_date() const noexcept = 0;
412
413
    /// \brief  Returns a const-qualified pointer to the node as a toml::value<toml::time>, if it is one.
414
    TOML_PURE_GETTER
415
    virtual const toml::value<time>* as_time() const noexcept = 0;
416
417
    /// \brief  Returns a const-qualified pointer to the node as a toml::value<toml::date_time>, if it is one.
418
    TOML_PURE_GETTER
419
    virtual const toml::value<date_time>* as_date_time() const noexcept = 0;
420
421
    /// \brief  Gets a pointer to the node as a more specific node type.
422
    ///
423
    /// \details \cpp
424
    ///
425
    /// toml::value<int64_t>* int_value = node->as<int64_t>();
426
    /// toml::table* tbl = node->as<toml::table>();
427
    /// if (int_value)
428
    ///   std::cout << "Node is a value<int64_t>\n";
429
    /// else if (tbl)
430
    ///   std::cout << "Node is a table\n";
431
    ///
432
    /// // fully-qualified value node types also work (useful for template code):
433
    /// toml::value<int64_t>* int_value2 = node->as<toml::value<int64_t>>();
434
    /// if (int_value2)
435
    ///   std::cout << "Node is a value<int64_t>\n";
436
    /// \ecpp
437
    ///
438
    /// \tparam T The node type or TOML value type to cast to.
439
    ///
440
    /// \returns  A pointer to the node as the given type, or nullptr if it was a different type.
441
    template <typename T>
442
    TOML_PURE_INLINE_GETTER
443
    impl::wrap_node<T>* as() noexcept
444
0
    {
445
0
      using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
446
0
      static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
447
0
              "The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
448
0
449
0
      if constexpr (std::is_same_v<unwrapped_type, table>)
450
0
        return as_table();
451
0
      else if constexpr (std::is_same_v<unwrapped_type, array>)
452
0
        return as_array();
453
0
      else if constexpr (std::is_same_v<unwrapped_type, std::string>)
454
0
        return as_string();
455
0
      else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
456
0
        return as_integer();
457
0
      else if constexpr (std::is_same_v<unwrapped_type, double>)
458
0
        return as_floating_point();
459
0
      else if constexpr (std::is_same_v<unwrapped_type, bool>)
460
0
        return as_boolean();
461
0
      else if constexpr (std::is_same_v<unwrapped_type, date>)
462
0
        return as_date();
463
0
      else if constexpr (std::is_same_v<unwrapped_type, time>)
464
0
        return as_time();
465
0
      else if constexpr (std::is_same_v<unwrapped_type, date_time>)
466
0
        return as_date_time();
467
0
468
0
      TOML_UNREACHABLE;
469
0
    }
Unexecuted instantiation: toml::v3::impl::node_wrapper<__remove_reference_t, toml::v3::table>::type* toml::v3::node::as<toml::v3::table>()
Unexecuted instantiation: toml::v3::impl::node_wrapper<__remove_reference_t, toml::v3::array>::type* toml::v3::node::as<toml::v3::array>()
470
471
    /// \brief  Gets a pointer to the node as a more specific node type (const overload).
472
    template <typename T>
473
    TOML_PURE_INLINE_GETTER
474
    const impl::wrap_node<T>* as() const noexcept
475
0
    {
476
0
      using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
477
0
      static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
478
0
              "The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
479
0
480
0
      if constexpr (std::is_same_v<unwrapped_type, table>)
481
0
        return as_table();
482
0
      else if constexpr (std::is_same_v<unwrapped_type, array>)
483
0
        return as_array();
484
0
      else if constexpr (std::is_same_v<unwrapped_type, std::string>)
485
0
        return as_string();
486
0
      else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
487
0
        return as_integer();
488
0
      else if constexpr (std::is_same_v<unwrapped_type, double>)
489
0
        return as_floating_point();
490
0
      else if constexpr (std::is_same_v<unwrapped_type, bool>)
491
0
        return as_boolean();
492
0
      else if constexpr (std::is_same_v<unwrapped_type, date>)
493
0
        return as_date();
494
0
      else if constexpr (std::is_same_v<unwrapped_type, time>)
495
0
        return as_time();
496
0
      else if constexpr (std::is_same_v<unwrapped_type, date_time>)
497
0
        return as_date_time();
498
0
499
0
      TOML_UNREACHABLE;
500
0
    }
Unexecuted instantiation: toml::v3::impl::node_wrapper<__remove_reference_t, toml::v3::table>::type const* toml::v3::node::as<toml::v3::table>() const
Unexecuted instantiation: toml::v3::impl::node_wrapper<__remove_reference_t, toml::v3::array>::type const* toml::v3::node::as<toml::v3::array>() const
Unexecuted instantiation: toml::v3::impl::node_wrapper<__remove_reference_t, toml::v3::value<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::type const* toml::v3::node::as<toml::v3::value<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >() const
Unexecuted instantiation: toml::v3::impl::node_wrapper<__remove_reference_t, toml::v3::value<long> >::type const* toml::v3::node::as<toml::v3::value<long> >() const
Unexecuted instantiation: toml::v3::impl::node_wrapper<__remove_reference_t, toml::v3::value<double> >::type const* toml::v3::node::as<toml::v3::value<double> >() const
Unexecuted instantiation: toml::v3::impl::node_wrapper<__remove_reference_t, toml::v3::value<bool> >::type const* toml::v3::node::as<toml::v3::value<bool> >() const
Unexecuted instantiation: toml::v3::impl::node_wrapper<__remove_reference_t, toml::v3::value<toml::v3::date> >::type const* toml::v3::node::as<toml::v3::value<toml::v3::date> >() const
Unexecuted instantiation: toml::v3::impl::node_wrapper<__remove_reference_t, toml::v3::value<toml::v3::time> >::type const* toml::v3::node::as<toml::v3::value<toml::v3::time> >() const
Unexecuted instantiation: toml::v3::impl::node_wrapper<__remove_reference_t, toml::v3::value<toml::v3::stdopt::date_time> >::type const* toml::v3::node::as<toml::v3::value<toml::v3::stdopt::date_time> >() const
501
502
    /// @}
503
504
    /// \name Value retrieval
505
    /// @{
506
507
    /// \brief  Gets the value contained by this node.
508
    ///
509
    /// \detail This function has 'exact' retrieval semantics; the only return value types allowed are the
510
    ///     TOML native value types, or types that can losslessly represent a native value type (e.g.
511
    ///     std::wstring on Windows).
512
    ///
513
    /// \tparam T One of the native TOML value types, or a type capable of losslessly representing one.
514
    ///
515
    /// \returns  The underlying value if the node was a value of the
516
    ///       matching type (or losslessly convertible to it), or an empty optional.
517
    ///
518
    /// \see node::value()
519
    template <typename T>
520
    TOML_NODISCARD
521
    optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>);
522
523
    /// \brief  Gets the value contained by this node.
524
    ///
525
    /// \detail This function has 'permissive' retrieval semantics; some value types are allowed
526
    ///     to convert to others (e.g. retrieving a boolean as an integer), and the specified return value
527
    ///     type can be any type where a reasonable conversion from a native TOML value exists
528
    ///     (e.g. std::wstring on Windows). If the source value cannot be represented by
529
    ///     the destination type, an empty optional is returned.
530
    ///
531
    /// \godbolt{zzG81K}
532
    ///
533
    /// \cpp
534
    /// auto tbl = toml::parse(R"(
535
    ///   int = -10
536
    ///   flt = 25.0
537
    ///   pi  = 3.14159
538
    ///   bool = false
539
    ///   huge = 9223372036854775807
540
    ///   str = "foo"
541
    /// )"sv);
542
    ///
543
    /// const auto print_value_with_typename =
544
    ///   [&](std::string_view key, std::string_view type_name, auto* dummy)
545
    ///   {
546
    ///     std::cout << "- " << std::setw(18) << std::left << type_name;
547
    ///     using type = std::remove_pointer_t<decltype(dummy)>;
548
    ///     if (auto val = tbl.get(key)->value<type>(); val)
549
    ///       std::cout << *val << "\n";
550
    ///     else
551
    ///       std::cout << "n/a\n";
552
    ///   };
553
    ///
554
    /// #define print_value(key, T) print_value_with_typename(key, #T, (T*)nullptr)
555
    ///
556
    /// for (auto key : { "int", "flt", "pi", "bool", "huge", "str" })
557
    /// {
558
    ///   std::cout << tbl[key].type() << " value '" << key << "' as:\n";
559
    ///   print_value(key, bool);
560
    ///   print_value(key, int);
561
    ///   print_value(key, unsigned int);
562
    ///   print_value(key, long long);
563
    ///   print_value(key, float);
564
    ///   print_value(key, double);
565
    ///   print_value(key, std::string);
566
    ///   print_value(key, std::string_view);
567
    ///   print_value(key, const char*);
568
    ///   std::cout << "\n";
569
    /// }
570
    /// \ecpp
571
    ///
572
    /// \out
573
    /// integer value 'int' as:
574
    /// - bool              true
575
    /// - int               -10
576
    /// - unsigned int      n/a
577
    /// - long long         -10
578
    /// - float             -10
579
    /// - double            -10
580
    /// - std::string       n/a
581
    /// - std::string_view  n/a
582
    /// - const char*       n/a
583
    ///
584
    /// floating-point value 'flt' as:
585
    /// - bool              n/a
586
    /// - int               25
587
    /// - unsigned int      25
588
    /// - long long         25
589
    /// - float             25
590
    /// - double            25
591
    /// - std::string       n/a
592
    /// - std::string_view  n/a
593
    /// - const char*       n/a
594
    ///
595
    /// floating-point value 'pi' as:
596
    /// - bool              n/a
597
    /// - int               n/a
598
    /// - unsigned int      n/a
599
    /// - long long         n/a
600
    /// - float             3.14159
601
    /// - double            3.14159
602
    /// - std::string       n/a
603
    /// - std::string_view  n/a
604
    /// - const char*       n/a
605
    ///
606
    /// boolean value 'bool' as:
607
    /// - bool              false
608
    /// - int               0
609
    /// - unsigned int      0
610
    /// - long long         0
611
    /// - float             n/a
612
    /// - double            n/a
613
    /// - std::string       n/a
614
    /// - std::string_view  n/a
615
    /// - const char*       n/a
616
    ///
617
    /// integer value 'huge' as:
618
    /// - bool              true
619
    /// - int               n/a
620
    /// - unsigned int      n/a
621
    /// - long long         9223372036854775807
622
    /// - float             n/a
623
    /// - double            n/a
624
    /// - std::string       n/a
625
    /// - std::string_view  n/a
626
    /// - const char*       n/a
627
    ///
628
    /// string value 'str' as:
629
    /// - bool              n/a
630
    /// - int               n/a
631
    /// - unsigned int      n/a
632
    /// - long long         n/a
633
    /// - float             n/a
634
    /// - double            n/a
635
    /// - std::string       foo
636
    /// - std::string_view  foo
637
    /// - const char*       foo
638
    /// \eout
639
    ///
640
    /// \tparam T One of the native TOML value types, or a type capable of converting to one.
641
    ///
642
    /// \returns  The underlying value if the node was a value of the matching type (or convertible to it)
643
    ///       and within the range of the output type, or an empty optional.
644
    ///
645
    /// \note   If you want strict value retrieval semantics that do not allow for any type conversions,
646
    ///       use node::value_exact() instead.
647
    ///
648
    /// \see node::value_exact()
649
    template <typename T>
650
    TOML_NODISCARD
651
    optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>);
652
653
    /// \brief  Gets the raw value contained by this node, or a default.
654
    ///
655
    /// \tparam T       Default value type. Must be one of the native TOML value types,
656
    ///             or convertible to it.
657
    /// \param  default_value The default value to return if the node wasn't a value, wasn't the
658
    ///             correct type, or no conversion was possible.
659
    ///
660
    /// \returns  The underlying value if the node was a value of the matching type (or convertible to it)
661
    ///       and within the range of the output type, or the provided default.
662
    ///
663
    /// \note This function has the same permissive retrieval semantics as node::value(). If you want strict
664
    ///     value retrieval semantics that do not allow for any type conversions, use node::value_exact()
665
    ///     instead.
666
    ///
667
    /// \see
668
    ///   - node::value()
669
    ///   - node::value_exact()
670
    template <typename T>
671
    TOML_NODISCARD
672
    auto value_or(T&& default_value) const noexcept(impl::value_retrieval_is_nothrow<T>);
673
674
    /// \brief  Gets a raw reference to a node's underlying data.
675
    ///
676
    /// \warning This function is dangerous if used carelessly and **WILL** break your code if the
677
    ///      chosen value type doesn't match the node's actual type. In debug builds an assertion
678
    ///      will fire when invalid accesses are attempted: \cpp
679
    ///
680
    /// auto tbl = toml::parse(R"(
681
    ///   min = 32
682
    ///   max = 45
683
    /// )"sv);
684
    ///
685
    /// int64_t& min_ref = tbl.at("min").ref<int64_t>(); // matching type
686
    /// double& max_ref = tbl.at("max").ref<double>();  // mismatched type, hits assert()
687
    /// \ecpp
688
    ///
689
    /// \note Specifying explicit ref qualifiers acts as an explicit ref-category cast,
690
    ///     whereas specifying explicit cv-ref qualifiers merges them with whatever
691
    ///     the cv qualification of the node is (to ensure cv-correctness is propagated), e.g.:
692
    ///     | node        | T                      | return type                  |
693
    ///     |-------------|------------------------|------------------------------|
694
    ///     | node&       | std::string            | std::string&                 |
695
    ///     | node&       | std::string&&          | std::string&&                |
696
    ///     | const node& | volatile std::string   | const volatile std::string&  |
697
    ///     | const node& | volatile std::string&& | const volatile std::string&& |
698
    ///
699
    /// \tparam T toml::table, toml::array, or one of the TOML value types.
700
    ///
701
    /// \returns  A reference to the underlying data.
702
    template <typename T>
703
    TOML_PURE_GETTER
704
    decltype(auto) ref() & noexcept
705
    {
706
      return do_ref<T>(*this);
707
    }
708
709
    /// \brief  Gets a raw reference to a node's underlying data (rvalue overload).
710
    template <typename T>
711
    TOML_PURE_GETTER
712
    decltype(auto) ref() && noexcept
713
    {
714
      return do_ref<T>(std::move(*this));
715
    }
716
717
    /// \brief  Gets a raw reference to a node's underlying data (const lvalue overload).
718
    template <typename T>
719
    TOML_PURE_GETTER
720
    decltype(auto) ref() const& noexcept
721
    {
722
      return do_ref<T>(*this);
723
    }
724
725
    /// \brief  Gets a raw reference to a node's underlying data (const rvalue overload).
726
    template <typename T>
727
    TOML_PURE_GETTER
728
    decltype(auto) ref() const&& noexcept
729
    {
730
      return do_ref<T>(std::move(*this));
731
    }
732
733
    /// @}
734
735
    /// \name Metadata
736
    /// @{
737
738
    /// \brief  Returns the source region responsible for generating this node during parsing.
739
    TOML_PURE_INLINE_GETTER
740
    const source_region& source() const noexcept
741
778k
    {
742
778k
      return source_;
743
778k
    }
744
745
    /// @}
746
747
    private:
748
    /// \cond
749
750
    template <typename Func, typename Node, typename T>
751
    static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<T, Node>>;
752
753
    template <typename Func, typename Node, typename T>
754
    static constexpr bool can_visit_nothrow = std::is_nothrow_invocable_v<Func, ref_cast_type<T, Node>>;
755
756
    template <typename Func, typename Node>
757
    static constexpr bool can_visit_any = can_visit<Func, Node, table>     //
758
                       || can_visit<Func, Node, array>     //
759
                       || can_visit<Func, Node, std::string> //
760
                       || can_visit<Func, Node, int64_t>   //
761
                       || can_visit<Func, Node, double>    //
762
                       || can_visit<Func, Node, bool>    //
763
                       || can_visit<Func, Node, date>    //
764
                       || can_visit<Func, Node, time>    //
765
                       || can_visit<Func, Node, date_time>;
766
767
    // clang-format off
768
769
    template <typename Func, typename Node>
770
    static constexpr bool can_visit_all = can_visit<Func, Node, table>     //
771
                       && can_visit<Func, Node, array>     //
772
                       && can_visit<Func, Node, std::string> //
773
                       && can_visit<Func, Node, int64_t>   //
774
                       && can_visit<Func, Node, double>    //
775
                       && can_visit<Func, Node, bool>    //
776
                       && can_visit<Func, Node, date>    //
777
                       && can_visit<Func, Node, time>    //
778
                       && can_visit<Func, Node, date_time>;
779
780
    template <typename Func, typename Node, typename T>
781
    static constexpr bool visit_is_nothrow_one = !can_visit<Func, Node, T> || can_visit_nothrow<Func, Node, T>;
782
783
    template <typename Func, typename Node>
784
    static constexpr bool visit_is_nothrow = visit_is_nothrow_one<Func, Node, table>     //
785
                        && visit_is_nothrow_one<Func, Node, array>     //
786
                        && visit_is_nothrow_one<Func, Node, std::string> //
787
                        && visit_is_nothrow_one<Func, Node, int64_t>     //
788
                        && visit_is_nothrow_one<Func, Node, double>    //
789
                        && visit_is_nothrow_one<Func, Node, bool>      //
790
                        && visit_is_nothrow_one<Func, Node, date>      //
791
                        && visit_is_nothrow_one<Func, Node, time>      //
792
                        && visit_is_nothrow_one<Func, Node, date_time>;
793
794
    // clang-format on
795
796
    template <typename Func, typename Node, typename T, bool = can_visit<Func, Node, T>>
797
    struct visit_return_type_
798
    {
799
      using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<T, Node>>()));
800
    };
801
    template <typename Func, typename Node, typename T>
802
    struct visit_return_type_<Func, Node, T, false>
803
    {
804
      using type = void;
805
    };
806
807
    template <typename Func, typename Node, typename T>
808
    using visit_return_type = typename visit_return_type_<Func, Node, T>::type;
809
810
    template <typename A, typename B>
811
    using nonvoid = std::conditional_t<std::is_void_v<A>, B, A>;
812
813
    template <typename Func, typename Node>
814
    static decltype(auto) do_visit(Func&& visitor, Node&& n) noexcept(visit_is_nothrow<Func&&, Node&&>)
815
0
    {
816
0
      static_assert(can_visit_any<Func&&, Node&&>,
817
0
              "TOML node visitors must be invocable for at least one of the toml::node "
818
0
              "specializations:" TOML_SA_NODE_TYPE_LIST);
819
0
820
0
      switch (n.type())
821
0
      {
822
0
        case node_type::table:
823
0
          if constexpr (can_visit<Func&&, Node&&, table>)
824
0
            return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<table>());
825
0
          break;
826
0
827
0
        case node_type::array:
828
0
          if constexpr (can_visit<Func&&, Node&&, array>)
829
0
            return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<array>());
830
0
          break;
831
0
832
0
        case node_type::string:
833
0
          if constexpr (can_visit<Func&&, Node&&, std::string>)
834
0
            return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<std::string>());
835
0
          break;
836
0
837
0
        case node_type::integer:
838
0
          if constexpr (can_visit<Func&&, Node&&, int64_t>)
839
0
            return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<int64_t>());
840
0
          break;
841
0
842
0
        case node_type::floating_point:
843
0
          if constexpr (can_visit<Func&&, Node&&, double>)
844
0
            return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<double>());
845
0
          break;
846
0
847
0
        case node_type::boolean:
848
0
          if constexpr (can_visit<Func&&, Node&&, bool>)
849
0
            return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<bool>());
850
0
          break;
851
0
852
0
        case node_type::date:
853
0
          if constexpr (can_visit<Func&&, Node&&, date>)
854
0
            return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<date>());
855
0
          break;
856
0
857
0
        case node_type::time:
858
0
          if constexpr (can_visit<Func&&, Node&&, time>)
859
0
            return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<time>());
860
0
          break;
861
0
862
0
        case node_type::date_time:
863
0
          if constexpr (can_visit<Func&&, Node&&, date_time>)
864
0
            return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<date_time>());
865
0
          break;
866
0
867
0
        case node_type::none: TOML_UNREACHABLE;
868
0
        default: TOML_UNREACHABLE;
869
0
      }
870
0
871
0
      if constexpr (!can_visit_all<Func&&, Node&&>)
872
0
      {
873
0
        // clang-format off
874
0
875
0
        using return_type =
876
0
          nonvoid<visit_return_type<Func&&, Node&&, table>,
877
0
          nonvoid<visit_return_type<Func&&, Node&&, array>,
878
0
          nonvoid<visit_return_type<Func&&, Node&&, std::string>,
879
0
          nonvoid<visit_return_type<Func&&, Node&&, int64_t>,
880
0
          nonvoid<visit_return_type<Func&&, Node&&, double>,
881
0
          nonvoid<visit_return_type<Func&&, Node&&, bool>,
882
0
          nonvoid<visit_return_type<Func&&, Node&&, date>,
883
0
          nonvoid<visit_return_type<Func&&, Node&&, time>,
884
0
              visit_return_type<Func&&, Node&&, date_time>
885
0
        >>>>>>>>;
886
0
887
0
        // clang-format on
888
0
889
0
        if constexpr (!std::is_void_v<return_type>)
890
0
        {
891
0
          static_assert(std::is_default_constructible_v<return_type>,
892
0
                  "Non-exhaustive visitors must return a default-constructible type, or void");
893
0
          return return_type{};
894
0
        }
895
0
      }
896
0
    }
Unexecuted instantiation: decltype(auto) toml::v3::node::do_visit<toml::v3::impl::node_deep_equality(toml::v3::node const*, toml::v3::node const*)::{lambda(auto:1&)#1}, toml::v3::node const&>(toml::v3::impl::node_deep_equality(toml::v3::node const*, toml::v3::node const*)::{lambda(auto:1&)#1}&&, toml::v3::node const&)
Unexecuted instantiation: decltype(auto) toml::v3::node::do_visit<toml::v3::array::equal(toml::v3::array const&, toml::v3::array const&)::{lambda(auto:1 const&)#1}, toml::v3::node&>(toml::v3::array::equal(toml::v3::array const&, toml::v3::array const&)::{lambda(auto:1 const&)#1}&&, toml::v3::node&)
Unexecuted instantiation: decltype(auto) toml::v3::node::do_visit<toml::v3::table::equal(toml::v3::table const&, toml::v3::table const&)::{lambda(auto:1 const&)#1}, toml::v3::node&>(toml::v3::table::equal(toml::v3::table const&, toml::v3::table const&)::{lambda(auto:1 const&)#1}&&, toml::v3::node&)
Unexecuted instantiation: decltype(auto) toml::v3::node::do_visit<toml::v3::impl::make_node_impl<toml::v3::node const&>(toml::v3::node const&, toml::v3::value_flags)::{lambda(auto:1&&)#1}, toml::v3::node const&>(toml::v3::node const&, toml::v3::node const&)
Unexecuted instantiation: decltype(auto) toml::v3::node::do_visit<toml::v3::impl::make_node_impl<toml::v3::node&>(toml::v3::node&, toml::v3::value_flags)::{lambda(auto:1&&)#1}, toml::v3::node&>(toml::v3::node&, toml::v3::node&)
897
898
    /// \endcond
899
900
    public:
901
    /// \name Visitation
902
    /// @{
903
904
    /// \brief  Invokes a visitor on the node based on the node's concrete type.
905
    ///
906
    /// \details Visitation is useful when you expect
907
    ///      a node to be one of a set number of types and need
908
    ///      to handle these types differently. Using `visit()` allows
909
    ///      you to eliminate some of the casting/conversion boilerplate: \cpp
910
    ///
911
    /// node.visit([](auto&& n)
912
    /// {
913
    ///   if constexpr (toml::is_string<decltype(n)>)
914
    ///     do_something_with_a_string(*n)); //n is a toml::value<std::string>
915
    ///   else if constexpr (toml::is_integer<decltype(n)>)
916
    ///     do_something_with_an_int(*n); //n is a toml::value<int64_t>
917
    /// });
918
    /// \ecpp
919
    ///
920
    /// Visitor functions need not be generic; specifying a concrete node type as the input argument type
921
    /// effectively acts a 'filter', only invoking the visitor if the concrete type is compatible.
922
    /// Thus the example above can be re-written as: \cpp
923
    /// node.visit([](toml::value<std::string>& s) { do_something_with_a_string(*s)); });
924
    /// node.visit([](toml::value<int64_t>& i)     { do_something_with_an_int(*i)); });
925
    /// \ecpp
926
    ///
927
    /// \tparam Func  A callable type invocable with one or more of the toml++ node types.
928
    ///
929
    /// \param  visitor The visitor object.
930
    ///
931
    /// \returns The return value of the visitor.
932
    ///      Can be void. Non-exhaustive visitors must return a default-constructible type.
933
    ///
934
    /// \see https://en.wikipedia.org/wiki/Visitor_pattern
935
    template <typename Func>
936
    decltype(auto) visit(Func&& visitor) & noexcept(visit_is_nothrow<Func&&, node&>)
937
0
    {
938
0
      return do_visit(static_cast<Func&&>(visitor), *this);
939
0
    }
Unexecuted instantiation: decltype(auto) toml::v3::node::visit<toml::v3::array::equal(toml::v3::array const&, toml::v3::array const&)::{lambda(auto:1 const&)#1}>(toml::v3::array::equal(toml::v3::array const&, toml::v3::array const&)::{lambda(auto:1 const&)#1}&&) &
Unexecuted instantiation: decltype(auto) toml::v3::node::visit<toml::v3::table::equal(toml::v3::table const&, toml::v3::table const&)::{lambda(auto:1 const&)#1}>(toml::v3::table::equal(toml::v3::table const&, toml::v3::table const&)::{lambda(auto:1 const&)#1}&&) &
Unexecuted instantiation: decltype(auto) toml::v3::node::visit<toml::v3::impl::make_node_impl<toml::v3::node&>(toml::v3::node&, toml::v3::value_flags)::{lambda(auto:1&&)#1}>(toml::v3::node&) &
940
941
    /// \brief  Invokes a visitor on the node based on the node's concrete type (rvalue overload).
942
    template <typename Func>
943
    decltype(auto) visit(Func&& visitor) && noexcept(visit_is_nothrow<Func&&, node&&>)
944
    {
945
      return do_visit(static_cast<Func&&>(visitor), static_cast<node&&>(*this));
946
    }
947
948
    /// \brief  Invokes a visitor on the node based on the node's concrete type (const lvalue overload).
949
    template <typename Func>
950
    decltype(auto) visit(Func&& visitor) const& noexcept(visit_is_nothrow<Func&&, const node&>)
951
0
    {
952
0
      return do_visit(static_cast<Func&&>(visitor), *this);
953
0
    }
Unexecuted instantiation: decltype(auto) toml::v3::node::visit<toml::v3::impl::node_deep_equality(toml::v3::node const*, toml::v3::node const*)::{lambda(auto:1&)#1}>(toml::v3::impl::node_deep_equality(toml::v3::node const*, toml::v3::node const*)::{lambda(auto:1&)#1}&&) const &
Unexecuted instantiation: decltype(auto) toml::v3::node::visit<toml::v3::impl::make_node_impl<toml::v3::node const&>(toml::v3::node const&, toml::v3::value_flags)::{lambda(auto:1&&)#1}>(toml::v3::node const&) const &
954
955
    /// \brief  Invokes a visitor on the node based on the node's concrete type (const rvalue overload).
956
    template <typename Func>
957
    decltype(auto) visit(Func&& visitor) const&& noexcept(visit_is_nothrow<Func&&, const node&&>)
958
    {
959
      return do_visit(static_cast<Func&&>(visitor), static_cast<const node&&>(*this));
960
    }
961
962
    /// @}
963
964
    /// \name Node views
965
    /// @{
966
967
    /// \brief  Creates a node_view pointing to this node.
968
    TOML_NODISCARD
969
    explicit operator node_view<node>() noexcept;
970
971
    /// \brief  Creates a node_view pointing to this node (const overload).
972
    TOML_NODISCARD
973
    explicit operator node_view<const node>() const noexcept;
974
975
    /// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
976
    ///
977
    /// \detail \cpp
978
    /// auto config = toml::parse(R"(
979
    ///
980
    /// [foo]
981
    /// bar = [ 0, 1, 2, [ 3 ], { kek = 4 } ]
982
    ///
983
    /// )"sv);
984
    ///
985
    /// std::cout << config.at_path("foo.bar[2]") << "\n";
986
    /// std::cout << config.at_path("foo.bar[3][0]") << "\n";
987
    /// std::cout << config.at_path("foo.bar[4].kek") << "\n";
988
    /// \ecpp
989
    ///
990
    /// \out
991
    /// 2
992
    /// 3
993
    /// 4
994
    /// \eout
995
    ///
996
    ///
997
    /// \note Keys in paths are interpreted literally, so whitespace (or lack thereof) matters:
998
    /// \cpp
999
    /// config.at_path( "foo.bar")  // same as node_view{ config }["foo"]["bar"]
1000
    /// config.at_path( "foo. bar") // same as node_view{ config }["foo"][" bar"]
1001
    /// config.at_path( "foo..bar") // same as node_view{ config }["foo"][""]["bar"]
1002
    /// config.at_path( ".foo.bar") // same as node_view{ config }[""]["foo"]["bar"]
1003
    /// \ecpp
1004
    /// <br>
1005
    /// Additionally, TOML allows '.' (period) characters to appear in keys if they are quoted strings.
1006
    /// This function makes no allowance for this, instead treating all period characters as sub-table delimiters.
1007
    /// If you have periods in your table keys, first consider:
1008
    /// 1. Not doing that
1009
    /// 2. Using node_view::operator[] instead.
1010
    ///
1011
    /// \param path   The "TOML path" to traverse.
1012
    TOML_NODISCARD
1013
    TOML_EXPORTED_MEMBER_FUNCTION
1014
    node_view<node> at_path(std::string_view path) noexcept;
1015
1016
    /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
1017
    ///
1018
    /// \see #at_path(std::string_view)
1019
    TOML_NODISCARD
1020
    TOML_EXPORTED_MEMBER_FUNCTION
1021
    node_view<const node> at_path(std::string_view path) const noexcept;
1022
1023
    /// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
1024
    ///
1025
    /// \detail \cpp
1026
    /// auto config = toml::parse(R"(
1027
    ///
1028
    /// [foo]
1029
    /// bar = [ 0, 1, 2, [ 3 ], { kek = 4 } ]
1030
    ///
1031
    /// )"sv);
1032
    ///
1033
    /// toml::path path1("foo.bar[2]");
1034
    /// toml::path path2("foo.bar[4].kek");
1035
    /// std::cout << config.at_path(path1) << "\n";
1036
    /// std::cout << config.at_path(path1.parent_path()) << "\n";
1037
    /// std::cout << config.at_path(path2) << "\n";
1038
    /// std::cout << config.at_path(path2.parent_path()) << "\n";
1039
    /// \ecpp
1040
    ///
1041
    /// \out
1042
    /// 2
1043
    /// [ 0, 1, 2, [ 3 ], { kek = 4 } ]
1044
    /// 4
1045
    /// { kek  = 4 }
1046
    /// \eout
1047
    ///
1048
    ///
1049
    /// \note Keys in paths are interpreted literally, so whitespace (or lack thereof) matters:
1050
    /// \cpp
1051
    /// config.at_path(toml::path("foo.bar")) // same as node_view{ config }["foo"]["bar"]
1052
    /// config.at_path(toml::path("foo. bar")) // same as node_view{ config }["foo"][" bar"]
1053
    /// config.at_path(toml::path("foo..bar")) // same as node_view{ config }["foo"][""]["bar"]
1054
    /// config.at_path(toml::path(".foo.bar")) // same as node_view{ config }[""]["foo"]["bar"]
1055
    /// \ecpp
1056
    /// <br>
1057
    /// Additionally, TOML allows '.' (period) characters to appear in keys if they are quoted strings.
1058
    /// This function makes no allowance for this, instead treating all period characters as sub-table delimiters.
1059
    ///
1060
    /// \param path   The "TOML path" to traverse.
1061
    TOML_NODISCARD
1062
    TOML_EXPORTED_MEMBER_FUNCTION
1063
    node_view<node> at_path(const toml::path& path) noexcept;
1064
1065
    /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
1066
    ///
1067
    /// \see #at_path(const toml::path&)
1068
    TOML_NODISCARD
1069
    TOML_EXPORTED_MEMBER_FUNCTION
1070
    node_view<const node> at_path(const toml::path& path) const noexcept;
1071
1072
#if TOML_ENABLE_WINDOWS_COMPAT
1073
1074
    /// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
1075
    ///
1076
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
1077
    ///
1078
    /// \see #at_path(std::string_view)
1079
    TOML_NODISCARD
1080
    TOML_EXPORTED_MEMBER_FUNCTION
1081
    node_view<node> at_path(std::wstring_view path);
1082
1083
    /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
1084
    ///
1085
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
1086
    ///
1087
    /// \see #at_path(std::string_view)
1088
    TOML_NODISCARD
1089
    TOML_EXPORTED_MEMBER_FUNCTION
1090
    node_view<const node> at_path(std::wstring_view path) const;
1091
1092
#endif // TOML_ENABLE_WINDOWS_COMPAT
1093
1094
    /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
1095
    ///
1096
    /// \param  path The "TOML path" to the desired child.
1097
    ///
1098
    /// \returns  A view of the child node at the given path if one existed, or an empty node view.
1099
    ///
1100
    /// \see toml::node_view
1101
    TOML_NODISCARD
1102
    TOML_EXPORTED_MEMBER_FUNCTION
1103
    node_view<node> operator[](const toml::path& path) noexcept;
1104
1105
    /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
1106
    ///
1107
    /// \param  path The "TOML path" to the desired child.
1108
    ///
1109
    /// \returns  A view of the child node at the given path if one existed, or an empty node view.
1110
    ///
1111
    /// \see toml::node_view
1112
    TOML_NODISCARD
1113
    TOML_EXPORTED_MEMBER_FUNCTION
1114
    node_view<const node> operator[](const toml::path& path) const noexcept;
1115
1116
    /// @}
1117
  };
1118
}
1119
TOML_NAMESPACE_END;
1120
1121
/// \cond
1122
TOML_IMPL_NAMESPACE_START
1123
{
1124
  TOML_PURE_GETTER
1125
  TOML_EXPORTED_FREE_FUNCTION
1126
  bool TOML_CALLCONV node_deep_equality(const node*, const node*) noexcept;
1127
}
1128
TOML_IMPL_NAMESPACE_END;
1129
/// \endcond
1130
1131
#undef TOML_NVCC_WORKAROUND
1132
#include "header_end.hpp"