NAMD
ResizeArrayRaw.h
Go to the documentation of this file.
1 
7 /*
8  Data storage class for ResizeArray and related container classes.
9  Copy and assignment copy raw pointers, use copy() to copy data.
10  Destructor does not delete data, call free first.
11 */
12 
13 
14 #ifndef RESIZEARRAYRAW_H
15 #define RESIZEARRAYRAW_H
16 
17 #include <new>
18 #include <string.h>
19 #include "common.h"
20 
21 #define ResizeArrayGrowthFactor 1.5
22 #define ResizeArrayMinSize 8
23 
24 // Need this juju to use templated friend below
25 template <class Type> class ResizeArray;
26 template <class Type> class SortableResizeArray;
27 template <class Type> class SortedArray;
28 template <class Type> class UniqueSortedArray;
29 template <class Type> class ResizeArrayIter;
30 
31 // Class assumes that one can bit move objects
32 // around on array. This will be true
33 // as long as object has no pointers to itself.
34 template <class Elem> class ResizeArrayRaw {
35 
36  private:
37  Elem *array;
38  unsigned char *varray;
39 
40  // Use of int (int32) is safe for counting elements.
41  int arraySize;
42  int allocSize;
43 
44  // No constructor run on new elements
45  // arraySize is not adjusted, only allocSize
46  void resizeRaw(int size) {
47  if (size <= allocSize) return;
48 
49  // Note that ResizeArrayGrowthFactor is type double so the
50  // multiplication below is also done in double.
51  // Assuming int32, the conversion from double overflows at
52  // allocSize = 1431655765
53  // Conditional remains safe if overflow causes RHS < 0.
54  if (size < (int)(allocSize*ResizeArrayGrowthFactor)) {
55  size = (int)(allocSize*ResizeArrayGrowthFactor);
56  }
57  // The next conditional will test true either for very small or
58  // unallocated arrays or if the above conditional causes overflow.
59  if ( (size-allocSize) < ResizeArrayMinSize) {
60  // Overflow occurs here only when allocSize is within
61  // ResizeArrayMinSize of 2^31.
62  size = allocSize+ResizeArrayMinSize;
63  }
64 
65  // Align everything to 64-byte boundaries (if possible).
66  // Use of sizeof below promotes expression to type size_t.
67  unsigned char *tmpv = new unsigned char[size*sizeof(Elem)+63];
68  //Elem *tmpa = (Elem *)((((long)tmpv)+63L)&(-64L));
69  // Someday we might need this alternate form.
70  //
71  // The following pointer manipulation is dangerous. We should use
72  // reinterpret_cast<uintptr_t> or equivalent to convert tmpv+63
73  // to an unsigned integer type before doing bitwise and operation.
74  //
75  // The 63 value (64-byte alignment) aligns for AVX-512 registers.
76  // Would be better to use a macro or maybe even a template parameter
77  // instead of hard-coding the alignment. With a template parameter,
78  // we could override the alignment where optimization warrants or
79  // target builds towards a particular alignment, e.g., AVX needs
80  // only 32-byte alignment.
81  Elem *tmpa = (Elem *)(tmpv+63 - (((long)(tmpv+63))&(63L)));
82  if (arraySize) CmiMemcpy((void *)tmpa, (void *)array, sizeof(Elem)*arraySize);
83 
84  if (allocSize) delete[] varray;
85  varray = tmpv;
86  array = tmpa;
87  allocSize = size;
88  }
89 
90  friend class ResizeArray<Elem>;
91  friend class SortableResizeArray<Elem>;
92  friend class SortedArray<Elem>;
93  friend class UniqueSortedArray<Elem>;
94  friend class ResizeArrayIter<Elem>;
95 
96  inline int size(void) const { return arraySize; }
97  inline Elem &operator[](int index) const { return array[index]; }
98 
99  // DMK - MIC Support - Allow us to see the buffer's size, not just how much of it is used
100  #if NAMD_MIC != 0
101  inline int bufSize(void) const { return allocSize; }
102  #endif
103 
104  // Default constructor
105  ResizeArrayRaw(void) :
106  array((Elem *)0), varray((unsigned char *)0), arraySize(0), allocSize(0) { }
107 
108  // Encap a pre-existing array
109  ResizeArrayRaw( Elem * * const array, int arraySize, int allocSize) {
110  if (allocSize < arraySize) allocSize = arraySize;
111  this->allocSize = allocSize;
112  this->arraySize = arraySize;
113  varray = (unsigned char *)*array;
114  this->array = (Elem *)*array;
115  *array = 0;
116  }
117 
118  // copy data
119  void copy(const ResizeArrayRaw<Elem> &rar ) {
120 
121  // Clean up this array
122  resize(0);
123  resizeRaw(rar.size());
124 
125  CmiMemcpy((void*)array, (void*)rar.array, sizeof(Elem)*rar.size());
126  arraySize = rar.size();
127  }
128 
129  // Properly constructs default object on new elements
130  // Properly destructs on removed elements
131  // arraySize is properly updated
132  void resize(int size) {
133  int i;
134 
135  if (size < arraySize) {
136  for (i=size; i<arraySize; i++) {
137  array[i].~Elem();
138  }
139  } else if (size > arraySize) {
140  resizeRaw(size);
141  for (i=arraySize; i<size; i++) {
142  new ((void *)&array[i]) Elem;
143  }
144  }
145  arraySize = size;
146  }
147 
148  // needed for ResizeArray destructor
149  void free(void) {
150  for (int i=0; i < arraySize; i++) {
151  array[i].~Elem();
152  }
153  delete[] varray;
154  }
155 
156  // resize to 0 and free storage
157  void clear(void) {
158  free();
159  array = 0;
160  varray = 0;
161  arraySize = 0;
162  allocSize = 0;
163  }
164 
165  inline void del(int index, int number) {
166  if (number) {
167  // Destruct objects to be deleted
168  for (int i=index; i < index+number; i++) {
169  array[i].~Elem();
170  }
171 
172  // Shift down
173  memmove((void *)(array+index),
174  (void *)(array+index+number),
175  (arraySize-number-index)*sizeof(Elem));
176 
177  // fixup size of array
178  arraySize -= number;
179  }
180  }
181 
182 
183  // Insert element in array
184  // If index is over the end of array, default
185  // constructor should be run over blank elements to pad.
186  inline void ins(const Elem &e, int index) {
187  // Size array depending if index is in current array or reaches beyond.
188  if (index < arraySize) {
189  resizeRaw(arraySize+1);
190  // Shift up
191  memmove((void *)(array+index+1),
192  (void *)(array+index),
193  (arraySize-index)*sizeof(Elem));
194  } else {
195  resizeRaw(index+1);
196  }
197 
198  // Write in new element via assignment - allows any refcounting
199  // etc. to take place correctly!
200  new((void *)&array[index]) Elem;
201  array[index] = e;
202 
203  // Take care of fill and setting correct arraySize
204  if (index > arraySize) {
205  for (Elem *tmp = array+arraySize; tmp < array+index; tmp++) {
206  new ((void *)tmp) Elem;
207  }
208  arraySize = index+1;
209  } else {
210  arraySize++;
211  }
212  }
213 
214  inline int find(const Elem &e) const {
215  for (int i=0; i<arraySize; i++) {
216  if (array[i] == e) return i;
217  }
218  return -1;
219  }
220 }; // end template definition
221 
222 #endif
#define ResizeArrayMinSize
#define ResizeArrayGrowthFactor