| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- /*
- * Copyright (c) 2014, Oculus VR, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
- /// \file DS_List.h
- /// \internal
- /// \brief Array based list.
- /// \details Usually the Queue class is used instead, since it has all the same functionality and is only worse at random access.
- ///
- #ifndef __LIST_H
- #define __LIST_H
- #include "RakAssert.h"
- #include <string.h> // memmove
- #include "Export.h"
- #include "RakMemoryOverride.h"
- /// Maximum unsigned long
- static const unsigned int MAX_UNSIGNED_LONG = 4294967295U;
- /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
- /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
- namespace DataStructures
- {
- /// \brief Array based implementation of a list.
- /// \note ONLY USE THIS FOR SHALLOW COPIES. I don't bother with operator= to improve performance.
- template <class list_type>
- class RAK_DLL_EXPORT List
- {
- public:
- /// Default constructor
- List();
- // Destructor
- ~List();
-
- /// \brief Copy constructor.
- /// \param[in] original_copy The list to duplicate
- List( const List& original_copy );
-
- /// \brief Assign one list to another.
- List& operator= ( const List& original_copy );
-
- /// \brief Access an element by its index in the array.
- /// \param[in] position The index into the array.
- /// \return The element at position \a position.
- list_type& operator[] ( const unsigned int position ) const;
- /// \brief Access an element by its index in the array.
- /// \param[in] position The index into the array.
- /// \return The element at position \a position.
- list_type& Get ( const unsigned int position ) const;
- /// \brief Push an element at the end of the stack.
- /// \param[in] input The new element.
- void Push(const list_type &input, const char *file, unsigned int line );
- /// \brief Pop an element from the end of the stack.
- /// \pre Size()>0
- /// \return The element at the end.
- list_type& Pop(void);
-
- /// \brief Insert an element at position \a position in the list.
- /// \param[in] input The new element.
- /// \param[in] position The position of the new element.
- void Insert( const list_type &input, const unsigned int position, const char *file, unsigned int line );
-
- /// \brief Insert at the end of the list.
- /// \param[in] input The new element.
- void Insert( const list_type &input, const char *file, unsigned int line );
-
- /// \brief Replace the value at \a position by \a input.
- /// \details If the size of the list is less than @em position, it increase the capacity of
- /// the list and fill slot with @em filler.
- /// \param[in] input The element to replace at position @em position.
- /// \param[in] filler The element use to fill new allocated capacity.
- /// \param[in] position The position of input in the list.
- void Replace( const list_type &input, const list_type filler, const unsigned int position, const char *file, unsigned int line );
-
- /// \brief Replace the last element of the list by \a input.
- /// \param[in] input The element used to replace the last element.
- void Replace( const list_type &input );
-
- /// \brief Delete the element at position \a position.
- /// \param[in] position The index of the element to delete
- void RemoveAtIndex( const unsigned int position );
- /// \brief Delete the element at position \a position.
- /// \note - swaps middle with end of list, only use if list order does not matter
- /// \param[in] position The index of the element to delete
- void RemoveAtIndexFast( const unsigned int position );
-
- /// \brief Delete the element at the end of the list.
- void RemoveFromEnd(const unsigned num=1);
-
- /// \brief Returns the index of the specified item or MAX_UNSIGNED_LONG if not found.
- /// \param[in] input The element to check for
- /// \return The index or position of @em input in the list.
- /// \retval MAX_UNSIGNED_LONG The object is not in the list
- /// \retval [Integer] The index of the element in the list
- unsigned int GetIndexOf( const list_type &input ) const;
-
- /// \return The number of elements in the list
- unsigned int Size( void ) const;
-
- /// \brief Clear the list
- void Clear( bool doNotDeallocateSmallBlocks, const char *file, unsigned int line );
-
- /// \brief Preallocate the list, so it needs fewer reallocations at runtime.
- void Preallocate( unsigned countNeeded, const char *file, unsigned int line );
- /// \brief Frees overallocated members, to use the minimum memory necessary.
- /// \attention
- /// This is a slow operation
- void Compress( const char *file, unsigned int line );
-
- private:
- /// An array of user values
- list_type* listArray;
-
- /// Number of elements in the list
- unsigned int list_size;
-
- /// Size of \a array
- unsigned int allocation_size;
- };
- template <class list_type>
- List<list_type>::List()
- {
- allocation_size = 0;
- listArray = 0;
- list_size = 0;
- }
- template <class list_type>
- List<list_type>::~List()
- {
- if (allocation_size>0)
- RakNet::OP_DELETE_ARRAY(listArray, _FILE_AND_LINE_);
- }
- template <class list_type>
- List<list_type>::List( const List& original_copy )
- {
- // Allocate memory for copy
- if ( original_copy.list_size == 0 )
- {
- list_size = 0;
- allocation_size = 0;
- }
- else
- {
- listArray = RakNet::OP_NEW_ARRAY<list_type >( original_copy.list_size , _FILE_AND_LINE_ );
- for ( unsigned int counter = 0; counter < original_copy.list_size; ++counter )
- listArray[ counter ] = original_copy.listArray[ counter ];
- // Don't call constructors, assignment operators, etc.
- //memcpy(listArray, original_copy.listArray, original_copy.list_size*sizeof(list_type));
- list_size = allocation_size = original_copy.list_size;
- }
- }
- template <class list_type>
- List<list_type>& List<list_type>::operator= ( const List& original_copy )
- {
- if ( ( &original_copy ) != this )
- {
- Clear( false, _FILE_AND_LINE_ );
- // Allocate memory for copy
- if ( original_copy.list_size == 0 )
- {
- list_size = 0;
- allocation_size = 0;
- }
- else
- {
- listArray = RakNet::OP_NEW_ARRAY<list_type >( original_copy.list_size , _FILE_AND_LINE_ );
- for ( unsigned int counter = 0; counter < original_copy.list_size; ++counter )
- listArray[ counter ] = original_copy.listArray[ counter ];
- // Don't call constructors, assignment operators, etc.
- //memcpy(listArray, original_copy.listArray, original_copy.list_size*sizeof(list_type));
- list_size = allocation_size = original_copy.list_size;
- }
- }
- return *this;
- }
- template <class list_type>
- inline list_type& List<list_type>::operator[] ( const unsigned int position ) const
- {
- #ifdef _DEBUG
- if (position>=list_size)
- {
- RakAssert ( position < list_size );
- }
- #endif
- return listArray[ position ];
- }
- // Just here for debugging
- template <class list_type>
- inline list_type& List<list_type>::Get ( const unsigned int position ) const
- {
- return listArray[ position ];
- }
- template <class list_type>
- void List<list_type>::Push(const list_type &input, const char *file, unsigned int line)
- {
- Insert(input, file, line);
- }
- template <class list_type>
- inline list_type& List<list_type>::Pop(void)
- {
- #ifdef _DEBUG
- RakAssert(list_size>0);
- #endif
- --list_size;
- return listArray[list_size];
- }
- template <class list_type>
- void List<list_type>::Insert( const list_type &input, const unsigned int position, const char *file, unsigned int line )
- {
- #ifdef _DEBUG
- if (position>list_size)
- {
- RakAssert( position <= list_size );
- }
- #endif
- // Reallocate list if necessary
- if ( list_size == allocation_size )
- {
- // allocate twice the currently allocated memory
- list_type * new_array;
- if ( allocation_size == 0 )
- allocation_size = 16;
- else
- allocation_size *= 2;
- new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
- // copy old array over
- for ( unsigned int counter = 0; counter < list_size; ++counter )
- new_array[ counter ] = listArray[ counter ];
- // Don't call constructors, assignment operators, etc.
- //memcpy(new_array, listArray, list_size*sizeof(list_type));
- // set old array to point to the newly allocated and twice as large array
- RakNet::OP_DELETE_ARRAY(listArray, file, line);
- listArray = new_array;
- }
- // Move the elements in the list to make room
- for ( unsigned int counter = list_size; counter != position; counter-- )
- listArray[ counter ] = listArray[ counter - 1 ];
- // Don't call constructors, assignment operators, etc.
- //memmove(listArray+position+1, listArray+position, (list_size-position)*sizeof(list_type));
- // Insert the new item at the correct spot
- listArray[ position ] = input;
- ++list_size;
- }
- template <class list_type>
- void List<list_type>::Insert( const list_type &input, const char *file, unsigned int line )
- {
- // Reallocate list if necessary
- if ( list_size == allocation_size )
- {
- // allocate twice the currently allocated memory
- list_type * new_array;
- if ( allocation_size == 0 )
- allocation_size = 16;
- else
- allocation_size *= 2;
- new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
- if (listArray)
- {
- // copy old array over
- for ( unsigned int counter = 0; counter < list_size; ++counter )
- new_array[ counter ] = listArray[ counter ];
- // Don't call constructors, assignment operators, etc.
- //memcpy(new_array, listArray, list_size*sizeof(list_type));
- // set old array to point to the newly allocated and twice as large array
- RakNet::OP_DELETE_ARRAY(listArray, file, line);
- }
-
- listArray = new_array;
- }
- // Insert the new item at the correct spot
- listArray[ list_size ] = input;
- ++list_size;
- }
- template <class list_type>
- inline void List<list_type>::Replace( const list_type &input, const list_type filler, const unsigned int position, const char *file, unsigned int line )
- {
- if ( ( list_size > 0 ) && ( position < list_size ) )
- {
- // Direct replacement
- listArray[ position ] = input;
- }
- else
- {
- if ( position >= allocation_size )
- {
- // Reallocate the list to size position and fill in blanks with filler
- list_type * new_array;
- allocation_size = position + 1;
- new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
- // copy old array over
- for ( unsigned int counter = 0; counter < list_size; ++counter )
- new_array[ counter ] = listArray[ counter ];
- // Don't call constructors, assignment operators, etc.
- //memcpy(new_array, listArray, list_size*sizeof(list_type));
- // set old array to point to the newly allocated array
- RakNet::OP_DELETE_ARRAY(listArray, file, line);
- listArray = new_array;
- }
- // Fill in holes with filler
- while ( list_size < position )
- listArray[ list_size++ ] = filler;
- // Fill in the last element with the new item
- listArray[ list_size++ ] = input;
- #ifdef _DEBUG
- RakAssert( list_size == position + 1 );
- #endif
- }
- }
- template <class list_type>
- inline void List<list_type>::Replace( const list_type &input )
- {
- if ( list_size > 0 )
- listArray[ list_size - 1 ] = input;
- }
- template <class list_type>
- void List<list_type>::RemoveAtIndex( const unsigned int position )
- {
- #ifdef _DEBUG
- if (position >= list_size)
- {
- RakAssert( position < list_size );
- return;
- }
- #endif
- if ( position < list_size )
- {
- // Compress the array
- for ( unsigned int counter = position; counter < list_size - 1 ; ++counter )
- listArray[ counter ] = listArray[ counter + 1 ];
- // Don't call constructors, assignment operators, etc.
- // memmove(listArray+position, listArray+position+1, (list_size-1-position) * sizeof(list_type));
- RemoveFromEnd();
- }
- }
- template <class list_type>
- void List<list_type>::RemoveAtIndexFast( const unsigned int position )
- {
- #ifdef _DEBUG
- if (position >= list_size)
- {
- RakAssert( position < list_size );
- return;
- }
- #endif
- --list_size;
- listArray[position]=listArray[list_size];
- }
- template <class list_type>
- inline void List<list_type>::RemoveFromEnd( const unsigned num )
- {
- // Delete the last elements on the list. No compression needed
- #ifdef _DEBUG
- RakAssert(list_size>=num);
- #endif
- list_size-=num;
- }
- template <class list_type>
- unsigned int List<list_type>::GetIndexOf( const list_type &input ) const
- {
- for ( unsigned int i = 0; i < list_size; ++i )
- if ( listArray[ i ] == input )
- return i;
- return MAX_UNSIGNED_LONG;
- }
- template <class list_type>
- inline unsigned int List<list_type>::Size( void ) const
- {
- return list_size;
- }
- template <class list_type>
- void List<list_type>::Clear( bool doNotDeallocateSmallBlocks, const char *file, unsigned int line )
- {
- if ( allocation_size == 0 )
- return;
- if (allocation_size>512 || doNotDeallocateSmallBlocks==false)
- {
- RakNet::OP_DELETE_ARRAY(listArray, file, line);
- allocation_size = 0;
- listArray = 0;
- }
- list_size = 0;
- }
- template <class list_type>
- void List<list_type>::Compress( const char *file, unsigned int line )
- {
- list_type * new_array;
- if ( allocation_size == 0 )
- return ;
- new_array = RakNet::OP_NEW_ARRAY<list_type >( allocation_size , file, line );
- // copy old array over
- for ( unsigned int counter = 0; counter < list_size; ++counter )
- new_array[ counter ] = listArray[ counter ];
- // Don't call constructors, assignment operators, etc.
- //memcpy(new_array, listArray, list_size*sizeof(list_type));
- // set old array to point to the newly allocated array
- RakNet::OP_DELETE_ARRAY(listArray, file, line);
- listArray = new_array;
- }
- template <class list_type>
- void List<list_type>::Preallocate( unsigned countNeeded, const char *file, unsigned int line )
- {
- unsigned amountToAllocate = allocation_size;
- if (allocation_size==0)
- amountToAllocate=16;
- while (amountToAllocate < countNeeded)
- amountToAllocate<<=1;
- if ( allocation_size < amountToAllocate)
- {
- // allocate twice the currently allocated memory
- list_type * new_array;
- allocation_size=amountToAllocate;
- new_array = RakNet::OP_NEW_ARRAY< list_type >( allocation_size , file, line );
- if (listArray)
- {
- // copy old array over
- for ( unsigned int counter = 0; counter < list_size; ++counter )
- new_array[ counter ] = listArray[ counter ];
- // Don't call constructors, assignment operators, etc.
- //memcpy(new_array, listArray, list_size*sizeof(list_type));
- // set old array to point to the newly allocated and twice as large array
- RakNet::OP_DELETE_ARRAY(listArray, file, line);
- }
- listArray = new_array;
- }
- }
-
- } // End namespace
- #endif
|