2020-11-17 11:16:16 +00:00
/*
Copyright ( C ) 2001 - 2006 , William Joseph .
All Rights Reserved .
This file is part of GtkRadiant .
GtkRadiant 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 ; either version 2 of the License , or
( at your option ) any later version .
GtkRadiant 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 GtkRadiant ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# if !defined( INCLUDED_CONTAINER_CACHE_H )
# define INCLUDED_CONTAINER_CACHE_H
# include <cstddef>
# include "container/hashtable.h"
# include "memory/allocator.h"
template < typename Type , typename Parameter >
class DefaultCreationPolicy
{
public :
Type * construct ( const Parameter & parameter ) {
return New < Type > ( ) . scalar ( parameter ) ;
}
void destroy ( Type * p ) {
Delete < Type > ( ) . scalar ( p ) ;
}
} ;
template < typename Type >
class SharedValue
{
typedef Type value_type ;
typedef value_type * pointer ;
typedef value_type & reference ;
std : : size_t m_count ;
pointer m_value ;
public :
SharedValue ( )
: m_count ( 0 ) , m_value ( 0 ) {
}
~ SharedValue ( ) {
ASSERT_MESSAGE ( m_count = = 0 , " destroying a referenced object \n " ) ;
}
void set ( pointer value ) {
m_value = value ;
}
pointer get ( ) {
return m_value ;
}
std : : size_t increment ( ) {
return + + m_count ;
}
std : : size_t decrement ( ) {
ASSERT_MESSAGE ( ! empty ( ) , " destroying a non-existent object \n " ) ;
return - - m_count ;
}
std : : size_t count ( ) {
return m_count ;
}
bool empty ( ) {
return m_count = = 0 ;
}
reference operator * ( ) const {
ASSERT_NOTNULL ( m_value ) ;
return * m_value ;
}
pointer operator - > ( ) const {
return & ( operator * ( ) ) ;
}
} ;
/// \brief Caches values that are uniquely identified by a key.
///
/// - Automatically removes objects that are no longer referenced.
///
/// \param Key Uniquely identifies each element.
/// \param Cached The type to be cached. Must define a constructor that accepts \c Key.
/// \param CreationPolicy Must define 'Cached* construct(const Key&)' and 'void destroy(Cached*)'. The lifetime of the \c Key passed to 'construct' is guaranteed to be longer than the subsequent matched call to 'destroy'.
template < typename Key , typename Cached , typename Hasher , typename KeyEqual = std : : equal_to < Key > , typename CreationPolicy = DefaultCreationPolicy < Cached , Key > >
class HashedCache : public CreationPolicy
{
2021-08-04 20:23:18 +00:00
typedef SharedValue < Cached > Element ;
typedef HashTable < Key , Element , Hasher , KeyEqual > map_type ;
2020-11-17 11:16:16 +00:00
2021-08-04 20:23:18 +00:00
map_type m_map ;
2020-11-17 11:16:16 +00:00
public :
2021-08-04 20:23:18 +00:00
explicit HashedCache ( const CreationPolicy & creation = CreationPolicy ( ) )
: CreationPolicy ( creation ) , m_map ( 256 ) {
}
~ HashedCache ( ) {
ASSERT_MESSAGE ( empty ( ) , " HashedCache::~HashedCache: not empty " ) ;
}
2020-11-17 11:16:16 +00:00
2021-08-04 20:23:18 +00:00
typedef typename map_type : : iterator iterator ;
typedef typename map_type : : value_type value_type ;
2020-11-17 11:16:16 +00:00
2021-08-04 20:23:18 +00:00
iterator begin ( ) {
return m_map . begin ( ) ;
}
iterator end ( ) {
return m_map . end ( ) ;
}
2020-11-17 11:16:16 +00:00
2021-08-04 20:23:18 +00:00
bool empty ( ) const {
return m_map . empty ( ) ;
}
2020-11-17 11:16:16 +00:00
2021-08-04 20:23:18 +00:00
iterator find ( const Key & key ) {
return m_map . find ( key ) ;
}
2020-11-17 11:16:16 +00:00
2021-08-04 20:23:18 +00:00
void capture ( iterator i ) {
2020-11-17 11:16:16 +00:00
( * i ) . value . increment ( ) ;
2021-08-04 20:23:18 +00:00
}
void release ( iterator i ) {
2020-11-17 11:16:16 +00:00
if ( ( * i ) . value . decrement ( ) = = 0 ) {
CreationPolicy : : destroy ( ( * i ) . value . get ( ) ) ;
2021-08-04 20:23:18 +00:00
m_map . erase ( i ) ;
2020-11-17 11:16:16 +00:00
}
2021-08-04 20:23:18 +00:00
}
2020-11-17 11:16:16 +00:00
# if 1
2021-08-04 20:23:18 +00:00
Element & capture ( const Key & key ) {
2020-11-17 11:16:16 +00:00
#if 0
Element & elem = m_map [ key ] ;
2021-08-04 20:23:18 +00:00
if ( elem . increment ( ) = = 1 ) {
elem . set ( CreationPolicy : : construct ( key ) ) ;
}
2020-11-17 11:16:16 +00:00
return elem ;
# else
iterator i = m_map . insert ( key , Element ( ) ) ;
if ( ( * i ) . value . increment ( ) = = 1 ) {
( * i ) . value . set ( CreationPolicy : : construct ( ( * i ) . key ) ) ;
2021-08-04 20:23:18 +00:00
}
2020-11-17 11:16:16 +00:00
return ( * i ) . value ;
# endif
2021-08-04 20:23:18 +00:00
}
2020-11-17 11:16:16 +00:00
# else
value_type & capture ( const Key & key ) {
2021-08-04 20:23:18 +00:00
iterator i = m_map . find ( key ) ;
if ( i = = m_map . end ( ) ) {
i = m_map . insert ( key , Element ( ) ) ;
2020-11-17 11:16:16 +00:00
( * i ) . value . set ( CreationPolicy : : construct ( ( * i ) . key ) ) ;
2021-08-04 20:23:18 +00:00
}
2020-11-17 11:16:16 +00:00
( * i ) . value . increment ( ) ;
2021-08-04 20:23:18 +00:00
return ( * i ) ;
2020-11-17 11:16:16 +00:00
}
# endif
2021-08-04 20:23:18 +00:00
void release ( const Key & key ) {
iterator i = m_map . find ( key ) ;
ASSERT_MESSAGE ( i ! = m_map . end ( ) , " releasing a non-existent object \n " ) ;
release ( i ) ;
}
2020-11-17 11:16:16 +00:00
2021-08-04 20:23:18 +00:00
void clear ( ) {
m_map . clear ( ) ;
}
2020-11-17 11:16:16 +00:00
} ;
# endif