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