MADNESS 0.10.1
stack.h
Go to the documentation of this file.
1/*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30*/
31
32#ifndef MADNESS_WORLD_STACK_H__INCLUDED
33#define MADNESS_WORLD_STACK_H__INCLUDED
34
35/**
36 \file stack.h
37 \brief Implement \c Stack for a fixed-size stack container.
38 \ingroup containers
39*/
40
42#include <cstring>
43#include <cstdlib>
44#include <algorithm>
45#include <memory>
46#include <new>
47#include <type_traits>
48
49namespace madness {
50
51 namespace detail {
52
53 /// Base class for Stack which implements basic memory operations for non-POD objects.
54
55 /// \tparam T The data type of the stack.
56 /// \tparam isPod An auxiliary template parameter to select the
57 /// POD/non-POD versions of this class.
58 template <typename T, bool isPod>
59 class StackBase {
60 protected:
61
62 /// Destroy a non-POD object.
63
64 /// \param[in] ptr A pointer to the object to be destroyed.
65 static void destroy(T* ptr) { ptr->~T(); }
66
67 /// Destroy a range of non-POD objects.
68
69 /// \param[in] first The beginning of the range to be destroyed.
70 /// \param[in] last The end of the range to be destroyed.
71 static void destroy(T* first, T* last) {
72 while(first != last) {
73 --last;
74 destroy(last);
75 }
76 }
77
78 /// Move a range of POD objects.
79
80 /// \param[in] first The beginning of the range to be moved.
81 /// \param[in] last The end of the range to be moved.
82 /// \param[in] dest Pointer to the uninitialized memory range.
83 static void uninitialized_move(T* first, T* last, T* dest) {
84 for (; first != last; ++first, ++dest) {
85 ::new (dest) T(std::move(*first));
86 destroy(first);
87 }
88 }
89
90 /// Copy a range of POD objects.
91
92 /// \param[in] first The beginning of the range to be copied.
93 /// \param[in] last The end of the range to be copied.
94 /// \param[in] dest Pointer to the uninitialized memory range.
95 static void uninitialized_copy(T* first, T* last, T* dest) {
96 std::uninitialized_copy(first, last, dest);
97 }
98
99 }; // class StackBase
100
101
102 /// Base class for `Stack` which implements basic memory operations for POD objects.
103
104 /// \tparam T The data type of the stack.
105 template <typename T>
106 class StackBase<T, true> {
107 protected:
108
109 /// Destroy a POD object (no op).
110
111 /// No need to destroy PODs.
112 static void destroy(T*) { }
113
114 /// Destroy a range of POD objects (no op).
115
116 /// No need to destroy PODs.
117 static void destroy(T*, T*) { }
118
119 /// Move a range of POD objects to an uninitialized buffer.
120
121 /// \param[in] first The beginning of the range to be moved.
122 /// \param[in] last The end of the range to be moved.
123 /// \param[in] dest Pointer to the uninitialized memory buffer.
124 static void uninitialized_move(T* first, T* last, T* dest) {
125 // Use simple copy for pods
126 if (first != last)
127 std::memcpy(dest, first, (last - first) * sizeof(T));
128 }
129
130 /// Copy a range of POD objects to an uninitialized buffer.
131
132 /// \param[in] first The beginning of the range to be copied.
133 /// \param[in] last The end of the range to be copied.
134 /// \param[in] dest Pointer to the uninitialized memory buffer.
135 static void uninitialized_copy(T* first, T* last, T* dest) {
136 // Use simple copy for pods
137 if (first != last)
138 std::memcpy(dest, first, (last - first) * sizeof(T));
139 }
140
141 }; // class StackBase<T, true>
142
143 } // namespace detail
144
145 /// Dynamically sized Stack with small stack size optimization.
146
147 /// This object is a dynamically sized stack that functions similarly to a
148 /// \c std::vector. It also includes an optimization for small stack sizes
149 /// that avoids memory allocations when the stack size is less than or equal
150 /// to \c N.
151 /// \tparam T The type of data stored in the stack.
152 /// \tparam N The fixed size of the stack.
153 template <typename T, unsigned int N>
154 class Stack : public detail::StackBase<T, std::is_standard_layout<T>::value && std::is_trivial<T>::value> {
155 public:
156 typedef T value_type; ///< Type of the stack elements.
157 typedef T& reference; ///< Element reference type.
158 typedef const T& const_reference; ///< Element constant reference type.
159 typedef unsigned int size_type; ///< An unsigned integral type.
160
161 private:
162 T* data_; ///< Pointer to the stack data.
163 size_type size_; ///< Number of elements on the stack.
164 size_type capacity_; ///< The maximum size, in elements, of the \c data_ buffer.
165 char buffer_[sizeof(T) * N]; ///< Static buffer for storing a small number of elements.
166
168
172
173 /// Check if the stack is using the small buffer to store data.
174
175 /// \return True if the small buffer is being used; false otherwise.
176 bool is_small() const { return data_ == static_cast<const void*>(buffer_); }
177
178 /// Allocate a raw buffer.
179
180 /// Allocate an uninitialized buffer.
181 /// \param[in] n The size of the new buffer.
182 /// \return Pointer to the new buffer.
183 T* allocate(const size_type n) {
184 void* const buffer = std::malloc(n * sizeof(T));
185 if(! buffer)
186 throw std::bad_alloc();
187
188 return reinterpret_cast<T*>(buffer);
189 }
190
191 /// \todo Brief description needed.
192
193 /// \todo Parameter description needed.
194 /// \param other Description needed.
195 void move(Stack<T,N>& other) {
196 // Move the stack data from other to this object
197 if(other.is_small()) {
198 // Other is using the static buffer space, so the data must
199 // be moved to this object's static buffer.
200 data_ = reinterpret_cast<T*>(buffer_);
201 uninitialized_move(other.data_, other.data_ + other.size_, data_);
202 capacity_ = N;
203 } else {
204 // Other is using an allocated buffer, so move the pointer
205 // to the data
206 data_ = other.data_;
207 capacity_ = other.capacity_;
208
209 other.data_ = reinterpret_cast<T*>(other.buffer_);
210 other.capacity_ = N;
211 }
212 size_ = other.size_;
213 other.size_ = 0u;
214 }
215
216 /// Deallocate memory.
217
218 /// Destroy the pointer if it is a dynamically allocated buffer;
219 /// otherwise do nothing.
220 void deallocate() { if(! is_small()) std::free(data_); }
221
222 public:
223 /// Construct an empty stack.
224
225 /// The capacity of the stack is \c N.
227 data_(reinterpret_cast<T*>(buffer_)),
228 size_(0u), capacity_(N)
229 { }
230
231 /// Copy constructor.
232
233 /// If the size of \c other is less than or equal to \c N, then this
234 /// object will use the small buffer. Otherwise, it will allocate memory
235 /// and copy the data of \c other. The capacity of the object will be
236 /// equal to <tt>max(N, other.size())</tt>.
237 /// \param[in] other The stack to be copied.
238 Stack(const Stack<T,N>& other) {
239 if(other.size_ > N) {
240 data_ = allocate(other.size_);
241 capacity_ = other.size_;
242 } else {
243 data_ = reinterpret_cast<T*>(buffer_);
244 capacity_ = N;
245 }
246 size_ = other.size_;
247 uninitialized_copy(other.data_, other.data_ + other.size_, data_);
248 }
249
250 /// Move constructor.
251
252 /// Move the data from \c other to this object.
253 /// \param[in] other The original stack.
254 Stack(Stack<T, N>&& other) { move(other); }
255
256 /// Assignment operator.
257
258 /// If the size of \c other is less than or equal to \c N, then this
259 /// object will use the small buffer. Otherwise, it will allocate memory
260 /// and copy the data of \c other. The capacity of the object will be
261 /// equal to <tt>max(N, other.size())</tt>.
262 /// \param[in] other The stack to be copied.
264 if(this != &other) { // avoid self assignment
265
266 if(capacity_ < other.size_) {
267 // Allocate a larger buffer
268 T* const buffer = allocate(other.size_);
269 uninitialized_copy(other.data_, other.data_ + other.size_, buffer);
270
271 // Destroy the existing buffer
273 deallocate();
274
275 data_ = buffer;
276 capacity_ = other.size_;
277 } else {
279 uninitialized_copy(other.data_, other.data_ + other.size_, data_);
280 }
281
282 size_ = other.size_;
283 }
284
285 return *this;
286 }
287
288 /// Move assignment operator.
289
290 /// Move the data from \c other to this object. If \c other object is
291 /// is using the static buffer, the data is moved to this object's
292 /// static buffer. Otherwise, the pointer to the allocated buffer is
293 /// moved.
294 /// \param[in] other The other stack object to be moved
295 /// \note \c other is left in a default constructed state so that it can
296 /// continue to be used.
298 if(this != &other) { // avoid self assignment
300 deallocate();
301 move(other);
302 }
303
304 return *this;
305 }
306
307 /// Destructor.
310 deallocate();
311 }
312
313 /// Push a new item onto the stack.
314
315 /// Push an item onto the top of the stack. If the stack size is equal
316 /// to the capacity, resize the stack (double).
317 /// \param[in] value The item to be pushed onto the stack.
318 void push(const_reference value) {
319 // Grow the buffer if there is no more free space on the stack
320 if(size_ == capacity_) {
321 const size_type n = (size_ << 1u) + 1u;
322
323 // Allocate new storage
324 T* const new_data = allocate(n);
325
326 // Move data to new vector
327 uninitialized_move(data_, data_ + size_, new_data);
328
329 // Deallocate the current data buffer
330 deallocate();
331
332 // Update the stack data and capacity
333 data_ = new_data;
334 capacity_ = n;
335 }
336
337 // Add value to the top of the stack
338 ::new (data_ + size_) T(value);
339 ++size_;
340 }
341
342 /// Pop an item off of the stack.
343
344 /// \throw MadnessException (via MADNESS_ASSERT) if the stack is empty.
345 void pop() {
347 --size_;
349 }
350
351 /// Get the last item pushed onto the stack.
352
353 /// \return A reference to the top of the stack.
354 /// \throw MadnessException When the stack is empty
357 return data_[size_ - 1];
358 }
359
360 /// Get the last item pushed onto the stack.
361
362 /// \return A const reference to the top of the stack.
363 /// \throw MadnessException When the stack is empty.
366 return data_[size_ - 1];
367 }
368
369 /// Size accessor.
370
371 /// \return The number of items pushed to the stack.
372 size_type size() const { return size_; }
373
374 /// Size accessor.
375
376 /// \return The number of items pushed to the stack.
377 size_type size() const volatile { return size_; }
378
379 /// Capacity accessor.
380
381 /// \return The size of allocated storage capacity.
382 size_type capacity() const { return capacity_; }
383
384 /// Check if the stack is empty.
385
386 /// \return True if the size of the stack is 0; otherwise false.
387 bool empty() const { return ! size_; }
388
389 /// Check if the stack is empty.
390
391 /// \return True if the size of the stack is 0; otherwise false.
392 bool empty() const volatile { return ! size_; }
393
394 /// Empty the stack.
395
396 /// Destroy items on the stack (if any) and set the size to 0.
397 void clear() {
399 size_ = 0u;
400 }
401
402 /// Empty the stack and free memory.
403
404 /// Destroy items on the stack (if any) and return it to the
405 /// default constructed state.
406 void reset() {
408 deallocate();
409 data_ = reinterpret_cast<T*>(buffer_);
410 size_ = 0u;
411 capacity_ = N;
412 }
413
414 /// Data accessor.
415
416 /// \return A const pointer to the stack data.
417 const T* data() const { return data_; }
418
419 /// Data accessor.
420
421 /// \return A pointer to the stack data.
422 T* data() { return data_; }
423
424 }; // class Stack
425
426} // namespace madness
427
428#endif // MADNESS_WORLD_STACK_H__INCLUDED
Dynamically sized Stack with small stack size optimization.
Definition stack.h:154
bool is_small() const
Check if the stack is using the small buffer to store data.
Definition stack.h:176
Stack< T, N > & operator=(const Stack< T, N > &other)
Assignment operator.
Definition stack.h:263
bool empty() const
Check if the stack is empty.
Definition stack.h:387
T * data_
Pointer to the stack data.
Definition stack.h:162
void reset()
Empty the stack and free memory.
Definition stack.h:406
reference top()
Get the last item pushed onto the stack.
Definition stack.h:355
size_type capacity_
The maximum size, in elements, of the data_ buffer.
Definition stack.h:164
T value_type
Type of the stack elements.
Definition stack.h:156
size_type size_
Number of elements on the stack.
Definition stack.h:163
Stack< T, N > & operator=(Stack< T, N > &&other)
Move assignment operator.
Definition stack.h:297
const T & const_reference
Element constant reference type.
Definition stack.h:158
void move(Stack< T, N > &other)
Definition stack.h:195
void clear()
Empty the stack.
Definition stack.h:397
size_type size() const volatile
Size accessor.
Definition stack.h:377
void push(const_reference value)
Push a new item onto the stack.
Definition stack.h:318
Stack(Stack< T, N > &&other)
Move constructor.
Definition stack.h:254
char buffer_[sizeof(T) *N]
Static buffer for storing a small number of elements.
Definition stack.h:165
Stack()
Construct an empty stack.
Definition stack.h:226
bool empty() const volatile
Check if the stack is empty.
Definition stack.h:392
void pop()
Pop an item off of the stack.
Definition stack.h:345
~Stack()
Destructor.
Definition stack.h:308
const_reference top() const
Get the last item pushed onto the stack.
Definition stack.h:364
size_type capacity() const
Capacity accessor.
Definition stack.h:382
Stack(const Stack< T, N > &other)
Copy constructor.
Definition stack.h:238
size_type size() const
Size accessor.
Definition stack.h:372
detail::StackBase< T, std::is_standard_layout< T >::value &&std::is_trivial< T >::value > StackBase_
Definition stack.h:167
const T * data() const
Data accessor.
Definition stack.h:417
unsigned int size_type
An unsigned integral type.
Definition stack.h:159
void deallocate()
Deallocate memory.
Definition stack.h:220
T & reference
Element reference type.
Definition stack.h:157
T * allocate(const size_type n)
Allocate a raw buffer.
Definition stack.h:183
T * data()
Data accessor.
Definition stack.h:422
static void uninitialized_move(T *first, T *last, T *dest)
Move a range of POD objects to an uninitialized buffer.
Definition stack.h:124
static void destroy(T *)
Destroy a POD object (no op).
Definition stack.h:112
static void destroy(T *, T *)
Destroy a range of POD objects (no op).
Definition stack.h:117
static void uninitialized_copy(T *first, T *last, T *dest)
Copy a range of POD objects to an uninitialized buffer.
Definition stack.h:135
Base class for Stack which implements basic memory operations for non-POD objects.
Definition stack.h:59
static void destroy(T *first, T *last)
Destroy a range of non-POD objects.
Definition stack.h:71
static void destroy(T *ptr)
Destroy a non-POD object.
Definition stack.h:65
static void uninitialized_copy(T *first, T *last, T *dest)
Copy a range of POD objects.
Definition stack.h:95
static void uninitialized_move(T *first, T *last, T *dest)
Move a range of POD objects.
Definition stack.h:83
auto T(World &world, response_space &f) -> response_space
Definition global_functions.cc:34
static double u(double r, double c)
Definition he.cc:20
Defines madness::MadnessException for exception handling.
#define MADNESS_ASSERT(condition)
Assert a condition that should be free of side-effects since in release builds this might be a no-op.
Definition madness_exception.h:134
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
#define N
Definition testconv.cc:37