Skip to content

Instantly share code, notes, and snippets.

@lighth7015
Created March 16, 2019 23:26
Show Gist options
  • Save lighth7015/f65135562dfc8ddcd96eced347966485 to your computer and use it in GitHub Desktop.
Save lighth7015/f65135562dfc8ddcd96eced347966485 to your computer and use it in GitHub Desktop.
Auto-registration factory
#include <cassert>
#include <functional>
#include <iostream>
#include <memory>
#include <unordered_map>
#include <utility>
/**
* Portions of this code adapted from https://stackoverflow.com/a/42191109/201787
*/
template<class T, class F>
class InvokeApplyOnConstruction
{
public:
InvokeApplyOnConstruction()
{
F::template Register<T>();
}
};
/**
*
*/
template<class T, class F>
struct RegistrationInvoker {
static const InvokeApplyOnConstruction<T, F> _registrationInvoker;
};
template<class T, class F>
const InvokeApplyOnConstruction<T, F> RegistrationInvoker<T, F>::_registrationInvoker
= InvokeApplyOnConstruction<T, F>();
/**
* Classic Factory object allowing runtime registration
*/
template<class T, class TPRoduct = std::unique_ptr<T>>
struct ModuleRegistry
{
using Product = TPRoduct;
using Creator = std::function<Product()>;
static ModuleRegistry& Instance() // Singleton
{
static ModuleRegistry instance;
return instance;
}
void publish( std::size_t id, Creator creator )
{
if ( _collection.find(id) == std::end(_collection) ) {
_collection[id] = std::move(creator);
}
}
void publish( std::size_t id, std::size_t type_id, Creator creator )
{
assert( _collection.find(type_id) == std::end( _collection ));
printf( "id: %lx, type: %lx\n", id, type_id );
_mapping[id] = type_id;
_collection[type_id] = std::move(creator);
}
Product get( const std::size_t id ) const
{
const auto entry = _collection.find(id);
assert( entry != std::end( _collection ));
}
private:
ModuleRegistry() = default;
ModuleRegistry(const ModuleRegistry&) = delete;
std::unordered_map<std::size_t, std::size_t> _mapping;
std::unordered_map<std::size_t, Creator> _collection;
};
/**
*
*/
class Connection
{
public:
virtual void* get() const = 0;
virtual ~Connection() = default;
};
class ModuleBase
{
public:
virtual void get() const = 0;
virtual ~ModuleBase() = default;
};
/**
* Invoked by the generic auto-registration classes.
*/
struct RegisterConnectionInstance
{
template<typename T>
static void Register()
{
ModuleRegistry<Connection>::Instance()
.publish( T::id, [] { return std::make_unique<T>(); } );
}
};
struct RegisterModuleBaseInstance
{
template<typename T>
static void Register()
{
ModuleRegistry<ModuleBase>::Instance()
.publish( T::id, [] { return std::make_unique<T>(); });
}
};
////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived>
class ConnectionFactory : RegistrationInvoker<Derived, RegisterConnectionInstance>
{
public:
static const std::size_t id;
};
template<class Derived>
class ModuleFactory : RegistrationInvoker<Derived, RegisterModuleBaseInstance>
{
public:
static const std::size_t id;
};
template<class Derived>
const std::size_t ConnectionFactory<Derived>::id =
reinterpret_cast<std::size_t>( &RegistrationInvoker<Derived, RegisterConnectionInstance>::_registrationInvoker );
template<class Derived>
const std::size_t ModuleFactory<Derived>::id =
reinterpret_cast<std::size_t>( &RegistrationInvoker<Derived, RegisterModuleBaseInstance>::_registrationInvoker );
////////////////////////////////////////////////////////////////////////////////////////////////
// Derived types
////////////////////////////////////////////////////////////////////////////////////////////////
class ScriptRuntime: public ModuleBase
, public ModuleFactory<ScriptRuntime>
{
public:
ScriptRuntime() {
std::cout << "Init Scripting Environment" << std::endl;
}
void get() const override {
std::cout << "Return self." << std::endl;
}
};
class PosixConnection: public Connection
, public ConnectionFactory<PosixConnection>
{
public:
static const std::size_t type = Posix;
PosixConnection() {
std::cout << "Establish XCB connection" << std::endl;
}
void* get() const override {
std::cout << "XCB connection" << std::endl;
return nullptr;
}
};
int main()
{
const auto& factory =
ModuleRegistry<Connection>::Instance();
// Shouldn't create three instances of a PosixConnection.
factory.get( PosixConnection::id );
factory.get( PosixConnection::id );
factory.get( PosixConnection::id );
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment