PSCF v1.1
ArraySet.h
1#ifndef UTIL_ARRAY_SET_H
2#define UTIL_ARRAY_SET_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/Array.h>
12#include <util/containers/PArray.h>
13#include <util/misc/Memory.h>
14#include <util/global.h>
15
16namespace Util
17{
18
19 template <typename Data> class PArrayIterator;
20
45 template <typename Data>
46 class ArraySet : public PArray<Data>
47 {
48
49 using PArray<Data>::ptrs_;
50 using PArray<Data>::capacity_;
51 using PArray<Data>::size_;
52
53 public:
54
58 ArraySet();
59
63 virtual ~ArraySet();
64
77 void allocate(Data const * array, int capacity);
78
86 void allocate(Array<Data> const & array);
87
89
90
99 void append(Data& data);
100
111 void remove(Data const & data);
112
119 Data& pop();
120
124 void clear();
125
127
129
130
144 int index(Data const & data) const;
145
149 bool isAllocated() const;
150
154 bool isValid() const;
155
159 void dump() const;
160
162
163 private:
164
165 // Associated C array of Data
166 const Data* data_;
167
168 // Locations of specific array elements within ptrs_
169 int* tags_;
170
171 // Return the array index in data_ of a Data* pointer
172 int id(Data const* ptr) const;
173
175 ArraySet(ArraySet const &);
176
178 ArraySet& operator = (ArraySet const &);
179
180 };
181
182
183 /*
184 * Default constructor.
185 */
186 template <typename Data>
188 : data_(0),
189 tags_(0)
190 {}
191
192 /*
193 * Destructor.
194 */
195 template <typename Data>
197 {
198 if (ptrs_) {
199 Memory::deallocate<Data*>(ptrs_, capacity_);
200 }
201 if (tags_) {
202 Memory::deallocate<int>(tags_, capacity_);
203 }
204 }
205
206 /*
207 * Create an association with a C array, and allocate required memory.
208 */
209 template <typename Data>
210 void ArraySet<Data>::allocate(Data const * array, int capacity)
211 {
212
213 // Preconditions
214 if (capacity == 0) UTIL_THROW("Zero capacity");
215 if (capacity < 0) UTIL_THROW("Negative capacity");
216 if (array == 0) UTIL_THROW("Null array pointer");
217 if (ptrs_) UTIL_THROW("ptrs_ array already allocated");
218 if (tags_) UTIL_THROW("tags_ array already allocated");
219
220 data_ = array;
221 Memory::allocate<Data*>(ptrs_, capacity);
222 Memory::allocate<int>(tags_, capacity);
223 capacity_ = capacity;
224 size_ = 0;
225
226 for (int i = 0; i < capacity_; ++i) {
227 ptrs_[i] = 0;
228 tags_[i] = -1;
229 }
230
231 }
232
233 /*
234 * Create association with an Array, and allocate required memory.
235 */
236 template <typename Data>
238 { allocate(&array[0], array.capacity()); }
239
240 /*
241 * Append an element to the set.
242 */
243 template <typename Data>
244 void ArraySet<Data>::append(Data& data)
245 {
246 Data* const ptr = &data;
247
248 // Check preconditions
249 if (ptr < data_ || ptr >= data_ + capacity_) {
250 UTIL_THROW("Pointer out of range");
251 }
252 int arrayId = id(ptr);
253 int setId = tags_[arrayId];
254 if (setId >= 0) {
255 UTIL_THROW("Attempt to add element that is already in set");
256 }
257
258 // Add to top of set
259 ptrs_[size_] = ptr;
260 tags_[id(ptr)] = size_;
261 ++size_;
262 }
263
264 /*
265 * Remove a specific element from the set.
266 */
267 template <typename Data>
268 void ArraySet<Data>::remove(Data const & data)
269 {
270 const Data* const ptr = &data;
271
272 // Preconditions
273 if (ptr < data_ || ptr >= data_ + capacity_) {
274 UTIL_THROW("Pointer out of range");
275 }
276 int arrayId = id(ptr);
277 int setId = tags_[arrayId];
278 if (setId < 0) {
279 UTIL_THROW("Element is not in set");
280 }
281
282 // Debug mode preconditions
283 assert(setId < capacity_);
284 assert(ptrs_[setId] == ptr);
285
286 // Remove from set
287 tags_[arrayId] = -1;
288 if (setId != size_ - 1) {
289 ptrs_[setId] = ptrs_[size_-1];
290 tags_[id(ptrs_[setId])] = setId;
291 }
292 ptrs_[size_-1] = 0;
293 --size_;
294
295 }
296
297 /*
298 * Remove the topmost element from the set.
299 */
300 template <typename Data>
302 {
303 // Precondition
304 if (size_ == 0) {
305 UTIL_THROW("Attempt to pop from empty ArraySet");
306 }
307
308 Data* ptr = ptrs_[size_ - 1];
309 tags_[id(ptr)] = -1;
310 ptrs_[size_-1] = 0;
311 --size_;
312 return *ptr;
313 }
314
315 /*
316 * Reset to empty state.
317 */
318 template <typename Data>
320 {
321 assert(ptrs_ != 0);
322 assert(tags_ != 0);
323 size_ = 0;
324 for (int i = 0; i < capacity_; ++i) {
325 ptrs_[i] = 0;
326 tags_[i] = -1;
327 }
328 }
329
334 template <typename Data>
335 int ArraySet<Data>::index(Data const & data) const
336 {
337 const Data* const ptr = &data;
338 if (ptr < data_ || ptr >= data_ + capacity_) {
339 UTIL_THROW("Pointer out of range");
340 }
341 return tags_[id(ptr)];
342 }
343
344 /*
345 * Is this allocated?
346 */
347 template <typename Data>
348 inline bool ArraySet<Data>::isAllocated() const
349 { return ptrs_ != 0; }
350
351 /*
352 * Return true if valid, or throw an exception.
353 */
354 template <typename Data>
356 {
357 int i, j, size;
358
359 if (ptrs_ != 0) {
360 if (tags_ == 0) {
361 UTIL_THROW("ptrs_ is allocated but tags_ is not");
362 }
363
364 // Loop over tags_
365 size = 0;
366 for (i = 0; i < capacity_ ; ++i) {
367 j = tags_[i];
368 if (j >= 0) {
369 if (j >= capacity_) {
370 UTIL_THROW("tags_[i] > capacity_");
371 }
372 if (id(ptrs_[j]) != i) {
373 UTIL_THROW("Inconsistent tags and ptrs: 1");
374 }
375 ++size;
376 }
377 }
378 if (size != size_) {
379 UTIL_THROW("Number of nonnegative tags != size");
380 }
381
382 // Loop over ptrs in set
383 size = 0;
384 for (i = 0; i < size_ ; ++i) {
385 if (ptrs_[i] !=0) {
386 j = id(ptrs_[i]);
387 if (tags_[j] != i) {
388 UTIL_THROW("Inconsistent tags and ptrs: 2");
389 }
390 ++size;
391 } else {
392 UTIL_THROW("Null pointer ptrs_[i] for i < size_");
393 }
394 }
395 if (size != size_) {
396 UTIL_THROW("Number of non-Null pointers != size");
397 }
398
399 // Check empty elements of ptrs_ array
400 for (i = size_; i < capacity_ ; ++i) {
401 if (ptrs_[i] != 0) {
402 UTIL_THROW("Non-null pointer ptrs_[i] for i >= size_");
403 }
404 }
405
406 } else {
407 if (tags_ != 0) {
408 UTIL_THROW("ptrs_ == 0, but tags_ != 0");
409 }
410 if (capacity_ != 0) {
411 UTIL_THROW("ptrs_ == 0, but capacity_ != 0");
412 }
413 if (size_ != 0) {
414 UTIL_THROW("ptrs_ == 0, but size_ != 0");
415 }
416 }
417 return true;
418 }
419
420 // Private inline function
421
422 template <typename Data>
423 inline int ArraySet<Data>::id(Data const * ptr) const
424 { return int(ptr - data_); }
425
426}
427#endif
A set of pointers to a subset of elements of an array.
Definition: ArraySet.h:47
void remove(Data const &data)
Remove an element from the set.
Definition: ArraySet.h:268
virtual ~ArraySet()
Destructor.
Definition: ArraySet.h:196
void append(Data &data)
Append an element to the set.
Definition: ArraySet.h:244
bool isValid() const
Return true if the ArraySet is valid, or throw an exception.
Definition: ArraySet.h:355
void dump() const
Write the internal state of the ArraySet to std::cout.
ArraySet()
Constructor.
Definition: ArraySet.h:187
bool isAllocated() const
Return true if the ArraySet is initialized, false otherwise.
Definition: ArraySet.h:348
void clear()
Reset to empty state.
Definition: ArraySet.h:319
void allocate(Data const *array, int capacity)
Associate with a C array and allocate required memory.
Definition: ArraySet.h:210
int index(Data const &data) const
Return the current index of an element within the set, if any.
Definition: ArraySet.h:335
Data & pop()
Pop the topmost element from the set.
Definition: ArraySet.h:301
Array container class template.
Definition: Array.h:34
int capacity() const
Return allocated size.
Definition: Array.h:159
An array that only holds pointers to its elements.
Definition: PArray.h:37
int capacity_
Allocated size of ptrs_ array.
Definition: PArray.h:93
int capacity() const
Return allocated size.
Definition: PArray.h:133
int size_
Logical size (number of elements with initialized data).
Definition: PArray.h:96
Data ** ptrs_
PArray of of pointers to Data objects.
Definition: PArray.h:90
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