New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve runtime performance and clang++ compatibility #2
Changes from all commits
dfd12e9
52d53d7
0811164
8335d91
bf9f111
e71fcc8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
cmake_minimum_required(VERSION 2.6) | ||
project(kangaru-example) | ||
|
||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") | ||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Werror") | ||
add_executable(kangaru-example example/kangaru-example.cpp) | ||
include_directories(${PROJECT_SOURCE_DIR}/include) | ||
|
||
install(TARGETS kangaru-example RUNTIME DESTINATION bin) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,13 @@ | |
#include <type_traits> | ||
#include <tuple> | ||
|
||
#if defined(__clang__) | ||
#pragma clang diagnostic push | ||
#pragma clang diagnostic ignored "-Wc++98-compat" | ||
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" | ||
#pragma clang diagnostic ignored "-Wweak-vtables" | ||
#endif // CLANG | ||
|
||
namespace kgr { | ||
|
||
template<typename... Types> | ||
|
@@ -43,15 +50,15 @@ struct seq_gen<0, S...> { | |
}; | ||
|
||
|
||
struct Holder { | ||
virtual ~Holder() { | ||
|
||
} | ||
class Holder { | ||
public: | ||
virtual ~Holder() = default; | ||
}; | ||
|
||
template<typename T> | ||
struct InstanceHolder : Holder { | ||
explicit InstanceHolder(std::shared_ptr<T> instance) : _instance{instance} {} | ||
class InstanceHolder final : public Holder { | ||
public: | ||
explicit InstanceHolder(std::shared_ptr<T> instance) : _instance{std::move(instance)} {} | ||
|
||
std::shared_ptr<T> getInstance() const { | ||
return _instance; | ||
|
@@ -62,15 +69,15 @@ struct InstanceHolder : Holder { | |
}; | ||
|
||
template<typename T, typename... Args> | ||
struct CallbackHolder : Holder { | ||
class CallbackHolder final : public Holder { | ||
public: | ||
using callback_t = std::function<std::shared_ptr<T>(Args...)>; | ||
|
||
explicit CallbackHolder(callback_t callback) : _callback{callback} {} | ||
explicit CallbackHolder(callback_t callback) : _callback{std::move(callback)} {} | ||
|
||
callback_t getCallback() const { | ||
return _callback; | ||
std::shared_ptr<T> operator ()(Args... args) { | ||
return _callback(args...); | ||
} | ||
|
||
private: | ||
callback_t _callback; | ||
}; | ||
|
@@ -81,10 +88,12 @@ std::unique_ptr<T> make_unique( Args&& ...args ) | |
return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) ); | ||
} | ||
|
||
template <typename T> void type_id() {} | ||
using type_id_fn = void(*)(); | ||
|
||
} // namespace detail | ||
|
||
struct Container : std::enable_shared_from_this<Container> { | ||
private: | ||
class Container : public std::enable_shared_from_this<Container> { | ||
template<typename Condition, typename T = void> using enable_if = detail::enable_if_t<Condition::value, T>; | ||
template<typename Condition, typename T = void> using disable_if = detail::enable_if_t<!Condition::value, T>; | ||
template<typename T> using is_service_single = std::is_base_of<Single, Service<T>>; | ||
|
@@ -97,43 +106,50 @@ struct Container : std::enable_shared_from_this<Container> { | |
template<int S, typename T> using parent_element = typename std::tuple_element<S, parent_types<T>>::type; | ||
template<int S, typename Tuple> using tuple_element = typename std::tuple_element<S, Tuple>::type; | ||
using holder_ptr = std::unique_ptr<detail::Holder>; | ||
|
||
using holder_cont = std::unordered_map<detail::type_id_fn, holder_ptr>; | ||
public: | ||
Container() = default; | ||
Container(const Container &) = default; | ||
Container(Container &&) = default; | ||
Container& operator =(const Container &) = default; | ||
Container& operator =(Container &&) = default; | ||
virtual ~Container() = default; | ||
|
||
template<typename T> | ||
void instance(std::shared_ptr<T> service) { | ||
static_assert(is_service_single<T>::value, "instance only accept Single Service instance."); | ||
call_save_instance(service, tuple_seq<parent_types<T>>()); | ||
|
||
call_save_instance(std::move(service), tuple_seq<parent_types<T>>{}); | ||
} | ||
|
||
template<typename T> | ||
void instance() { | ||
static_assert(is_service_single<T>::value, "instance only accept Single Service instance."); | ||
|
||
instance(make_service<T>()); | ||
} | ||
|
||
template<typename T, disable_if<is_abstract<T>>..., disable_if<is_base_of_container<T>>...> | ||
template<typename T, disable_if<is_abstract<T>>* = nullptr, disable_if<is_base_of_container<T>>* = nullptr> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
std::shared_ptr<T> service() { | ||
return get_service<T>(); | ||
} | ||
|
||
template<typename T, enable_if<is_container<T>>...> | ||
template<typename T, enable_if<is_container<T>>* = nullptr> | ||
std::shared_ptr<T> service() { | ||
return shared_from_this(); | ||
} | ||
|
||
template<typename T, disable_if<is_container<T>>..., enable_if<is_base_of_container<T>>...> | ||
template<typename T, disable_if<is_container<T>>* = nullptr, enable_if<is_base_of_container<T>>* = nullptr> | ||
std::shared_ptr<T> service() { | ||
return std::dynamic_pointer_cast<T>(shared_from_this()); | ||
} | ||
|
||
template<typename T, enable_if<is_abstract<T>>...> | ||
template<typename T, enable_if<is_abstract<T>>* = nullptr> | ||
std::shared_ptr<T> service() { | ||
auto it = _services.find(typeid(T).name()); | ||
auto it = _services.find(&detail::template type_id<T>); | ||
|
||
if (it != _services.end()) { | ||
auto holder = dynamic_cast<detail::InstanceHolder<T>*>(it->second.get()); | ||
auto holder = static_cast<detail::InstanceHolder<T>*>(it->second.get()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
if (holder) { | ||
return holder->getInstance(); | ||
|
@@ -152,17 +168,17 @@ struct Container : std::enable_shared_from_this<Container> { | |
virtual void init(){} | ||
|
||
private: | ||
template<typename T, enable_if<is_service_single<T>>...> | ||
template<typename T, enable_if<is_service_single<T>>* = nullptr> | ||
std::shared_ptr<T> get_service() { | ||
auto it = _services.find(typeid(T).name()); | ||
auto it = _services.find(&detail::template type_id<T>); | ||
|
||
if (it == _services.end()) { | ||
auto service = make_service<T>(); | ||
instance(service); | ||
|
||
return service; | ||
} else { | ||
auto holder = dynamic_cast<detail::InstanceHolder<T>*>(it->second.get()); | ||
auto holder = static_cast<detail::InstanceHolder<T>*>(it->second.get()); | ||
|
||
if (holder) { | ||
return holder->getInstance(); | ||
|
@@ -171,14 +187,14 @@ struct Container : std::enable_shared_from_this<Container> { | |
return {}; | ||
} | ||
|
||
template<typename T, disable_if<is_service_single<T>>...> | ||
template<typename T, disable_if<is_service_single<T>>* = nullptr> | ||
std::shared_ptr<T> get_service() { | ||
return make_service<T>(); | ||
} | ||
|
||
template<typename T, int ...S> | ||
void call_save_instance(std::shared_ptr<T> service, detail::seq<S...>) { | ||
save_instance<T, parent_element<S, T>...>(service); | ||
save_instance<T, parent_element<S, T>...>(std::move(service)); | ||
} | ||
|
||
template<typename Tuple, int ...S> | ||
|
@@ -187,13 +203,13 @@ struct Container : std::enable_shared_from_this<Container> { | |
} | ||
|
||
template<typename T, typename Tuple, int ...S> | ||
std::shared_ptr<T> callback_make_service(detail::seq<S...> seq, Tuple dependencies) const { | ||
auto it = _callbacks.find(typeid(T).name()); | ||
std::shared_ptr<T> callback_make_service(detail::seq<S...>, Tuple dependencies) const { | ||
auto it = _callbacks.find(&detail::template type_id<T>); | ||
|
||
if (it != _callbacks.end()) { | ||
auto holder = dynamic_cast<detail::CallbackHolder<T, tuple_element<S, Tuple>...>*>(it->second.get()); | ||
auto holder = static_cast<detail::CallbackHolder<T, tuple_element<S, Tuple>...>*>(it->second.get()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment for InstanceHolder. |
||
if (holder) { | ||
return holder->getCallback()(std::get<S>(dependencies)...); | ||
return (*holder)(std::get<S>(dependencies)...); | ||
} | ||
} | ||
return {}; | ||
|
@@ -219,21 +235,21 @@ struct Container : std::enable_shared_from_this<Container> { | |
template<typename T, typename ...Others> | ||
detail::enable_if_t<(sizeof...(Others) > 0), void> save_instance(std::shared_ptr<T> service) { | ||
save_instance<T>(service); | ||
save_instance<Others...>(service); | ||
save_instance<Others...>(std::move(service)); | ||
} | ||
|
||
template<typename T> | ||
void save_instance (std::shared_ptr<T> service) { | ||
_services[typeid(T).name()] = detail::make_unique<detail::InstanceHolder<T>>(service); | ||
_services[&detail::template type_id<T>] = detail::make_unique<detail::InstanceHolder<T>>(std::move(service)); | ||
} | ||
|
||
template<typename T, typename Tuple, int ...S, typename U> | ||
void save_callback (detail::seq<S...>, U callback) { | ||
_callbacks[typeid(T).name()] = detail::make_unique<detail::CallbackHolder<T, std::shared_ptr<tuple_element<S, Tuple>>...>>(callback); | ||
_callbacks[&detail::template type_id<T>] = detail::make_unique<detail::CallbackHolder<T, std::shared_ptr<tuple_element<S, Tuple>>...>>(callback); | ||
} | ||
|
||
std::unordered_map<std::string, holder_ptr> _callbacks; | ||
std::unordered_map<std::string, holder_ptr> _services; | ||
holder_cont _callbacks; | ||
holder_cont _services; | ||
}; | ||
|
||
template<typename T = Container, typename ...Args> | ||
|
@@ -247,3 +263,7 @@ std::shared_ptr<T> make_container(Args&& ...args) { | |
} | ||
|
||
} // namespace kgr | ||
|
||
#if defined(__clang__) | ||
#pragma clang diagnostic pop | ||
#endif // CLANG |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is needed to remove clang warnings for inlined virtual destructors.