Simpatico  v1.10
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 
16 namespace 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_;
51  using PArray<Data>::size_;
52 
53  public:
54 
58  ArraySet();
59 
63  virtual ~ArraySet();
64 
77  void allocate(const Data* array, int capacity);
78 
86  void allocate(const Array<Data>& array);
87 
89 
90 
99  void append(Data& data);
100 
111  void remove(const Data& data);
112 
119  Data& pop();
120 
124  void clear();
125 
127 
129 
130 
144  int index(const Data& 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(const Data *ptr) const;
173 
175  ArraySet(const ArraySet&);
176 
178  ArraySet& operator = (const ArraySet&);
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(const Data* 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);
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(const Data& 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(const Data& 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(const Data *ptr) const
424  { return int(ptr - data_); }
425 
426 }
427 #endif
int capacity_
Allocated size of ptrs_ array.
Definition: PArray.h:90
ArraySet()
Constructor.
Definition: ArraySet.h:187
void clear()
Reset to empty state.
Definition: ArraySet.h:319
void dump() const
Write the internal state of the ArraySet to std::cout.
void append(Data &data)
Append an element to the set.
Definition: ArraySet.h:244
int capacity() const
Return allocated size.
Definition: PArray.h:130
Array container class template.
Definition: AutoCorrArray.h:28
File containing preprocessor macros for error handling.
void remove(const Data &data)
Remove an element from the set.
Definition: ArraySet.h:268
bool isValid() const
Return true if the ArraySet is valid, or throw an exception.
Definition: ArraySet.h:355
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
int index(const Data &data) const
Return the current index of an element within the set, if any.
Definition: ArraySet.h:335
A container for pointers to a subset of elements of an associated array.
Definition: ArraySet.h:46
Utility classes for scientific computation.
Definition: accumulators.mod:1
int size_
Logical size (number of elements with initialized data).
Definition: PArray.h:93
bool isAllocated() const
Return true if the ArraySet is initialized, false otherwise.
Definition: ArraySet.h:348
void allocate(const Data *array, int capacity)
Associate with a C array and allocate required memory.
Definition: ArraySet.h:210
Forward iterator for a PArray.
Definition: ArraySet.h:19
Data ** ptrs_
PArray of of pointers to Data objects.
Definition: PArray.h:87
virtual ~ArraySet()
Destructor.
Definition: ArraySet.h:196
int size() const
Return logical size.
Definition: PArray.h:137
int capacity() const
Return allocated size.
Definition: Array.h:153
An array that only holds pointers to its elements.
Definition: PArray.h:33
Data & pop()
Pop the topmost from the set.
Definition: ArraySet.h:301