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

fktn-k / fkYAML / 29530625244

16 Jul 2026 08:05PM UTC coverage: 99.833% (-0.2%) from 100.0%
29530625244

Pull #530

github

web-flow
Merge 76bc4e861 into 979a13044
Pull Request #530: Add tests and documentation for `basic_node::erase`

1420 of 1428 branches covered (99.44%)

Branch coverage included in aggregate %.

13 of 13 new or added lines in 1 file covered. (100.0%)

3 existing lines in 2 files now uncovered.

5173 of 5176 relevant lines covered (99.94%)

403.16 hits per line

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

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

9
#ifndef FK_YAML_NODE_HPP
10
#define FK_YAML_NODE_HPP
11

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

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

45
FK_YAML_NAMESPACE_BEGIN
46

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1,205✔
392
        if (is_mapping) {
216✔
393
            m_attrs = detail::node_attr_bits::map_bit;
216✔
394
            m_value.p_map = detail::create_object<mapping_type>();
395

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

989✔
407
            auto& seq = *m_value.p_seq;
989✔
408
            seq.reserve(std::distance(init.begin(), init.end()));
3,074✔
409
            for (auto& elem_ref : init) {
2,085✔
410
                seq.emplace_back(std::move(elem_ref.release()));
411
            }
UNCOV
412
        }
×
413
    } // LCOV_EXCL_LINE
414

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

22,740✔
432
        m_attrs = detail::node_attr_bits::default_bits;
22,740✔
433
        mp_meta.reset();
22,740✔
434
    }
435

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1,321✔
619
        basic_node key_node = std::forward<KeyType>(key);
620

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

408✔
631
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
408✔
632
        return act_node.m_value.p_map->operator[](std::move(key_node));
1,321✔
633
    }
634

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

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

161✔
653
        basic_node key_node = std::forward<KeyType>(key);
654

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

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

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

60✔
679
        const node_value& node_value = resolve_reference().m_value;
680

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

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

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

9✔
705
        const node_value& node_value = resolve_reference().m_value;
706

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

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

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

4,272✔
728
        const detail::node_attr_t lhs_val_bit = lhs.m_attrs & detail::node_attr_mask::value;
4,272✔
729
        if (lhs_val_bit != (act_rhs.m_attrs & detail::node_attr_mask::value)) {
565✔
730
            return false;
731
        }
732

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

3,707✔
763
        return ret;
764
    }
765

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

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

1,751✔
783
        const basic_node& lhs = resolve_reference();
1,751✔
784
        const basic_node& act_rhs = rhs.resolve_reference();
785

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

1,751✔
789
        if (lhs_val_bit < rhs_val_bit) {
268✔
790
            return true;
791
        }
792

1,483✔
793
        if (lhs_val_bit != rhs_val_bit) {
194✔
794
            return false;
795
        }
796

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

1,289✔
825
        return ret;
826
    }
827

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

12✔
1002
        return false;
1003
    }
1004

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

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

18✔
1023
        basic_node node_key = std::forward<KeyType>(key);
1024

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

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

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

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

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

582✔
1067
        basic_node node_key = std::forward<KeyType>(key);
1068

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4✔
1232
        auto p_meta = mp_meta;
1233

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

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

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

261✔
1260
        auto p_meta = mp_meta;
1261

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

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

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

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

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

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

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

2,518✔
1332
        auto ret = ValueType();
2,517✔
1333
        resolve_reference().get_value_impl(ret);
2,443✔
1334
        return ret;
42✔
1335
    }
1336

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

114✔
1621
        swap(m_prop.tag, rhs.m_prop.tag);
114✔
1622
        swap(m_prop.anchor, rhs.m_prop.anchor);
56✔
1623
    }
56✔
1624

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

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

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

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

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

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

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

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

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

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

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

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

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

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

6✔
1789
    /// @brief Erase a mapping entry by key.
1790
    /// @tparam KeyType A type for the input key (any type convertible to node).
1791
    /// @param key A key identifying the mapping entry to erase.
4✔
1792
    /// @return true if an entry was found and erased, false otherwise.
6✔
1793
    template <typename KeyType>
5✔
1794
    bool erase(KeyType&& key) {
3✔
1795
        basic_node key_node = std::forward<KeyType>(key);
3✔
1796
        basic_node& act_node = resolve_reference();
1797
        if FK_YAML_UNLIKELY (!act_node.is_mapping_impl()) {
1798
            throw type_error("erase() cannot be called on a non-mapping node.", get_type());
1✔
1799
        }
10✔
1800

1801
        auto& map = *act_node.m_value.p_map;
1802
        for (auto itr = map.begin(); itr != map.end(); ++itr) {
1803
            if (itr->first == key_node) {
1804
                map.erase(itr);
2,961✔
1805
                return true;
2,961✔
1806
            }
108✔
1807
        }
108✔
1808
        return false;
108✔
1809
    }
1810

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

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

120✔
1834
    bool is_sequence_impl() const noexcept {
1835
        return m_attrs & detail::node_attr_bits::seq_bit;
1836
    }
591✔
1837

591✔
1838
    bool is_mapping_impl() const noexcept {
1839
        return m_attrs & detail::node_attr_bits::map_bit;
1840
    }
3,811✔
1841

3,811✔
1842
    bool is_null_impl() const noexcept {
1843
        return m_attrs & detail::node_attr_bits::null_bit;
1844
    }
1,955✔
1845

1846
    bool is_boolean_impl() const noexcept {
1847
        return m_attrs & detail::node_attr_bits::bool_bit;
1,955✔
1848
    }
1849

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

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

2,626✔
1860
    bool is_float_number_impl() const noexcept {
1861
        return m_attrs & detail::node_attr_bits::float_bit;
1862
    }
1863

1864
    bool is_string_impl() const noexcept {
2,597✔
1865
        return m_attrs & detail::node_attr_bits::string_bit;
1866
    }
2,597✔
1867

2,519✔
1868
    bool is_scalar_impl() const noexcept {
1869
        return m_attrs & detail::node_attr_bits::scalar_bits;
1870
    }
124✔
1871

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2085
#if defined(__clang__)
2086
#pragma clang diagnostic pop
2087
#endif
2088

2089
#endif
2090

2091
} // namespace yaml_literals
2092
} // namespace literals
2093

2094
FK_YAML_NAMESPACE_END
2095

2096
namespace std {
2097

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

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

6✔
2114
        const auto type = n.get_type();
2115

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

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

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

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

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

2163
} // namespace std
2164

2165
#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