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

fktn-k / fkYAML / 28818715174

06 Jul 2026 07:47PM UTC coverage: 99.863% (-0.1%) from 99.969%
28818715174

Pull #524

github

web-flow
Merge 4e615345f into 9f56b48cc
Pull Request #524: Fix brace initialization of empty collection nodes (issue #502)

1415 of 1422 branches covered (99.51%)

Branch coverage included in aggregate %.

13 of 13 new or added lines in 2 files covered. (100.0%)

1 existing line in 1 file now uncovered.

5153 of 5155 relevant lines covered (99.96%)

402.99 hits per line

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

99.09
/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,616✔
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,933✔
207
            switch (value_type_bit) {
16,933✔
208
            case detail::node_attr_bits::seq_bit:
1,854✔
209
                p_seq->clear();
1,854✔
210
                detail::destroy_object<sequence_type>(p_seq);
1,854✔
211
                p_seq = nullptr;
1,854✔
212
                break;
1,854✔
213
            case detail::node_attr_bits::map_bit:
924✔
214
                p_map->clear();
924✔
215
                detail::destroy_object<mapping_type>(p_map);
924✔
216
                p_map = nullptr;
924✔
217
                break;
924✔
218
            case detail::node_attr_bits::string_bit:
3,148✔
219
                detail::destroy_object<string_type>(p_str);
3,148✔
220
                p_str = nullptr;
3,148✔
221
                break;
3,148✔
222
            default:
11,007✔
223
                break;
11,007✔
224
            }
225
        }
16,933✔
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,619✔
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,573✔
263
        : m_attrs(rhs.m_attrs),
3,573✔
264
          mp_meta(rhs.mp_meta),
3,573✔
265
          m_prop(rhs.m_prop) {
3,573✔
266
        if FK_YAML_LIKELY (!has_anchor_name()) {
3,573✔
267
            switch (m_attrs & detail::node_attr_mask::value) {
3,346✔
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:
762✔
287
                m_value.p_str = detail::create_object<string_type>(*(rhs.m_value.p_str));
762✔
288
                break;
762✔
289
            default:                   // LCOV_EXCL_LINE
290
                detail::unreachable(); // LCOV_EXCL_LINE
291
            }
292
        }
293
    }
3,573✔
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,087✔
299
        : m_attrs(rhs.m_attrs),
9,087✔
300
          mp_meta(std::move(rhs.mp_meta)),
9,087✔
301
          m_prop(std::move(rhs.m_prop)) {
9,087✔
302
        if FK_YAML_LIKELY (!has_anchor_name()) {
9,087✔
303
            switch (m_attrs & detail::node_attr_mask::value) {
9,045✔
304
            case detail::node_attr_bits::seq_bit:
1,270✔
305
                FK_YAML_ASSERT(rhs.m_value.p_seq != nullptr);
1,270✔
306
                m_value.p_seq = rhs.m_value.p_seq;
1,270✔
307
                rhs.m_value.p_seq = nullptr;
1,270✔
308
                break;
1,270✔
309
            case detail::node_attr_bits::map_bit:
860✔
310
                FK_YAML_ASSERT(rhs.m_value.p_map != nullptr);
860✔
311
                m_value.p_map = rhs.m_value.p_map;
860✔
312
                rhs.m_value.p_map = nullptr;
860✔
313
                break;
860✔
314
            case detail::node_attr_bits::null_bit:
1,029✔
315
                FK_YAML_ASSERT(rhs.m_value.p_map == nullptr);
1,029✔
316
                m_value.p_map = rhs.m_value.p_map;
1,029✔
317
                break;
1,029✔
318
            case detail::node_attr_bits::bool_bit:
1,493✔
319
                m_value.boolean = rhs.m_value.boolean;
1,493✔
320
                rhs.m_value.boolean = static_cast<boolean_type>(false);
1,493✔
321
                break;
1,493✔
322
            case detail::node_attr_bits::int_bit:
1,386✔
323
                m_value.integer = rhs.m_value.integer;
1,386✔
324
                rhs.m_value.integer = static_cast<integer_type>(0);
1,386✔
325
                break;
1,386✔
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,588✔
331
                FK_YAML_ASSERT(rhs.m_value.p_str != nullptr);
2,588✔
332
                m_value.p_str = rhs.m_value.p_str;
2,588✔
333
                rhs.m_value.p_str = nullptr;
2,588✔
334
                break;
2,588✔
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,087✔
341
        rhs.m_value.p_map = nullptr;
9,087✔
342
    }
9,087✔
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,130✔
357
        noexcept(ConverterType<U, void>::to_node(std::declval<basic_node&>(), std::declval<CompatibleType>()))) {
6,130✔
358
        ConverterType<U, void>::to_node(*this, std::forward<CompatibleType>(val));
6,130✔
359
    }
6,130✔
360

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

762
        return ret;
3,686✔
763
    }
764

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

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

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

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

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

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

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

824
        return ret;
1,285✔
825
    }
826

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1001
        return false;
12✔
1002
    }
1003

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1231
        auto p_meta = mp_meta;
4✔
1232

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

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

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

1259
        auto p_meta = mp_meta;
258✔
1260

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1484
    /// @brief Checks if the node is an integer that was parsed from a uint64_t value exceeding INT64_MAX.
1485
    /// @return true if the node holds an unsigned integer, false otherwise.
1486
    bool is_uint() const noexcept {
21✔
1487
        return resolve_reference().is_uint_impl();
21✔
1488
    }
1489

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

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

1532
    /// @brief Returns reference to the integer node value.
1533
    /// @throw fkyaml::type_error The node value is not an integer, or exceeds INT64_MAX.
1534
    /// @return Constant reference to the integer node value.
1535
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/as_int/
1536
    const integer_type& as_int() const {
1,921✔
1537
        const basic_node& act_node = resolve_reference();
1,921✔
1538
        if FK_YAML_LIKELY (act_node.is_integer_impl()) {
1,921✔
1539
            if FK_YAML_UNLIKELY (act_node.is_uint_impl()) {
1,903!
1540
                throw fkyaml::type_error(
×
1541
                    "The integer value exceeds INT64_MAX and cannot be returned as a signed integer. "
1542
                    "Use as_uint() instead.",
1543
                    get_type());
1544
            }
1545
            return act_node.m_value.integer;
1,903✔
1546
        }
1547
        throw fkyaml::type_error("The node value is not an integer.", get_type());
18✔
1548
    }
1549

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

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

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

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

1598
    /// @brief Swaps the internally stored data with the specified basic_node object.
1599
    /// @param[in] rhs A basic_node object to be swapped with.
1600
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/swap/
1601
    void swap(basic_node& rhs) noexcept {
1,699✔
1602
        using std::swap;
1603
        swap(m_attrs, rhs.m_attrs);
1,699✔
1604
        swap(mp_meta, rhs.mp_meta);
1,699✔
1605

1606
        node_value tmp {};
1,699✔
1607
        std::memcpy(&tmp, &m_value, sizeof(node_value));
1,699✔
1608
        std::memcpy(&m_value, &rhs.m_value, sizeof(node_value));
1,699✔
1609
        std::memcpy(&rhs.m_value, &tmp, sizeof(node_value));
1,699✔
1610

1611
        swap(m_prop.tag, rhs.m_prop.tag);
1,699✔
1612
        swap(m_prop.anchor, rhs.m_prop.anchor);
1,699✔
1613
    }
1,699✔
1614

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

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

1651
    /// @brief Returns a const iterator to the first element of a container node (sequence or mapping).
1652
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1653
    /// @return A const iterator to the first element of a container node.
1654
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/begin/
1655
    const_iterator cbegin() const {
18✔
1656
        return begin();
18✔
1657
    }
1658

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

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

1695
    /// @brief Returns a const iterator to the past-the-last element of a container node (sequence or mapping).
1696
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1697
    /// @return A const iterator to the past-the-last element of a container node.
1698
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/end/
1699
    const_iterator cend() const {
18✔
1700
        return end();
18✔
1701
    }
1702

1703
    /// @brief Returns an 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 An iterator to the reverse-beginning element of a container node.
1707
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rbegin/
1708
    reverse_iterator rbegin() {
69✔
1709
        return {end()};
69✔
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 rbegin() const {
27✔
1718
        return {end()};
27✔
1719
    }
1720

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

1730
    /// @brief Returns an iterator to the reverse-end (i.e., one before the first) element of a container node (sequence
1731
    /// or mapping).
1732
    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.
1733
    /// @return An iterator to the reverse-end element.
1734
    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rend/
1735
    reverse_iterator rend() {
9✔
1736
        return {begin()};
9✔
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 rend() const {
27✔
1745
        return {begin()};
27✔
1746
    }
1747

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

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

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

1779
private:
1780
    /// @brief Resolves anchor/alias reference and returns reference to an actual value node.
1781
    /// @return Reference to an actual value node.
1782
    basic_node& resolve_reference() {
2,944✔
1783
        if FK_YAML_UNLIKELY (has_anchor_name()) {
2,944✔
1784
            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;
107✔
1785
            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));
107✔
1786
            return itr->second;
107✔
1787
        }
1788
        return *this;
2,837✔
1789
    }
1790

1791
    /// @brief Resolves anchor/alias reference and returns const reference to an actual value node.
1792
    /// @return Const reference to an actual value node.
1793
    const basic_node& resolve_reference() const {
29,771✔
1794
        if FK_YAML_UNLIKELY (has_anchor_name()) {
29,771✔
1795
            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;
416✔
1796
            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));
416✔
1797
            return itr->second;
416✔
1798
        }
1799
        return *this;
29,355✔
1800
    }
1801

1802
    bool is_sequence_impl() const noexcept {
4,679✔
1803
        return m_attrs & detail::node_attr_bits::seq_bit;
4,679✔
1804
    }
1805

1806
    bool is_mapping_impl() const noexcept {
1,859✔
1807
        return m_attrs & detail::node_attr_bits::map_bit;
1,859✔
1808
    }
1809

1810
    bool is_null_impl() const noexcept {
120✔
1811
        return m_attrs & detail::node_attr_bits::null_bit;
120✔
1812
    }
1813

1814
    bool is_boolean_impl() const noexcept {
591✔
1815
        return m_attrs & detail::node_attr_bits::bool_bit;
591✔
1816
    }
1817

1818
    bool is_integer_impl() const noexcept {
3,811✔
1819
        return m_attrs & detail::node_attr_bits::int_bit;
3,811✔
1820
    }
1821

1822
    bool is_uint_impl() const noexcept {
1,955✔
1823
        // Both int_bit and uint_bit must be set: this node stores a uint64_t value
1824
        // whose bit pattern was placed into the signed integer_type field.
1825
        return (m_attrs & detail::node_attr_bits::int_bit) && (m_attrs & detail::node_attr_bits::uint_bit);
1,955✔
1826
    }
1827

1828
    bool is_float_number_impl() const noexcept {
353✔
1829
        return m_attrs & detail::node_attr_bits::float_bit;
353✔
1830
    }
1831

1832
    bool is_string_impl() const noexcept {
1,100✔
1833
        return m_attrs & detail::node_attr_bits::string_bit;
1,100✔
1834
    }
1835

1836
    bool is_scalar_impl() const noexcept {
2,622✔
1837
        return m_attrs & detail::node_attr_bits::scalar_bits;
2,622✔
1838
    }
1839

1840
    template <
1841
        typename ValueType, detail::enable_if_t<detail::negation<detail::is_basic_node<ValueType>>::value, int> = 0>
1842
    void get_value_impl(ValueType& v) const
2,597✔
1843
        noexcept(noexcept(ConverterType<ValueType, void>::from_node(std::declval<const basic_node&>(), v))) {
1844
        ConverterType<ValueType, void>::from_node(*this, v);
2,597✔
1845
    }
2,519✔
1846

1847
    template <typename ValueType, detail::enable_if_t<detail::is_basic_node<ValueType>::value, int> = 0>
1848
    void get_value_impl(ValueType& v) const {
124✔
1849
        v = *this;
124✔
1850
    }
124✔
1851

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

1859
    /// @brief Returns constant reference to the sequence node value.
1860
    /// @throw fkyaml::exception The node value is not a sequence.
1861
    /// @return Constant reference to the sequence node value.
1862
    const sequence_type& get_value_ref_impl(const sequence_type* /*unused*/) const {
7✔
1863
        return as_seq();
7✔
1864
    }
1865

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

1873
    /// @brief Returns constant reference to the mapping node value.
1874
    /// @throw fkyaml::exception The node value is not a mapping.
1875
    /// @return Constant reference to the mapping node value.
1876
    const mapping_type& get_value_ref_impl(const mapping_type* /*unused*/) const {
7✔
1877
        return as_map();
7✔
1878
    }
1879

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

1887
    /// @brief Returns reference to the boolean node value.
1888
    /// @throw fkyaml::exception The node value is not a boolean.
1889
    /// @return Constant reference to the boolean node value.
1890
    const boolean_type& get_value_ref_impl(const boolean_type* /*unused*/) const {
7✔
1891
        return as_bool();
7✔
1892
    }
1893

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

1901
    /// @brief Returns reference to the integer node value.
1902
    /// @throw fkyaml::exception The node value is not an integer.
1903
    /// @return Constant reference to the integer node value.
1904
    const integer_type& get_value_ref_impl(const integer_type* /*unused*/) const {
7✔
1905
        return as_int();
7✔
1906
    }
1907

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

1915
    /// @brief Returns reference to the floating point number node value.
1916
    /// @throw fkyaml::exception The node value is not a floating point number.
1917
    /// @return Constant reference to the floating point number node value.
1918
    const float_number_type& get_value_ref_impl(const float_number_type* /*unused*/) const {
7✔
1919
        return as_float();
7✔
1920
    }
1921

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

1929
    /// @brief Returns reference to the string node value.
1930
    /// @throw fkyaml::exception The node value is not a string.
1931
    /// @return Constant reference to the string node value.
1932
    const string_type& get_value_ref_impl(const string_type* /*unused*/) const {
7✔
1933
        return as_str();
7✔
1934
    }
1935

1936
    /// The current node attributes.
1937
    detail::node_attr_t m_attrs {detail::node_attr_bits::default_bits};
1938
    /// The shared set of YAML directives applied to this node.
1939
    mutable std::shared_ptr<detail::document_metainfo<basic_node>> mp_meta {
1940
        // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new)
1941
        std::shared_ptr<detail::document_metainfo<basic_node>>(new detail::document_metainfo<basic_node>())};
1942
    /// The current node value.
1943
    node_value m_value {};
1944
    /// The property set of this node.
1945
    detail::node_property m_prop {};
1946
};
1947

1948
/// @brief Swap function for basic_node objects.
1949
/// @param[in] lhs A left-side-hand basic_node object to be swapped with.
1950
/// @param[in] rhs A right-side-hand basic_node object to be swapped with.
1951
/// @sa https://fktn-k.github.io/fkYAML/api/swap/
1952
template <
1953
    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,
1954
    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,
1955
    template <typename, typename = void> class ConverterType>
1956
inline void swap(
1✔
1957
    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>& lhs,
1958
    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>&
1959
        rhs) noexcept(noexcept(lhs.swap(rhs))) {
1960
    lhs.swap(rhs);
1✔
1961
}
1✔
1962

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

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

1999
/// @brief namespace for user-defined literals for the fkYAML library.
2000
inline namespace literals {
2001
/// @brief namespace for user-defined literals for YAML node objects.
2002
inline namespace yaml_literals {
2003

2004
// Whitespace before the literal operator identifier is deprecated in C++23 or better but required in C++11.
2005
// Ignore the warning as a workaround. https://github.com/fktn-k/fkYAML/pull/417
2006
#if defined(__clang__)
2007
#pragma clang diagnostic push
2008
#pragma clang diagnostic ignored "-Wdeprecated"
2009
#endif
2010

2011
#if defined(__GNUC__) && (__GNUC__ > 6)
2012
#define FK_YAML_QUOTE_OPERATOR operator""_yaml
2013
#else
2014
#define FK_YAML_QUOTE_OPERATOR operator"" _yaml
2015
#endif
2016

2017
/// @brief The user-defined string literal which deserializes a `char` array into a `node` object.
2018
/// @param s An input `char` 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 char* s, std::size_t n) {
6✔
2023
    return fkyaml::node::deserialize(s, s + n);
6✔
2024
}
2025

2026
/// @brief The user-defined string literal which deserializes a `char16_t` array into a `node` object.
2027
/// @param s An input `char16_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 char16_t* s, std::size_t n) {
3✔
2032
    return fkyaml::node::deserialize(s, s + n);
3✔
2033
}
2034

2035
/// @brief The user-defined string literal which deserializes a `char32_t` array into a `node` object.
2036
/// @param s An input `char32_t` array.
2037
/// @param n The size of `s`.
2038
/// @return The resulting `node` object deserialized from `s`.
2039
/// @sa https://fktn-k.github.io/fkYAML/api/operator_literal_yaml/
2040
inline fkyaml::node FK_YAML_QUOTE_OPERATOR(const char32_t* s, std::size_t n) {
3✔
2041
    return fkyaml::node::deserialize(s, s + n);
3✔
2042
}
2043

2044
#if FK_YAML_HAS_CHAR8_T
2045
/// @brief The user-defined string literal which deserializes a `char8_t` array into a `node` object.
2046
/// @param s An input `char8_t` array.
2047
/// @param n The size of `s`.
2048
/// @return The resulting `node` object deserialized from `s`.
2049
inline fkyaml::node FK_YAML_QUOTE_OPERATOR(const char8_t* s, std::size_t n) {
2050
    return fkyaml::node::deserialize(s, s + n);
2051
}
2052

2053
#if defined(__clang__)
2054
#pragma clang diagnostic pop
2055
#endif
2056

2057
#endif
2058

2059
} // namespace yaml_literals
2060
} // namespace literals
2061

2062
FK_YAML_NAMESPACE_END
2063

2064
namespace std {
2065

2066
template <
2067
    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,
2068
    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,
2069
    template <typename, typename = void> class ConverterType>
2070
// NOLINTNEXTLINE(cert-dcl58-cpp)
2071
struct hash<fkyaml::basic_node<
2072
    SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>> {
2073
    using node_t = fkyaml::basic_node<
2074
        SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>;
2075

2076
    std::size_t operator()(const node_t& n) const {
76✔
2077
        using boolean_type = typename node_t::boolean_type;
2078
        using integer_type = typename node_t::integer_type;
2079
        using float_number_type = typename node_t::float_number_type;
2080
        using string_type = typename node_t::string_type;
2081

2082
        const auto type = n.get_type();
76✔
2083

2084
        std::size_t seed = 0;
76✔
2085
        hash_combine(seed, std::hash<uint8_t>()(static_cast<uint8_t>(type)));
76✔
2086

2087
        switch (type) {
76✔
2088
        case fkyaml::node_type::SEQUENCE:
2✔
2089
            hash_combine(seed, n.size());
2✔
2090
            for (const auto& elem : n) {
10✔
2091
                hash_combine(seed, operator()(elem));
6✔
2092
            }
2093
            return seed;
2✔
2094

2095
        case fkyaml::node_type::MAPPING:
2✔
2096
            hash_combine(seed, n.size());
2✔
2097
            for (auto itr = n.begin(), end_itr = n.end(); itr != end_itr; ++itr) {
4✔
2098
                hash_combine(seed, operator()(itr.key()));
2✔
2099
                hash_combine(seed, operator()(itr.value()));
2✔
2100
            }
2101
            return seed;
2✔
2102

2103
        case fkyaml::node_type::NULL_OBJECT:
2✔
2104
            hash_combine(seed, 0);
2✔
2105
            return seed;
2✔
2106
        case fkyaml::node_type::BOOLEAN:
26✔
2107
            hash_combine(seed, std::hash<boolean_type>()(n.template get_value<boolean_type>()));
26✔
2108
            return seed;
26✔
2109
        case fkyaml::node_type::INTEGER:
8✔
2110
            hash_combine(seed, std::hash<integer_type>()(n.template get_value<integer_type>()));
8✔
2111
            return seed;
8✔
2112
        case fkyaml::node_type::FLOAT:
2✔
2113
            hash_combine(seed, std::hash<float_number_type>()(n.template get_value<float_number_type>()));
2✔
2114
            return seed;
2✔
2115
        case fkyaml::node_type::STRING:
34✔
2116
            hash_combine(seed, std::hash<string_type>()(n.template get_value<string_type>()));
34✔
2117
            return seed;
34✔
2118
        default:                           // LCOV_EXCL_LINE
2119
            fkyaml::detail::unreachable(); // LCOV_EXCL_LINE
2120
        }
2121
    }
2122

2123
private:
2124
    // taken from boost::hash_combine
2125
    FK_YAML_NO_SANITIZE("unsigned-shift-base", "unsigned-integer-overflow")
2126
    static void hash_combine(std::size_t& seed, std::size_t v) {
162✔
2127
        seed ^= v + 0x9e3779b9 + (seed << 6u) + (seed >> 2u);
162✔
2128
    }
162✔
2129
};
2130

2131
} // namespace std
2132

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