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

fktn-k / fkYAML / 28737574442

05 Jul 2026 10:22AM UTC coverage: 99.969% (-0.03%) from 100.0%
28737574442

Pull #513

github

web-flow
Merge 82c57e140 into a3a096bc5
Pull Request #513: Support unsigned 64-bit integers (uint64_t) exceeding INT64_MAX (#501)

1393 of 1394 branches covered (99.93%)

Branch coverage included in aggregate %.

35 of 36 new or added lines in 4 files covered. (97.22%)

5129 of 5130 relevant lines covered (99.98%)

401.7 hits per line

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

99.79
/include/fkYAML/node.hpp
1
//  _______   __ __   __  _____   __  __  __
2
// |   __| |_/  |  \_/  |/  _  \ /  \/  \|  |     fkYAML: A C++ header-only YAML library
3
// |   __|  _  < \_   _/|  ___  |    _   |  |___  version 0.4.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,480✔
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) {
16,805✔
207
            switch (value_type_bit) {
16,805✔
208
            case detail::node_attr_bits::seq_bit:
1,851✔
209
                p_seq->clear();
1,851✔
210
                detail::destroy_object<sequence_type>(p_seq);
1,851✔
211
                p_seq = nullptr;
1,851✔
212
                break;
1,851✔
213
            case detail::node_attr_bits::map_bit:
921✔
214
                p_map->clear();
921✔
215
                detail::destroy_object<mapping_type>(p_map);
921✔
216
                p_map = nullptr;
921✔
217
                break;
921✔
218
            case detail::node_attr_bits::string_bit:
3,075✔
219
                detail::destroy_object<string_type>(p_str);
3,075✔
220
                p_str = nullptr;
3,075✔
221
                break;
3,075✔
222
            default:
10,958✔
223
                break;
10,958✔
224
            }
225
        }
16,805✔
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,610✔
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,540✔
263
        : m_attrs(rhs.m_attrs),
3,540✔
264
          mp_meta(rhs.mp_meta),
3,540✔
265
          m_prop(rhs.m_prop) {
3,540✔
266
        if FK_YAML_LIKELY (!has_anchor_name()) {
3,540✔
267
            switch (m_attrs & detail::node_attr_mask::value) {
3,313✔
268
            case detail::node_attr_bits::seq_bit:
592✔
269
                m_value.p_seq = detail::create_object<sequence_type>(*(rhs.m_value.p_seq));
592✔
270
                break;
592✔
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:
435✔
275
                m_value.p_map = nullptr;
435✔
276
                break;
435✔
277
            case detail::node_attr_bits::bool_bit:
564✔
278
                m_value.boolean = rhs.m_value.boolean;
564✔
279
                break;
564✔
280
            case detail::node_attr_bits::int_bit:
518✔
281
                m_value.integer = rhs.m_value.integer;
518✔
282
                break;
518✔
283
            case detail::node_attr_bits::float_bit:
229✔
284
                m_value.float_val = rhs.m_value.float_val;
229✔
285
                break;
229✔
286
            case detail::node_attr_bits::string_bit:
729✔
287
                m_value.p_str = detail::create_object<string_type>(*(rhs.m_value.p_str));
729✔
288
                break;
729✔
289
            default:                   // LCOV_EXCL_LINE
290
                detail::unreachable(); // LCOV_EXCL_LINE
291
            }
292
        }
293
    }
3,540✔
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,043✔
299
        : m_attrs(rhs.m_attrs),
9,043✔
300
          mp_meta(std::move(rhs.mp_meta)),
9,043✔
301
          m_prop(std::move(rhs.m_prop)) {
9,043✔
302
        if FK_YAML_LIKELY (!has_anchor_name()) {
9,043✔
303
            switch (m_attrs & detail::node_attr_mask::value) {
9,001✔
304
            case detail::node_attr_bits::seq_bit:
1,268✔
305
                FK_YAML_ASSERT(rhs.m_value.p_seq != nullptr);
1,268✔
306
                m_value.p_seq = rhs.m_value.p_seq;
1,268✔
307
                rhs.m_value.p_seq = nullptr;
1,268✔
308
                break;
1,268✔
309
            case detail::node_attr_bits::map_bit:
857✔
310
                FK_YAML_ASSERT(rhs.m_value.p_map != nullptr);
857✔
311
                m_value.p_map = rhs.m_value.p_map;
857✔
312
                rhs.m_value.p_map = nullptr;
857✔
313
                break;
857✔
314
            case detail::node_attr_bits::null_bit:
1,026✔
315
                FK_YAML_ASSERT(rhs.m_value.p_map == nullptr);
1,026✔
316
                m_value.p_map = rhs.m_value.p_map;
1,026✔
317
                break;
1,026✔
318
            case detail::node_attr_bits::bool_bit:
1,494✔
319
                m_value.boolean = rhs.m_value.boolean;
1,494✔
320
                rhs.m_value.boolean = static_cast<boolean_type>(false);
1,494✔
321
                break;
1,494✔
322
            case detail::node_attr_bits::int_bit:
1,388✔
323
                m_value.integer = rhs.m_value.integer;
1,388✔
324
                rhs.m_value.integer = static_cast<integer_type>(0);
1,388✔
325
                break;
1,388✔
326
            case detail::node_attr_bits::float_bit:
419✔
327
                m_value.float_val = rhs.m_value.float_val;
419✔
328
                rhs.m_value.float_val = static_cast<float_number_type>(0.0);
419✔
329
                break;
419✔
330
            case detail::node_attr_bits::string_bit:
2,549✔
331
                FK_YAML_ASSERT(rhs.m_value.p_str != nullptr);
2,549✔
332
                m_value.p_str = rhs.m_value.p_str;
2,549✔
333
                rhs.m_value.p_str = nullptr;
2,549✔
334
                break;
2,549✔
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,043✔
341
        rhs.m_value.p_map = nullptr;
9,043✔
342
    }
9,043✔
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,083✔
357
        noexcept(ConverterType<U, void>::to_node(std::declval<basic_node&>(), std::declval<CompatibleType>()))) {
6,083✔
358
        ConverterType<U, void>::to_node(*this, std::forward<CompatibleType>(val));
6,083✔
359
    }
6,083✔
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,204✔
376
        bool is_mapping =
377
            std::all_of(init.begin(), init.end(), [](const detail::node_ref_storage<basic_node>& node_ref) {
1,204✔
378
                // Do not use is_sequence_impl() since node_ref may be an anchor or alias.
379
                return node_ref->is_sequence() && node_ref->size() == 2;
1,389✔
380
            });
381

382
        if (is_mapping) {
1,204✔
383
            m_attrs = detail::node_attr_bits::map_bit;
216✔
384
            m_value.p_map = detail::create_object<mapping_type>();
216✔
385

386
            auto& map = *m_value.p_map;
216✔
387
            for (auto& elem_ref : init) {
611✔
388
                auto elem = elem_ref.release();
395✔
389
                auto& seq = *elem.m_value.p_seq;
395✔
390
                map.emplace(std::move(seq[0]), std::move(seq[1]));
395✔
391
            }
392
        }
393
        else {
394
            m_attrs = detail::node_attr_bits::seq_bit;
988✔
395
            m_value.p_seq = detail::create_object<sequence_type>();
988✔
396

397
            auto& seq = *m_value.p_seq;
988✔
398
            seq.reserve(std::distance(init.begin(), init.end()));
988✔
399
            for (auto& elem_ref : init) {
3,072✔
400
                seq.emplace_back(std::move(elem_ref.release()));
2,084✔
401
            }
402
        }
403
    }
1,204✔
404

405
    /// @brief Destroy the basic_node object and its value storage.
406
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/destructor/
407
    ~basic_node() noexcept // NOLINT(bugprone-exception-escape)
22,509✔
408
    {
409
        if (m_attrs & detail::node_attr_mask::anchoring) {
22,509✔
410
            if (m_attrs & detail::node_attr_bits::anchor_bit) {
496✔
411
                auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;
261✔
412
                std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));
261✔
413
                itr->second.m_value.destroy(itr->second.m_attrs & detail::node_attr_mask::value);
261✔
414
                itr->second.m_attrs = detail::node_attr_bits::default_bits;
261✔
415
                itr->second.mp_meta.reset();
261✔
416
            }
417
        }
418
        else if ((m_attrs & detail::node_attr_bits::null_bit) == 0) {
22,013✔
419
            m_value.destroy(m_attrs & detail::node_attr_mask::value);
10,445✔
420
        }
421

422
        m_attrs = detail::node_attr_bits::default_bits;
22,509✔
423
        mp_meta.reset();
22,509✔
424
    }
22,509✔
425

426
public:
427
    /// @brief Deserialize the first YAML document in the input into a basic_node object.
428
    /// @tparam InputType Type of a compatible input.
429
    /// @param[in] input An input source in the YAML format.
430
    /// @return The resulting basic_node object deserialized from the input source.
431
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/deserialize/
432
    template <typename InputType>
433
    static basic_node deserialize(InputType&& input) {
61✔
434
        return deserializer_type().deserialize(detail::input_adapter(std::forward<InputType>(input)));
62✔
435
    }
436

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

452
    /// @brief Deserialize all YAML documents in the input into basic_node objects.
453
    /// @tparam InputType Type of a compatible input.
454
    /// @param[in] input An input source in the YAML format.
455
    /// @return The resulting basic_node objects deserialized from the input.
456
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/deserialize_docs/
457
    template <typename InputType>
458
    static std::vector<basic_node> deserialize_docs(InputType&& input) {
5✔
459
        return deserializer_type().deserialize_docs(detail::input_adapter(std::forward<InputType>(input)));
5✔
460
    }
461

462
    /// @brief Deserialize all YAML documents in the input ranged by the iterators into basic_node objects.
463
    /// @tparam ItrType Type of a compatible iterator.
464
    /// @param[in] begin An iterator to the first element of an input sequence.
465
    /// @param[in] end An iterator to the past-the-last element of an input sequence.
466
    /// @return The resulting basic_node objects deserialized from the pair of iterators.
467
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/deserialize_docs/
468
    template <typename ItrType>
469
    static std::vector<basic_node> deserialize_docs(ItrType&& begin, ItrType&& end) {
4✔
470
        return deserializer_type().deserialize_docs(
8✔
471
            detail::input_adapter(std::forward<ItrType>(begin), std::forward<ItrType>(end)));
8✔
472
    }
473

474
    /// @brief Serialize a basic_node object into a string.
475
    /// @param[in] node A basic_node object to be serialized.
476
    /// @return The resulting string object from the serialization of the given node.
477
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/serialize/
478
    static std::string serialize(const basic_node& node) {
30✔
479
        return serializer_type().serialize(node);
60✔
480
    }
481

482
    /// @brief Serialize basic_node objects into a string.
483
    /// @param docs basic_node objects to be serialized.
484
    /// @return The resulting string object from the serialization of the given nodes.
485
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/serialize_docs/
486
    static std::string serialize_docs(const std::vector<basic_node>& docs) {
1✔
487
        return serializer_type().serialize_docs(docs);
2✔
488
    }
489

490
    /// @brief A factory method for sequence basic_node objects without sequence_type objects.
491
    /// @return A YAML sequence node.
492
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/sequence/
493
    static basic_node sequence() {
110✔
494
        basic_node node;
110✔
495
        node.m_attrs = detail::node_attr_bits::seq_bit;
110✔
496
        node.m_value.p_seq = detail::create_object<sequence_type>();
110✔
497
        return node;
110✔
498
    } // LCOV_EXCL_LINE
499

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

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

522
    /// @brief A factory method for mapping basic_node objects without mapping_type objects.
523
    /// @return A YAML mapping node.
524
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/mapping/
525
    static basic_node mapping() {
407✔
526
        basic_node node;
407✔
527
        node.m_attrs = detail::node_attr_bits::map_bit;
407✔
528
        node.m_value.p_map = detail::create_object<mapping_type>();
407✔
529
        return node;
407✔
530
    } // LCOV_EXCL_LINE
531

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

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

554
    /// @brief A factory method for alias basic_node objects referencing the given anchor basic_node object.
555
    /// @note The given anchor basic_node must have a non-empty anchor name.
556
    /// @param[in] anchor_node A basic_node object with an anchor name.
557
    /// @return An alias YAML node created from the given anchor node.
558
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/alias_of/
559
    static basic_node alias_of(const basic_node& anchor_node) {
228✔
560
        constexpr detail::node_attr_t anchor_bit = detail::node_attr_bits::anchor_bit;
228✔
561

562
        if FK_YAML_UNLIKELY (!anchor_node.has_anchor_name() || !(anchor_node.m_attrs & anchor_bit)) {
228✔
563
            throw fkyaml::exception("Cannot create an alias without anchor name.");
3✔
564
        }
565

566
        basic_node node = anchor_node;
225✔
567
        node.m_attrs &= ~detail::node_attr_mask::anchoring;
225✔
568
        node.m_attrs |= detail::node_attr_bits::alias_bit;
225✔
569
        return node;
225✔
570
    } // LCOV_EXCL_LINE
571

572
public:
573
    /// @brief A copy assignment operator of the basic_node class.
574
    /// @param[in] rhs A lvalue basic_node object to be copied with.
575
    /// @return Reference to this basic_node object.
576
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator=/
577
    basic_node& operator=(const basic_node& rhs) noexcept {
126✔
578
        basic_node(rhs).swap(*this);
126✔
579
        return *this;
126✔
580
    }
581

582
    /// @brief A move assignment operator of the basic_node class.
583
    /// @param[in] rhs A rvalue basic_node object to be moved from.
584
    /// @return Reference to this basic_node object.
585
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator=/
586
    basic_node& operator=(basic_node&& rhs) noexcept {
1,291✔
587
        basic_node(std::move(rhs)).swap(*this);
1,291✔
588
        return *this;
1,291✔
589
    }
590

591
    /// @brief A subscript operator of the basic_node class with a key of a compatible type with basic_node.
592
    /// @tparam KeyType A key type compatible with basic_node
593
    /// @param key A key to the target value in a sequence/mapping node.
594
    /// @return The value associated with the given key, or a default basic_node object associated with the given key.
595
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator[]/
596
    template <
597
        typename KeyType, detail::enable_if_t<
598
                              detail::conjunction<
599
                                  detail::negation<detail::is_basic_node<KeyType>>,
600
                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,
601
                              int> = 0>
602
    basic_node& operator[](KeyType&& key) {
1,323✔
603
        basic_node& act_node = resolve_reference();
1,323✔
604

605
        if FK_YAML_UNLIKELY (act_node.is_scalar_impl()) {
1,323✔
606
            throw fkyaml::type_error("operator[] is unavailable for a scalar node.", get_type());
5✔
607
        }
608

609
        basic_node key_node = std::forward<KeyType>(key);
1,318✔
610

611
        if (act_node.is_sequence_impl()) {
1,318✔
612
            // Do not use is_integer_impl() since n may be an anchor or alias.
613
            if FK_YAML_UNLIKELY (!key_node.is_integer()) {
913✔
614
                throw fkyaml::type_error(
6✔
615
                    "An argument of operator[] for sequence nodes must be an integer.", get_type());
616
            }
617
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
907✔
618
            return act_node.m_value.p_seq->operator[](key_node.get_value<int>());
907✔
619
        }
620

621
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
405✔
622
        return act_node.m_value.p_map->operator[](std::move(key_node));
405✔
623
    }
1,318✔
624

625
    /// @brief A subscript operator of the basic_node class with a key of a compatible type with basic_node.
626
    /// @tparam KeyType A key type compatible with basic_node
627
    /// @param key A key to the target value in a sequence/mapping node.
628
    /// @return The value associated with the given key, or a default basic_node object associated with the given key.
629
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator[]/
630
    template <
631
        typename KeyType, detail::enable_if_t<
632
                              detail::conjunction<
633
                                  detail::negation<detail::is_basic_node<KeyType>>,
634
                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,
635
                              int> = 0>
636
    const basic_node& operator[](KeyType&& key) const {
165✔
637
        const basic_node& act_node = resolve_reference();
165✔
638

639
        if FK_YAML_UNLIKELY (act_node.is_scalar_impl()) {
165✔
640
            throw fkyaml::type_error("operator[] is unavailable for a scalar node.", get_type());
6✔
641
        }
642

643
        basic_node key_node = std::forward<KeyType>(key);
159✔
644

645
        if (act_node.is_sequence_impl()) {
159✔
646
            if FK_YAML_UNLIKELY (!key_node.is_integer_impl()) {
115✔
647
                throw fkyaml::type_error(
6✔
648
                    "An argument of operator[] for sequence nodes must be an integer.", get_type());
649
            }
650
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
109✔
651
            return act_node.m_value.p_seq->operator[](key_node.get_value<int>());
109✔
652
        }
653

654
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
44✔
655
        return act_node.m_value.p_map->operator[](std::move(key_node));
44✔
656
    }
159✔
657

658
    /// @brief A subscript operator of the basic_node class with a basic_node key object.
659
    /// @tparam KeyType A key type which is a kind of the basic_node template class.
660
    /// @param key A key to the target value in a sequence/mapping node.
661
    /// @return The value associated with the given key, or a default basic_node object associated with the given key.
662
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator[]/
663
    template <typename KeyType, detail::enable_if_t<detail::is_basic_node<KeyType>::value, int> = 0>
664
    basic_node& operator[](KeyType&& key) {
65✔
665
        if FK_YAML_UNLIKELY (is_scalar()) {
65✔
666
            throw fkyaml::type_error("operator[] is unavailable for a scalar node.", get_type());
5✔
667
        }
668

669
        const node_value& node_value = resolve_reference().m_value;
60✔
670

671
        if (is_sequence()) {
60✔
672
            if FK_YAML_UNLIKELY (!key.is_integer()) {
7✔
673
                throw fkyaml::type_error(
6✔
674
                    "An argument of operator[] for sequence nodes must be an integer.", get_type());
675
            }
676
            FK_YAML_ASSERT(node_value.p_seq != nullptr);
1✔
677
            return node_value.p_seq->operator[](std::forward<KeyType>(key).template get_value<int>());
1✔
678
        }
679

680
        FK_YAML_ASSERT(node_value.p_map != nullptr);
53✔
681
        return node_value.p_map->operator[](std::forward<KeyType>(key));
53✔
682
    }
683

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

695
        const node_value& node_value = resolve_reference().m_value;
9✔
696

697
        if (is_sequence()) {
9✔
698
            if FK_YAML_UNLIKELY (!key.is_integer()) {
7✔
699
                throw fkyaml::type_error(
6✔
700
                    "An argument of operator[] for sequence nodes must be an integer.", get_type());
701
            }
702
            FK_YAML_ASSERT(node_value.p_seq != nullptr);
1✔
703
            return node_value.p_seq->operator[](key.template get_value<int>());
1✔
704
        }
705

706
        FK_YAML_ASSERT(node_value.p_map != nullptr);
2✔
707
        return node_value.p_map->operator[](std::forward<KeyType>(key));
2✔
708
    }
709

710
    /// @brief An equal-to operator of the basic_node class.
711
    /// @param rhs A basic_node object to be compared with this basic_node object.
712
    /// @return true if both types and values are equal, false otherwise.
713
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_eq/
714
    bool operator==(const basic_node& rhs) const noexcept {
4,246✔
715
        const basic_node& lhs = resolve_reference();
4,246✔
716
        const basic_node& act_rhs = rhs.resolve_reference();
4,246✔
717

718
        const detail::node_attr_t lhs_val_bit = lhs.m_attrs & detail::node_attr_mask::value;
4,246✔
719
        if (lhs_val_bit != (act_rhs.m_attrs & detail::node_attr_mask::value)) {
4,246✔
720
            return false;
565✔
721
        }
722

723
        bool ret = false;
3,681✔
724
        switch (lhs_val_bit) {
3,681✔
725
        case detail::node_attr_bits::seq_bit:
80✔
726
            ret = (*(lhs.m_value.p_seq) == *(act_rhs.m_value.p_seq));
80✔
727
            break;
80✔
728
        case detail::node_attr_bits::map_bit:
146✔
729
            ret = (*(lhs.m_value.p_map) == *(act_rhs.m_value.p_map));
146✔
730
            break;
146✔
731
        case detail::node_attr_bits::null_bit:
57✔
732
            // Always true for comparisons between null nodes.
733
            ret = true;
57✔
734
            break;
57✔
735
        case detail::node_attr_bits::bool_bit:
223✔
736
            ret = (lhs.m_value.boolean == act_rhs.m_value.boolean);
223✔
737
            break;
223✔
738
        case detail::node_attr_bits::int_bit:
174✔
739
            ret = (lhs.m_value.integer == act_rhs.m_value.integer);
174✔
740
            break;
174✔
741
        case detail::node_attr_bits::float_bit:
27✔
742
            ret =
27✔
743
                (std::abs(lhs.m_value.float_val - act_rhs.m_value.float_val) <
27✔
744
                 std::numeric_limits<float_number_type>::epsilon());
27✔
745
            break;
27✔
746
        case detail::node_attr_bits::string_bit:
2,974✔
747
            ret = (*(lhs.m_value.p_str) == *(act_rhs.m_value.p_str));
2,974✔
748
            break;
2,974✔
749
        default:                   // LCOV_EXCL_LINE
750
            detail::unreachable(); // LCOV_EXCL_LINE
751
        }
752

753
        return ret;
3,681✔
754
    }
755

756
    /// @brief A not-equal-to operator of the basic_node class.
757
    /// @param rhs A basic_node object to be compared with this basic_node object.
758
    /// @return true if either types or values are different, false otherwise.
759
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_ne/
760
    bool operator!=(const basic_node& rhs) const noexcept {
55✔
761
        return !operator==(rhs);
55✔
762
    }
763

764
    /// @brief A less-than operator of the basic_node class.
765
    /// @param rhs A basic_node object to be compared with this basic_node object.
766
    /// @return true this basic_node object is less than `rhs`.
767
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_lt/
768
    bool operator<(const basic_node& rhs) const noexcept {
3,700✔
769
        if (operator==(rhs)) {
3,700✔
770
            return false;
1,958✔
771
        }
772

773
        const basic_node& lhs = resolve_reference();
1,742✔
774
        const basic_node& act_rhs = rhs.resolve_reference();
1,742✔
775

776
        const detail::node_attr_t lhs_val_bit = lhs.m_attrs & detail::node_attr_mask::value;
1,742✔
777
        const detail::node_attr_t rhs_val_bit = act_rhs.m_attrs & detail::node_attr_mask::value;
1,742✔
778

779
        if (lhs_val_bit < rhs_val_bit) {
1,742✔
780
            return true;
268✔
781
        }
782

783
        if (lhs_val_bit != rhs_val_bit) {
1,474✔
784
            return false;
194✔
785
        }
786

787
        bool ret = false;
1,280✔
788
        switch (lhs_val_bit) {
1,280✔
789
        case detail::node_attr_bits::seq_bit:
21✔
790
            ret = (*(lhs.m_value.p_seq) < *(act_rhs.m_value.p_seq));
21✔
791
            break;
21✔
792
        case detail::node_attr_bits::map_bit:
35✔
793
            ret = (*(lhs.m_value.p_map) < *(act_rhs.m_value.p_map));
35✔
794
            break;
35✔
795
        case detail::node_attr_bits::null_bit: // LCOV_EXCL_LINE
796
            // Will not come here since null nodes are always the same.
797
            detail::unreachable(); // LCOV_EXCL_LINE
798
        case detail::node_attr_bits::bool_bit:
46✔
799
            // false < true
800
            ret = (!lhs.m_value.boolean && act_rhs.m_value.boolean);
46✔
801
            break;
46✔
802
        case detail::node_attr_bits::int_bit:
26✔
803
            ret = (lhs.m_value.integer < act_rhs.m_value.integer);
26✔
804
            break;
26✔
805
        case detail::node_attr_bits::float_bit:
12✔
806
            ret = (lhs.m_value.float_val < act_rhs.m_value.float_val);
12✔
807
            break;
12✔
808
        case detail::node_attr_bits::string_bit:
1,140✔
809
            ret = (*(lhs.m_value.p_str) < *(act_rhs.m_value.p_str));
1,140✔
810
            break;
1,140✔
811
        default:                   // LCOV_EXCL_LINE
812
            detail::unreachable(); // LCOV_EXCL_LINE
813
        }
814

815
        return ret;
1,280✔
816
    }
817

818
    /// @brief A less-than-or-equal-to operator of the basic_node class.
819
    /// @param rhs A basic_node object to be compared with this basic_node object.
820
    /// @return true this basic_node object is less than or equal to `rhs`.
821
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_le/
822
    bool operator<=(const basic_node& rhs) const noexcept {
122✔
823
        return !rhs.operator<(*this);
122✔
824
    }
825

826
    /// @brief A greater-than operator of the basic_node class.
827
    /// @param rhs A basic_node object to be compared with this basic_node object.
828
    /// @return true this basic_node object is greater than `rhs`.
829
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_gt/
830
    bool operator>(const basic_node& rhs) const noexcept {
61✔
831
        return !operator<=(rhs);
61✔
832
    }
833

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

842
public:
843
    /// @brief Returns the type of the current basic_node value.
844
    /// @return The type of the YAML node value.
845
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_type/
846
    node_type get_type() const noexcept {
3,147✔
847
        return detail::node_attr_bits::to_node_type(resolve_reference().m_attrs);
3,147✔
848
    }
849

850
    /// @brief Returns the type of the current basic_node value.
851
    /// @deprecated Use get_type() function. (since 0.3.12)
852
    /// @return The type of the YAML node value.
853
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/type/
854
    FK_YAML_DEPRECATED("Since 0.3.12; Use get_type()")
855
    node_t type() const noexcept {
14✔
856
        node_type tmp_type = get_type();
14✔
857
        return detail::convert_from_node_type(tmp_type);
14✔
858
    }
859

860
    /// @brief Tests whether the current basic_node value is of sequence type.
861
    /// @return true if the type is sequence, false otherwise.
862
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_sequence/
863
    bool is_sequence() const noexcept {
2,256✔
864
        return resolve_reference().is_sequence_impl();
2,256✔
865
    }
866

867
    /// @brief Tests whether the current basic_node value is of mapping type.
868
    /// @return true if the type is mapping, false otherwise.
869
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_mapping/
870
    bool is_mapping() const noexcept {
1,267✔
871
        return resolve_reference().is_mapping_impl();
1,267✔
872
    }
873

874
    /// @brief Tests whether the current basic_node value is of null type.
875
    /// @return true if the type is null, false otherwise.
876
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_null/
877
    bool is_null() const noexcept {
120✔
878
        return resolve_reference().is_null_impl();
120✔
879
    }
880

881
    /// @brief Tests whether the current basic_node value is of boolean type.
882
    /// @return true if the type is boolean, false otherwise
883
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_boolean/
884
    bool is_boolean() const noexcept {
197✔
885
        return resolve_reference().is_boolean_impl();
197✔
886
    }
887

888
    /// @brief Tests whether the current basic_node value is of integer type.
889
    /// @return true if the type is integer, false otherwise.
890
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_integer/
891
    bool is_integer() const noexcept {
1,691✔
892
        return resolve_reference().is_integer_impl();
1,691✔
893
    }
894

895
    /// @brief Tests whether the current basic_node value is of float number type.
896
    /// @return true if the type is floating point number, false otherwise.
897
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_float_number/
898
    bool is_float_number() const noexcept {
110✔
899
        return resolve_reference().is_float_number_impl();
110✔
900
    }
901

902
    /// @brief Tests whether the current basic_node value is of string type.
903
    /// @return true if the type is string, false otherwise.
904
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_string/
905
    bool is_string() const noexcept {
481✔
906
        return resolve_reference().is_string_impl();
481✔
907
    }
908

909
    /// @brief Tests whether the current basic_node value is of scalar types.
910
    /// @return true if the type is scalar, false otherwise.
911
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_scalar/
912
    bool is_scalar() const noexcept {
473✔
913
        return resolve_reference().is_scalar_impl();
473✔
914
    }
915

916
    /// @brief Tests whether the current basic_node is an anchor node.
917
    /// @return true if the current basic_node is an anchor node, false otherwise.
918
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_anchor/
919
    bool is_anchor() const noexcept {
479✔
920
        return m_attrs & detail::node_attr_bits::anchor_bit;
479✔
921
    }
922

923
    /// @brief Tests whether the current basic_node is an alias node.
924
    /// @return true if the current basic_node is an alias node, false otherwise.
925
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_alias/
926
    bool is_alias() const noexcept {
105✔
927
        return m_attrs & detail::node_attr_bits::alias_bit;
105✔
928
    }
929

930
    /// @brief Tests whether the current basic_node value (sequence, mapping, string) is empty.
931
    /// @return true if the node value is empty, false otherwise.
932
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/empty/
933
    bool empty() const {
53✔
934
        const basic_node& act_node = resolve_reference();
53✔
935
        switch (act_node.m_attrs & detail::node_attr_mask::value) {
53✔
936
        case detail::node_attr_bits::seq_bit: {
16✔
937
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
16✔
938
            return act_node.m_value.p_seq->empty();
16✔
939
        }
940
        case detail::node_attr_bits::map_bit: {
13✔
941
            FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
13✔
942
            return act_node.m_value.p_map->empty();
13✔
943
        }
944
        case detail::node_attr_bits::string_bit: {
8✔
945
            FK_YAML_ASSERT(act_node.m_value.p_str != nullptr);
8✔
946
            return act_node.m_value.p_str->empty();
8✔
947
        }
948
        default:
16✔
949
            throw fkyaml::type_error("The target node is not of a container type.", get_type());
16✔
950
        }
951
    }
952

953
    /// @brief Returns the size of the current basic_node value (sequence, mapping, string).
954
    /// @return The size of a node value.
955
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/size/
956
    std::size_t size() const {
956✔
957
        const basic_node& act_node = resolve_reference();
956✔
958
        switch (act_node.m_attrs & detail::node_attr_mask::value) {
956✔
959
        case detail::node_attr_bits::seq_bit:
639✔
960
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
639✔
961
            return act_node.m_value.p_seq->size();
639✔
962
        case detail::node_attr_bits::map_bit:
280✔
963
            FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
280✔
964
            return act_node.m_value.p_map->size();
280✔
965
        case detail::node_attr_bits::string_bit:
21✔
966
            FK_YAML_ASSERT(act_node.m_value.p_str != nullptr);
21✔
967
            return act_node.m_value.p_str->size();
21✔
968
        default:
16✔
969
            throw fkyaml::type_error("The target node is not of a container type.", get_type());
16✔
970
        }
971
    }
972

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

992
        return false;
12✔
993
    }
994

995
    /// @brief Get a basic_node object with a key of a compatible type.
996
    /// @tparam KeyType A key type compatible with basic_node
997
    /// @param key A key to the target basic_node object in a sequence/mapping node.
998
    /// @return Reference to the basic_node object associated with the given key.
999
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/at/
1000
    template <
1001
        typename KeyType, detail::enable_if_t<
1002
                              detail::conjunction<
1003
                                  detail::negation<detail::is_basic_node<KeyType>>,
1004
                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,
1005
                              int> = 0>
1006
    basic_node& at(KeyType&& key) {
23✔
1007
        basic_node& act_node = resolve_reference();
23✔
1008

1009
        if FK_YAML_UNLIKELY (act_node.is_scalar_impl()) {
23✔
1010
            throw fkyaml::type_error("at() is unavailable for a scalar node.", get_type());
5✔
1011
        }
1012

1013
        basic_node node_key = std::forward<KeyType>(key);
18✔
1014

1015
        if (act_node.is_sequence_impl()) {
18✔
1016
            if FK_YAML_UNLIKELY (!node_key.is_integer_impl()) {
8✔
1017
                throw fkyaml::type_error("An argument of at() for sequence nodes must be an integer.", get_type());
6✔
1018
            }
1019

1020
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
2✔
1021
            sequence_type& seq = *act_node.m_value.p_seq;
2✔
1022
            int index = std::move(node_key).template get_value<int>();
2✔
1023
            int size = static_cast<int>(seq.size());
2✔
1024
            if FK_YAML_UNLIKELY (index >= size) {
2✔
1025
                throw fkyaml::out_of_range(index);
1✔
1026
            }
1027
            return seq[index];
1✔
1028
        }
1029

1030
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
10✔
1031
        mapping_type& map = *act_node.m_value.p_map;
10✔
1032
        const bool is_found = map.find(node_key) != map.end();
10✔
1033
        if FK_YAML_UNLIKELY (!is_found) {
10✔
1034
            throw fkyaml::out_of_range(serialize(node_key).c_str());
7✔
1035
        }
1036
        return map[std::move(node_key)];
3✔
1037
    }
18✔
1038

1039
    /// @brief Get a basic_node object with a key of a compatible type.
1040
    /// @tparam KeyType A key type compatible with basic_node
1041
    /// @param key A key to the target basic_node object in a sequence/mapping node.
1042
    /// @return Constant reference to the basic_node object associated with the given key.
1043
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/at/
1044
    template <
1045
        typename KeyType, detail::enable_if_t<
1046
                              detail::conjunction<
1047
                                  detail::negation<detail::is_basic_node<KeyType>>,
1048
                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,
1049
                              int> = 0>
1050
    const basic_node& at(KeyType&& key) const {
587✔
1051
        const basic_node& act_node = resolve_reference();
587✔
1052

1053
        if FK_YAML_UNLIKELY (act_node.is_scalar_impl()) {
587✔
1054
            throw fkyaml::type_error("at() is unavailable for a scalar node.", get_type());
5✔
1055
        }
1056

1057
        basic_node node_key = std::forward<KeyType>(key);
582✔
1058

1059
        if (act_node.is_sequence_impl()) {
582✔
1060
            if FK_YAML_UNLIKELY (!node_key.is_integer()) {
541✔
1061
                throw fkyaml::type_error("An argument of at() for sequence nodes must be an integer.", get_type());
6✔
1062
            }
1063

1064
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
535✔
1065
            const sequence_type& seq = *act_node.m_value.p_seq;
535✔
1066
            int index = std::move(node_key).template get_value<int>();
535✔
1067
            int size = static_cast<int>(seq.size());
535✔
1068
            if FK_YAML_UNLIKELY (index >= size) {
535✔
1069
                throw fkyaml::out_of_range(index);
1✔
1070
            }
1071
            return seq[index];
534✔
1072
        }
1073

1074
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
41✔
1075
        const mapping_type& map = *act_node.m_value.p_map;
41✔
1076
        const bool is_found = map.find(node_key) != map.end();
41✔
1077
        if FK_YAML_UNLIKELY (!is_found) {
41✔
1078
            throw fkyaml::out_of_range(serialize(node_key).c_str());
7✔
1079
        }
1080
        return map.at(std::move(node_key));
34✔
1081
    }
582✔
1082

1083
    /// @brief Get a basic_node object with a basic_node key object.
1084
    /// @tparam KeyType A key type which is a kind of the basic_node template class.
1085
    /// @param key A key to the target basic_node object in a sequence/mapping node.
1086
    /// @return Reference to the basic_node object associated with the given key.
1087
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/at/
1088
    template <typename KeyType, detail::enable_if_t<detail::is_basic_node<KeyType>::value, int> = 0>
1089
    basic_node& at(KeyType&& key) {
21✔
1090
        basic_node& act_node = resolve_reference();
21✔
1091
        if FK_YAML_UNLIKELY (act_node.is_scalar_impl()) {
21✔
1092
            throw fkyaml::type_error("at() is unavailable for a scalar node.", get_type());
5✔
1093
        }
1094

1095
        if (act_node.is_sequence_impl()) {
16✔
1096
            if FK_YAML_UNLIKELY (!key.is_integer()) {
7✔
1097
                throw fkyaml::type_error("An argument of at() for sequence nodes must be an integer.", get_type());
5✔
1098
            }
1099

1100
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
2✔
1101
            sequence_type& seq = *act_node.m_value.p_seq;
2✔
1102
            int index = std::forward<KeyType>(key).template get_value<int>();
2✔
1103
            int size = static_cast<int>(seq.size());
2✔
1104
            if FK_YAML_UNLIKELY (index >= size) {
2✔
1105
                throw fkyaml::out_of_range(index);
1✔
1106
            }
1107
            return seq[index];
1✔
1108
        }
1109

1110
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
9✔
1111
        mapping_type& map = *act_node.m_value.p_map;
9✔
1112
        bool is_found = map.find(key) != map.end();
9✔
1113
        if FK_YAML_UNLIKELY (!is_found) {
9✔
1114
            throw fkyaml::out_of_range(serialize(key).c_str());
7✔
1115
        }
1116
        return map[std::forward<KeyType>(key)];
2✔
1117
    }
1118

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

1131
        if (act_node.is_sequence_impl()) {
16✔
1132
            if FK_YAML_UNLIKELY (!key.is_integer()) {
7✔
1133
                throw fkyaml::type_error("An argument of at() for sequence nodes must be an integer.", get_type());
5✔
1134
            }
1135

1136
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
2✔
1137
            const sequence_type& seq = *act_node.m_value.p_seq;
2✔
1138
            int index = std::forward<KeyType>(key).template get_value<int>();
2✔
1139
            int size = static_cast<int>(seq.size());
2✔
1140
            if FK_YAML_UNLIKELY (index >= size) {
2✔
1141
                throw fkyaml::out_of_range(index);
1✔
1142
            }
1143
            return seq[index];
1✔
1144
        }
1145

1146
        FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
9✔
1147
        const mapping_type& map = *act_node.m_value.p_map;
9✔
1148
        bool is_found = map.find(key) != map.end();
9✔
1149
        if FK_YAML_UNLIKELY (!is_found) {
9✔
1150
            throw fkyaml::out_of_range(serialize(key).c_str());
7✔
1151
        }
1152
        return map.at(std::forward<KeyType>(key));
2✔
1153
    }
1154

1155
    /// @brief Get the YAML version for this basic_node object.
1156
    /// @return The YAML version if already set, `yaml_version_type::VERSION_1_2` otherwise.
1157
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_yaml_version_type/
1158
    yaml_version_type get_yaml_version_type() const noexcept {
14✔
1159
        return mp_meta->is_version_specified ? mp_meta->version : yaml_version_type::VERSION_1_2;
14✔
1160
    }
1161

1162
    /// @brief Set the YAML version for this basic_node object.
1163
    /// @param[in] version The target YAML version.
1164
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/set_yaml_version_type/
1165
    void set_yaml_version_type(const yaml_version_type version) noexcept {
6✔
1166
        mp_meta->version = version;
6✔
1167
        mp_meta->is_version_specified = true;
6✔
1168
    }
6✔
1169

1170
    /// @brief Get the YAML version for this basic_node object.
1171
    /// @deprecated Use get_yaml_version_type() function. (since 0.3.12)
1172
    /// @return The YAML version if already set, `yaml_version_t::VER_1_2` otherwise.
1173
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_yaml_version/
1174
    FK_YAML_DEPRECATED("Since 0.3.12; Use get_yaml_version_type()")
1175
    yaml_version_t get_yaml_version() const noexcept {
4✔
1176
        yaml_version_type tmp_type = get_yaml_version_type();
4✔
1177
        return detail::convert_from_yaml_version_type(tmp_type);
4✔
1178
    }
1179

1180
    /// @brief Set the YAML version for this basic_node object.
1181
    /// @deprecated Use set_yaml_version_type(yaml_version_type) function. (since 0.3.12)
1182
    /// @param[in] version The target YAML version.
1183
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/set_yaml_version/
1184
    FK_YAML_DEPRECATED("Since 0.3.12; Use set_yaml_version_type(const yaml_version_type)")
1185
    void set_yaml_version(const yaml_version_t version) noexcept {
3✔
1186
        set_yaml_version_type(detail::convert_to_yaml_version_type(version));
3✔
1187
    }
3✔
1188

1189
    /// @brief Check whether this basic_node object has already had any anchor name.
1190
    /// @return true if ths basic_node has an anchor name, false otherwise.
1191
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/has_anchor_name/
1192
    bool has_anchor_name() const noexcept {
45,421✔
1193
        return (m_attrs & detail::node_attr_mask::anchoring) && !m_prop.anchor.empty();
45,421✔
1194
    }
1195

1196
    /// @brief Get the anchor name associated with this basic_node object.
1197
    /// @note Some anchor name must be set before calling this method. Call has_anchor_name() to see if this basic_node
1198
    /// object has any anchor name.
1199
    /// @return The anchor name associated with the node.
1200
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_anchor_name/
1201
    const std::string& get_anchor_name() const {
51✔
1202
        if FK_YAML_UNLIKELY (!has_anchor_name()) {
51✔
1203
            throw fkyaml::exception("No anchor name has been set.");
1✔
1204
        }
1205
        return m_prop.anchor;
50✔
1206
    }
1207

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

1222
        auto p_meta = mp_meta;
4✔
1223

1224
        basic_node node;
4✔
1225
        node.swap(*this);
4✔
1226
        p_meta->anchor_table.emplace(anchor_name, std::move(node));
4✔
1227

1228
        m_attrs &= ~detail::node_attr_mask::anchoring;
4✔
1229
        m_attrs |= detail::node_attr_bits::anchor_bit;
4✔
1230
        mp_meta = p_meta;
4✔
1231
        const auto offset = static_cast<uint32_t>(mp_meta->anchor_table.count(anchor_name) - 1);
4✔
1232
        detail::node_attr_bits::set_anchor_offset(offset, m_attrs);
4✔
1233
        m_prop.anchor = anchor_name;
4✔
1234
    }
4✔
1235

1236
    /// @brief Add an anchor name to this basic_node object.
1237
    /// @note If this basic_node object has already had any anchor name, the new anchor name will overwrite the old one.
1238
    /// @param[in] anchor_name An anchor name. This should not be empty.
1239
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/add_anchor_name/
1240
    void add_anchor_name(std::string&& anchor_name) {
258✔
1241
        if (is_anchor()) {
258✔
1242
            m_attrs &= ~detail::node_attr_mask::anchoring;
1✔
1243
            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;
1✔
1244
            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));
1✔
1245
            mp_meta.reset();
1✔
1246
            itr->second.swap(*this);
1✔
1247
            mp_meta->anchor_table.erase(itr);
1✔
1248
        }
1249

1250
        auto p_meta = mp_meta;
258✔
1251

1252
        basic_node node;
258✔
1253
        node.swap(*this);
258✔
1254
        p_meta->anchor_table.emplace(anchor_name, std::move(node));
258✔
1255

1256
        m_attrs &= ~detail::node_attr_mask::anchoring;
258✔
1257
        m_attrs |= detail::node_attr_bits::anchor_bit;
258✔
1258
        mp_meta = p_meta;
258✔
1259
        auto offset = static_cast<uint32_t>(mp_meta->anchor_table.count(anchor_name) - 1);
258✔
1260
        detail::node_attr_bits::set_anchor_offset(offset, m_attrs);
258✔
1261
        m_prop.anchor = std::move(anchor_name);
258✔
1262
    }
258✔
1263

1264
    /// @brief Check whether this basic_node object has already had any tag name.
1265
    /// @return true if ths basic_node has a tag name, false otherwise.
1266
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/has_tag_name/
1267
    bool has_tag_name() const noexcept {
306✔
1268
        return !m_prop.tag.empty();
306✔
1269
    }
1270

1271
    /// @brief Get the tag name associated with this basic_node object.
1272
    /// @note Some tag name must be set before calling this method. Call has_tag_name() to see if this basic_node
1273
    /// object has any tag name.
1274
    /// @return The tag name associated with the node. It may be empty.
1275
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_tag_name/
1276
    const std::string& get_tag_name() const {
65✔
1277
        if FK_YAML_UNLIKELY (!has_tag_name()) {
65✔
1278
            throw fkyaml::exception("No tag name has been set.");
1✔
1279
        }
1280
        return m_prop.tag;
64✔
1281
    }
1282

1283
    /// @brief Add a tag name to this basic_node object.
1284
    /// @note If this basic_node object has already had any tag name, the new tag name will overwrite the old one.
1285
    /// @param[in] tag_name A tag name to get associated with this basic_node object.
1286
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/add_tag_name/
1287
    void add_tag_name(const std::string& tag_name) {
2✔
1288
        m_prop.tag = tag_name;
2✔
1289
    }
2✔
1290

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

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

1322
        auto ret = ValueType();
2,516✔
1323
        resolve_reference().get_value_impl(ret);
2,515✔
1324
        return ret;
2,441✔
1325
    }
42✔
1326

1327
    /// @brief Get the node value object converted into a given type. The conversion result is filled into `value_ref`.
1328
    /// @tparam T A compatible value type.
1329
    /// @param value_ref A storage into which the conversion result is filled.
1330
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_value_inplace/
1331
    template <typename T>
1332
    void get_value_inplace(T& value_ref) const
204✔
1333
        noexcept(noexcept(std::declval<const basic_node&>().template get_value_impl<T>(std::declval<T&>()))) {
1334
        resolve_reference().get_value_impl(value_ref);
204✔
1335
    }
201✔
1336

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

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

1378
    /// @brief Explicit reference access to the internally stored YAML node value.
1379
    /// @tparam ReferenceType Reference type to the target YAML node value.
1380
    /// @return Reference to the internally stored YAML node value.
1381
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_value_ref/
1382
    template <typename ReferenceType, detail::enable_if_t<std::is_reference<ReferenceType>::value, int> = 0>
1383
    FK_YAML_DEPRECATED("Since 0.4.3; Use one of as_seq(), as_map(), as_bool(), as_int(), as_float() or as_str()")
1384
    ReferenceType get_value_ref() {
84✔
1385
        return get_value_ref_impl(static_cast<detail::add_pointer_t<ReferenceType>>(nullptr));
84✔
1386
    }
1387

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

1403
    /// @brief Returns reference to the sequence node value.
1404
    /// @throw fkyaml::type_error The node value is not a sequence.
1405
    /// @return Reference to the sequence node value.
1406
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_seq/
1407
    sequence_type& as_seq() {
278✔
1408
        basic_node& act_node = resolve_reference(); // NOLINT(misc-const-correctness)
278✔
1409
        if FK_YAML_LIKELY (act_node.is_sequence_impl()) {
278✔
1410
            return *act_node.m_value.p_seq;
260✔
1411
        }
1412
        throw fkyaml::type_error("The node value is not a sequence.", get_type());
18✔
1413
    }
1414

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

1427
    /// @brief Returns reference to the mapping node value.
1428
    /// @throw fkyaml::type_error The node value is not a mapping.
1429
    /// @return Reference to the mapping node value.
1430
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_map/
1431
    mapping_type& as_map() {
534✔
1432
        basic_node& act_node = resolve_reference(); // NOLINT(misc-const-correctness)
534✔
1433
        if FK_YAML_LIKELY (act_node.is_mapping_impl()) {
534✔
1434
            return *act_node.m_value.p_map;
516✔
1435
        }
1436
        throw fkyaml::type_error("The node value is not a mapping.", get_type());
18✔
1437
    }
1438

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

1451
    /// @brief Returns reference to the boolean node value.
1452
    /// @throw fkyaml::type_error The node value is not a boolean.
1453
    /// @return Reference to the boolean node value.
1454
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_bool/
1455
    boolean_type& as_bool() {
46✔
1456
        basic_node& act_node = resolve_reference();
46✔
1457
        if FK_YAML_LIKELY (act_node.is_boolean_impl()) {
46✔
1458
            return act_node.m_value.boolean;
28✔
1459
        }
1460
        throw fkyaml::type_error("The node value is not a boolean.", get_type());
18✔
1461
    }
1462

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

1475
    /// @brief Checks if the node is an integer that was parsed from a uint64_t value exceeding INT64_MAX.
1476
    /// @return true if the node holds an unsigned integer, false otherwise.
1477
    bool is_uint() const noexcept {
21✔
1478
        return resolve_reference().is_uint_impl();
21✔
1479
    }
1480

1481
    /// @brief Returns the integer node value as an unsigned 64-bit integer.
1482
    /// This is valid both for nodes where integer_type is unsigned and for nodes where a large
1483
    /// positive decimal scalar (> INT64_MAX) was stored with the uint_bit flag set.
1484
    /// @throw fkyaml::type_error if the node is not a compatible integer.
1485
    /// @return The node value as uint64_t.
1486
    uint64_t as_uint() const {
25✔
1487
        const basic_node& act_node = resolve_reference();
25✔
1488
        if FK_YAML_LIKELY (act_node.is_integer_impl()) {
25✔
1489
            // When integer_type is unsigned the stored value IS the uint64_t directly.
1490
            if (std::is_unsigned<integer_type>::value) {
1491
                return static_cast<uint64_t>(act_node.m_value.integer);
1492
            }
1493
            // When integer_type is signed, only uint_bit-marked nodes carry a uint64_t.
1494
            if (act_node.m_attrs & detail::node_attr_bits::uint_bit) {
21✔
1495
                return static_cast<uint64_t>(act_node.m_value.integer);
11✔
1496
            }
1497
            // Signed values in the non-negative range can be returned safely.
1498
            if (act_node.m_value.integer >= static_cast<integer_type>(0)) {
10✔
1499
                return static_cast<uint64_t>(act_node.m_value.integer);
6✔
1500
            }
1501
        }
1502
        throw fkyaml::type_error("The node value cannot be represented as an unsigned integer.", get_type());
8✔
1503
    }
1504

1505
    /// @brief Returns reference to the integer node value.
1506
    /// @throw fkyaml::type_error The node value is not an integer.
1507
    /// @return Reference to the integer node value.
1508
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_int/
1509
    integer_type& as_int() {
49✔
1510
        basic_node& act_node = resolve_reference();
49✔
1511
        if FK_YAML_LIKELY (act_node.is_integer_impl()) {
49✔
1512
            if FK_YAML_UNLIKELY (act_node.is_uint_impl()) {
31✔
1513
                throw fkyaml::type_error(
3✔
1514
                    "The integer value exceeds INT64_MAX and cannot be returned as a signed integer. "
1515
                    "Use as_uint() instead.",
1516
                    get_type());
1517
            }
1518
            return act_node.m_value.integer;
28✔
1519
        }
1520
        throw fkyaml::type_error("The node value is not an integer.", get_type());
18✔
1521
    }
1522

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

1541
    /// @brief Returns reference to the float node value.
1542
    /// @throw fkyaml::type_error The node value is not a float.
1543
    /// @return Reference to the float node value.
1544
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_float/
1545
    float_number_type& as_float() {
38✔
1546
        basic_node& act_node = resolve_reference();
38✔
1547
        if FK_YAML_LIKELY (act_node.is_float_number_impl()) {
38✔
1548
            return act_node.m_value.float_val;
20✔
1549
        }
1550
        throw fkyaml::type_error("The node value is not a float.", get_type());
18✔
1551
    }
1552

1553
    /// @brief Returns reference to the float node value.
1554
    /// @throw fkyaml::type_error The node value is not a float.
1555
    /// @return Constant reference to the float node value.
1556
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_float/
1557
    const float_number_type& as_float() const {
205✔
1558
        const basic_node& act_node = resolve_reference();
205✔
1559
        if FK_YAML_LIKELY (act_node.is_float_number_impl()) {
205✔
1560
            return act_node.m_value.float_val;
187✔
1561
        }
1562
        throw fkyaml::type_error("The node value is not a float.", get_type());
18✔
1563
    }
1564

1565
    /// @brief Returns reference to the string node value.
1566
    /// @throw fkyaml::type_error The node value is not a string.
1567
    /// @return Reference to the string node value.
1568
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_str/
1569
    string_type& as_str() {
347✔
1570
        basic_node& act_node = resolve_reference();
347✔
1571
        if FK_YAML_LIKELY (act_node.is_string_impl()) {
347✔
1572
            return *act_node.m_value.p_str;
329✔
1573
        }
1574
        throw fkyaml::type_error("The node value is not a string.", get_type());
18✔
1575
    }
1576

1577
    /// @brief Returns reference to the string node value.
1578
    /// @throw fkyaml::type_error The node value is not a string.
1579
    /// @return Constant reference to the string node value.
1580
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_str/
1581
    const string_type& as_str() const {
192✔
1582
        const basic_node& act_node = resolve_reference();
192✔
1583
        if FK_YAML_LIKELY (act_node.is_string_impl()) {
192✔
1584
            return *act_node.m_value.p_str;
174✔
1585
        }
1586
        throw fkyaml::type_error("The node value is not a string.", get_type());
18✔
1587
    }
1588

1589
    /// @brief Swaps the internally stored data with the specified basic_node object.
1590
    /// @param[in] rhs A basic_node object to be swapped with.
1591
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/swap/
1592
    void swap(basic_node& rhs) noexcept {
1,693✔
1593
        using std::swap;
1594
        swap(m_attrs, rhs.m_attrs);
1,693✔
1595
        swap(mp_meta, rhs.mp_meta);
1,693✔
1596

1597
        node_value tmp {};
1,693✔
1598
        std::memcpy(&tmp, &m_value, sizeof(node_value));
1,693✔
1599
        std::memcpy(&m_value, &rhs.m_value, sizeof(node_value));
1,693✔
1600
        std::memcpy(&rhs.m_value, &tmp, sizeof(node_value));
1,693✔
1601

1602
        swap(m_prop.tag, rhs.m_prop.tag);
1,693✔
1603
        swap(m_prop.anchor, rhs.m_prop.anchor);
1,693✔
1604
    }
1,693✔
1605

1606
    /// @brief Returns an iterator to the first element of a container node (sequence or mapping).
1607
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1608
    /// @return An iterator to the first element of a container node.
1609
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/begin/
1610
    iterator begin() {
114✔
1611
        basic_node& act_node = resolve_reference();
114✔
1612
        switch (act_node.m_attrs & detail::node_attr_mask::value) {
114✔
1613
        case detail::node_attr_bits::seq_bit:
56✔
1614
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
56✔
1615
            return {act_node.m_value.p_seq->begin()};
56✔
1616
        case detail::node_attr_bits::map_bit:
48✔
1617
            FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
48✔
1618
            return {act_node.m_value.p_map->begin()};
48✔
1619
        default:
10✔
1620
            throw fkyaml::type_error("The target node is neither of sequence nor mapping types.", get_type());
10✔
1621
        }
1622
    }
1623

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

1642
    /// @brief Returns a const iterator to the first element of a container node (sequence or mapping).
1643
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1644
    /// @return A const iterator to the first element of a container node.
1645
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/begin/
1646
    const_iterator cbegin() const {
18✔
1647
        return begin();
18✔
1648
    }
1649

1650
    /// @brief Returns an iterator to the past-the-last element of a container node (sequence or mapping).
1651
    /// @throw `type_error` if the basic_node value is not of container types.
1652
    /// @return An iterator to the past-the-last element of a container node.
1653
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/end/
1654
    iterator end() {
108✔
1655
        basic_node& act_node = resolve_reference();
108✔
1656
        switch (act_node.m_attrs & detail::node_attr_mask::value) {
108✔
1657
        case detail::node_attr_bits::seq_bit:
51✔
1658
            FK_YAML_ASSERT(act_node.m_value.p_seq != nullptr);
51✔
1659
            return {act_node.m_value.p_seq->end()};
51✔
1660
        case detail::node_attr_bits::map_bit:
47✔
1661
            FK_YAML_ASSERT(act_node.m_value.p_map != nullptr);
47✔
1662
            return {act_node.m_value.p_map->end()};
47✔
1663
        default:
10✔
1664
            throw fkyaml::type_error("The target node is neither of sequence nor mapping types.", get_type());
10✔
1665
        }
1666
    }
1667

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

1686
    /// @brief Returns a const iterator to the past-the-last element of a container node (sequence or mapping).
1687
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1688
    /// @return A const iterator to the past-the-last element of a container node.
1689
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/end/
1690
    const_iterator cend() const {
18✔
1691
        return end();
18✔
1692
    }
1693

1694
    /// @brief Returns an iterator to the reverse-beginning (i.e., last) element of a container node (sequence or
1695
    /// mapping).
1696
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1697
    /// @return An iterator to the reverse-beginning element of a container node.
1698
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rbegin/
1699
    reverse_iterator rbegin() {
69✔
1700
        return {end()};
69✔
1701
    }
1702

1703
    /// @brief Returns a const iterator to the reverse-beginning (i.e., last) element of a container node (sequence or
1704
    /// mapping).
1705
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1706
    /// @return A const iterator to the reverse-beginning element of a container node.
1707
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rbegin/
1708
    const_reverse_iterator rbegin() const {
27✔
1709
        return {end()};
27✔
1710
    }
1711

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

1721
    /// @brief Returns an iterator to the reverse-end (i.e., one before the first) element of a container node (sequence
1722
    /// or mapping).
1723
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1724
    /// @return An iterator to the reverse-end element.
1725
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rend/
1726
    reverse_iterator rend() {
9✔
1727
        return {begin()};
9✔
1728
    }
1729

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

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

1748
    /// @brief Returns a range of mapping entries.
1749
    /// @throw `type_error` if this basic_node is not a mapping.
1750
    /// @return A range of mapping entries.
1751
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/map_items/
1752
    map_range map_items() {
9✔
1753
        if FK_YAML_UNLIKELY (!is_mapping()) {
9✔
1754
            throw type_error("map_items() cannot be called on a non-mapping node.", get_type());
6✔
1755
        }
1756
        return {*this};
3✔
1757
    }
1758

1759
    /// @brief Returns a const range of mapping entries.
1760
    /// @throw `type_error` if this basic_node is not a mapping.
1761
    /// @return A const range of mapping entries.
1762
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/map_items/
1763
    const_map_range map_items() const {
32✔
1764
        if FK_YAML_UNLIKELY (!is_mapping()) {
32✔
1765
            throw type_error("map_items() cannot be called on a non-mapping node.", get_type());
6✔
1766
        }
1767
        return {*this};
26✔
1768
    }
1769

1770
private:
1771
    /// @brief Resolves anchor/alias reference and returns reference to an actual value node.
1772
    /// @return Reference to an actual value node.
1773
    basic_node& resolve_reference() {
2,941✔
1774
        if FK_YAML_UNLIKELY (has_anchor_name()) {
2,941✔
1775
            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;
107✔
1776
            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));
107✔
1777
            return itr->second;
107✔
1778
        }
1779
        return *this;
2,834✔
1780
    }
1781

1782
    /// @brief Resolves anchor/alias reference and returns const reference to an actual value node.
1783
    /// @return Const reference to an actual value node.
1784
    const basic_node& resolve_reference() const {
29,587✔
1785
        if FK_YAML_UNLIKELY (has_anchor_name()) {
29,587✔
1786
            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;
416✔
1787
            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));
416✔
1788
            return itr->second;
416✔
1789
        }
1790
        return *this;
29,171✔
1791
    }
1792

1793
    bool is_sequence_impl() const noexcept {
4,669✔
1794
        return m_attrs & detail::node_attr_bits::seq_bit;
4,669✔
1795
    }
1796

1797
    bool is_mapping_impl() const noexcept {
1,847✔
1798
        return m_attrs & detail::node_attr_bits::map_bit;
1,847✔
1799
    }
1800

1801
    bool is_null_impl() const noexcept {
120✔
1802
        return m_attrs & detail::node_attr_bits::null_bit;
120✔
1803
    }
1804

1805
    bool is_boolean_impl() const noexcept {
591✔
1806
        return m_attrs & detail::node_attr_bits::bool_bit;
591✔
1807
    }
1808

1809
    bool is_integer_impl() const noexcept {
3,807✔
1810
        return m_attrs & detail::node_attr_bits::int_bit;
3,807✔
1811
    }
1812

1813
    bool is_uint_impl() const noexcept {
1,953✔
1814
        // Both int_bit and uint_bit must be set: this node stores a uint64_t value
1815
        // whose bit pattern was placed into the signed integer_type field.
1816
        return (m_attrs & detail::node_attr_bits::int_bit) && (m_attrs & detail::node_attr_bits::uint_bit);
1,953✔
1817
    }
1818

1819
    bool is_float_number_impl() const noexcept {
353✔
1820
        return m_attrs & detail::node_attr_bits::float_bit;
353✔
1821
    }
1822

1823
    bool is_string_impl() const noexcept {
1,020✔
1824
        return m_attrs & detail::node_attr_bits::string_bit;
1,020✔
1825
    }
1826

1827
    bool is_scalar_impl() const noexcept {
2,613✔
1828
        return m_attrs & detail::node_attr_bits::scalar_bits;
2,613✔
1829
    }
1830

1831
    template <
1832
        typename ValueType, detail::enable_if_t<detail::negation<detail::is_basic_node<ValueType>>::value, int> = 0>
1833
    void get_value_impl(ValueType& v) const
2,595✔
1834
        noexcept(noexcept(ConverterType<ValueType, void>::from_node(std::declval<const basic_node&>(), v))) {
1835
        ConverterType<ValueType, void>::from_node(*this, v);
2,595✔
1836
    }
2,517✔
1837

1838
    template <typename ValueType, detail::enable_if_t<detail::is_basic_node<ValueType>::value, int> = 0>
1839
    void get_value_impl(ValueType& v) const {
124✔
1840
        v = *this;
124✔
1841
    }
124✔
1842

1843
    /// @brief Returns reference to the sequence node value.
1844
    /// @throw fkyaml::exception The node value is not a sequence.
1845
    /// @return Reference to the sequence node value.
1846
    sequence_type& get_value_ref_impl(sequence_type* /*unused*/) {
7✔
1847
        return as_seq();
7✔
1848
    }
1849

1850
    /// @brief Returns constant reference to the sequence node value.
1851
    /// @throw fkyaml::exception The node value is not a sequence.
1852
    /// @return Constant reference to the sequence node value.
1853
    const sequence_type& get_value_ref_impl(const sequence_type* /*unused*/) const {
7✔
1854
        return as_seq();
7✔
1855
    }
1856

1857
    /// @brief Returns reference to the mapping node value.
1858
    /// @throw fkyaml::exception The node value is not a mapping.
1859
    /// @return Reference to the mapping node value.
1860
    mapping_type& get_value_ref_impl(mapping_type* /*unused*/) {
7✔
1861
        return as_map();
7✔
1862
    }
1863

1864
    /// @brief Returns constant reference to the mapping node value.
1865
    /// @throw fkyaml::exception The node value is not a mapping.
1866
    /// @return Constant reference to the mapping node value.
1867
    const mapping_type& get_value_ref_impl(const mapping_type* /*unused*/) const {
7✔
1868
        return as_map();
7✔
1869
    }
1870

1871
    /// @brief Returns reference to the boolean node value.
1872
    /// @throw fkyaml::exception The node value is not a boolean.
1873
    /// @return Reference to the boolean node value.
1874
    boolean_type& get_value_ref_impl(boolean_type* /*unused*/) {
7✔
1875
        return as_bool();
7✔
1876
    }
1877

1878
    /// @brief Returns reference to the boolean node value.
1879
    /// @throw fkyaml::exception The node value is not a boolean.
1880
    /// @return Constant reference to the boolean node value.
1881
    const boolean_type& get_value_ref_impl(const boolean_type* /*unused*/) const {
7✔
1882
        return as_bool();
7✔
1883
    }
1884

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

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

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

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

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

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

1927
    /// The current node attributes.
1928
    detail::node_attr_t m_attrs {detail::node_attr_bits::default_bits};
1929
    /// The shared set of YAML directives applied to this node.
1930
    mutable std::shared_ptr<detail::document_metainfo<basic_node>> mp_meta {
1931
        // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new)
1932
        std::shared_ptr<detail::document_metainfo<basic_node>>(new detail::document_metainfo<basic_node>())};
1933
    /// The current node value.
1934
    node_value m_value {};
1935
    /// The property set of this node.
1936
    detail::node_property m_prop {};
1937
};
1938

1939
/// @brief Swap function for basic_node objects.
1940
/// @param[in] lhs A left-side-hand basic_node object to be swapped with.
1941
/// @param[in] rhs A right-side-hand basic_node object to be swapped with.
1942
/// @sa https://fktn-k.github.io/fkYAML/api/swap/
1943
template <
1944
    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,
1945
    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,
1946
    template <typename, typename = void> class ConverterType>
1947
inline void swap(
1✔
1948
    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>& lhs,
1949
    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>&
1950
        rhs) noexcept(noexcept(lhs.swap(rhs))) {
1951
    lhs.swap(rhs);
1✔
1952
}
1✔
1953

1954
/// @brief Insertion operator for basic_node template class. A wrapper for the serialization feature.
1955
/// @param[in] os An output stream object.
1956
/// @param[in] n A basic_node object.
1957
/// @return Reference to the output stream object `os`.
1958
/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/insertion_operator/
1959
template <
1960
    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,
1961
    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,
1962
    template <typename, typename = void> class ConverterType>
1963
inline std::ostream& operator<<(
1✔
1964
    std::ostream& os,
1965
    const basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>&
1966
        n) {
1967
    os << basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>::
1✔
1968
            serialize(n);
1969
    return os;
1✔
1970
}
1971

1972
/// @brief Extraction operator for basic_node template class. A wrapper for the deserialization feature with input
1973
/// streams.
1974
/// @param[in] is An input stream object.
1975
/// @param[in] n A basic_node object.
1976
/// @return Reference to the input stream object `is`.
1977
/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/extraction_operator/
1978
template <
1979
    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,
1980
    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,
1981
    template <typename, typename = void> class ConverterType>
1982
inline std::istream& operator>>(
1✔
1983
    std::istream& is,
1984
    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>& n) {
1985
    n = basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>::
1✔
1986
        deserialize(is);
1987
    return is;
1✔
1988
}
1989

1990
/// @brief namespace for user-defined literals for the fkYAML library.
1991
inline namespace literals {
1992
/// @brief namespace for user-defined literals for YAML node objects.
1993
inline namespace yaml_literals {
1994

1995
// Whitespace before the literal operator identifier is deprecated in C++23 or better but required in C++11.
1996
// Ignore the warning as a workaround. https://github.com/fktn-k/fkYAML/pull/417
1997
#if defined(__clang__)
1998
#pragma clang diagnostic push
1999
#pragma clang diagnostic ignored "-Wdeprecated"
2000
#endif
2001

2002
#if defined(__GNUC__) && (__GNUC__ > 6)
2003
#define FK_YAML_QUOTE_OPERATOR operator""_yaml
2004
#else
2005
#define FK_YAML_QUOTE_OPERATOR operator"" _yaml
2006
#endif
2007

2008
/// @brief The user-defined string literal which deserializes a `char` array into a `node` object.
2009
/// @param s An input `char` array.
2010
/// @param n The size of `s`.
2011
/// @return The resulting `node` object deserialized from `s`.
2012
/// @sa https://fktn-k.github.io/fkYAML/api/operator_literal_yaml/
2013
inline fkyaml::node FK_YAML_QUOTE_OPERATOR(const char* s, std::size_t n) {
6✔
2014
    return fkyaml::node::deserialize(s, s + n);
6✔
2015
}
2016

2017
/// @brief The user-defined string literal which deserializes a `char16_t` array into a `node` object.
2018
/// @param s An input `char16_t` array.
2019
/// @param n The size of `s`.
2020
/// @return The resulting `node` object deserialized from `s`.
2021
/// @sa https://fktn-k.github.io/fkYAML/api/operator_literal_yaml/
2022
inline fkyaml::node FK_YAML_QUOTE_OPERATOR(const char16_t* s, std::size_t n) {
3✔
2023
    return fkyaml::node::deserialize(s, s + n);
3✔
2024
}
2025

2026
/// @brief The user-defined string literal which deserializes a `char32_t` array into a `node` object.
2027
/// @param s An input `char32_t` array.
2028
/// @param n The size of `s`.
2029
/// @return The resulting `node` object deserialized from `s`.
2030
/// @sa https://fktn-k.github.io/fkYAML/api/operator_literal_yaml/
2031
inline fkyaml::node FK_YAML_QUOTE_OPERATOR(const char32_t* s, std::size_t n) {
3✔
2032
    return fkyaml::node::deserialize(s, s + n);
3✔
2033
}
2034

2035
#if FK_YAML_HAS_CHAR8_T
2036
/// @brief The user-defined string literal which deserializes a `char8_t` array into a `node` object.
2037
/// @param s An input `char8_t` array.
2038
/// @param n The size of `s`.
2039
/// @return The resulting `node` object deserialized from `s`.
2040
inline fkyaml::node FK_YAML_QUOTE_OPERATOR(const char8_t* s, std::size_t n) {
2041
    return fkyaml::node::deserialize(s, s + n);
2042
}
2043

2044
#if defined(__clang__)
2045
#pragma clang diagnostic pop
2046
#endif
2047

2048
#endif
2049

2050
} // namespace yaml_literals
2051
} // namespace literals
2052

2053
FK_YAML_NAMESPACE_END
2054

2055
namespace std {
2056

2057
template <
2058
    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,
2059
    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,
2060
    template <typename, typename = void> class ConverterType>
2061
// NOLINTNEXTLINE(cert-dcl58-cpp)
2062
struct hash<fkyaml::basic_node<
2063
    SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>> {
2064
    using node_t = fkyaml::basic_node<
2065
        SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>;
2066

2067
    std::size_t operator()(const node_t& n) const {
76✔
2068
        using boolean_type = typename node_t::boolean_type;
2069
        using integer_type = typename node_t::integer_type;
2070
        using float_number_type = typename node_t::float_number_type;
2071
        using string_type = typename node_t::string_type;
2072

2073
        const auto type = n.get_type();
76✔
2074

2075
        std::size_t seed = 0;
76✔
2076
        hash_combine(seed, std::hash<uint8_t>()(static_cast<uint8_t>(type)));
76✔
2077

2078
        switch (type) {
76✔
2079
        case fkyaml::node_type::SEQUENCE:
2✔
2080
            hash_combine(seed, n.size());
2✔
2081
            for (const auto& elem : n) {
10✔
2082
                hash_combine(seed, operator()(elem));
6✔
2083
            }
2084
            return seed;
2✔
2085

2086
        case fkyaml::node_type::MAPPING:
2✔
2087
            hash_combine(seed, n.size());
2✔
2088
            for (auto itr = n.begin(), end_itr = n.end(); itr != end_itr; ++itr) {
4✔
2089
                hash_combine(seed, operator()(itr.key()));
2✔
2090
                hash_combine(seed, operator()(itr.value()));
2✔
2091
            }
2092
            return seed;
2✔
2093

2094
        case fkyaml::node_type::NULL_OBJECT:
2✔
2095
            hash_combine(seed, 0);
2✔
2096
            return seed;
2✔
2097
        case fkyaml::node_type::BOOLEAN:
26✔
2098
            hash_combine(seed, std::hash<boolean_type>()(n.template get_value<boolean_type>()));
26✔
2099
            return seed;
26✔
2100
        case fkyaml::node_type::INTEGER:
8✔
2101
            hash_combine(seed, std::hash<integer_type>()(n.template get_value<integer_type>()));
8✔
2102
            return seed;
8✔
2103
        case fkyaml::node_type::FLOAT:
2✔
2104
            hash_combine(seed, std::hash<float_number_type>()(n.template get_value<float_number_type>()));
2✔
2105
            return seed;
2✔
2106
        case fkyaml::node_type::STRING:
34✔
2107
            hash_combine(seed, std::hash<string_type>()(n.template get_value<string_type>()));
34✔
2108
            return seed;
34✔
2109
        default:                           // LCOV_EXCL_LINE
2110
            fkyaml::detail::unreachable(); // LCOV_EXCL_LINE
2111
        }
2112
    }
2113

2114
private:
2115
    // taken from boost::hash_combine
2116
    FK_YAML_NO_SANITIZE("unsigned-shift-base", "unsigned-integer-overflow")
2117
    static void hash_combine(std::size_t& seed, std::size_t v) {
162✔
2118
        seed ^= v + 0x9e3779b9 + (seed << 6u) + (seed >> 2u);
162✔
2119
    }
162✔
2120
};
2121

2122
} // namespace std
2123

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

© 2026 Coveralls, Inc