22 namespace Transactional {
24 enum {mempool_max_size = 4};
25 struct MemoryPool :
public std::array<atomic<void*>, mempool_max_size> {
27 std::fill(this->begin(), this->end(),
nullptr);
31 for(
auto &&x: *
this) {
32 operator delete((
void*)x);
41 typedef size_t size_type;
42 typedef ptrdiff_t difference_type;
44 typedef const T* const_pointer;
46 typedef const T& const_reference;
57 template<
typename Y> allocator(
const allocator<Y> &x) noexcept : m_pool(x.m_pool) {}
62 unsigned int pool_size()
const {
63 return std::min((
int)mempool_max_size, std::max(4, 256 / (
int)
sizeof(T)));
65 pointer allocate(size_type num,
const void * = 0) {
66 for(
unsigned int i = 0; i < pool_size(); ++i) {
67 auto &x = (*m_pool)[i];
68 void *ptr = x.exchange(
nullptr);
72 return static_cast<pointer
>(ptr);
75 return (pointer) (
operator new(num *
sizeof(T)));
77 template <
class U,
class... Args>
78 void construct(U* p, Args&&... args) {
79 new((
void*) p) U(std::forward<Args>(args)...);
82 void deallocate(pointer ptr, size_type ) {
84 for(
unsigned int i = 0; i < pool_size(); ++i) {
85 auto &x = (*m_pool)[i];
100 pointer address(reference value)
const noexcept {
103 const_pointer address(const_reference value)
const noexcept {
107 size_type max_size() const noexcept {
108 return std::numeric_limits<size_t>::max() /
sizeof(T);
111 template <
typename Y>
friend class allocator;
115 template <
class T1,
class T2>
116 bool operator==(
const allocator<T1>&,
const allocator<T2>&) noexcept {
120 template <
class T1,
class T2>
121 bool operator!=(
const allocator<T1>&,
const allocator<T2>&) noexcept {
125 template <
typename T,
int max_fixed_size = 4>
128 using reference = T&;
129 using const_reference =
const T&;
130 using size_type = size_t;
132 using const_pointer =
const T*;
133 using iterator = pointer;
134 using const_iterator = const_pointer;
138 if(size > max_fixed_size) {
139 new (&m_vector) std::vector<T>(size);
140 m_size = HAS_STD_VECTOR;
143 for(size_type i = 0; i < size; ++i)
144 new (m_array + i) T();
152 this->operator=(std::move(r));
158 for(size_type i = 0; i < m_size; ++i) {
159 new (m_array + i) T(r.m_array[i]);
162 else if(r.m_vector.size() <= max_fixed_size) {
163 m_size = r.m_vector.size();
164 for(size_type i = 0; i < m_size; ++i) {
165 new (m_array + i) T(r.m_vector[i]);
169 m_size = HAS_STD_VECTOR;
170 new (&m_vector) std::vector<T>(r.m_vector);
178 for(size_type i = 0; i < m_size; ++i) {
179 new (m_array + i) T(std::move(r.m_array[i]));
184 m_size = HAS_STD_VECTOR;
185 new (&m_vector) std::vector<T>(std::move(r.m_vector));
189 iterator begin() noexcept {
return is_fixed() ? &m_array[0] : &m_vector[0];}
190 const_iterator begin()
const noexcept {
return is_fixed() ? &m_array[0] : &m_vector[0];}
191 iterator end() noexcept {
return is_fixed() ? &m_array[m_size] : &m_vector[m_vector.size()];}
192 const_iterator end()
const noexcept {
return is_fixed() ? &m_array[m_size] : &m_vector[m_vector.size()];}
193 size_type size()
const noexcept {
return is_fixed() ? m_size : m_vector.size();}
194 bool empty()
const noexcept {
return !size();}
195 reference operator[](size_type n) {
return is_fixed() ? m_array[n] : m_vector[n];}
196 const_reference operator[](size_type n)
const {
return is_fixed() ? m_array[n] : m_vector[n];}
197 const_reference at(size_type n)
const {
if(n >= size())
throw std::out_of_range(
"");
return (*
this)[n];}
198 reference at(size_type n) {
if(n >= size())
throw std::out_of_range(
"");
return (*
this)[n];}
199 reference front() {
return is_fixed() ? m_array.front() : m_vector.front();}
200 const_reference front()
const {
return is_fixed() ? m_array.front() : m_vector.front();}
201 reference back() {
return (*
this)[this->size() - 1];}
202 const_reference back()
const {
return (*
this)[this->size() - 1];}
203 void push_back(
const T& x) {
206 void push_back(T&& x) {
207 emplace_back(std::move(x));
209 template <
class... Args>
210 void emplace_back(Args&&... args) {
211 if(m_size < max_fixed_size) {
212 new (m_array + m_size) T(std::forward<Args>(args)...);
216 if(m_size == max_fixed_size) {
217 move_fixed_to_var(m_size);
219 m_vector.emplace_back(std::forward<Args>(args)...);
222 iterator erase(const_iterator position) {
224 for(
auto it = const_cast<iterator>(position);;) {
231 *it = std::move(*nit);
235 return const_cast<iterator
>(position);
238 auto it = m_vector.erase(m_vector.begin() + (position - begin()));
251 void resize(size_type sz) {
253 if(sz > max_fixed_size) {
254 move_fixed_to_var(sz);
257 for(size_type i = m_size; i < sz; ++i)
258 new (m_array + i) T();
259 for(size_type i = sz; i < m_size; ++i)
269 void shrink_to_fit() {
270 if( !is_fixed())
return;
271 if(m_vector.capacity() - m_vector.size() > max_fixed_size) {
272 m_vector.shrink_to_fit();
281 bool is_fixed()
const noexcept {
return m_size != (size_type)HAS_STD_VECTOR;}
282 void clear_fixed() noexcept {
284 for(size_type i = 0; i < m_size; ++i)
288 void move_fixed_to_var(size_type new_size) {
291 for(size_type i = 0; i < m_size; ++i) {
292 tmp.emplace_back(std::move(m_array[i]));
295 new (&m_vector) std::vector<T>();
296 m_vector.reserve(std::max(new_size, (size_type)(max_fixed_size * 2)));
297 assert(new_size >= m_size);
299 m_vector.emplace_back(std::move(x));
300 m_vector.resize(new_size);
301 m_size = HAS_STD_VECTOR;
304 enum : size_type {HAS_STD_VECTOR = (size_type)-1};
306 T m_array[max_fixed_size];
307 std::vector<T> m_vector;