update invoke impl and speedup unit tests compilation

This commit is contained in:
2018-12-16 13:11:36 +07:00
parent 7fd7117eb6
commit 7fd2f5f1c2
5 changed files with 265 additions and 332 deletions

View File

@@ -3,6 +3,7 @@ project(kari)
file(GLOB test_sources "*.cpp" "*.hpp")
add_executable(${PROJECT_NAME} ${test_sources})
set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD 14
CXX_STANDARD_REQUIRED YES

View File

@@ -23,7 +23,7 @@
[language]: https://en.wikipedia.org/wiki/C%2B%2B14
[license]: https://github.com/BlackMATov/kari.hpp/blob/master/LICENSE.md
[godbolt]: https://godbolt.org/g/XPBgjY
[wandbox]: https://wandbox.org/permlink/l6uHui1884zfQNa4
[wandbox]: https://wandbox.org/permlink/F6AVvcCHsoBztZ0w
[paypal]: https://www.paypal.me/matov
[kari]: https://github.com/BlackMATov/kari.hpp

9
catch_main.cpp Normal file
View File

@@ -0,0 +1,9 @@
/*******************************************************************************
* This file is part of the "https://github.com/BlackMATov/kari.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018 Matvey Cherevko
******************************************************************************/
#define CATCH_CONFIG_MAIN
#define CATCH_CONFIG_FAST_COMPILE
#include "catch.hpp"

174
kari.hpp
View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* This file is part of the "kari.hpp"
* This file is part of the "https://github.com/BlackMATov/kari.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018 Matvey Cherevko
******************************************************************************/
@@ -12,38 +12,43 @@
#include <functional>
#include <type_traits>
#define KARI_HPP_NOEXCEPT_RETURN(...) \
// -----------------------------------------------------------------------------
//
// https://github.com/BlackMATov/invoke.hpp
//
// -----------------------------------------------------------------------------
#define INVOKE_HPP_NOEXCEPT_RETURN(...) \
noexcept(noexcept(__VA_ARGS__)) { return __VA_ARGS__; }
#define KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(...) \
#define INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(...) \
noexcept(noexcept(__VA_ARGS__)) -> decltype (__VA_ARGS__) { return __VA_ARGS__; }
namespace kari
{
namespace detail
{
namespace std_ext
{
//
// void_t
//
namespace detail
namespace invoke_hpp
{
template < typename... Ts >
namespace impl
{
template < typename... Args >
struct make_void {
using type = void;
};
}
template < typename... Ts >
using void_t = typename detail::make_void<Ts...>::type;
template < typename... Args >
using void_t = typename impl::make_void<Args...>::type;
}
//
// is_reference_wrapper, is_reference_wrapper_v
// is_reference_wrapper
//
namespace detail
namespace invoke_hpp
{
namespace impl
{
template < typename T >
struct is_reference_wrapper_impl
@@ -56,16 +61,16 @@ namespace kari
template < typename T >
struct is_reference_wrapper
: detail::is_reference_wrapper_impl<std::remove_cv_t<T>> {};
template < typename T >
constexpr bool is_reference_wrapper_v = is_reference_wrapper<T>::value;
: impl::is_reference_wrapper_impl<std::remove_cv_t<T>> {};
}
//
// invoke
//
namespace detail
namespace invoke_hpp
{
namespace impl
{
//
// invoke_member_object_impl
@@ -77,7 +82,7 @@ namespace kari
typename std::enable_if_t<std::is_base_of<Base, std::decay_t<Derived>>::value, int> = 0
>
constexpr auto invoke_member_object_impl(F Base::* f, Derived&& ref)
KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
std::forward<Derived>(ref).*f)
template
@@ -86,7 +91,7 @@ namespace kari
typename std::enable_if_t<is_reference_wrapper<std::decay_t<RefWrap>>::value, int> = 0
>
constexpr auto invoke_member_object_impl(F Base::* f, RefWrap&& ref)
KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
ref.get().*f)
template
@@ -94,11 +99,11 @@ namespace kari
typename Base, typename F, typename Pointer,
typename std::enable_if_t<
!std::is_base_of<Base, std::decay_t<Pointer>>::value &&
!is_reference_wrapper_v<std::decay_t<Pointer>>
!is_reference_wrapper<std::decay_t<Pointer>>::value
, int> = 0
>
constexpr auto invoke_member_object_impl(F Base::* f, Pointer&& ptr)
KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
(*std::forward<Pointer>(ptr)).*f)
//
@@ -111,7 +116,7 @@ namespace kari
typename std::enable_if_t<std::is_base_of<Base, std::decay_t<Derived>>::value, int> = 0
>
constexpr auto invoke_member_function_impl(F Base::* f, Derived&& ref, Args&&... args)
KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
(std::forward<Derived>(ref).*f)(std::forward<Args>(args)...))
template
@@ -120,7 +125,7 @@ namespace kari
typename std::enable_if_t<is_reference_wrapper<std::decay_t<RefWrap>>::value, int> = 0
>
constexpr auto invoke_member_function_impl(F Base::* f, RefWrap&& ref, Args&&... args)
KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
(ref.get().*f)(std::forward<Args>(args)...))
template
@@ -128,11 +133,11 @@ namespace kari
typename Base, typename F, typename Pointer, typename... Args,
typename std::enable_if_t<
!std::is_base_of<Base, std::decay_t<Pointer>>::value &&
!is_reference_wrapper_v<std::decay_t<Pointer>>
!is_reference_wrapper<std::decay_t<Pointer>>::value
, int> = 0
>
constexpr auto invoke_member_function_impl(F Base::* f, Pointer&& ptr, Args&&... args)
KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
((*std::forward<Pointer>(ptr)).*f)(std::forward<Args>(args)...))
}
@@ -142,7 +147,7 @@ namespace kari
typename std::enable_if_t<!std::is_member_pointer<std::decay_t<F>>::value, int> = 0
>
constexpr auto invoke(F&& f, Args&&... args)
KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
std::forward<F>(f)(std::forward<Args>(args)...))
template
@@ -151,8 +156,8 @@ namespace kari
typename std::enable_if_t<std::is_member_object_pointer<std::decay_t<F>>::value, int> = 0
>
constexpr auto invoke(F&& f, T&& t)
KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(
detail::invoke_member_object_impl(std::forward<F>(f), std::forward<T>(t)))
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
impl::invoke_member_object_impl(std::forward<F>(f), std::forward<T>(t)))
template
<
@@ -160,14 +165,17 @@ namespace kari
typename std::enable_if_t<std::is_member_function_pointer<std::decay_t<F>>::value, int> = 0
>
constexpr auto invoke(F&& f, Args&&... args)
KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(
detail::invoke_member_function_impl(std::forward<F>(f), std::forward<Args>(args)...))
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
impl::invoke_member_function_impl(std::forward<F>(f), std::forward<Args>(args)...))
}
//
// invoke_result, invoke_result_t
// invoke_result
//
namespace detail
namespace invoke_hpp
{
namespace impl
{
struct invoke_result_impl_tag {};
@@ -175,66 +183,88 @@ namespace kari
struct invoke_result_impl {};
template < typename F, typename... Args >
struct invoke_result_impl<void_t<invoke_result_impl_tag, decltype(std_ext::invoke(std::declval<F>(), std::declval<Args>()...))>, F, Args...> {
using type = decltype(std_ext::invoke(std::declval<F>(), std::declval<Args>()...));
struct invoke_result_impl<void_t<invoke_result_impl_tag, decltype(invoke_hpp::invoke(std::declval<F>(), std::declval<Args>()...))>, F, Args...> {
using type = decltype(invoke_hpp::invoke(std::declval<F>(), std::declval<Args>()...));
};
}
template < typename F, typename... Args >
struct invoke_result
: detail::invoke_result_impl<void, F, Args...> {};
: impl::invoke_result_impl<void, F, Args...> {};
template < typename F, typename... Args >
using invoke_result_t = typename invoke_result<F, Args...>::type;
//
// is_invocable, is_invocable_v
//
namespace detail
{
struct is_invocable_impl_tag {};
template < typename Void, typename F, typename... Args >
struct is_invocable_impl
: std::false_type {};
template < typename F, typename... Args >
struct is_invocable_impl<void_t<is_invocable_impl_tag, invoke_result_t<F, Args...>>, F, Args...>
: std::true_type {};
}
template < typename F, typename... Args >
struct is_invocable
: detail::is_invocable_impl<void, F, Args...> {};
//
// is_invocable
//
namespace invoke_hpp
{
namespace impl
{
struct is_invocable_r_impl_tag {};
template < typename Void, typename R, typename F, typename... Args >
struct is_invocable_r_impl
: std::false_type {};
template < typename R, typename F, typename... Args >
struct is_invocable_r_impl<void_t<is_invocable_r_impl_tag, invoke_result_t<F, Args...>>, R, F, Args...>
: std::conditional_t<
std::is_void<R>::value,
std::true_type,
std::is_convertible<invoke_result_t<F, Args...>, R>> {};
}
template < typename R, typename F, typename... Args >
struct is_invocable_r
: impl::is_invocable_r_impl<void, R, F, Args...> {};
template < typename F, typename... Args >
constexpr bool is_invocable_v = is_invocable<F, Args...>::value;
using is_invocable = is_invocable_r<void, F, Args...>;
}
//
// apply
//
namespace detail
namespace invoke_hpp
{
namespace impl
{
template < typename F, typename Tuple, std::size_t... I >
constexpr auto apply_impl(F&& f, Tuple&& args, std::index_sequence<I...>)
KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(
std_ext::invoke(
constexpr decltype(auto) apply_impl(F&& f, Tuple&& args, std::index_sequence<I...>)
INVOKE_HPP_NOEXCEPT_RETURN(
invoke_hpp::invoke(
std::forward<F>(f),
std::get<I>(std::forward<Tuple>(args))...))
}
template < typename F, typename Tuple >
constexpr auto apply(F&& f, Tuple&& args)
KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(
detail::apply_impl(
constexpr decltype(auto) apply(F&& f, Tuple&& args)
INVOKE_HPP_NOEXCEPT_RETURN(
impl::apply_impl(
std::forward<F>(f),
std::forward<Tuple>(args),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>()))
}
}
}
#undef INVOKE_HPP_NOEXCEPT_RETURN
#undef INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN
// -----------------------------------------------------------------------------
//
// https://github.com/BlackMATov/kari.hpp
//
// -----------------------------------------------------------------------------
#define KARI_HPP_NOEXCEPT_RETURN(...) \
noexcept(noexcept(__VA_ARGS__)) { return __VA_ARGS__; }
#define KARI_HPP_NOEXCEPT_DECLTYPE_RETURN(...) \
noexcept(noexcept(__VA_ARGS__)) -> decltype (__VA_ARGS__) { return __VA_ARGS__; }
namespace kari
{
@@ -248,19 +278,19 @@ namespace kari
std::size_t N, typename F, typename... Args,
typename std::enable_if_t<
(N == 0) &&
std_ext::is_invocable_v<std::decay_t<F>, Args...>
invoke_hpp::is_invocable<std::decay_t<F>, Args...>::value
, int> = 0
>
constexpr auto make_curry(F&& f, std::tuple<Args...>&& args)
KARI_HPP_NOEXCEPT_RETURN(
std_ext::apply(std::forward<F>(f), std::move(args)))
invoke_hpp::apply(std::forward<F>(f), std::move(args)))
template
<
std::size_t N, typename F, typename... Args,
typename std::enable_if_t<
(N > 0) ||
!std_ext::is_invocable_v<std::decay_t<F>, Args...>
!invoke_hpp::is_invocable<std::decay_t<F>, Args...>::value
, int> = 0
>
constexpr auto make_curry(F&& f, std::tuple<Args...>&& args)
@@ -688,7 +718,3 @@ namespace kari
#undef KARI_HPP_NOEXCEPT_RETURN
#undef KARI_HPP_NOEXCEPT_DECLTYPE_RETURN
// Local Variables:
// indent-tabs-mode: nil
// End:

View File

@@ -1,10 +1,10 @@
/*******************************************************************************
* This file is part of the "kari.hpp"
* This file is part of the "https://github.com/BlackMATov/kari.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018 Matvey Cherevko
******************************************************************************/
#define CATCH_CONFIG_MAIN
#define CATCH_CONFIG_FAST_COMPILE
#include "catch.hpp"
#include "kari.hpp"
@@ -632,105 +632,6 @@ TEST_CASE("kari") {
}
}
TEST_CASE("kari_details") {
SECTION("invoke") {
using namespace kari::detail;
REQUIRE(std_ext::invoke(std::minus<>(), 44, 2) == 42);
REQUIRE(std_ext::invoke(&box::addV, box(10), 2) == 12);
{
auto b1 = box(10);
const auto b2 = box(10);
REQUIRE(std_ext::invoke(&box::addV, b1, 2) == 12);
REQUIRE(std_ext::invoke(&box::v, b2) == 10);
REQUIRE(std_ext::invoke(&box::addV, &b1, 2) == 14);
REQUIRE(std_ext::invoke(&box::v, &b2) == 10);
}
{
auto b1 = box(10);
const auto b2 = box(10);
REQUIRE(std_ext::invoke(&box::addV, std::ref(b1), 2) == 12);
REQUIRE(std_ext::invoke(&box::v, std::ref(b2)) == 10);
}
{
struct box2 : box {
box2(int v) : box(v) {}
};
auto b1 = box2(10);
const auto b2 = box2(10);
REQUIRE(std_ext::invoke(&box::addV, b1, 2) == 12);
REQUIRE(std_ext::invoke(&box::v, b2) == 10);
REQUIRE(std_ext::invoke(&box::addV, &b1, 2) == 14);
REQUIRE(std_ext::invoke(&box::v, &b2) == 10);
REQUIRE(std_ext::invoke(&box2::addV, b1, 2) == 16);
REQUIRE(std_ext::invoke(&box2::v, b2) == 10);
REQUIRE(std_ext::invoke(&box2::addV, &b1, 2) == 18);
REQUIRE(std_ext::invoke(&box2::v, &b2) == 10);
}
{
struct box2 : box {
box2(int v) : box(v) {}
};
auto b1 = box2(10);
const auto b2 = box2(10);
REQUIRE(std_ext::invoke(&box::addV, std::ref(b1), 2) == 12);
REQUIRE(std_ext::invoke(&box::v, std::ref(b2)) == 10);
REQUIRE(std_ext::invoke(&box2::addV, std::ref(b1), 2) == 14);
REQUIRE(std_ext::invoke(&box2::v, std::ref(b2)) == 10);
}
{
struct box2 : box {
box2(int v) : box(v), ov(v) {}
int ov;
};
auto b1 = box2(10);
const auto b2 = box2(10);
REQUIRE(std_ext::invoke(&box2::ov, box2(10)) == 10);
REQUIRE(std_ext::invoke(&box2::ov, b1) == 10);
REQUIRE(std_ext::invoke(&box2::ov, b2) == 10);
REQUIRE(std_ext::invoke(&box2::ov, &b1) == 10);
REQUIRE(std_ext::invoke(&box2::ov, &b2) == 10);
REQUIRE(std_ext::invoke(&box2::ov, std::ref(b1)) == 10);
REQUIRE(std_ext::invoke(&box2::ov, std::ref(b2)) == 10);
}
{
struct box2 : box {
box2(int v) : box(v), ov(v) {}
int ov;
};
struct box3 : box2 {
box3(int v) : box2(v) {}
};
auto b1 = box3(10);
const auto b2 = box3(10);
REQUIRE(std_ext::invoke(&box2::ov, box3(10)) == 10);
REQUIRE(std_ext::invoke(&box2::ov, b1) == 10);
REQUIRE(std_ext::invoke(&box2::ov, b2) == 10);
REQUIRE(std_ext::invoke(&box2::ov, &b1) == 10);
REQUIRE(std_ext::invoke(&box2::ov, &b2) == 10);
REQUIRE(std_ext::invoke(&box2::ov, std::ref(b1)) == 10);
REQUIRE(std_ext::invoke(&box2::ov, std::ref(b2)) == 10);
}
}
SECTION("is_invocable") {
using namespace kari::detail;
const auto f1 = [](int i, int j){
return i + j;
};
const auto f2 = [](int i, int j) noexcept {
return i + j;
};
static_assert( std_ext::is_invocable_v<decltype(f1), int, int>, "static unit test error");
static_assert(!std_ext::is_invocable_v<decltype(f1), int, box>, "static unit test error");
static_assert( std_ext::is_invocable_v<decltype(f2), int, int>, "static unit test error");
static_assert(!std_ext::is_invocable_v<decltype(f2), int, box>, "static unit test error");
}
}
TEST_CASE("kari_helpers") {
SECTION("fid") {
REQUIRE(fid(box(10)).v() == 10);
@@ -820,7 +721,3 @@ TEST_CASE("kari_regression") {
REQUIRE(c2(1,2,3) == 6);
}
}
// Local Variables:
// indent-tabs-mode: nil
// End: