From ca84551b309058f986a40f66592fa669f2e075f6 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 13 Dec 2018 00:34:59 +0700 Subject: [PATCH 1/3] invoke impl to separated file --- invoke.hpp | 248 +++++++++++++++++++++++++++++++++++++++++++++++++ jobber.hpp | 2 +- promise.hpp | 251 +------------------------------------------------- scheduler.hpp | 2 +- 4 files changed, 252 insertions(+), 251 deletions(-) create mode 100644 invoke.hpp diff --git a/invoke.hpp b/invoke.hpp new file mode 100644 index 0000000..01d2f13 --- /dev/null +++ b/invoke.hpp @@ -0,0 +1,248 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/invoke.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018 Matvey Cherevko + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include + +#define INVOKE_HPP_NOEXCEPT_RETURN(...) \ + noexcept(noexcept(__VA_ARGS__)) { return __VA_ARGS__; } + +#define INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(...) \ + noexcept(noexcept(__VA_ARGS__)) -> decltype (__VA_ARGS__) { return __VA_ARGS__; } + +// +// void_t +// + +namespace invoke_hpp +{ + namespace impl + { + template < typename... Args > + struct make_void { + using type = void; + }; + } + + template < typename... Args > + using void_t = typename impl::make_void::type; +} + +// +// is_reference_wrapper +// + +namespace invoke_hpp +{ + namespace impl + { + template < typename T > + struct is_reference_wrapper_impl + : std::false_type {}; + + template < typename U > + struct is_reference_wrapper_impl> + : std::true_type {}; + } + + template < typename T > + struct is_reference_wrapper + : impl::is_reference_wrapper_impl> {}; +} + +// +// invoke +// + +namespace invoke_hpp +{ + namespace impl + { + // + // invoke_member_object_impl + // + + template + < + typename Base, typename F, typename Derived, + typename std::enable_if_t>::value, int> = 0 + > + constexpr auto invoke_member_object_impl(F Base::* f, Derived&& ref) + INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( + std::forward(ref).*f) + + template + < + typename Base, typename F, typename RefWrap, + typename std::enable_if_t>::value, int> = 0 + > + constexpr auto invoke_member_object_impl(F Base::* f, RefWrap&& ref) + INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( + ref.get().*f) + + template + < + typename Base, typename F, typename Pointer, + typename std::enable_if_t< + !std::is_base_of>::value && + !is_reference_wrapper>::value + , int> = 0 + > + constexpr auto invoke_member_object_impl(F Base::* f, Pointer&& ptr) + INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( + (*std::forward(ptr)).*f) + + // + // invoke_member_function_impl + // + + template + < + typename Base, typename F, typename Derived, typename... Args, + typename std::enable_if_t>::value, int> = 0 + > + constexpr auto invoke_member_function_impl(F Base::* f, Derived&& ref, Args&&... args) + INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( + (std::forward(ref).*f)(std::forward(args)...)) + + template + < + typename Base, typename F, typename RefWrap, typename... Args, + typename std::enable_if_t>::value, int> = 0 + > + constexpr auto invoke_member_function_impl(F Base::* f, RefWrap&& ref, Args&&... args) + INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( + (ref.get().*f)(std::forward(args)...)) + + template + < + typename Base, typename F, typename Pointer, typename... Args, + typename std::enable_if_t< + !std::is_base_of>::value && + !is_reference_wrapper>::value + , int> = 0 + > + constexpr auto invoke_member_function_impl(F Base::* f, Pointer&& ptr, Args&&... args) + INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( + ((*std::forward(ptr)).*f)(std::forward(args)...)) + } + + template + < + typename F, typename... Args, + typename std::enable_if_t>::value, int> = 0 + > + constexpr auto invoke(F&& f, Args&&... args) + INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( + std::forward(f)(std::forward(args)...)) + + template + < + typename F, typename T, + typename std::enable_if_t>::value, int> = 0 + > + constexpr auto invoke(F&& f, T&& t) + INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( + impl::invoke_member_object_impl(std::forward(f), std::forward(t))) + + template + < + typename F, typename... Args, + typename std::enable_if_t>::value, int> = 0 + > + constexpr auto invoke(F&& f, Args&&... args) + INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( + impl::invoke_member_function_impl(std::forward(f), std::forward(args)...)) +} + +// +// invoke_result +// + +namespace invoke_hpp +{ + namespace impl + { + struct invoke_result_impl_tag {}; + + template < typename Void, typename F, typename... Args > + struct invoke_result_impl {}; + + template < typename F, typename... Args > + struct invoke_result_impl(), std::declval()...))>, F, Args...> { + using type = decltype(invoke_hpp::invoke(std::declval(), std::declval()...)); + }; + } + + template < typename F, typename... Args > + struct invoke_result + : impl::invoke_result_impl {}; + + template < typename F, typename... Args > + using invoke_result_t = typename invoke_result::type; +} + +// +// 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>, R, F, Args...> + : std::conditional_t< + std::is_void::value, + std::true_type, + std::is_convertible, R>> {}; + } + + template < typename R, typename F, typename... Args > + struct is_invocable_r + : impl::is_invocable_r_impl {}; + + template < typename F, typename... Args > + using is_invocable = is_invocable_r; +} + +// +// apply +// + +namespace invoke_hpp +{ + namespace impl + { + template < typename F, typename Tuple, std::size_t... I > + constexpr decltype(auto) apply_impl(F&& f, Tuple&& args, std::index_sequence) + INVOKE_HPP_NOEXCEPT_RETURN( + invoke_hpp::invoke( + std::forward(f), + std::get(std::forward(args))...)) + } + + template < typename F, typename Tuple > + constexpr decltype(auto) apply(F&& f, Tuple&& args) + INVOKE_HPP_NOEXCEPT_RETURN( + impl::apply_impl( + std::forward(f), + std::forward(args), + std::make_index_sequence>::value>())) +} + +#undef INVOKE_HPP_NOEXCEPT_RETURN +#undef INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN diff --git a/jobber.hpp b/jobber.hpp index 4cef528..4a21c11 100644 --- a/jobber.hpp +++ b/jobber.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * This file is part of the "promise.hpp" + * This file is part of the "https://github.com/blackmatov/promise.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ diff --git a/promise.hpp b/promise.hpp index 62678a8..79a5663 100644 --- a/promise.hpp +++ b/promise.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * This file is part of the "promise.hpp" + * This file is part of the "https://github.com/blackmatov/promise.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ @@ -23,254 +23,7 @@ #include #include -// -// invoke.hpp -// https://github.com/BlackMATov/invoke.hpp -// - -namespace promise_hpp -{ - #define INVOKE_HPP_NOEXCEPT_RETURN(...) \ - noexcept(noexcept(__VA_ARGS__)) { return __VA_ARGS__; } - - #define INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(...) \ - noexcept(noexcept(__VA_ARGS__)) -> decltype (__VA_ARGS__) { return __VA_ARGS__; } - - // - // void_t - // - - namespace invoke_hpp - { - namespace impl - { - template < typename... Args > - struct make_void { - using type = void; - }; - } - - template < typename... Args > - using void_t = typename impl::make_void::type; - } - - // - // is_reference_wrapper - // - - namespace invoke_hpp - { - namespace impl - { - template < typename T > - struct is_reference_wrapper_impl - : std::false_type {}; - - template < typename U > - struct is_reference_wrapper_impl> - : std::true_type {}; - } - - template < typename T > - struct is_reference_wrapper - : impl::is_reference_wrapper_impl> {}; - } - - // - // invoke - // - - namespace invoke_hpp - { - namespace impl - { - // - // invoke_member_object_impl - // - - template - < - typename Base, typename F, typename Derived, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke_member_object_impl(F Base::* f, Derived&& ref) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - std::forward(ref).*f) - - template - < - typename Base, typename F, typename RefWrap, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke_member_object_impl(F Base::* f, RefWrap&& ref) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - ref.get().*f) - - template - < - typename Base, typename F, typename Pointer, - typename std::enable_if_t< - !std::is_base_of>::value && - !is_reference_wrapper>::value - , int> = 0 - > - constexpr auto invoke_member_object_impl(F Base::* f, Pointer&& ptr) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - (*std::forward(ptr)).*f) - - // - // invoke_member_function_impl - // - - template - < - typename Base, typename F, typename Derived, typename... Args, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke_member_function_impl(F Base::* f, Derived&& ref, Args&&... args) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - (std::forward(ref).*f)(std::forward(args)...)) - - template - < - typename Base, typename F, typename RefWrap, typename... Args, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke_member_function_impl(F Base::* f, RefWrap&& ref, Args&&... args) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - (ref.get().*f)(std::forward(args)...)) - - template - < - typename Base, typename F, typename Pointer, typename... Args, - typename std::enable_if_t< - !std::is_base_of>::value && - !is_reference_wrapper>::value - , int> = 0 - > - constexpr auto invoke_member_function_impl(F Base::* f, Pointer&& ptr, Args&&... args) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - ((*std::forward(ptr)).*f)(std::forward(args)...)) - } - - template - < - typename F, typename... Args, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke(F&& f, Args&&... args) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - std::forward(f)(std::forward(args)...)) - - template - < - typename F, typename T, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke(F&& f, T&& t) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - impl::invoke_member_object_impl(std::forward(f), std::forward(t))) - - template - < - typename F, typename... Args, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke(F&& f, Args&&... args) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - impl::invoke_member_function_impl(std::forward(f), std::forward(args)...)) - } - - // - // invoke_result - // - - namespace invoke_hpp - { - namespace impl - { - struct invoke_result_impl_tag {}; - - template < typename Void, typename F, typename... Args > - struct invoke_result_impl {}; - - template < typename F, typename... Args > - struct invoke_result_impl(), std::declval()...))>, F, Args...> { - using type = decltype(invoke_hpp::invoke(std::declval(), std::declval()...)); - }; - } - - template < typename F, typename... Args > - struct invoke_result - : impl::invoke_result_impl {}; - - template < typename F, typename... Args > - using invoke_result_t = typename invoke_result::type; - } - - // - // 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>, R, F, Args...> - : std::conditional_t< - std::is_void::value, - std::true_type, - std::is_convertible, R>> {}; - } - - template < typename R, typename F, typename... Args > - struct is_invocable_r - : impl::is_invocable_r_impl {}; - - template < typename F, typename... Args > - using is_invocable = is_invocable_r; - } - - // - // apply - // - - namespace invoke_hpp - { - namespace impl - { - template < typename F, typename Tuple, std::size_t... I > - constexpr decltype(auto) apply_impl(F&& f, Tuple&& args, std::index_sequence) - INVOKE_HPP_NOEXCEPT_RETURN( - invoke_hpp::invoke( - std::forward(f), - std::get(std::forward(args))...)) - } - - template < typename F, typename Tuple > - constexpr decltype(auto) apply(F&& f, Tuple&& args) - INVOKE_HPP_NOEXCEPT_RETURN( - impl::apply_impl( - std::forward(f), - std::forward(args), - std::make_index_sequence>::value>())) - } - - #undef INVOKE_HPP_NOEXCEPT_RETURN - #undef INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN -} - -// -// promise.hpp -// https://github.com/BlackMATov/promise.hpp -// +#include "invoke.hpp" namespace promise_hpp { diff --git a/scheduler.hpp b/scheduler.hpp index 303fa57..97af654 100644 --- a/scheduler.hpp +++ b/scheduler.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * This file is part of the "promise.hpp" + * This file is part of the "https://github.com/blackmatov/promise.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ From 7aa600966b6ba4915d6728d7e909ea4a2f7a0151 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 13 Dec 2018 00:51:27 +0700 Subject: [PATCH 2/3] separate tests --- tests_main.cpp => catch_main.cpp | 2 +- invoke_tests.cpp | 510 +++++++++++++++++++++++++++++++ jobber_tests.cpp | 281 +++++++++++++++++ tests.cpp => promise_tests.cpp | 373 +--------------------- scheduler_tests.cpp | 114 +++++++ 5 files changed, 908 insertions(+), 372 deletions(-) rename tests_main.cpp => catch_main.cpp (83%) create mode 100644 invoke_tests.cpp create mode 100644 jobber_tests.cpp rename tests.cpp => promise_tests.cpp (73%) create mode 100644 scheduler_tests.cpp diff --git a/tests_main.cpp b/catch_main.cpp similarity index 83% rename from tests_main.cpp rename to catch_main.cpp index 637c53c..9500ab4 100644 --- a/tests_main.cpp +++ b/catch_main.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * This file is part of the "promise.hpp" + * This file is part of the "https://github.com/blackmatov/promise.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ diff --git a/invoke_tests.cpp b/invoke_tests.cpp new file mode 100644 index 0000000..14d0c5e --- /dev/null +++ b/invoke_tests.cpp @@ -0,0 +1,510 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/invoke.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018 Matvey Cherevko + ******************************************************************************/ + +#define CATCH_CONFIG_FAST_COMPILE +#include "catch.hpp" + +#include "invoke.hpp" +namespace inv = invoke_hpp; + +namespace +{ + void simple_static_function() { + } + + int simple_static_function_r() { + return 42; + } + + int simple_static_function_r_with_arg(int v) { + return v; + } + + const int& simple_static_function_r_with_ref_arg(const int& v) { + return v; + } + + class obj_t { + public: + int value = 42; + const int value_c = 42; + + void member() { + } + + int member_r() { + return 42; + } + + int member_r_with_arg(int v) { + return v; + } + + const int& member_r_with_ref_arg(const int& v) { + return v; + } + }; + + class obj2_t { + }; +} + +TEST_CASE("invoke"){ + SECTION("invoke_functions"){ + inv::invoke(simple_static_function); + REQUIRE(inv::invoke(simple_static_function_r) == 42); + REQUIRE(inv::invoke(simple_static_function_r_with_arg, 42) == 42); + { + int v = 42; + REQUIRE(&inv::invoke(simple_static_function_r_with_ref_arg, v) == &v); + } + } + SECTION("invoke_members"){ + obj_t o; + + inv::invoke(&obj_t::member, o); + inv::invoke(&obj_t::member, &o); + inv::invoke(&obj_t::member, std::ref(o)); + + REQUIRE(inv::invoke(&obj_t::member_r, o) == 42); + REQUIRE(inv::invoke(&obj_t::member_r, &o) == 42); + REQUIRE(inv::invoke(&obj_t::member_r, std::ref(o)) == 42); + + REQUIRE(inv::invoke(&obj_t::member_r_with_arg, o, 42) == 42); + REQUIRE(inv::invoke(&obj_t::member_r_with_arg, &o, 42) == 42); + REQUIRE(inv::invoke(&obj_t::member_r_with_arg, std::ref(o), 42) == 42); + + { + int v = 42; + REQUIRE(&inv::invoke(&obj_t::member_r_with_ref_arg, o, std::ref(v)) == &v); + REQUIRE(&inv::invoke(&obj_t::member_r_with_ref_arg, &o, std::ref(v)) == &v); + REQUIRE(&inv::invoke(&obj_t::member_r_with_ref_arg, std::ref(o), std::ref(v)) == &v); + } + } + SECTION("invoke_member_objects"){ + obj_t o; + + REQUIRE(inv::invoke(&obj_t::value, o) == 42); + REQUIRE(inv::invoke(&obj_t::value, &o) == 42); + REQUIRE(inv::invoke(&obj_t::value, std::ref(o)) == 42); + + REQUIRE(inv::invoke(&obj_t::value_c, o) == 42); + REQUIRE(inv::invoke(&obj_t::value_c, &o) == 42); + REQUIRE(inv::invoke(&obj_t::value_c, std::ref(o)) == 42); + } +} + +TEST_CASE("invoke_result"){ + SECTION("invoke_result_functions"){ + static_assert( + std::is_same< + void, + inv::invoke_result_t>::value, + "unit test fail"); + static_assert( + std::is_same< + int, + inv::invoke_result_t>::value, + "unit test fail"); + static_assert( + std::is_same< + int, + inv::invoke_result_t>::value, + "unit test fail"); + static_assert( + std::is_same< + const int&, + inv::invoke_result_t>::value, + "unit test fail"); + } + SECTION("invoke_result_members"){ + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>>::value, + "unit test fail"); + + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>>::value, + "unit test fail"); + + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same, int>>::value, + "unit test fail"); + + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same>::value, + "unit test fail"); + static_assert( + std::is_same, const int&>>::value, + "unit test fail"); + } +} + +TEST_CASE("is_invocable"){ + SECTION("is_invocable_functions"){ + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + } + SECTION("is_not_invocable_functions"){ + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + } + SECTION("is_invocable_members"){ + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable, int>::value, + "unit test fail"); + } + SECTION("is_not_invocable_members"){ + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable*>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable, int>::value, + "unit test fail"); + } + SECTION("is_invocable_objects"){ + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable::value, + "unit test fail"); + static_assert( + inv::is_invocable>::value, + "unit test fail"); + } + SECTION("is_not_invocable_objects"){ + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable::value, + "unit test fail"); + static_assert( + !inv::is_invocable>::value, + "unit test fail"); + } +} + +TEST_CASE("is_invocable_r"){ + SECTION("is_invocable_r_functions"){ + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + } + SECTION("is_not_invocable_r_functions"){ + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + } + SECTION("is_invocable_r_members"){ + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r, int>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r, int>::value, + "unit test fail"); + } + SECTION("is_not_invocable_r_members"){ + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r, obj2_t>::value, + "unit test fail"); + } + SECTION("is_invocable_r_objects"){ + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + inv::is_invocable_r>::value, + "unit test fail"); + } + SECTION("is_not_invocable_r_objects"){ + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r, obj2_t>::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r, obj2_t>::value, + "unit test fail"); + + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + static_assert( + !inv::is_invocable_r>::value, + "unit test fail"); + } +} + +TEST_CASE("apply"){ + SECTION("apply_functions"){ + inv::apply(simple_static_function, std::make_tuple()); + REQUIRE(inv::apply(simple_static_function_r, std::make_tuple()) == 42); + REQUIRE(inv::apply(simple_static_function_r_with_arg, std::make_tuple(42)) == 42); + { + int v = 42; + REQUIRE(&inv::apply(simple_static_function_r_with_ref_arg, std::make_tuple(std::ref(v))) == &v); + } + } + SECTION("apply_members"){ + obj_t o; + + inv::apply(&obj_t::member, std::make_tuple(o)); + inv::apply(&obj_t::member, std::make_tuple(&o)); + inv::apply(&obj_t::member, std::make_tuple(std::ref(o))); + + REQUIRE(inv::apply(&obj_t::member_r, std::make_tuple(o)) == 42); + REQUIRE(inv::apply(&obj_t::member_r, std::make_tuple(&o)) == 42); + REQUIRE(inv::apply(&obj_t::member_r, std::make_tuple(std::ref(o))) == 42); + + REQUIRE(inv::apply(&obj_t::member_r_with_arg, std::make_tuple(o, 42)) == 42); + REQUIRE(inv::apply(&obj_t::member_r_with_arg, std::make_tuple(&o, 42)) == 42); + REQUIRE(inv::apply(&obj_t::member_r_with_arg, std::make_tuple(std::ref(o), 42)) == 42); + + { + int v = 42; + REQUIRE(&inv::apply(&obj_t::member_r_with_ref_arg, std::make_tuple(o, std::ref(v))) == &v); + REQUIRE(&inv::apply(&obj_t::member_r_with_ref_arg, std::make_tuple(&o, std::ref(v))) == &v); + REQUIRE(&inv::apply(&obj_t::member_r_with_ref_arg, std::make_tuple(std::ref(o), std::ref(v))) == &v); + } + } + SECTION("apply_member_objects"){ + obj_t o; + + REQUIRE(inv::apply(&obj_t::value, std::make_tuple(o)) == 42); + REQUIRE(inv::apply(&obj_t::value, std::make_tuple(&o)) == 42); + REQUIRE(inv::apply(&obj_t::value, std::make_tuple(std::ref(o))) == 42); + + REQUIRE(inv::apply(&obj_t::value_c, std::make_tuple(o)) == 42); + REQUIRE(inv::apply(&obj_t::value_c, std::make_tuple(&o)) == 42); + REQUIRE(inv::apply(&obj_t::value_c, std::make_tuple(std::ref(o))) == 42); + } +} diff --git a/jobber_tests.cpp b/jobber_tests.cpp new file mode 100644 index 0000000..a279bb9 --- /dev/null +++ b/jobber_tests.cpp @@ -0,0 +1,281 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/promise.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018 Matvey Cherevko + ******************************************************************************/ + +#define CATCH_CONFIG_FAST_COMPILE +#include "catch.hpp" + +#include +#include +#include + +#include "jobber.hpp" +namespace jb = jobber_hpp; + +TEST_CASE("jobber") { + { + jb::jobber j(1); + auto pv0 = j.async([](){ + throw std::exception(); + }); + REQUIRE_THROWS_AS(pv0.get(), std::exception); + } + { + auto pv0 = jb::promise(); + { + jb::jobber j{0}; + pv0 = j.async([](){ + return 42; + }); + } + REQUIRE_THROWS_AS(pv0.get(), jb::jobber_cancelled_exception); + } + { + int v5 = 5; + + jb::jobber j(1); + auto pv0 = j.async([](int v){ + REQUIRE(v == 5); + throw std::exception(); + }, v5); + REQUIRE_THROWS_AS(pv0.get(), std::exception); + + auto pv1 = j.async([](int& v){ + REQUIRE(v == 5); + return v != 5 + ? 0 + : throw std::exception(); + }, std::ref(v5)); + REQUIRE_THROWS_AS(pv1.get(), std::exception); + + auto pv3 = j.async([](int& v){ + v = 4; + return v; + }, std::ref(v5)); + REQUIRE(pv3.get() == v5); + REQUIRE(v5 == 4); + } + { + const float pi = 3.14159265358979323846264338327950288f; + jb::jobber j(1); + auto p0 = j.async([](float angle){ + return std::sin(angle); + }, pi); + auto p1 = j.async([](float angle){ + return std::cos(angle); + }, pi * 2); + REQUIRE(p0.get() == Approx(0.f).margin(0.01f)); + REQUIRE(p1.get() == Approx(1.f).margin(0.01f)); + } + { + jb::jobber j(1); + j.pause(); + jb::jobber_priority max_priority = jb::jobber_priority::highest; + j.async([](){ + std::this_thread::sleep_for(std::chrono::milliseconds(2)); + }); + for ( std::size_t i = 0; i < 10; ++i ) { + jb::jobber_priority p = static_cast( + i % static_cast(jb::jobber_priority::highest)); + j.async(p, [&max_priority](jb::jobber_priority priority) { + REQUIRE(priority <= max_priority); + max_priority = priority; + }, p); + } + j.resume(); + j.wait_all(); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 10; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + + j.resume(); + REQUIRE(counter < 10); + j.wait_all(); + REQUIRE(counter == 10); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 10; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + REQUIRE(counter < 10); + j.active_wait_all(); + REQUIRE(counter == 10); + } + { + jb::jobber j(1); + + const auto time_now = [](){ + return std::chrono::high_resolution_clock::now(); + }; + + REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_for(std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_until(time_now() + std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_for(std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_until(time_now() + std::chrono::milliseconds(-1))); + + j.pause(); + j.async([]{}); + + REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_for(std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_until(time_now() + std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_for(std::chrono::milliseconds(-1))); + REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_until(time_now() + std::chrono::milliseconds(-1))); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 10; ++i ) { + j.async([&counter](){ + ++counter; + }); + } + + const auto time_now = [](){ + return std::chrono::high_resolution_clock::now(); + }; + + j.wait_all_for(std::chrono::milliseconds(10)); + j.wait_all_until(time_now() + std::chrono::milliseconds(10)); + REQUIRE(counter == 0); + + j.active_wait_all_for(std::chrono::milliseconds(10)); + j.active_wait_all_until(time_now() + std::chrono::milliseconds(10)); + REQUIRE(counter > 0); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 50; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + + const auto time_now = [](){ + return std::chrono::high_resolution_clock::now(); + }; + + const auto b = time_now(); + + j.resume(); + j.wait_all_for(std::chrono::milliseconds(100)); + REQUIRE(time_now() - b > std::chrono::milliseconds(50)); + REQUIRE(counter > 2); + REQUIRE(counter < 50); + + j.wait_all_until(time_now() + std::chrono::seconds(3)); + REQUIRE(counter == 50); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 50; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + + const auto time_now = [](){ + return std::chrono::high_resolution_clock::now(); + }; + + const auto b = time_now(); + + j.wait_all_for(std::chrono::milliseconds(15)); + REQUIRE(time_now() - b > std::chrono::milliseconds(10)); + REQUIRE(counter == 0); + + j.wait_all_until(time_now() + std::chrono::milliseconds(15)); + REQUIRE(time_now() - b > std::chrono::milliseconds(20)); + REQUIRE(counter == 0); + + j.active_wait_all_for(std::chrono::milliseconds(100)); + REQUIRE(time_now() - b > std::chrono::milliseconds(70)); + REQUIRE(counter > 2); + REQUIRE(counter < 50); + + j.active_wait_all_until(time_now() + std::chrono::seconds(3)); + REQUIRE(counter == 50); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 30; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + j.resume(); + REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_for(std::chrono::milliseconds(50))); + REQUIRE(counter > 0); + REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_for(std::chrono::seconds(5))); + REQUIRE(counter == 30); + } + { + jb::jobber j(1); + std::atomic counter = ATOMIC_VAR_INIT(0); + j.pause(); + for ( std::size_t i = 0; i < 30; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_for(std::chrono::milliseconds(50))); + REQUIRE(counter > 0); + REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_for(std::chrono::seconds(5))); + REQUIRE(counter == 30); + } + { + jb::jobber j(2); + jb::jobber g(2); + + std::vector> jp(50); + for ( auto& jpi : jp ) { + jpi = j.async([&g](){ + std::vector> gp(50); + for ( std::size_t i = 0; i < gp.size(); ++i ) { + gp[i] = g.async([](float angle){ + return std::sin(angle); + }, static_cast(i)); + } + return std::accumulate(gp.begin(), gp.end(), 0.f, + [](float r, jb::promise& f){ + return r + f.get(); + }); + }); + } + float r0 = std::accumulate(jp.begin(), jp.end(), 0.f, + [](float r, jb::promise& f){ + return r + f.get(); + }); + float r1 = 0.f; + for ( std::size_t i = 0; i < 50; ++i ) { + r1 += std::sin(static_cast(i)); + } + REQUIRE(r0 == Approx(r1 * 50.f).margin(0.01f)); + } +} diff --git a/tests.cpp b/promise_tests.cpp similarity index 73% rename from tests.cpp rename to promise_tests.cpp index a3500de..e53714d 100644 --- a/tests.cpp +++ b/promise_tests.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * This file is part of the "promise.hpp" + * This file is part of the "https://github.com/blackmatov/promise.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ @@ -7,16 +7,12 @@ #define CATCH_CONFIG_FAST_COMPILE #include "catch.hpp" +#include #include #include -#include "jobber.hpp" #include "promise.hpp" -#include "scheduler.hpp" - -namespace jb = jobber_hpp; namespace pr = promise_hpp; -namespace sd = scheduler_hpp; namespace { @@ -982,368 +978,3 @@ TEST_CASE("get_and_wait") { } } } - -TEST_CASE("jobber") { - { - jb::jobber j(1); - auto pv0 = j.async([](){ - throw std::exception(); - }); - REQUIRE_THROWS_AS(pv0.get(), std::exception); - } - { - auto pv0 = pr::promise(); - { - jb::jobber j{0}; - pv0 = j.async([](){ - return 42; - }); - } - REQUIRE_THROWS_AS(pv0.get(), jb::jobber_cancelled_exception); - } - { - int v5 = 5; - - jb::jobber j(1); - auto pv0 = j.async([](int v){ - REQUIRE(v == 5); - throw std::exception(); - }, v5); - REQUIRE_THROWS_AS(pv0.get(), std::exception); - - auto pv1 = j.async([](int& v){ - REQUIRE(v == 5); - return v != 5 - ? 0 - : throw std::exception(); - }, std::ref(v5)); - REQUIRE_THROWS_AS(pv1.get(), std::exception); - - auto pv3 = j.async([](int& v){ - v = 4; - return v; - }, std::ref(v5)); - REQUIRE(pv3.get() == v5); - REQUIRE(v5 == 4); - } - { - const float pi = 3.14159265358979323846264338327950288f; - jb::jobber j(1); - auto p0 = j.async([](float angle){ - return std::sin(angle); - }, pi); - auto p1 = j.async([](float angle){ - return std::cos(angle); - }, pi * 2); - REQUIRE(p0.get() == Approx(0.f).margin(0.01f)); - REQUIRE(p1.get() == Approx(1.f).margin(0.01f)); - } - { - jb::jobber j(1); - j.pause(); - jb::jobber_priority max_priority = jb::jobber_priority::highest; - j.async([](){ - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - }); - for ( std::size_t i = 0; i < 10; ++i ) { - jb::jobber_priority p = static_cast( - i % static_cast(jb::jobber_priority::highest)); - j.async(p, [&max_priority](jb::jobber_priority priority) { - REQUIRE(priority <= max_priority); - max_priority = priority; - }, p); - } - j.resume(); - j.wait_all(); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 10; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - - j.resume(); - REQUIRE(counter < 10); - j.wait_all(); - REQUIRE(counter == 10); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 10; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - REQUIRE(counter < 10); - j.active_wait_all(); - REQUIRE(counter == 10); - } - { - jb::jobber j(1); - - const auto time_now = [](){ - return std::chrono::high_resolution_clock::now(); - }; - - REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_for(std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_until(time_now() + std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_for(std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_until(time_now() + std::chrono::milliseconds(-1))); - - j.pause(); - j.async([]{}); - - REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_for(std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_until(time_now() + std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_for(std::chrono::milliseconds(-1))); - REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_until(time_now() + std::chrono::milliseconds(-1))); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 10; ++i ) { - j.async([&counter](){ - ++counter; - }); - } - - const auto time_now = [](){ - return std::chrono::high_resolution_clock::now(); - }; - - j.wait_all_for(std::chrono::milliseconds(10)); - j.wait_all_until(time_now() + std::chrono::milliseconds(10)); - REQUIRE(counter == 0); - - j.active_wait_all_for(std::chrono::milliseconds(10)); - j.active_wait_all_until(time_now() + std::chrono::milliseconds(10)); - REQUIRE(counter > 0); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 50; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - - const auto time_now = [](){ - return std::chrono::high_resolution_clock::now(); - }; - - const auto b = time_now(); - - j.resume(); - j.wait_all_for(std::chrono::milliseconds(100)); - REQUIRE(time_now() - b > std::chrono::milliseconds(50)); - REQUIRE(counter > 2); - REQUIRE(counter < 50); - - j.wait_all_until(time_now() + std::chrono::seconds(3)); - REQUIRE(counter == 50); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 50; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - - const auto time_now = [](){ - return std::chrono::high_resolution_clock::now(); - }; - - const auto b = time_now(); - - j.wait_all_for(std::chrono::milliseconds(15)); - REQUIRE(time_now() - b > std::chrono::milliseconds(10)); - REQUIRE(counter == 0); - - j.wait_all_until(time_now() + std::chrono::milliseconds(15)); - REQUIRE(time_now() - b > std::chrono::milliseconds(20)); - REQUIRE(counter == 0); - - j.active_wait_all_for(std::chrono::milliseconds(100)); - REQUIRE(time_now() - b > std::chrono::milliseconds(70)); - REQUIRE(counter > 2); - REQUIRE(counter < 50); - - j.active_wait_all_until(time_now() + std::chrono::seconds(3)); - REQUIRE(counter == 50); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 30; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - j.resume(); - REQUIRE(jb::jobber_wait_status::timeout == j.wait_all_for(std::chrono::milliseconds(50))); - REQUIRE(counter > 0); - REQUIRE(jb::jobber_wait_status::no_timeout == j.wait_all_for(std::chrono::seconds(5))); - REQUIRE(counter == 30); - } - { - jb::jobber j(1); - std::atomic counter = ATOMIC_VAR_INIT(0); - j.pause(); - for ( std::size_t i = 0; i < 30; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - REQUIRE(jb::jobber_wait_status::timeout == j.active_wait_all_for(std::chrono::milliseconds(50))); - REQUIRE(counter > 0); - REQUIRE(jb::jobber_wait_status::no_timeout == j.active_wait_all_for(std::chrono::seconds(5))); - REQUIRE(counter == 30); - } - { - jb::jobber j(2); - jb::jobber g(2); - - std::vector> jp(50); - for ( auto& jpi : jp ) { - jpi = j.async([&g](){ - std::vector> gp(50); - for ( std::size_t i = 0; i < gp.size(); ++i ) { - gp[i] = g.async([](float angle){ - return std::sin(angle); - }, static_cast(i)); - } - return std::accumulate(gp.begin(), gp.end(), 0.f, - [](float r, pr::promise& f){ - return r + f.get(); - }); - }); - } - float r0 = std::accumulate(jp.begin(), jp.end(), 0.f, - [](float r, pr::promise& f){ - return r + f.get(); - }); - float r1 = 0.f; - for ( std::size_t i = 0; i < 50; ++i ) { - r1 += std::sin(static_cast(i)); - } - REQUIRE(r0 == Approx(r1 * 50.f).margin(0.01f)); - } -} - -TEST_CASE("scheduler") { - { - sd::scheduler s; - auto pv0 = s.schedule([](){ - throw std::exception(); - }); - s.process_all_tasks(); - REQUIRE_THROWS_AS(pv0.get(), std::exception); - } - { - auto pv0 = pr::promise(); - { - sd::scheduler s; - pv0 = s.schedule([](){ - return 42; - }); - } - REQUIRE_THROWS_AS(pv0.get(), sd::scheduler_cancelled_exception); - } - { - sd::scheduler s; - int counter = 0; - s.schedule([&counter](){ ++counter; }); - REQUIRE(counter == 0); - s.process_all_tasks(); - REQUIRE(counter == 1); - s.schedule([&counter](){ ++counter; }); - s.schedule([&counter](){ ++counter; }); - REQUIRE(counter == 1); - s.process_all_tasks(); - REQUIRE(counter == 3); - } - { - sd::scheduler s; - int counter = 0; - for ( std::size_t i = 0; i < 50; ++i ) { - s.schedule([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - s.process_tasks_for(std::chrono::milliseconds(-1)); - s.process_tasks_for(std::chrono::milliseconds(0)); - REQUIRE(counter == 0); - s.process_tasks_for(std::chrono::milliseconds(100)); - REQUIRE(counter > 2); - REQUIRE(counter < 50); - s.process_tasks_for(std::chrono::seconds(3)); - REQUIRE(counter == 50); - } - { - sd::scheduler s; - int counter = 0; - for ( std::size_t i = 0; i < 50; ++i ) { - s.schedule([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - - const auto time_now = [](){ - return std::chrono::high_resolution_clock::now(); - }; - - const auto b = time_now(); - - s.process_tasks_until(time_now() - std::chrono::milliseconds(1)); - s.process_tasks_until(time_now()); - REQUIRE(counter == 0); - s.process_tasks_until(time_now() + std::chrono::milliseconds(100)); - REQUIRE(time_now() - b > std::chrono::milliseconds(50)); - REQUIRE(counter > 2); - REQUIRE(counter < 50); - s.process_tasks_until(time_now() + std::chrono::seconds(3)); - REQUIRE(counter == 50); - } - { - sd::scheduler s; - std::string accumulator; - s.schedule(sd::scheduler_priority::lowest, [](std::string& acc){ - acc.append("o"); - }, std::ref(accumulator)); - s.schedule(sd::scheduler_priority::below_normal, [](std::string& acc){ - acc.append("l"); - }, std::ref(accumulator)); - s.schedule(sd::scheduler_priority::highest, [](std::string& acc){ - acc.append("h"); - }, std::ref(accumulator)); - s.schedule(sd::scheduler_priority::above_normal, [](std::string& acc){ - acc.append("e"); - }, std::ref(accumulator)); - s.schedule(sd::scheduler_priority::normal, [](std::string& acc){ - acc.append("l"); - }, std::ref(accumulator)); - s.process_all_tasks(); - REQUIRE(accumulator == "hello"); - } -} diff --git a/scheduler_tests.cpp b/scheduler_tests.cpp new file mode 100644 index 0000000..f092eb9 --- /dev/null +++ b/scheduler_tests.cpp @@ -0,0 +1,114 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/promise.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018 Matvey Cherevko + ******************************************************************************/ + +#define CATCH_CONFIG_FAST_COMPILE +#include "catch.hpp" + +#include +#include +#include + +#include "scheduler.hpp" +namespace sd = scheduler_hpp; + +TEST_CASE("scheduler") { + { + sd::scheduler s; + auto pv0 = s.schedule([](){ + throw std::exception(); + }); + s.process_all_tasks(); + REQUIRE_THROWS_AS(pv0.get(), std::exception); + } + { + auto pv0 = sd::promise(); + { + sd::scheduler s; + pv0 = s.schedule([](){ + return 42; + }); + } + REQUIRE_THROWS_AS(pv0.get(), sd::scheduler_cancelled_exception); + } + { + sd::scheduler s; + int counter = 0; + s.schedule([&counter](){ ++counter; }); + REQUIRE(counter == 0); + s.process_all_tasks(); + REQUIRE(counter == 1); + s.schedule([&counter](){ ++counter; }); + s.schedule([&counter](){ ++counter; }); + REQUIRE(counter == 1); + s.process_all_tasks(); + REQUIRE(counter == 3); + } + { + sd::scheduler s; + int counter = 0; + for ( std::size_t i = 0; i < 50; ++i ) { + s.schedule([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + s.process_tasks_for(std::chrono::milliseconds(-1)); + s.process_tasks_for(std::chrono::milliseconds(0)); + REQUIRE(counter == 0); + s.process_tasks_for(std::chrono::milliseconds(100)); + REQUIRE(counter > 2); + REQUIRE(counter < 50); + s.process_tasks_for(std::chrono::seconds(3)); + REQUIRE(counter == 50); + } + { + sd::scheduler s; + int counter = 0; + for ( std::size_t i = 0; i < 50; ++i ) { + s.schedule([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + }); + } + + const auto time_now = [](){ + return std::chrono::high_resolution_clock::now(); + }; + + const auto b = time_now(); + + s.process_tasks_until(time_now() - std::chrono::milliseconds(1)); + s.process_tasks_until(time_now()); + REQUIRE(counter == 0); + s.process_tasks_until(time_now() + std::chrono::milliseconds(100)); + REQUIRE(time_now() - b > std::chrono::milliseconds(50)); + REQUIRE(counter > 2); + REQUIRE(counter < 50); + s.process_tasks_until(time_now() + std::chrono::seconds(3)); + REQUIRE(counter == 50); + } + { + sd::scheduler s; + std::string accumulator; + s.schedule(sd::scheduler_priority::lowest, [](std::string& acc){ + acc.append("o"); + }, std::ref(accumulator)); + s.schedule(sd::scheduler_priority::below_normal, [](std::string& acc){ + acc.append("l"); + }, std::ref(accumulator)); + s.schedule(sd::scheduler_priority::highest, [](std::string& acc){ + acc.append("h"); + }, std::ref(accumulator)); + s.schedule(sd::scheduler_priority::above_normal, [](std::string& acc){ + acc.append("e"); + }, std::ref(accumulator)); + s.schedule(sd::scheduler_priority::normal, [](std::string& acc){ + acc.append("l"); + }, std::ref(accumulator)); + s.process_all_tasks(); + REQUIRE(accumulator == "hello"); + } +} From ce63cb62043a1ce8673a3e55887114b9b5d07c8f Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 13 Dec 2018 00:53:28 +0700 Subject: [PATCH 3/3] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 456787f..c5cbbdd 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ ## Installation -[promise.hpp][promise] is a single header library. All you need to do is copy the header file into your project and include this file: +[promise.hpp][promise] is a header only library. All you need to do is copy the header files (invoke.hpp and promise.hpp) into your project and include this file: ```cpp #include "promise.hpp"