2 * Copyright (C) 2011 Max Kellermann <max@duempel.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 #ifndef XCSOAR_SLICE_ALLOCATOR_HPP
31 #define XCSOAR_SLICE_ALLOCATOR_HPP
38 * An optimized allocator for many objects of the same size. It is
39 * extremely efficient at allocating single objects, but never frees
40 * up memory to the system heap until it is destructed completely.
41 * Released slots will be reused, though.
43 * Limitation: this allocator refuses to allocate more than one
46 * @param T the type that is wrapped by this allocator
47 * @param size the number of objects for each area
49 template<typename T
, unsigned size
>
50 class SliceAllocator
{
52 typedef std::size_t size_type
;
55 typedef const T
*const_pointer
;
57 typedef const T
&const_reference
;
61 typedef SliceAllocator
<O
, size
> other
;
66 * One allocated item in the heap. When it is on the "available"
67 * list, the "next" attribute points to the next available slot.
68 * When it is in use, the whole object is casted statically to "T".
73 char padding
[sizeof(T
) - sizeof(void *)];
77 * One area holds a certain number of slots. When all areas are
78 * full, a new one is allocated, but empty areas are never freed.
88 unsigned num_available
;
92 :next(nullptr), available(&items
[0])
97 for (unsigned i
= 0; i
< size
- 1; ++i
)
98 items
[i
].next
= &items
[i
+ 1];
99 items
[size
- 1].next
= nullptr;
103 assert(num_available
== size
);
107 if (available
== nullptr)
111 available
= available
->next
;
114 assert(num_available
> 0);
121 bool deallocate(Item
*i
) {
122 if (i
< &items
[0] || i
>= &items
[size
])
138 * A linked list of areas.
144 SliceAllocator():head(nullptr) {}
147 SliceAllocator(const SliceAllocator
&other
):head(nullptr) {}
150 while (head
!= nullptr) {
157 T
*allocate(const size_type n
) {
160 /* try to allocate in one of the existing areas */
163 for (area
= head
; area
!= nullptr; area
= area
->next
) {
164 Item
*i
= area
->allocate();
166 return static_cast<T
*>(static_cast<void *>(i
));
169 /* no room, create a new Area and insert it into the linked list */
179 /* allocate from the new area */
181 Item
*i
= area
->allocate();
182 return static_cast<T
*>(static_cast<void *>(i
));
185 void deallocate(T
*t
, const size_type n
) {
188 Item
*i
= static_cast<Item
*>(static_cast<void *>(t
));
190 for (Area
*area
= head
;; area
= area
->next
) {
191 assert(area
!= nullptr);
193 if (area
->deallocate(i
))
200 template<typename U
, typename
... Args
>
201 void construct(U
*p
, Args
&&... args
) {
202 ::new((void *)p
) U(std::forward
<Args
>(args
)...);
211 * This allocator refers to one global SliceAllocator, instead of
212 * creating a new SliceAllocator for each container.
214 * @param T the type that is wrapped by this allocator
215 * @param size the number of objects for each area
217 template<typename T
, unsigned size
>
218 class GlobalSliceAllocator
{
219 typedef SliceAllocator
<T
, size
> Allocator
;
221 static Allocator allocator
;
224 typedef size_t size_type
;
225 typedef T value_type
;
227 typedef const T
*const_pointer
;
228 typedef T
&reference
;
229 typedef const T
&const_reference
;
233 typedef GlobalSliceAllocator
<O
, size
> other
;
237 GlobalSliceAllocator() = default;
241 GlobalSliceAllocator(const GlobalSliceAllocator
<U
, size
> &_other
) {}
243 T
*allocate(const size_type n
) {
244 return allocator
.allocate(n
);
247 void deallocate(T
*t
, const size_type n
) {
248 allocator
.deallocate(t
, n
);
251 template<typename U
, typename
... Args
>
252 void construct(U
*p
, Args
&&... args
) {
253 allocator
.construct(p
, std::forward
<Args
>(args
)...);
257 allocator
.destroy(t
);