this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Filip Konvicka <filip.konvicka@logis.cz>
5 *
6 * Copyright:
7 * LOGIS, s.r.o., 2009
8 *
9 * Bugfixes provided by:
10 * Gustavo Gutierrez
11 *
12 * This file is part of Gecode, the generic constraint
13 * development environment:
14 * http://www.gecode.org
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining
17 * a copy of this software and associated documentation files (the
18 * "Software"), to deal in the Software without restriction, including
19 * without limitation the rights to use, copy, modify, merge, publish,
20 * distribute, sublicense, and/or sell copies of the Software, and to
21 * permit persons to whom the Software is furnished to do so, subject to
22 * the following conditions:
23 *
24 * The above copyright notice and this permission notice shall be
25 * included in all copies or substantial portions of the Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 */
35
36#include <limits>
37
38namespace Gecode {
39
40 template<class T> struct space_allocator;
41
42/**
43
44\defgroup FuncMemAllocator Using allocators with Gecode
45\ingroup FuncMem
46
47%Gecode provides two allocator classes that can be used with
48generic data structures such as those of the STL
49(e.g. <tt>std::set</tt>). Memory can be allocated from the space heap
50(see Space) or from a region (see Region).
51
52\section FuncMemAllocatorA Using allocators with dynamic data structures
53
54There are two possible scenarios for allocator usage. One is to
55let the dynamic data structure allocate memory from the space or
56region:
57
58\code
59struct MySpace : public Space {
60 typedef std::set<int, std::less<int>, Gecode::space_allocator<int> > S;
61 S safe_set;
62
63 MySpace(void)
64 : safe_set(S::key_compare(), S::allocator_type(*this))
65 {}
66
67 MySpace(bool share, MySpace& other)
68 : Space(share, other),
69 safe_set(other.safe_set.begin(), other.safe_set.end(),
70 S::key_compare(), S::allocator_type(*this))
71 {}
72
73 ...
74};
75\endcode
76
77In this example, \a S is a set that allocates its nodes from the
78space heap. Note that we pass an instance of space_allocator
79bound to this space to the constructor of the set. A similar
80thing must be done in the copying constructor, where we must be
81sure to pass an allocator that allocates memory from the
82destination ("this") space, not "other". Note that the set
83itself is a member of \a MySpace, so it is destroyed within
84<i>MySpace::~MySpace</i> as usual. The set destructor destroys
85all contained items and deallocates all nodes in its destructors.
86
87\section FuncMemAllocatorB Preventing unnecessary destruction overhead
88
89In the above example, we know that the value type in \a S is a
90builtin type and does not have a destructor. So what happens
91during \a safe_set destruction is that it just deallocates all
92nodes. However, we know that all nodes were allocated from the
93space heap, which is going to disappear with the space anyway.
94If we prevent calling \a safe_set destructor, we may save a
95significant amount of time during space destruction. A safe way
96of doing this is to allocate the set object itself on the space
97heap, and keep only a reference to it as a member of the
98space. We can use the convenience helpers Space::construct for
99the construction.
100
101\code
102struct MySpace : public Space {
103 typedef std::set<int, std::less<int>, Gecode::space_allocator<int> > S;
104 S& fast_set;
105
106 MySpace(void)
107 : fast_set(construct<S>(S::key_compare(), S::allocator_type(*this)))
108 {}
109
110 MySpace(MySpace& other)
111 : Space(other),
112 fast_set(construct<S>(other.safe_set.begin(), other.safe_set.end(),
113 S::key_compare(), S::allocator_type(*this)))
114 {}
115
116 ...
117};
118\endcode
119
120\section FuncMemAllocatorC Region example
121
122The above examples were using a space_allocator. A region_allocator
123works similarly, one just should keep in mind that regions never
124really release any memory. Similar to Space, Region provides
125helper functions Region::construct to make non-stack allocation
126easy.
127
128\code
129Space& home = ...;
130typedef std::set<int, std::less<int>, Gecode::region_allocator<int> > SR;
131// Create a set with the region allocator. Note that the set destructor is still quite costly...
132{
133 Region r;
134 SR r_safe_set(SR::key_compare(), (SR::allocator_type(r)));
135 for(int i=0; i<10000; ++i)
136 r_safe_set.insert(i*75321%10000);
137}
138// Create a set directly in the region (not on the stack). No destructors will be called.
139{
140 Region r;
141 SR& r_fast_set=r.construct<SR>(SR::key_compare(), SR::allocator_type(r));
142 for(int i=0; i<10000; ++i)
143 r_fast_set.insert(i*75321%10000);
144}
145\endcode
146
147*/
148
149
150 /**
151 * \brief %Space allocator - specialization for \c void.
152 *
153 * The specialization is needed as the default instantiation fails
154 * for \c void.
155 */
156 template<>
157 struct space_allocator<void> {
158 typedef void* pointer;
159 typedef const void* const_pointer;
160 typedef void value_type;
161 /// Rebinding helper (returns the type of a similar allocator for type \a U)
162 template<class U> struct rebind {
163 typedef space_allocator<U> other;
164 };
165 };
166
167 /**
168 * \brief Allocator that allocates memory from a space heap
169 *
170 * Note that this allocator may be used to construct dynamic
171 * data structures that allocate memory from the space heap,
172 * or even reside in the space heap as a whole.
173 *
174 * \ingroup FuncMemAllocator
175 */
176 template<class T>
177 struct space_allocator {
178 /// Type of objects the allocator creates. This is identical to \a T.
179 typedef T value_type;
180 /// Type that can represent the size of the largest object.
181 typedef size_t size_type;
182 /// Type that can represent the difference between any two pointers.
183 typedef ptrdiff_t difference_type;
184 /// Type of pointers returned by the allocator.
185 typedef T* pointer;
186 /// Const version of pointer.
187 typedef T const* const_pointer;
188 /// Non-const reference to \a T.
189 typedef T& reference;
190 /// Const reference to \a T.
191 typedef T const& const_reference;
192 /// Rebinding helper (returns the type of a similar allocator for type \a U).
193 template<class U> struct rebind {
194 /// The allocator type for \a U
195 typedef space_allocator<U> other;
196 };
197
198 /// The space that we allocate objects from
199 Space& space;
200
201 /**
202 * \brief Construction
203 * @param space The space whose heap to allocate objects from.
204 */
205 space_allocator(Space& space) noexcept : space(space) {}
206 /**
207 * \brief Copy construction
208 * @param al The allocator to copy.
209 */
210 space_allocator(space_allocator const& al) noexcept : space(al.space) {}
211 /**
212 * \brief Assignment operator
213 * @param al The allocator to assign.
214 */
215 space_allocator& operator =(space_allocator const& al) {
216 (void) al;
217 assert(&space == &al.space);
218 return *this;
219 }
220 /**
221 * \brief Copy from other instantiation
222 * @param al The source allocator.
223 */
224 template<class U>
225 space_allocator(space_allocator<U> const& al) noexcept : space(al.space) {}
226
227 /// Convert a reference \a x to a pointer
228 pointer address(reference x) const { return &x; }
229 /// Convert a const reference \a x to a const pointer
230 const_pointer address(const_reference x) const { return &x; }
231 /// Returns the largest size for which a call to allocate might succeed.
232 size_type max_size(void) const noexcept {
233 return std::numeric_limits<size_type>::max() /
234 (sizeof(T)>0 ? sizeof(T) : 1);
235 }
236 /**
237 * \brief Allocates storage
238 *
239 * Returns a pointer to the first element in a block of storage
240 * <tt>count*sizeof(T)</tt> bytes in size. The block is aligned
241 * appropriately for objects of type \a T. Throws the exception
242 * \a bad_alloc if the storage is unavailable.
243 */
244 pointer allocate(size_type count) {
245 return static_cast<pointer>(space.ralloc(sizeof(T)*count));
246 }
247
248 /**
249 * \brief Allocates storage
250 *
251 * Returns a pointer to the first element in a block of storage
252 * <tt>count*sizeof(T)</tt> bytes in size. The block is aligned
253 * appropriately for objects of type \a T. Throws the exception
254 * \a bad_alloc if the storage is unavailable.
255 * The (unused) parameter could be used as an allocation hint,
256 * but this allocator ignores it.
257 */
258 pointer allocate(size_type count, const void * const hint) {
259 (void) hint;
260 return allocate(count);
261 }
262
263 /// Deallocates the storage obtained by a call to allocate() with arguments \a count and \a p.
264 void deallocate(pointer p, size_type count) {
265 space.rfree(static_cast<void*>(p), count);
266 }
267
268 /*
269 * \brief Constructs an object
270 *
271 * Constructs an object of type \a T with the initial value of \a t
272 * at the location specified by \a element. This function calls
273 * the <i>placement new()</i> operator.
274 */
275 void construct(pointer element, const_reference t) {
276 new (element) T(t);
277 }
278
279 /// Calls the destructor on the object pointed to by \a element.
280 void destroy(pointer element) {
281 element->~T();
282 }
283 };
284
285 /**
286 * \brief Tests two space allocators for equality
287 *
288 * Two allocators are equal when each can release storage allocated
289 * from the other.
290 */
291 template<class T1, class T2>
292 bool operator==(space_allocator<T1> const& al1,
293 space_allocator<T2> const& al2) noexcept {
294 return &al1.space == &al2.space;
295 }
296
297 /**
298 * \brief Tests two space allocators for inequality
299 *
300 * Two allocators are equal when each can release storage allocated
301 * from the other.
302 */
303 template<class T1, class T2>
304 bool operator!=(space_allocator<T1> const& al1,
305 space_allocator<T2> const& al2) noexcept {
306 return &al1.space != &al2.space;
307 }
308
309
310 template<class T> struct region_allocator;
311
312 /**
313 * \brief %Region allocator - specialization for \c void.
314 *
315 * The specialization is needed as the default instantiation fails
316 * for \c void.
317 */
318 template<>
319 struct region_allocator<void> {
320 typedef void* pointer;
321 typedef const void* const_pointer;
322 typedef void value_type;
323 /// Rebinding helper (returns the type of a similar allocator for type \a U)
324 template<class U> struct rebind {
325 typedef region_allocator<U> other;
326 };
327 };
328
329 /**
330 * \brief Allocator that allocates memory from a region
331 *
332 * Note that this allocator may be used to construct dynamic data structures
333 * that allocate memory from the region, or even reside in the region as a whole.
334 *
335 * \ingroup FuncMemAllocator
336 */
337 template<class T>
338 struct region_allocator {
339 /// Type of objects the allocator creates. This is identical to \a T.
340 typedef T value_type;
341 /// Type that can represent the size of the largest object.
342 typedef size_t size_type;
343 /// Type that can represent the difference between any two pointers.
344 typedef ptrdiff_t difference_type;
345 /// Type of pointers returned by the allocator.
346 typedef T* pointer;
347 /// Const version of pointer.
348 typedef T const* const_pointer;
349 /// Non-const reference to \a T.
350 typedef T& reference;
351 /// Const reference to \a T.
352 typedef T const& const_reference;
353
354 /// Rebinding helper (returns the type of a similar allocator for type \a U).
355 template<class U> struct rebind {
356 /// The allocator type for \a U
357 typedef region_allocator<U> other;
358 };
359
360 /// The region that we allocate objects from
361 Region& region;
362
363 /**
364 * \brief Construction
365 * @param region The region to allocate objects from.
366 */
367 region_allocator(Region& region) noexcept
368 : region(region) {}
369 /**
370 * \brief Copy construction
371 * @param al The allocator to copy.
372 */
373 region_allocator(region_allocator const& al) noexcept
374 : region(al.region) {}
375 /**
376 * \brief Copy from other instantiation.
377 * @param al The source allocator.
378 */
379 template<class U>
380 region_allocator(region_allocator<U> const& al) noexcept
381 : region(al.region) {}
382
383 /// Convert a reference \a x to a pointer
384 pointer address(reference x) const { return &x; }
385 /// Convert a const reference \a x to a const pointer
386 const_pointer address(const_reference x) const { return &x; }
387 /// Returns the largest size for which a call to allocate might succeed.
388 size_type max_size(void) const noexcept {
389 return std::numeric_limits<size_type>::max()
390 / (sizeof(T)>0 ? sizeof(T) : 1);
391 }
392
393 /**
394 * \brief Allocates storage
395 *
396 * Returns a pointer to the first element in a block of storage
397 * <tt>count*sizeof(T)</tt> bytes in size. The block is aligned
398 * appropriately for objects of type \a T. Throws the exception
399 * \a bad_alloc if the storage is unavailable.
400 */
401 pointer allocate(size_type count) {
402 return static_cast<pointer>(region.ralloc(sizeof(T)*count));
403 }
404
405 /**
406 * \brief Allocates storage
407 *
408 * Returns a pointer to the first element in a block of storage
409 * <tt>count*sizeof(T)</tt> bytes in size. The block is aligned
410 * appropriately for objects of type \a T. Throws the exception
411 * \a bad_alloc if the storage is unavailable.
412 *
413 * The (unused) parameter could be used as an allocation hint,
414 * but this allocator ignores it.
415 */
416 pointer allocate(size_type count, const void * const hint) {
417 (void) hint;
418 return allocate(count);
419 }
420
421 /**
422 * \brief Deallocates storage
423 *
424 * Deallocates storage obtained by a call to allocate() with
425 * arguments \a count and \a p. Note that region allocator never
426 * actually deallocates memory (so this function does nothing);
427 * the memory is released when the region is destroyed.
428 */
429 void deallocate(pointer p, size_type count) {
430 region.rfree(static_cast<void*>(p), count);
431 }
432
433 /**
434 * \brief Constructs an object
435 *
436 * Constructs an object of type \a T with the initial value
437 * of \a t at the location specified by \a element. This function
438 * calls the <i>placement new()</i> operator.
439 */
440 void construct(pointer element, const_reference t) {
441 new (element) T(t);
442 }
443
444 /// Calls the destructor on the object pointed to by \a element.
445 void destroy(pointer element) {
446 element->~T();
447 }
448 };
449
450 /*
451 * \brief Tests two region allocators for equality
452 *
453 * Two allocators are equal when each can release storage allocated
454 * from the other.
455 */
456 template<class T1, class T2>
457 bool operator==(region_allocator<T1> const& al1,
458 region_allocator<T2> const& al2) noexcept {
459 return &al1.region == &al2.region;
460 }
461
462 /*
463 * \brief Tests two region allocators for inequality
464 *
465 * Two allocators are equal when each can release storage allocated
466 * from the other.
467 */
468 template<class T1, class T2>
469 bool operator!=(region_allocator<T1> const& al1,
470 region_allocator<T2> const& al2) noexcept {
471 return &al1.region != &al2.region;
472 }
473
474}
475
476// STATISTICS: kernel-memory