// Copyright 2007 Georgia Institute of Technology. All rights reserved. /** * @file arraylist.h * * Defines a typical multi-purpose, resizable array and its utilities. */ #ifndef COLLECTIONS_ARRAYLIST_H #define COLLECTIONS_ARRAYLIST_H #include "fastlib/base/base.h" #define ARRAYLIST__DEBUG_INIT_OK(who, size, cap) \ DEBUG_INIT_OK(who); \ DEBUG_ASSERT(size >= 0); \ DEBUG_ASSERT(size <= cap); #define ARRAYLIST__DEBUG_PUSH_BACK_OK(who, inc) \ DEBUG_MODIFY_OK(who); \ DEBUG_ASSERT(inc >= 0); #define ARRAYLIST__DEBUG_POP_BACK_OK(who, dec) \ DEBUG_MODIFY_OK(who); \ DEBUG_BOUNDS_INCLUSIVE(dec, who->size()); #define ARRAYLIST__DEBUG_INSERT_OK(who, pos, inc) \ DEBUG_MODIFY_OK(who); \ DEBUG_BOUNDS_INCLUSIVE(pos, who->size()); \ DEBUG_ASSERT(inc >= 0); #define ARRAYLIST__DEBUG_REMOVE_OK(who, pos, dec) \ DEBUG_MODIFY_OK(who); \ DEBUG_BOUNDS_INCLUSIVE(pos, who->size()); \ DEBUG_BOUNDS_INCLUSIVE(dec, who->size() - pos); /** * A typical multi-purpose, resizable array, coded with an emphasis on * speed. Also features debug-mode poisoning and bounds-checking. * * This class is roughly equivalent to std::vector, but with several * important differences. Notably, it relocates objects with a simple * bit-copy, which is potentially much faster than std::vector's use * of the copy constructor but prevents use with objects that have * self-referential points (an uncommon programming practice). Also, * ArrayList is fully FASTlib complient and can store all FASTlib * complient classes (i.e. those that declare OBJECT_TRAVERSAL) even * if they do not have copy constructors. * * As with std::vector, it is unwise to use pointers to objects stored * by ArrayList unless you know the array will not change for the * life-span of the pointer. */ template class ArrayList { public: /** An accessible typedef for the elements in the array. */ typedef TElem Elem; private: Elem *ptr_; // the stored or aliased array index_t size_; // number of active objects index_t cap_; // allocated size of the array; -1 if alias OBJECT_TRAVERSAL_DEPRECATED_COPIES(ArrayList) { // note that only the active objects are copied, etc. OT_OBJ(size_); OT_ALLOC_EXPERT(ptr_, size_, false, i, OT_OBJ(ptr_[i])); } OT_TRANSIENTS(ArrayList) { OT_OBJ(cap_); } OT_REFILL_TRANSIENTS(ArrayList) { // after copy, array is truncated; also unsets aliasing cap_ = size_; } OT_BECOME_ALIAS(ArrayList) { cap_ = -1; } OT_IS_ALIAS(ArrayList) { return cap_ == -1; } OT_ALIAS_METHODS(ArrayList); private: /* Allocates more space; unlikely, so not inlined. */ void IncreaseCap_(index_t cap); /* Convenient one-liner for three assignments. */ void Init_(Elem *ptr, index_t size, index_t cap) { ptr_ = ptr; size_ = size; cap_ = cap; } /* Brings the ArrayList to a default empty state. */ void Reset_() { Init_(NULL, 0, 0); } public: /** * Initializes an ArrayList with a given size and (optionally) * capacity (defaults to size) but does not construct the contents. * * This function can be used to initialize lists that will be * constructed later (e.g. by copy construction) and is needed for * the use of non-default constructors. It is important to * construct or somehow fill the contents of the list before general * use or destruction. * * Note that shallow types (ints, doubles, etc. and types declared * with OBJECT_TRAVERSAL_SHALLOW) have NOP construction and thus no * performance gains come of using this function with them. * * @param size the initial number of elements * @param cap (optional) the initial amount of allocated space * @returns a pointer to the beginning of the array * * @see Init, InitCopy, InitRepeat */ Elem *InitRaw(index_t size, index_t cap) { ARRAYLIST__DEBUG_INIT_OK(this, size, cap); Init_(mem::Alloc(size), size, cap); return ptr_; } Elem *InitRaw(index_t size) { return InitRaw(size, size); } /** * Initializes an empty ArrayList. * * @see InitCopy, InitRepeat, InitRaw, InitAlias, InitSteal */ void Init() { DEBUG_INIT_OK(this); Reset_(); } /** * Initializes an ArrayList with a given size and (optionally) * capacity (defaults to size), default constructing the contents. * * @param size the initial number of elements * @param cap (optional) the initial amount of allocated space * * @see InitCopy, InitRepeat, InitRaw */ void Init(index_t size, index_t cap) { ARRAYLIST__DEBUG_INIT_OK(this, size, cap); ot::Construct(InitRaw(size, cap), size); } void Init(index_t size) { Init(size, size); } /** * Initializes an ArrayList with a given size and (optionally) * capacity (defaults to size), copying some object to each of the * elements. * * @param elem the initial value copied to each element * @param size the initial number of elements * @param cap (optional) the initial amount of allocated space * * @see Init, InitCopy, InitRaw */ void InitRepeat(const Elem &elem, index_t size, index_t cap) { ARRAYLIST__DEBUG_INIT_OK(this, size, cap); ot::RepeatConstruct(InitRaw(size, cap), elem, size); } void InitRepeat(const Elem &elem, index_t size) { InitRepeat(elem, size, size); } /** * Initializes an ArrayList with a given size and (optionally) * capacity (defaults to size), element-wise copying the contents of * another array. (Note that InitCopy of an ArrayList also exists.) * * @param ptr the initial values copied into the array * @param size the initial number of elements * @param cap (optional) the initial amount of allocated space * * @see Init, InitRepeat, InitRaw, InitAlias, InitSteal */ void InitCopy(const Elem *ptr, index_t size, index_t cap) { ARRAYLIST__DEBUG_INIT_OK(this, size, cap); ot::CopyConstruct(InitRaw(size, cap), ptr, size); } void InitCopy(const Elem *ptr, index_t size) { InitCopy(ptr, size, size); } /** * Initializes an ArrayList to a copy of another ArrayList, but with * specified capacity. * * @param src the initial values copied into the array * @param cap the initial amount of allocated space * * @see Init, InitSubCopy */ void InitCopy(const ArrayList &src, index_t cap) { ARRAYLIST__DEBUG_INIT_OK(this, src.size(), cap); InitCopy(src.begin(), src.size(), cap); } /** * Initializes an ArrayList to a copy of a section of another * ArrayList, with (optionally) specified capacity (defaults to the * other list's size). * * @param src the ArrayList to copy from * @param pos the offset into the source list * @param size the number of elements to copy * @param cap (optional) the initial amount of allocated space * * @see Init, InitCopy, InitSubAlias */ void InitSubCopy(const ArrayList &src, index_t pos, index_t size, index_t cap) { ARRAYLIST__DEBUG_INIT_OK(this, size, cap); DEBUG_BOUNDS_INCLUSIVE(pos, src.size()); DEBUG_BOUNDS_INCLUSIVE(size, src.size() - pos); InitCopy(src.begin() + pos, size, capacity); } void InitSubCopy(const ArrayList &src, index_t pos, index_t size) { InitSubCopy(src, pos, size, size); } /** * Initializes an ArrayList as an alias of an array with a given * size. (Note that InitAlias of an ArrayList also exists.) * * It is your responsibility to eventually free the aliased array, * but said array must not be freed or moved for the duration of the * alias's lifespan. * * @param ptr the array to alias * @param size the length of the aliased array * * @see Init, InitCopy, InitSubAlias */ void InitAlias(Elem *ptr, index_t size) { DEBUG_INIT_OK(this); Init_(ptr, size, -1); } /** * Initializes an ArrayList as an alias of a section of another * ArrayList. * * @param src the ArrayList to copy from * @param pos the offset into the source list * @param size the number of elements to copy * * @see Init, InitAlias, InitSubCopy */ void InitSubAlias(const ArrayList &src, index_t pos, index_t size) { DEBUG_INIT_OK(this); DEBUG_BOUNDS_INCLUSIVE(pos, src.size()); DEBUG_BOUNDS_INCLUSIVE(size, src.size() - pos); InitAlias(src.begin() + pos, size); } /** * Initializes an ArrayList directly with an array with a given size * and (optionally) capacity (defaults to size). (Note that * InitSteal of an ArrayList also exists.) * * The input array will be automatically freed when the ArrayList is * destroyed and may be reallocated during use. Because ArrayLists * use mem::Free and mem::Realloc, the array must be allocated with * mem::Alloc (or more appropriately, mem::AllocConstruct) rather * than new[]. * * @param ptr the array to steal (assume deallocation rights) * @param size the number of elements in the stolen array * @param cap (optional) the allocated size of the stolen array * * @see Init, InitCopy, InitAlias */ void InitSteal(Elem *ptr, index_t size, index_t cap) { ARRAYLIST__DEBUG_INIT_OK(this, size, cap); Init_(ptr, size, cap); } void InitSteal(Elem *ptr, index_t size) { InitSteal(ptr, size, size); } /** * Returns a pointer to the beginning of the ArrayList's array and * demotes the ArrayList to an alias (voids deallocation rights). * * It is your responsibility to eventually free the returned array, * but said array must not be freed or moved for the duration of the * (now aliasing) ArrayList's lifespan. Because ArrayLists use * mem::Alloc, the array must be deallocated with mem::Free. * * @see InitSteal */ Elem *ReleasePtr() { DEBUG_MODIFY_OK(this); cap_ = -1; return ptr_; } /** * Exchanges arrays with another ArrayList. * * You can swap aliases and non-aliases safely. Aliases made to * swapped arrays are not invalidated, but still point to the same * elements, i.e. which ArrayLists they alias are also conceptually * swapped. * * @param other the ArrayList to exchange with * * @see InitCopy, InitAlias, InitSteal */ void Swap(ArrayList *other) { // note absense of DEBUG_MODIFY_OK => can swap aliases mem::Swap(this, other); } /** * Increases an ArrayList's size, increasing capacity if needed, and * default constructs newly added elements. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param size the increased size; must be larger than starting size * * @see ShrinkTo, Resize, Reserve */ void GrowTo(index_t size) { DEBUG_MODIFY_OK(this); DEBUG_ASSERT(size >= size_); if (unlikely(size > cap_)) { IncreaseCap_(size + cap_); } ot::Construct(ptr_ + size_, size - size_); size_ = size; } /** * Decreases an ArrayList's size, destructing removed elements. * * This operation does not strictly invalidate pointers into the * ArrayList because it never reallocates to take less space, but * pointers to beyond the new size of the array are invalid because * they reference destructed objects. * * @param size the decreased size; must be less than starting size * * @see GrowTo, Resize, Reserve */ void ShrinkTo(index_t size) { DEBUG_MODIFY_OK(this); DEBUG_BOUNDS_INCLUSIVE(size, size_); ot::Destruct(ptr_ + size, size_ - size); size_ = size; } /** * Changes an ArrayList's size, increasing capacity if needed, and * constructing or destructing elements as appropriate. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param size the new size for the array * * @see GrowTo, ShrinkTo, Reserve, Trim, Clear */ void Resize(index_t size) { DEBUG_MODIFY_OK(this); DEBUG_ASSERT(size >= 0); if (unlikely(size >= size_)) { GrowTo(size); } else { ShrinkTo(size); } } /** * Ensures that an ArrayList has capacity greater than a given size. * * Note that all operations that add elements to ArrayLists will * automatically increase capacity as needed. This command's * purpose it to reduce the frequency of such operations in * hand-tuned situations or to ensure that pointers remain valid * after subsequent resizings (though this practice is error prone * and thus not recommended). * * This operation invalidates all pointers into the ArrayList * (including aliases). * * @param size the needed minimum capacity of the array * * @see Trim, Resize, Clear */ void Reserve(index_t size) { DEBUG_MODIFY_OK(this); DEBUG_ASSERT(size >= 0); if (unlikely(size > cap_)) { ptr_ = mem::Realloc(ptr_, size); cap_ = size; } } /** * Reduces the capacity of an ArrayList to exactly its size. * * This may be useful to conserve memory in certain situations, but * keep in mind that copying, freezing, and serializing ArrayLists * already only uses as much space as is necessary to represent the * active objects. * * This operation invalidates all pointers into the ArrayList * (including aliases). * * @see Reserve, Resize, Clear */ void Trim() { DEBUG_MODIFY_OK(this); ptr_ = mem::Realloc(ptr_, size_); cap_ = size_; } /** * Zeroes the size of an ArrayList and frees its memory. * * This brings an ArrayList to the same state as @c Init() and is * equivalent to @c Resize(0) followed by @c Trim() . This is * slower than just @c Resize(0) because subsequent use needs to * allocate new memory. * * @see Resize, Trim, Reserve */ void Clear() { DEBUG_MODIFY_OK(this); mem::Free(ot::Destruct(ptr_, size_)); Reset_(); } /** * Adds (optionally) inc elements (default 1) to the end of an * ArrayList, but does not construct them. * * It is important for you to construct or otherwise fill added * elements before you use them. * * Note that shallow types (ints, doubles, etc. and types declared * with OBJECT_TRAVERSAL_SHALLOW) have NOP construction and thus no * performance gains come of using this function with them. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param inc (optional) the number of elements to add * @returns a pointer to the first of the added elements * * @see PushBack, PushBackCopy, AppendCopy, PopBackRaw, InsertRaw */ Elem *PushBackRaw(index_t inc = 1) { ARRAYLIST__DEBUG_PUSH_BACK_OK(this, inc); if (unlikely(size_ + inc > cap_)) { IncreaseCap_(size_ + inc + cap_); } Elem *elem = ptr_ + size_; size_ += inc; return elem; } /** * Adds (optionally) inc elements (default 1) to the end of an * ArrayList, default constructing them. * * Equivalent to @c a.GrowTo(a.size() + inc) * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param inc (optional) the number of elements to add * * @see PushBackCopy, AppendCopy, PushBackRaw, PopBack, Insert, * GrowTo */ void PushBack(index_t inc) { ARRAYLIST__DEBUG_PUSH_BACK_OK(this, inc); ot::Construct(PushBackRaw(inc), inc); } Elem &PushBack() { DEBUG_MODIFY_OK(this); return *ot::Construct(PushBackRaw()); } /** * Adds a copy of an element to the end of an ArrayList. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param src the element to add * * @see PushBack, AppendCopy, PopBackInit, InsertCopy */ Elem &PushBackCopy(const Elem &src) { DEBUG_MODIFY_OK(this); return *ot::CopyConstruct(PushBackRaw(), &src); } /** * Adds copies of each element in an array to the end of an * ArrayList. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param src the array of elements to append * @param size the number of elements to append * * @see PushBackCopy, SegmentInit, InfixCopy */ void AppendCopy(const Elem *src, index_t size) { ARRAYLIST__DEBUG_PUSH_BACK_OK(this, size); ot::CopyConstruct(PushBackRaw(size), src, size); } /** * Adds copies of each element in a source ArrayList to the end of * an ArrayList. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param src the Arraylist to append * * @see PushBackCopy, AppendSteal, SegmentInit, InfixCopy */ void AppendCopy(const ArrayList &src) { DEBUG_MODIFY_OK(this); AppendCopy(src.begin(), src.size()); } /** * Moves the elements in a source ArrayList to the end of an * ArrayList, converting the source into a sub-alias. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * Given the above, be careful not to AppendSteal from multiple * ArrayLists and then expect each of them to alias their respective * portions of the created ArrayList. * * @param src the ArrayList to append and steal from * * @see AppendCopy, InfixSteal */ void AppendSteal(ArrayList *src); /** * Removes (optionally) dec elements (default 1) from the end of an * ArrayList, but does not destruct them. * * While it is technically possible to call this function and * destruct elements afterwards, it is recommended for you to * destruct elements first to minimize code change if you have to * move to RemoveRaw. * * Note that shallow types (ints, doubles, etc. and types declared * with OBJECT_TRAVERSAL_SHALLOW) have NOP destruction and thus no * performance gains come of using this function with them. * * @param dec (optional) the number of elements to remove * * @see PopBack, PopBackInit, SegmentInit, PushBackRaw, RemoveRaw */ void PopBackRaw(index_t dec = 1) { ARRAYLIST__DEBUG_POP_BACK_OK(this, dec); size_ -= dec; } /** * Removes (optionally) dec elements (default 1) from the end of an * ArrayList, destructing them. * * Equivalent to @c a.ShrinkTo(a.size() - dec) * * @param dec (optional) the number of elements to remove * * @see PopBackInit, SegmentInit, PopBackRaw, PushBack, Remove, * ShrinkTo */ void PopBack(index_t dec = 1) { ARRAYLIST__DEBUG_POP_BACK_OK(this, dec); ot::Destruct(ptr_ + size_ - dec, dec); PopBackRaw(dec); } /** * Moves an element from the end of an ArrayList to a given location. * * Provided dest must have no clean-up responsibilities. This is * always true of shallow types and generally true of travsered * types that have not been initialized, but can be complicated for * untraversed types that allocate on construction. Consider * calling @c dest->~Elem() before this function, or just using the * element in place followed by a normal PopBack when finished. * * @param dest an uninitialized object to receive the element * * @see PopBack, SegmentInit, PushBackCopy, RemoveInit */ void PopBackInit(Elem *dest) { DEBUG_MODIFY_OK(this); DEBUG_INIT_OK(dest); DEBUG_ASSERT(size_ > 0); mem::Copy(dest, ptr_ + size_ - 1); PopBackRaw(); } /** * Moves multiple elements from the end of an ArrayList to a given * location. * * Provided dest must have no clean-up responsibilities. This is * always true of shallow types and generally true of travsered * types that have not been initialized, but can be complicated for * untraversed types that allocate on construction. Consider * calling @c dest[i].~Elem() before this function, or just using * the element in place followed by a normal PopBack when finished. * * @param size the number of elements to move * @param dest an array of uninitialized objects to receive the * elements * * @see PopBackInit, AppendCopy, RemoveInit */ void SegmentInit(index_t size, Elem *dest) { ARRAYLIST__DEBUG_POP_BACK_OK(this, size); mem::Copy(dest, ptr_ + size_ - size, size); PopBackRaw(size); } /** * Moves multiple elements from the end of an ArrayList to a new * ArrayList. * * @param size the number of elements to move * @param dest an uninitialized ArrayList to receive the elements * * @see PopBackInit, SegmentAppend, AppendCopy, ExtractInit */ void SegmentInit(index_t size, ArrayList *dest); /** * Moves multiple elements from the end of an ArrayList to the end * of another ArrayList. * * @param size the number of elements to move * @param dest an ArrayList to receive the elements * * @see PopBackInit, SegmentInit, AppendCopy, ExtractAppend */ void SegmentAppend(index_t size, ArrayList *dest); /** * Adds (optionally) inc elements (default 1) at a given position in * an ArrayList, but does not construct them. * * It is important for you to construct or otherwise fill added * elements before you use them. * * Note that shallow types (ints, doubles, etc. and types declared * with OBJECT_TRAVERSAL_SHALLOW) have NOP construction and thus no * performance gains come of using this function with them. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param pos the position where new elements should appear * @param inc (optional) the number of elements to add * @returns a pointer to the first of the added elements * * @see Insert, InsertCopy, InfixCopy, RemoveRaw, PushBackRaw */ Elem *InsertRaw(index_t pos, index_t inc = 1) { ARRAYLIST__DEBUG_INSERT_OK(this, pos, inc); if (unlikely(size_ + inc > cap_)) { IncreaseCap_(size_ + inc + cap_); } mem::Move(ptr_ + pos + inc, ptr_ + pos, size_ - pos); size_ += inc; return ptr_ + pos; } /** * Adds (optionally) inc elements (default 1) at a given position in * an ArrayList, default constructing them. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param pos the position where new elements should appear * @param inc (optional) the number of elements to add * * @see InsertCopy, InfixCopy, InsertRaw, Remove, PushBack */ void Insert(index_t pos, index_t inc) { ARRAYLIST__DEBUG_INSERT_OK(this, pos, inc); ot::Construct(InsertRaw(pos, inc), inc); } Elem &Insert(index_t pos) { DEBUG_MODIFY_OK(this); DEBUG_BOUNDS_INCLUSIVE(pos, size_); return *ot::Construct(InsertRaw(pos)); } /** * Adds a copy of an element at a given position in an ArrayList. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param pos the position where the new element should appear * @param src the element to add * * @see Insert, InfixCopy, RemoveInit, PushBackCopy */ Elem &InsertCopy(index_t pos, const Elem &src) { DEBUG_MODIFY_OK(this); DEBUG_BOUNDS_INCLUSIVE(pos, size_); return *ot::CopyConstruct(InsertRaw(pos), &src); } /** * Adds copies of each element in an array at a given position in an * ArrayList. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param pos the position where infixed elements should appear * @param src the array of elements to infix * @param size the number of elements to infix * * @see InsertCopy, ExtractInit, AppendCopy */ void InfixCopy(index_t pos, const Elem *src, index_t size) { ARRAYLIST__DEBUG_INSERT_OK(this, pos, size); ot::CopyConstruct(InsertRaw(pos, size), src, size); } /** * Adds copies of each element in a source ArrayList at a given * position in an ArrayList. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * @param pos the position where infixed elements should appear * @param src the Arraylist to append * * @see InsertCopy, InfixSteal, ExtractInit, AppendCopy */ void InfixCopy(index_t pos, const ArrayList &src) { DEBUG_MODIFY_OK(this); DEBUG_BOUNDS_INCLUSIVE(pos, size_); InfixCopy(pos, src.begin(), src.size()); } /** * Moves the elements in a source ArrayList to a given position in * an ArrayList, converting the source into a sub-alias. * * This operation invalidates all pointers into the ArrayList * (including aliases) unless you can prove that the new size does * not exceed capacity, i.e. you Reserved space before creating the * pointers/aliases. * * Given the above, be careful not to InfixSteal from multiple * ArrayLists and then expect each of them to alias their respective * portions of the created ArrayList, especially because infixed * regions may ultimately (and inappropriately) overlap. * * @param pos the position where infixed elements should appear * @param src the ArrayList to infix and steal from * * @see AppendCopy, InfixSteal */ void InfixSteal(index_t pos, ArrayList *src); /** * Removes (optionally) dec elements (default 1) from a given * position in an ArrayList, but does not destruct them. * * It is important for you to destruct elements before calling this * function, as they will be overwritten. * * Note that shallow types (ints, doubles, etc. and types declared * with OBJECT_TRAVERSAL_SHALLOW) have NOP destruction and thus no * performance gains come of using this function with them. * * @param pos the position of the first element to remove * @param dec (optional) the number of elements to remove * * @see Remove, RemoveInit, ExtractInit, InsertRaw, PopBackRaw */ void RemoveRaw(index_t pos, index_t dec = 1) { ARRAYLIST__DEBUG_REMOVE_OK(this, pos, dec); mem::Move(ptr_ + pos, ptr_ + pos + dec, size_ - dec - pos); size_ -= dec; } /** * Removes (optionally) dec elements (default 1) from a given * position in an ArrayList, destructing them. * * @param pos the position of the first element to remove * @param dec (optional) the number of elements to remove * * @see RemoveInit, ExtractInit, RemoveRaw, Insert, PopBack */ void Remove(index_t pos, index_t dec = 1) { ARRAYLIST__DEBUG_REMOVE_OK(this, pos, dec); ot::Destruct(ptr_ + pos, dec); RemoveRaw(pos, dec); } /** * Moves an element from a given position in an ArrayList to a given * location. * * Provided dest must have no clean-up responsibilities. This is * always true of shallow types and generally true of travsered * types that have not been initialized, but can be complicated for * untraversed types that allocate on construction. Consider * calling @c dest->~Elem() before this function, or just using the * element in place followed by a normal Remove when finished. * * @param pos the position of the element to move * @param dest an uninitialized object to receive the element * * @see Remove, ExtractInit, InsertCopy, PopBackInit */ void RemoveInit(index_t pos, Elem *dest) { DEBUG_MODIFY_OK(this); DEBUG_INIT_OK(dest); DEBUG_BOUNDS(pos, size_); mem::Copy(dest, ptr_ + pos); RemoveRaw(pos); } /** * Moves multiple elements from a given position in an ArrayList to * a given location. * * Provided dest must have no clean-up responsibilities. This is * always true of shallow types and generally true of travsered * types that have not been initialized, but can be complicated for * untraversed types that allocate on construction. Consider * calling @c dest[i].~Elem() before this function, or just using * the element in place followed by a normal Remove when finished. * * @param pos the position of the first element to move * @param size the number of elements to move * @param dest an array of uninitialized objects to receive the * elements * * @see RemoveInit, InfixCopy, PopBackInit */ void ExtractInit(index_t pos, index_t size, Elem *dest) { ARRAYLIST__DEBUG_REMOVE_OK(this, pos, size); mem::Copy(dest, ptr_ + pos, size); RemoveRaw(pos, size); } /** * Moves multiple elements from a given position in an ArrayList to * a new ArrayList. * * @param pos the position of the first element to move * @param size the number of elements to move * @param dest an uninitialized ArrayList to receive the elements * * @see RemoveInit, ExtractAppend, InfixCopy, SegmentInit */ void ExtractInit(index_t pos, index_t size, ArrayList *dest); /** * Moves multiple elements from a given position in an ArrayList to * the end of another ArrayList. * * @param pos the position of the first element to move * @param size the number of elements to move * @param dest an ArrayList to receive the elements * * @see RemoveInit, ExtractInit, InfixCopy, SegmentAppend */ void ExtractAppend(index_t pos, index_t size, ArrayList *dest); /** The number of active elements in the ArrayList. */ index_t size() const { return size_; } /** The allocated number of elements, or -1 if alias. */ index_t capacity() const { return cap_; } /** Whether the ArrayList is empty (size 0). */ bool empty() const { return size_ == 0; } /** Access an element at position i. */ const Elem &operator[] (index_t i) const { DEBUG_BOUNDS(i, size_); return ptr_[i]; } Elem &operator[] (index_t i) { DEBUG_BOUNDS(i, size_); return ptr_[i]; } /** Get a pointer to the beginning of the array. */ const Elem *begin() const { return ptr_; } Elem* begin() { return ptr_; } /** Get a pointer to just past the end of the array. */ const Elem *end() const { return ptr_ + size_; } Elem *end() { return ptr_ + size_; } /** Get the first element in the array, as in @c *a.begin() */ const Elem &front() const { return *ptr_; } Elem &front() { return *ptr_; } /** Get the last element in the array, as in @c *(a.end() - 1) */ const Elem &back() const { return ptr_[size_ - 1]; } Elem &back() { return ptr_[size_ - 1]; } ////////// Deprecated ////////////////////////////////////////////// /** Renamed InitCopy */ COMPILER_DEPRECATED void Copy(const Elem *ptr, index_t size) { InitCopy(ptr, size); } /** Renamed InitSteal */ COMPILER_DEPRECATED void Steal(const Elem *ptr, index_t size) { InitSteal(ptr, size); } /** Renamed InitSteal; other will alias */ COMPILER_DEPRECATED void Steal(ArrayList *other) { InitSteal(other); other->Reset_(); } /** Renamed ReleasePtr; will become alias */ COMPILER_DEPRECATED Elem *ReleasePointer() { Elem *retval = ReleasePtr(); Reset_(); return retval; } /** Renamed Renew */ COMPILER_DEPRECATED void Destruct() { Renew(); } /** Utility under investigation */ void EnsureSizeAtLeast(index_t size) { if (unlikely(size > size_)) { GrowTo(size); } } /** Renamed PushBack; no longer returns pointer */ COMPILER_DEPRECATED Elem *AddBack(index_t inc = 1) { index_t offset = size_; PushBack(inc); return ptr_ + offset; } /** Renamed PushBackRaw */ COMPILER_DEPRECATED Elem *AddBackUnconstructed(index_t inc = 1) { return PushBackRaw(inc); } /** Renamed PushBackCopy */ COMPILER_DEPRECATED Elem *AddBackItem(const Elem &elem) { return &PushBackCopy(elem); } /** Behavior similar to PopBackInit */ COMPILER_DEPRECATED Elem *PopBackPtr() { PopBackRaw(); return end(); } }; template void ArrayList::IncreaseCap_(index_t cap) { // round up capcity for possible paging performance cap = (cap + sizeof(long) - 1) & ~(sizeof(long) - 1); ptr_ = mem::Realloc(ptr_, cap); cap_ = cap; } template void ArrayList::AppendSteal(ArrayList *src) { DEBUG_MODIFY_OK(this); DEBUG_MODIFY_OK(src); Elem *elem = PushBackRaw(src->size()); mem::Copy(elem, src->begin(), src->size()); mem::Free(src->ptr_); src->ptr_ = elem; src->cap_ = -1; } template void ArrayList::SegmentInit(index_t size, ArrayList *dest) { ARRAYLIST__DEBUG_POP_BACK_OK(this, size); DEBUG_INIT_OK(dest); SegmentInit(size, dest->InitRaw(size)); } template void ArrayList::SegmentAppend(index_t size, ArrayList *dest) { ARRAYLIST__DEBUG_POP_BACK_OK(this, size); DEBUG_MODIFY_OK(dest); SegmentInit(size, dest->PushBackRaw(size)); } template void ArrayList::InfixSteal(index_t pos, ArrayList *src) { DEBUG_MODIFY_OK(this); DEBUG_MODIFY_OK(src); DEBUG_BOUNDS_INCLUSIVE(pos, size_); Elem *elem = InsertRaw(pos, src->size()); mem::Copy(elem, src->begin(), src->size()); mem::Free(src->ptr_); src->ptr_ = elem; src->cap_ = -1; } template void ArrayList::ExtractInit(index_t pos, index_t size, ArrayList *dest) { ARRAYLIST__DEBUG_REMOVE_OK(this, pos, size); DEBUG_INIT_OK(dest); ExtractInit(pos, size, dest->InitRaw(size)); } template void ArrayList::ExtractAppend(index_t pos, index_t size, ArrayList *dest) { ARRAYLIST__DEBUG_REMOVE_OK(this, pos, size); DEBUG_MODIFY_OK(dest); ExtractInit(pos, size, dest->PushBackRaw(size)); } #undef ARRAYLIST__DEBUG_REMOVE_OK #undef ARRAYLIST__DEBUG_INSERT_OK #undef ARRAYLIST__DEBUG_POP_BACK_OK #undef ARRAYLIST__DEBUG_PUSH_BACK_OK #undef ARRAYLIST__DEBUG_INIT_OK #endif