summaryrefslogtreecommitdiff
path: root/asl/box.hpp
blob: 7556d766e0e10ac9e845eb4dba422f93ce241fc9 (plain)
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
#pragma once

#include "asl/allocator.hpp"
#include "asl/assert.hpp"
#include "asl/annotations.hpp"
#include "asl/memory.hpp"
#include "asl/utility.hpp"

namespace asl
{

template<is_object T, allocator Allocator = DefaultAllocator>
class box
{
    T* m_ptr;
    ASL_NO_UNIQUE_ADDRESS Allocator m_alloc;
    
public:
    explicit constexpr box(niche)
        requires default_constructible<Allocator>
        : m_ptr{nullptr}
        , m_alloc{}
    {}

    constexpr box(T* ptr, Allocator alloc)
        : m_ptr{ptr}
        , m_alloc{ASL_MOVE(alloc)}
    {
        ASL_ASSERT(m_ptr != nullptr);
    }

    constexpr box(box&& other)
        : m_ptr{exchange(other.m_ptr, nullptr)}
        , m_alloc{ASL_MOVE(other.m_alloc)}
    {}

    constexpr box& operator=(box&& other)
    {
        if (this == &other) { return *this; }

        if (m_ptr != nullptr) { reset(); }

        m_ptr = exchange(other.m_ptr, nullptr);
        m_alloc = ASL_MOVE(other.m_alloc);

        return *this;
    }

    box(const box&) = delete;
    box& operator=(const box&) = delete;

    constexpr ~box()
    {
        reset();
    }

    constexpr void reset()
    {
        if (m_ptr != nullptr)
        {
            if constexpr (!trivially_destructible<T>)
            {
                m_ptr->~T();
            }
            m_alloc.dealloc(m_ptr, layout::of<T>());
            m_ptr = nullptr;
        }
    }

    constexpr T* get() const { return m_ptr; }

    constexpr T& operator*() const
    {
        ASL_ASSERT(m_ptr != nullptr);
        return *m_ptr;
    }

    constexpr T* operator->() const
    {
        ASL_ASSERT(m_ptr != nullptr);
        return m_ptr;
    }

    constexpr bool operator==(niche) const
    {
        return m_ptr == nullptr;
    }
};

template<is_object T, allocator Allocator = DefaultAllocator, typename... Args>
constexpr box<T, Allocator> make_box_in(Allocator allocator, Args&&... args)
    requires constructible_from<T, Args&&...>
{
    void* raw_ptr = allocator.alloc(layout::of<T>());
    T* ptr = new (raw_ptr) T(ASL_FWD(args)...);
    return box(ptr, ASL_MOVE(allocator));
}

template<is_object T, allocator Allocator = DefaultAllocator, typename... Args>
constexpr box<T, Allocator> make_box(Args&&... args)
    requires default_constructible<Allocator> && constructible_from<T, Args&&...>
{
    Allocator allocator{};
    void* raw_ptr = allocator.alloc(layout::of<T>());
    T* ptr = new (raw_ptr) T{ ASL_FWD(args)... };
    return box<T>(ptr, ASL_MOVE(allocator));
}

} // namespace asl