From: James Sedgwick Date: Tue, 21 Apr 2015 21:49:05 +0000 (-0700) Subject: fix collect for non-default-constructible types, for real this time X-Git-Tag: v0.36.0~18 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=23bf239f3c5930d3ff40b21d9195fa520a427abd;p=folly.git fix collect for non-default-constructible types, for real this time Summary: this was a fun one. Add a specialized implementation that builds up the results in a map with their indices and aggregates them into a vector at the end Test Plan: unit tests Reviewed By: hans@fb.com Subscribers: folly-diffs@, jsedgwick, yfeldblum, chalfant FB internal diff: D2002444 Signature: t1:2002444:1429642589:ee5aa5e8c461db97a28642b9887b3158df317813 --- diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h index ea8368e8..5bc6f58d 100644 --- a/folly/futures/Future-inl.h +++ b/folly/futures/Future-inl.h @@ -584,12 +584,44 @@ whenAll(InputIterator first, InputIterator last) { namespace detail { +template struct CollectContextHelper; + +template +struct CollectContextHelper::value>::type> { + static inline std::vector& getResults(std::vector& results) { + return results; + } +}; + +template +struct CollectContextHelper::value>::type> { + static inline std::vector getResults(std::vector& results) { + std::vector finalResults; + finalResults.reserve(results.size()); + for (auto& opt : results) { + finalResults.push_back(std::move(opt.value())); + } + return finalResults; + } +}; + template struct CollectContext { - explicit CollectContext(int n) : count(0), threw(false) {} + + typedef typename std::conditional< + std::is_default_constructible::value, + T, + Optional + >::type VecT; + + explicit CollectContext(int n) : count(0), threw(false) { + results.resize(n); + } Promise> p; - std::vector results; + std::vector results; std::atomic count; std::atomic_bool threw; @@ -600,7 +632,7 @@ struct CollectContext { } inline void setValue() { - p.setValue(std::move(results)); + p.setValue(CollectContextHelper::getResults(results)); } inline void addResult(int i, Try& t) { @@ -610,7 +642,9 @@ struct CollectContext { template <> struct CollectContext { + explicit CollectContext(int n) : count(0), threw(false) {} + Promise p; std::atomic count; std::atomic_bool threw; diff --git a/folly/futures/test/FutureTest.cpp b/folly/futures/test/FutureTest.cpp index 8efa6c64..edc9d301 100644 --- a/folly/futures/test/FutureTest.cpp +++ b/folly/futures/test/FutureTest.cpp @@ -879,6 +879,39 @@ TEST(Future, collect) { } } +struct NotDefaultConstructible { + NotDefaultConstructible() = delete; + NotDefaultConstructible(int arg) : i(arg) {} + int i; +}; + +// We have a specialized implementation for non-default-constructible objects +// Ensure that it works and preserves order +TEST(Future, collectNotDefaultConstructible) { + vector> promises(10); + vector> futures; + vector indices(10); + std::iota(indices.begin(), indices.end(), 0); + random_shuffle(indices.begin(), indices.end()); + + for (auto& p : promises) + futures.push_back(p.getFuture()); + + auto allf = collect(futures.begin(), futures.end()); + + for (auto i : indices) { + EXPECT_FALSE(allf.isReady()); + promises[i].setValue(NotDefaultConstructible(i)); + } + + EXPECT_TRUE(allf.isReady()); + int i = 0; + for (auto val : allf.value()) { + EXPECT_EQ(i, val.i); + i++; + } +} + TEST(Future, whenAny) { { vector> promises(10);