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
|