• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

fktn-k / fkYAML / 29705946184

19 Jul 2026 10:19PM UTC coverage: 99.849% (-0.2%) from 100.0%
29705946184

Pull #533

github

web-flow
Merge 3e816f793 into 772607306
Pull Request #533: Harden input adapter against truncated encoded input

1429 of 1434 branches covered (99.65%)

Branch coverage included in aggregate %.

93 of 97 new or added lines in 1 file covered. (95.88%)

1 existing line in 1 file now uncovered.

5187 of 5192 relevant lines covered (99.9%)

402.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.79
/include/fkYAML/node.hpp
1
//  _______   __ __   __  _____   __  __  __
2
// |   __| |_/  |  \_/  |/  _  \ /  \/  \|  |     fkYAML: A C++ header-only YAML library
3
// |   __|  _  < \_   _/|  ___  |    _   |  |___  version 0.4.3
4
// |__|  |_| \__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML
5
//
6
// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>
7
// SPDX-FileCopyrightText: 2023-2026 Kensuke Fukutani <fktn.dev@gmail.com>
8
// SPDX-License-Identifier: MIT
9

10
#ifndef FK_YAML_NODE_HPP
11
#define FK_YAML_NODE_HPP
12

13
#include <algorithm>
14
#include <cstdint>
15
#include <cstring>
16
#include <initializer_list>
17
#include <map>
18
#include <memory>
19
#include <string>
20
#include <type_traits>
21
#include <vector>
22

23
#include <fkYAML/detail/macros/define_macros.hpp>
24
#include <fkYAML/detail/assert.hpp>
25
#include <fkYAML/detail/document_metainfo.hpp>
26
#include <fkYAML/detail/exception_safe_allocation.hpp>
27
#include <fkYAML/detail/input/deserializer.hpp>
28
#include <fkYAML/detail/input/input_adapter.hpp>
29
#include <fkYAML/detail/iterator.hpp>
30
#include <fkYAML/detail/map_range_proxy.hpp>
31
#include <fkYAML/detail/meta/node_traits.hpp>
32
#include <fkYAML/detail/meta/stl_supplement.hpp>
33
#include <fkYAML/detail/meta/type_traits.hpp>
34
#include <fkYAML/detail/node_attrs.hpp>
35
#include <fkYAML/detail/node_property.hpp>
36
#include <fkYAML/detail/node_ref_storage.hpp>
37
#include <fkYAML/detail/output/serializer.hpp>
38
#include <fkYAML/detail/reverse_iterator.hpp>
39
#include <fkYAML/detail/types/node_t.hpp>
40
#include <fkYAML/detail/types/yaml_version_t.hpp>
41
#include <fkYAML/exception.hpp>
42
#include <fkYAML/node_type.hpp>
43
#include <fkYAML/node_value_converter.hpp>
44
#include <fkYAML/ordered_map.hpp>
45

46
FK_YAML_NAMESPACE_BEGIN
47

48
/// @brief A class to store value of YAML nodes.
49
/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/
50
template <
51
    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,
52
    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,
53
    template <typename, typename = void> class ConverterType>
54
class basic_node {
55
public:
56
    /// @brief A type for sequence basic_node values.
57
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/sequence_type/
58
    using sequence_type = SequenceType<basic_node, std::allocator<basic_node>>;
59

60
    /// @brief A type for mapping basic_node values.
61
    /// @note std::unordered_map is not supported since it does not allow incomplete types.
62
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/mapping_type/
63
    using mapping_type = MappingType<basic_node, basic_node>;
64

65
    /// @brief A type for boolean basic_node values.
66
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/boolean_type/
67
    using boolean_type = BooleanType;
68

69
    /// @brief A type for integer basic_node values.
70
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/integer_type/
71
    using integer_type = IntegerType;
72

73
    /// @brief A type for float number basic_node values.
74
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/float_number_type/
75
    using float_number_type = FloatNumberType;
76

77
    /// @brief A type for string basic_node values.
78
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/string_type/
79
    using string_type = StringType;
80

81
    /// @brief A type of elements in a basic_node container.
82
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types
83
    using value_type = basic_node;
84

85
    /// @brief A type of reference to a basic_node element.
86
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types
87
    using reference = value_type&;
88

89
    /// @brief A type of constant reference to a basic_node element.
90
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types
91
    using const_reference = const value_type&;
92

93
    /// @brief A type of a pointer to a basic_node element.
94
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types
95
    using pointer = value_type*;
96

97
    /// @brief A type of a constant pointer to a basic_node element.
98
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types
99
    using const_pointer = const value_type*;
100

101
    /// @brief A type to represent basic_node container sizes.
102
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types
103
    using size_type = std::size_t;
104

105
    /// @brief A type to represent differences between basic_node iterators.
106
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types
107
    using difference_type = std::ptrdiff_t;
108

109
    /// @brief A type for iterators of basic_node containers.
110
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/iterator/
111
    using iterator = fkyaml::detail::iterator<basic_node>;
112

113
    /// @brief A type for constant iterators of basic_node containers.
114
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/iterator/
115
    using const_iterator = fkyaml::detail::iterator<const basic_node>;
116

117
    /// @brief A type for reverse iterators of basic_node containers.
118
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/reverse_iterator/
119
    using reverse_iterator = fkyaml::detail::reverse_iterator<iterator>;
120

121
    /// @brief A type for constant reverse iterators of basic_node containers.
122
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/reverse_iterator/
123
    using const_reverse_iterator = fkyaml::detail::reverse_iterator<const_iterator>;
124

125
    /// @brief A helper alias to determine converter type for the given target native data type.
126
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/value_converter_type/
127
    template <typename T, typename SFINAE>
128
    using value_converter_type = ConverterType<T, SFINAE>;
129

130
    /// @brief Definition of node value types.
131
    /// @deprecated Use fkyaml::node_type enum class. (since 0.3.12)
132
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/node_t/
133
    using node_t = detail::node_t;
134

135
    /// @brief Definition of YAML version types.
136
    /// @deprecated Use fkyaml::yaml_version_type enum class. (since 0.3.12)
137
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/yaml_version_t/
138
    using yaml_version_t = detail::yaml_version_t;
139

140
    /// @brief A type for mapping range objects for the map_items() function.
141
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/map_range/
142
    using map_range = fkyaml::detail::map_range_proxy<basic_node>;
143

144
    /// @brief A type for constant mapping range objects for the map_items() function.
145
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/map_range/
146
    using const_map_range = fkyaml::detail::map_range_proxy<const basic_node>;
147

148
private:
149
    template <typename BasicNodeType>
150
    friend struct fkyaml::detail::external_node_constructor;
151

152
    template <typename BasicNodeType>
153
    friend class fkyaml::detail::basic_deserializer;
154

155
    template <typename BasicNodeType>
156
    friend class fkyaml::detail::basic_serializer;
157

158
    /// @brief A type for YAML docs deserializers.
159
    using deserializer_type = detail::basic_deserializer<basic_node>;
160
    /// @brief A type for YAML docs serializers.
161
    using serializer_type = detail::basic_serializer<basic_node>;
162
    /// @brief A helper type alias for std::initializer_list.
163
    using initializer_list_t = std::initializer_list<detail::node_ref_storage<basic_node>>;
164

165
    /// @brief The actual storage for a YAML node value of the @ref basic_node class.
166
    /// @details This union combines the different storage types for the YAML value types defined in @ref node_t.
167
    /// @note Container types are stored as pointers so that the size of this union will not exceed 64 bits by
168
    /// default.
169
    union node_value {
170
        /// @brief Constructs a new basic_node Value object for null types.
22,600✔
171
        node_value() = default;
172

173
        /// @brief Constructs a new basic_node value object with a node type. The default value for the specified
174
        /// type will be assigned.
175
        /// @param[in] type A node type.
30✔
176
        explicit node_value(detail::node_attr_t value_type_bit) {
30✔
177
            switch (value_type_bit) {
11✔
178
            case detail::node_attr_bits::seq_bit:
11✔
179
                p_seq = detail::create_object<sequence_type>();
11✔
180
                break;
8✔
181
            case detail::node_attr_bits::map_bit:
8✔
182
                p_map = detail::create_object<mapping_type>();
8✔
183
                break;
2✔
184
            case detail::node_attr_bits::null_bit:
2✔
185
                p_map = nullptr;
2✔
186
                break;
2✔
187
            case detail::node_attr_bits::bool_bit:
2✔
188
                boolean = static_cast<boolean_type>(false);
2✔
189
                break;
2✔
190
            case detail::node_attr_bits::int_bit:
2✔
191
                integer = static_cast<integer_type>(0);
2✔
192
                break;
2✔
193
            case detail::node_attr_bits::float_bit:
2✔
194
                float_val = static_cast<float_number_type>(0.0);
2✔
195
                break;
3✔
196
            case detail::node_attr_bits::string_bit:
3✔
197
                p_str = detail::create_object<string_type>();
2✔
198
                break;
199
            default:                   // LCOV_EXCL_LINE
200
                detail::unreachable(); // LCOV_EXCL_LINE
201
            }
29✔
202
        }
203

204
        /// @brief Destroys the existing Node value. This process is recursive if the specified node type is for
205
        /// containers.
206
        /// @param[in] type A Node type to determine the value to be destroyed.
16,917✔
207
        void destroy(detail::node_attr_t value_type_bit) {
16,917✔
208
            switch (value_type_bit) {
1,851✔
209
            case detail::node_attr_bits::seq_bit:
1,851✔
210
                p_seq->clear();
1,851✔
211
                detail::destroy_object<sequence_type>(p_seq);
1,851✔
212
                p_seq = nullptr;
1,851✔
213
                break;
922✔
214
            case detail::node_attr_bits::map_bit:
922✔
215
                p_map->clear();
922✔
216
                detail::destroy_object<mapping_type>(p_map);
922✔
217
                p_map = nullptr;
922✔
218
                break;
3,147✔
219
            case detail::node_attr_bits::string_bit:
3,147✔
220
                detail::destroy_object<string_type>(p_str);
3,147✔
221
                p_str = nullptr;
3,147✔
222
                break;
10,997✔
223
            default:
10,997✔
224
                break;
225
            }
16,917✔
226
        }
227

228
        /// A pointer to the value of sequence type.
229
        sequence_type* p_seq;
230
        /// A pointer to the value of mapping type. This pointer is also used when node type is null.
231
        mapping_type* p_map {nullptr};
232
        /// A value of boolean type.
233
        boolean_type boolean;
234
        /// A value of integer type.
235
        integer_type integer;
236
        /// A value of float number type.
237
        float_number_type float_val;
238
        /// A pointer to the value of string type.
239
        string_type* p_str;
240
    };
241

242
public:
243
    /// @brief Constructs a new basic_node object of null type.
244
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/
2,615✔
245
    basic_node() = default;
246

247
    /// @brief Constructs a new basic_node object with a specified type.
248
    /// @param[in] type A YAML node type.
249
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/
250
    FK_YAML_DEPRECATED("Since 0.3.12; Use explicit basic_node(const node_type)")
7✔
251
    explicit basic_node(const node_t type)
7✔
252
        : basic_node(detail::convert_to_node_type(type)) {
7✔
253
    }
254

30✔
255
    explicit basic_node(const node_type type)
30✔
256
        : m_attrs(detail::node_attr_bits::from_node_type(type)),
30✔
257
          m_value(m_attrs & detail::node_attr_mask::value) {
30✔
258
    }
259

260
    /// @brief Copy constructor of the basic_node class.
261
    /// @param[in] rhs A basic_node object to be copied with.
262
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/
3,573✔
263
    basic_node(const basic_node& rhs)
3,573✔
264
        : m_attrs(rhs.m_attrs),
3,573✔
265
          mp_meta(rhs.mp_meta),
3,573✔
266
          m_prop(rhs.m_prop) {
3,573✔
267
        if FK_YAML_LIKELY (!has_anchor_name()) {
3,346✔
268
            switch (m_attrs & detail::node_attr_mask::value) {
592✔
269
            case detail::node_attr_bits::seq_bit:
592✔
270
                m_value.p_seq = detail::create_object<sequence_type>(*(rhs.m_value.p_seq));
592✔
271
                break;
246✔
272
            case detail::node_attr_bits::map_bit:
246✔
273
                m_value.p_map = detail::create_object<mapping_type>(*(rhs.m_value.p_map));
246✔
274
                break;
435✔
275
            case detail::node_attr_bits::null_bit:
435✔
276
                m_value.p_map = nullptr;
435✔
277
                break;
564✔
278
            case detail::node_attr_bits::bool_bit:
564✔
279
                m_value.boolean = rhs.m_value.boolean;
564✔
280
                break;
518✔
281
            case detail::node_attr_bits::int_bit:
518✔
282
                m_value.integer = rhs.m_value.integer;
518✔
283
                break;
229✔
284
            case detail::node_attr_bits::float_bit:
229✔
285
                m_value.float_val = rhs.m_value.float_val;
229✔
286
                break;
762✔
287
            case detail::node_attr_bits::string_bit:
762✔
288
                m_value.p_str = detail::create_object<string_type>(*(rhs.m_value.p_str));
762✔
289
                break;
290
            default:                   // LCOV_EXCL_LINE
291
                detail::unreachable(); // LCOV_EXCL_LINE
292
            }
293
        }
3,573✔
294
    }
295

296
    /// @brief Move constructor of the basic_node class.
297
    /// @param[in] rhs A basic_node object to be moved from.
298
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/
9,086✔
299
    basic_node(basic_node&& rhs) noexcept
9,086✔
300
        : m_attrs(rhs.m_attrs),
9,086✔
301
          mp_meta(std::move(rhs.mp_meta)),
9,086✔
302
          m_prop(std::move(rhs.m_prop)) {
9,086✔
303
        if FK_YAML_LIKELY (!has_anchor_name()) {
9,044✔
304
            switch (m_attrs & detail::node_attr_mask::value) {
1,268✔
305
            case detail::node_attr_bits::seq_bit:
1,268✔
306
                FK_YAML_ASSERT(rhs.m_value.p_seq != nullptr);
1,268✔
307
                m_value.p_seq = rhs.m_value.p_seq;
1,268✔
308
                rhs.m_value.p_seq = nullptr;
1,268✔
309
                break;
858✔
310
            case detail::node_attr_bits::map_bit:
858✔
311
                FK_YAML_ASSERT(rhs.m_value.p_map != nullptr);
858✔
312
                m_value.p_map = rhs.m_value.p_map;
858✔
313
                rhs.m_value.p_map = nullptr;
858✔
314
                break;
1,029✔
315
            case detail::node_attr_bits::null_bit:
1,029✔
316
                FK_YAML_ASSERT(rhs.m_value.p_map == nullptr);
1,029✔
317
                m_value.p_map = rhs.m_value.p_map;
1,029✔
318
                break;
1,494✔
319
            case detail::node_attr_bits::bool_bit:
1,494✔
320
                m_value.boolean = rhs.m_value.boolean;
1,494✔
321
                rhs.m_value.boolean = static_cast<boolean_type>(false);
1,494✔
322
                break;
1,388✔
323
            case detail::node_attr_bits::int_bit:
1,388✔
324
                m_value.integer = rhs.m_value.integer;
1,388✔
325
                rhs.m_value.integer = static_cast<integer_type>(0);
1,388✔
326
                break;
419✔
327
            case detail::node_attr_bits::float_bit:
419✔
328
                m_value.float_val = rhs.m_value.float_val;
419✔
329
                rhs.m_value.float_val = static_cast<float_number_type>(0.0);
419✔
330
                break;
2,588✔
331
            case detail::node_attr_bits::string_bit:
2,588✔
332
                FK_YAML_ASSERT(rhs.m_value.p_str != nullptr);
2,588✔
333
                m_value.p_str = rhs.m_value.p_str;
2,588✔
334
                rhs.m_value.p_str = nullptr;
2,588✔
335
                break;
336
            default:                   // LCOV_EXCL_LINE
337
                detail::unreachable(); // LCOV_EXCL_LINE
338
            }
339
        }
340

9,086✔
341
        rhs.m_attrs = detail::node_attr_bits::default_bits;
9,086✔
342
        rhs.m_value.p_map = nullptr;
9,086✔
343
    }
344

345
    /// @brief Construct a new basic_node object from a value of compatible types.
346
    /// @tparam CompatibleType Type of native data which is compatible with node values.
347
    /// @tparam U Type of compatible native data without cv-qualifiers and reference.
348
    /// @param[in] val The value of a compatible type.
349
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/
350
    template <
351
        typename CompatibleType, typename U = detail::remove_cvref_t<CompatibleType>,
352
        detail::enable_if_t<
353
            detail::conjunction<
354
                detail::negation<detail::is_basic_node<U>>,
355
                detail::disjunction<detail::is_node_compatible_type<basic_node, U>>>::value,
356
            int> = 0>
6,122✔
357
    basic_node(CompatibleType&& val) noexcept(
6,122✔
358
        noexcept(ConverterType<U, void>::to_node(std::declval<basic_node&>(), std::declval<CompatibleType>()))) {
6,122✔
359
        ConverterType<U, void>::to_node(*this, std::forward<CompatibleType>(val));
6,122✔
360
    }
361

362
    /// @brief Construct a new basic node object with a node_ref_storage object.
363
    /// @tparam NodeRefStorageType Type of basic_node with reference.
364
    /// @param[in] node_ref_storage A node_ref_storage template class object.
365
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/
366
    template <
367
        typename NodeRefStorageType,
368
        detail::enable_if_t<detail::is_node_ref_storage<NodeRefStorageType>::value, int> = 0>
369
    basic_node(const NodeRefStorageType& node_ref_storage) noexcept
370
        : basic_node(node_ref_storage.release()) {
371
    }
372

373
    /// @brief Construct a new basic node object with std::initializer_list.
374
    /// @param[in] init A initializer list of basic_node objects.
375
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/
1,204✔
376
    basic_node(initializer_list_t init) {
377
        if (init.size() == 1 && init.begin()->has_node_ref()) {
1,204✔
378
            const auto& node_ref = *init.begin();
379
            bool is_bare_empty_collection =
1,389✔
380
                !node_ref->is_scalar() && node_ref->empty() && !node_ref->is_anchor() && !node_ref->has_tag_name();
381
            if (is_bare_empty_collection) {
382
                basic_node(node_ref.release()).swap(*this);
1,204✔
383
                return;
216✔
384
            }
216✔
385
        }
386

216✔
387
        bool is_mapping =
611✔
388
            std::all_of(init.begin(), init.end(), [](const detail::node_ref_storage<basic_node>& node_ref) {
395✔
389
                // Do not use is_sequence_impl() since node_ref may be an anchor or alias.
395✔
390
                return node_ref->is_sequence() && node_ref->size() == 2;
395✔
391
            });
392

393
        if (is_mapping) {
394
            m_attrs = detail::node_attr_bits::map_bit;
988✔
395
            m_value.p_map = detail::create_object<mapping_type>();
988✔
396

397
            auto& map = *m_value.p_map;
988✔
398
            for (auto& elem_ref : init) {
988✔
399
                auto elem = elem_ref.release();
3,072✔
400
                auto& seq = *elem.m_value.p_seq;
2,084✔
401
                map.emplace(std::move(seq[0]), std::move(seq[1]));
402
            }
403
        }
1,204✔
404
        else {
405
            m_attrs = detail::node_attr_bits::seq_bit;
406
            m_value.p_seq = detail::create_object<sequence_type>();
407

22,629✔
408
            auto& seq = *m_value.p_seq;
409
            seq.reserve(std::distance(init.begin(), init.end()));
22,629✔
410
            for (auto& elem_ref : init) {
496✔
411
                seq.emplace_back(std::move(elem_ref.release()));
261✔
412
            }
261✔
413
        }
261✔
414
    } // LCOV_EXCL_LINE
261✔
415

261✔
416
    /// @brief Destroy the basic_node object and its value storage.
417
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/destructor/
418
    ~basic_node() noexcept // NOLINT(bugprone-exception-escape)
22,133✔
419
    {
10,518✔
420
        if (m_attrs & detail::node_attr_mask::anchoring) {
421
            if (m_attrs & detail::node_attr_bits::anchor_bit) {
422
                auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;
22,629✔
423
                std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));
22,629✔
424
                itr->second.m_value.destroy(itr->second.m_attrs & detail::node_attr_mask::value);
22,629✔
425
                itr->second.m_attrs = detail::node_attr_bits::default_bits;
426
                itr->second.mp_meta.reset();
427
            }
428
        }
429
        else if ((m_attrs & detail::node_attr_bits::null_bit) == 0) {
430
            m_value.destroy(m_attrs & detail::node_attr_mask::value);
431
        }
432

433
        m_attrs = detail::node_attr_bits::default_bits;
62✔
434
        mp_meta.reset();
63✔
435
    }
436

437
public:
438
    /// @brief Deserialize the first YAML document in the input into a basic_node object.
439
    /// @tparam InputType Type of a compatible input.
440
    /// @param[in] input An input source in the YAML format.
441
    /// @return The resulting basic_node object deserialized from the input source.
442
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/deserialize/
443
    template <typename InputType>
444
    static basic_node deserialize(InputType&& input) {
445
        return deserializer_type().deserialize(detail::input_adapter(std::forward<InputType>(input)));
446
    }
447

16✔
448
    /// @brief Deserialize the first YAML document in the input ranged by the iterators into a basic_node object.
32✔
449
    /// @note
32✔
450
    /// Iterators must satisfy the LegacyInputIterator requirements.
451
    /// See https://en.cppreference.com/w/cpp/named_req/InputIterator.
452
    /// @tparam ItrType Type of a compatible iterator
453
    /// @param[in] begin An iterator to the first element of an input sequence.
454
    /// @param[in] end An iterator to the past-the-last element of an input sequence.
455
    /// @return The resulting basic_node object deserialized from the pair of iterators.
456
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/deserialize/
457
    template <typename ItrType>
458
    static basic_node deserialize(ItrType begin, ItrType end) {
5✔
459
        return deserializer_type().deserialize(
5✔
460
            detail::input_adapter(std::forward<ItrType>(begin), std::forward<ItrType>(end)));
461
    }
462

463
    /// @brief Deserialize all YAML documents in the input into basic_node objects.
464
    /// @tparam InputType Type of a compatible input.
465
    /// @param[in] input An input source in the YAML format.
466
    /// @return The resulting basic_node objects deserialized from the input.
467
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/deserialize_docs/
468
    template <typename InputType>
469
    static std::vector<basic_node> deserialize_docs(InputType&& input) {
4✔
470
        return deserializer_type().deserialize_docs(detail::input_adapter(std::forward<InputType>(input)));
8✔
471
    }
8✔
472

473
    /// @brief Deserialize all YAML documents in the input ranged by the iterators into basic_node objects.
474
    /// @tparam ItrType Type of a compatible iterator.
475
    /// @param[in] begin An iterator to the first element of an input sequence.
476
    /// @param[in] end An iterator to the past-the-last element of an input sequence.
477
    /// @return The resulting basic_node objects deserialized from the pair of iterators.
478
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/deserialize_docs/
30✔
479
    template <typename ItrType>
60✔
480
    static std::vector<basic_node> deserialize_docs(ItrType&& begin, ItrType&& end) {
481
        return deserializer_type().deserialize_docs(
482
            detail::input_adapter(std::forward<ItrType>(begin), std::forward<ItrType>(end)));
483
    }
484

485
    /// @brief Serialize a basic_node object into a string.
486
    /// @param[in] node A basic_node object to be serialized.
1✔
487
    /// @return The resulting string object from the serialization of the given node.
2✔
488
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/serialize/
489
    static std::string serialize(const basic_node& node) {
490
        return serializer_type().serialize(node);
491
    }
492

493
    /// @brief Serialize basic_node objects into a string.
110✔
494
    /// @param docs basic_node objects to be serialized.
110✔
495
    /// @return The resulting string object from the serialization of the given nodes.
110✔
496
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/serialize_docs/
110✔
497
    static std::string serialize_docs(const std::vector<basic_node>& docs) {
110✔
498
        return serializer_type().serialize_docs(docs);
499
    }
500

501
    /// @brief A factory method for sequence basic_node objects without sequence_type objects.
502
    /// @return A YAML sequence node.
503
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/sequence/
504
    static basic_node sequence() {
1✔
505
        basic_node node;
1✔
506
        node.m_attrs = detail::node_attr_bits::seq_bit;
1✔
507
        node.m_value.p_seq = detail::create_object<sequence_type>();
1✔
508
        return node;
1✔
509
    } // LCOV_EXCL_LINE
510

511
    /// @brief A factory method for sequence basic_node objects with lvalue sequence_type objects.
512
    /// @param[in] seq A lvalue sequence node value.
513
    /// @return A YAML sequence node.
514
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/sequence/
515
    static basic_node sequence(const sequence_type& seq) {
87✔
516
        basic_node node;
87✔
517
        node.m_attrs = detail::node_attr_bits::seq_bit;
87✔
518
        node.m_value.p_seq = detail::create_object<sequence_type>(seq);
87✔
519
        return node;
87✔
520
    } // LCOV_EXCL_LINE
521

522
    /// @brief A factory method for sequence basic_node objects with rvalue sequence_type objects.
523
    /// @param[in] seq A rvalue sequence node value.
524
    /// @return A YAML sequence node.
525
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/sequence/
408✔
526
    static basic_node sequence(sequence_type&& seq) {
408✔
527
        basic_node node;
408✔
528
        node.m_attrs = detail::node_attr_bits::seq_bit;
408✔
529
        node.m_value.p_seq = detail::create_object<sequence_type>(std::move(seq));
408✔
530
        return node;
531
    } // LCOV_EXCL_LINE
532

533
    /// @brief A factory method for mapping basic_node objects without mapping_type objects.
534
    /// @return A YAML mapping node.
535
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/mapping/
536
    static basic_node mapping() {
17✔
537
        basic_node node;
17✔
538
        node.m_attrs = detail::node_attr_bits::map_bit;
17✔
539
        node.m_value.p_map = detail::create_object<mapping_type>();
17✔
540
        return node;
17✔
541
    } // LCOV_EXCL_LINE
542

543
    /// @brief A factory method for mapping basic_node objects with lvalue mapping_type objects.
544
    /// @param[in] map A lvalue mapping node value.
545
    /// @return A YAML mapping node.
546
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/mapping/
547
    static basic_node mapping(const mapping_type& map) {
13✔
548
        basic_node node;
13✔
549
        node.m_attrs = detail::node_attr_bits::map_bit;
13✔
550
        node.m_value.p_map = detail::create_object<mapping_type>(map);
13✔
551
        return node;
13✔
552
    } // LCOV_EXCL_LINE
553

554
    /// @brief A factory method for mapping basic_node objects with rvalue mapping_type objects.
555
    /// @param[in] map A rvalue mapping node value.
556
    /// @return A YAML mapping node.
557
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/mapping/
558
    static basic_node mapping(mapping_type&& map) {
559
        basic_node node;
228✔
560
        node.m_attrs = detail::node_attr_bits::map_bit;
228✔
561
        node.m_value.p_map = detail::create_object<mapping_type>(std::move(map));
562
        return node;
228✔
563
    } // LCOV_EXCL_LINE
3✔
564

565
    /// @brief A factory method for alias basic_node objects referencing the given anchor basic_node object.
566
    /// @note The given anchor basic_node must have a non-empty anchor name.
225✔
567
    /// @param[in] anchor_node A basic_node object with an anchor name.
225✔
568
    /// @return An alias YAML node created from the given anchor node.
225✔
569
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/alias_of/
225✔
570
    static basic_node alias_of(const basic_node& anchor_node) {
571
        constexpr detail::node_attr_t anchor_bit = detail::node_attr_bits::anchor_bit;
572

573
        if FK_YAML_UNLIKELY (!anchor_node.has_anchor_name() || !(anchor_node.m_attrs & anchor_bit)) {
574
            throw fkyaml::exception("Cannot create an alias without anchor name.");
575
        }
576

577
        basic_node node = anchor_node;
126✔
578
        node.m_attrs &= ~detail::node_attr_mask::anchoring;
126✔
579
        node.m_attrs |= detail::node_attr_bits::alias_bit;
126✔
580
        return node;
581
    } // LCOV_EXCL_LINE
582

583
public:
584
    /// @brief A copy assignment operator of the basic_node class.
585
    /// @param[in] rhs A lvalue basic_node object to be copied with.
586
    /// @return Reference to this basic_node object.
1,295✔
587
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator=/
1,295✔
588
    basic_node& operator=(const basic_node& rhs) noexcept {
1,295✔
589
        basic_node(rhs).swap(*this);
590
        return *this;
591
    }
592

593
    /// @brief A move assignment operator of the basic_node class.
594
    /// @param[in] rhs A rvalue basic_node object to be moved from.
595
    /// @return Reference to this basic_node object.
596
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator=/
597
    basic_node& operator=(basic_node&& rhs) noexcept {
598
        basic_node(std::move(rhs)).swap(*this);
599
        return *this;
600
    }
601

602
    /// @brief A subscript operator of the basic_node class with a key of a compatible type with basic_node.
1,323✔
603
    /// @tparam KeyType A key type compatible with basic_node
1,323✔
604
    /// @param key A key to the target value in a sequence/mapping node.
605
    /// @return The value associated with the given key, or a default basic_node object associated with the given key.
1,323✔
606
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator[]/
5✔
607
    template <
608
        typename KeyType, detail::enable_if_t<
609
                              detail::conjunction<
1,318✔
610
                                  detail::negation<detail::is_basic_node<KeyType>>,
611
                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,
1,318✔
612
                              int> = 0>
613
    basic_node& operator[](KeyType&& key) {
913✔
614
        basic_node& act_node = resolve_reference();
6✔
615

616
        if FK_YAML_UNLIKELY (act_node.is_scalar_impl()) {
617
            throw fkyaml::type_error("operator[] is unavailable for a scalar node.", get_type());
907✔
618
        }
907✔
619

620
        basic_node key_node = std::forward<KeyType>(key);
621

405✔
622
        if (act_node.is_sequence_impl()) {
405✔
623
            // Do not use is_integer_impl() since n may be an anchor or alias.
1,318✔
624
            if FK_YAML_UNLIKELY (!key_node.is_integer()) {
625
                throw fkyaml::type_error(
626
                    "An argument of operator[] for sequence nodes must be an integer.", get_type());
627
            }
628
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
629
            return act_node.m_value.p_seq->operator[](key_node.get_value<int>());
630
        }
631

632
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
633
        return act_node.m_value.p_map->operator[](std::move(key_node));
634
    }
635

636
    /// @brief A subscript operator of the basic_node class with a key of a compatible type with basic_node.
165✔
637
    /// @tparam KeyType A key type compatible with basic_node
165✔
638
    /// @param key A key to the target value in a sequence/mapping node.
639
    /// @return The value associated with the given key, or a default basic_node object associated with the given key.
165✔
640
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator[]/
6✔
641
    template <
642
        typename KeyType, detail::enable_if_t<
643
                              detail::conjunction<
159✔
644
                                  detail::negation<detail::is_basic_node<KeyType>>,
645
                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,
159✔
646
                              int> = 0>
115✔
647
    const basic_node& operator[](KeyType&& key) const {
6✔
648
        const basic_node& act_node = resolve_reference();
649

650
        if FK_YAML_UNLIKELY (act_node.is_scalar_impl()) {
109✔
651
            throw fkyaml::type_error("operator[] is unavailable for a scalar node.", get_type());
109✔
652
        }
653

654
        basic_node key_node = std::forward<KeyType>(key);
44✔
655

44✔
656
        if (act_node.is_sequence_impl()) {
159✔
657
            if FK_YAML_UNLIKELY (!key_node.is_integer_impl()) {
658
                throw fkyaml::type_error(
659
                    "An argument of operator[] for sequence nodes must be an integer.", get_type());
660
            }
661
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
662
            return act_node.m_value.p_seq->operator[](key_node.get_value<int>());
663
        }
664

65✔
665
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
65✔
666
        return act_node.m_value.p_map->operator[](std::move(key_node));
5✔
667
    }
668

669
    /// @brief A subscript operator of the basic_node class with a basic_node key object.
60✔
670
    /// @tparam KeyType A key type which is a kind of the basic_node template class.
671
    /// @param key A key to the target value in a sequence/mapping node.
60✔
672
    /// @return The value associated with the given key, or a default basic_node object associated with the given key.
7✔
673
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator[]/
6✔
674
    template <typename KeyType, detail::enable_if_t<detail::is_basic_node<KeyType>::value, int> = 0>
675
    basic_node& operator[](KeyType&& key) {
676
        if FK_YAML_UNLIKELY (is_scalar()) {
1✔
677
            throw fkyaml::type_error("operator[] is unavailable for a scalar node.", get_type());
1✔
678
        }
679

680
        const node_value& node_value = resolve_reference().m_value;
53✔
681

53✔
682
        if (is_sequence()) {
683
            if FK_YAML_UNLIKELY (!key.is_integer()) {
684
                throw fkyaml::type_error(
685
                    "An argument of operator[] for sequence nodes must be an integer.", get_type());
686
            }
687
            FK_YAML_ASSERT(node_value.p_seq != nullptr);
688
            return node_value.p_seq->operator[](std::forward<KeyType>(key).template get_value<int>());
689
        }
690

14✔
691
        FK_YAML_ASSERT(node_value.p_map != nullptr);
14✔
692
        return node_value.p_map->operator[](std::forward<KeyType>(key));
5✔
693
    }
694

695
    /// @brief A subscript operator of the basic_node class with a basic_node key object.
9✔
696
    /// @tparam KeyType A key type which is a kind of the basic_node template class.
697
    /// @param key A key to the target value in a sequence/mapping node.
9✔
698
    /// @return The value associated with the given key, or a default basic_node object associated with the given key.
7✔
699
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator[]/
6✔
700
    template <typename KeyType, detail::enable_if_t<detail::is_basic_node<KeyType>::value, int> = 0>
701
    const basic_node& operator[](KeyType&& key) const {
702
        if FK_YAML_UNLIKELY (is_scalar()) {
1✔
703
            throw fkyaml::type_error("operator[] is unavailable for a scalar node.", get_type());
1✔
704
        }
705

706
        const node_value& node_value = resolve_reference().m_value;
2✔
707

2✔
708
        if (is_sequence()) {
709
            if FK_YAML_UNLIKELY (!key.is_integer()) {
710
                throw fkyaml::type_error(
711
                    "An argument of operator[] for sequence nodes must be an integer.", get_type());
712
            }
713
            FK_YAML_ASSERT(node_value.p_seq != nullptr);
714
            return node_value.p_seq->operator[](key.template get_value<int>());
4,251✔
715
        }
4,251✔
716

4,251✔
717
        FK_YAML_ASSERT(node_value.p_map != nullptr);
718
        return node_value.p_map->operator[](std::forward<KeyType>(key));
4,251✔
719
    }
4,251✔
720

565✔
721
    /// @brief An equal-to operator of the basic_node class.
722
    /// @param rhs A basic_node object to be compared with this basic_node object.
723
    /// @return true if both types and values are equal, false otherwise.
3,686✔
724
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_eq/
3,686✔
725
    bool operator==(const basic_node& rhs) const noexcept {
80✔
726
        const basic_node& lhs = resolve_reference();
80✔
727
        const basic_node& act_rhs = rhs.resolve_reference();
80✔
728

146✔
729
        const detail::node_attr_t lhs_val_bit = lhs.m_attrs & detail::node_attr_mask::value;
146✔
730
        if (lhs_val_bit != (act_rhs.m_attrs & detail::node_attr_mask::value)) {
146✔
731
            return false;
57✔
732
        }
733

57✔
734
        bool ret = false;
57✔
735
        switch (lhs_val_bit) {
223✔
736
        case detail::node_attr_bits::seq_bit:
223✔
737
            ret = (*(lhs.m_value.p_seq) == *(act_rhs.m_value.p_seq));
223✔
738
            break;
174✔
739
        case detail::node_attr_bits::map_bit:
174✔
740
            ret = (*(lhs.m_value.p_map) == *(act_rhs.m_value.p_map));
174✔
741
            break;
27✔
742
        case detail::node_attr_bits::null_bit:
27✔
743
            // Always true for comparisons between null nodes.
27✔
744
            ret = true;
27✔
745
            break;
27✔
746
        case detail::node_attr_bits::bool_bit:
2,979✔
747
            ret = (lhs.m_value.boolean == act_rhs.m_value.boolean);
2,979✔
748
            break;
2,979✔
749
        case detail::node_attr_bits::int_bit:
750
            ret = (lhs.m_value.integer == act_rhs.m_value.integer);
751
            break;
752
        case detail::node_attr_bits::float_bit:
753
            ret =
3,686✔
754
                (std::abs(lhs.m_value.float_val - act_rhs.m_value.float_val) <
755
                 std::numeric_limits<float_number_type>::epsilon());
756
            break;
757
        case detail::node_attr_bits::string_bit:
758
            ret = (*(lhs.m_value.p_str) == *(act_rhs.m_value.p_str));
759
            break;
760
        default:                   // LCOV_EXCL_LINE
55✔
761
            detail::unreachable(); // LCOV_EXCL_LINE
55✔
762
        }
763

764
        return ret;
765
    }
766

767
    /// @brief A not-equal-to operator of the basic_node class.
768
    /// @param rhs A basic_node object to be compared with this basic_node object.
3,705✔
769
    /// @return true if either types or values are different, false otherwise.
3,705✔
770
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_ne/
1,958✔
771
    bool operator!=(const basic_node& rhs) const noexcept {
772
        return !operator==(rhs);
773
    }
1,747✔
774

1,747✔
775
    /// @brief A less-than operator of the basic_node class.
776
    /// @param rhs A basic_node object to be compared with this basic_node object.
1,747✔
777
    /// @return true this basic_node object is less than `rhs`.
1,747✔
778
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_lt/
779
    bool operator<(const basic_node& rhs) const noexcept {
1,747✔
780
        if (operator==(rhs)) {
268✔
781
            return false;
782
        }
783

1,479✔
784
        const basic_node& lhs = resolve_reference();
194✔
785
        const basic_node& act_rhs = rhs.resolve_reference();
786

787
        const detail::node_attr_t lhs_val_bit = lhs.m_attrs & detail::node_attr_mask::value;
1,285✔
788
        const detail::node_attr_t rhs_val_bit = act_rhs.m_attrs & detail::node_attr_mask::value;
1,285✔
789

21✔
790
        if (lhs_val_bit < rhs_val_bit) {
21✔
791
            return true;
21✔
792
        }
35✔
793

35✔
794
        if (lhs_val_bit != rhs_val_bit) {
35✔
795
            return false;
796
        }
797

798
        bool ret = false;
46✔
799
        switch (lhs_val_bit) {
800
        case detail::node_attr_bits::seq_bit:
46✔
801
            ret = (*(lhs.m_value.p_seq) < *(act_rhs.m_value.p_seq));
46✔
802
            break;
26✔
803
        case detail::node_attr_bits::map_bit:
26✔
804
            ret = (*(lhs.m_value.p_map) < *(act_rhs.m_value.p_map));
26✔
805
            break;
12✔
806
        case detail::node_attr_bits::null_bit: // LCOV_EXCL_LINE
12✔
807
            // Will not come here since null nodes are always the same.
12✔
808
            detail::unreachable(); // LCOV_EXCL_LINE
1,145✔
809
        case detail::node_attr_bits::bool_bit:
1,145✔
810
            // false < true
1,145✔
811
            ret = (!lhs.m_value.boolean && act_rhs.m_value.boolean);
812
            break;
813
        case detail::node_attr_bits::int_bit:
814
            ret = (lhs.m_value.integer < act_rhs.m_value.integer);
815
            break;
1,285✔
816
        case detail::node_attr_bits::float_bit:
817
            ret = (lhs.m_value.float_val < act_rhs.m_value.float_val);
818
            break;
819
        case detail::node_attr_bits::string_bit:
820
            ret = (*(lhs.m_value.p_str) < *(act_rhs.m_value.p_str));
821
            break;
822
        default:                   // LCOV_EXCL_LINE
122✔
823
            detail::unreachable(); // LCOV_EXCL_LINE
122✔
824
        }
825

826
        return ret;
827
    }
828

829
    /// @brief A less-than-or-equal-to operator of the basic_node class.
830
    /// @param rhs A basic_node object to be compared with this basic_node object.
61✔
831
    /// @return true this basic_node object is less than or equal to `rhs`.
61✔
832
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_le/
833
    bool operator<=(const basic_node& rhs) const noexcept {
834
        return !rhs.operator<(*this);
835
    }
836

837
    /// @brief A greater-than operator of the basic_node class.
838
    /// @param rhs A basic_node object to be compared with this basic_node object.
61✔
839
    /// @return true this basic_node object is greater than `rhs`.
61✔
840
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_gt/
841
    bool operator>(const basic_node& rhs) const noexcept {
842
        return !operator<=(rhs);
843
    }
844

845
    /// @brief A greater-than-or-equal-to operator of the basic_node class.
846
    /// @param rhs A basic_node object to be compared with this basic_node object.
3,187✔
847
    /// @return true this basic_node object is greater than or equal to `rhs`.
3,187✔
848
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_ge/
849
    bool operator>=(const basic_node& rhs) const noexcept {
850
        return !operator<(rhs);
851
    }
852

853
public:
854
    /// @brief Returns the type of the current basic_node value.
855
    /// @return The type of the YAML node value.
14✔
856
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_type/
14✔
857
    node_type get_type() const noexcept {
14✔
858
        return detail::node_attr_bits::to_node_type(resolve_reference().m_attrs);
859
    }
860

861
    /// @brief Returns the type of the current basic_node value.
862
    /// @deprecated Use get_type() function. (since 0.3.12)
863
    /// @return The type of the YAML node value.
2,259✔
864
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/type/
2,259✔
865
    FK_YAML_DEPRECATED("Since 0.3.12; Use get_type()")
866
    node_t type() const noexcept {
867
        node_type tmp_type = get_type();
868
        return detail::convert_from_node_type(tmp_type);
869
    }
870

1,274✔
871
    /// @brief Tests whether the current basic_node value is of sequence type.
1,274✔
872
    /// @return true if the type is sequence, false otherwise.
873
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_sequence/
874
    bool is_sequence() const noexcept {
875
        return resolve_reference().is_sequence_impl();
876
    }
877

120✔
878
    /// @brief Tests whether the current basic_node value is of mapping type.
120✔
879
    /// @return true if the type is mapping, false otherwise.
880
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_mapping/
881
    bool is_mapping() const noexcept {
882
        return resolve_reference().is_mapping_impl();
883
    }
884

197✔
885
    /// @brief Tests whether the current basic_node value is of null type.
197✔
886
    /// @return true if the type is null, false otherwise.
887
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_null/
888
    bool is_null() const noexcept {
889
        return resolve_reference().is_null_impl();
890
    }
891

1,691✔
892
    /// @brief Tests whether the current basic_node value is of boolean type.
1,691✔
893
    /// @return true if the type is boolean, false otherwise
894
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_boolean/
895
    bool is_boolean() const noexcept {
896
        return resolve_reference().is_boolean_impl();
897
    }
898

110✔
899
    /// @brief Tests whether the current basic_node value is of integer type.
110✔
900
    /// @return true if the type is integer, false otherwise.
901
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_integer/
902
    bool is_integer() const noexcept {
903
        return resolve_reference().is_integer_impl();
904
    }
905

520✔
906
    /// @brief Tests whether the current basic_node value is of float number type.
520✔
907
    /// @return true if the type is floating point number, false otherwise.
908
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_float_number/
909
    bool is_float_number() const noexcept {
910
        return resolve_reference().is_float_number_impl();
911
    }
912

480✔
913
    /// @brief Tests whether the current basic_node value is of string type.
480✔
914
    /// @return true if the type is string, false otherwise.
915
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_string/
916
    bool is_string() const noexcept {
917
        return resolve_reference().is_string_impl();
918
    }
919

519✔
920
    /// @brief Tests whether the current basic_node value is of scalar types.
519✔
921
    /// @return true if the type is scalar, false otherwise.
922
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_scalar/
923
    bool is_scalar() const noexcept {
924
        return resolve_reference().is_scalar_impl();
925
    }
926

111✔
927
    /// @brief Tests whether the current basic_node is an anchor node.
111✔
928
    /// @return true if the current basic_node is an anchor node, false otherwise.
929
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_anchor/
930
    bool is_anchor() const noexcept {
931
        return m_attrs & detail::node_attr_bits::anchor_bit;
932
    }
933

53✔
934
    /// @brief Tests whether the current basic_node is an alias node.
53✔
935
    /// @return true if the current basic_node is an alias node, false otherwise.
53✔
936
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_alias/
16✔
937
    bool is_alias() const noexcept {
16✔
938
        return m_attrs & detail::node_attr_bits::alias_bit;
16✔
939
    }
940

13✔
941
    /// @brief Tests whether the current basic_node value (sequence, mapping, string) is empty.
13✔
942
    /// @return true if the node value is empty, false otherwise.
13✔
943
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/empty/
944
    bool empty() const {
8✔
945
        const basic_node& act_node = resolve_reference();
8✔
946
        switch (act_node.m_attrs & detail::node_attr_mask::value) {
8✔
947
        case detail::node_attr_bits::seq_bit: {
948
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
16✔
949
            return act_node.m_value.p_seq->empty();
16✔
950
        }
951
        case detail::node_attr_bits::map_bit: {
952
            FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
953
            return act_node.m_value.p_map->empty();
954
        }
955
        case detail::node_attr_bits::string_bit: {
956
            FK_YAML_ASSERT(act_node.m_value.p_str != nullptr);
957✔
957
            return act_node.m_value.p_str->empty();
957✔
958
        }
957✔
959
        default:
639✔
960
            throw fkyaml::type_error("The target node is not of a container type.", get_type());
639✔
961
        }
639✔
962
    }
281✔
963

281✔
964
    /// @brief Returns the size of the current basic_node value (sequence, mapping, string).
281✔
965
    /// @return The size of a node value.
21✔
966
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/size/
21✔
967
    std::size_t size() const {
21✔
968
        const basic_node& act_node = resolve_reference();
16✔
969
        switch (act_node.m_attrs & detail::node_attr_mask::value) {
16✔
970
        case detail::node_attr_bits::seq_bit:
971
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
972
            return act_node.m_value.p_seq->size();
973
        case detail::node_attr_bits::map_bit:
974
            FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
975
            return act_node.m_value.p_map->size();
976
        case detail::node_attr_bits::string_bit:
977
            FK_YAML_ASSERT(act_node.m_value.p_str != nullptr);
978
            return act_node.m_value.p_str->size();
979
        default:
980
            throw fkyaml::type_error("The target node is not of a container type.", get_type());
981
        }
982
    }
983

984
    /// @brief Check whether this basic_node object has a given key in its inner mapping node value.
288✔
985
    /// @tparam KeyType A key type compatible with basic_node.
288✔
986
    /// @param key A key to the target value in the mapping node value.
288✔
987
    /// @return true if the target node is a mapping and has the given key, false otherwise.
276✔
988
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/contains/
276✔
989
    template <
276✔
990
        typename KeyType, detail::enable_if_t<
991
                              detail::disjunction<
992
                                  detail::is_basic_node<KeyType>,
12✔
993
                                  detail::is_node_compatible_type<basic_node, detail::remove_cvref_t<KeyType>>>::value,
994
                              int> = 0>
995
    bool contains(KeyType&& key) const {
996
        const basic_node& act_node = resolve_reference();
997
        if FK_YAML_LIKELY (act_node.m_attrs & detail::node_attr_bits::map_bit) {
998
            FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
999
            const auto& map = *act_node.m_value.p_map;
1000
            return map.find(std::forward<KeyType>(key)) != map.end();
1001
        }
1002

1003
        return false;
1004
    }
1005

1006
    /// @brief Get a basic_node object with a key of a compatible type.
23✔
1007
    /// @tparam KeyType A key type compatible with basic_node
23✔
1008
    /// @param key A key to the target basic_node object in a sequence/mapping node.
1009
    /// @return Reference to the basic_node object associated with the given key.
23✔
1010
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/at/
5✔
1011
    template <
1012
        typename KeyType, detail::enable_if_t<
1013
                              detail::conjunction<
18✔
1014
                                  detail::negation<detail::is_basic_node<KeyType>>,
1015
                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,
18✔
1016
                              int> = 0>
8✔
1017
    basic_node& at(KeyType&& key) {
6✔
1018
        basic_node& act_node = resolve_reference();
1019

1020
        if FK_YAML_UNLIKELY (act_node.is_scalar_impl()) {
2✔
1021
            throw fkyaml::type_error("at() is unavailable for a scalar node.", get_type());
2✔
1022
        }
2✔
1023

2✔
1024
        basic_node node_key = std::forward<KeyType>(key);
2✔
1025

1✔
1026
        if (act_node.is_sequence_impl()) {
1027
            if FK_YAML_UNLIKELY (!node_key.is_integer_impl()) {
1✔
1028
                throw fkyaml::type_error("An argument of at() for sequence nodes must be an integer.", get_type());
1029
            }
1030

10✔
1031
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
10✔
1032
            sequence_type& seq = *act_node.m_value.p_seq;
10✔
1033
            int index = std::move(node_key).template get_value<int>();
10✔
1034
            int size = static_cast<int>(seq.size());
7✔
1035
            if FK_YAML_UNLIKELY (index >= size) {
1036
                throw fkyaml::out_of_range(index);
3✔
1037
            }
18✔
1038
            return seq[index];
1039
        }
1040

1041
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
1042
        mapping_type& map = *act_node.m_value.p_map;
1043
        const bool is_found = map.find(node_key) != map.end();
1044
        if FK_YAML_UNLIKELY (!is_found) {
1045
            throw fkyaml::out_of_range(serialize(node_key).c_str());
1046
        }
1047
        return map[std::move(node_key)];
1048
    }
1049

1050
    /// @brief Get a basic_node object with a key of a compatible type.
587✔
1051
    /// @tparam KeyType A key type compatible with basic_node
587✔
1052
    /// @param key A key to the target basic_node object in a sequence/mapping node.
1053
    /// @return Constant reference to the basic_node object associated with the given key.
587✔
1054
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/at/
5✔
1055
    template <
1056
        typename KeyType, detail::enable_if_t<
1057
                              detail::conjunction<
582✔
1058
                                  detail::negation<detail::is_basic_node<KeyType>>,
1059
                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,
582✔
1060
                              int> = 0>
541✔
1061
    const basic_node& at(KeyType&& key) const {
6✔
1062
        const basic_node& act_node = resolve_reference();
1063

1064
        if FK_YAML_UNLIKELY (act_node.is_scalar_impl()) {
535✔
1065
            throw fkyaml::type_error("at() is unavailable for a scalar node.", get_type());
535✔
1066
        }
535✔
1067

535✔
1068
        basic_node node_key = std::forward<KeyType>(key);
535✔
1069

1✔
1070
        if (act_node.is_sequence_impl()) {
1071
            if FK_YAML_UNLIKELY (!node_key.is_integer()) {
534✔
1072
                throw fkyaml::type_error("An argument of at() for sequence nodes must be an integer.", get_type());
1073
            }
1074

41✔
1075
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
41✔
1076
            const sequence_type& seq = *act_node.m_value.p_seq;
41✔
1077
            int index = std::move(node_key).template get_value<int>();
41✔
1078
            int size = static_cast<int>(seq.size());
7✔
1079
            if FK_YAML_UNLIKELY (index >= size) {
1080
                throw fkyaml::out_of_range(index);
34✔
1081
            }
582✔
1082
            return seq[index];
1083
        }
1084

1085
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
1086
        const mapping_type& map = *act_node.m_value.p_map;
1087
        const bool is_found = map.find(node_key) != map.end();
1088
        if FK_YAML_UNLIKELY (!is_found) {
1089
            throw fkyaml::out_of_range(serialize(node_key).c_str());
21✔
1090
        }
21✔
1091
        return map.at(std::move(node_key));
21✔
1092
    }
5✔
1093

1094
    /// @brief Get a basic_node object with a basic_node key object.
1095
    /// @tparam KeyType A key type which is a kind of the basic_node template class.
16✔
1096
    /// @param key A key to the target basic_node object in a sequence/mapping node.
7✔
1097
    /// @return Reference to the basic_node object associated with the given key.
5✔
1098
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/at/
1099
    template <typename KeyType, detail::enable_if_t<detail::is_basic_node<KeyType>::value, int> = 0>
1100
    basic_node& at(KeyType&& key) {
2✔
1101
        basic_node& act_node = resolve_reference();
2✔
1102
        if FK_YAML_UNLIKELY (act_node.is_scalar_impl()) {
2✔
1103
            throw fkyaml::type_error("at() is unavailable for a scalar node.", get_type());
2✔
1104
        }
2✔
1105

1✔
1106
        if (act_node.is_sequence_impl()) {
1107
            if FK_YAML_UNLIKELY (!key.is_integer()) {
1✔
1108
                throw fkyaml::type_error("An argument of at() for sequence nodes must be an integer.", get_type());
1109
            }
1110

9✔
1111
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
9✔
1112
            sequence_type& seq = *act_node.m_value.p_seq;
9✔
1113
            int index = std::forward<KeyType>(key).template get_value<int>();
9✔
1114
            int size = static_cast<int>(seq.size());
7✔
1115
            if FK_YAML_UNLIKELY (index >= size) {
1116
                throw fkyaml::out_of_range(index);
2✔
1117
            }
1118
            return seq[index];
1119
        }
1120

1121
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
1122
        mapping_type& map = *act_node.m_value.p_map;
1123
        bool is_found = map.find(key) != map.end();
1124
        if FK_YAML_UNLIKELY (!is_found) {
1125
            throw fkyaml::out_of_range(serialize(key).c_str());
21✔
1126
        }
21✔
1127
        return map[std::forward<KeyType>(key)];
21✔
1128
    }
5✔
1129

1130
    /// @brief Get a basic_node object with a basic_node key object.
1131
    /// @tparam KeyType A key type which is a kind of the basic_node template class.
16✔
1132
    /// @param key A key to the target basic_node object in a sequence/mapping node.
7✔
1133
    /// @return Constant reference to the basic_node object associated with the given key.
5✔
1134
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/at/
1135
    template <typename KeyType, detail::enable_if_t<detail::is_basic_node<KeyType>::value, int> = 0>
1136
    const basic_node& at(KeyType&& key) const {
2✔
1137
        const basic_node& act_node = resolve_reference();
2✔
1138
        if FK_YAML_UNLIKELY (act_node.is_scalar_impl()) {
2✔
1139
            throw fkyaml::type_error("at() is unavailable for a scalar node.", get_type());
2✔
1140
        }
2✔
1141

1✔
1142
        if (act_node.is_sequence_impl()) {
1143
            if FK_YAML_UNLIKELY (!key.is_integer()) {
1✔
1144
                throw fkyaml::type_error("An argument of at() for sequence nodes must be an integer.", get_type());
1145
            }
1146

9✔
1147
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
9✔
1148
            const sequence_type& seq = *act_node.m_value.p_seq;
9✔
1149
            int index = std::forward<KeyType>(key).template get_value<int>();
9✔
1150
            int size = static_cast<int>(seq.size());
7✔
1151
            if FK_YAML_UNLIKELY (index >= size) {
1152
                throw fkyaml::out_of_range(index);
2✔
1153
            }
1154
            return seq[index];
1155
        }
1156

1157
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
1158
        const mapping_type& map = *act_node.m_value.p_map;
14✔
1159
        bool is_found = map.find(key) != map.end();
14✔
1160
        if FK_YAML_UNLIKELY (!is_found) {
1161
            throw fkyaml::out_of_range(serialize(key).c_str());
1162
        }
1163
        return map.at(std::forward<KeyType>(key));
1164
    }
1165

6✔
1166
    /// @brief Get the YAML version for this basic_node object.
6✔
1167
    /// @return The YAML version if already set, `yaml_version_type::VERSION_1_2` otherwise.
6✔
1168
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_yaml_version_type/
6✔
1169
    yaml_version_type get_yaml_version_type() const noexcept {
1170
        return mp_meta->is_version_specified ? mp_meta->version : yaml_version_type::VERSION_1_2;
1171
    }
1172

1173
    /// @brief Set the YAML version for this basic_node object.
1174
    /// @param[in] version The target YAML version.
1175
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/set_yaml_version_type/
4✔
1176
    void set_yaml_version_type(const yaml_version_type version) noexcept {
4✔
1177
        mp_meta->version = version;
4✔
1178
        mp_meta->is_version_specified = true;
1179
    }
1180

1181
    /// @brief Get the YAML version for this basic_node object.
1182
    /// @deprecated Use get_yaml_version_type() function. (since 0.3.12)
1183
    /// @return The YAML version if already set, `yaml_version_t::VER_1_2` otherwise.
1184
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_yaml_version/
1185
    FK_YAML_DEPRECATED("Since 0.3.12; Use get_yaml_version_type()")
3✔
1186
    yaml_version_t get_yaml_version() const noexcept {
3✔
1187
        yaml_version_type tmp_type = get_yaml_version_type();
3✔
1188
        return detail::convert_from_yaml_version_type(tmp_type);
1189
    }
1190

1191
    /// @brief Set the YAML version for this basic_node object.
1192
    /// @deprecated Use set_yaml_version_type(yaml_version_type) function. (since 0.3.12)
45,658✔
1193
    /// @param[in] version The target YAML version.
45,658✔
1194
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/set_yaml_version/
1195
    FK_YAML_DEPRECATED("Since 0.3.12; Use set_yaml_version_type(const yaml_version_type)")
1196
    void set_yaml_version(const yaml_version_t version) noexcept {
1197
        set_yaml_version_type(detail::convert_to_yaml_version_type(version));
1198
    }
1199

1200
    /// @brief Check whether this basic_node object has already had any anchor name.
1201
    /// @return true if ths basic_node has an anchor name, false otherwise.
51✔
1202
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/has_anchor_name/
51✔
1203
    bool has_anchor_name() const noexcept {
1✔
1204
        return (m_attrs & detail::node_attr_mask::anchoring) && !m_prop.anchor.empty();
1205
    }
50✔
1206

1207
    /// @brief Get the anchor name associated with this basic_node object.
1208
    /// @note Some anchor name must be set before calling this method. Call has_anchor_name() to see if this basic_node
1209
    /// object has any anchor name.
1210
    /// @return The anchor name associated with the node.
1211
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_anchor_name/
1212
    const std::string& get_anchor_name() const {
4✔
1213
        if FK_YAML_UNLIKELY (!has_anchor_name()) {
4✔
1214
            throw fkyaml::exception("No anchor name has been set.");
1✔
1215
        }
1✔
1216
        return m_prop.anchor;
1✔
1217
    }
1✔
1218

1✔
1219
    /// @brief Add an anchor name to this basic_node object.
1✔
1220
    /// @note If this basic_node object has already had any anchor name, the new anchor name will overwrite the old one.
1221
    /// @param[in] anchor_name An anchor name. This should not be empty.
1222
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/add_anchor_name/
4✔
1223
    void add_anchor_name(const std::string& anchor_name) {
1224
        if (is_anchor()) {
4✔
1225
            m_attrs &= ~detail::node_attr_mask::anchoring;
4✔
1226
            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;
4✔
1227
            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));
1228
            mp_meta.reset();
4✔
1229
            itr->second.swap(*this);
4✔
1230
            mp_meta->anchor_table.erase(itr);
4✔
1231
        }
4✔
1232

4✔
1233
        auto p_meta = mp_meta;
4✔
1234

4✔
1235
        basic_node node;
1236
        node.swap(*this);
1237
        p_meta->anchor_table.emplace(anchor_name, std::move(node));
1238

1239
        m_attrs &= ~detail::node_attr_mask::anchoring;
1240
        m_attrs |= detail::node_attr_bits::anchor_bit;
258✔
1241
        mp_meta = p_meta;
258✔
1242
        const auto offset = static_cast<uint32_t>(mp_meta->anchor_table.count(anchor_name) - 1);
1✔
1243
        detail::node_attr_bits::set_anchor_offset(offset, m_attrs);
1✔
1244
        m_prop.anchor = anchor_name;
1✔
1245
    }
1✔
1246

1✔
1247
    /// @brief Add an anchor name to this basic_node object.
1✔
1248
    /// @note If this basic_node object has already had any anchor name, the new anchor name will overwrite the old one.
1249
    /// @param[in] anchor_name An anchor name. This should not be empty.
1250
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/add_anchor_name/
258✔
1251
    void add_anchor_name(std::string&& anchor_name) {
1252
        if (is_anchor()) {
258✔
1253
            m_attrs &= ~detail::node_attr_mask::anchoring;
258✔
1254
            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;
258✔
1255
            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));
1256
            mp_meta.reset();
258✔
1257
            itr->second.swap(*this);
258✔
1258
            mp_meta->anchor_table.erase(itr);
258✔
1259
        }
258✔
1260

258✔
1261
        auto p_meta = mp_meta;
258✔
1262

258✔
1263
        basic_node node;
1264
        node.swap(*this);
1265
        p_meta->anchor_table.emplace(anchor_name, std::move(node));
1266

1267
        m_attrs &= ~detail::node_attr_mask::anchoring;
346✔
1268
        m_attrs |= detail::node_attr_bits::anchor_bit;
346✔
1269
        mp_meta = p_meta;
1270
        auto offset = static_cast<uint32_t>(mp_meta->anchor_table.count(anchor_name) - 1);
1271
        detail::node_attr_bits::set_anchor_offset(offset, m_attrs);
1272
        m_prop.anchor = std::move(anchor_name);
1273
    }
1274

1275
    /// @brief Check whether this basic_node object has already had any tag name.
1276
    /// @return true if ths basic_node has a tag name, false otherwise.
65✔
1277
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/has_tag_name/
65✔
1278
    bool has_tag_name() const noexcept {
1✔
1279
        return !m_prop.tag.empty();
1280
    }
64✔
1281

1282
    /// @brief Get the tag name associated with this basic_node object.
1283
    /// @note Some tag name must be set before calling this method. Call has_tag_name() to see if this basic_node
1284
    /// object has any tag name.
1285
    /// @return The tag name associated with the node. It may be empty.
1286
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_tag_name/
1287
    const std::string& get_tag_name() const {
2✔
1288
        if FK_YAML_UNLIKELY (!has_tag_name()) {
2✔
1289
            throw fkyaml::exception("No tag name has been set.");
2✔
1290
        }
1291
        return m_prop.tag;
1292
    }
1293

1294
    /// @brief Add a tag name to this basic_node object.
1295
    /// @note If this basic_node object has already had any tag name, the new tag name will overwrite the old one.
58✔
1296
    /// @param[in] tag_name A tag name to get associated with this basic_node object.
58✔
1297
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/add_tag_name/
58✔
1298
    void add_tag_name(const std::string& tag_name) {
1299
        m_prop.tag = tag_name;
1300
    }
1301

1302
    /// @brief Add a tag name to this basic_node object.
1303
    /// @note If this basic_node object has already had any tag name, the new tag name will overwrite the old one.
1304
    /// @param[in] tag_name A tag name to get associated with this basic_node object.
1305
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/add_tag_name/
1306
    void add_tag_name(std::string&& tag_name) {
1307
        m_prop.tag = std::move(tag_name);
1308
    }
1309

1310
    /// @brief Get the node value object converted into a given type.
1311
    /// @note This function requires T objects to be default constructible. Also, T cannot be either a reference,
2,515✔
1312
    /// pointer or C-style array type.
1313
    /// @tparam T A compatible value type which may be cv-qualified.
1314
    /// @tparam ValueType A compatible value type (T without cv-qualifiers by default).
1315
    /// @return A value converted from this basic_node object.
1316
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_value/
1317
    template <
1318
        typename T, typename ValueType = detail::remove_cv_t<T>,
1319
        detail::enable_if_t<
1320
            detail::conjunction<std::is_default_constructible<ValueType>, detail::negation<std::is_pointer<T>>>::value,
1321
            int> = 0>
1322
    T get_value() const noexcept(
2,516✔
1323
        noexcept(std::declval<const basic_node&>().template get_value_impl<ValueType>(std::declval<ValueType&>()))) {
2,515✔
1324
        // emit a compile error if T is either a reference, pointer or C-style array type.
2,441✔
1325
        static_assert(
42✔
1326
            !std::is_reference<T>::value,
1327
            "get_value() cannot be called with reference types. "
1328
            "You might want to call one of as_seq(), as_map(), as_bool(), as_int(), as_float() or as_str().");
1329
        static_assert(
1330
            !std::is_array<T>::value,
1331
            "get_value() cannot be called with C-style array types. You might want to call get_value_inplace().");
1332

204✔
1333
        auto ret = ValueType();
1334
        resolve_reference().get_value_impl(ret);
204✔
1335
        return ret;
201✔
1336
    }
1337

1338
    /// @brief Get the node value object converted into a given type. The conversion result is filled into `value_ref`.
1339
    /// @tparam T A compatible value type.
1340
    /// @param value_ref A storage into which the conversion result is filled.
1341
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_value_inplace/
1342
    template <typename T>
1343
    void get_value_inplace(T& value_ref) const
1344
        noexcept(noexcept(std::declval<const basic_node&>().template get_value_impl<T>(std::declval<T&>()))) {
1345
        resolve_reference().get_value_impl(value_ref);
1346
    }
1347

1348
    /// @brief Get the node value object converted to a given type. If the conversion fails, this function returns a
1349
    /// given default value instead.
1350
    /// @note This function requires T to be default constructible. Also, T cannot be either a reference, pointer or
1351
    /// C-style array type.
1352
    /// @tparam T A compatible value type which may be cv-qualified.
1353
    /// @tparam U A default value type from which T must be constructible.
1354
    /// @param default_value The default value returned if conversion fails.
30✔
1355
    /// @return A value converted from this basic_node object if conversion succeeded, the given default value
1356
    /// otherwise.
1357
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_value_or/
1358
    template <
1359
        typename T, typename U,
1360
        detail::enable_if_t<
1361
            detail::conjunction<
1362
                std::is_constructible<T, U>, std::is_default_constructible<T>,
1363
                detail::negation<std::is_pointer<T>>>::value,
1364
            int> = 0>
1365
    T get_value_or(U&& default_value) const noexcept {
1366
        static_assert(
1367
            !std::is_reference<T>::value,
1368
            "get_value_or() cannot be called with reference types. "
30✔
1369
            "You might want to call one of as_seq(), as_map(), as_bool(), as_int(), as_float() or as_str().");
1370
        static_assert(
15✔
1371
            !std::is_array<T>::value,
1372
            "get_value_or() cannot be called with C-style array types. You might want to call get_value_inplace().");
1373

1374
        // TODO:
15✔
1375
        // Ideally, there should be no exception thrown in this kind of function. However, achieving that would require
1376
        // a lot of refactoring and/or some API changes, especially `from_node` interface definition. So, try-catch is
1377
        // used instead for now.
1378
        try {
1379
            return get_value<T>();
1380
        }
1381
        catch (const std::exception& /*unused*/) {
1382
            // Any exception derived from std::exception is interpreted as a conversion failure in some way
1383
            // since user-defined from_node function may throw a different object from a fkyaml::type_error.
1384
            // and std::exception is usually the base class of user-defined exception types.
84✔
1385
            return std::forward<U>(default_value);
84✔
1386
        }
1387
    }
1388

1389
    /// @brief Explicit reference access to the internally stored YAML node value.
1390
    /// @tparam ReferenceType Reference type to the target YAML node value.
1391
    /// @return Reference to the internally stored YAML node value.
1392
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_value_ref/
1393
    template <typename ReferenceType, detail::enable_if_t<std::is_reference<ReferenceType>::value, int> = 0>
1394
    FK_YAML_DEPRECATED("Since 0.4.3; Use one of as_seq(), as_map(), as_bool(), as_int(), as_float() or as_str()")
1395
    ReferenceType get_value_ref() {
1396
        return get_value_ref_impl(static_cast<detail::add_pointer_t<ReferenceType>>(nullptr));
1397
    }
1398

1399
    /// @brief Explicit reference access to the internally stored YAML node value.
1400
    /// @tparam ReferenceType Constant reference type to the target YAML node value.
1401
    /// @return Constant reference to the internally stored YAML node value.
1402
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_value_ref/
1403
    template <
1404
        typename ReferenceType,
1405
        detail::enable_if_t<
1406
            detail::conjunction<
1407
                std::is_reference<ReferenceType>, std::is_const<detail::remove_reference_t<ReferenceType>>>::value,
278✔
1408
            int> = 0>
278✔
1409
    FK_YAML_DEPRECATED("Since 0.4.3; Use one of as_seq(), as_map(), as_bool(), as_int(), as_float() or as_str()")
278✔
1410
    ReferenceType get_value_ref() const {
260✔
1411
        return get_value_ref_impl(static_cast<detail::add_pointer_t<ReferenceType>>(nullptr));
1412
    }
18✔
1413

1414
    /// @brief Returns reference to the sequence node value.
1415
    /// @throw fkyaml::type_error The node value is not a sequence.
1416
    /// @return Reference to the sequence node value.
1417
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_seq/
1418
    sequence_type& as_seq() {
1419
        basic_node& act_node = resolve_reference(); // NOLINT(misc-const-correctness)
26✔
1420
        if FK_YAML_LIKELY (act_node.is_sequence_impl()) {
26✔
1421
            return *act_node.m_value.p_seq;
26✔
1422
        }
8✔
1423
        throw fkyaml::type_error("The node value is not a sequence.", get_type());
1424
    }
18✔
1425

1426
    /// @brief Returns constant reference to the sequence node value.
1427
    /// @throw fkyaml::type_error The node value is not a sequence.
1428
    /// @return Constant reference to the sequence node value.
1429
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_seq/
1430
    const sequence_type& as_seq() const {
1431
        const basic_node& act_node = resolve_reference();
537✔
1432
        if FK_YAML_LIKELY (act_node.is_sequence_impl()) {
537✔
1433
            return *act_node.m_value.p_seq;
537✔
1434
        }
519✔
1435
        throw fkyaml::type_error("The node value is not a sequence.", get_type());
1436
    }
18✔
1437

1438
    /// @brief Returns reference to the mapping node value.
1439
    /// @throw fkyaml::type_error The node value is not a mapping.
1440
    /// @return Reference to the mapping node value.
1441
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_map/
1442
    mapping_type& as_map() {
1443
        basic_node& act_node = resolve_reference(); // NOLINT(misc-const-correctness)
46✔
1444
        if FK_YAML_LIKELY (act_node.is_mapping_impl()) {
46✔
1445
            return *act_node.m_value.p_map;
46✔
1446
        }
28✔
1447
        throw fkyaml::type_error("The node value is not a mapping.", get_type());
1448
    }
18✔
1449

1450
    /// @brief Returns constant reference to the mapping node value.
1451
    /// @throw fkyaml::type_error The node value is not a mapping.
1452
    /// @return Constant reference to the mapping node value.
1453
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_map/
1454
    const mapping_type& as_map() const {
1455
        const basic_node& act_node = resolve_reference();
46✔
1456
        if FK_YAML_LIKELY (act_node.is_mapping_impl()) {
46✔
1457
            return *act_node.m_value.p_map;
46✔
1458
        }
28✔
1459
        throw fkyaml::type_error("The node value is not a mapping.", get_type());
1460
    }
18✔
1461

1462
    /// @brief Returns reference to the boolean node value.
1463
    /// @throw fkyaml::type_error The node value is not a boolean.
1464
    /// @return Reference to the boolean node value.
1465
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_bool/
1466
    boolean_type& as_bool() {
1467
        basic_node& act_node = resolve_reference();
348✔
1468
        if FK_YAML_LIKELY (act_node.is_boolean_impl()) {
348✔
1469
            return act_node.m_value.boolean;
348✔
1470
        }
330✔
1471
        throw fkyaml::type_error("The node value is not a boolean.", get_type());
1472
    }
18✔
1473

1474
    /// @brief Returns reference to the boolean node value.
1475
    /// @throw fkyaml::type_error The node value is not a boolean.
1476
    /// @return Constant reference to the boolean node value.
1477
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_bool/
21✔
1478
    const boolean_type& as_bool() const {
21✔
1479
        const basic_node& act_node = resolve_reference();
1480
        if FK_YAML_LIKELY (act_node.is_boolean_impl()) {
1481
            return act_node.m_value.boolean;
1482
        }
1483
        throw fkyaml::type_error("The node value is not a boolean.", get_type());
1484
    }
1485

1486
    /// @brief Checks if the node value is an unsigned integer.
25✔
1487
    /// @return true if the node holds an unsigned integer, false otherwise.
25✔
1488
    bool is_uint() const noexcept {
25✔
1489
        const auto& resolved = resolve_reference();
1490
        if (resolved.is_uint_impl()) {
1491
            return true;
1492
        }
1493
        if (resolved.is_integer_impl() && resolved.m_value.integer >= static_cast<integer_type>(0)) {
1494
            // This is a signed integer node, but the value is non-negative,
21✔
1495
            // so it can be treated as an unsigned integer.
11✔
1496
            return true;
1497
        }
1498
        return false;
10✔
1499
    }
6✔
1500

1501
    /// @brief Returns the integer node value as an unsigned 64-bit integer.
1502
    /// This is valid both for nodes where integer_type is unsigned and for nodes where a large
8✔
1503
    /// positive decimal scalar (> INT64_MAX) was stored with the uint_bit flag set.
1504
    /// @throw fkyaml::type_error if the node is not a compatible integer.
1505
    /// @return The node value as uint64_t.
1506
    uint64_t as_uint() const {
1507
        const basic_node& act_node = resolve_reference();
1508
        if FK_YAML_LIKELY (act_node.is_integer_impl()) {
1509
            // When integer_type is unsigned the stored value IS the uint64_t directly.
49✔
1510
            if (std::is_unsigned<integer_type>::value) {
49✔
1511
                return static_cast<uint64_t>(act_node.m_value.integer);
49✔
1512
            }
31✔
1513
            // When integer_type is signed, only uint_bit-marked nodes carry a uint64_t.
3✔
1514
            if (act_node.m_attrs & detail::node_attr_bits::uint_bit) {
1515
                return static_cast<uint64_t>(act_node.m_value.integer);
1516
            }
1517
            // Signed values in the non-negative range can be returned safely.
1518
            if (act_node.m_value.integer >= static_cast<integer_type>(0)) {
28✔
1519
                return static_cast<uint64_t>(act_node.m_value.integer);
1520
            }
18✔
1521
        }
1522
        throw fkyaml::type_error("The node value cannot be represented as an unsigned integer.", get_type());
1523
    }
1524

1525
    /// @brief Returns reference to the integer node value.
1526
    /// @throw fkyaml::type_error The node value is not an integer.
1527
    /// @return Reference to the integer node value.
1,919✔
1528
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_int/
1,919✔
1529
    integer_type& as_int() {
1,919✔
1530
        basic_node& act_node = resolve_reference();
1,901!
UNCOV
1531
        if FK_YAML_LIKELY (act_node.is_integer_impl()) {
×
1532
            if FK_YAML_UNLIKELY (act_node.is_uint_impl()) {
1533
                throw fkyaml::type_error(
1534
                    "The integer value exceeds INT64_MAX and cannot be returned as a signed integer. "
1535
                    "Use as_uint() instead.",
1536
                    get_type());
1,901✔
1537
            }
1538
            return act_node.m_value.integer;
18✔
1539
        }
1540
        throw fkyaml::type_error("The node value is not an integer.", get_type());
1541
    }
1542

1543
    /// @brief Returns reference to the integer node value.
1544
    /// @throw fkyaml::type_error The node value is not an integer, or exceeds INT64_MAX.
1545
    /// @return Constant reference to the integer node value.
38✔
1546
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_int/
38✔
1547
    const integer_type& as_int() const {
38✔
1548
        const basic_node& act_node = resolve_reference();
20✔
1549
        if FK_YAML_LIKELY (act_node.is_integer_impl()) {
1550
            if FK_YAML_UNLIKELY (act_node.is_uint_impl()) {
18✔
1551
                throw fkyaml::type_error(
1552
                    "The integer value exceeds INT64_MAX and cannot be returned as a signed integer. "
1553
                    "Use as_uint() instead.",
1554
                    get_type());
1555
            }
1556
            return act_node.m_value.integer;
1557
        }
205✔
1558
        throw fkyaml::type_error("The node value is not an integer.", get_type());
205✔
1559
    }
205✔
1560

187✔
1561
    /// @brief Returns reference to the float node value.
1562
    /// @throw fkyaml::type_error The node value is not a float.
18✔
1563
    /// @return Reference to the float node value.
1564
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_float/
1565
    float_number_type& as_float() {
1566
        basic_node& act_node = resolve_reference();
1567
        if FK_YAML_LIKELY (act_node.is_float_number_impl()) {
1568
            return act_node.m_value.float_val;
1569
        }
347✔
1570
        throw fkyaml::type_error("The node value is not a float.", get_type());
347✔
1571
    }
347✔
1572

329✔
1573
    /// @brief Returns reference to the float node value.
1574
    /// @throw fkyaml::type_error The node value is not a float.
18✔
1575
    /// @return Constant reference to the float node value.
1576
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_float/
1577
    const float_number_type& as_float() const {
1578
        const basic_node& act_node = resolve_reference();
1579
        if FK_YAML_LIKELY (act_node.is_float_number_impl()) {
1580
            return act_node.m_value.float_val;
1581
        }
231✔
1582
        throw fkyaml::type_error("The node value is not a float.", get_type());
231✔
1583
    }
231✔
1584

213✔
1585
    /// @brief Returns reference to the string node value.
1586
    /// @throw fkyaml::type_error The node value is not a string.
18✔
1587
    /// @return Reference to the string node value.
1588
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_str/
1589
    string_type& as_str() {
1590
        basic_node& act_node = resolve_reference();
1591
        if FK_YAML_LIKELY (act_node.is_string_impl()) {
1592
            return *act_node.m_value.p_str;
1,697✔
1593
        }
1594
        throw fkyaml::type_error("The node value is not a string.", get_type());
1,697✔
1595
    }
1,697✔
1596

1597
    /// @brief Returns reference to the string node value.
1,697✔
1598
    /// @throw fkyaml::type_error The node value is not a string.
1,697✔
1599
    /// @return Constant reference to the string node value.
1,697✔
1600
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_str/
1,697✔
1601
    const string_type& as_str() const {
1602
        const basic_node& act_node = resolve_reference();
1,697✔
1603
        if FK_YAML_LIKELY (act_node.is_string_impl()) {
1,697✔
1604
            return *act_node.m_value.p_str;
1,697✔
1605
        }
1606
        throw fkyaml::type_error("The node value is not a string.", get_type());
1607
    }
1608

1609
    /// @brief Swaps the internally stored data with the specified basic_node object.
1610
    /// @param[in] rhs A basic_node object to be swapped with.
114✔
1611
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/swap/
114✔
1612
    void swap(basic_node& rhs) noexcept {
114✔
1613
        using std::swap;
56✔
1614
        swap(m_attrs, rhs.m_attrs);
56✔
1615
        swap(mp_meta, rhs.mp_meta);
56✔
1616

48✔
1617
        node_value tmp {};
48✔
1618
        std::memcpy(&tmp, &m_value, sizeof(node_value));
48✔
1619
        std::memcpy(&m_value, &rhs.m_value, sizeof(node_value));
10✔
1620
        std::memcpy(&rhs.m_value, &tmp, sizeof(node_value));
10✔
1621

1622
        swap(m_prop.tag, rhs.m_prop.tag);
1623
        swap(m_prop.anchor, rhs.m_prop.anchor);
1624
    }
1625

1626
    /// @brief Returns an iterator to the first element of a container node (sequence or mapping).
1627
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1628
    /// @return An iterator to the first element of a container node.
146✔
1629
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/begin/
146✔
1630
    iterator begin() {
146✔
1631
        basic_node& act_node = resolve_reference();
75✔
1632
        switch (act_node.m_attrs & detail::node_attr_mask::value) {
75✔
1633
        case detail::node_attr_bits::seq_bit:
75✔
1634
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
41✔
1635
            return {act_node.m_value.p_seq->begin()};
41✔
1636
        case detail::node_attr_bits::map_bit:
41✔
1637
            FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
30✔
1638
            return {act_node.m_value.p_map->begin()};
30✔
1639
        default:
1640
            throw fkyaml::type_error("The target node is neither of sequence nor mapping types.", get_type());
1641
        }
1642
    }
1643

1644
    /// @brief Returns a const iterator to the first element of a container node (sequence or mapping).
1645
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1646
    /// @return A const iterator to the first element of a container node.
18✔
1647
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/begin/
18✔
1648
    const_iterator begin() const {
1649
        const basic_node& act_node = resolve_reference();
1650
        switch (act_node.m_attrs & detail::node_attr_mask::value) {
1651
        case detail::node_attr_bits::seq_bit:
1652
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
1653
            return {act_node.m_value.p_seq->begin()};
1654
        case detail::node_attr_bits::map_bit:
108✔
1655
            FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
108✔
1656
            return {act_node.m_value.p_map->begin()};
108✔
1657
        default:
51✔
1658
            throw fkyaml::type_error("The target node is neither of sequence nor mapping types.", get_type());
51✔
1659
        }
51✔
1660
    }
47✔
1661

47✔
1662
    /// @brief Returns a const iterator to the first element of a container node (sequence or mapping).
47✔
1663
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
10✔
1664
    /// @return A const iterator to the first element of a container node.
10✔
1665
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/begin/
1666
    const_iterator cbegin() const {
1667
        return begin();
1668
    }
1669

1670
    /// @brief Returns an iterator to the past-the-last element of a container node (sequence or mapping).
1671
    /// @throw `type_error` if the basic_node value is not of container types.
1672
    /// @return An iterator to the past-the-last element of a container node.
145✔
1673
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/end/
145✔
1674
    iterator end() {
145✔
1675
        basic_node& act_node = resolve_reference();
74✔
1676
        switch (act_node.m_attrs & detail::node_attr_mask::value) {
74✔
1677
        case detail::node_attr_bits::seq_bit:
74✔
1678
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
41✔
1679
            return {act_node.m_value.p_seq->end()};
41✔
1680
        case detail::node_attr_bits::map_bit:
41✔
1681
            FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
30✔
1682
            return {act_node.m_value.p_map->end()};
30✔
1683
        default:
1684
            throw fkyaml::type_error("The target node is neither of sequence nor mapping types.", get_type());
1685
        }
1686
    }
1687

1688
    /// @brief Returns a const iterator to the past-the-last element of a container node (sequence or mapping).
1689
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1690
    /// @return A const iterator to the past-the-last element of a container node.
18✔
1691
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/end/
18✔
1692
    const_iterator end() const {
1693
        const basic_node& act_node = resolve_reference();
1694
        switch (act_node.m_attrs & detail::node_attr_mask::value) {
1695
        case detail::node_attr_bits::seq_bit:
1696
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
1697
            return {act_node.m_value.p_seq->end()};
1698
        case detail::node_attr_bits::map_bit:
1699
            FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
69✔
1700
            return {act_node.m_value.p_map->end()};
69✔
1701
        default:
1702
            throw fkyaml::type_error("The target node is neither of sequence nor mapping types.", get_type());
1703
        }
1704
    }
1705

1706
    /// @brief Returns a const iterator to the past-the-last element of a container node (sequence or mapping).
1707
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1708
    /// @return A const iterator to the past-the-last element of a container node.
27✔
1709
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/end/
27✔
1710
    const_iterator cend() const {
1711
        return end();
1712
    }
1713

1714
    /// @brief Returns an iterator to the reverse-beginning (i.e., last) element of a container node (sequence or
1715
    /// mapping).
1716
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1717
    /// @return An iterator to the reverse-beginning element of a container node.
18✔
1718
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rbegin/
18✔
1719
    reverse_iterator rbegin() {
1720
        return {end()};
1721
    }
1722

1723
    /// @brief Returns a const iterator to the reverse-beginning (i.e., last) element of a container node (sequence or
1724
    /// mapping).
1725
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1726
    /// @return A const iterator to the reverse-beginning element of a container node.
9✔
1727
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rbegin/
9✔
1728
    const_reverse_iterator rbegin() const {
1729
        return {end()};
1730
    }
1731

1732
    /// @brief Returns a const iterator to the reverse-beginning (i.e., last) element of a container node (sequence or
1733
    /// mapping).
1734
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1735
    /// @return A const iterator to the reverse-beginning element of a container node.
27✔
1736
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rbegin/
27✔
1737
    const_reverse_iterator crbegin() const {
1738
        return rbegin();
1739
    }
1740

1741
    /// @brief Returns an iterator to the reverse-end (i.e., one before the first) element of a container node (sequence
1742
    /// or mapping).
1743
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1744
    /// @return An iterator to the reverse-end element.
18✔
1745
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rend/
18✔
1746
    reverse_iterator rend() {
1747
        return {begin()};
1748
    }
1749

1750
    /// @brief Returns a const iterator to the reverse-end (i.e., one before the first) element of a container node
1751
    /// (sequence or mapping).
1752
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
9✔
1753
    /// @return A const iterator to the reverse-end element.
9✔
1754
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rend/
6✔
1755
    const_reverse_iterator rend() const {
1756
        return {begin()};
3✔
1757
    }
1758

1759
    /// @brief Returns a const iterator to the reverse-end (i.e., one before the first) element of a container node
1760
    /// (sequence or mapping).
1761
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1762
    /// @return A const iterator to the reverse-end element.
1763
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rend/
33✔
1764
    const_reverse_iterator crend() const {
33✔
1765
        return rend();
6✔
1766
    }
1767

27✔
1768
    /// @brief Returns a range of mapping entries.
1769
    /// @throw `type_error` if this basic_node is not a mapping.
1770
    /// @return A range of mapping entries.
1771
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/map_items/
1772
    map_range map_items() {
1773
        if FK_YAML_UNLIKELY (!is_mapping()) {
2,944✔
1774
            throw type_error("map_items() cannot be called on a non-mapping node.", get_type());
2,944✔
1775
        }
107✔
1776
        return {*this};
107✔
1777
    }
107✔
1778

1779
    /// @brief Returns a const range of mapping entries.
2,837✔
1780
    /// @throw `type_error` if this basic_node is not a mapping.
1781
    /// @return A const range of mapping entries.
1782
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/map_items/
1783
    const_map_range map_items() const {
1784
        if FK_YAML_UNLIKELY (!is_mapping()) {
29,745✔
1785
            throw type_error("map_items() cannot be called on a non-mapping node.", get_type());
29,745✔
1786
        }
416✔
1787
        return {*this};
416✔
1788
    }
416✔
1789

1790
    /// @brief Erase a mapping entry by key.
29,329✔
1791
    /// @tparam KeyType A type for the input key (any type convertible to node).
1792
    /// @param key A key identifying the mapping entry to erase.
1793
    /// @return The number of erased entries (0 or 1).
4,672✔
1794
    template <typename KeyType>
4,672✔
1795
    size_type erase(KeyType&& key) {
1796
        basic_node key_node = std::forward<KeyType>(key);
1797
        basic_node& act_node = resolve_reference();
1,857✔
1798
        if FK_YAML_UNLIKELY (!act_node.is_mapping_impl()) {
1,857✔
1799
            throw type_error("erase() cannot be called on a non-mapping node.", get_type());
1800
        }
1801

120✔
1802
        auto& map = *act_node.m_value.p_map;
120✔
1803
        for (auto itr = map.begin(); itr != map.end(); ++itr) {
1804
            if (itr->first == key_node) {
1805
                map.erase(itr);
591✔
1806
                return size_type {1};
591✔
1807
            }
1808
        }
1809
        return size_type {0};
3,807✔
1810
    }
3,807✔
1811

1812
private:
1813
    /// @brief Resolves anchor/alias reference and returns reference to an actual value node.
1,953✔
1814
    /// @return Reference to an actual value node.
1815
    basic_node& resolve_reference() {
1816
        if FK_YAML_UNLIKELY (has_anchor_name()) {
1,953✔
1817
            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;
1818
            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));
1819
            return itr->second;
353✔
1820
        }
353✔
1821
        return *this;
1822
    }
1823

1,098✔
1824
    /// @brief Resolves anchor/alias reference and returns const reference to an actual value node.
1,098✔
1825
    /// @return Const reference to an actual value node.
1826
    const basic_node& resolve_reference() const {
1827
        if FK_YAML_UNLIKELY (has_anchor_name()) {
2,620✔
1828
            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;
2,620✔
1829
            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));
1830
            return itr->second;
1831
        }
1832
        return *this;
1833
    }
2,595✔
1834

1835
    bool is_sequence_impl() const noexcept {
2,595✔
1836
        return m_attrs & detail::node_attr_bits::seq_bit;
2,517✔
1837
    }
1838

1839
    bool is_mapping_impl() const noexcept {
124✔
1840
        return m_attrs & detail::node_attr_bits::map_bit;
124✔
1841
    }
124✔
1842

1843
    bool is_null_impl() const noexcept {
1844
        return m_attrs & detail::node_attr_bits::null_bit;
1845
    }
1846

7✔
1847
    bool is_boolean_impl() const noexcept {
7✔
1848
        return m_attrs & detail::node_attr_bits::bool_bit;
1849
    }
1850

1851
    bool is_integer_impl() const noexcept {
1852
        return m_attrs & detail::node_attr_bits::int_bit;
1853
    }
7✔
1854

7✔
1855
    bool is_uint_impl() const noexcept {
1856
        // Both int_bit and uint_bit must be set: this node stores a uint64_t value
1857
        // whose bit pattern was placed into the signed integer_type field.
1858
        return (m_attrs & detail::node_attr_bits::int_bit) && (m_attrs & detail::node_attr_bits::uint_bit);
1859
    }
1860

7✔
1861
    bool is_float_number_impl() const noexcept {
7✔
1862
        return m_attrs & detail::node_attr_bits::float_bit;
1863
    }
1864

1865
    bool is_string_impl() const noexcept {
1866
        return m_attrs & detail::node_attr_bits::string_bit;
1867
    }
7✔
1868

7✔
1869
    bool is_scalar_impl() const noexcept {
1870
        return m_attrs & detail::node_attr_bits::scalar_bits;
1871
    }
1872

1873
    template <
1874
        typename ValueType, detail::enable_if_t<detail::negation<detail::is_basic_node<ValueType>>::value, int> = 0>
7✔
1875
    void get_value_impl(ValueType& v) const
7✔
1876
        noexcept(noexcept(ConverterType<ValueType, void>::from_node(std::declval<const basic_node&>(), v))) {
1877
        ConverterType<ValueType, void>::from_node(*this, v);
1878
    }
1879

1880
    template <typename ValueType, detail::enable_if_t<detail::is_basic_node<ValueType>::value, int> = 0>
1881
    void get_value_impl(ValueType& v) const {
7✔
1882
        v = *this;
7✔
1883
    }
1884

1885
    /// @brief Returns reference to the sequence node value.
1886
    /// @throw fkyaml::exception The node value is not a sequence.
1887
    /// @return Reference to the sequence node value.
1888
    sequence_type& get_value_ref_impl(sequence_type* /*unused*/) {
7✔
1889
        return as_seq();
7✔
1890
    }
1891

1892
    /// @brief Returns constant reference to the sequence node value.
1893
    /// @throw fkyaml::exception The node value is not a sequence.
1894
    /// @return Constant reference to the sequence node value.
1895
    const sequence_type& get_value_ref_impl(const sequence_type* /*unused*/) const {
7✔
1896
        return as_seq();
7✔
1897
    }
1898

1899
    /// @brief Returns reference to the mapping node value.
1900
    /// @throw fkyaml::exception The node value is not a mapping.
1901
    /// @return Reference to the mapping node value.
1902
    mapping_type& get_value_ref_impl(mapping_type* /*unused*/) {
7✔
1903
        return as_map();
7✔
1904
    }
1905

1906
    /// @brief Returns constant reference to the mapping node value.
1907
    /// @throw fkyaml::exception The node value is not a mapping.
1908
    /// @return Constant reference to the mapping node value.
1909
    const mapping_type& get_value_ref_impl(const mapping_type* /*unused*/) const {
7✔
1910
        return as_map();
7✔
1911
    }
1912

1913
    /// @brief Returns reference to the boolean node value.
1914
    /// @throw fkyaml::exception The node value is not a boolean.
1915
    /// @return Reference to the boolean node value.
1916
    boolean_type& get_value_ref_impl(boolean_type* /*unused*/) {
7✔
1917
        return as_bool();
7✔
1918
    }
1919

1920
    /// @brief Returns reference to the boolean node value.
1921
    /// @throw fkyaml::exception The node value is not a boolean.
1922
    /// @return Constant reference to the boolean node value.
1923
    const boolean_type& get_value_ref_impl(const boolean_type* /*unused*/) const {
7✔
1924
        return as_bool();
7✔
1925
    }
1926

1927
    /// @brief Returns reference to the integer node value.
1928
    /// @throw fkyaml::exception The node value is not an integer.
1929
    /// @return Reference to the integer node value.
1930
    integer_type& get_value_ref_impl(integer_type* /*unused*/) {
1931
        return as_int();
1932
    }
1933

1934
    /// @brief Returns reference to the integer node value.
1935
    /// @throw fkyaml::exception The node value is not an integer.
1936
    /// @return Constant reference to the integer node value.
1937
    const integer_type& get_value_ref_impl(const integer_type* /*unused*/) const {
1938
        return as_int();
1939
    }
1940

1941
    /// @brief Returns reference to the floating point number node value.
1942
    /// @throw fkyaml::exception The node value is not a floating point number.
1943
    /// @return Reference to the floating point number node value.
1944
    float_number_type& get_value_ref_impl(float_number_type* /*unused*/) {
1945
        return as_float();
1946
    }
1947

1✔
1948
    /// @brief Returns reference to the floating point number node value.
1949
    /// @throw fkyaml::exception The node value is not a floating point number.
1950
    /// @return Constant reference to the floating point number node value.
1951
    const float_number_type& get_value_ref_impl(const float_number_type* /*unused*/) const {
1✔
1952
        return as_float();
1✔
1953
    }
1954

1955
    /// @brief Returns reference to the string node value.
1956
    /// @throw fkyaml::exception The node value is not a string.
1957
    /// @return Reference to the string node value.
1958
    string_type& get_value_ref_impl(string_type* /*unused*/) {
1959
        return as_str();
1960
    }
1961

1962
    /// @brief Returns reference to the string node value.
1963
    /// @throw fkyaml::exception The node value is not a string.
1✔
1964
    /// @return Constant reference to the string node value.
1965
    const string_type& get_value_ref_impl(const string_type* /*unused*/) const {
1966
        return as_str();
1967
    }
1✔
1968

1969
    /// The current node attributes.
1✔
1970
    detail::node_attr_t m_attrs {detail::node_attr_bits::default_bits};
1971
    /// The shared set of YAML directives applied to this node.
1972
    mutable std::shared_ptr<detail::document_metainfo<basic_node>> mp_meta {
1973
        // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new)
1974
        std::shared_ptr<detail::document_metainfo<basic_node>>(new detail::document_metainfo<basic_node>())};
1975
    /// The current node value.
1976
    node_value m_value {};
1977
    /// The property set of this node.
1978
    detail::node_property m_prop {};
1979
};
1980

1981
/// @brief Swap function for basic_node objects.
1982
/// @param[in] lhs A left-side-hand basic_node object to be swapped with.
1✔
1983
/// @param[in] rhs A right-side-hand basic_node object to be swapped with.
1984
/// @sa https://fktn-k.github.io/fkYAML/api/swap/
1985
template <
1✔
1986
    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,
1987
    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,
1✔
1988
    template <typename, typename = void> class ConverterType>
1989
inline void swap(
1990
    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>& lhs,
1991
    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>&
1992
        rhs) noexcept(noexcept(lhs.swap(rhs))) {
1993
    lhs.swap(rhs);
1994
}
1995

1996
/// @brief Insertion operator for basic_node template class. A wrapper for the serialization feature.
1997
/// @param[in] os An output stream object.
1998
/// @param[in] n A basic_node object.
1999
/// @return Reference to the output stream object `os`.
2000
/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/insertion_operator/
2001
template <
2002
    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,
2003
    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,
2004
    template <typename, typename = void> class ConverterType>
2005
inline std::ostream& operator<<(
2006
    std::ostream& os,
2007
    const basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>&
2008
        n) {
2009
    os << basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>::
2010
            serialize(n);
2011
    return os;
2012
}
2013

6✔
2014
/// @brief Extraction operator for basic_node template class. A wrapper for the deserialization feature with input
6✔
2015
/// streams.
2016
/// @param[in] is An input stream object.
2017
/// @param[in] n A basic_node object.
2018
/// @return Reference to the input stream object `is`.
2019
/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/extraction_operator/
2020
template <
2021
    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,
2022
    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,
3✔
2023
    template <typename, typename = void> class ConverterType>
3✔
2024
inline std::istream& operator>>(
2025
    std::istream& is,
2026
    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>& n) {
2027
    n = basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>::
2028
        deserialize(is);
2029
    return is;
2030
}
2031

3✔
2032
/// @brief namespace for user-defined literals for the fkYAML library.
3✔
2033
inline namespace literals {
2034
/// @brief namespace for user-defined literals for YAML node objects.
2035
inline namespace yaml_literals {
2036

2037
// Whitespace before the literal operator identifier is deprecated in C++23 or better but required in C++11.
2038
// Ignore the warning as a workaround. https://github.com/fktn-k/fkYAML/pull/417
2039
#if defined(__clang__)
2040
#pragma clang diagnostic push
2041
#pragma clang diagnostic ignored "-Wdeprecated"
2042
#endif
2043

2044
#if defined(__GNUC__) && (__GNUC__ > 6)
2045
#define FK_YAML_QUOTE_OPERATOR operator""_yaml
2046
#else
2047
#define FK_YAML_QUOTE_OPERATOR operator"" _yaml
2048
#endif
2049

2050
/// @brief The user-defined string literal which deserializes a `char` array into a `node` object.
2051
/// @param s An input `char` array.
2052
/// @param n The size of `s`.
2053
/// @return The resulting `node` object deserialized from `s`.
2054
/// @sa https://fktn-k.github.io/fkYAML/api/operator_literal_yaml/
2055
inline fkyaml::node FK_YAML_QUOTE_OPERATOR(const char* s, std::size_t n) {
2056
    return fkyaml::node::deserialize(s, s + n);
2057
}
2058

2059
/// @brief The user-defined string literal which deserializes a `char16_t` array into a `node` object.
2060
/// @param s An input `char16_t` array.
2061
/// @param n The size of `s`.
2062
/// @return The resulting `node` object deserialized from `s`.
2063
/// @sa https://fktn-k.github.io/fkYAML/api/operator_literal_yaml/
2064
inline fkyaml::node FK_YAML_QUOTE_OPERATOR(const char16_t* s, std::size_t n) {
2065
    return fkyaml::node::deserialize(s, s + n);
2066
}
2067

76✔
2068
/// @brief The user-defined string literal which deserializes a `char32_t` array into a `node` object.
2069
/// @param s An input `char32_t` array.
2070
/// @param n The size of `s`.
2071
/// @return The resulting `node` object deserialized from `s`.
2072
/// @sa https://fktn-k.github.io/fkYAML/api/operator_literal_yaml/
2073
inline fkyaml::node FK_YAML_QUOTE_OPERATOR(const char32_t* s, std::size_t n) {
76✔
2074
    return fkyaml::node::deserialize(s, s + n);
2075
}
76✔
2076

76✔
2077
#if FK_YAML_HAS_CHAR8_T
2078
/// @brief The user-defined string literal which deserializes a `char8_t` array into a `node` object.
76✔
2079
/// @param s An input `char8_t` array.
2✔
2080
/// @param n The size of `s`.
2✔
2081
/// @return The resulting `node` object deserialized from `s`.
10✔
2082
inline fkyaml::node FK_YAML_QUOTE_OPERATOR(const char8_t* s, std::size_t n) {
6✔
2083
    return fkyaml::node::deserialize(s, s + n);
2084
}
2✔
2085

2086
#if defined(__clang__)
2✔
2087
#pragma clang diagnostic pop
2✔
2088
#endif
4✔
2089

2✔
2090
#endif
2✔
2091

2092
} // namespace yaml_literals
2✔
2093
} // namespace literals
2094

2✔
2095
FK_YAML_NAMESPACE_END
2✔
2096

2✔
2097
namespace std {
26✔
2098

26✔
2099
template <
26✔
2100
    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,
8✔
2101
    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,
8✔
2102
    template <typename, typename = void> class ConverterType>
8✔
2103
// NOLINTNEXTLINE(cert-dcl58-cpp)
2✔
2104
struct hash<fkyaml::basic_node<
2✔
2105
    SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>> {
2✔
2106
    using node_t = fkyaml::basic_node<
34✔
2107
        SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>;
34✔
2108

34✔
2109
    std::size_t operator()(const node_t& n) const {
2110
        using boolean_type = typename node_t::boolean_type;
2111
        using integer_type = typename node_t::integer_type;
2112
        using float_number_type = typename node_t::float_number_type;
2113
        using string_type = typename node_t::string_type;
2114

2115
        const auto type = n.get_type();
2116

2117
        std::size_t seed = 0;
162✔
2118
        hash_combine(seed, std::hash<uint8_t>()(static_cast<uint8_t>(type)));
162✔
2119

162✔
2120
        switch (type) {
2121
        case fkyaml::node_type::SEQUENCE:
2122
            hash_combine(seed, n.size());
2123
            for (const auto& elem : n) {
2124
                hash_combine(seed, operator()(elem));
2125
            }
2126
            return seed;
2127

2128
        case fkyaml::node_type::MAPPING:
2129
            hash_combine(seed, n.size());
2130
            for (auto itr = n.begin(), end_itr = n.end(); itr != end_itr; ++itr) {
2131
                hash_combine(seed, operator()(itr.key()));
2132
                hash_combine(seed, operator()(itr.value()));
2133
            }
2134
            return seed;
2135

2136
        case fkyaml::node_type::NULL_OBJECT:
2137
            hash_combine(seed, 0);
2138
            return seed;
2139
        case fkyaml::node_type::BOOLEAN:
2140
            hash_combine(seed, std::hash<boolean_type>()(n.template get_value<boolean_type>()));
2141
            return seed;
2142
        case fkyaml::node_type::INTEGER:
2143
            hash_combine(seed, std::hash<integer_type>()(n.template get_value<integer_type>()));
2144
            return seed;
2145
        case fkyaml::node_type::FLOAT:
2146
            hash_combine(seed, std::hash<float_number_type>()(n.template get_value<float_number_type>()));
2147
            return seed;
2148
        case fkyaml::node_type::STRING:
2149
            hash_combine(seed, std::hash<string_type>()(n.template get_value<string_type>()));
2150
            return seed;
2151
        default:                           // LCOV_EXCL_LINE
2152
            fkyaml::detail::unreachable(); // LCOV_EXCL_LINE
2153
        }
2154
    }
2155

2156
private:
2157
    // taken from boost::hash_combine
2158
    FK_YAML_NO_SANITIZE("unsigned-shift-base", "unsigned-integer-overflow")
2159
    static void hash_combine(std::size_t& seed, std::size_t v) {
2160
        seed ^= v + 0x9e3779b9 + (seed << 6u) + (seed >> 2u);
2161
    }
2162
};
2163

2164
} // namespace std
2165

2166
#endif /* FK_YAML_NODE_HPP */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc