Repository navigation
Expand file tree
/
Copy pathcookie_allocator.h
More file actions
187 lines (172 loc) · 7.13 KB
/
Copy pathcookie_allocator.h
File metadata and controls
187 lines (172 loc) · 7.13 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#pragma once
#include <memory>
#include <type_traits>
namespace Yc
{
template<class T, class Cookie>
class value_with_cookie
{
static_assert(std::is_trivially_copyable_v<Cookie> && std::is_trivially_constructible_v<Cookie>);
union u_t
{
T value;
~u_t() {}
}u;
mutable Cookie cookie_value{};
public:
T& value()noexcept
{
return u.value;
}
const T& value()const noexcept
{
return u.value;
}
Cookie& cookie()const noexcept
{
return cookie_value;
}
};
template<class Cookie>
struct cookie_wrapper
{
Cookie cookie{};
};
// 主模板
template<class Allocator ,class = void>
class allocator_with_cookie_base
{
public:
allocator_with_cookie_base() = default;
allocator_with_cookie_base(const Allocator&)noexcept
{
}
static Allocator get_allocator()noexcept
{
return {};
}
};
// 有状态分配器的特化
template<class Allocator>
class allocator_with_cookie_base
<
Allocator,
std::void_t<std::enable_if_t<!std::allocator_traits<Allocator>::is_always_equal::value>>
>
{
Allocator alloc{};
public:
allocator_with_cookie_base() = default;
allocator_with_cookie_base(const Allocator& a)noexcept :alloc{a}
{
}
Allocator& get_allocator()noexcept
{
return alloc;
}
const Allocator& get_allocator()const noexcept
{
return alloc;
}
};
// 从一般的分配器制作value_with_cookie类型的分配器
// 其中 U 默认是value_with_cookie<typename std::allocator_traits<Allocator>::value_type, Cookie>
// 也就是外层容器的value_with_cookie<T, Cookie>
template<class U, class Allocator, class Cookie>
class allocator_with_cookie : public allocator_with_cookie_base<Allocator>
{
// 如果是原分配器的带cookie的分配器,那么为true
static constexpr inline bool is_cookie_allocator =
std::is_same_v<U, value_with_cookie<typename std::allocator_traits<Allocator>::value_type, Cookie>>;
using infact_allocator = std::allocator_traits<Allocator>::template rebind_alloc<U>;
public:
template<class T>
allocator_with_cookie(const allocator_with_cookie<T, Allocator, Cookie>& a)noexcept :allocator_with_cookie_base<Allocator>{a.get_allocator()}
{
}
using allocator_with_cookie_base<Allocator>::allocator_with_cookie_base;
using pointer = std::allocator_traits<infact_allocator>::pointer;
using const_pointer = std::allocator_traits<infact_allocator>::const_pointer;
using void_pointer = std::allocator_traits<infact_allocator>::void_pointer;
using const_void_pointer = std::allocator_traits<infact_allocator>::const_void_pointer;
using value_type = U;
using size_type = std::allocator_traits<infact_allocator>::size_type;
using difference_type = std::allocator_traits<infact_allocator>::difference_type;
using propagate_on_container_copy_assignment = std::allocator_traits<infact_allocator>::propagate_on_container_copy_assignment;
using propagate_on_container_move_assignment = std::allocator_traits<infact_allocator>::propagate_on_container_move_assignment;
using propagate_on_container_swap = std::allocator_traits<infact_allocator>::propagate_on_container_swap;
// rebind由allocator_traits自动化处理,这里不提供
allocator_with_cookie select_on_container_copy_construction()noexcept
{
auto&& alloc = this->get_allocator();
return { std::allocator_traits<Allocator>::select_on_container_copy_construction(alloc) };
}
auto allocate(size_type n)
{
infact_allocator alloc = this->get_allocator();
return std::allocator_traits<infact_allocator>::allocate(alloc, n);
}
auto allocate(size_type n, const_void_pointer cvp)
{
infact_allocator alloc = this->get_allocator();
return std::allocator_traits<infact_allocator>::allocate(alloc, n, cvp);
}
auto allocate_at_least(size_type n)
{
infact_allocator alloc = this->get_allocator();
return std::allocator_traits<infact_allocator>::allocate_at_least(alloc, n);
}
void deallocate(pointer p, size_type n)noexcept
{
infact_allocator alloc = this->get_allocator();
std::allocator_traits<infact_allocator>::deallocate(alloc, p, n);
}
auto max_size()const noexcept
{
infact_allocator alloc = this->get_allocator();
return std::allocator_traits<infact_allocator>::max_size(alloc);
}
template<class T, class... Args>
void construct(T* xp, Args&&... args)
{
if constexpr (is_cookie_allocator && std::is_same_v<T, U>)
{
auto&& alloc = this->get_allocator();
value_with_cookie<typename std::allocator_traits<Allocator>::value_type, Cookie>* p = xp;
std::allocator_traits<Allocator>::construct(alloc, std::addressof(p->value()), std::forward<Args>(args)...);
}
else
{
typename std::allocator_traits<Allocator>::template rebind_alloc<T> alloc{ this->get_allocator() };
std::allocator_traits<Allocator>::template rebind_traits<T>::construct(alloc, xp, std::forward<Args>(args)...);
}
}
template<class T, class Arg>
void construct(T* xp, std::pair<cookie_wrapper<Cookie>, Arg> arg)
{
if constexpr (is_cookie_allocator && std::is_same_v<T, U>)
{
auto&& alloc = this->get_allocator();
value_with_cookie<typename std::allocator_traits<Allocator>::value_type, Cookie>* p = xp;
std::allocator_traits<Allocator>::construct(alloc, std::addressof(p->value()), std::forward<Arg>(arg.second));
p->cookie() = arg.first.cookie;
}
}
template<class T>
void destroy(T* xp)
{
if constexpr (is_cookie_allocator && std::is_same_v<T, U>)
{
auto&& alloc = this->get_allocator();
value_with_cookie<typename std::allocator_traits<Allocator>::value_type, Cookie>* p = xp;
std::allocator_traits<Allocator>::destroy(alloc, std::addressof(p->value()));
}
else
{
typename std::allocator_traits<Allocator>::template rebind_alloc<T> alloc{ this->get_allocator() };
std::allocator_traits<Allocator>::template rebind_traits<T>::destroy(alloc, xp);
}
}
friend bool operator==(allocator_with_cookie, allocator_with_cookie) = default;
};
}