Use 'if constexpr ()' instead of tag dispatch.

This commit is contained in:
John Preston 2017-09-29 13:55:25 +03:00
parent 5cc7cb1d85
commit ea0f6b9a12
5 changed files with 78 additions and 176 deletions

View File

@ -187,29 +187,14 @@ optional_wrap_once_t<Type> make_optional(Type &&value) {
return optional_wrap_once_t<Type> { std::forward<Type>(value) };
}
template <typename Type, typename Method>
inline auto optional_chain(
const optional<Type> &value,
Method &method,
std::false_type)
-> optional_chain_result_t<decltype(method(*value))> {
return value ? make_optional(method(*value)) : none;
}
template <typename Type, typename Method>
inline auto optional_chain(
const optional<Type> &value,
Method &method,
std::true_type)
-> optional_chain_result_t<decltype(method(*value))> {
return value ? (method(*value), true) : false;
}
template <typename Type, typename Method>
inline auto operator|(const optional<Type> &value, Method method)
-> optional_chain_result_t<decltype(method(*value))> {
using is_void_return = std::is_same<decltype(method(*value)), void>;
return optional_chain(value, method, is_void_return {});
if constexpr (std::is_same_v<decltype(method(*value)), void>) {
return value ? (method(*value), true) : false;
} else {
return value ? make_optional(method(*value)) : none;
}
}
} // namespace base

View File

@ -43,25 +43,16 @@ inline span<const char> make_span(const QByteArray &cont) {
#endif // OS_MAC_OLD
namespace base {
namespace internal {
template <typename D, typename T>
inline constexpr D up_cast_helper(std::true_type, T object) {
return object;
}
template <typename D, typename T>
inline constexpr D up_cast_helper(std::false_type, T object) {
return nullptr;
}
} // namespace internal
template <typename D, typename T>
inline constexpr D up_cast(T object) {
using DV = std::decay_t<decltype(*D())>;
using TV = std::decay_t<decltype(*T())>;
return internal::up_cast_helper<D>(std::integral_constant<bool, std::is_base_of<DV, TV>::value || std::is_same<DV, TV>::value>(), object);
if constexpr (std::is_base_of_v<DV, TV>) {
return object;
} else {
return nullptr;
}
}
template <typename Container, typename T>

View File

@ -257,16 +257,6 @@ template <typename ...Args>
constexpr bool combine_producers_with_mapper_v
= combine_producers_with_mapper<Args...>::value;
template <
typename ...Values,
typename ...Errors,
typename ...Generators>
inline decltype(auto) combine_helper(
std::true_type,
producer<Values, Errors, Generators> &&...producers) {
return combine_implementation(std::move(producers)...);
}
template <typename ...Producers, std::size_t ...I>
inline decltype(auto) combine_call(
std::index_sequence<I...>,
@ -275,18 +265,6 @@ inline decltype(auto) combine_call(
argument_mapper<I>::call(std::move(producers)...)...);
}
template <typename ...Args>
inline decltype(auto) combine_helper(
std::false_type,
Args &&...args) {
constexpr auto kProducersCount = sizeof...(Args) - 1;
return combine_call(
std::make_index_sequence<kProducersCount>(),
std::forward<Args>(args)...)
| map(argument_mapper<kProducersCount>::call(
std::forward<Args>(args)...));
}
} // namespace details
template <
@ -295,9 +273,18 @@ template <
details::combine_just_producers_v<Args...>
|| details::combine_producers_with_mapper_v<Args...>>>
inline decltype(auto) combine(Args &&...args) {
return details::combine_helper(
details::combine_just_producers<Args...>(),
std::forward<Args>(args)...);
if constexpr (details::combine_just_producers_v<Args...>) {
return details::combine_implementation(std::move(args)...);
} else if constexpr (details::combine_producers_with_mapper_v<Args...>) {
constexpr auto kProducersCount = sizeof...(Args) - 1;
return details::combine_call(
std::make_index_sequence<kProducersCount>(),
std::forward<Args>(args)...)
| map(details::argument_mapper<kProducersCount>::call(
std::forward<Args>(args)...));
} else {
static_assert(false_(args...), "Bad combine() call.");
}
}
namespace details {

View File

@ -86,6 +86,10 @@ struct is_type_erased_handlers<type_erased_handlers<Value, Error>>
: std::true_type {
};
template <typename Handlers>
constexpr bool is_type_erased_handlers_v
= is_type_erased_handlers<Handlers>::value;
template <typename Value, typename Error, typename OnNext, typename OnError, typename OnDone>
class consumer_handlers final
: public type_erased_handlers<Value, Error> {
@ -285,7 +289,8 @@ namespace details {
template <typename Value, typename Error, typename Handlers>
class consumer_base {
using is_type_erased = is_type_erased_handlers<Handlers>;
static constexpr bool is_type_erased
= is_type_erased_handlers_v<Handlers>;
public:
template <
@ -345,44 +350,22 @@ private:
mutable std::shared_ptr<Handlers> _handlers;
bool handlers_put_next(Value &&value, std::true_type) const {
return _handlers->put_next(std::move(value));
bool handlers_put_next(Value &&value) const {
if constexpr (is_type_erased) {
return _handlers->put_next(std::move(value));
} else {
return _handlers->Handlers::put_next(std::move(value));
}
}
bool handlers_put_next_copy(
const Value &value,
std::true_type) const {
return _handlers->put_next_copy(value);
bool handlers_put_next_copy(const Value &value) const {
if constexpr (is_type_erased) {
return _handlers->put_next_copy(value);
} else {
return _handlers->Handlers::put_next_copy(value);
}
}
void handlers_put_error(Error &&error, std::true_type) const {
return std::exchange(_handlers, nullptr)->put_error(std::move(error));
}
void handlers_put_error_copy(
const Error &error,
std::true_type) const {
return std::exchange(_handlers, nullptr)->put_error_copy(error);
}
void handlers_put_done(std::true_type) const {
return std::exchange(_handlers, nullptr)->put_done();
}
bool handlers_put_next(Value &&value, std::false_type) const {
return _handlers->Handlers::put_next(std::move(value));
}
bool handlers_put_next_copy(
const Value &value,
std::false_type) const {
return _handlers->Handlers::put_next_copy(value);
}
void handlers_put_error(Error &&error, std::false_type) const {
return std::exchange(_handlers, nullptr)->Handlers::put_error(std::move(error));
}
void handlers_put_error_copy(
const Error &error,
std::false_type) const {
return std::exchange(_handlers, nullptr)->Handlers::put_error_copy(error);
}
void handlers_put_done(std::false_type) const {
return std::exchange(_handlers, nullptr)->Handlers::put_done();
std::shared_ptr<Handlers> take_handlers() const {
return std::exchange(_handlers, nullptr);
}
template <
@ -408,7 +391,7 @@ template <typename Value, typename Error, typename Handlers>
inline bool consumer_base<Value, Error, Handlers>::put_next(
Value &&value) const {
if (_handlers) {
if (handlers_put_next(std::move(value), is_type_erased())) {
if (handlers_put_next(std::move(value))) {
return true;
}
_handlers = nullptr;
@ -420,7 +403,7 @@ template <typename Value, typename Error, typename Handlers>
inline bool consumer_base<Value, Error, Handlers>::put_next_copy(
const Value &value) const {
if (_handlers) {
if (handlers_put_next_copy(value, is_type_erased())) {
if (handlers_put_next_copy(value)) {
return true;
}
_handlers = nullptr;
@ -432,7 +415,11 @@ template <typename Value, typename Error, typename Handlers>
inline void consumer_base<Value, Error, Handlers>::put_error(
Error &&error) const {
if (_handlers) {
handlers_put_error(std::move(error), is_type_erased());
if constexpr (is_type_erased) {
take_handlers()->put_error(std::move(error));
} else {
take_handlers()->Handlers::put_error(std::move(error));
}
}
}
@ -440,14 +427,22 @@ template <typename Value, typename Error, typename Handlers>
inline void consumer_base<Value, Error, Handlers>::put_error_copy(
const Error &error) const {
if (_handlers) {
handlers_put_error_copy(error, is_type_erased());
if constexpr (is_type_erased) {
take_handlers()->put_error_copy(error);
} else {
take_handlers()->Handlers::put_error_copy(error);
}
}
}
template <typename Value, typename Error, typename Handlers>
inline void consumer_base<Value, Error, Handlers>::put_done() const {
if (_handlers) {
handlers_put_done(is_type_erased());
if constexpr (is_type_erased) {
take_handlers()->put_done();
} else {
take_handlers()->Handlers::put_done();
}
}
}

View File

@ -99,54 +99,19 @@ struct is_callable<Method, Arg>
template <typename Method, typename ...Args>
constexpr bool is_callable_v = is_callable<Method, Args...>::value;
enum class CallableArgTag {
Plain,
Tuple,
Empty,
};
template <CallableArgTag Arg>
using callable_arg_tag = std::integral_constant<CallableArgTag, Arg>;
template <typename Method, typename Arg>
inline decltype(auto) callable_helper(
Method &&method,
Arg &&arg,
callable_arg_tag<CallableArgTag::Plain>) {
return std::forward<Method>(method)(std::forward<Arg>(arg));
}
template <typename Method, typename Arg>
inline decltype(auto) callable_helper(
Method &&method,
Arg &&arg,
callable_arg_tag<CallableArgTag::Tuple>) {
return std::apply(
std::forward<Method>(method),
std::forward<Arg>(arg));
}
template <typename Method, typename Arg>
inline decltype(auto) callable_helper(
Method &&method,
Arg &&,
callable_arg_tag<CallableArgTag::Empty>) {
return std::forward<Method>(method)();
}
template <typename Method, typename Arg>
inline decltype(auto) callable_invoke(Method &&method, Arg &&arg) {
// #TODO if constexpr
constexpr auto kTag = is_callable_plain_v<Method, Arg>
? CallableArgTag::Plain
: is_callable_tuple_v<Method, Arg>
? CallableArgTag::Tuple
: is_callable_v<Method>
? CallableArgTag::Empty
: throw "Bad callable_invoke instance.";
return callable_helper(
std::forward<Method>(method),
std::forward<Arg>(arg),
callable_arg_tag<kTag>());
if constexpr (is_callable_plain_v<Method, Arg>) {
return std::forward<Method>(method)(std::forward<Arg>(arg));
} else if constexpr (is_callable_tuple_v<Method, Arg>) {
return std::apply(
std::forward<Method>(method),
std::forward<Arg>(arg));
} else if constexpr (is_callable_v<Method>) {
return std::forward<Method>(method)();
} else {
static_assert(false_(method, arg), "Bad callable_invoke() call.");
}
}
template <typename Method, typename Arg>
@ -167,39 +132,18 @@ constexpr bool allows_const_ref_v = (sizeof(test_allows_const_ref(
std::declval<Method>(),
std::declval<Arg>())) == sizeof(true_t));
template <typename Method, typename Arg>
struct allows_const_ref
: std::bool_constant<
allows_const_ref_v<Method, Arg>> {
};
template <typename Method, typename Arg>
inline decltype(auto) const_ref_call_helper(
Method &&method,
const Arg &arg,
std::true_type) {
return callable_invoke(std::forward<Method>(method), arg);
}
template <typename Method, typename Arg>
inline decltype(auto) const_ref_call_helper(
Method &&method,
const Arg &arg,
std::false_type) {
auto copy = arg;
return callable_invoke(
std::forward<Method>(method),
std::move(copy));
}
template <typename Method, typename Arg>
inline decltype(auto) const_ref_call_invoke(
Method &&method,
const Arg &arg) {
return const_ref_call_helper(
std::forward<Method>(method),
arg,
allows_const_ref<Method, Arg>());
if constexpr (allows_const_ref_v<Method, Arg>) {
return callable_invoke(std::forward<Method>(method), arg);
} else {
auto copy = arg;
return callable_invoke(
std::forward<Method>(method),
std::move(copy));
}
}
} // namespace details