/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #pragma once #include "StandardHeaders.h" #include "MCoreSystem.h" #include "Algorithms.h" #include "MemoryManager.h" namespace MCore { /** * Dynamic array template with a maximum of 65536 items. * It also doesn't store a memory category and maximum number of elements like the MCore::Array template. */ template class SmallArray { public: /** * The memory block ID, used inside the memory manager. * This will make all arrays remain in the same memory blocks, which is more efficient in a lot of cases. * However, array data can still remain in other blocks. */ enum { MEMORYBLOCK_ID = 2 }; /** * Default constructor. * Initializes the array so it's empty and has no memory allocated. */ MCORE_INLINE SmallArray() : mData(nullptr), mLength(0) {} /** * Constructor which creates a given number of elements. * @param elems The element data. * @param num The number of elements in 'elems'. */ MCORE_INLINE explicit SmallArray(T* elems, uint32 num) : mLength(num) { mData = (T*)MCore::Allocate(mLength * sizeof(T), MCORE_MEMCATEGORY_SMALLARRAY, MEMORYBLOCK_ID, MCORE_FILE, MCORE_LINE); for (uint32 i=0; i 0) { mData = (T*)MCore::Allocate(mLength * sizeof(T), MCORE_MEMCATEGORY_SMALLARRAY, MEMORYBLOCK_ID, MCORE_FILE, MCORE_LINE); for (uint32 i=0; i& other) : mData(nullptr), mLength(0) { *this = other; } /** * Move constructor. * @param other The array to move the data from. */ SmallArray(SmallArray&& other) { mData=other.mData; mLength=other.mLength; other.mData=nullptr; other.mLength=0; } /** * Destructor. Deletes all entry data. * However, if you store pointers to objects, these objects won't be deleted.
* Example:
*
         * SmallArray< Object* > data;
         * for (uint32 i=0; i<10; i++)
         *    data.Add( new Object() );
         * 
* Now when the array 'data' will be destructed, it will NOT free up the memory of the integers which you allocated by hand, using new. * In order to free up this memory, you can do this: *
         * for (uint32 i=0; i
         */
        ~SmallArray()                                                            { for (uint32 i=0; i); return result; }

        /**
         * Set a given element to a given value.
         * @param pos The element number.
         * @param value The value to store at that element number.
         */
        MCORE_INLINE void SetElem(uint32 pos, const T& value)                    { mData[pos] = value; }

        /**
         * Add a given element to the back of the array.
         * @param x The element to add.
         */
        MCORE_INLINE void Add(const T& x)                                        { Grow(++mLength); Construct(mLength-1, x); }

        /**
         * Add a given array to the back of this array.
         * @param a The array to add.
         */
        MCORE_INLINE void Add(const SmallArray& a)                            { uint32 l=mLength; Grow(mLength+a.mLength); for (uint32 i=0; i 0) Remove((uint32)0); }

        /**
         * Remove the last array element.
         */
        MCORE_INLINE void RemoveLast()                                            { if (mLength > 0) Destruct(--mLength); }

        /**
         * Insert an empty element (default constructed) at a given position in the array.
         * @param pos The position to create the empty element.
         */
        MCORE_INLINE void Insert(uint32 pos)                                    { Grow(mLength+1); MoveElements(pos+1, pos, mLength-pos-1); Construct(pos); }

        /**
         * Insert a given element at a given position in the array.
         * @param pos The position to insert the empty element.
         * @param x The element to store at this position.
         */
        MCORE_INLINE void Insert(uint32 pos, const T& x)                        { Grow(mLength+1); MoveElements(pos+1, pos, mLength-pos-1); Construct(pos, x); }

        /**
         * Remove an element at a given position.
         * @param pos The element number to remove.
         */
        MCORE_INLINE void Remove(uint32 pos)                                    { Destruct(pos); MoveElements(pos, pos+1, mLength-pos-1); mLength--; }

        /**
         * Remove a given number of elements starting at a given position in the array.
         * @param pos The start element, so to start removing from.
         * @param num The number of elements to remove from this position.
         */
        MCORE_INLINE void Remove(uint32 pos, uint32 num)                        { for (uint32 i=pos; i
         * And we perform a SwapRemove(2), we will remove element C and place the last element (G) at the empty created position where C was located.
         * So we will get this:
* AB.DEFG [where . is empty, after we did the SwapRemove(2)]
* ABGDEF [this is the result. G has been moved to the empty position]. */ MCORE_INLINE void SwapRemove(uint32 pos) { Destruct(pos); if (pos != mLength-1) { Construct(pos, mData[mLength-1]); Destruct(mLength-1); } mLength--; } // remove element at and place the last element of the array in that position /** * Swap two elements. * @param pos1 The first element number. * @param pos2 The second element number. */ MCORE_INLINE void Swap(uint32 pos1, uint32 pos2) { if (pos1 != pos2) MCore::Swap(GetItem(pos1), GetItem(pos2)); } /** * Clear the array contents. So GetLength() will return 0 after performing this method. * @param clearMem If set to true (default) the allocated memory will also be released. If set to false, GetMaxLength() will still return the number of elements * which the array contained before calling the Clear() method. */ MCORE_INLINE void Clear(bool clearMem=true) { for (uint32 i=0; i= newLength) return; uint32 oldLen=mLength; Grow(newLength); for (uint32 i=oldLen; i operators). * The method will sort all elements between the given 'first' and 'last' element (first and last are also included in the sort). * @param first The first element to start sorting. * @param last The last element to sort (when set to MCORE_INVALIDINDEX32, GetLength()-1 will be used). * @param cmp The compare function. */ MCORE_INLINE void Sort(uint32 first=0, uint32 last=MCORE_INVALIDINDEX32, CmpFunc cmp=StdCmp) { if (last==MCORE_INVALIDINDEX32) last=mLength-1; InnerSort(first, last, cmp); } /** * Performs a sort on a given part of the array. * @param first The first element to start the sorting at. * @param last The last element to end the sorting. * @param cmp The compare function. */ MCORE_INLINE void InnerSort(int32 first, int32 last, CmpFunc cmp) { if (first >= last) return; int32 split=Partition(first, last, cmp); InnerSort(first, split-1, cmp); InnerSort(split+1, last, cmp); } /** * Resize the array to a given size. * This does not mean an actual realloc will be made. This will only happen when the new length is bigger than the maxLength of the array. * @param newLength The new length the array should be. * @result returns false if the allocation/reallocation of the array failed */ bool Resize(uint32 newLength) { // check for growing or shrinking array if (newLength > mLength) { // growing array, construct empty elements at end of array uint32 oldLen = mLength; GrowExact(newLength); if (mData == nullptr) { return false; } for (uint32 i=oldLen; i 0) MCore::MemMove(mData+destIndex, mData+sourceIndex, numElements * sizeof(T)); } // operators bool operator==(const SmallArray& other) const { if (mLength != other.mLength) return false; for (uint32 i=0; i& operator= (const SmallArray& other) { if (&other != this) { Clear(); Grow(other.mLength); for (uint32 i=0; i& operator= (SmallArray&& other) { MCORE_ASSERT(&other != this); if (mData!=nullptr) MCore::Free(mData); mData=other.mData; mLength=other.mLength; other.mData=nullptr; other.mLength=0; return *this; } //SmallArray& operator+ (const SmallArray& other) const { SmallArray newArray; newArray.Grow(mLength+other.mLength); uint32 i; for (i=0; i& operator+=(const T& other) { Add(other); return *this; } SmallArray& operator+=(const SmallArray& other) { Add(other); return *this; } MCORE_INLINE T& operator[](const uint32 index) { MCORE_ASSERT(indexFree(); return; } if (mData) mData = (T*)MCore::Realloc(mData, newSize * sizeof(T), MCORE_MEMCATEGORY_SMALLARRAY, MEMORYBLOCK_ID, MCORE_FILE, MCORE_LINE); else mData = (T*)MCore::Allocate(newSize * sizeof(T), MCORE_MEMCATEGORY_SMALLARRAY, MEMORYBLOCK_ID, MCORE_FILE, MCORE_LINE); } MCORE_INLINE void Free() { mLength=0; if (mData) MCore::Free(mData); mData=nullptr; } MCORE_INLINE void Construct(uint32 index, const T& original) { ::new(mData+index) T(original); } // copy-construct an element at which is a copy of MCORE_INLINE void Construct(uint32 index) { ::new(mData+index) T; } // construct an element at place MCORE_INLINE void Destruct(uint32 index) { #if (MCORE_COMPILER == MCORE_COMPILER_MSVC) // work around a compiler bug, marking this index parameter as unused MCORE_UNUSED(index); #endif (mData+index)->~T(); } // destruct an element at // partition part of array (for sorting) int32 Partition(int32 left, int32 right, CmpFunc cmp) { ::MCore::Swap(mData[left], mData[ (left+right)>>1 ]); T& target = mData[right]; int32 i = left-1; int32 j = right; bool neverQuit = true; // workaround to disable a "warning C4127: conditional expression is constant" while (neverQuit) { while (i < j) { if (cmp(mData[++i], target) >= 0) break; } while (j > i) { if (cmp(mData[--j], target) <= 0) break; } if (i >= j) break; ::MCore::Swap(mData[i], mData[j]); } ::MCore::Swap(mData[i], mData[right]); return i; } }; } // namespace MCore