Dynalib Utils
DynaListImpl.h
Go to the documentation of this file.
1 
20 #ifndef DYNALISTIMPL_H
21 #define DYNALISTIMPL_H
22 
23 #include <iostream>
24 #include <type_traits>
25 
26 #include "BitManip.h"
27 #include "DynaAllocImpl.h"
28 #include "DynaList.h"
29 #include "CheckForError.h"
30 #include "Exception.h"
31 
32 #define MAKE_LISTTYPE_INSTANCE(C, T) \
33  template class DynaAllocVect<C>; \
34  template class DynaList<C>; \
35  typedef DynaAllocVect<C> T##AllocVect; \
36  typedef DynaList<C> T##List
37 
38 //===========================================================================
39 // Static Methods
40 //===========================================================================
41 
42 //===========================================================================
43 // Constructors/Destructor
44 //===========================================================================
45 template <class T> DynaList<T>::DynaList() {
46  adjustSize(0);
47 }
48 
49 template <class T> DynaList<T>::DynaList(uint initCapacity) {
50  adjustSize(initCapacity);
51 }
52 
53 template <class T> DynaList<T>::DynaList(T* array, int count) {
54  _insertArray(&array, 0, 0, count);
55 }
56 
57 template <class T> DynaList<T>::~DynaList() {
58  clear();
59  _members = DynaAllocVect<T>::deleteVect(_members, _count, isFlags(OWNS_MEMBERS));
60 }
61 
62 template <class T> DynaList<T>::DynaList(const DynaList<T>& other) {
63  T* item;
64  _count = other._count;
65  _capacity = other._capacity;
66  _flags = other._flags;
67  _members = new T*[other._capacity];
68  for (int i = 0, len = other._capacity; i < len; ++i) {
69  item = other._members[i];
70  if (item != nullptr) {
71  try {
72  T* newItem = item->copy();
73  _members[i] = newItem;
74  }
75  catch (Exception& e) {
76  }
77  }
78  }
79 }
80 
81 template <class T> DynaList<T>* DynaList<T>::copy() {
82  return new DynaList<T>(*this);
83 };
84 
85 //===========================================================================
86 // Private Methods
87 //===========================================================================
88 template <class T> void DynaList<T>::_insertArray(T** array, int arrayOffset, int toIndex, int count) {
89  if ((_count + count) >= _capacity)
90  adjustSizeLog(count);
91  if (toIndex < _count)
92  memmove(_members + toIndex + count, _members + toIndex, (_count - toIndex) * sizeof(T*));
93  _count += count;
94  memmove(_members + toIndex, array + arrayOffset, count * sizeof(T*));
95 }
96 
97 template <class T> void DynaList<T>::_swap(int index1, int index2) {
98  T* tmp = _members[ index1 ];
99  _members[ index1 ] = _members[ index2 ];
100  _members[ index2 ] = tmp;
101 }
102 
103 template <class T> void DynaList<T>::_trimTheCount() {
104  int idx = _count - 1;
105  for (; idx >= 0; --idx) {
106  if (_members[idx] != nullptr)
107  break;
108  }
109  _count = idx + 1;
110 }
111 
112 template <class T> DynaList<T>* DynaList<T>::_copyRange(int frIndex, int toIndex) {
113  int range = toIndex - frIndex + 1;
114  auto* newList = new DynaList<T>(range);
115  newList->setAllFlags(_flags);
116  newList->_insertArray(getInternalTypedArray(), frIndex, 0, range);
117  return newList;
118 }
119 
120 template <class T> void DynaList<T>::_deleteExcessCapacity() {
121  if ((_capacity - _count) >= DynaAllocVect<T>::getAllocUnits())
122  adjustSize(0);
123 }
124 
125 template <class T> void DynaList<T>::_deleteRange(int frIndex, int toIndex) {
126  if (toIndex == END_OF_LIST)
127  toIndex = _count;
128  else
129  ++toIndex;
130  // First go through and delete the items in the range
131  if (isFlags(OWNS_MEMBERS)) {
132  for (int idx = frIndex; idx < toIndex; ++idx) {
133  delete _members[idx];
134  }
135  }
136  // Then slide everything down over the items in the range
137  if (_count > toIndex) {
138  memmove(_members + frIndex, _members + toIndex, (_count - toIndex) * sizeof(T*));
139  }
140  _count -= (toIndex - frIndex);
141  // Null out any remaining slots at the end of the list (the pointers will be in the list twice otherwise)
142  for (int idx = _count; idx < _capacity; ++idx) {
143  _members[idx] = nullptr;
144  }
145  if (isFlags(AUTO_TRIM))
146  _deleteExcessCapacity();
147 }
148 
149 template <class T> void DynaList<T>::_clearRange(int frIndex, int toIndex) {
150  if (toIndex == END_OF_LIST)
151  toIndex = _count - 1;
152  if (isFlags(OWNS_MEMBERS)) {
153  for (int idx = frIndex; idx <= toIndex; ++idx) {
154  delete _members[idx];
155  _members[idx] = nullptr;
156  }
157  }
158  else {
159  for (int idx = frIndex; idx <= toIndex; ++idx) {
160  _members[idx] = nullptr;
161  }
162  }
163  setFlags(PACK_NEEDED);
164  if (isFlags(AUTO_TRIM))
165  _deleteExcessCapacity();
166 }
167 
168 template <class T> void DynaList<T>::_nullRange(int frIndex, int toIndex) {
169  if (toIndex == END_OF_LIST)
170  toIndex = _count - 1;
171  for (int idx = frIndex; idx <= toIndex; ++idx) {
172  _members[idx] = nullptr;
173  }
174  if (isFlags(AUTO_TRIM))
175  _deleteExcessCapacity();
176 }
177 
178 template <class T> void DynaList<T>::_deleteOrClear(int frIndex, int toIndex) {
179  if (isFlags(AUTO_PACK))
180  _deleteRange(frIndex, toIndex);
181  else
182  _clearRange(frIndex, toIndex);
183 }
184 
185 template <class T> bool DynaList<T>::_setAutoPack(bool isPack) {
186  if (isPack) {
187  setFlags(AUTO_PACK);
188  pack();
189  }
190  else
191  clearFlags(AUTO_PACK);
192  return isPack;
193 }
194 
195 template <class T> bool DynaList<T>::_setAutoTrim(bool isTrim) {
196  if (isTrim) {
197  setFlags(AUTO_TRIM);
198  trim();
199  }
200  else
201  clearFlags(AUTO_TRIM);
202  return isTrim;
203 }
204 
205 template <class T> DynaList<T>* DynaList<T>::setAutoPackTrim(bool pack, bool trim) {
206  if (!_setAutoPack(pack))
207  _setAutoTrim(trim);
208  return this;
209 }
210 
211 template <class T> DynaList<T>* DynaList<T>::setOwnsMembers(bool ownsMembers) {
212  if (ownsMembers)
213  setFlags(OWNS_MEMBERS);
214  else
215  clearFlags(OWNS_MEMBERS);
216  return this;
217 }
218 
219 template <class T> int DynaList<T>::_nextFreeSlot() {
220  int idx = 0;
221  for (; idx < _count; ++idx) {
222  if (_members[idx] == nullptr)
223  break;
224  }
225  if ((idx == _count) && (_count >= _capacity))
226  adjustSizeLog(1);
227  return idx;
228 }
229 
230 //===========================================================================
231 // Public Methods
232 //===========================================================================
233 template <class T> DynaList<T>& DynaList<T>::operator+=(T* value) {
234  append(value);
235  return *this;
236 };
237 
238 template <class T> DynaList<T>& DynaList<T>::operator+=(T&& value) {
239  auto v = new T(value);
240  append(v);
241  return *this;
242 }
243 
244 template <class T> DynaList<T>& DynaList<T>::operator-=(int index) {
245  deleteItem(index);
246  return *this;
247 };
248 
249 template <class T> DynaList<T>& DynaList<T>::operator<<(T* value) {
250  append(value);
251  return *this;
252 }
253 
254 template <class T> DynaList<T>& DynaList<T>::operator<<(T&& value) {
255  auto v = new T(value);
256  append(v);
257  return *this;
258 }
259 
260 template <class T> int DynaList<T>::firstNullSlot() {
261  for (int idx = 0; idx < _count; ++idx) {
262  if (_members[idx] == nullptr)
263  return idx;
264  }
265  return INVALID_INDEX;
266 }
267 
268 template <class T> DynaList<T>* DynaList<T>::setCapacity(uint newCapacity) {
269  if (newCapacity != _capacity) {
270  _members = DynaAllocVect<T>::reallocVect(_members, (uint)_capacity, newCapacity, isFlags(OWNS_MEMBERS));
271  _capacity = newCapacity;
272  if (_count > _capacity)
273  _count = _capacity;
274  }
275  return this;
276 }
277 
278 template <class T> void DynaList<T>::adjustSize(int delta) {
279  setCapacity(_count + delta);
280 }
281 
282 template <class T> void DynaList<T>::adjustSizeLog(int delta) {
283  setCapacity(((_count + delta) * 3 / 2) + 1);
284 }
285 
286 template <class T> void DynaList<T>::trim() {
287  _trimTheCount();
288  adjustSize(0);
289 }
290 
291 template <class T> void DynaList<T>::pack() {
292  _trimTheCount();
293  for (int idx = _count - 1; idx >= 0; --idx) {
294  if (_members[idx] == nullptr)
295  remove(idx);
296  }
297 }
298 
299 template <class T> void DynaList<T>::clear() {
300  if (_count > 0)
301  deleteItems(0, _count - 1);
302 }
303 
304 template <class T> int DynaList<T>::indexOf(T* value, uint start, uint step) {
305  uint cnt = getCount();
306  for (uint i = start; i < cnt; i += step) {
307  if (_members[i] == value)
308  return i;
309  }
310  return END_OF_LIST;
311 }
312 
313 template <class T> int DynaList<T>::indexOf(T** value, uint arraySize, uint start, uint step) {
314  uint cnt = getCount();
315  for (uint i = start; i < cnt; i += step) {
316  for (uint j = 0; j < arraySize; ++j) {
317  if (_members[i] == value[j])
318  return i;
319  }
320  }
321  return -1;
322 }
323 
324 template <class T> int DynaList<T>::insert(int index, T* value) {
325  if (!isFlags(AUTO_PACK)) {
326  if (index == FIRST_FREE)
327  index = _nextFreeSlot();
328  else {
329  if (index == END_OF_LIST)
330  index = _count;
331  if (index >= _capacity)
332  adjustSizeLog(index - _capacity + 1);
333  CheckForError::assertValidArg(_members[index] == nullptr, "Slot " + to_string(index) + " is not null");
334  }
335  if (index >= _count)
336  _count = index + 1;
337  }
338  else {
340  if (index == END_OF_LIST)
341  index = _count;
342  else
343  CheckForError::assertInBounds(index, _count);
344  if (_count >= _capacity)
345  adjustSizeLog(1);
346  if (index < _count)
347  memmove(_members + index + 1, _members + index, (_count - index) * sizeof(T*));
348  ++_count;
349  }
350  _members[index] = value;
351  return index;
352 }
353 
354 template <class T> int DynaList<T>::insert(int index, T&& value) {
355  return insert(index, &value);
356 }
357 
358 template <class T> int DynaList<T>::insert(int index, T** array, uint length) {
359  if (length > 0) {
361  if (index == END_OF_LIST)
362  index = _count;
363  else
364  CheckForError::assertInBounds(index, _count);
365  _insertArray(array, 0, index, length);
366  }
367  return index + length - 1;
368 }
369 
370 template <class T> int DynaList<T>::insert(int index, DynaList<T>* list) {
371  int length = list != nullptr ? list->getCount() : 0;
372  return length > 0 ? insert(index, list->getInternalTypedArray(), (uint)length) : END_OF_LIST;
373 }
374 
375 template <class T> int DynaList<T>::append(T* value) {
376  return insert(END_OF_LIST, value);
377 }
378 
379 template <class T> int DynaList<T>::append(T&& value) {
380  return append(&value);
381 }
382 
383 template <class T> int DynaList<T>::append(T** array, uint length) {
384  return insert(END_OF_LIST, array, length);
385 }
386 
387 template <class T> int DynaList<T>::append(DynaList<T>* list) {
388  return insert(END_OF_LIST, list);
389 }
390 
391 template <class T> T* DynaList<T>::set(int index, T* value) {
392  CheckForError::assertInBounds(index, _count - 1);
393  T* oldItem = _members[index];
394  _members[index] = value;
395  return oldItem;
396 }
397 
398 template <class T> void DynaList<T>::move(int index, int destIndex) {
399  CheckForError::assertInBounds(index, _count - 1);
400  CheckForError::assertInBounds(destIndex, _count);
401  if (index != destIndex) {
402  T* item = _members[index];
403  if (destIndex < index) {
404  int moveCount = index - destIndex;
405  if (moveCount == 1)
406  _swap(index, destIndex);
407  else {
408  memmove(_members + destIndex + 1, _members + destIndex, (index - destIndex) * sizeof(T*));
409  _members[destIndex] = item;
410  }
411  }
412  else if (index < --destIndex){
413  int moveCount = destIndex - index;
414  if (moveCount == 1)
415  _swap(index, destIndex);
416  else {
417  memmove(_members + index, _members + index + 1, (destIndex - index) * sizeof(T*));
418  _members[destIndex] = item;
419  }
420  }
421  }
422 }
423 
424 template <class T> void DynaList<T>::slide(int frIndex, int toIndex) {
425  CheckForError::assertInBounds( frIndex, _count - 1 );
426  CheckForError::assertInBounds( toIndex, _count - 1 );
427  if ( frIndex != toIndex ) {
428  T* item = _members[ frIndex ];
429  if ( frIndex < toIndex ) {
430  memmove(_members + frIndex, _members + frIndex + 1, (toIndex - frIndex) * sizeof(T*));
431  _members[ toIndex ] = item;
432  }
433  else {
434  memmove( _members + toIndex + 1, _members + toIndex, (frIndex - toIndex) * sizeof(T*));
435  _members[ toIndex ] = item;
436  }
437  }
438 }
439 
440 template <class T> T* DynaList<T>::remove(int index) {
441  CheckForError::assertInBounds(index, _count - 1);
442  T* item = _members[index];
443  _nullRange(index, index);
444  _deleteOrClear(index, index);
445  return item;
446 }
447 
448 template <class T> DynaList<T>* DynaList<T>::remove(int frIndex, int toIndex) {
449  CheckForError::assertInBounds(frIndex, toIndex);
450  CheckForError::assertInBounds(toIndex, _count - 1);
451  DynaList<T>* newArray = _copyRange(frIndex, toIndex);
452  _nullRange(frIndex, toIndex);
453  _deleteOrClear(frIndex, toIndex);
454  return newArray;
455 }
456 
457 template <class T> void DynaList<T>::deleteItem(int index) {
458  CheckForError::assertInBounds(index, _count - 1);
459  _deleteOrClear(index, index);
460 }
461 
462 template <class T> void DynaList<T>::deleteItems(int frIndex, int toIndex) {
463  CheckForError::assertInBounds(frIndex, toIndex);
464  CheckForError::assertInBounds(toIndex, _count - 1);
465  _deleteOrClear(frIndex, toIndex);
466 }
467 
468 
469 template <class T> void DynaList<T>::push(T* value) {
470  insert(0, value);
471 }
472 
473 template <class T> void DynaList<T>::pushLast(T* value) {
474  append(value);
475 }
476 
477 template <class T> T* DynaList<T>::pop() {
478  if (_count > 0)
479  return remove(0);
480  else
481  throw EmptyStackException();
482 }
483 
484 template <class T> T* DynaList<T>::popLast() {
485  if (_count > 0)
486  return remove(_count - 1);
487  else
488  throw EmptyStackException();
489 }
490 
491 template <class T> DynaListIter<T> DynaList<T>::begin () const {
492  return DynaListIter<T>( this, 0 );
493 }
494 
495 template <class T> DynaListIter<T> DynaList<T>::end () const {
496  return DynaListIter<T>( this, _count );
497 }
498 
499 #endif //DYNALISTIMPL_H
#define END_OF_LIST
Definition: DynaArray.h:19
#define OWNS_MEMBERS
Definition: DynaList.h:26
T * remove(int index)
Definition: DynaListImpl.h:440
static bool assertInBounds(int index, int maxIndex, const std::string &msg="???")
Definition: CheckForError.cpp:42
int insert(int index, T *value)
Definition: DynaListImpl.h:324
void _trimTheCount()
Definition: DynaListImpl.h:103
void push(T *value)
Definition: DynaListImpl.h:469
#define INVALID_INDEX
Definition: DynaArray.h:20
GeneratorWrapper< T > value(T &&value)
Definition: catch.hpp:4005
DynaList< T > * setCapacity(uint newCapacity)
Definition: DynaListImpl.h:268
DynaList< T > * copy() override
Definition: DynaListImpl.h:81
void setAllFlags(uint8_t flags)
Definition: DynaList.h:62
GeneratorWrapper< T > range(T const &start, T const &end, T const &step)
Definition: catch.hpp:4699
static bool assertNotNull(void *obj, const std::string &msg="???")
Definition: CheckForError.cpp:36
uint getCount()
Definition: DynaList.h:80
DynaList()
Definition: DynaListImpl.h:45
void _nullRange(int frIndex, int toIndex)
Definition: DynaListImpl.h:168
void deleteItems(int frIndex, int toIndex)
Definition: DynaListImpl.h:462
void _clearRange(int frIndex, int toIndex)
Definition: DynaListImpl.h:149
void move(int index, int destIndex)
Definition: DynaListImpl.h:398
void _insertArray(T **array, int arrayOffset, int toIndex, int count)
Definition: DynaListImpl.h:88
void deleteItem(int index)
Definition: DynaListImpl.h:457
void _deleteExcessCapacity()
Definition: DynaListImpl.h:120
#define AUTO_TRIM
Definition: DynaArray.h:18
#define AUTO_PACK
Definition: DynaArray.h:16
void _deleteOrClear(int frIndex, int toIndex)
Definition: DynaListImpl.h:178
T ** getInternalTypedArray()
Definition: DynaList.h:86
void pushLast(T *value)
Definition: DynaListImpl.h:473
static T ** deleteVect(T **array, uint arrayCount, bool isOwner)
Definition: DynaAllocImpl.h:103
void pack()
Definition: DynaListImpl.h:291
void clear()
Definition: DynaListImpl.h:299
int _nextFreeSlot()
Definition: DynaListImpl.h:219
std::string trim(std::string const &str)
Returns a new string without whitespace at the start/end.
DynaList< T > * _copyRange(int frIndex, int toIndex)
Definition: DynaListImpl.h:112
void slide(int frIndex, int toIndex)
Definition: DynaListImpl.h:424
DynaListIter< T > end() const
Definition: DynaListImpl.h:495
Definition: DynaList.h:38
bool _setAutoPack(bool isPack)
Definition: DynaListImpl.h:185
int firstNullSlot()
Definition: DynaListImpl.h:260
Definition: Exception.h:65
int indexOf(T *value, uint start, uint step)
Definition: DynaListImpl.h:304
DynaList< T > * setOwnsMembers(bool ownsMembers)
Definition: DynaListImpl.h:211
T * set(int index, T *value)
Definition: DynaListImpl.h:391
#define PACK_NEEDED
Definition: DynaArray.h:17
void adjustSize(int delta)
Definition: DynaListImpl.h:278
static bool assertValidArg(bool expResult, const std::string &msg="???")
Definition: CheckForError.cpp:30
std::string to_string(std::uint64_t x)
Definition: date.h:7722
DynaList< T > & operator-=(int index)
Definition: DynaListImpl.h:244
void _swap(int index1, int index2)
Definition: DynaListImpl.h:97
virtual ~DynaList()
Definition: DynaListImpl.h:57
Definition: Exception.h:13
static T ** reallocVect(T **array, uint oldCount, uint newCount, bool isOwner)
Definition: DynaAllocImpl.h:61
DynaList< T > & operator<<(T *value)
Definition: DynaListImpl.h:249
DynaList< T > & operator+=(T *value)
Definition: DynaListImpl.h:233
void trim()
Definition: DynaListImpl.h:286
DynaListIter< T > begin() const
Definition: DynaListImpl.h:491
T * pop()
Definition: DynaListImpl.h:477
void adjustSizeLog(int delta)
Definition: DynaListImpl.h:282
void _deleteRange(int frIndex, int toIndex)
Definition: DynaListImpl.h:125
bool _setAutoTrim(bool isTrim)
Definition: DynaListImpl.h:195
#define FIRST_FREE
Definition: DynaArray.h:21
int append(T *value)
Definition: DynaListImpl.h:375
Definition: DynaList.h:36
DynaList< T > * setAutoPackTrim(bool pack, bool trim)
Definition: DynaListImpl.h:205
T * popLast()
Definition: DynaListImpl.h:484
Definition: DynaAlloc.h:26