jitcraft/PoolAllocator.h
author David Anderson <dvander@alliedmods.net>
Mon Jun 25 02:57:28 2012 -0700 (2012-06-25)
changeset 0 c455ebb9a5dc
child 55 e073a9fe8e57
permissions -rw-r--r--
Initial import of prototype.
     1 /*
     2  * Copyright (C) 2012 David Anderson
     3  *
     4  * This file is part of JITCraft.
     5  *
     6  * JITCraft is free software: you can redistribute it and/or modify it under
     7  * the terms of the GNU General Public License as published by the Free
     8  * Software Foundation, either version 3 of the License, or (at your option)
     9  * any later version.
    10  * 
    11  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    13  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along with
    16  * JITCraft. If not, see http://www.gnu.org/licenses/.
    17  */
    18 #ifndef _include_jitcraft_pool_allocator_h_
    19 #define _include_jitcraft_pool_allocator_h_
    20 
    21 #include <new>
    22 #include <stddef.h>
    23 #include <limits.h>
    24 #include "Utility.h"
    25 
    26 namespace jc {
    27 
    28 // Allocates memory in chunks that are not freed until the entire allocator
    29 // is freed. This is intended for use with large, temporary data structures.
    30 class PoolAllocator
    31 {
    32     friend class PoolAllocationScope;
    33 
    34     struct Pool {
    35         char *base;
    36         char *ptr;
    37         char *end;
    38         Pool *prev;
    39 
    40         size_t size() const {
    41             return size_t(end - base);
    42         }
    43     };
    44 
    45     static const size_t kDefaultPoolSize = 8 * 1024;
    46     static const size_t kMaxReserveSize = 64 * 1024;
    47 
    48   private:
    49     Pool *reserved_;
    50     Pool *last_;
    51 
    52   private:
    53     void unwind(char *pos);
    54     void *slowAllocate(size_t actualBytes);
    55 
    56   public:
    57     PoolAllocator();
    58     ~PoolAllocator();
    59 
    60     void *allocate(size_t bytes) {
    61         // Guarantee malloc alignment.
    62         size_t actualBytes = Align(bytes, kMallocAlignment);
    63         if (!last_ || (size_t(last_->end - last_->ptr) < actualBytes))
    64             return slowAllocate(actualBytes);
    65         char *ptr = last_->ptr;
    66         last_->ptr += actualBytes;
    67         return ptr;
    68     }
    69 
    70     char *enter();
    71     void leave(char *position);
    72 };
    73 
    74 class PoolScope
    75 {
    76     PoolAllocator &pool_;
    77     char *position_;
    78 
    79   public:
    80     PoolScope(PoolAllocator &allocator)
    81       : pool_(allocator),
    82         position_(allocator.enter())
    83     {
    84     }
    85     ~PoolScope()
    86     {
    87         pool_.leave(position_);
    88     }
    89 };
    90 
    91 class PoolObject
    92 {
    93   public:
    94     void *operator new(size_t size, PoolAllocator &pool) {
    95         return pool.allocate(size);
    96     }
    97     void *operator new [](size_t size, PoolAllocator &pool) {
    98         return pool.allocate(size);
    99     }
   100     
   101     // Using delete on pool-allocated objects is illegal.
   102     void operator delete(void *ptr, PoolAllocator &pool) {
   103         assert(false);
   104     }
   105     void operator delete [](void *ptr, PoolAllocator &pool) {
   106         assert(false);
   107     }
   108 };
   109 
   110 // Simple vector<> lookalike that can use the pool allocator.
   111 template <typename T>
   112 class PoolList : public PoolObject
   113 {
   114     T *t_;
   115     size_t length_;
   116     size_t max_;
   117 
   118   private:
   119     void ensure(PoolAllocator &pool, size_t n) {
   120         if (max_ - length_ >= n)
   121             return;
   122 
   123         size_t newMax = max_;
   124         if (newMax == 0)
   125             newMax = 8;
   126         while (newMax - length_ < n) {
   127             // Make sure the request does not overflow.
   128             if (newMax >= INT_MAX)
   129                 throw std::bad_alloc();
   130             newMax *= 2;
   131         }
   132 
   133         // Ensure no overflow.
   134         if (newMax > UINT_MAX / sizeof(T))
   135             throw std::bad_alloc();
   136 
   137         T *new_ = (T *)pool.allocate(newMax * sizeof(T));
   138         for (size_t i = 0; i < length_; i++)
   139             new (&new_[i]) T(t_[i]);
   140 
   141         t_ = new_;
   142         max_ = newMax;
   143     }
   144 
   145   public:
   146     PoolList()
   147       : t_(NULL),
   148         length_(NULL),
   149         max_(NULL)
   150     {
   151     }
   152 
   153   public:
   154     void append(PoolAllocator &pool, const T &t) {
   155         ensure(pool, 1);
   156         new (&t_[length_]) T(t);
   157         length_++;
   158     }
   159 
   160     size_t length() const {
   161         return length_;
   162     }
   163 
   164     T &at(size_t i) {
   165         assert(i < length());
   166         return t_[i];
   167     }
   168 };
   169 
   170 }
   171 
   172 #endif // _include_jitcraft_pool_allocator_h_