2009-08-21 22:21:05 +02:00
/*
* This file is part of OpenTTD .
* OpenTTD is free software ; you can redistribute it and / or modify it under the terms of the GNU General Public License as published by the Free Software Foundation , version 2.
* OpenTTD is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
* See the GNU General Public License for more details . You should have received a copy of the GNU General Public License along with OpenTTD . If not , see < http : //www.gnu.org/licenses/>.
*/
2019-09-29 22:27:32 +02:00
/** @file pool_type.hpp Definition of Pool, structure used to access PoolItems, and PoolItem, base structure for Vehicle, Town, and other indexed items. */
2009-05-22 17:13:50 +02:00
2009-05-22 17:39:22 +02:00
# ifndef POOL_TYPE_HPP
# define POOL_TYPE_HPP
2009-05-22 17:13:50 +02:00
2011-02-19 19:23:45 +01:00
# include "smallvec_type.hpp"
2011-02-20 00:05:47 +01:00
# include "enum_type.hpp"
/** Various types of a pool. */
enum PoolType {
PT_NONE = 0x00 , ///< No pool is selected.
PT_NORMAL = 0x01 , ///< Normal pool containing game objects.
PT_NCLIENT = 0x02 , ///< Network client pools.
PT_NADMIN = 0x04 , ///< Network admin pool.
PT_DATA = 0x08 , ///< NewGRF or other data, that is not reset together with normal pools.
PT_ALL = 0x0F , ///< All pool types.
} ;
DECLARE_ENUM_AS_BIT_SET ( PoolType )
2011-02-19 19:23:45 +01:00
2019-03-03 18:30:09 +01:00
typedef std : : vector < struct PoolBase * > PoolVector ; ///< Vector of pointers to PoolBase
2011-02-19 19:23:45 +01:00
/** Base class for base of all pools. */
struct PoolBase {
2011-02-20 00:05:47 +01:00
const PoolType type ; ///< Type of this pool.
2011-02-19 19:23:45 +01:00
/**
* Function used to access the vector of all pools .
* @ return pointer to vector of all pools
*/
static PoolVector * GetPools ( )
{
static PoolVector * pools = new PoolVector ( ) ;
return pools ;
}
2011-02-20 00:05:47 +01:00
static void Clean ( PoolType ) ;
2011-02-19 19:23:45 +01:00
/**
2013-01-08 23:46:42 +01:00
* Constructor registers this object in the pool vector .
2011-02-20 00:05:47 +01:00
* @ param pt type of this pool .
2011-02-19 19:23:45 +01:00
*/
2011-02-20 00:05:47 +01:00
PoolBase ( PoolType pt ) : type ( pt )
2011-02-19 19:23:45 +01:00
{
2019-02-18 23:39:06 +01:00
PoolBase : : GetPools ( ) - > push_back ( this ) ;
2011-02-19 19:23:45 +01:00
}
2011-02-24 07:57:55 +01:00
virtual ~ PoolBase ( ) ;
2011-02-19 19:23:45 +01:00
/**
* Virtual method that deletes all items in the pool .
*/
virtual void CleanPool ( ) = 0 ;
2013-06-15 17:06:22 +02:00
private :
/**
* Dummy private copy constructor to prevent compilers from
* copying the structure , which fails due to GetPools ( ) .
*/
PoolBase ( const PoolBase & other ) ;
2011-02-19 19:23:45 +01:00
} ;
2009-10-21 17:40:50 +02:00
/**
* Base class for all pools .
* @ tparam Titem Type of the class / struct that is going to be pooled
* @ tparam Tindex Type of the index for this pool
* @ tparam Tgrowth_step Size of growths ; if the pool is full increase the size by this amount
* @ tparam Tmax_size Maximum size of the pool
2011-02-20 00:05:47 +01:00
* @ tparam Tpool_type Type of this pool
2009-10-21 21:38:50 +02:00
* @ tparam Tcache Whether to perform ' alloc ' caching , i . e . don ' t actually free / malloc just reuse the memory
* @ tparam Tzero Whether to zero the memory
* @ warning when Tcache is enabled * all * instances of this pool ' s item must be of the same size .
2009-10-21 17:40:50 +02:00
*/
2011-02-20 00:05:47 +01:00
template < class Titem , typename Tindex , size_t Tgrowth_step , size_t Tmax_size , PoolType Tpool_type = PT_NORMAL , bool Tcache = false , bool Tzero = true >
2011-02-19 19:23:45 +01:00
struct Pool : PoolBase {
2014-02-10 21:13:07 +01:00
/* Ensure Tmax_size is within the bounds of Tindex. */
2020-12-27 11:44:22 +01:00
static_assert ( ( uint64 ) ( Tmax_size - 1 ) > > 8 * sizeof ( Tindex ) = = 0 ) ;
2014-02-10 21:13:07 +01:00
2021-04-01 19:39:55 +02:00
static constexpr size_t MAX_SIZE = Tmax_size ; ///< Make template parameter accessible from outside
2009-05-22 17:13:50 +02:00
const char * const name ; ///< Name of this pool
size_t size ; ///< Current allocated size
size_t first_free ; ///< No item with index lower than this is free (doesn't say anything about this one!)
size_t first_unused ; ///< This and all higher indexes are free (doesn't say anything about first_unused-1 !)
2019-04-10 23:07:06 +02:00
size_t items ; ///< Number of used indexes (non-nullptr)
2021-06-03 16:55:08 +02:00
# ifdef WITH_ASSERT
2011-02-09 19:55:51 +01:00
size_t checked ; ///< Number of items we checked for
2021-06-03 16:55:08 +02:00
# endif /* WITH_ASSERT */
2009-05-22 17:13:50 +02:00
bool cleaning ; ///< True if cleaning pool (deleting all items)
Titem * * data ; ///< Pointer to array of pointers to Titem
Pool ( const char * name ) ;
2011-02-19 19:23:45 +01:00
virtual void CleanPool ( ) ;
2009-05-22 17:13:50 +02:00
/**
2013-08-09 20:43:44 +02:00
* Returns Titem with given index
2009-05-22 17:13:50 +02:00
* @ param index of item to get
* @ return pointer to Titem
* @ pre index < this - > first_unused
*/
2011-12-20 18:57:56 +01:00
inline Titem * Get ( size_t index )
2009-05-22 17:13:50 +02:00
{
assert ( index < this - > first_unused ) ;
return this - > data [ index ] ;
}
/**
2019-04-10 23:07:06 +02:00
* Tests whether given index can be used to get valid ( non - nullptr ) Titem
2009-05-22 17:13:50 +02:00
* @ param index index to examine
2019-04-10 23:07:06 +02:00
* @ return true if PoolItem : : Get ( index ) will return non - nullptr pointer
2009-05-22 17:13:50 +02:00
*/
2011-12-20 18:57:56 +01:00
inline bool IsValidID ( size_t index )
2009-05-22 17:13:50 +02:00
{
2019-04-10 23:07:06 +02:00
return index < this - > first_unused & & this - > Get ( index ) ! = nullptr ;
2009-05-22 17:13:50 +02:00
}
/**
* Tests whether we can allocate ' n ' items
* @ param n number of items we want to allocate
* @ return true if ' n ' items can be allocated
*/
2011-12-20 18:57:56 +01:00
inline bool CanAllocate ( size_t n = 1 )
2009-05-22 17:13:50 +02:00
{
2011-02-09 19:55:51 +01:00
bool ret = this - > items < = Tmax_size - n ;
2021-06-03 16:55:08 +02:00
# ifdef WITH_ASSERT
2011-02-09 19:55:51 +01:00
this - > checked = ret ? n : 0 ;
2021-06-03 16:55:08 +02:00
# endif /* WITH_ASSERT */
2011-02-09 19:55:51 +01:00
return ret ;
2009-05-22 17:13:50 +02:00
}
2019-12-14 17:21:48 +01:00
/**
* Iterator to iterate all valid T of a pool
* @ tparam T Type of the class / struct that is going to be iterated
*/
template < class T >
struct PoolIterator {
typedef T value_type ;
typedef T * pointer ;
typedef T & reference ;
typedef size_t difference_type ;
typedef std : : forward_iterator_tag iterator_category ;
2020-01-06 18:19:24 +01:00
explicit PoolIterator ( size_t index ) : index ( index )
2019-12-14 17:21:48 +01:00
{
this - > ValidateIndex ( ) ;
} ;
2019-12-18 18:21:23 +01:00
bool operator = = ( const PoolIterator & other ) const { return this - > index = = other . index ; }
bool operator ! = ( const PoolIterator & other ) const { return ! ( * this = = other ) ; }
2019-12-14 17:21:48 +01:00
T * operator * ( ) const { return T : : Get ( this - > index ) ; }
PoolIterator & operator + + ( ) { this - > index + + ; this - > ValidateIndex ( ) ; return * this ; }
private :
size_t index ;
2020-01-06 18:19:24 +01:00
void ValidateIndex ( ) { while ( this - > index < T : : GetPoolSize ( ) & & ! ( T : : IsValidID ( this - > index ) ) ) this - > index + + ; }
2019-12-14 17:21:48 +01:00
} ;
/*
* Iterable ensemble of all valid T
* @ tparam T Type of the class / struct that is going to be iterated
*/
template < class T >
struct IterateWrapper {
size_t from ;
2020-01-06 18:19:24 +01:00
IterateWrapper ( size_t from = 0 ) : from ( from ) { }
PoolIterator < T > begin ( ) { return PoolIterator < T > ( this - > from ) ; }
2019-12-14 17:21:48 +01:00
PoolIterator < T > end ( ) { return PoolIterator < T > ( T : : GetPoolSize ( ) ) ; }
2019-12-18 18:21:23 +01:00
bool empty ( ) { return this - > begin ( ) = = this - > end ( ) ; }
2019-12-14 17:21:48 +01:00
} ;
2020-01-06 18:19:24 +01:00
/**
* Iterator to iterate all valid T of a pool
* @ tparam T Type of the class / struct that is going to be iterated
*/
template < class T , class F >
struct PoolIteratorFiltered {
typedef T value_type ;
typedef T * pointer ;
typedef T & reference ;
typedef size_t difference_type ;
typedef std : : forward_iterator_tag iterator_category ;
explicit PoolIteratorFiltered ( size_t index , F filter ) : index ( index ) , filter ( filter )
{
this - > ValidateIndex ( ) ;
} ;
bool operator = = ( const PoolIteratorFiltered & other ) const { return this - > index = = other . index ; }
bool operator ! = ( const PoolIteratorFiltered & other ) const { return ! ( * this = = other ) ; }
T * operator * ( ) const { return T : : Get ( this - > index ) ; }
PoolIteratorFiltered & operator + + ( ) { this - > index + + ; this - > ValidateIndex ( ) ; return * this ; }
private :
size_t index ;
F filter ;
void ValidateIndex ( ) { while ( this - > index < T : : GetPoolSize ( ) & & ! ( T : : IsValidID ( this - > index ) & & this - > filter ( this - > index ) ) ) this - > index + + ; }
} ;
/*
* Iterable ensemble of all valid T
* @ tparam T Type of the class / struct that is going to be iterated
*/
template < class T , class F >
struct IterateWrapperFiltered {
size_t from ;
F filter ;
IterateWrapperFiltered ( size_t from , F filter ) : from ( from ) , filter ( filter ) { }
PoolIteratorFiltered < T , F > begin ( ) { return PoolIteratorFiltered < T , F > ( this - > from , this - > filter ) ; }
PoolIteratorFiltered < T , F > end ( ) { return PoolIteratorFiltered < T , F > ( T : : GetPoolSize ( ) , this - > filter ) ; }
bool empty ( ) { return this - > begin ( ) = = this - > end ( ) ; }
} ;
2009-10-21 17:40:50 +02:00
/**
* Base class for all PoolItems
* @ tparam Tpool The pool this item is going to be part of
*/
2011-02-20 00:05:47 +01:00
template < struct Pool < Titem , Tindex , Tgrowth_step , Tmax_size , Tpool_type , Tcache , Tzero > * Tpool >
2009-05-22 17:13:50 +02:00
struct PoolItem {
Tindex index ; ///< Index of this pool item
2019-12-14 17:21:48 +01:00
/** Type of the pool this item is going to be part of */
typedef struct Pool < Titem , Tindex , Tgrowth_step , Tmax_size , Tpool_type , Tcache , Tzero > Pool ;
2009-05-22 17:13:50 +02:00
/**
* Allocates space for new Titem
* @ param size size of Titem
* @ return pointer to allocated memory
2019-04-10 23:07:06 +02:00
* @ note can never fail ( return nullptr ) , use CanAllocate ( ) to check first !
2009-05-22 17:13:50 +02:00
*/
2011-12-20 18:57:56 +01:00
inline void * operator new ( size_t size )
2009-05-22 17:13:50 +02:00
{
return Tpool - > GetNew ( size ) ;
}
/**
* Marks Titem as free . Its memory is released
* @ param p memory to free
* @ note the item has to be allocated in the pool !
*/
2011-12-20 18:57:56 +01:00
inline void operator delete ( void * p )
2009-05-22 17:13:50 +02:00
{
2019-04-10 23:07:06 +02:00
if ( p = = nullptr ) return ;
2009-05-22 17:13:50 +02:00
Titem * pn = ( Titem * ) p ;
assert ( pn = = Tpool - > Get ( pn - > index ) ) ;
Tpool - > FreeItem ( pn - > index ) ;
}
/**
* Allocates space for new Titem with given index
* @ param size size of Titem
* @ param index index of item
* @ return pointer to allocated memory
2019-04-10 23:07:06 +02:00
* @ note can never fail ( return nullptr ) , use CanAllocate ( ) to check first !
2009-05-22 17:13:50 +02:00
* @ pre index has to be unused ! Else it will crash
*/
2011-12-20 18:57:56 +01:00
inline void * operator new ( size_t size , size_t index )
2009-05-22 17:13:50 +02:00
{
return Tpool - > GetNew ( size , index ) ;
}
/**
* Allocates space for new Titem at given memory address
* @ param size size of Titem
* @ param ptr where are we allocating the item ?
* @ return pointer to allocated memory ( = = ptr )
* @ note use of this is strongly discouraged
* @ pre the memory must not be allocated in the Pool !
*/
2011-12-20 18:57:56 +01:00
inline void * operator new ( size_t size , void * ptr )
2009-05-22 17:13:50 +02:00
{
for ( size_t i = 0 ; i < Tpool - > first_unused ; i + + ) {
/* Don't allow creating new objects over existing.
* Even if we called the destructor and reused this memory ,
* we don ' t know whether ' size ' and size of currently allocated
* memory are the same ( because of possible inheritance ) .
* Use { size_t index = item - > index ; delete item ; new ( index ) item ; }
* instead to make sure destructor is called and no memory leaks . */
assert ( ptr ! = Tpool - > data [ i ] ) ;
}
return ptr ;
}
/** Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function() */
/**
* Tests whether we can allocate ' n ' items
* @ param n number of items we want to allocate
* @ return true if ' n ' items can be allocated
*/
2011-12-20 18:57:56 +01:00
static inline bool CanAllocateItem ( size_t n = 1 )
2009-05-22 17:13:50 +02:00
{
return Tpool - > CanAllocate ( n ) ;
}
/**
* Returns current state of pool cleaning - yes or no
* @ return true iff we are cleaning the pool now
*/
2011-12-20 18:57:56 +01:00
static inline bool CleaningPool ( )
2009-05-22 17:13:50 +02:00
{
return Tpool - > cleaning ;
}
/**
2019-04-10 23:07:06 +02:00
* Tests whether given index can be used to get valid ( non - nullptr ) Titem
2009-05-22 17:13:50 +02:00
* @ param index index to examine
2019-04-10 23:07:06 +02:00
* @ return true if PoolItem : : Get ( index ) will return non - nullptr pointer
2009-05-22 17:13:50 +02:00
*/
2011-12-20 18:57:56 +01:00
static inline bool IsValidID ( size_t index )
2009-05-22 17:13:50 +02:00
{
return Tpool - > IsValidID ( index ) ;
}
/**
2013-08-09 20:43:44 +02:00
* Returns Titem with given index
2009-05-22 17:13:50 +02:00
* @ param index of item to get
* @ return pointer to Titem
* @ pre index < this - > first_unused
*/
2011-12-20 18:57:56 +01:00
static inline Titem * Get ( size_t index )
2009-05-22 17:13:50 +02:00
{
return Tpool - > Get ( index ) ;
}
/**
2013-08-09 20:43:44 +02:00
* Returns Titem with given index
2009-05-22 17:13:50 +02:00
* @ param index of item to get
* @ return pointer to Titem
2019-04-10 23:07:06 +02:00
* @ note returns nullptr for invalid index
2009-05-22 17:13:50 +02:00
*/
2011-12-20 18:57:56 +01:00
static inline Titem * GetIfValid ( size_t index )
2009-05-22 17:13:50 +02:00
{
2019-04-10 23:07:06 +02:00
return index < Tpool - > first_unused ? Tpool - > Get ( index ) : nullptr ;
2009-05-22 17:13:50 +02:00
}
/**
* Returns first unused index . Useful when iterating over
* all pool items .
* @ return first unused index
*/
2011-12-20 18:57:56 +01:00
static inline size_t GetPoolSize ( )
2009-05-22 17:13:50 +02:00
{
return Tpool - > first_unused ;
}
/**
* Returns number of valid items in the pool
* @ return number of valid items in the pool
*/
2011-12-20 18:57:56 +01:00
static inline size_t GetNumItems ( )
2009-05-22 17:13:50 +02:00
{
return Tpool - > items ;
}
2009-07-05 15:20:05 +02:00
/**
* Dummy function called after destructor of each member .
* If you want to use it , override it in PoolItem ' s subclass .
* @ param index index of deleted item
2019-04-10 23:07:06 +02:00
* @ note when this function is called , PoolItem : : Get ( index ) = = nullptr .
2009-07-05 15:20:05 +02:00
* @ note it ' s called only when ! CleaningPool ( )
*/
2011-12-20 18:57:56 +01:00
static inline void PostDestructor ( size_t index ) { }
2019-12-14 17:21:48 +01:00
/**
* Returns an iterable ensemble of all valid Titem
* @ param from index of the first Titem to consider
* @ return an iterable ensemble of all valid Titem
*/
static Pool : : IterateWrapper < Titem > Iterate ( size_t from = 0 ) { return Pool : : IterateWrapper < Titem > ( from ) ; }
2009-05-22 17:13:50 +02:00
} ;
private :
2013-01-08 23:46:42 +01:00
static const size_t NO_FREE_ITEM = MAX_UVALUE ( size_t ) ; ///< Constant to indicate we can't allocate any more items
2009-05-22 17:13:50 +02:00
2009-10-21 21:38:50 +02:00
/**
* Helper struct to cache ' freed ' PoolItems so we
* do not need to allocate them again .
*/
struct AllocCache {
/** The next in our 'cache' */
AllocCache * next ;
} ;
/** Cache of freed pointers */
AllocCache * alloc_cache ;
2009-05-22 17:13:50 +02:00
void * AllocateItem ( size_t size , size_t index ) ;
void ResizeFor ( size_t index ) ;
size_t FindFirstFree ( ) ;
void * GetNew ( size_t size ) ;
void * GetNew ( size_t size , size_t index ) ;
void FreeItem ( size_t index ) ;
} ;
2009-05-22 17:39:22 +02:00
# endif /* POOL_TYPE_HPP */