memgraph/utils/ioc/container.hpp
2015-12-07 21:51:55 +01:00

98 lines
2.0 KiB
C++

#pragma once
#include <cassert>
#include <memory>
#include <vector>
#include <map>
namespace ioc
{
class Container
{
struct Holdable
{
using uptr = std::unique_ptr<Holdable>;
Holdable() = default;
virtual ~Holdable() = default;
};
template <class T>
struct Item : public Holdable
{
virtual std::shared_ptr<T> get() = 0;
};
template <class T>
struct Instance : public Item<T>
{
Instance(std::shared_ptr<T> item) : item(std::move(item)) {}
Instance(std::shared_ptr<T>&& item) : item(item) {}
std::shared_ptr<T> get() override
{
assert(item != nullptr);
return item;
}
std::shared_ptr<T> item;
};
template <class T>
struct Creator : public Item<T>
{
using func = std::function<std::shared_ptr<T>()>;
Creator(func&& f) : f(f) {}
std::shared_ptr<T> get() override
{
return f();
}
func f;
};
public:
template <class T>
std::shared_ptr<T> resolve()
{
auto it = items.find(key<T>());
assert(it != items.end());
// try to cast Holdable* to Item<T>*
auto item = dynamic_cast<Item<T>*>(it->second.get());
assert(item != nullptr);
return item->get();
}
template <class T, class... Deps, class... Args>
std::shared_ptr<T> singleton(Args&&... args)
{
auto item = std::make_shared<T>(resolve<Deps>()..., args...);
items.emplace(key<T>(), Holdable::uptr(new Instance<T>(item)));
return item;
}
template <class T>
void factory(typename Creator<T>::func&& f)
{
items[key<T>()] = std::move(Holdable::uptr(
new Creator<T>(std::forward<typename Creator<T>::func>(f))
));
}
private:
std::map<std::string, Holdable::uptr> items;
template <class T>
std::string key()
{
return typeid(T).name();
}
};
}