ROSE  0.11.96.11
StackAllocator.h
1 // WARNING: Changes to this file must be contributed back to Sawyer or else they will
2 // be clobbered by the next update from Sawyer. The Sawyer repository is at
3 // https://github.com/matzke1/sawyer.
4 
5 
6 
7 
8 #ifndef SAWYER_STACK_ALLOCATOR
9 #define SAWYER_STACK_ALLOCATOR
10 
11 #include <Sawyer/Sawyer.h>
12 
13 namespace Sawyer {
14 
20 template<typename T>
22 public:
23  typedef T Value;
25 private:
26  const size_t elmtsPerBlock_; // elements per large block of memory requested
27  std::list<T*> blocks_; // front() is the most recent block from which an element is allocated
28  size_t available_; // number of elements available in most recent block
29  std::list<T*> freeBlocks_; // blocks that aren't being used currently
30 
31 public:
32  explicit StackAllocator(size_t elmtsPerBlock)
33  : elmtsPerBlock_(elmtsPerBlock), available_(0) {}
34 
35  ~StackAllocator() {
36  prune();
37  BOOST_FOREACH (T *ptr, blocks_)
38  delete[] ptr;
39  blocks_.clear();
40  available_ = 0;
41  }
42 
44  void prune() {
45  BOOST_FOREACH (T *ptr, freeBlocks_)
46  delete[] ptr;
47  freeBlocks_.clear();
48  }
49 
54  T* reserve(size_t nElmts) {
55  if (nElmts > available_) {
56  ASSERT_require(nElmts <= elmtsPerBlock_);
57  allocateBlock();
58  }
59  return blocks_.front() + (elmtsPerBlock_ - available_);
60  }
61 
64  T* allocNext() {
65  if (0 == available_)
66  allocateBlock();
67  return blocks_.front() + (elmtsPerBlock_ - available_--);
68  }
69 
73  void revert(T *ptr) {
74  ASSERT_not_null(ptr);
75  while (!blocks_.empty() && (ptr < blocks_.front() || ptr >= blocks_.front() + elmtsPerBlock_))
76  freeBlock();
77  ASSERT_always_forbid2(blocks_.empty(), "bad address or previously reverted");
78  available_ = elmtsPerBlock_ - (ptr - blocks_.front());
79  }
80 
81 private:
82  void allocateBlock() {
83  if (freeBlocks_.empty()) {
84  blocks_.insert(blocks_.begin(), new T[elmtsPerBlock_]);
85  } else {
86  blocks_.insert(blocks_.begin(), freeBlocks_.front());
87  freeBlocks_.erase(freeBlocks_.begin());
88  }
89  available_ = elmtsPerBlock_;
90  }
91 
92  void freeBlock() {
93  ASSERT_forbid(blocks_.empty());
94  freeBlocks_.insert(freeBlocks_.begin(), blocks_.front());
95  blocks_.erase(blocks_.begin());
96  available_ = 0;
97  }
98 };
99 
100 } // namespace
101 
102 #endif
Sawyer::StackAllocator::allocNext
T * allocNext()
Allocate one element.
Definition: StackAllocator.h:64
Sawyer::StackAllocator
Stack-like allocator.
Definition: StackAllocator.h:21
Sawyer::StackAllocator::reserve
T * reserve(size_t nElmts)
Reserve space for objects.
Definition: StackAllocator.h:54
Sawyer
Name space for the entire library.
Definition: Access.h:13
Sawyer::StackAllocator::Value
T Value
Type of values being allocated.
Definition: StackAllocator.h:23
Sawyer::StackAllocator::revert
void revert(T *ptr)
Free all elements back to the specified element.
Definition: StackAllocator.h:73
Sawyer::StackAllocator::prune
void prune()
Free unused large blocks.
Definition: StackAllocator.h:44