Simpatico  v1.10
GStack.h
1 #ifndef UTIL_G_STACK_H
2 #define UTIL_G_STACK_H
3 
4 /*
5 * Util Package - C++ Utilities for Scientific Computation
6 *
7 * Copyright 2010 - 2017, The Regents of the University of Minnesota
8 * Distributed under the terms of the GNU General Public License.
9 */
10 
11 #include <util/containers/GStack.h>
12 #include <util/global.h>
13 
14 namespace Util
15 {
16 
27  template <typename Data>
28  class GStack
29  {
30 
31  public:
32 
36  GStack();
37 
45  GStack(const GStack<Data>& other);
46 
53  ~GStack();
54 
64  GStack<Data>& operator=(const GStack<Data>& other);
65 
75  void reserve(int capacity);
76 
80  void deallocate();
81 
85  void clear();
86 
94  void push(Data& data);
95 
104  Data& pop();
105 
109  Data& peek();
110 
114  const Data& peek() const;
115 
121  int capacity() const;
122 
128  int size() const;
129 
133  bool isAllocated() const;
134 
138  bool isValid() const;
139 
140  private:
141 
143  Data** ptrs_;
144 
146  int capacity_;
147 
149  int size_;
150 
151  };
152 
153  /*
154  * Constructor.
155  */
156  template <typename Data>
158  : ptrs_(0),
159  capacity_(0),
160  size_(0)
161  {}
162 
170  template <typename Data>
172  : ptrs_(0),
173  capacity_(0),
174  size_(0)
175  {
176  assert(other.capacity_ >= other.size_);
177  if (other.ptrs_ == 0) {
178  assert(other.capacity_ == 0);
179  assert(other.size_ == 0);
180  ptrs_ = 0;
181  capacity_ = 0;
182  size_ = 0;
183  } else {
184  assert(other.capacity_ > 0);
185  // Allocate array of Data* pointers
186  Memory::allocate<Data*>(ptrs_, other.capacity_);
187  capacity_ = other.capacity_;
188  size_ = other.size_;
189  // Copy pointers
190  if (size_ > 0) {
191  for (int i = 0; i < size_; ++i) {
192  ptrs_[i] = other.ptrs_[i];
193  }
194  }
195  // Nullify unused elements of ptrs_ array
196  if (capacity_ > size_) {
197  for (int i = size_; i < capacity_; ++i) {
198  ptrs_[i] = 0;
199  }
200  }
201  }
202  }
203 
204  /*
205  * Destructor.
206  */
207  template <typename Data>
209  {
210  size_ = 0;
211  if (isAllocated()) {
212  Memory::deallocate(ptrs_, capacity_);
213  capacity_ = 0;
214  }
215  }
216 
217  /*
218  * Assignment, element by element.
219  */
220  template <typename Data>
222  {
223  // Check for self assignment
224  if (this == &other) return *this;
225 
226  clear();
227  for (int i = 0; i < other.size_; ++i) {
228  append(other[i]);
229  }
230  return *this;
231  }
232 
233  /*
234  * Reserve space for the underlying array of Data* pointers.
235  */
236  template <typename Data>
238  {
239  if (capacity <= 0) {
240  UTIL_THROW("Cannot reserve with capacity <=0");
241  }
242  if (ptrs_ == 0) {
243  assert(capacity_ == 0);
244  assert(size_ == 0);
245  Memory::allocate<Data*>(ptrs_, capacity);
246  capacity_ = capacity;
247  size_ = 0;
248  for (int i = 0; i < capacity_; ++i) {
249  ptrs_[i] = 0;
250  }
251  } else if (capacity > capacity_) {
252  assert(capacity_ > 0);
253  assert(capacity_ >= size_);
254  assert(size_ >= 0);
255  Data** newPtr = 0;
256  Memory::allocate<Data*>(newPtr, capacity);
257  if (size_ > 0) {
258  for (int i = 0; i < size_; ++i) {
259  newPtr[i] = ptrs_[i];
260  }
261  }
262  if (size_ < capacity) {
263  for (int i = size_; i < capacity; ++i) {
264  newPtr[i] = 0;
265  }
266  }
267  Memory::deallocate<Data*>(ptrs_, capacity_);
268  ptrs_ = newPtr;
269  capacity_ = capacity;
270  }
271  }
272 
273  /*
274  * Deallocate associated memory.
275  */
276  template <typename Data>
278  {
279  size_ = 0;
280  if (isAllocated()) {
281  assert(capacity_ > 0);
282  Memory::deallocate<Data*>(ptrs_, capacity_);
283  capacity_ = 0;
284  }
285  }
286 
287  /*
288  * Reset to empty state, without deallocating.
289  */
290  template <typename Data>
291  inline void GStack<Data>::clear()
292  { size_ = 0; }
293 
294  /*
295  * Push an element onto the GStack.
296  */
297  template <typename Data>
298  void GStack<Data>::push(Data& data)
299  {
300  if (!isAllocated()) {
301  assert(capacity_ == 0);
302  Memory::allocate<Data*>(ptrs_, 64);
303  capacity_ = 64;
304  size_ = 0;
305  for (int i = 0; i < capacity_; ++i) {
306  ptrs_[i] = 0;
307  }
308  } else if (size_ == capacity_) {
309  assert(capacity_ > 0);
310  assert(capacity_ >= size_);
311  assert(size_ >= 0);
312  Data** newPtr = 0;
313  Memory::allocate<Data*>(newPtr, 2*capacity_);
314  if (size_ > 0) {
315  for (int i = 0; i < size_; ++i) {
316  newPtr[i] = ptrs_[i];
317  }
318  }
319  if (size_ < 2*capacity_) {
320  for (int i = size_; i < 2*capacity_; ++i) {
321  newPtr[i] = 0;
322  }
323  }
324  Memory::deallocate<Data*>(ptrs_, capacity_);
325  ptrs_ = newPtr;
326  capacity_ = 2*capacity_;
327  // size_ is unchanged
328  }
329 
330  // Append new element
331  assert(size_ <= capacity_);
332  ptrs_[size_] = &data;
333  ++size_;
334  }
335 
336  /*
337  * Pop a Data object off the stack.
338  */
339  template <typename Data>
341  {
342  if (size_ == 0) {
343  UTIL_THROW("Attempt to pop from empty stack");
344  }
345  Data *ptr = ptrs_[size_-1];
346  ptrs_[size_-1] = 0;
347  --size_;
348  return *ptr;
349  }
350 
351  /*
352  * Return a reference to the top element, without popping.
353  */
354  template <typename Data>
355  inline Data& GStack<Data>::peek()
356  { return *ptrs_[size_-1]; }
357 
358  /*
359  * Return a const reference to the top element, without popping.
360  */
361  template <typename Data>
362  inline const Data& GStack<Data>::peek() const
363  { return *ptrs_[size_-1]; }
364 
365  /*
366  * Return current capacity.
367  */
368  template <typename Data>
369  inline int GStack<Data>::capacity() const
370  { return capacity_; }
371 
372  /*
373  * Return logical size.
374  */
375  template <typename Data>
376  inline int GStack<Data>::size() const
377  { return size_; }
378 
379  /*
380  * Is this GStack allocated?
381  */
382  template <class Data>
383  inline bool GStack<Data>::isAllocated() const
384  { return (bool)ptrs_; }
385 
386  /*
387  * Return true if valid, or throw an exception.
388  */
389  template <typename Data>
391  {
392  if (capacity_ < 0) {
393  UTIL_THROW("Negative capacity_");
394  }
395  if (size_ < 0) {
396  UTIL_THROW("Negative size_");
397  }
398  if (size_ > capacity_) {
399  UTIL_THROW("size_ > capacity_");
400  }
401 
402  if (ptrs_ != 0) {
403  int i;
404  for (i = 0; i < size_ ; ++i) {
405  if (ptrs_[i] == 0) {
406  UTIL_THROW("Null ptrs_[i] for i < size_");
407  }
408  }
409  for (i = size_; i < capacity_ ; ++i) {
410  if (ptrs_[i] != 0) {
411  UTIL_THROW("Non-null ptrs_[i] for i >= size_");
412  }
413  }
414  } else {
415  if (capacity_ != 0) {
416  UTIL_THROW("Unallocated stack but capacity != 0");
417  }
418  }
419  return true;
420  }
421 
422 }
423 #endif
void push(Data &data)
Push an element onto the stack.
Definition: GStack.h:298
An automatically growable Stack.
Definition: GStack.h:28
Data & pop()
Pop an element off the stack.
Definition: GStack.h:340
GStack()
Constructor.
Definition: GStack.h:157
void deallocate()
Deallocate (delete) underlying array of pointers.
Definition: GStack.h:277
int capacity() const
Return allocated size.
Definition: GStack.h:369
File containing preprocessor macros for error handling.
GStack< Data > & operator=(const GStack< Data > &other)
Assignment, element by element.
Definition: GStack.h:221
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
Data & peek()
Return a reference to the top element (don&#39;t pop).
Definition: GStack.h:355
bool isValid() const
Is this GStack in a valid internal state?
Definition: GStack.h:390
Utility classes for scientific computation.
Definition: accumulators.mod:1
void clear()
Reset to empty state.
Definition: GStack.h:291
bool isAllocated() const
Is this GStack allocated?
Definition: GStack.h:383
int size() const
Return logical size.
Definition: GStack.h:376
void reserve(int capacity)
Reserve memory for specified number of elements.
Definition: GStack.h:237
static void deallocate(Data *&ptr, size_t size)
Allocate a C array.
Definition: Memory.h:124
~GStack()
Destructor.
Definition: GStack.h:208