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>
2012-11-15 00:39:56 +01:00
2017-01-29 17:50:18 +01:00
// Helper namespace
2016-04-14 00:59:00 +02:00
namespace id_manager
2015-11-26 09:06:29 +01:00
{
2017-01-25 18:50:30 +01:00
// Common global mutex
extern shared_mutex g_mutex ;
2017-01-29 17:50:18 +01:00
// ID traits
template < typename T , typename = void >
2016-04-14 00:59:00 +02:00
struct id_traits
{
2017-01-25 18:50:30 +01:00
static_assert ( sizeof ( T ) = = 0 , " ID object must specify: id_base, id_step, id_count " ) ;
2015-09-18 00:41:14 +02:00
2017-01-29 17:50:18 +01:00
static const u32 base = 1 ; // First ID (N = 0)
static const u32 step = 1 ; // Any ID: N * id_step + id_base
static const u32 count = 65535 ; // Limit: N < id_count
2017-01-25 18:50:30 +01:00
static const u32 invalid = 0 ;
2016-04-14 00:59:00 +02:00
} ;
2015-09-18 00:41:14 +02:00
2017-01-29 17:50:18 +01:00
template < typename T >
2017-01-25 18:50:30 +01:00
struct id_traits < T , void_t < decltype ( & T : : id_base ) , decltype ( & T : : id_step ) , decltype ( & T : : id_count ) > >
2016-04-14 00:59:00 +02:00
{
2017-01-29 17:50:18 +01:00
static const u32 base = T : : id_base ;
static const u32 step = T : : id_step ;
static const u32 count = T : : id_count ;
2017-01-25 18:50:30 +01:00
static const u32 invalid = base > 0 ? 0 : - 1 ;
2015-11-26 09:06:29 +01:00
2017-01-25 18:50:30 +01:00
static_assert ( u64 { step } * count + base < UINT32_MAX , " ID traits: invalid object range " ) ;
2016-04-14 00:59:00 +02:00
} ;
2015-08-11 18:14:53 +02:00
2016-04-14 00:59:00 +02:00
// Optional object initialization function (called after ID registration)
2017-01-29 17:50:18 +01:00
template < typename T , typename = void >
2016-04-14 00:59:00 +02:00
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
2017-01-29 17:50:18 +01: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
{
2017-01-29 17:50:18 +01: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)
2017-01-29 17:50:18 +01:00
template < typename T , typename = void >
2016-04-14 00:59:00 +02:00
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
2017-01-29 17:50:18 +01:00
template < typename T >
2016-04-14 00:59:00 +02:00
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
2017-01-29 17:50:18 +01:00
// Correct usage testing
template < typename T , typename T2 , typename = void >
struct id_verify : std : : integral_constant < bool , std : : is_base_of < T , T2 > : : value >
{
// If common case, T2 shall be derived from or equal to T
} ;
template < typename T , typename T2 >
struct id_verify < T , T2 , void_t < typename T2 : : id_type > > : std : : integral_constant < bool , std : : is_same < T , typename T2 : : id_type > : : value >
{
// If T2 contains id_type type, T must be equal to it
} ;
2016-04-14 00:59:00 +02:00
class typeinfo
{
// Global variable for each registered type
2017-01-29 17:50:18 +01:00
template < typename T >
2016-04-14 00:59:00 +02:00
struct registered
{
static const u32 index ;
} ;
2015-11-26 09:06:29 +01:00
2017-01-29 17:50:18 +01:00
// Increment type counter
static u32 add_type ( u32 i )
{
static atomic_t < u32 > g_next { 0 } ;
2016-04-14 00:59:00 +02:00
2017-01-29 17:50:18 +01:00
return g_next . fetch_add ( i ) ;
}
2016-04-14 00:59:00 +02:00
public :
// Get type index
2017-01-29 17:50:18 +01:00
template < typename T >
2016-04-14 00:59:00 +02:00
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 ;
}
2017-01-29 17:50:18 +01:00
// Get type count
static inline u32 get_count ( )
2016-06-21 10:22:30 +02:00
{
2017-01-29 17:50:18 +01:00
return add_type ( 0 ) ;
2016-04-14 00:59:00 +02:00
}
2017-01-29 17:50:18 +01:00
// Get type finalizer
template < typename T >
static inline auto get_stop ( )
2016-04-14 00:59:00 +02:00
{
2017-01-29 17:50:18 +01:00
return [ ] ( void * ptr ) - > void
{
return id_manager : : on_stop < T > : : func ( static_cast < T * > ( ptr ) ) ;
} ;
2015-11-26 09:06:29 +01:00
}
} ;
2015-09-18 00:41:14 +02:00
2017-01-29 17:50:18 +01:00
template < typename T >
const u32 typeinfo : : registered < T > : : index = typeinfo : : add_type ( 1 ) ;
2016-08-01 00:35:53 +02:00
// ID value with additional type stored
class id_key
{
2017-01-29 17:50:18 +01:00
u32 m_value ; // ID value
u32 m_type ; // True object type
void ( * m_stop ) ( void * ) ; // Finalizer
2016-08-01 00:35:53 +02:00
public :
id_key ( ) = default ;
2017-01-29 17:50:18 +01:00
id_key ( u32 value , u32 type , void ( * stop ) ( void * ) )
2016-08-01 00:35:53 +02:00
: m_value ( value )
, m_type ( type )
2017-01-29 17:50:18 +01:00
, m_stop ( stop )
2016-08-01 00:35:53 +02:00
{
}
2017-01-29 17:50:18 +01:00
u32 value ( ) const
2016-08-01 00:35:53 +02:00
{
return m_value ;
}
u32 type ( ) const
{
return m_type ;
}
2017-01-29 17:50:18 +01:00
auto on_stop ( ) const
2016-08-01 00:35:53 +02:00
{
2017-01-29 17:50:18 +01:00
return m_stop ;
2016-08-01 00:35:53 +02:00
}
2017-01-29 17:50:18 +01:00
operator u32 ( ) const
2017-01-28 15:59:43 +01:00
{
2017-01-29 17:50:18 +01:00
return m_value ;
2017-01-28 15:59:43 +01:00
}
} ;
2017-01-29 17:50:18 +01:00
using id_map = std : : vector < std : : pair < id_key , std : : shared_ptr < void > > > ;
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
{
2017-01-25 18:50:30 +01:00
// Last allocated ID for constructors
static thread_local u32 g_id ;
2016-04-27 00:27:24 +02:00
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
2017-01-29 17:50:18 +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
}
2017-01-29 17:50:18 +01:00
template < typename T >
static constexpr u32 get_index ( u32 id )
{
return ( id - id_manager : : id_traits < T > : : base ) / id_manager : : id_traits < T > : : step ;
}
2016-05-13 16:01:48 +02:00
// Helper
2017-01-29 17:50:18 +01:00
template < typename F >
2016-05-13 16:01:48 +02:00
struct function_traits ;
2017-01-29 17:50:18 +01:00
template < typename F , typename R , typename A1 , typename A2 >
struct function_traits < R ( F : : * ) ( A1 , A2 & ) const >
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
using object_type = A2 ;
using result_type = R ;
} ;
2017-01-29 17:50:18 +01:00
template < typename F , typename R , typename A1 , typename A2 >
struct function_traits < R ( F : : * ) ( A1 , A2 & ) >
2017-01-25 01:45:36 +01:00
{
using object_type = A2 ;
using result_type = R ;
} ;
2017-01-29 17:50:18 +01:00
template < typename F , typename A1 , typename A2 >
struct function_traits < void ( F : : * ) ( A1 , A2 & ) const >
2017-01-25 01:45:36 +01:00
{
using object_type = A2 ;
2017-01-29 17:50:18 +01:00
using void_type = void ;
2017-01-25 01:45:36 +01:00
} ;
2017-01-29 17:50:18 +01:00
template < typename F , typename A1 , typename A2 >
struct function_traits < void ( F : : * ) ( A1 , A2 & ) >
2017-01-25 01:45:36 +01:00
{
using object_type = A2 ;
2017-01-29 17:50:18 +01:00
using void_type = void ;
2016-05-13 16:01:48 +02:00
} ;
// Helper
2017-01-29 17:50:18 +01:00
template < typename T , typename RT >
2017-01-25 01:45:36 +01:00
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-29 17:50:18 +01:00
template < typename RT >
2017-01-25 01:45:36 +01:00
struct return_pair < bool , RT >
{
bool result ;
RT value ;
explicit operator bool ( ) const
{
return result ;
}
} ;
// Prepare new ID (returns nullptr if out of resources)
2017-01-29 17:50:18 +01:00
static id_manager : : id_map : : pointer allocate_id ( const id_manager : : id_key & info , u32 base , u32 step , u32 count ) ;
// Find ID (additionally check type if types are not equal)
template < typename T , typename Type >
static id_manager : : id_map : : pointer find_id ( u32 id )
{
static_assert ( id_manager : : id_verify < T , Type > : : value , " Invalid ID type combination " ) ;
const u32 index = get_index < Type > ( id ) ;
2015-08-04 12:46:05 +02:00
2017-01-29 17:50:18 +01:00
auto & vec = g_map [ get_type < T > ( ) ] ;
if ( index > = vec . size ( ) | | index > = id_manager : : id_traits < Type > : : count )
{
return nullptr ;
}
if ( const auto ptr = & vec [ index ] )
{
if ( std : : is_same < T , Type > : : value | | ptr - > first . type ( ) = = get_type < Type > ( ) )
{
return ptr ;
}
}
2017-01-25 18:50:30 +01:00
2017-01-29 17:50:18 +01:00
return nullptr ;
}
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()
2017-01-29 17:50:18 +01:00
template < typename T , typename Type , 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
{
2017-01-29 17:50:18 +01:00
static_assert ( id_manager : : id_verify < T , Type > : : value , " Invalid ID type combination " ) ;
2017-01-25 18:50:30 +01:00
2017-01-29 17:50:18 +01:00
// ID info
const id_manager : : id_key info { get_type < T > ( ) , get_type < Type > ( ) , id_manager : : typeinfo : : get_stop < Type > ( ) } ;
2016-06-21 10:22:30 +02:00
2017-01-29 17:50:18 +01:00
// ID traits
using traits = id_manager : : id_traits < Type > ;
2016-04-14 00:59:00 +02:00
2017-01-25 18:50:30 +01:00
// Allocate new id
2017-01-29 17:50:18 +01:00
writer_lock lock ( id_manager : : g_mutex ) ;
if ( auto * place = allocate_id ( info , traits : : base , traits : : step , traits : : count ) )
2016-04-14 00:59:00 +02:00
{
2017-01-29 17:50:18 +01:00
// Get object, store it
place - > second = provider ( ) ;
return place ;
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-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
2017-01-29 17:50:18 +01:00
// Get last ID (updated in create_id/allocate_id)
2017-01-25 18:50:30 +01:00
static inline u32 last_id ( )
{
return g_id ;
}
2015-11-26 09:06:29 +01:00
// Add a new ID of specified type with specified constructor arguments (returns object or nullptr)
2017-01-29 17:50:18 +01: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
{
2017-01-29 17:50:18 +01:00
id_manager : : on_init < Make > : : func ( static_cast < Make * > ( pair - > second . get ( ) ) , pair - > second ) ;
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)
2017-01-29 17:50:18 +01: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
{
2017-01-29 17:50:18 +01:00
id_manager : : on_init < Make > : : func ( static_cast < Make * > ( pair - > second . get ( ) ) , pair - > second ) ;
return pair - > first ;
2015-08-07 23:28:09 +02:00
}
2017-01-29 17:50:18 +01:00
return id_manager : : id_traits < Make > : : invalid ;
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)
2017-01-29 17:50:18 +01: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
{
2017-01-29 17:50:18 +01:00
id_manager : : on_init < Made > : : func ( static_cast < Made * > ( pair - > second . get ( ) ) , pair - > second ) ;
return pair - > first ;
2015-03-15 10:20:29 +01:00
}
2017-01-29 17:50:18 +01:00
return id_manager : : id_traits < Made > : : invalid ;
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()
2017-01-29 17:50:18 +01:00
template < typename T , typename Made = T , typename F , typename = std : : result_of_t < F ( ) > >
2016-08-01 01:26:55 +02:00
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
{
2017-01-29 17:50:18 +01:00
id_manager : : on_init < Made > : : func ( static_cast < Made * > ( pair - > second . get ( ) ) , pair - > second ) ;
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
2017-01-29 17:50:18 +01:00
template < typename T , typename Get = T >
2017-01-25 01:45:36 +01:00
static inline explicit_bool_t check ( u32 id )
2015-07-08 17:01:59 +02:00
{
2017-01-25 18:50:30 +01:00
reader_lock lock ( id_manager : : g_mutex ) ;
2016-04-14 00:59:00 +02:00
2017-01-29 17:50:18 +01:00
return find_id < T , 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
2017-01-29 17:50:18 +01:00
template < typename T , typename Get = T , typename F , typename FRT = std : : result_of_t < F ( T & ) > , typename = std : : enable_if_t < std : : is_void < FRT > : : value > >
2017-01-25 01:45:36 +01:00
static inline explicit_bool_t check ( u32 id , F & & func , int = 0 )
{
2017-01-25 18:50:30 +01:00
reader_lock lock ( id_manager : : g_mutex ) ;
2017-01-25 01:45:36 +01:00
2017-01-29 17:50:18 +01:00
const auto found = find_id < T , Get > ( id ) ;
2017-01-25 01:45:36 +01:00
if ( UNLIKELY ( found = = nullptr ) )
{
return false ;
}
2017-01-25 18:50:30 +01:00
func ( * static_cast < Get * > ( found - > second . get ( ) ) ) ;
2017-01-25 01:45:36 +01:00
return true ;
}
// Check the ID, access object under reader lock, propagate return value
2017-01-29 17:50:18 +01:00
template < typename T , typename Get = T , typename F , typename FRT = std : : result_of_t < F ( T & ) > , typename = std : : enable_if_t < ! std : : is_void < FRT > : : value > >
2017-01-25 01:45:36 +01:00
static inline return_pair < bool , FRT > check ( u32 id , F & & func )
{
2017-01-25 18:50:30 +01:00
reader_lock lock ( id_manager : : g_mutex ) ;
2017-01-25 01:45:36 +01:00
2017-01-29 17:50:18 +01:00
const auto found = find_id < T , Get > ( id ) ;
2017-01-25 01:45:36 +01:00
if ( UNLIKELY ( found = = nullptr ) )
{
return { false } ;
}
2017-01-25 18:50:30 +01:00
return { true , func ( * static_cast < Get * > ( found - > second . get ( ) ) ) } ;
2017-01-25 01:45:36 +01:00
}
// Get the object
2017-01-29 17:50:18 +01:00
template < typename T , typename Get = T >
static inline std : : shared_ptr < Get > get ( u32 id )
2016-04-14 00:59:00 +02:00
{
2017-01-25 18:50:30 +01:00
reader_lock lock ( id_manager : : g_mutex ) ;
2016-04-14 00:59:00 +02:00
2017-01-29 17:50:18 +01:00
const auto found = find_id < T , 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-29 17:50:18 +01:00
return { found - > second , static_cast < Get * > ( 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
2017-01-29 17:50:18 +01:00
template < typename T , typename Get = T , typename F , typename FRT = std : : result_of_t < F ( T & ) > , typename = std : : enable_if_t < std : : is_void < FRT > : : value > >
2017-01-25 01:45:36 +01:00
static inline auto get ( u32 id , F & & func , int = 0 )
2015-11-26 09:06:29 +01:00
{
2017-01-25 18:50:30 +01:00
using result_type = std : : shared_ptr < Get > ;
2016-05-13 16:01:48 +02:00
2017-01-25 18:50:30 +01:00
reader_lock lock ( id_manager : : g_mutex ) ;
2016-04-14 00:59:00 +02:00
2017-01-29 17:50:18 +01:00
const auto found = find_id < T , 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 18:50:30 +01:00
const auto ptr = static_cast < Get * > ( found - > second . get ( ) ) ;
2017-01-25 01:45:36 +01:00
func ( * ptr ) ;
return result_type { found - > second , ptr } ;
}
// Get the object, access object under reader lock, propagate return value
2017-01-29 17:50:18 +01:00
template < typename T , typename Get = T , typename F , typename FRT = std : : result_of_t < F ( T & ) > , typename = std : : enable_if_t < ! std : : is_void < FRT > : : value > >
2017-01-25 01:45:36 +01:00
static inline auto get ( u32 id , F & & func )
{
2017-01-25 18:50:30 +01:00
using result_type = return_pair < Get , FRT > ;
2017-01-25 01:45:36 +01:00
2017-01-25 18:50:30 +01:00
reader_lock lock ( id_manager : : g_mutex ) ;
2017-01-25 01:45:36 +01:00
2017-01-29 17:50:18 +01:00
const auto found = find_id < T , Get > ( id ) ;
2017-01-25 01:45:36 +01:00
if ( UNLIKELY ( found = = nullptr ) )
{
return result_type { nullptr } ;
}
2017-01-25 18:50:30 +01:00
const auto ptr = static_cast < Get * > ( found - > second . get ( ) ) ;
2017-01-25 01:45:36 +01:00
return result_type { { found - > second , ptr } , func ( * ptr ) } ;
}
2017-01-29 17:50:18 +01:00
// Access all objects of specified type. Returns the number of objects processed.
template < typename T , typename Get = T , typename F , typename FT = decltype ( & std : : decay_t < F > : : operator ( ) ) , typename FRT = typename function_traits < FT > : : void_type >
2017-01-25 01:45:36 +01:00
static inline u32 select ( F & & func , int = 0 )
{
2017-01-29 17:50:18 +01:00
static_assert ( id_manager : : id_verify < T , Get > : : value , " Invalid ID type combination " ) ;
2017-01-25 18:50:30 +01:00
reader_lock lock ( id_manager : : g_mutex ) ;
2017-01-25 01:45:36 +01:00
u32 result = 0 ;
2017-01-29 17:50:18 +01:00
for ( auto & id : g_map [ get_type < T > ( ) ] )
2015-07-08 17:01:59 +02:00
{
2017-01-29 17:50:18 +01:00
if ( id . second )
2017-01-25 01:45:36 +01:00
{
2017-01-29 17:50:18 +01:00
if ( std : : is_same < T , Get > : : value | | id . first . type ( ) = = get_type < Get > ( ) )
{
func ( id . first , * static_cast < typename function_traits < FT > : : object_type * > ( id . second . get ( ) ) ) ;
result + + ;
}
2017-01-25 01:45:36 +01:00
}
2017-01-29 17:50:18 +01:00
}
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-29 17:50:18 +01:00
// Access all objects of specified type. If function result evaluates to true, stop and return the object and the value.
template < typename T , typename Get = T , typename F , typename FT = decltype ( & std : : decay_t < F > : : operator ( ) ) , typename FRT = typename function_traits < FT > : : result_type >
2017-01-25 01:45:36 +01:00
static inline auto select ( F & & func )
2016-05-13 16:01:48 +02:00
{
2017-01-29 17:50:18 +01:00
static_assert ( id_manager : : id_verify < T , Get > : : value , " Invalid ID type combination " ) ;
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
2017-01-25 18:50:30 +01:00
reader_lock lock ( id_manager : : g_mutex ) ;
2016-05-13 16:01:48 +02:00
2017-01-29 17:50:18 +01:00
for ( auto & id : g_map [ get_type < T > ( ) ] )
2016-05-13 16:01:48 +02:00
{
2017-01-29 17:50:18 +01:00
if ( auto ptr = static_cast < object_type * > ( id . second . get ( ) ) )
2016-05-13 16:01:48 +02:00
{
2017-01-29 17:50:18 +01:00
if ( std : : is_same < T , Get > : : value | | id . first . type ( ) = = get_type < Get > ( ) )
2016-05-13 16:01:48 +02:00
{
2017-01-29 17:50:18 +01:00
if ( FRT result = func ( id . first , * ptr ) )
{
return result_type { { id . second , ptr } , 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
}
2017-01-29 17:50:18 +01:00
// Remove the ID
template < typename T , typename Get = T >
static inline explicit_bool_t remove ( u32 id )
2016-05-13 16:01:48 +02:00
{
2017-01-29 17:50:18 +01:00
std : : shared_ptr < void > ptr ;
2016-08-01 01:26:55 +02:00
{
2017-01-29 17:50:18 +01:00
writer_lock lock ( id_manager : : g_mutex ) ;
2016-08-01 01:26:55 +02:00
2017-01-29 17:50:18 +01:00
if ( const auto found = find_id < T , Get > ( id ) )
2016-08-01 01:26:55 +02:00
{
2017-01-29 17:50:18 +01:00
ptr = std : : move ( found - > second ) ;
}
else
{
return false ;
2016-08-01 01:26:55 +02:00
}
}
2017-01-29 17:50:18 +01:00
id_manager : : on_stop < Get > : : func ( static_cast < Get * > ( ptr . get ( ) ) ) ;
return true ;
2015-08-04 12:46:05 +02:00
}
2017-01-25 01:45:36 +01:00
// Remove the ID and return the object
2017-01-29 17:50:18 +01:00
template < typename T , typename Get = T >
2017-01-25 18:50:30 +01:00
static inline std : : shared_ptr < Get > withdraw ( u32 id )
2015-08-07 23:28:09 +02:00
{
2017-01-29 17:50:18 +01:00
std : : shared_ptr < void > ptr ;
2016-04-14 00:59:00 +02:00
{
2017-01-29 17:50:18 +01:00
writer_lock lock ( id_manager : : g_mutex ) ;
if ( const auto found = find_id < T , Get > ( id ) )
{
ptr = std : : move ( found - > second ) ;
}
else
{
return nullptr ;
}
2015-11-26 09:06:29 +01:00
}
2015-08-07 23:28:09 +02:00
2017-01-29 17:50:18 +01:00
id_manager : : on_stop < Get > : : func ( static_cast < Get * > ( ptr . get ( ) ) ) ;
return { ptr , static_cast < Get * > ( ptr . get ( ) ) } ;
2017-01-25 01:45:36 +01:00
}
// Remove the ID after accessing the object under writer lock, return the object and propagate return value
2017-01-29 17:50:18 +01:00
template < typename T , typename Get = T , typename F , typename FRT = std : : result_of_t < F ( Get & ) > , typename = std : : enable_if_t < std : : is_void < FRT > : : value > >
2017-01-25 01:45:36 +01:00
static inline auto withdraw ( u32 id , F & & func , int = 0 )
{
2017-01-25 18:50:30 +01:00
using result_type = std : : shared_ptr < Get > ;
2017-01-25 01:45:36 +01:00
std : : shared_ptr < void > ptr ;
{
2017-01-25 18:50:30 +01:00
writer_lock lock ( id_manager : : g_mutex ) ;
2017-01-25 01:45:36 +01:00
2017-01-29 17:50:18 +01:00
if ( const auto found = find_id < T , Get > ( id ) )
{
func ( * static_cast < Get * > ( found - > second . get ( ) ) ) ;
2017-01-25 01:45:36 +01:00
2017-01-29 17:50:18 +01:00
ptr = std : : move ( found - > second ) ;
}
else
2017-01-25 01:45:36 +01:00
{
return result_type { nullptr } ;
}
}
2017-01-29 17:50:18 +01:00
id_manager : : on_stop < Get > : : func ( static_cast < Get * > ( ptr . get ( ) ) ) ;
2017-01-25 18:50:30 +01:00
return result_type { ptr , static_cast < Get * > ( 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
2017-01-29 17:50:18 +01:00
template < typename T , typename Get = T , typename F , typename FRT = std : : result_of_t < F ( Get & ) > , typename = std : : enable_if_t < ! std : : is_void < FRT > : : value > >
2017-01-25 01:45:36 +01:00
static inline auto withdraw ( u32 id , F & & func )
2015-07-01 00:25:52 +02:00
{
2017-01-25 18:50:30 +01:00
using result_type = return_pair < Get , FRT > ;
2017-01-25 01:45:36 +01:00
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
{
2017-01-25 18:50:30 +01:00
writer_lock lock ( id_manager : : g_mutex ) ;
2015-07-01 00:25:52 +02:00
2017-01-29 17:50:18 +01:00
if ( const auto found = find_id < T , Get > ( id ) )
2017-01-25 01:45:36 +01:00
{
2017-01-29 17:50:18 +01:00
const auto _ptr = static_cast < Get * > ( found - > second . get ( ) ) ;
2017-01-25 01:45:36 +01:00
2017-01-29 17:50:18 +01:00
ret = func ( * _ptr ) ;
2017-01-25 01:45:36 +01:00
2017-01-29 17:50:18 +01:00
if ( ret )
{
return result_type { { found - > second , _ptr } , std : : move ( ret ) } ;
}
2017-01-25 01:45:36 +01:00
2017-01-29 17:50:18 +01:00
ptr = std : : move ( found - > second ) ;
}
else
2016-05-13 16:01:48 +02:00
{
2017-01-29 17:50:18 +01:00
return result_type { nullptr } ;
2016-05-13 16:01:48 +02:00
}
2015-07-01 00:25:52 +02:00
}
2017-01-29 17:50:18 +01:00
id_manager : : on_stop < Get > : : func ( static_cast < Get * > ( ptr . get ( ) ) ) ;
2017-01-25 18:50:30 +01:00
return result_type { { ptr , static_cast < Get * > ( 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.
2017-01-29 17:50:18 +01:00
static std : : vector < std : : pair < void ( * ) ( void * ) , std : : shared_ptr < void > > > g_vec ;
2015-09-18 00:41:14 +02:00
2017-01-29 17:50:18 +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 > ( ) ;
2016-04-14 00:59:00 +02:00
}
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)
2017-01-29 17:50:18 +01:00
template < typename T , typename Make = T , typename . . . Args >
2016-04-14 00:59:00 +02:00
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-04-14 00:59:00 +02:00
std : : shared_ptr < T > ptr ;
{
2017-01-25 18:50:30 +01:00
writer_lock lock ( id_manager : : g_mutex ) ;
2016-04-14 00:59:00 +02:00
2017-01-29 17:50:18 +01:00
auto & pair = g_vec [ get_type < T > ( ) ] ;
if ( ! pair . second )
2016-04-14 00:59:00 +02:00
{
ptr = std : : make_shared < Make > ( std : : forward < Args > ( args ) . . . ) ;
2017-01-29 17:50:18 +01:00
pair . first = id_manager : : typeinfo : : get_stop < T > ( ) ;
pair . second = ptr ;
}
else
{
return nullptr ;
2016-04-14 00:59:00 +02:00
}
}
2015-09-18 00:41:14 +02:00
2017-01-29 17:50:18 +01:00
id_manager : : on_init < T > : : func ( ptr . get ( ) , ptr ) ;
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)
2017-01-29 17:50:18 +01:00
template < typename T , typename Make = T , typename . . . Args >
2016-04-14 00:59:00 +02:00
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-04-14 00:59:00 +02:00
std : : shared_ptr < T > ptr ;
std : : shared_ptr < void > old ;
{
2017-01-25 18:50:30 +01:00
writer_lock lock ( id_manager : : g_mutex ) ;
2016-04-14 00:59:00 +02:00
2017-01-29 17:50:18 +01:00
auto & pair = g_vec [ get_type < T > ( ) ] ;
2016-04-14 00:59:00 +02:00
ptr = std : : make_shared < Make > ( std : : forward < Args > ( args ) . . . ) ;
2017-01-29 17:50:18 +01:00
old = std : : move ( pair . second ) ;
2016-04-14 00:59:00 +02:00
2017-01-29 17:50:18 +01:00
pair . first = id_manager : : typeinfo : : get_stop < T > ( ) ;
pair . second = ptr ;
2016-04-14 00:59:00 +02:00
}
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
2017-01-29 17:50:18 +01:00
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-04-14 00:59:00 +02:00
std : : shared_ptr < T > ptr ;
{
2017-01-25 18:50:30 +01:00
writer_lock lock ( id_manager : : g_mutex ) ;
2015-08-10 21:39:52 +02:00
2017-01-29 17:50:18 +01:00
auto & pair = g_vec [ get_type < T > ( ) ] ;
if ( ! pair . second )
2016-04-14 00:59:00 +02:00
{
ptr = provider ( ) ;
2015-08-10 21:39:52 +02:00
2017-01-29 17:50:18 +01:00
pair . first = id_manager : : typeinfo : : get_stop < T > ( ) ;
pair . second = ptr ;
}
else
{
return nullptr ;
2016-04-14 00:59:00 +02:00
}
}
2017-01-29 17:50:18 +01:00
id_manager : : on_init < T > : : func ( ptr . get ( ) , ptr ) ;
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)
2017-01-29 17:50:18 +01:00
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-04-14 00:59:00 +02:00
std : : shared_ptr < T > ptr ;
std : : shared_ptr < void > old ;
{
2017-01-25 18:50:30 +01:00
writer_lock lock ( id_manager : : g_mutex ) ;
2015-08-06 15:05:33 +02:00
2017-01-29 17:50:18 +01:00
auto & pair = g_vec [ get_type < T > ( ) ] ;
2016-04-14 00:59:00 +02:00
ptr = provider ( ) ;
2017-01-29 17:50:18 +01:00
old = std : : move ( pair . second ) ;
2015-08-06 15:05:33 +02:00
2017-01-29 17:50:18 +01:00
pair . first = id_manager : : typeinfo : : get_stop < T > ( ) ;
pair . second = ptr ;
2016-04-14 00:59:00 +02:00
}
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)
2017-01-29 17:50:18 +01:00
template < typename T , typename Make = T , typename . . . Args >
2016-04-14 00:59:00 +02:00
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-04-14 00:59:00 +02:00
std : : shared_ptr < T > ptr ;
2015-08-06 15:05:33 +02:00
{
2017-01-25 18:50:30 +01:00
writer_lock lock ( id_manager : : g_mutex ) ;
2016-04-14 00:59:00 +02:00
2017-01-29 17:50:18 +01:00
auto & pair = g_vec [ get_type < T > ( ) ] ;
if ( auto & old = pair . second )
2016-04-14 00:59:00 +02:00
{
2017-01-29 17:50:18 +01:00
return { old , static_cast < T * > ( old . get ( ) ) } ;
2016-04-14 00:59:00 +02:00
}
else
{
ptr = std : : make_shared < Make > ( std : : forward < Args > ( args ) . . . ) ;
2017-01-29 17:50:18 +01:00
pair . first = id_manager : : typeinfo : : get_stop < T > ( ) ;
pair . second = ptr ;
2016-04-14 00:59:00 +02:00
}
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-08-06 17:55:19 +02:00
2015-11-26 09:06:29 +01:00
// Check whether the object exists
2017-01-29 17:50:18 +01:00
template < typename T , typename Get = T >
2017-01-25 01:45:36 +01:00
static inline explicit_bool_t check ( )
2015-08-06 17:55:19 +02:00
{
2017-01-25 18:50:30 +01:00
reader_lock lock ( id_manager : : g_mutex ) ;
2015-08-06 17:55:19 +02:00
2017-01-29 17:50:18 +01:00
return g_vec [ get_type < T > ( ) ] . second ! = nullptr ;
2016-04-14 00:59:00 +02:00
}
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)
2017-01-29 17:50:18 +01:00
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
{
2017-01-25 18:50:30 +01:00
reader_lock lock ( id_manager : : g_mutex ) ;
2016-04-14 00:59:00 +02:00
2017-01-29 17:50:18 +01:00
auto & ptr = g_vec [ get_type < T > ( ) ] . second ;
2015-11-26 09:06:29 +01:00
2017-01-29 17:50:18 +01:00
return { ptr , static_cast < T * > ( ptr . get ( ) ) } ;
2016-04-14 00:59:00 +02:00
}
2015-11-26 09:06:29 +01:00
// Delete the object
2017-01-29 17:50:18 +01:00
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 18:50:30 +01:00
std : : shared_ptr < void > ptr ;
{
writer_lock lock ( id_manager : : g_mutex ) ;
2017-01-29 17:50:18 +01:00
ptr = std : : move ( g_vec [ get_type < T > ( ) ] . second ) ;
2017-01-25 18:50:30 +01:00
}
2017-01-29 17:50:18 +01:00
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
2017-01-29 17:50:18 +01:00
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 18:50:30 +01:00
std : : shared_ptr < void > ptr ;
{
writer_lock lock ( id_manager : : g_mutex ) ;
2017-01-29 17:50:18 +01:00
ptr = std : : move ( g_vec [ get_type < T > ( ) ] . second ) ;
2017-01-25 18:50:30 +01:00
}
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
}
2017-01-29 17:50:18 +01:00
return { ptr , static_cast < T * > ( ptr . get ( ) ) } ;
2015-08-06 17:55:19 +02:00
}
2016-04-14 00:59:00 +02:00
} ;