gc_allocator.h raw
1 /*
2 * Copyright (c) 1996-1997 Silicon Graphics Computer Systems, Inc.
3 * Copyright (c) 2002 Hewlett-Packard Company
4 *
5 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
7 *
8 * Permission is hereby granted to use or copy this program
9 * for any purpose, provided the above notices are retained on all copies.
10 * Permission to modify the code and to distribute modified code is granted,
11 * provided the above notices are retained, and a notice that the code was
12 * modified is included with the above copyright notice.
13 */
14
15 /*
16 * This implements standard-conforming allocators that interact with
17 * the garbage collector. `gc_allocator<T>` allocates garbage-collectible
18 * objects of type `T`. `traceable_allocator<T>` allocates objects that
19 * are not themselves garbage-collected ones, but are scanned by the
20 * collector for pointers to collectible objects. `traceable_allocator<T>`
21 * should be used for explicitly managed STL containers that may point to
22 * collectible objects.
23 *
24 * This code was derived from an earlier version of the GNU C++ standard
25 * library, which itself was derived from the SGI STL implementation.
26 *
27 * Ignore-off-page allocator: George T. Talbot
28 */
29
30 #ifndef GC_ALLOCATOR_H
31 #define GC_ALLOCATOR_H
32
33 #include "gc.h"
34
35 #include <new> // for placement `new` and `bad_alloc`
36
37 #ifdef GC_NAMESPACE_ALLOCATOR
38 namespace boehmgc
39 {
40 #endif
41
42 #if !defined(GC_NO_MEMBER_TEMPLATES) && defined(_MSC_VER) && _MSC_VER <= 1200
43 // MSVC++ 6.0 do not support member templates.
44 # define GC_NO_MEMBER_TEMPLATES
45 #endif
46
47 #if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
48 # define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
49 #else
50 # define GC_ALLOCATOR_THROW_OR_ABORT() throw std::bad_alloc()
51 #endif
52
53 #if __cplusplus >= 201103L
54 # define GC_ALCTR_PTRDIFF_T std::ptrdiff_t
55 # define GC_ALCTR_SIZE_T std::size_t
56 #else
57 # define GC_ALCTR_PTRDIFF_T ptrdiff_t
58 # define GC_ALCTR_SIZE_T size_t
59 #endif
60
61 // First some helpers to allow us to dispatch on whether or not a type
62 // is known to be pointer-free. These are private, except that the client
63 // may invoke the `GC_DECLARE_PTRFREE` macro.
64
65 struct GC_true_type {
66 };
67 struct GC_false_type {
68 };
69
70 template <class GC_tp> struct GC_type_traits {
71 GC_false_type GC_is_ptr_free;
72 };
73
74 #define GC_DECLARE_PTRFREE(T) \
75 template <> struct GC_type_traits<T> { \
76 GC_true_type GC_is_ptr_free; \
77 }
78
79 GC_DECLARE_PTRFREE(char);
80 GC_DECLARE_PTRFREE(signed char);
81 GC_DECLARE_PTRFREE(unsigned char);
82 GC_DECLARE_PTRFREE(signed short);
83 GC_DECLARE_PTRFREE(unsigned short);
84 GC_DECLARE_PTRFREE(signed int);
85 GC_DECLARE_PTRFREE(unsigned int);
86 GC_DECLARE_PTRFREE(signed long);
87 GC_DECLARE_PTRFREE(unsigned long);
88 GC_DECLARE_PTRFREE(float);
89 GC_DECLARE_PTRFREE(double);
90 GC_DECLARE_PTRFREE(long double);
91 // The client may want to add others.
92
93 // In the following `GC_Tp` is `GC_true_type` if we are allocating
94 // a pointer-free object.
95 template <class GC_Tp>
96 inline void *
97 GC_selective_alloc(GC_ALCTR_SIZE_T n, GC_Tp, bool ignore_off_page)
98 {
99 void *obj = ignore_off_page ? GC_MALLOC_IGNORE_OFF_PAGE(n) : GC_MALLOC(n);
100 if (0 == obj)
101 GC_ALLOCATOR_THROW_OR_ABORT();
102 return obj;
103 }
104
105 #if !defined(__WATCOMC__)
106 // Note: template-id not supported in this context by Watcom compiler.
107 template <>
108 inline void *
109 GC_selective_alloc<GC_true_type>(GC_ALCTR_SIZE_T n, GC_true_type,
110 bool ignore_off_page)
111 {
112 void *obj = ignore_off_page ? GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(n)
113 : GC_MALLOC_ATOMIC(n);
114 if (0 == obj)
115 GC_ALLOCATOR_THROW_OR_ABORT();
116 return obj;
117 }
118 #endif
119
120 // Now the public `gc_allocator<T>` class.
121 template <class GC_Tp> class gc_allocator
122 {
123 public:
124 typedef GC_ALCTR_SIZE_T size_type;
125 typedef GC_ALCTR_PTRDIFF_T difference_type;
126 typedef GC_Tp *pointer;
127 typedef const GC_Tp *const_pointer;
128 typedef GC_Tp &reference;
129 typedef const GC_Tp &const_reference;
130 typedef GC_Tp value_type;
131
132 template <class GC_Tp1> struct rebind {
133 typedef gc_allocator<GC_Tp1> other;
134 };
135
136 GC_CONSTEXPR
137 gc_allocator() GC_NOEXCEPT
138 {
139 // Empty.
140 }
141
142 GC_CONSTEXPR
143 gc_allocator(const gc_allocator &) GC_NOEXCEPT
144 {
145 // Empty.
146 }
147
148 #ifndef GC_NO_MEMBER_TEMPLATES
149 template <class GC_Tp1>
150 GC_ATTR_EXPLICIT GC_CONSTEXPR
151 gc_allocator(const gc_allocator<GC_Tp1> &) GC_NOEXCEPT
152 {
153 }
154 #endif
155
156 GC_CONSTEXPR ~gc_allocator() GC_NOEXCEPT {}
157
158 GC_CONSTEXPR pointer
159 address(reference GC_x) const
160 {
161 return &GC_x;
162 }
163
164 GC_CONSTEXPR const_pointer
165 address(const_reference GC_x) const
166 {
167 return &GC_x;
168 }
169
170 // `GC_n` is permitted to be 0. The C++ standard says nothing about what
171 // the return value is when `GC_n` is zero.
172 GC_CONSTEXPR GC_Tp *
173 allocate(size_type GC_n, const void * = 0)
174 {
175 GC_type_traits<GC_Tp> traits;
176 return static_cast<GC_Tp *>(GC_selective_alloc(
177 GC_n * sizeof(GC_Tp), traits.GC_is_ptr_free, false));
178 }
179
180 GC_CONSTEXPR void
181 deallocate(pointer __p, size_type /* `GC_n` */) GC_NOEXCEPT
182 {
183 GC_FREE(__p);
184 }
185
186 GC_CONSTEXPR size_type
187 max_size() const GC_NOEXCEPT
188 {
189 return static_cast<GC_ALCTR_SIZE_T>(-1) / sizeof(GC_Tp);
190 }
191
192 GC_CONSTEXPR void
193 construct(pointer __p, const GC_Tp &__val)
194 {
195 new (__p) GC_Tp(__val);
196 }
197
198 GC_CONSTEXPR void
199 destroy(pointer __p)
200 {
201 __p->~GC_Tp();
202 }
203 };
204
205 template <> class gc_allocator<void>
206 {
207 public:
208 typedef GC_ALCTR_SIZE_T size_type;
209 typedef GC_ALCTR_PTRDIFF_T difference_type;
210 typedef void *pointer;
211 typedef const void *const_pointer;
212 typedef void value_type;
213
214 template <class GC_Tp1> struct rebind {
215 typedef gc_allocator<GC_Tp1> other;
216 };
217 };
218
219 template <class GC_T1, class GC_T2>
220 GC_CONSTEXPR inline bool
221 operator==(const gc_allocator<GC_T1> &,
222 const gc_allocator<GC_T2> &) GC_NOEXCEPT
223 {
224 return true;
225 }
226
227 template <class GC_T1, class GC_T2>
228 GC_CONSTEXPR inline bool
229 operator!=(const gc_allocator<GC_T1> &,
230 const gc_allocator<GC_T2> &) GC_NOEXCEPT
231 {
232 return false;
233 }
234
235 // Now the public `gc_allocator_ignore_off_page<T>` class.
236 template <class GC_Tp> class gc_allocator_ignore_off_page
237 {
238 public:
239 typedef GC_ALCTR_SIZE_T size_type;
240 typedef GC_ALCTR_PTRDIFF_T difference_type;
241 typedef GC_Tp *pointer;
242 typedef const GC_Tp *const_pointer;
243 typedef GC_Tp &reference;
244 typedef const GC_Tp &const_reference;
245 typedef GC_Tp value_type;
246
247 template <class GC_Tp1> struct rebind {
248 typedef gc_allocator_ignore_off_page<GC_Tp1> other;
249 };
250
251 GC_CONSTEXPR
252 gc_allocator_ignore_off_page() GC_NOEXCEPT
253 {
254 // Empty.
255 }
256
257 GC_CONSTEXPR
258 gc_allocator_ignore_off_page(const gc_allocator_ignore_off_page &)
259 GC_NOEXCEPT
260 {
261 // Empty.
262 }
263
264 #ifndef GC_NO_MEMBER_TEMPLATES
265 template <class GC_Tp1>
266 GC_ATTR_EXPLICIT GC_CONSTEXPR
267 gc_allocator_ignore_off_page(const gc_allocator_ignore_off_page<GC_Tp1> &)
268 GC_NOEXCEPT
269 {
270 }
271 #endif
272
273 GC_CONSTEXPR ~gc_allocator_ignore_off_page() GC_NOEXCEPT {}
274
275 GC_CONSTEXPR pointer
276 address(reference GC_x) const
277 {
278 return &GC_x;
279 }
280
281 GC_CONSTEXPR const_pointer
282 address(const_reference GC_x) const
283 {
284 return &GC_x;
285 }
286
287 // `GC_n` is permitted to be 0. The C++ standard says nothing about what
288 // the return value is when `GC_n` is zero.
289 GC_CONSTEXPR GC_Tp *
290 allocate(size_type GC_n, const void * = 0)
291 {
292 GC_type_traits<GC_Tp> traits;
293 return static_cast<GC_Tp *>(
294 GC_selective_alloc(GC_n * sizeof(GC_Tp), traits.GC_is_ptr_free, true));
295 }
296
297 GC_CONSTEXPR void
298 deallocate(pointer __p, size_type /* `GC_n` */) GC_NOEXCEPT
299 {
300 GC_FREE(__p);
301 }
302
303 GC_CONSTEXPR size_type
304 max_size() const GC_NOEXCEPT
305 {
306 return static_cast<GC_ALCTR_SIZE_T>(-1) / sizeof(GC_Tp);
307 }
308
309 GC_CONSTEXPR void
310 construct(pointer __p, const GC_Tp &__val)
311 {
312 new (__p) GC_Tp(__val);
313 }
314
315 GC_CONSTEXPR void
316 destroy(pointer __p)
317 {
318 __p->~GC_Tp();
319 }
320 };
321
322 template <> class gc_allocator_ignore_off_page<void>
323 {
324 public:
325 typedef GC_ALCTR_SIZE_T size_type;
326 typedef GC_ALCTR_PTRDIFF_T difference_type;
327 typedef void *pointer;
328 typedef const void *const_pointer;
329 typedef void value_type;
330
331 template <class GC_Tp1> struct rebind {
332 typedef gc_allocator_ignore_off_page<GC_Tp1> other;
333 };
334 };
335
336 template <class GC_T1, class GC_T2>
337 GC_CONSTEXPR inline bool
338 operator==(const gc_allocator_ignore_off_page<GC_T1> &,
339 const gc_allocator_ignore_off_page<GC_T2> &) GC_NOEXCEPT
340 {
341 return true;
342 }
343
344 template <class GC_T1, class GC_T2>
345 GC_CONSTEXPR inline bool
346 operator!=(const gc_allocator_ignore_off_page<GC_T1> &,
347 const gc_allocator_ignore_off_page<GC_T2> &) GC_NOEXCEPT
348 {
349 return false;
350 }
351
352 // And the public `traceable_allocator<T>` class.
353
354 // Note that we currently do not specialize the pointer-free case,
355 // since a pointer-free traceable container does not make that much sense,
356 // though it could become an issue due to abstraction boundaries.
357
358 template <class GC_Tp> class traceable_allocator
359 {
360 public:
361 typedef GC_ALCTR_SIZE_T size_type;
362 typedef GC_ALCTR_PTRDIFF_T difference_type;
363 typedef GC_Tp *pointer;
364 typedef const GC_Tp *const_pointer;
365 typedef GC_Tp &reference;
366 typedef const GC_Tp &const_reference;
367 typedef GC_Tp value_type;
368
369 template <class GC_Tp1> struct rebind {
370 typedef traceable_allocator<GC_Tp1> other;
371 };
372
373 GC_CONSTEXPR
374 traceable_allocator() GC_NOEXCEPT
375 {
376 // Empty.
377 }
378
379 GC_CONSTEXPR
380 traceable_allocator(const traceable_allocator &) GC_NOEXCEPT
381 {
382 // Empty.
383 }
384
385 #ifndef GC_NO_MEMBER_TEMPLATES
386 template <class GC_Tp1>
387 GC_ATTR_EXPLICIT GC_CONSTEXPR
388 traceable_allocator(const traceable_allocator<GC_Tp1> &) GC_NOEXCEPT
389 {
390 }
391 #endif
392
393 GC_CONSTEXPR ~traceable_allocator() GC_NOEXCEPT {}
394
395 GC_CONSTEXPR pointer
396 address(reference GC_x) const
397 {
398 return &GC_x;
399 }
400
401 GC_CONSTEXPR const_pointer
402 address(const_reference GC_x) const
403 {
404 return &GC_x;
405 }
406
407 // `GC_n` is permitted to be 0. The C++ standard says nothing about what
408 // the return value is when `GC_n` is zero.
409 GC_CONSTEXPR GC_Tp *
410 allocate(size_type GC_n, const void * = 0)
411 {
412 void *obj = GC_MALLOC_UNCOLLECTABLE(GC_n * sizeof(GC_Tp));
413 if (0 == obj)
414 GC_ALLOCATOR_THROW_OR_ABORT();
415 return static_cast<GC_Tp *>(obj);
416 }
417
418 GC_CONSTEXPR void
419 deallocate(pointer __p, size_type /* `GC_n` */) GC_NOEXCEPT
420 {
421 GC_FREE(__p);
422 }
423
424 GC_CONSTEXPR size_type
425 max_size() const GC_NOEXCEPT
426 {
427 return static_cast<GC_ALCTR_SIZE_T>(-1) / sizeof(GC_Tp);
428 }
429
430 GC_CONSTEXPR void
431 construct(pointer __p, const GC_Tp &__val)
432 {
433 new (__p) GC_Tp(__val);
434 }
435
436 GC_CONSTEXPR void
437 destroy(pointer __p)
438 {
439 __p->~GC_Tp();
440 }
441 };
442
443 template <> class traceable_allocator<void>
444 {
445 public:
446 typedef GC_ALCTR_SIZE_T size_type;
447 typedef GC_ALCTR_PTRDIFF_T difference_type;
448 typedef void *pointer;
449 typedef const void *const_pointer;
450 typedef void value_type;
451
452 template <class GC_Tp1> struct rebind {
453 typedef traceable_allocator<GC_Tp1> other;
454 };
455 };
456
457 template <class GC_T1, class GC_T2>
458 GC_CONSTEXPR inline bool
459 operator==(const traceable_allocator<GC_T1> &,
460 const traceable_allocator<GC_T2> &) GC_NOEXCEPT
461 {
462 return true;
463 }
464
465 template <class GC_T1, class GC_T2>
466 GC_CONSTEXPR inline bool
467 operator!=(const traceable_allocator<GC_T1> &,
468 const traceable_allocator<GC_T2> &) GC_NOEXCEPT
469 {
470 return false;
471 }
472
473 #undef GC_ALCTR_PTRDIFF_T
474 #undef GC_ALCTR_SIZE_T
475
476 #ifdef GC_NAMESPACE_ALLOCATOR
477 }
478 #endif
479
480 #endif /* GC_ALLOCATOR_H */
481