1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#pragma once


#include <memory><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include "internal/dev_env.hpp"


namespace uni {

namespace node_handlers {

namespace internal {


template<class Allocator, class NodeType>
struct base_handler {
    using allocator_type = Allocator;

  protected:
    using allocator_traits = std::allocator_traits<allocator_type>;

    using node_allocator_type = allocator_traits::template rebind_alloc<NodeType>;
    using node_allocator_traits = std::allocator_traits<node_allocator_type>;

    [[no_unique_address]] node_allocator_type _allocator;

  public:
    base_handler(const allocator_type& allocator = allocator_type()) noexcept(NO_EXCEPT)
        : _allocator(allocator)
    {}

    base_handler(const base_handler& source) noexcept(NO_EXCEPT)
        : _allocator(node_allocator_traits::select_on_container_copy_construction(source._allocator))
    {}

    base_handler(base_handler&& source) noexcept = default;

    auto& operator=(const base_handler& source) noexcept(NO_EXCEPT) {
        if(&source != this) {
            if constexpr(allocator_traits::propagate_on_container_copy_assignment::value) {
                this->_allocator = source._allocator;
            }
        }
        return *this;
    }

    auto& operator=(base_handler&& source) noexcept(NO_EXCEPT) {
        if(&source != this) {
            if constexpr(allocator_traits::propagate_on_container_move_assignment::value) {
                this->_allocator = source._allocator;
            }
        }
        return *this;
    }
};


} // namespace internal


template<class Allocator>
struct cloneable {
    template<class NodeType>
    struct handler : internal::base_handler<Allocator, NodeType> {
        using internal::base_handler<Allocator, NodeType>::base_handler;

        using node_type = NodeType;
        using node_pointer = std::shared_ptr<node_type>;

        inline static node_pointer nil = std::make_shared<node_type>();

        template<class... Args>
        inline auto create(Args&&... args) noexcept(NO_EXCEPT) {
            return std::allocate_shared<node_type>(this->_allocator, std::forward<Args>(args)...);
        }

        inline auto clone(const node_pointer& ptr) noexcept(NO_EXCEPT) {
            return this->create(*ptr);
        }

        inline constexpr bool disposable(const node_pointer&) const noexcept { return false; }
        inline constexpr void dispose(const node_pointer&) const noexcept {}
    };
};


template<class Allocator>
struct reusing {
    template<class NodeType>
    struct handler : internal::base_handler<Allocator, NodeType> {
        using node_type = NodeType;
        using node_pointer = std::add_pointer_t<node_type>;

      private:
        using base = internal::base_handler<Allocator, NodeType>;
        using node_allocator_traits = typename base::node_allocator_traits;

        inline static int _instance_count = 0;

      public:
        using base::base;

        using allocator_type = typename base::allocator_type;


        inline static node_pointer nil;


        handler(const allocator_type& allocator = allocator_type()) noexcept(NO_EXCEPT) : base(allocator) {
            if(handler::_instance_count++ == 0) {
                handler::nil = new node_type{};
            }
        }

        ~handler() noexcept {
            if(--handler::_instance_count == 0) {<--- Condition '--handler::_instance_count==0' is always true
                delete handler::nil;
            }
        }


        template<class... Args>
        inline auto create(Args&&... args) noexcept(NO_EXCEPT) {
            node_pointer node = node_allocator_traits::allocate(this->_allocator, 1);
            node_allocator_traits::construct(this->_allocator, node, std::forward<Args>(args)...);

            return node;
        }

        inline auto clone(const node_pointer ptr) const noexcept { return ptr; }

        inline bool disposable(const node_pointer node) const noexcept(NO_EXCEPT) {
            return node != handler::nil;
        }

        inline void dispose(const node_pointer node) noexcept(NO_EXCEPT) {
            node_allocator_traits::destroy(this->_allocator, node);
            node_allocator_traits::deallocate(this->_allocator, node, 1);
        }
    };
};


} // namespace node_handlers

} // namespace uni