Files
mlpack/fastlib2/fastlib/col/arraylist.h
T

1179 lines
36 KiB
C++

// Copyright 2007 Georgia Institute of Technology. All rights reserved.
/**
* @file arraylist.h
*
* Defines a typical multi-purpose, resizable array and its utilities.
*/
#ifndef COL_ARRAYLIST_H
#define COL_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<typename TElem>
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<Elem>(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 *src, index_t size, index_t cap) {
ARRAYLIST__DEBUG_INIT_OK(this, size, cap);
ot::CopyConstruct(InitRaw(size, cap), src, size);
}
void InitCopy(const Elem *src, index_t size) {
InitCopy(src, 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 at least size active elements,
* adding and constructing 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 a lower bound on the size for the array
*
* @see Resize, GrowTo, Reserve
*/
void SizeAtLeast(index_t size) {
DEBUG_MODIFY_OK(this);
DEBUG_ASSERT(size >= 0);
if (unlikely(size > size_)) {
GrowTo(size);
}
}
/**
* Ensures that an ArrayList has at most size active elements,
* destructing and removing elements as appropriate.
*
* @param size an upper bound on the size for the array
*
* @see Resize, ShrinkTo, Trim
*/
void SizeAtMost(index_t size) {
DEBUG_MODIFY_OK(this);
DEBUG_ASSERT(size >= 0);
if (unlikely(size < size_)) {
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 *src, index_t size) {
InitCopy(src, size);
}
/** Renamed InitSteal */
COMPILER_DEPRECATED
void Steal(const Elem *src, index_t size) {
InitSteal(src, 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();
}
/** Renamed SizeAtLeast */
COMPILER_DEPRECATED
void EnsureSizeAtLeast(index_t size) {
SizeAtLeast(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<typename TElem>
void ArrayList<TElem>::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<typename TElem>
void ArrayList<TElem>::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<typename TElem>
void ArrayList<TElem>::SegmentInit(index_t size, ArrayList *dest) {
ARRAYLIST__DEBUG_POP_BACK_OK(this, size);
DEBUG_INIT_OK(dest);
SegmentInit(size, dest->InitRaw(size));
}
template<typename TElem>
void ArrayList<TElem>::SegmentAppend(index_t size, ArrayList *dest) {
ARRAYLIST__DEBUG_POP_BACK_OK(this, size);
DEBUG_MODIFY_OK(dest);
SegmentInit(size, dest->PushBackRaw(size));
}
template<typename TElem>
void ArrayList<TElem>::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<typename TElem>
void ArrayList<TElem>::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<typename TElem>
void ArrayList<TElem>::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 /* COL_ARRAYLIST_H */