diff --git a/headers/3rdparty/promise.hpp/jobber.hpp b/headers/3rdparty/promise.hpp/jobber.hpp index 4a21c119..032f64f2 100644 --- a/headers/3rdparty/promise.hpp/jobber.hpp +++ b/headers/3rdparty/promise.hpp/jobber.hpp @@ -329,6 +329,7 @@ namespace jobber_hpp if ( task ) { lock.unlock(); task->run(); + lock.lock(); --active_task_count_; cond_var_.notify_all(); } diff --git a/headers/3rdparty/promise.hpp/promise.hpp b/headers/3rdparty/promise.hpp/promise.hpp index 84524d30..d4103726 100644 --- a/headers/3rdparty/promise.hpp/promise.hpp +++ b/headers/3rdparty/promise.hpp/promise.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -92,19 +93,30 @@ namespace promise_hpp public: storage() = default; - ~storage() noexcept(std::is_nothrow_destructible::value) { + ~storage() + noexcept(std::is_nothrow_destructible::value) + { if ( initialized_ ) { ptr_()->~T(); } } template < typename U > - void set(U&& value) noexcept(std::is_nothrow_constructible::value) { + void set(U&& value) + noexcept(std::is_nothrow_constructible::value) + { assert(!initialized_); ::new(ptr_()) T(std::forward(value)); initialized_ = true; } + T get() + noexcept(std::is_nothrow_move_constructible::value) + { + assert(initialized_); + return std::move(*ptr_()); + } + const T& value() const noexcept { assert(initialized_); return *ptr_(); @@ -245,6 +257,18 @@ namespace promise_hpp }); } + template < typename ResolveF > + auto then_tuple(ResolveF&& on_resolve) { + return then([ + f = std::forward(on_resolve) + ](auto&& v) mutable { + auto r = invoke_hpp::invoke( + std::forward(f), + std::forward(v)); + return make_tuple_promise(std::move(r)); + }); + } + template < typename ResolveF , typename RejectF , typename ResolveFR = invoke_hpp::invoke_result_t > @@ -637,6 +661,17 @@ namespace promise_hpp }); } + template < typename ResolveF > + auto then_tuple(ResolveF&& on_resolve) { + return then([ + f = std::forward(on_resolve) + ]() mutable { + auto r = invoke_hpp::invoke( + std::forward(f)); + return make_tuple_promise(std::move(r)); + }); + } + template < typename ResolveF , typename RejectF , typename ResolveFR = invoke_hpp::invoke_result_t > @@ -992,40 +1027,55 @@ namespace promise_hpp // make_all_promise // - template < typename Iter > - auto make_all_promise(Iter begin, Iter end) { - using child_promise_t = typename Iter::value_type; - using child_promise_value_t = typename child_promise_t::value_type; - using promise_out_container_t = std::vector; + namespace impl + { + template < typename ResultType > + class all_promise_context_t final : private detail::noncopyable { + public: + all_promise_context_t(std::size_t count) + : results_(count) {} - struct context_t { - promise_out_container_t results; - std::atomic_size_t counter = ATOMIC_VAR_INIT(0); - - context_t(std::size_t count) - : results(count) {} - - bool apply_result(std::size_t index, const child_promise_value_t& value) { - results[index] = value; - return ++counter == results.size(); + template < typename T > + bool apply_result(std::size_t index, T&& value) { + results_[index].set(std::forward(value)); + return ++counter_ == results_.size(); } + + std::vector get_results() { + std::vector ret; + ret.reserve(results_.size()); + for ( auto&& v : results_ ) { + ret.emplace_back(v.get()); + } + return ret; + } + private: + std::atomic_size_t counter_{0}; + std::vector> results_; }; + } + template < typename Iter + , typename SubPromise = typename Iter::value_type + , typename SubPromiseResult = typename SubPromise::value_type + , typename ResultPromiseValueType = std::vector > + promise + make_all_promise(Iter begin, Iter end) { if ( begin == end ) { - return make_resolved_promise(promise_out_container_t()); + return make_resolved_promise(ResultPromiseValueType()); } - - return make_promise([begin, end](auto&& resolver, auto&& rejector){ + return make_promise([begin, end](auto&& resolver, auto&& rejector){ std::size_t result_index = 0; - auto context = std::make_shared(std::distance(begin, end)); - for ( auto iter = begin; iter != end; ++iter, ++result_index ) { + auto context = std::make_shared>(std::distance(begin, end)); + for ( Iter iter = begin; iter != end; ++iter, ++result_index ) { (*iter).then([ context, resolver, result_index ](auto&& v) mutable { if ( context->apply_result(result_index, std::forward(v)) ) { - resolver(std::move(context->results)); + resolver(context->get_results()); } }).except(rejector); } @@ -1043,18 +1093,18 @@ namespace promise_hpp // make_any_promise // - template < typename Iter > + template < typename Iter + , typename SubPromise = typename Iter::value_type + , typename SubPromiseResult = typename SubPromise::value_type > auto make_any_promise(Iter begin, Iter end) { - using child_promise_t = typename Iter::value_type; - using child_promise_value_t = typename child_promise_t::value_type; - if ( begin == end ) { throw std::logic_error("at least one input promise must be provided for make_any_promise"); } - - return make_promise([begin, end](auto&& resolver, auto&& rejector){ - for ( auto iter = begin; iter != end; ++iter ) { - (*iter).then(resolver).except(rejector); + return make_promise([begin, end](auto&& resolver, auto&& rejector){ + for ( Iter iter = begin; iter != end; ++iter ) { + (*iter) + .then(resolver) + .except(rejector); } }); } @@ -1065,6 +1115,128 @@ namespace promise_hpp std::begin(container), std::end(container)); } + + // + // make_tuple_promise + // + + namespace impl + { + template < typename Tuple > + struct tuple_promise_result_impl {}; + + template < typename... Args > + struct tuple_promise_result_impl...>> { + using type = std::tuple; + }; + + template < typename Tuple > + struct tuple_promise_result { + using type = typename tuple_promise_result_impl>::type; + }; + + template < typename Tuple > + using tuple_promise_result_t = typename tuple_promise_result::type; + + template < typename... ResultTypes > + class tuple_promise_context_t { + public: + template < std::size_t N, typename T > + bool apply_result(T&& value) { + std::get(results_).set(std::forward(value)); + return ++counter_ == sizeof...(ResultTypes); + } + + std::tuple get_results() { + return get_results_impl( + std::make_index_sequence()); + } + private: + template < std::size_t... Is > + std::tuple get_results_impl(std::index_sequence) { + return std::make_tuple(std::get(results_).get()...); + } + private: + std::atomic_size_t counter_{0}; + std::tuple...> results_; + }; + + template < typename... ResultTypes > + using tuple_promise_context_ptr = std::shared_ptr< + tuple_promise_context_t>; + + template < std::size_t I + , typename Tuple + , typename Resolver + , typename Rejector + , typename... ResultTypes > + promise make_tuple_sub_promise_impl( + Tuple&& tuple, + Resolver&& resolver, + Rejector&& rejector, + const tuple_promise_context_ptr& context) + { + return std::get(tuple).then([ + context, + resolver + ](auto&& v) mutable { + if (context->template apply_result(std::forward(v))) { + resolver(context->get_results()); + } + }).except(rejector); + } + + template < typename Tuple + , std::size_t... Is + , typename ResultTuple = tuple_promise_result_t> > + std::enable_if_t< + sizeof...(Is) == 0, + promise> + make_tuple_promise_impl(Tuple&&, std::index_sequence) { + return make_resolved_promise(ResultTuple()); + } + + template < typename Tuple + , std::size_t... Is + , typename ResultTuple = tuple_promise_result_t> > + std::enable_if_t< + sizeof...(Is) != 0, + promise> + make_tuple_promise_impl(Tuple&& tuple, std::index_sequence) { + auto result = promise(); + + auto resolver = [result](auto&& v) mutable { + return result.resolve(std::forward(v)); + }; + + auto rejector = [result](auto&& e) mutable { + return result.reject(std::forward(e)); + }; + + try { + auto context = std::make_shared...>>(); + std::make_tuple(make_tuple_sub_promise_impl( + tuple, + resolver, + rejector, + context)...); + } catch (...) { + result.reject(std::current_exception()); + } + + return result; + } + } + + template < typename Tuple + , typename ResultTuple = impl::tuple_promise_result_t> > + promise + make_tuple_promise(Tuple&& tuple) { + return impl::make_tuple_promise_impl( + std::forward(tuple), + std::make_index_sequence::value>()); + } } namespace std diff --git a/headers/3rdparty/variant/config.hpp b/headers/3rdparty/variant/config.hpp index 4c93412f..1b0838b0 100644 --- a/headers/3rdparty/variant/config.hpp +++ b/headers/3rdparty/variant/config.hpp @@ -30,7 +30,7 @@ #define MPARK_BUILTIN_ADDRESSOF #endif -#if __has_builtin(__builtin_unreachable) +#if __has_builtin(__builtin_unreachable) || defined(__GNUC__) #define MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() #elif defined(_MSC_VER) #define MPARK_BUILTIN_UNREACHABLE __assume(false) diff --git a/modules/promise.hpp b/modules/promise.hpp index 5871ecea..04a5088d 160000 --- a/modules/promise.hpp +++ b/modules/promise.hpp @@ -1 +1 @@ -Subproject commit 5871ecea027ae745417bdfd33e8e296ad152c3cf +Subproject commit 04a5088d5b5785f7a2b239ca6b6f016ef4ddc574 diff --git a/modules/variant b/modules/variant index 7dd1e48c..6507d027 160000 --- a/modules/variant +++ b/modules/variant @@ -1 +1 @@ -Subproject commit 7dd1e48c33856a3dbee44c2a1ba8f2daa3665a58 +Subproject commit 6507d02740dd87f8c266fc6132149724f436b4a5 diff --git a/scripts/build_all.bat b/scripts/build_all.bat index 03705ec0..4d063dc1 100644 --- a/scripts/build_all.bat +++ b/scripts/build_all.bat @@ -1,7 +1,7 @@ @echo off set SCRIPT_DIR=%~dp0% -%SCRIPT_DIR%\build_debug.bat || goto :error -%SCRIPT_DIR%\build_release.bat || goto :error +call %SCRIPT_DIR%\build_debug.bat || goto :error +call %SCRIPT_DIR%\build_release.bat || goto :error goto :EOF