Stan  1.0
probability, sampling & optimization
stack_alloc.hpp
Go to the documentation of this file.
1 #ifndef __STAN__MEMORY__STACK_ALLOC_HPP__
2 #define __STAN__MEMORY__STACK_ALLOC_HPP__
3 
4 #include <cstdlib>
5 #include <cstddef>
6 #include <sstream>
7 #include <stdexcept>
8 #include <stdint.h> // FIXME: replace with cstddef?
9 #include <vector>
10 
11 #ifdef __GNUC__
12 #define likely(x) (__builtin_expect((x),1))
13 #define unlikely(x) (__builtin_expect((x),0))
14 #else
15 #define likely(x) (x)
16 #define unlikely(x) (x)
17 #endif
18 
19 namespace stan {
20 
21  namespace memory {
22 
34  template <typename T>
35  bool is_aligned(T* ptr, unsigned int bytes_aligned) {
36  return (reinterpret_cast<uintptr_t>(ptr) % bytes_aligned) == 0U;
37  }
38 
39 
40  namespace {
41  const size_t DEFAULT_INITIAL_NBYTES = 1 << 16; // 64KB
42 
43 
44  // FIXME: enforce alignment
45  // big fun to inline, but only called twice
46  inline char* eight_byte_aligned_malloc(size_t size) {
47  char* ptr = static_cast<char*>(malloc(size));
48  if (!ptr) return ptr; // malloc failed to alloc
49  if (!is_aligned(ptr,8U)) {
50  std::stringstream s;
51  s << "invalid alignment to 8 bytes, ptr="
52  << reinterpret_cast<uintptr_t>(ptr)
53  << std::endl;
54  throw std::runtime_error(s.str());
55  }
56  return ptr;
57  }
58  }
59 
79  class stack_alloc {
80  private:
81  std::vector<char*> blocks_; // storage for blocks, may be bigger than cur_block_
82  std::vector<size_t> sizes_; // could store initial & shift for others
83  size_t cur_block_; // index into blocks_ for next alloc
84  char* cur_block_end_; // ptr to cur_block_ptr_ + sizes_[cur_block_]
85  char* next_loc_; // ptr to next available spot in cur block
86 
95  char* move_to_next_block(size_t len) {
96  char* result;
97  ++cur_block_;
98  // Find the next block (if any) containing at least len bytes.
99  while ((cur_block_ < blocks_.size()) && (sizes_[cur_block_] < len))
100  ++cur_block_;
101  // Allocate a new block if necessary.
102  if (unlikely(cur_block_ >= blocks_.size())) {
103  // New block should be max(2*size of last block, len) bytes.
104  size_t newsize = sizes_.back() * 2;
105  if (newsize < len)
106  newsize = len;
107  blocks_.push_back(eight_byte_aligned_malloc(newsize));
108  if (!blocks_.back())
109  throw std::bad_alloc();
110  sizes_.push_back(newsize);
111  }
112  result = blocks_[cur_block_];
113  // Get the object's state back in order.
114  next_loc_ = result + len;
115  cur_block_end_ = result + sizes_[cur_block_];
116  return result;
117  }
118 
119  public:
120 
130  stack_alloc(size_t initial_nbytes = DEFAULT_INITIAL_NBYTES) :
131  blocks_(1, eight_byte_aligned_malloc(initial_nbytes)),
132  sizes_(1,initial_nbytes),
133  cur_block_(0),
134  cur_block_end_(blocks_[0] + initial_nbytes),
135  next_loc_(blocks_[0]) {
136 
137  if (!blocks_[0])
138  throw std::bad_alloc(); // no msg allowed in bad_alloc ctor
139  }
140 
148  // free ALL blocks
149  for (size_t i = 0; i < blocks_.size(); ++i)
150  if (blocks_[i])
151  free(blocks_[i]);
152  }
153 
166  inline void* alloc(size_t len) {
167  // Typically, just return and increment the next location.
168  char* result = next_loc_;
169  next_loc_ += len;
170  // Occasionally, we have to switch blocks.
171  if (unlikely(next_loc_ >= cur_block_end_))
172  result = move_to_next_block(len);
173  return (void*)result;
174  }
175 
182  inline void recover_all() {
183  cur_block_ = 0;
184  next_loc_ = blocks_[0];
185  cur_block_end_ = next_loc_ + sizes_[0];
186  }
187 
193  inline void free_all() {
194  // frees all BUT the first (index 0) block
195  for (size_t i = 1; i < blocks_.size(); ++i)
196  if (blocks_[i])
197  free(blocks_[i]);
198  sizes_.resize(1);
199  blocks_.resize(1);
200  recover_all();
201  }
202 
203  };
204 
205  }
206 }
207 #endif
An instance of this class provides a memory pool through which blocks of raw memory may be allocated ...
Definition: stack_alloc.hpp:79
void free_all()
Free all memory used by the stack allocator other than the initial block allocation back to the syste...
stack_alloc(size_t initial_nbytes=DEFAULT_INITIAL_NBYTES)
Construct a resizable stack allocator initially holding the specified number of bytes.
void recover_all()
Recover all the memory used by the stack allocator.
~stack_alloc()
Destroy this memory allocator.
void * alloc(size_t len)
Return a newly allocated block of memory of the appropriate size managed by the stack allocator.
bool is_aligned(T *ptr, unsigned int bytes_aligned)
Return true if the specified pointer is aligned on the number of bytes.
Definition: stack_alloc.hpp:35
Probability, optimization and sampling library.
Definition: agrad.cpp:6
#define unlikely(x)
Definition: stack_alloc.hpp:16

     [ Stan Home Page ] © 2011–2012, Stan Development Team.