Advertisement
Guest User

Untitled

a guest
Mar 18th, 2018
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.00 KB | None | 0 0
  1. /*
  2. =============================================================================
  3.     File:   DynamicArray.h
  4.     Desc:   Dynamic (variable sized) templated array.
  5.     The array is always stored in a contiguous chunk.
  6.     The array can be resized.
  7.     A size increase will cause more memory to be allocated,
  8.     and may result in relocation of the array memory.
  9.     A size decrease has no effect on the memory allocation.
  10. =============================================================================
  11. */
  12. #pragma once
  13.  
  14. #include <Base/Template/Containers/Array/Array.h>
  15.  
  16. template
  17. <
  18.     typename TYPE,  //!< The type of stored elements
  19.     UINT ALIGNMENT = GET_ALIGNMENT_FOR_CONTAINERS(TYPE) //!< Alignment of allocated memory
  20. >
  21. class DynamicArray
  22.     : public TArrayTraits< TYPE, DynamicArray< TYPE > >
  23. {
  24. public_internal:    // Calling member functions is slow in debug builds.
  25.     TYPE *  mData;  //!< The pointer to the allocated memory.
  26.     AHeap & mHeap;  //!< The allocator used by this array.
  27.     U32     mNum;   //!< The number of valid, 'live' elements, this should be inside the range [0..mMax).
  28.     U32     mMax;   //!< The number of allocated entries + highest bit is set if we cannot deallocate the memory.
  29.     friend class ArrayUtil;
  30. public:
  31.     // 1 bit is used for indicating if the memory was externally allocated (and the array cannot delete it)
  32.     enum { CAPACITY_BITS = (sizeof(U32) * BITS_IN_BYTE) - 1 };
  33.  
  34.     enum We_Store_Capacity_And_Bit_Flags_In_One_Int
  35.     {
  36.         DONT_FREE_MEMORY_MASK = U32(1 << CAPACITY_BITS),    //!< Indicates that the storage is not the array's to delete.
  37.         EXTRACT_CAPACITY_MASK = U32(~DONT_FREE_MEMORY_MASK),
  38.         //TODO: CAN_MODIFY_MEMORY_MASK
  39.     };
  40.  
  41. public:
  42.     DynamicArray( AHeap & _heap )
  43.         : mHeap( _heap )
  44.     {
  45.         mData = nil;
  46.         mNum = 0;
  47.         mMax = 0;
  48.     }
  49.     explicit DynamicArray( const DynamicArray& other )
  50.         : mHeap( other.mHeap )
  51.     {
  52.         mData = nil;
  53.         mNum = 0;
  54.         mMax = 0;
  55.         this->Copy( other );
  56.     }
  57.     /// NOTE: the 'externalStorage' must be uninitialized!
  58.     DynamicArray( TYPE* externalStorage, U32 maxCount )
  59.     {
  60.         mData = nil;
  61.         mNum = 0;   // data is preallocated, but not constructed yet
  62.         mMax = 0;
  63.         this->SetExternalData( externalStorage, maxCount );
  64.     }
  65.  
  66.     /// Use it only if you know what you're doing.
  67.     explicit DynamicArray(ENoInit)
  68.     {}
  69.  
  70.     /// Destructs array elements and deallocates array memory.
  71.     ~DynamicArray()
  72.     {
  73.         this->clear();
  74.     }
  75.  
  76.     /// use it only if you know whatcha doin'
  77.     void SetExternalData( TYPE* data, U32 maxCount, U32 newCount = 0 )
  78.     {
  79.         mxASSERT(mData == nil && mMax == 0);
  80.         mData = data;
  81.         mNum = newCount;
  82.         mMax = maxCount;
  83.         mMax |= DONT_FREE_MEMORY_MASK;
  84.     }
  85.  
  86.     // Returns the current capacity of this array.
  87.     U32 capacity() const
  88.     {
  89.         U32 capacity = (mMax & EXTRACT_CAPACITY_MASK);
  90.         return capacity;
  91.     }
  92.  
  93.     /// Convenience function to get the number of elements in this array.
  94.     /// Returns the size (the number of elements in the array).
  95.     U32 num() const {
  96.         return mNum;
  97.     }
  98.  
  99.     TYPE * raw() {
  100.         return mData;
  101.     }
  102.     const TYPE* raw() const {
  103.         return mData;
  104.     }
  105.  
  106.     mxFORCEINLINE const Range< TYPE > getSlice() const
  107.     {
  108.         return Range< TYPE >( mData, mNum );
  109.     }
  110.  
  111.     mxFORCEINLINE Range< TYPE > getSlice()
  112.     {
  113.         return Range< TYPE >( mData, mNum );
  114.     }
  115.  
  116.     /// use it only if you know whatcha doin'
  117.     void setReference( Range< TYPE > & slice )
  118.     {
  119.         mxASSERT(mData == nil && mMax == 0);
  120.         mData = slice.raw();
  121.         mNum = slice.num();
  122.         mMax = slice.num();
  123.         mMax |= DONT_FREE_MEMORY_MASK;
  124.     }
  125.  
  126.  
  127.     /// Convenience function to empty the array. Doesn't release allocated memory.
  128.     /// Doesn't call objects' destructors.
  129.     void empty()
  130.     {
  131.         mNum = 0;
  132.     }
  133.  
  134.     /// Convenience function to empty the array. Doesn't release allocated memory.
  135.     /// Invokes objects' destructors.
  136.     void destroyAndEmpty()
  137.     {
  138.         TDestructN_IfNonPOD( mData, mNum );
  139.         this->empty();
  140.     }
  141.  
  142.     /// Releases allocated memory (calling destructors of elements) and empties the array.
  143.     void clear()
  144.     {
  145.         if(PtrToBool( mData ))
  146.         {
  147.             TDestructN_IfNonPOD( mData, mNum );
  148.             this->_releaseMemory();
  149.             mData = nil;
  150.         }
  151.         mNum = 0;
  152.         mMax = 0;
  153.     }
  154.  
  155.     /// Resizes the array to exactly the number of elements it contains or frees up memory if empty.
  156.     void shrink()
  157.     {
  158.         // Condense the array.
  159.         if( mNum > 0 ) {
  160.             this->resize( mNum );
  161.         } else {
  162.             this->clear();
  163.         }
  164.     }
  165.  
  166.     /// See: http://www.codercorner.com/blog/?p=494
  167.     void EmptyOrClear()
  168.     {
  169.         const U32 capacity = this->capacity();
  170.         const U32 num = this->num();
  171.         if( num > capacity/2 ) {
  172.             this->empty();
  173.         } else {
  174.             this->clear();
  175.         }
  176.     }
  177.  
  178.     /// Adds an element to the end.
  179.     ERet add( const TYPE& newOne )
  180.     {
  181.         mxDO(this->reserve( mNum + 1 ));
  182.         new(&mData[ mNum++ ]) TYPE( newOne );   // copy-construct
  183.         return ALL_OK;
  184.     }
  185.  
  186.     /// Increments the size and returns a reference to the first default-constructed element.
  187.     TYPE & AddNew()
  188.     {
  189.         this->reserve( mNum + 1 );
  190.         //NOTE: do not use TYPE(), because it zeroes out PODs, stealing CPU cycles
  191.         return *new(&mData[ mNum++ ]) TYPE;
  192.     }
  193.     ERet AddMany( const TYPE* items, U32 numItems )
  194.     {
  195.         const U32 oldNum = mNum;
  196.         const U32 newNum = oldNum + numItems;
  197.         mxDO(this->setNum( newNum ));
  198.         TCopyArray( mData + oldNum, items, numItems );
  199.         return ALL_OK;
  200.     }
  201.  
  202.     TYPE & AddUninitialized()
  203.     {
  204.         this->reserve( mNum + 1 );
  205.         return mData[ mNum++ ];
  206.     }
  207.     TYPE* AddManyUninitialized( U32 numElements )
  208.     {
  209.         const U32 oldNum = mNum;
  210.         const U32 newNum = oldNum + numElements;
  211.         if(mxFAILED(this->reserve( newNum ))) {return nil;}
  212.         mNum = newNum;
  213.         return mData + oldNum;
  214.     }
  215.     ERet AddZeroed( U32 numElements )
  216.     {
  217.         mxSTATIC_ASSERT(TypeTrait<TYPE>::IsPlainOldDataType);
  218.         const U32 newNum = mNum + numElements;
  219.         mxDO(this->reserve( newNum ));
  220.         MemZero( (BYTE*)mData + mNum*sizeof(TYPE), numElements*sizeof(TYPE) );
  221.         mNum = newNum;
  222.         return ALL_OK;
  223.     }
  224.  
  225.     /// assumes that the user has allocated enough space
  226.     void AddFast_Unsafe( const TYPE& newOne )
  227.     {
  228.         mxASSERT( mNum < this->capacity() );
  229.         new(&mData[ mNum++ ]) TYPE( newOne );   // copy-construct
  230.     }
  231.  
  232.     // Slow!
  233.     bool AddUnique( const TYPE& item )
  234.     {
  235.         const U32 num = mNum;
  236.         for( U32 i = 0; i < num; i++ )
  237.         {
  238.             if( mData[i] == item ) {
  239.                 return false;
  240.             }
  241.         }
  242.         this->add( item );
  243.         return true;
  244.     }
  245.  
  246.     // Slow!
  247.     bool Remove( const TYPE& item )
  248.     {
  249.         return Arrays::RemoveElement( *this, item );
  250.     }
  251.  
  252.     // Slow!
  253.     void RemoveAt( U32 index, U32 count = 1 )
  254.     {
  255.         Arrays::RemoveAt( mData, mNum, index, count );
  256.     }
  257.  
  258.     // this method is faster (uses the 'swap trick')
  259.     // Doesn't preserve the relative order of elements.
  260.     void RemoveAt_Fast( U32 index )
  261.     {//I KNOW THIS IS CRAP!
  262.         Arrays::RemoveAt_Fast( mData, mNum, index );
  263.     }
  264.  
  265.     // Removes all occurrences of value in the array
  266.     // and returns the number of entries removed.
  267.     //
  268.     U32 RemoveAll( const TYPE& theValue )
  269.     {
  270.         U32 numRemoved = 0;
  271.         for( U32 i = 0; i < mNum; ++i )
  272.         {
  273.             if( mData[i] == theValue ) {
  274.                 this->RemoveAt( i );
  275.                 numRemoved++;
  276.             }
  277.         }
  278.         return numRemoved;
  279.     }
  280.  
  281.     // removes the last element
  282.     TYPE PopLastValue()
  283.     {
  284.         mxASSERT(mNum > 0);
  285.         return mData[ --mNum ];
  286.     }
  287.  
  288.     // Slow!
  289.     // inserts a new element at the given index and keeps the relative order of elements.
  290.     TYPE & InsertAt( U32 index )
  291.     {
  292.         mxASSERT( this->isValidIndex( index ) );
  293.         const U32 oldNum = mNum;
  294.         const U32 newNum = oldNum + 1;
  295.         TYPE* data = mData;
  296.         this->reserve( newNum );
  297.         for ( U32 i = oldNum; i > index; --i )
  298.         {
  299.             data[i] = data[i-1];
  300.         }
  301.         mNum = newNum;
  302.         return data[ index ];
  303.     }
  304.  
  305.     U32 RemoveContainedItem( const TYPE* o )
  306.     {
  307.         const U32 itemIndex = this->GetContainedItemIndex( o );
  308.         chkRET_X_IF_NOT( this->isValidIndex( itemIndex ), INDEX_NONE );
  309.         this->RemoveAt( itemIndex );
  310.         return itemIndex;
  311.     }
  312.  
  313.     /// Ensures no reallocation occurs until at least size 'numElements'.
  314.     ERet reserve( U32 numElements )
  315.     {
  316.     //  mxASSERT( numElements > 0 );//<- this helped me to catch errors
  317.         mxASSERT( numElements <= DBG_MAX_ARRAY_CAPACITY );
  318.         // resize if necessary
  319.         if( numElements > this->capacity() )
  320.         {
  321.             const U32 newCapacity = ArrayUtil::CalculateNewCapacity( numElements );
  322.             mxDO(this->resize( newCapacity ));
  323.         }
  324.         return ALL_OK;
  325.     }
  326.  
  327.     /// Sets the new number of elements. Resizes the array to this number if necessary.
  328.     /// NOTE: invokes the new objects' constructors!
  329.     ERet setNum( U32 numElements )
  330.     {
  331.         // resize to the exact size specified irregardless of granularity.
  332.         if( numElements > this->capacity() )
  333.         {
  334.             mxDO(this->resize( numElements ));
  335.         }
  336.         // Call default constructors for new elements.
  337.         if( numElements > mNum )
  338.         {
  339.             const U32 numNewItems = numElements - mNum;
  340.             TConstructN_IfNonPOD( mData + mNum, numNewItems );
  341.         }
  342.         mNum = numElements;
  343.         return ALL_OK;
  344.     }
  345.  
  346.     bool ownsMemory() const
  347.     {
  348.         return (mMax & DONT_FREE_MEMORY_MASK) == 0;
  349.     }
  350.  
  351.     // Returns the amount of reserved memory in bytes (memory allocated for storing the elements).
  352.     size_t allocatedMemorySize() const
  353.     {
  354.         return this->capacity() * sizeof(TYPE);
  355.     }
  356.  
  357.     // Returns the total amount of occupied memory in bytes.
  358.     size_t usedMemorySize() const
  359.     {
  360.         return this->allocatedMemorySize() + sizeof(*this);
  361.     }
  362.  
  363.     friend void F_UpdateMemoryStats( MemStatsCollector& stats, const DynamicArray& o )
  364.     {
  365.         stats.staticMem += sizeof(o);
  366.         stats.dynamicMem += o.allocatedMemorySize();
  367.     }
  368.  
  369. public: // Reflection.
  370.  
  371.     typedef
  372.     DynamicArray
  373.     ARRAY_TYPE;
  374.  
  375.     class ArrayDescriptor : public MetaArray
  376.     {
  377.     public:
  378.         ArrayDescriptor( const Chars& typeName )
  379.             : MetaArray( typeName, STypeDescription::For_Type<ARRAY_TYPE>(), T_DeduceTypeInfo<TYPE>(), sizeof(TYPE) )
  380.         {}
  381.         //=-- MetaArray
  382.         virtual bool IsDynamic() const override
  383.         {
  384.             return true;
  385.         }
  386.         virtual void* Get_Array_Pointer_Address( const void* pArrayObject ) const override
  387.         {
  388.             const ARRAY_TYPE* theArray = static_cast< const ARRAY_TYPE* >( pArrayObject );
  389.             return c_cast(void*) &theArray->mData;
  390.         }
  391.         virtual U32 Generic_Get_Count( const void* pArrayObject ) const override
  392.         {
  393.             const ARRAY_TYPE* theArray = static_cast< const ARRAY_TYPE* >( pArrayObject );
  394.             return theArray->num();
  395.         }
  396.         virtual ERet Generic_Set_Count( void* pArrayObject, U32 newNum ) const override
  397.         {
  398.             ARRAY_TYPE* theArray = static_cast< ARRAY_TYPE* >( pArrayObject );
  399.             mxDO(theArray->setNum( newNum ));
  400.             return ALL_OK;
  401.         }
  402.         virtual U32 Generic_Get_Capacity( const void* pArrayObject ) const override
  403.         {
  404.             const ARRAY_TYPE* theArray = static_cast< const ARRAY_TYPE* >( pArrayObject );
  405.             return theArray->capacity();
  406.         }
  407.         virtual ERet Generic_Set_Capacity( void* pArrayObject, U32 newNum ) const override
  408.         {
  409.             ARRAY_TYPE* theArray = static_cast< ARRAY_TYPE* >( pArrayObject );
  410.             mxDO(theArray->reserve( newNum ));
  411.             return ALL_OK;
  412.         }
  413.         virtual void* Generic_Get_Data( void* pArrayObject ) const override
  414.         {
  415.             ARRAY_TYPE* theArray = static_cast< ARRAY_TYPE* >( pArrayObject );
  416.             return theArray->raw();
  417.         }
  418.         virtual const void* Generic_Get_Data( const void* pArrayObject ) const override
  419.         {
  420.             const ARRAY_TYPE* theArray = static_cast< const ARRAY_TYPE* >( pArrayObject );
  421.             return theArray->raw();
  422.         }
  423.         virtual void SetDontFreeMemory( void* pArrayObject ) const override
  424.         {
  425.             ARRAY_TYPE* theArray = static_cast< ARRAY_TYPE* >( pArrayObject );
  426.             theArray->mMax |= DONT_FREE_MEMORY_MASK;
  427.         }
  428.     };
  429.  
  430. public: // Binary Serialization.
  431.  
  432.     friend AWriter& operator << ( AWriter& file, const DynamicArray& o )
  433.     {
  434.         const U32 number = o.mNum;
  435.         file << number;
  436.  
  437.         file.SerializeArray( o.mData, number );
  438.  
  439.         return file;
  440.     }
  441.     friend AReader& operator >> ( AReader& file, DynamicArray& o )
  442.     {
  443.         U32 number;
  444.         file >> number;
  445.         o.setNum( number );
  446.  
  447.         file.SerializeArray( o.mData, number );
  448.  
  449.         return file;
  450.     }
  451.     friend mxArchive& operator && ( mxArchive & archive, DynamicArray & o )
  452.     {
  453.         U32 num = o.num();
  454.         archive && num;
  455.  
  456.         if( archive.IsReading() )
  457.         {
  458.             o.setNum( num );
  459.         }
  460.  
  461.         TSerializeArray( archive, o.mData, num );
  462.  
  463.         return archive;
  464.     }
  465.  
  466. public:
  467.     //TODO: make special shrink(), ReserveAndGrowByHalf(newCapacity) and ReserveAndGrowByNumber(newCapacity,granularity) ?
  468.  
  469.     //TODO: sorting, binary search, algorithms & iterators
  470.  
  471.     // Deep copy. Slow!
  472.     /// copy-assignment operator
  473.     void operator = ( const DynamicArray& other )
  474.     {
  475.         this->Copy( other );
  476.     }
  477.     mxTODO("move-assignment operator");
  478.  
  479.     template< class OTHER_ARRAY >
  480.     ERet Copy( const OTHER_ARRAY& other )
  481.     {
  482.         const U32 newNum = other.num();
  483.         mxASSERT(newNum < DBG_MAX_ARRAY_CAPACITY);
  484.         //@todo: copy memory allocator?
  485.         mxDO(this->setNum( newNum ));
  486.         if( newNum )
  487.         {
  488.             mxWARNING_NOTE("untested: CopyConstruct should be faster then Assignment");
  489.             //TCopyArray( mData, other.raw(), newNum );
  490.             TCopyConstructArray( mData, other.raw(), newNum );
  491.         }
  492.         return ALL_OK;
  493.     }
  494.  
  495.     void AddBytes( const void* src, size_t numBytes )
  496.     {
  497.         mxSTATIC_ASSERT( sizeof(TYPE) == sizeof(BYTE) );
  498.         const size_t oldNum = mNum;
  499.         const size_t newNum = oldNum + numBytes;
  500.         this->setNum( newNum );
  501.         memcpy( (BYTE*)mData + oldNum, src, numBytes );
  502.     }
  503.  
  504.     template< typename U >
  505.     void CopyFromArray( const U* src, U32 num )
  506.     {
  507.         this->setNum( num );
  508.         for( U32 i = 0; i < num; i++ )
  509.         {
  510.             mData[ i ] = src[ i ];
  511.         }
  512.     }
  513.     template< typename U, size_t N >
  514.     void CopyFromArray( const U (&src)[N] )
  515.     {
  516.         this->CopyFromArray( src, N );
  517.     }
  518.  
  519.     ERet AppendOther( const DynamicArray& other )
  520.     {
  521.         const U32 oldNum = mNum;
  522.         const U32 newNum = oldNum + other.num();
  523.         mxDO(this->setNum( newNum ));
  524.         TCopyArray( mData + oldNum, other.mData, other.num() );
  525.         return ALL_OK;
  526.     }
  527.  
  528.     //NOTE:extremely slow!
  529.     DynamicArray& AppendUniqueElements( const DynamicArray& other )
  530.     {
  531.         for( U32 i = 0; i < other.num(); i++ )
  532.         {
  533.             if(!this->contains( other[i] ))
  534.             {
  535.                 this->add( other[i] );
  536.             }
  537.         }
  538.         return *this;
  539.     }
  540.  
  541.     // works only with types that can be copied via assignment
  542.     // returns the number of removed elements
  543.     //
  544.     template< class FUNCTOR >
  545.     U32 Do_RemoveIf( FUNCTOR& functor )
  546.     {
  547.         const U32 oldNum = mNum;
  548.         U32 newNum = 0;
  549.         for( U32 i = 0; i < oldNum; i++ )
  550.         {
  551.             // if no need to remove this element
  552.             if( !functor( mData[i] ) )
  553.             {
  554.                 // then copy it
  555.                 mData[ newNum++ ] = mData[ i ];
  556.             }
  557.             // otherwise, skip it
  558.         }
  559.         mNum = newNum;
  560.         return (oldNum - newNum);
  561.     }
  562.  
  563. public:
  564.     // Testing, Checking & Debugging.
  565.  
  566.     // you better check urself, before u wreck urself
  567.     bool DbgCheckSelf() const
  568.     {
  569.         //chkRET_FALSE_IF_NOT( IsPowerOfTwo( this->capacity() ) );
  570.         chkRET_FALSE_IF_NOT( this->capacity() <= DBG_MAX_ARRAY_CAPACITY );
  571.         chkRET_FALSE_IF_NOT( mNum <= this->capacity() );//this can happen after AddFast_Unsafe()
  572.         chkRET_FALSE_IF_NOT( mData );
  573.         chkRET_FALSE_IF_NOT( sizeof(U32) <= sizeof(U32) );//need to impl size_t for 64-bit systems
  574.         return true;
  575.     }
  576.  
  577. private:
  578.     void _releaseMemory()
  579.     {
  580.         if( this->ownsMemory() )
  581.         {
  582.             mHeap.Deallocate( mData/*, this->capacity() * sizeof(TYPE)*/ );
  583.             mData = nil;
  584.         }
  585.     }
  586.  
  587.     /// allocates more memory if needed, but doesn't initialize new elements (doesn't change array count)
  588.     ERet resize( U32 newCapacity )
  589.     {
  590.         return ArrayUtil::resize( *this, newCapacity, mHeap, ALIGNMENT );
  591.     }
  592.  
  593. public_internal:
  594.  
  595.     /// For serialization, we want to initialize the vtables
  596.     /// in classes post data load, and NOT call the default constructor
  597.     /// for the arrays (as the data has already been set).
  598.     explicit DynamicArray( _FinishedLoadingFlag )
  599.     {
  600.     }
  601.  
  602.     mxFORCEINLINE AHeap &   GetAllocator() const { return mHeap; }
  603.  
  604. private:
  605.     NO_COMPARES(DynamicArray);
  606. };
  607.  
  608. //---------------------------------------------------------------------------
  609. // Reflection.
  610. //
  611. template< typename TYPE >
  612. struct TypeDeducer< DynamicArray< TYPE > >
  613. {
  614.     static inline const MetaType& GetType()
  615.     {
  616.         static DynamicArray< TYPE >::ArrayDescriptor staticTypeInfo(mxEXTRACT_TYPE_NAME(DynamicArray));
  617.         return staticTypeInfo;
  618.     }
  619.     static inline ETypeKind GetTypeKind()
  620.     {
  621.         return ETypeKind::Type_Array;
  622.     }
  623. };
  624.  
  625. //--------------------------------------------------------------//
  626. //              End Of File.                                    //
  627. //--------------------------------------------------------------//
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement