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 
49 namespace 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 
169  using StackBase_::destroy;
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.
226  Stack() :
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.
263  Stack<T,N>& operator=(const Stack<T,N>& other) {
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
272  destroy(data_, data_ + size_);
273  deallocate();
274 
275  data_ = buffer;
276  capacity_ = other.size_;
277  } else {
278  destroy(data_, data_ + size_);
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
299  destroy(data_, data_ + size_);
300  deallocate();
301  move(other);
302  }
303 
304  return *this;
305  }
306 
307  /// Destructor.
308  ~Stack() {
309  destroy(data_, data_ + size_);
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_;
348  destroy(data_ + 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() {
398  destroy(data_, data_ + size_);
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() {
407  destroy(data_, data_ + size_);
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
bool empty() const
Check if the stack is empty.
Definition: stack.h:387
T * data_
Pointer to the stack data.
Definition: stack.h:162
const T * data() const
Data accessor.
Definition: stack.h:417
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
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
T * allocate(const size_type n)
Allocate a raw buffer.
Definition: stack.h:183
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
T * data()
Data accessor.
Definition: stack.h:422
bool empty() const volatile
Check if the stack is empty.
Definition: stack.h:392
Stack< T, N > & operator=(const Stack< T, N > &other)
Assignment operator.
Definition: stack.h:263
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
Stack< T, N > & operator=(Stack< T, N > &&other)
Move assignment operator.
Definition: stack.h:297
detail::StackBase< T, std::is_standard_layout< T >::value &&std::is_trivial< T >::value > StackBase_
Definition: stack.h:167
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
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
char * malloc()
auto T(World &world, response_space &f) -> response_space
Definition: global_functions.cc:34
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
File holds all helper structures necessary for the CC_Operator and CC2 class.
Definition: DFParameters.h:10
#define N
Definition: testconv.cc:37
double u(const double x, const double expnt)
Definition: testperiodic.cc:56