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