Files
core_misc/tjp/core/initializer/Initializer.hpp
Timothy Prepscius fa54be052a flatten 20260225
2026-02-25 12:39:24 -05:00

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