Skip to content

Commit

Permalink
future of ref (#32)
Browse files Browse the repository at this point in the history
* future of ref

* msvc error

* msvc accomodation
  • Loading branch information
FrancoisChabot authored Jun 19, 2019
1 parent 1c71606 commit 3595c63
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 46 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ if(VAR_FUTURES_BUILD_TESTS)
tests/allocator.cpp
tests/async.cpp
tests/int.cpp
tests/future_of_reference.cpp
tests/misc.cpp
tests/void.cpp
)
Expand Down
2 changes: 1 addition & 1 deletion include/var_future/impl/promise.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ template <typename... Us>
void Basic_promise<Alloc, Ts...>::set_value(Us&&... vals) {
assert(storage_);

storage_->fullfill(std::make_tuple(std::forward<Us>(vals)...));
storage_->fullfill(fullfill_type(std::forward<Us>(vals)...));
storage_.reset();
}

Expand Down
4 changes: 2 additions & 2 deletions include/var_future/impl/then.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ class Future_then_handler : public Future_handler_base<QueueT, void, Ts...> {
if (err) {
do_fail(q, *err, std::move(dst), std::move(cb));
} else {
fullfill_type cb_args;
finish_to_fullfill<0, 0>(std::move(f), cb_args);

fullfill_type cb_args = finish_to_fullfill<std::tuple_size_v<finish_type>-1>(std::move(f));

do_fullfill(q, std::move(cb_args), std::move(dst), std::move(cb));
}
Expand Down
7 changes: 3 additions & 4 deletions include/var_future/impl/then_expect.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ class Future_then_expect_handler
}

static void do_fullfill(QueueT* q, fullfill_type v, dst_type dst, CbT cb) {
std::tuple<expected<Ts>...> cb_args;
fullfill_to_finish<0, 0>(std::move(v), cb_args);
auto cb_args = fullfill_to_finish<0, 0, std::tuple<expected<Ts>...>>(std::move(v));

do_finish(q, std::move(cb_args), std::move(dst), std::move(cb));
}
Expand All @@ -84,8 +84,7 @@ class Future_then_expect_handler
}

static void do_fail(QueueT* q, fail_type e, dst_type dst, CbT cb) {
std::tuple<expected<Ts>...> cb_args;
fail_to_expect<0>(e, cb_args);
auto cb_args = fail_to_expect<0, std::tuple<expected<Ts>...>>(e);
do_finish(q, std::move(cb_args), std::move(dst), std::move(cb));
}

Expand Down
6 changes: 2 additions & 4 deletions include/var_future/impl/then_finally_expect.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ class Future_finally_handler : public Future_handler_base<QueueT, void, Ts...> {
}

static void do_fullfill(QueueT* q, fullfill_type v, CbT cb) {
std::tuple<expected<Ts>...> cb_args;
fullfill_to_finish<0, 0>(std::move(v), cb_args);
auto cb_args = fullfill_to_finish<0, 0, std::tuple<expected<Ts>...>>(std::move(v));
do_finish(q, std::move(cb_args), std::move(cb));
}

Expand All @@ -63,8 +62,7 @@ class Future_finally_handler : public Future_handler_base<QueueT, void, Ts...> {
}

static void do_fail(QueueT* q, fail_type e, CbT cb) {
std::tuple<expected<Ts>...> cb_args;
fail_to_expect<0>(std::move(e), cb_args);
auto cb_args = fail_to_expect<0, std::tuple<expected<Ts>...>>(std::move(e));
do_finish(q, std::move(cb_args), std::move(cb));
}
};
Expand Down
87 changes: 52 additions & 35 deletions include/var_future/impl/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,50 +153,67 @@ using finish_type_t = std::tuple<expected<Ts>...>;
template <typename... Ts>
using fail_type_t = std::exception_ptr;

template <std::size_t i, std::size_t j, typename... Ts, typename... Us>
void finish_to_fullfill(std::tuple<Ts...>&& src, std::tuple<Us...>& dst) {
if constexpr (j >= sizeof...(Us)) {
(void)src;
(void)dst;
return;
} else {
using src_type = std::tuple_element_t<i, std::tuple<Ts...>>;
if constexpr (std::is_same_v<expected<void>, src_type>) {
finish_to_fullfill<i + 1, j>(std::move(src), dst);
} else {
assert(std::get<i>(src).has_value());
std::get<j>(dst) = std::move(*std::get<i>(src));
finish_to_fullfill<i + 1, j + 1>(std::move(src), dst);
template <std::size_t i, typename... Ts>
auto finish_to_fullfill(std::tuple<Ts...>&& src) {
(void)src;
assert(std::get<i>(src).has_value());

using val_t = typename std::tuple_element_t<i, std::tuple<Ts...>>::value_type;
if constexpr(std::is_same_v<void, val_t>) {
if constexpr (i == 0) {
return std::tuple<>();
}
else {
return finish_to_fullfill<i-1>(std::move(src));
}
}
else {
auto val_tup = std::tuple<val_t>(std::move(*std::get<i>(src)));
if constexpr (i == 0) {
return val_tup;
}
else {
return std::tuple_cat(finish_to_fullfill<i-1>(std::move(src)), std::move(val_tup));
}
}
}

template <std::size_t i, std::size_t j, typename... Ts, typename... Us>
void fullfill_to_finish(std::tuple<Ts...>&& src, std::tuple<Us...>& dst) {
static_assert(sizeof...(Ts) <= sizeof...(Us));

if constexpr (j >= sizeof...(Us)) {
(void)src;
(void)dst;
return;
} else {
using dst_type = std::tuple_element_t<j, std::tuple<Us...>>;
if constexpr (std::is_same_v<expected<void>, dst_type>) {
std::get<j>(dst) = {};
fullfill_to_finish<i, j + 1>(std::move(src), dst);
} else {
std::get<j>(dst) = std::move(std::get<i>(src));
fullfill_to_finish<i + 1, j + 1>(std::move(src), dst);
template <std::size_t i, std::size_t j, typename Result_t, typename... Ts>
auto fullfill_to_finish(std::tuple<Ts...>&& src) {
(void)src;
using dst_t = std::tuple_element_t<i, Result_t>;
if constexpr(std::is_same_v<expected<void>, dst_t>) {
if constexpr(i == std::tuple_size_v<Result_t> - 1) {
return std::tuple<expected<void>>();
}
else{
return std::tuple_cat(std::tuple<expected<void>>(), fullfill_to_finish<i+1, j, Result_t>(std::move(src)));
}
}
else {
using val_t = expected<std::tuple_element_t<j, std::tuple<Ts...>>>;
std::tuple<val_t> tup_val(std::move(std::get<j>(src)));

if constexpr(i == std::tuple_size_v<Result_t> - 1) {
return tup_val;
}
else {
auto recur = fullfill_to_finish<i+1, j+1, Result_t>(std::move(src));
return std::tuple_cat(tup_val, recur);
}
}
}

template <std::size_t i, typename... Ts>
void fail_to_expect(const std::exception_ptr& src, std::tuple<Ts...>& dst) {
if constexpr (i >= sizeof...(Ts)) {
return;
template <std::size_t i, typename T>
auto fail_to_expect(const std::exception_ptr& src) {
(void)src;
using element_t = std::tuple_element_t<i, T>;
std::tuple<element_t> val_tup(unexpected{src});

if constexpr (i >= std::tuple_size_v<T>-1) {
return val_tup;
} else {
std::get<i>(dst) = aom::unexpected{src};
return std::tuple_cat(val_tup, fail_to_expect<i+1, T>(src));
}
}

Expand Down
38 changes: 38 additions & 0 deletions tests/future_of_reference.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2019 Age of Minds inc.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>
#include "var_future/future.h"

#include "gtest/gtest.h"

#include <queue>

using namespace aom;

TEST(Ref_Future, simple_case) {

Promise<std::reference_wrapper<int>> p;
Future<std::reference_wrapper<int>> f = p.get_future();

int var = 0;

p.set_value(var);

f.finally([](expected<std::reference_wrapper<int>> dst) {
(*dst).get() = 4;
});

EXPECT_EQ(var, 4);
}

0 comments on commit 3595c63

Please sign in to comment.