2012-11-15 00:39:56 +01:00
# pragma once
2015-03-06 23:58:42 +01:00
2016-04-27 00:27:24 +02:00
# include "Utilities/types.h"
2017-01-24 21:19:52 +01:00
# include "Utilities/mutex.h"
2015-11-30 16:10:17 +01:00
2016-04-27 00:27:24 +02:00
# include <memory>
# include <vector>
# include <unordered_map>
2012-11-15 00:39:56 +01:00
2016-04-14 00:59:00 +02:00
// Mostly helper namespace
namespace id_manager
2015-11-26 09:06:29 +01:00
{
2016-04-14 00:59:00 +02:00
// Optional ID traits
template < typename T , typename = void >
struct id_traits
{
using tag = void ;
2015-09-18 00:41:14 +02:00
2016-04-14 00:59:00 +02:00
static constexpr u32 min = 1 ;
static constexpr u32 max = 0x7fffffff ;
} ;
2015-09-18 00:41:14 +02:00
2016-04-14 00:59:00 +02:00
template < typename T >
struct id_traits < T , void_t < typename T : : id_base , decltype ( & T : : id_min ) , decltype ( & T : : id_max ) > >
{
using tag = typename T : : id_base ;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
static constexpr u32 min = T : : id_min ;
static constexpr u32 max = T : : id_max ;
} ;
2015-08-11 18:14:53 +02:00
2016-04-14 00:59:00 +02:00
// Optional object initialization function (called after ID registration)
template < typename T , typename = void >
struct on_init
{
2016-07-24 01:56:03 +02:00
static inline void func ( T * , const std : : shared_ptr < void > & )
2016-04-14 00:59:00 +02:00
{
2016-06-25 07:16:15 +02:00
// Forbid forward declarations
static constexpr auto size = sizeof ( std : : conditional_t < std : : is_void < T > : : value , void * , T > ) ;
2016-04-14 00:59:00 +02:00
}
} ;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
template < typename T >
2016-07-24 01:56:03 +02:00
struct on_init < T , decltype ( std : : declval < T > ( ) . on_init ( std : : declval < const std : : shared_ptr < void > & > ( ) ) ) >
2016-04-14 00:59:00 +02:00
{
2016-07-24 01:56:03 +02:00
static inline void func ( T * ptr , const std : : shared_ptr < void > & _ptr )
2016-04-14 00:59:00 +02:00
{
2016-07-24 01:56:03 +02:00
if ( ptr ) ptr - > on_init ( _ptr ) ;
2016-04-14 00:59:00 +02:00
}
} ;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
// Optional object finalization function (called after ID removal)
template < typename T , typename = void >
struct on_stop
{
2016-05-13 16:01:48 +02:00
static inline void func ( T * )
2016-04-14 00:59:00 +02:00
{
2016-06-25 07:16:15 +02:00
// Forbid forward declarations
static constexpr auto size = sizeof ( std : : conditional_t < std : : is_void < T > : : value , void * , T > ) ;
2016-04-14 00:59:00 +02:00
}
} ;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
template < typename T >
struct on_stop < T , decltype ( std : : declval < T > ( ) . on_stop ( ) ) >
{
2016-05-13 16:01:48 +02:00
static inline void func ( T * ptr )
2016-04-14 00:59:00 +02:00
{
2016-06-25 07:16:15 +02:00
if ( ptr ) ptr - > on_stop ( ) ;
2016-04-14 00:59:00 +02:00
}
} ;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
class typeinfo
{
// Global variable for each registered type
template < typename T >
struct registered
{
static const u32 index ;
} ;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
// Access global type list
2016-04-27 00:27:24 +02:00
static std : : vector < typeinfo > & access ( ) ;
2016-04-14 00:59:00 +02:00
2016-04-27 00:27:24 +02:00
// Add to the global list
2016-06-21 10:22:30 +02:00
static u32 add_type ( ) ;
2016-04-14 00:59:00 +02:00
public :
2016-06-21 10:22:30 +02:00
void ( * on_stop ) ( void * ) = nullptr ;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
// Get type index
template < typename T >
static inline u32 get_index ( )
2015-11-26 09:06:29 +01:00
{
2016-06-21 10:22:30 +02:00
return registered < T > : : index ;
}
// Register functions
template < typename T >
static inline void update ( )
{
2016-08-12 18:24:29 +02:00
access ( ) [ get_index < T > ( ) ] . on_stop = [ ] ( void * ptr ) { return id_manager : : on_stop < T > : : func ( static_cast < T * > ( ptr ) ) ; } ;
2016-04-14 00:59:00 +02:00
}
// Read all registered types
static inline const auto & get ( )
{
return access ( ) ;
2015-11-26 09:06:29 +01:00
}
} ;
2015-09-18 00:41:14 +02:00
2016-04-27 00:27:24 +02:00
template < typename T >
2016-06-21 10:22:30 +02:00
const u32 typeinfo : : registered < T > : : index = typeinfo : : add_type ( ) ;
2016-08-01 00:35:53 +02:00
// ID value with additional type stored
class id_key
{
u32 m_value ; // ID value
u32 m_type ; // True object type
public :
id_key ( ) = default ;
id_key ( u32 value , u32 type = 0 )
: m_value ( value )
, m_type ( type )
{
}
u32 id ( ) const
{
return m_value ;
}
u32 type ( ) const
{
return m_type ;
}
bool operator = = ( const id_key & rhs ) const
{
return m_value = = rhs . m_value ;
}
bool operator ! = ( const id_key & rhs ) const
{
return m_value ! = rhs . m_value ;
}
} ;
// Custom hasher for ID values
struct id_hash final
{
std : : size_t operator ( ) ( const id_key & key ) const
{
return key . id ( ) ;
}
} ;
using id_map = std : : unordered_map < id_key , std : : shared_ptr < void > , id_hash > ;
2016-04-14 00:59:00 +02:00
}
// Object manager for emulated process. Multiple objects of specified arbitrary type are given unique IDs.
class idm
{
// Rules for ID allocation:
// 0) Individual ID counter may be specified for each type by defining 'using id_base = ...;'
// 1) If no id_base specified, void is assumed.
// 2) g_id[id_base] indicates next ID allocated in g_map.
// 3) g_map[id_base] contains the additional copy of object pointer.
2016-04-27 00:27:24 +02:00
static shared_mutex g_mutex ;
2016-04-14 00:59:00 +02:00
// Type Index -> ID -> Object. Use global since only one process is supported atm.
2016-08-01 00:35:53 +02:00
static std : : vector < id_manager : : id_map > g_map ;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
// Next ID for each category
static std : : vector < u32 > g_id ;
2015-08-11 18:14:53 +02:00
2015-11-26 09:06:29 +01:00
template < typename T >
2016-04-14 00:59:00 +02:00
static inline u32 get_type ( )
2015-09-18 00:41:14 +02:00
{
2016-04-27 00:27:24 +02:00
return id_manager : : typeinfo : : get_index < T > ( ) ;
2015-08-08 03:16:08 +02:00
}
2016-04-14 00:59:00 +02:00
template < typename T >
static inline u32 get_tag ( )
{
return get_type < typename id_manager : : id_traits < T > : : tag > ( ) ;
}
2015-08-08 03:16:08 +02:00
2016-04-27 00:27:24 +02:00
// Update optional ID storage
template < typename T >
2016-05-13 16:01:48 +02:00
static inline auto set_id_value ( T * ptr , u32 id ) - > decltype ( static_cast < void > ( std : : declval < T & > ( ) . id ) )
2015-07-01 00:25:52 +02:00
{
2016-04-27 00:27:24 +02:00
ptr - > id = id ;
2016-04-14 00:59:00 +02:00
}
2016-05-13 16:01:48 +02:00
static inline void set_id_value ( . . . )
2016-04-14 00:59:00 +02:00
{
2016-04-27 00:27:24 +02:00
}
2015-07-01 00:25:52 +02:00
2016-05-13 16:01:48 +02:00
// Helper
template < typename F >
struct function_traits ;
template < typename F , typename R , typename A1 , typename A2 >
struct function_traits < R ( F : : * ) ( A1 , A2 & ) const >
{
2017-01-25 01:45:36 +01:00
using object_type = A2 ;
using result_type = R ;
} ;
template < typename F , typename R , typename A1 , typename A2 >
struct function_traits < R ( F : : * ) ( A1 , A2 & ) >
{
using object_type = A2 ;
using result_type = R ;
} ;
template < typename F , typename A1 , typename A2 >
struct function_traits < void ( F : : * ) ( A1 , A2 & ) const >
{
using object_type = A2 ;
using void_type = void ;
} ;
template < typename F , typename A1 , typename A2 >
struct function_traits < void ( F : : * ) ( A1 , A2 & ) >
{
using object_type = A2 ;
using void_type = void ;
2016-05-13 16:01:48 +02:00
} ;
// Helper
2017-01-25 01:45:36 +01:00
template < typename T , typename RT >
struct return_pair
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
std : : shared_ptr < T > ptr ;
RT value ;
explicit operator bool ( ) const
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
return ptr . operator bool ( ) ;
2016-05-13 16:01:48 +02:00
}
2017-01-25 01:45:36 +01:00
auto operator - > ( ) const
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
return ptr . get ( ) ;
2016-05-13 16:01:48 +02:00
}
} ;
2017-01-25 01:45:36 +01:00
template < typename RT >
struct return_pair < bool , RT >
{
bool result ;
RT value ;
explicit operator bool ( ) const
{
return result ;
}
} ;
// Prepare new ID (returns nullptr if out of resources)
2016-08-01 01:26:55 +02:00
static id_manager : : id_map : : pointer allocate_id ( u32 tag , u32 type , u32 min , u32 max ) ;
2015-08-04 12:46:05 +02:00
2016-04-27 00:27:24 +02:00
// Deallocate ID, returns object
static std : : shared_ptr < void > deallocate_id ( u32 tag , u32 id ) ;
2015-08-04 12:46:05 +02:00
2017-01-25 01:45:36 +01:00
// Allocate new ID and assign the object from the provider()
2016-08-01 01:26:55 +02:00
template < typename T , typename Set , typename F >
2016-08-01 00:35:53 +02:00
static id_manager : : id_map : : pointer create_id ( F & & provider )
2016-04-14 00:59:00 +02:00
{
2016-06-21 10:22:30 +02:00
id_manager : : typeinfo : : update < T > ( ) ;
id_manager : : typeinfo : : update < typename id_manager : : id_traits < T > : : tag > ( ) ;
2016-04-25 12:49:12 +02:00
writer_lock lock ( g_mutex ) ;
2016-04-14 00:59:00 +02:00
2016-08-01 01:26:55 +02:00
if ( auto place = allocate_id ( get_tag < T > ( ) , get_type < Set > ( ) , id_manager : : id_traits < T > : : min , id_manager : : id_traits < T > : : max ) )
2016-04-14 00:59:00 +02:00
{
try
{
2016-04-27 00:27:24 +02:00
// Get object, store it
2016-04-14 00:59:00 +02:00
place - > second = provider ( ) ;
2016-04-27 00:27:24 +02:00
// Update ID value if required
2016-08-01 00:35:53 +02:00
set_id_value ( static_cast < T * > ( place - > second . get ( ) ) , place - > first . id ( ) ) ;
2016-04-14 00:59:00 +02:00
return & * g_map [ get_type < T > ( ) ] . emplace ( * place ) . first ;
}
catch ( . . . )
{
2016-08-01 00:35:53 +02:00
deallocate_id ( get_tag < T > ( ) , place - > first . id ( ) ) ;
2016-04-14 00:59:00 +02:00
throw ;
}
2015-08-04 12:46:05 +02:00
}
2015-07-01 00:25:52 +02:00
2015-08-11 18:14:53 +02:00
return nullptr ;
2015-07-01 00:25:52 +02:00
}
2016-04-27 00:27:24 +02:00
// Get ID (internal)
2016-08-01 01:26:55 +02:00
static id_manager : : id_map : : pointer find_id ( u32 type , u32 true_type , u32 id ) ;
2016-04-14 00:59:00 +02:00
2017-01-25 01:45:36 +01:00
// Remove ID and return the object
2016-08-01 01:26:55 +02:00
static std : : shared_ptr < void > delete_id ( u32 type , u32 true_type , u32 tag , u32 id ) ;
2016-04-14 00:59:00 +02:00
public :
// Initialize object manager
2016-04-27 00:27:24 +02:00
static void init ( ) ;
2016-04-14 00:59:00 +02:00
// Remove all objects
2016-04-27 00:27:24 +02:00
static void clear ( ) ;
2016-04-14 00:59:00 +02:00
2015-11-26 09:06:29 +01:00
// Add a new ID of specified type with specified constructor arguments (returns object or nullptr)
2016-04-14 00:59:00 +02:00
template < typename T , typename Make = T , typename . . . Args >
2016-08-01 01:26:55 +02:00
static inline std : : enable_if_t < std : : is_constructible < Make , Args . . . > : : value , std : : shared_ptr < Make > > make_ptr ( Args & & . . . args )
2015-03-12 20:02:02 +01:00
{
2016-08-15 16:11:45 +02:00
if ( auto pair = create_id < T , Make > ( [ & ] { return std : : make_shared < Make > ( std : : forward < Args > ( args ) . . . ) ; } ) )
2015-08-04 12:46:05 +02:00
{
2016-07-24 01:56:03 +02:00
id_manager : : on_init < T > : : func ( static_cast < T * > ( pair - > second . get ( ) ) , pair - > second ) ;
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( nullptr ) ;
2016-08-01 01:26:55 +02:00
return { pair - > second , static_cast < Make * > ( pair - > second . get ( ) ) } ;
2015-08-04 12:46:05 +02:00
}
2015-11-26 09:06:29 +01:00
return nullptr ;
2015-08-04 12:46:05 +02:00
}
2015-11-26 09:06:29 +01:00
// Add a new ID of specified type with specified constructor arguments (returns id)
2016-04-14 00:59:00 +02:00
template < typename T , typename Make = T , typename . . . Args >
2016-05-13 16:01:48 +02:00
static inline std : : enable_if_t < std : : is_constructible < Make , Args . . . > : : value , u32 > make ( Args & & . . . args )
2015-08-07 23:28:09 +02:00
{
2016-08-15 16:11:45 +02:00
if ( auto pair = create_id < T , Make > ( [ & ] { return std : : make_shared < Make > ( std : : forward < Args > ( args ) . . . ) ; } ) )
2015-08-07 23:28:09 +02:00
{
2016-07-24 01:56:03 +02:00
id_manager : : on_init < T > : : func ( static_cast < T * > ( pair - > second . get ( ) ) , pair - > second ) ;
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( nullptr ) ;
2016-08-01 00:35:53 +02:00
return pair - > first . id ( ) ;
2015-08-07 23:28:09 +02:00
}
2016-08-08 18:01:06 +02:00
fmt : : throw_exception ( " Out of IDs ('%s') " HERE , typeid ( T ) . name ( ) ) ;
2015-08-07 23:28:09 +02:00
}
2015-11-26 09:06:29 +01:00
// Add a new ID for an existing object provided (returns new id)
2016-08-01 01:26:55 +02:00
template < typename T , typename Made = T >
2016-05-13 16:01:48 +02:00
static inline u32 import_existing ( const std : : shared_ptr < T > & ptr )
2015-03-15 10:20:29 +01:00
{
2016-08-15 16:11:45 +02:00
if ( auto pair = create_id < T , Made > ( [ & ] { return ptr ; } ) )
2015-03-15 10:20:29 +01:00
{
2016-07-24 01:56:03 +02:00
id_manager : : on_init < T > : : func ( static_cast < T * > ( pair - > second . get ( ) ) , pair - > second ) ;
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( nullptr ) ;
2016-08-01 00:35:53 +02:00
return pair - > first . id ( ) ;
2015-03-15 10:20:29 +01:00
}
2016-08-08 18:01:06 +02:00
fmt : : throw_exception ( " Out of IDs ('%s') " HERE , typeid ( T ) . name ( ) ) ;
2015-03-15 10:20:29 +01:00
}
2016-04-14 00:59:00 +02:00
// Add a new ID for an object returned by provider()
2016-08-01 01:26:55 +02:00
template < typename T , typename Made = T , typename F , typename = std : : result_of_t < F ( ) > >
static inline std : : shared_ptr < Made > import ( F & & provider )
2016-04-14 00:59:00 +02:00
{
2016-08-01 01:26:55 +02:00
if ( auto pair = create_id < T , Made > ( std : : forward < F > ( provider ) ) )
2016-04-14 00:59:00 +02:00
{
2016-07-24 01:56:03 +02:00
id_manager : : on_init < T > : : func ( static_cast < T * > ( pair - > second . get ( ) ) , pair - > second ) ;
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( nullptr ) ;
2016-08-01 01:26:55 +02:00
return { pair - > second , static_cast < Made * > ( pair - > second . get ( ) ) } ;
2016-04-14 00:59:00 +02:00
}
return nullptr ;
}
2015-11-26 09:06:29 +01:00
2017-01-25 01:45:36 +01:00
// Check the ID
2016-08-01 01:26:55 +02:00
template < typename T , typename Get = void >
2017-01-25 01:45:36 +01:00
static inline explicit_bool_t check ( u32 id )
2015-07-08 17:01:59 +02:00
{
2016-04-14 00:59:00 +02:00
reader_lock lock ( g_mutex ) ;
2016-08-01 01:26:55 +02:00
return find_id ( get_type < T > ( ) , get_type < Get > ( ) , id ) ! = nullptr ;
2015-11-26 09:06:29 +01:00
}
2015-07-08 17:01:59 +02:00
2017-01-25 01:45:36 +01:00
// Check the ID, access object under shared lock
template < typename T , typename Get = void , typename F , typename FRT = std : : result_of_t < F ( T & ) > , typename = std : : enable_if_t < std : : is_void < FRT > : : value > >
static inline explicit_bool_t check ( u32 id , F & & func , int = 0 )
{
using pointer_type = std : : conditional_t < std : : is_void < Get > : : value , T , Get > ;
reader_lock lock ( g_mutex ) ;
const auto found = find_id ( get_type < T > ( ) , get_type < Get > ( ) , id ) ;
if ( UNLIKELY ( found = = nullptr ) )
{
return false ;
}
func ( * static_cast < pointer_type * > ( found - > second . get ( ) ) ) ;
return true ;
}
// Check the ID, access object under reader lock, propagate return value
template < typename T , typename Get = void , typename F , typename FRT = std : : result_of_t < F ( T & ) > , typename = std : : enable_if_t < ! std : : is_void < FRT > : : value > >
static inline return_pair < bool , FRT > check ( u32 id , F & & func )
{
using pointer_type = std : : conditional_t < std : : is_void < Get > : : value , T , Get > ;
reader_lock lock ( g_mutex ) ;
const auto found = find_id ( get_type < T > ( ) , get_type < Get > ( ) , id ) ;
if ( UNLIKELY ( found = = nullptr ) )
{
return { false } ;
}
return { true , func ( * static_cast < pointer_type * > ( found - > second . get ( ) ) ) } ;
}
// Get the object
2016-08-01 01:26:55 +02:00
template < typename T , typename Get = void , typename Made = std : : conditional_t < std : : is_void < Get > : : value , T , Get > >
static inline std : : shared_ptr < Made > get ( u32 id )
2016-04-14 00:59:00 +02:00
{
reader_lock lock ( g_mutex ) ;
2016-08-01 01:26:55 +02:00
const auto found = find_id ( get_type < T > ( ) , get_type < Get > ( ) , id ) ;
2015-07-08 17:01:59 +02:00
2016-04-27 00:27:24 +02:00
if ( UNLIKELY ( found = = nullptr ) )
2016-04-14 00:59:00 +02:00
{
return nullptr ;
}
2017-01-25 01:45:36 +01:00
return { found - > second , static_cast < Made * > ( found - > second . get ( ) ) } ;
2016-04-14 00:59:00 +02:00
}
2017-01-25 01:45:36 +01:00
// Get the object, access object under reader lock
template < typename T , typename Get = void , typename F , typename FRT = std : : result_of_t < F ( T & ) > , typename = std : : enable_if_t < std : : is_void < FRT > : : value > >
static inline auto get ( u32 id , F & & func , int = 0 )
2015-11-26 09:06:29 +01:00
{
2017-01-25 01:45:36 +01:00
using pointer_type = std : : conditional_t < std : : is_void < Get > : : value , T , Get > ;
using result_type = std : : shared_ptr < pointer_type > ;
2016-05-13 16:01:48 +02:00
2016-04-14 00:59:00 +02:00
reader_lock lock ( g_mutex ) ;
2016-08-01 01:26:55 +02:00
const auto found = find_id ( get_type < T > ( ) , get_type < Get > ( ) , id ) ;
2016-05-13 16:01:48 +02:00
if ( UNLIKELY ( found = = nullptr ) )
{
2017-01-25 01:45:36 +01:00
return result_type { nullptr } ;
2016-05-13 16:01:48 +02:00
}
2015-07-08 17:01:59 +02:00
2017-01-25 01:45:36 +01:00
const auto ptr = static_cast < pointer_type * > ( found - > second . get ( ) ) ;
func ( * ptr ) ;
return result_type { found - > second , ptr } ;
}
// Get the object, access object under reader lock, propagate return value
template < typename T , typename Get = void , typename F , typename FRT = std : : result_of_t < F ( T & ) > , typename = std : : enable_if_t < ! std : : is_void < FRT > : : value > >
static inline auto get ( u32 id , F & & func )
{
using pointer_type = std : : conditional_t < std : : is_void < Get > : : value , T , Get > ;
using result_type = return_pair < pointer_type , FRT > ;
reader_lock lock ( g_mutex ) ;
const auto found = find_id ( get_type < T > ( ) , get_type < Get > ( ) , id ) ;
if ( UNLIKELY ( found = = nullptr ) )
{
return result_type { nullptr } ;
}
const auto ptr = static_cast < pointer_type * > ( found - > second . get ( ) ) ;
return result_type { { found - > second , ptr } , func ( * ptr ) } ;
}
// Access all objects of specified types under reader lock (use lambda or callable object), return the number of objects processed
template < typename . . . Types , typename F , typename FT = decltype ( & std : : decay_t < F > : : operator ( ) ) , typename FRT = typename function_traits < FT > : : void_type >
static inline u32 select ( F & & func , int = 0 )
{
reader_lock lock ( g_mutex ) ;
u32 result = 0 ;
for ( u32 type : { get_type < Types > ( ) . . . } )
2015-07-08 17:01:59 +02:00
{
2017-01-25 01:45:36 +01:00
for ( auto & id : g_map [ type ] )
{
func ( id . first . id ( ) , * static_cast < typename function_traits < FT > : : object_type * > ( id . second . get ( ) ) ) ;
result + + ;
}
2016-05-13 16:01:48 +02:00
}
2017-01-25 01:45:36 +01:00
return result ;
2016-05-13 16:01:48 +02:00
}
2017-01-25 01:45:36 +01:00
// Access all objects of specified types under reader lock (use lambda or callable object), if return value evaluates to true, stop and return the object and the value
template < typename . . . Types , typename F , typename FT = decltype ( & std : : decay_t < F > : : operator ( ) ) , typename FRT = typename function_traits < FT > : : result_type >
static inline auto select ( F & & func )
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
using object_type = typename function_traits < FT > : : object_type ;
using result_type = return_pair < object_type , FRT > ;
2016-05-13 16:01:48 +02:00
reader_lock lock ( g_mutex ) ;
for ( u32 type : { get_type < Types > ( ) . . . } )
{
for ( auto & id : g_map [ type ] )
{
2017-01-25 01:45:36 +01:00
if ( FRT result = func ( id . first . id ( ) , * static_cast < object_type * > ( id . second . get ( ) ) ) )
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
return result_type { { id . second , static_cast < object_type * > ( id . second . get ( ) ) } , std : : move ( result ) } ;
2016-05-13 16:01:48 +02:00
}
}
2015-07-08 17:01:59 +02:00
}
2017-01-25 01:45:36 +01:00
return result_type { nullptr } ;
2016-05-13 16:01:48 +02:00
}
// Get count of objects
2016-08-01 01:26:55 +02:00
template < typename T , typename Get = void >
2016-05-13 16:01:48 +02:00
static inline u32 get_count ( )
{
reader_lock lock ( g_mutex ) ;
2016-08-01 01:26:55 +02:00
if ( std : : is_void < Get > : : value )
{
return : : size32 ( g_map [ get_type < T > ( ) ] ) ;
}
u32 result = 0 ;
for ( auto & id : g_map [ get_type < T > ( ) ] )
{
if ( id . first . type ( ) = = get_type < Get > ( ) )
{
result + + ;
}
}
return result ;
2015-07-08 17:01:59 +02:00
}
2016-04-14 00:59:00 +02:00
// Remove the ID
2016-08-01 01:26:55 +02:00
template < typename T , typename Get = void >
2017-01-25 01:45:36 +01:00
static inline explicit_bool_t remove ( u32 id )
2015-11-26 09:06:29 +01:00
{
2017-01-25 01:45:36 +01:00
auto ptr = delete_id ( get_type < T > ( ) , get_type < Get > ( ) , get_tag < T > ( ) , id ) ;
2015-08-04 12:46:05 +02:00
2016-04-27 00:27:24 +02:00
if ( LIKELY ( ptr ) )
2016-04-14 00:59:00 +02:00
{
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( static_cast < T * > ( ptr . get ( ) ) ) ;
2015-11-26 09:06:29 +01:00
}
2015-08-04 12:46:05 +02:00
2016-04-14 00:59:00 +02:00
return ptr . operator bool ( ) ;
2015-08-04 12:46:05 +02:00
}
2017-01-25 01:45:36 +01:00
// Remove the ID and return the object
2016-08-01 01:26:55 +02:00
template < typename T , typename Get = void , typename Made = std : : conditional_t < std : : is_void < Get > : : value , T , Get > >
static inline std : : shared_ptr < Made > withdraw ( u32 id )
2015-08-07 23:28:09 +02:00
{
2017-01-25 01:45:36 +01:00
auto ptr = delete_id ( get_type < T > ( ) , get_type < Get > ( ) , get_tag < T > ( ) , id ) ;
2015-08-07 23:28:09 +02:00
2016-04-27 00:27:24 +02:00
if ( LIKELY ( ptr ) )
2016-04-14 00:59:00 +02:00
{
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( static_cast < T * > ( ptr . get ( ) ) ) ;
2015-11-26 09:06:29 +01:00
}
2015-08-07 23:28:09 +02:00
2017-01-25 01:45:36 +01:00
return { ptr , static_cast < Made * > ( ptr . get ( ) ) } ;
}
// Remove the ID after accessing the object under writer lock, return the object and propagate return value
template < typename T , typename Get = void , typename F , typename FRT = std : : result_of_t < F ( T & ) > , typename = std : : enable_if_t < std : : is_void < FRT > : : value > >
static inline auto withdraw ( u32 id , F & & func , int = 0 )
{
using pointer_type = std : : conditional_t < std : : is_void < Get > : : value , T , Get > ;
using result_type = std : : shared_ptr < pointer_type > ;
std : : shared_ptr < void > ptr ;
{
writer_lock lock ( g_mutex ) ;
const auto found = find_id ( get_type < T > ( ) , get_type < Get > ( ) , id ) ;
if ( UNLIKELY ( found = = nullptr ) )
{
return result_type { nullptr } ;
}
func ( * static_cast < pointer_type * > ( found - > second . get ( ) ) ) ;
ptr = deallocate_id ( get_tag < T > ( ) , id ) ;
g_map [ get_type < T > ( ) ] . erase ( id ) ;
}
id_manager : : on_stop < T > : : func ( static_cast < T * > ( ptr . get ( ) ) ) ;
return result_type { ptr , static_cast < pointer_type * > ( ptr . get ( ) ) } ;
2015-08-07 23:28:09 +02:00
}
2017-01-25 01:45:36 +01:00
// Conditionally remove the ID (if return value evaluates to false) after accessing the object under writer lock, return the object and propagate return value
template < typename T , typename Get = void , typename F , typename FRT = std : : result_of_t < F ( T & ) > , typename = std : : enable_if_t < ! std : : is_void < FRT > : : value > >
static inline auto withdraw ( u32 id , F & & func )
2015-07-01 00:25:52 +02:00
{
2017-01-25 01:45:36 +01:00
using pointer_type = std : : conditional_t < std : : is_void < Get > : : value , T , Get > ;
using result_type = return_pair < pointer_type , FRT > ;
2016-05-13 16:01:48 +02:00
std : : shared_ptr < void > ptr ;
2017-01-25 01:45:36 +01:00
FRT ret ;
2015-07-01 00:25:52 +02:00
{
2016-05-13 16:01:48 +02:00
writer_lock lock ( g_mutex ) ;
2015-07-01 00:25:52 +02:00
2016-08-01 01:26:55 +02:00
const auto found = find_id ( get_type < T > ( ) , get_type < Get > ( ) , id ) ;
2015-07-01 00:25:52 +02:00
2017-01-25 01:45:36 +01:00
if ( UNLIKELY ( found = = nullptr ) )
{
return result_type { nullptr } ;
}
const auto _ptr = static_cast < pointer_type * > ( found - > second . get ( ) ) ;
ret = func ( * _ptr ) ;
if ( ret )
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
return result_type { { found - > second , _ptr } , std : : move ( ret ) } ;
2016-05-13 16:01:48 +02:00
}
2016-04-14 00:59:00 +02:00
2016-05-13 16:01:48 +02:00
ptr = deallocate_id ( get_tag < T > ( ) , id ) ;
2015-07-01 00:25:52 +02:00
2016-05-13 16:01:48 +02:00
g_map [ get_type < T > ( ) ] . erase ( id ) ;
2015-07-01 00:25:52 +02:00
}
2016-05-13 16:01:48 +02:00
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( static_cast < T * > ( ptr . get ( ) ) ) ;
2015-07-01 00:25:52 +02:00
2017-01-25 01:45:36 +01:00
return result_type { { ptr , static_cast < pointer_type * > ( ptr . get ( ) ) } , std : : move ( ret ) } ;
2015-07-01 00:25:52 +02:00
}
2016-04-14 00:59:00 +02:00
} ;
2015-08-06 15:05:33 +02:00
2016-04-14 00:59:00 +02:00
// Object manager for emulated process. One unique object per type, or zero.
class fxm
2015-08-06 15:05:33 +02:00
{
2016-04-14 00:59:00 +02:00
// Type Index -> Object. Use global since only one process is supported atm.
static std : : vector < std : : shared_ptr < void > > g_map ;
2015-12-01 15:48:32 +01:00
2016-04-14 00:59:00 +02:00
static shared_mutex g_mutex ;
2015-09-18 00:41:14 +02:00
2016-04-14 00:59:00 +02:00
template < typename T >
static inline u32 get_type ( )
2015-09-18 00:41:14 +02:00
{
2016-04-27 00:27:24 +02:00
return id_manager : : typeinfo : : get_index < T > ( ) ;
2016-04-14 00:59:00 +02:00
}
2015-08-06 15:05:33 +02:00
2016-04-27 00:27:24 +02:00
static std : : shared_ptr < void > remove ( u32 type ) ;
2015-08-06 15:05:33 +02:00
2016-04-14 00:59:00 +02:00
public :
// Initialize object manager
2016-04-27 00:27:24 +02:00
static void init ( ) ;
2016-04-14 00:59:00 +02:00
// Remove all objects
2016-04-27 00:27:24 +02:00
static void clear ( ) ;
2015-08-06 15:05:33 +02:00
2015-11-26 09:06:29 +01:00
// Create the object (returns nullptr if it already exists)
2016-04-14 00:59:00 +02:00
template < typename T , typename Make = T , typename . . . Args >
static std : : enable_if_t < std : : is_constructible < Make , Args . . . > : : value , std : : shared_ptr < T > > make ( Args & & . . . args )
2015-08-06 17:55:19 +02:00
{
2016-06-21 10:22:30 +02:00
id_manager : : typeinfo : : update < T > ( ) ;
2016-04-14 00:59:00 +02:00
std : : shared_ptr < T > ptr ;
{
2016-04-25 12:49:12 +02:00
writer_lock lock ( g_mutex ) ;
2016-04-14 00:59:00 +02:00
if ( ! g_map [ get_type < T > ( ) ] )
{
ptr = std : : make_shared < Make > ( std : : forward < Args > ( args ) . . . ) ;
g_map [ get_type < T > ( ) ] = ptr ;
}
}
2015-09-18 00:41:14 +02:00
2016-04-14 00:59:00 +02:00
if ( ptr )
2015-09-18 00:41:14 +02:00
{
2016-07-24 01:56:03 +02:00
id_manager : : on_init < T > : : func ( ptr . get ( ) , ptr ) ;
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( nullptr ) ;
2015-09-18 00:41:14 +02:00
}
2016-04-14 00:59:00 +02:00
return ptr ;
2015-09-18 00:41:14 +02:00
}
2015-11-26 09:06:29 +01:00
// Create the object unconditionally (old object will be removed if it exists)
2016-04-14 00:59:00 +02:00
template < typename T , typename Make = T , typename . . . Args >
static std : : enable_if_t < std : : is_constructible < Make , Args . . . > : : value , std : : shared_ptr < T > > make_always ( Args & & . . . args )
2015-09-18 00:41:14 +02:00
{
2016-06-21 10:22:30 +02:00
id_manager : : typeinfo : : update < T > ( ) ;
2016-04-14 00:59:00 +02:00
std : : shared_ptr < T > ptr ;
std : : shared_ptr < void > old ;
{
2016-04-25 12:49:12 +02:00
writer_lock lock ( g_mutex ) ;
2016-04-14 00:59:00 +02:00
old = std : : move ( g_map [ get_type < T > ( ) ] ) ;
ptr = std : : make_shared < Make > ( std : : forward < Args > ( args ) . . . ) ;
g_map [ get_type < T > ( ) ] = ptr ;
}
2015-09-18 00:41:14 +02:00
2016-04-14 00:59:00 +02:00
if ( old )
2015-11-26 09:06:29 +01:00
{
2016-04-14 00:59:00 +02:00
id_manager : : on_stop < T > : : func ( static_cast < T * > ( old . get ( ) ) ) ;
2015-11-26 09:06:29 +01:00
}
2015-08-06 17:55:19 +02:00
2016-07-24 01:56:03 +02:00
id_manager : : on_init < T > : : func ( ptr . get ( ) , ptr ) ;
2016-04-14 00:59:00 +02:00
return ptr ;
2015-08-06 17:55:19 +02:00
}
2015-12-19 12:40:52 +01:00
// Emplace the object returned by provider() and return it if no object exists
template < typename T , typename F >
2016-04-14 00:59:00 +02:00
static auto import ( F & & provider ) - > decltype ( static_cast < std : : shared_ptr < T > > ( provider ( ) ) )
2015-08-10 21:39:52 +02:00
{
2016-06-21 10:22:30 +02:00
id_manager : : typeinfo : : update < T > ( ) ;
2016-04-14 00:59:00 +02:00
std : : shared_ptr < T > ptr ;
{
2016-04-25 12:49:12 +02:00
writer_lock lock ( g_mutex ) ;
2015-08-10 21:39:52 +02:00
2016-04-14 00:59:00 +02:00
if ( ! g_map [ get_type < T > ( ) ] )
{
ptr = provider ( ) ;
2015-08-10 21:39:52 +02:00
2016-04-14 00:59:00 +02:00
g_map [ get_type < T > ( ) ] = ptr ;
}
}
if ( ptr )
2015-08-10 21:39:52 +02:00
{
2016-07-24 01:56:03 +02:00
id_manager : : on_init < T > : : func ( ptr . get ( ) , ptr ) ;
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( nullptr ) ;
2015-08-10 21:39:52 +02:00
}
2016-04-14 00:59:00 +02:00
return ptr ;
2015-08-10 21:39:52 +02:00
}
2015-12-19 12:40:52 +01:00
// Emplace the object return by provider() (old object will be removed if it exists)
template < typename T , typename F >
2016-04-14 00:59:00 +02:00
static auto import_always ( F & & provider ) - > decltype ( static_cast < std : : shared_ptr < T > > ( provider ( ) ) )
2015-08-06 15:05:33 +02:00
{
2016-06-21 10:22:30 +02:00
id_manager : : typeinfo : : update < T > ( ) ;
2016-04-14 00:59:00 +02:00
std : : shared_ptr < T > ptr ;
std : : shared_ptr < void > old ;
{
2016-04-25 12:49:12 +02:00
writer_lock lock ( g_mutex ) ;
2015-08-06 15:05:33 +02:00
2016-04-14 00:59:00 +02:00
old = std : : move ( g_map [ get_type < T > ( ) ] ) ;
ptr = provider ( ) ;
2015-08-06 15:05:33 +02:00
2016-04-14 00:59:00 +02:00
g_map [ get_type < T > ( ) ] = ptr ;
}
if ( old )
2015-08-06 15:05:33 +02:00
{
2016-04-14 00:59:00 +02:00
id_manager : : on_stop < T > : : func ( static_cast < T * > ( old . get ( ) ) ) ;
2015-08-06 15:05:33 +02:00
}
2016-07-24 01:56:03 +02:00
id_manager : : on_init < T > : : func ( ptr . get ( ) , ptr ) ;
2016-04-14 00:59:00 +02:00
return ptr ;
2015-08-06 15:05:33 +02:00
}
2015-11-26 09:06:29 +01:00
// Get the object unconditionally (create an object if it doesn't exist)
2016-04-14 00:59:00 +02:00
template < typename T , typename Make = T , typename . . . Args >
static std : : enable_if_t < std : : is_constructible < Make , Args . . . > : : value , std : : shared_ptr < T > > get_always ( Args & & . . . args )
2015-08-06 15:05:33 +02:00
{
2016-06-21 10:22:30 +02:00
id_manager : : typeinfo : : update < T > ( ) ;
2016-04-14 00:59:00 +02:00
std : : shared_ptr < T > ptr ;
2015-08-06 15:05:33 +02:00
{
2016-04-25 12:49:12 +02:00
writer_lock lock ( g_mutex ) ;
2016-04-14 00:59:00 +02:00
if ( auto & value = g_map [ get_type < T > ( ) ] )
{
return { value , static_cast < T * > ( value . get ( ) ) } ;
}
else
{
ptr = std : : make_shared < Make > ( std : : forward < Args > ( args ) . . . ) ;
g_map [ get_type < T > ( ) ] = ptr ;
}
2015-08-06 15:05:33 +02:00
}
2016-07-24 01:56:03 +02:00
id_manager : : on_init < T > : : func ( ptr . get ( ) , ptr ) ;
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( nullptr ) ;
2016-04-14 00:59:00 +02:00
return ptr ;
2015-08-06 15:05:33 +02:00
}
2015-08-06 17:55:19 +02:00
2015-11-26 09:06:29 +01:00
// Check whether the object exists
template < typename T >
2017-01-25 01:45:36 +01:00
static inline explicit_bool_t check ( )
2015-08-06 17:55:19 +02:00
{
2016-04-14 00:59:00 +02:00
reader_lock lock ( g_mutex ) ;
2015-08-06 17:55:19 +02:00
2016-04-14 00:59:00 +02:00
return g_map [ get_type < T > ( ) ] . operator bool ( ) ;
}
2015-08-06 17:55:19 +02:00
2015-11-26 09:06:29 +01:00
// Get the object (returns nullptr if it doesn't exist)
template < typename T >
2016-05-13 16:01:48 +02:00
static inline std : : shared_ptr < T > get ( )
2015-11-26 09:06:29 +01:00
{
2016-04-14 00:59:00 +02:00
reader_lock lock ( g_mutex ) ;
auto & ptr = g_map [ get_type < T > ( ) ] ;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
return { ptr , static_cast < T * > ( ptr . get ( ) ) } ;
}
2015-11-26 09:06:29 +01:00
// Delete the object
template < typename T >
2017-01-25 01:45:36 +01:00
static inline explicit_bool_t remove ( )
2015-11-26 09:06:29 +01:00
{
2017-01-25 01:45:36 +01:00
auto ptr = remove ( get_type < T > ( ) ) ;
2016-04-14 00:59:00 +02:00
if ( ptr )
2015-08-06 17:55:19 +02:00
{
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( static_cast < T * > ( ptr . get ( ) ) ) ;
2015-08-06 17:55:19 +02:00
}
2016-04-14 00:59:00 +02:00
return ptr . operator bool ( ) ;
2015-11-26 09:06:29 +01:00
}
2015-08-06 17:55:19 +02:00
2015-11-26 09:06:29 +01:00
// Delete the object and return it
template < typename T >
2016-05-13 16:01:48 +02:00
static inline std : : shared_ptr < T > withdraw ( )
2015-11-26 09:06:29 +01:00
{
2017-01-25 01:45:36 +01:00
auto ptr = remove ( get_type < T > ( ) ) ;
2016-04-14 00:59:00 +02:00
if ( ptr )
2015-11-26 09:06:29 +01:00
{
2016-06-25 07:16:15 +02:00
id_manager : : on_stop < T > : : func ( static_cast < T * > ( ptr . get ( ) ) ) ;
2015-11-26 09:06:29 +01:00
}
2016-04-14 00:59:00 +02:00
return { ptr , static_cast < T * > ( ptr . get ( ) ) } ;
2015-08-06 17:55:19 +02:00
}
2016-04-14 00:59:00 +02:00
} ;