Bond
 
Loading...
Searching...
No Matches
capped_allocator.h
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#pragma once
5
6#include <bond/core/config.h>
7
8#include "capped_allocator_fwd.h"
9#include "detail/value_or_reference.h"
10#include "multi_threaded_counter.h"
11#include "shared_counter.h"
12#include "single_threaded_counter.h"
13
14#include <bond/core/detail/alloc.h>
15
16#include <boost/utility/enable_if.hpp>
17
18namespace bond { namespace ext
19{
20 namespace detail
21 {
23 template <typename Alloc, typename Enable = void>
25
27 template <typename Alloc>
28 struct allocator_reference_type_workaround<Alloc, typename boost::enable_if_c<
29 !std::is_void<typename Alloc::value_type>::value
30 && !(std::is_void<typename Alloc::reference>::value
31 || std::is_void<typename Alloc::const_reference>::value)>::type>
32 {
33 using reference = typename Alloc::reference;
34 using const_reference = typename Alloc::const_reference;
35 };
36
38 template <typename Alloc>
39 struct allocator_reference_type_workaround<Alloc, typename boost::enable_if_c<
40 !std::is_void<typename Alloc::value_type>::value
41 && (std::is_void<typename Alloc::reference>::value
42 || std::is_void<typename Alloc::const_reference>::value)>::type>
43 {
44 using reference = typename Alloc::value_type&;
45 using const_reference = const typename Alloc::value_type&;
46 };
47
49 template <typename Alloc>
50 struct allocator_reference_type_workaround<Alloc, typename boost::enable_if<
51 std::is_void<typename Alloc::value_type>>::type>
52 {
53 using reference = void;
54 using const_reference = void;
55 };
56
57 } // namespace detail
58
59
68 template <typename Alloc, typename Counter>
70 {
71 using holder = typename capped_allocator::allocator_holder;
72 using traits = std::allocator_traits<Alloc>;
73
74 public:
75 using value_type = typename traits::value_type;
76 using pointer = typename traits::pointer;
77 using const_pointer = typename traits::const_pointer;
78 using void_pointer = typename traits::void_pointer;
79 using const_void_pointer = typename traits::const_void_pointer;
82 using size_type = typename traits::size_type;
83 using difference_type = typename traits::difference_type;
84 using propagate_on_container_copy_assignment = typename traits::propagate_on_container_copy_assignment;
85 using propagate_on_container_move_assignment = typename traits::propagate_on_container_move_assignment;
86 using propagate_on_container_swap = typename traits::propagate_on_container_swap;
87#if __cplusplus >= 201703L
88 using is_always_equal = typename traits::is_always_equal;
89#endif
90
91 template <typename U>
92 struct rebind
93 {
95 };
96
97
121 const Alloc& alloc = {},
122 bool subtract_on_deallocate = true)
123 : holder{ alloc },
124 _count{ count },
125 _subtract_on_deallocate{ subtract_on_deallocate }
126 {}
127
139 template <typename C = Counter,
140 typename boost::enable_if<std::uses_allocator<C, Alloc>>::type* = nullptr>
142 typename C::value_type max_value,
143 const Alloc& alloc = {},
144 bool subtract_on_deallocate = true)
145 : capped_allocator{ Counter{ max_value, alloc }, alloc, subtract_on_deallocate }
146 {}
147
149 template <typename OtherAlloc,
150 typename boost::enable_if<std::is_convertible<OtherAlloc, Alloc>>::type* = nullptr>
152 : capped_allocator{ other._count, other.get_allocator(), other._subtract_on_deallocate }
153 {}
154
155 pointer allocate(size_type n)
156 {
157 const auto size = n * sizeof(value_type);
158
159 if (_count.get().try_add(size))
160 {
161 try
162 {
163 return traits::allocate(get_allocator(), n);
164 }
165 catch (...)
166 {
167 _count.get().subtract(size);
168 throw;
169 }
170 }
171
172 throw std::bad_alloc{};
173 }
174
175 pointer allocate(size_type n, const_void_pointer hint)
176 {
177 const auto size = n * sizeof(value_type);
178
179 if (_count.get().try_add(size))
180 {
181 try
182 {
183 return traits::allocate(get_allocator(), n, hint);
184 }
185 catch (...)
186 {
187 _count.get().subtract(size);
188 throw;
189 }
190 }
191
192 throw std::bad_alloc{};
193 }
194
195 void deallocate(pointer ptr, size_type n)
196 {
197 traits::deallocate(get_allocator(), ptr, n);
198
199 if (_subtract_on_deallocate)
200 {
201 _count.get().subtract(n * sizeof(value_type));
202 }
203 }
204
205 template <typename T, typename... Args>
206 void construct(T* ptr, Args&&... args)
207 {
208 traits::construct(get_allocator(), ptr, std::forward<Args>(args)...);
209 }
210
211 template <typename T>
212 void destroy(T* ptr)
213 {
214 traits::destroy(get_allocator(), ptr);
215 }
216
217 size_type max_size() const BOND_NOEXCEPT
218 {
219 return (std::min)(
220 _count.get().max_value() / sizeof(value_type),
221 traits::max_size(get_allocator()));
222 }
223
224 capped_allocator select_on_container_copy_construction()
225 {
226 return capped_allocator{
227 _count,
228 traits::select_on_container_copy_construction(get_allocator()),
229 _subtract_on_deallocate };
230 }
231
232 const Alloc& get_allocator() const BOND_NOEXCEPT
233 {
234 return holder::get();
235 }
236
237 Alloc& get_allocator() BOND_NOEXCEPT
238 {
239 return holder::get();
240 }
241
242 const Counter& get_counter() const BOND_NOEXCEPT
243 {
244 return _count.get();
245 }
246
247 Counter& get_counter() BOND_NOEXCEPT
248 {
249 return _count.get();
250 }
251
252 private:
253 template <typename OtherAlloc, typename OtherCounter>
254 friend class capped_allocator;
255
256 detail::value_or_reference<Counter> _count;
257 bool _subtract_on_deallocate;
258 };
259
260
261 template <typename Alloc, typename Counter>
262 inline bool operator==(
263 const capped_allocator<Alloc, Counter>& a1,
264 const capped_allocator<Alloc, Counter>& a2) BOND_NOEXCEPT
265 {
266 return a1.get_allocator() == a2.get_allocator();
267 }
268
269 template <typename Alloc, typename Counter>
270 inline bool operator!=(
271 const capped_allocator<Alloc, Counter>& a1,
272 const capped_allocator<Alloc, Counter>& a2) BOND_NOEXCEPT
273 {
274 return a1.get_allocator() != a2.get_allocator();
275 }
276
277} } // namespace bond::ext
Helper type that holds an allocator.
Definition: alloc.h:22
Definition: capped_allocator.h:70
capped_allocator(const capped_allocator< OtherAlloc, Counter > &other)
Converts from a compatible allocator.
Definition: capped_allocator.h:151
capped_allocator(detail::value_or_reference< Counter > count, const Alloc &alloc={}, bool subtract_on_deallocate=true)
Constructs capped allocator adapter.
Definition: capped_allocator.h:119
capped_allocator(typename C::value_type max_value, const Alloc &alloc={}, bool subtract_on_deallocate=true)
Constructs capped allocator adapter.
Definition: capped_allocator.h:141
Helper type that can hold either a value or a reference.
Definition: value_or_reference.h:20
namespace bond
Definition: apply.h:17
boost::enable_if< is_signed_int_or_enum< SignedT >, bool >::type operator==(const Variant &variant, SignedT value)
Compares variant for equality against the provided signed integer or enum value.
Definition: metadata.h:24
Helper type to deal with types that are not C++11 conformant.
Definition: capped_allocator.h:24