Files
cpp-thirdparty/noarch/include/kangaru/generic.hpp
Bassem Girgis 81b4b9e273 Initial commit
2018-12-20 17:34:07 -06:00

102 lines
3.1 KiB
C++

#ifndef KGR_KANGARU_INCLUDE_KANGARU_GENERIC_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_GENERIC_HPP
#include "container.hpp"
#include "detail/injected.hpp"
#include "detail/traits.hpp"
namespace kgr {
namespace detail {
template<typename Generic, typename Type, typename = void>
struct GenericServiceDestruction {
~GenericServiceDestruction() {
static_cast<Generic&>(*this).instance().~Type();
}
};
template<typename Generic, typename Type>
struct GenericServiceDestruction<Generic, Type, enable_if_t<std::is_trivially_destructible<Type>::value>> {};
template<typename, typename> struct autocall_function;
} // namespace detail
template<typename CRTP, typename Type>
struct GenericService : detail::GenericServiceDestruction<GenericService<CRTP, Type>, Type> {
friend struct Container;
using Self = CRTP;
GenericService() = default;
GenericService(GenericService&& other) {
emplace(std::move(other.instance()));
}
GenericService& operator=(GenericService&& other) {
emplace(std::move(other.instance()));
return *this;
}
GenericService(const GenericService& other) {
emplace(other.instance());
}
GenericService& operator=(const GenericService& other) {
emplace(other.instance());
return *this;
}
template<typename... Args, detail::enable_if_t<detail::is_someway_constructible<Type, Args...>::value, int> = 0>
GenericService(in_place_t, Args&&... args) {
emplace(std::forward<Args>(args)...);
}
protected:
Type& instance() {
return *reinterpret_cast<Type*>(&_instance);
}
const Type& instance() const {
return *reinterpret_cast<const Type*>(&_instance);
}
private:
friend struct detail::GenericServiceDestruction<GenericService<CRTP, Type>, Type>;
template<typename, typename...> friend struct detail::has_emplace_helper;
template<typename, typename> friend struct detail::autocall_function;
template<typename... Args, detail::enable_if_t<std::is_constructible<Type, Args...>::value, int> = 0>
void emplace(Args&&... args) {
new (&_instance) Type(std::forward<Args>(args)...);
}
template<typename... Args, detail::enable_if_t<detail::is_only_brace_constructible<Type, Args...>::value, int> = 0>
void emplace(Args&&... args) {
new (&_instance) Type{std::forward<Args>(args)...};
}
template<typename F, typename... Ts>
void autocall(Inject<Ts>... others) {
CRTP::call(instance(), F::value, std::forward<Inject<Ts>>(others).forward()...);
}
template<typename F, template<typename> class Map>
void autocall(Inject<ContainerService> cs) {
autocall<Map, F>(detail::tuple_seq<detail::function_arguments_t<typename F::value_type>>{}, std::move(cs));
}
template<template<typename> class Map, typename F, std::size_t... S>
void autocall(detail::seq<S...>, Inject<ContainerService> cs) {
cs.forward().invoke<Map>([this](detail::function_argument_t<S, typename F::value_type>... args){
CRTP::call(instance(), F::value, std::forward<detail::function_argument_t<S, typename F::value_type>>(args)...);
});
}
detail::aligned_storage_t<sizeof(Type), alignof(Type)> _instance;
};
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_GENERIC_HPP