239 lines
5.0 KiB
C++
239 lines
5.0 KiB
C++
// TJP COPYRIGHT HEADER
|
|
|
|
#pragma once
|
|
|
|
#include "Initializer.h"
|
|
#include <functional>
|
|
#include <vector>
|
|
#include <tjp/core/assert/debug_assert.h>
|
|
#include <tjp/core/algorithm/vector_erase_if_value.hpp>
|
|
#include <tjp/core/ptr/Ptr.hpp>
|
|
#include <tjp/core/rtti/RTTI.hpp>
|
|
|
|
#include <string>
|
|
#include <map>
|
|
|
|
namespace tjp {
|
|
namespace core {
|
|
namespace initializer {
|
|
|
|
typedef std::string ID;
|
|
|
|
typedef std::function<void(void *)> InitializerFunction;
|
|
typedef std::pair<type_index, InitializerFunction> KeyedInitializerFunction;
|
|
typedef std::map<type_index, std::vector<KeyedInitializerFunction>> InitializersMap;
|
|
|
|
struct Initializers
|
|
{
|
|
InitializersMap map;
|
|
|
|
Initializers(InitializersMap &&map_) :
|
|
map(map_) {}
|
|
|
|
Initializers merge(const Initializers &base)
|
|
{
|
|
auto result = Initializers(InitializersMap(map));
|
|
|
|
for (auto &[fromI, fromV] : base.map)
|
|
{
|
|
auto &toV = result.map[fromI];
|
|
|
|
for (auto &fromKF: fromV)
|
|
{
|
|
auto contains = false;
|
|
|
|
auto &fromK = fromKF.first;
|
|
for (auto &toKF : toV)
|
|
{
|
|
auto &toK = toKF.first;
|
|
|
|
if (fromK == toK)
|
|
{
|
|
contains = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!contains)
|
|
toV.push_back(fromKF);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Initializers replace(const Initializers &base)
|
|
{
|
|
auto result = Initializers(InitializersMap(map));
|
|
|
|
for (auto &[fromI, fromV] : base.map)
|
|
{
|
|
auto &toV = result.map[fromI];
|
|
|
|
for (auto &fromKF: fromV)
|
|
{
|
|
auto &fromK = fromKF.first;
|
|
vector_erase_if_value(toV, [&](auto &v) { return v.first == fromK; });
|
|
toV.push_back(fromKF);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
} ;
|
|
|
|
struct Token {};
|
|
|
|
struct Initializer;
|
|
struct InitializerChain;
|
|
|
|
// SFINAE test
|
|
template <typename T>
|
|
class has_setInitializer
|
|
{
|
|
private:
|
|
typedef char true_type;
|
|
typedef long false_type;
|
|
|
|
template <typename C> static false_type& test(...);
|
|
template <typename C> static true_type& test( decltype(&C::setInitializer) ) ;
|
|
|
|
|
|
public:
|
|
enum { value = sizeof(test<T>(0)) == sizeof(true_type) };
|
|
};
|
|
|
|
template<typename T, typename std::enable_if<has_setInitializer<T>::value, T>::type* = nullptr>
|
|
void chain_initializer(Initializer *initializer, T *t);
|
|
|
|
template<typename T, typename std::enable_if<!has_setInitializer<T>::value, T>::type* = nullptr>
|
|
void chain_initializer(Initializer *initializer, T *t) { }
|
|
|
|
struct Initializer;
|
|
|
|
//void deallocate(Initializer *);
|
|
|
|
struct Catalog : StrongThis<Catalog>
|
|
{
|
|
std::map<ID, StrongPtr<Initializer>> initializerById;
|
|
|
|
StrongPtr<Initializer> get(const ID &id);
|
|
|
|
void put(const ID &id, const StrongPtr<Initializer> &initializer);
|
|
|
|
template<typename T, typename U, typename ... Args>
|
|
StrongPtr<T> construct_with(const U &id, Args&& ...args);
|
|
} ;
|
|
|
|
|
|
struct Initializer : StrongThis<Initializer>
|
|
{
|
|
WeakPtr<Catalog> catalog;
|
|
std::string id;
|
|
Initializers initializers;
|
|
|
|
Initializer(Initializers &&initializers_);
|
|
|
|
StrongPtr<Initializer> getInitializer(const ID &id);
|
|
|
|
template<typename R>
|
|
void initialize(R *r)
|
|
{
|
|
chain_initializer(this, r);
|
|
|
|
auto type = type_id<R>();
|
|
|
|
auto i = initializers.map.find(type);
|
|
if (i != initializers.map.end())
|
|
{
|
|
for (auto &[key, initializer]: i->second)
|
|
{
|
|
initializer(r);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename R>
|
|
void initialize_reflect(R *r)
|
|
{
|
|
r->initialize_with(this);
|
|
}
|
|
|
|
template<typename T, typename ... Args>
|
|
StrongPtr<T> construct(Args&& ...args)
|
|
{
|
|
auto p = strong<T>(Token{}, std::forward<Args>(args)...);
|
|
initialize_reflect(ptr_of(p));
|
|
return p;
|
|
}
|
|
|
|
template<typename T, typename U, typename ... Args>
|
|
StrongPtr<T> construct_with(const U &id, Args&& ...args)
|
|
{
|
|
auto initializer = getInitializer(ID(id));
|
|
debug_assert(initializer);
|
|
return initializer->construct<T>(std::forward<Args>(args)...);
|
|
}
|
|
} ;
|
|
|
|
struct InitializerChain
|
|
{
|
|
StrongPtr<Initializer> initializer;
|
|
|
|
template<typename T>
|
|
void initialize(T *t)
|
|
{
|
|
debug_assert(initializer);
|
|
initializer->initialize_reflect(t);
|
|
}
|
|
|
|
template<typename T>
|
|
void initialize(const StrongPtr<T> &t)
|
|
{
|
|
debug_assert(initializer);
|
|
initializer->initialize_reflect(ptr_of(t));
|
|
}
|
|
|
|
void setInitializer(const StrongPtr<Initializer> &initializer_)
|
|
{
|
|
initializer = initializer_;
|
|
}
|
|
|
|
template<typename T, typename ... Args>
|
|
StrongPtr<T> construct(Args&& ...args)
|
|
{
|
|
return initializer->construct<T>(std::forward<Args>(args)...);
|
|
}
|
|
|
|
template<typename T, typename U, typename ... Args>
|
|
StrongPtr<T> construct_with(const U &id, Args&& ...args)
|
|
{
|
|
return initializer->construct_with<T>(id, std::forward<Args>(args)...);
|
|
}
|
|
|
|
std::string &initializer_id()
|
|
{
|
|
return initializer->id;
|
|
}
|
|
} ;
|
|
|
|
template<typename T, typename U, typename ... Args>
|
|
StrongPtr<T> Catalog::construct_with(const U &id, Args&& ...args)
|
|
{
|
|
auto initializer = get(ID(id));
|
|
debug_assert(initializer);
|
|
return initializer->construct<T>(std::forward<Args>(args)...);
|
|
}
|
|
|
|
template<typename T, typename std::enable_if<has_setInitializer<T>::value, T>::type*>
|
|
void chain_initializer(Initializer *initializer, T *t)
|
|
{
|
|
t->setInitializer(strong_this(initializer));
|
|
}
|
|
|
|
|
|
} // namespace
|
|
} // namespace
|
|
} // namespace
|
|
|