2009-05-22 17:13:50 +02:00
/* $Id$ */
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/>.
*/
2009-05-22 17:39:22 +02:00
/** @file pool_type.hpp Defintion 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
typedef SmallVector < struct PoolBase * , 4 > PoolVector ; ///< Vector of pointers to PoolBase
/** 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
/**
* Contructor 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
{
* PoolBase : : GetPools ( ) - > Append ( ) = this ;
}
~ PoolBase ( ) ;
/**
* Virtual method that deletes all items in the pool .
*/
virtual void CleanPool ( ) = 0 ;
} ;
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 {
2009-05-22 17:13:50 +02:00
static const size_t MAX_SIZE = Tmax_size ; ///< Make template parameter accessible from outside
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 !)
size_t items ; ///< Number of used indexes (non-NULL)
2011-02-09 19:55:51 +01:00
# ifdef OTTD_ASSERT
size_t checked ; ///< Number of items we checked for
# endif /* OTTD_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
/**
* Returs Titem with given index
* @ param index of item to get
* @ return pointer to Titem
* @ pre index < this - > first_unused
*/
FORCEINLINE Titem * Get ( size_t index )
{
assert ( index < this - > first_unused ) ;
return this - > data [ index ] ;
}
/**
* Tests whether given index can be used to get valid ( non - NULL ) Titem
* @ param index index to examine
* @ return true if PoolItem : : Get ( index ) will return non - NULL pointer
*/
FORCEINLINE bool IsValidID ( size_t index )
{
return index < this - > first_unused & & this - > Get ( index ) ! = NULL ;
}
/**
* Tests whether we can allocate ' n ' items
* @ param n number of items we want to allocate
* @ return true if ' n ' items can be allocated
*/
FORCEINLINE bool CanAllocate ( size_t n = 1 )
{
2011-02-09 19:55:51 +01:00
bool ret = this - > items < = Tmax_size - n ;
# ifdef OTTD_ASSERT
this - > checked = ret ? n : 0 ;
# endif /* OTTD_ASSERT */
return ret ;
2009-05-22 17:13:50 +02:00
}
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
/**
* Allocates space for new Titem
* @ param size size of Titem
* @ return pointer to allocated memory
* @ note can never fail ( return NULL ) , use CanAllocate ( ) to check first !
*/
FORCEINLINE void * operator new ( size_t size )
{
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 !
*/
FORCEINLINE void operator delete ( void * p )
{
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
* @ note can never fail ( return NULL ) , use CanAllocate ( ) to check first !
* @ pre index has to be unused ! Else it will crash
*/
FORCEINLINE void * operator new ( size_t size , size_t index )
{
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 !
*/
FORCEINLINE void * operator new ( size_t size , void * ptr )
{
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
*/
static FORCEINLINE bool CanAllocateItem ( size_t n = 1 )
{
return Tpool - > CanAllocate ( n ) ;
}
/**
* Returns current state of pool cleaning - yes or no
* @ return true iff we are cleaning the pool now
*/
static FORCEINLINE bool CleaningPool ( )
{
return Tpool - > cleaning ;
}
/**
* Tests whether given index can be used to get valid ( non - NULL ) Titem
* @ param index index to examine
* @ return true if PoolItem : : Get ( index ) will return non - NULL pointer
*/
static FORCEINLINE bool IsValidID ( size_t index )
{
return Tpool - > IsValidID ( index ) ;
}
/**
* Returs Titem with given index
* @ param index of item to get
* @ return pointer to Titem
* @ pre index < this - > first_unused
*/
static FORCEINLINE Titem * Get ( size_t index )
{
return Tpool - > Get ( index ) ;
}
/**
* Returs Titem with given index
* @ param index of item to get
* @ return pointer to Titem
* @ note returns NULL for invalid index
*/
static FORCEINLINE Titem * GetIfValid ( size_t index )
{
return index < Tpool - > first_unused ? Tpool - > Get ( index ) : NULL ;
}
/**
* Returns first unused index . Useful when iterating over
* all pool items .
* @ return first unused index
*/
static FORCEINLINE size_t GetPoolSize ( )
{
return Tpool - > first_unused ;
}
/**
* Returns number of valid items in the pool
* @ return number of valid items in the pool
*/
static FORCEINLINE size_t GetNumItems ( )
{
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
* @ note when this function is called , PoolItem : : Get ( index ) = = NULL .
* @ note it ' s called only when ! CleaningPool ( )
*/
static FORCEINLINE void PostDestructor ( size_t index ) { }
2009-05-22 17:13:50 +02:00
} ;
private :
static const size_t NO_FREE_ITEM = MAX_UVALUE ( size_t ) ; ///< Contant to indicate we can't allocate any more items
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 ) ;
} ;
# define FOR_ALL_ITEMS_FROM(type, iter, var, start) \
for ( size_t iter = start ; var = NULL , iter < type : : GetPoolSize ( ) ; iter + + ) \
if ( ( var = type : : Get ( iter ) ) ! = NULL )
# define FOR_ALL_ITEMS(type, iter, var) FOR_ALL_ITEMS_FROM(type, iter, var, 0)
2009-05-22 17:39:22 +02:00
# endif /* POOL_TYPE_HPP */