Commit c0b40097 authored by Aaryaman Sagar's avatar Aaryaman Sagar Committed by Facebook GitHub Bot

Handle std::vector<bool> in FanoutChannel

Summary:
std::vector<bool>::iterator::operator* returns a temporary proxy bool accessor
in many implementations.  So range-based for loops over it don't work if we
assume non-const lvalue-ref binding, eg.
```
for (auto& ref : vectorBools) { ... }
```
Won't compile.  Silly std::vector<bool>.

Reviewed By: SmithAndr

Differential Revision: D30833990

fbshipit-source-id: cb8d53a48eb2a40587911ad2f0c50b99a472a59c
parent 7d8dfb91
...@@ -154,7 +154,10 @@ class FanoutChannelProcessor : public IFanoutChannelProcessor<TValue> { ...@@ -154,7 +154,10 @@ class FanoutChannelProcessor : public IFanoutChannelProcessor<TValue> {
getInitialValues = std::move(getInitialValues)]() mutable { getInitialValues = std::move(getInitialValues)]() mutable {
if (getInitialValues) { if (getInitialValues) {
auto initialValues = getInitialValues(); auto initialValues = getInitialValues();
for (auto& value : initialValues) { // use auto&& to deal with the annoying std::vector<bool>, for which
// auto& will not compile because std::vector<bool>::iterator::operator*
// returns a temporary for many implementations
for (auto&& value : initialValues) {
sender->senderPush(std::move(value)); sender->senderPush(std::move(value));
} }
} }
......
...@@ -33,17 +33,19 @@ class FanoutChannelFixture : public Test { ...@@ -33,17 +33,19 @@ class FanoutChannelFixture : public Test {
~FanoutChannelFixture() { executor_.drain(); } ~FanoutChannelFixture() { executor_.drain(); }
using TCallback = StrictMock<MockNextCallback<int>>; template <typename T>
using Callback = StrictMock<MockNextCallback<T>>;
std::pair<ChannelCallbackHandle, TCallback*> processValues( template <typename T>
Receiver<int> receiver) { std::pair<ChannelCallbackHandle, Callback<T>*> processValues(
auto callback = std::make_unique<TCallback>(); Receiver<T> receiver) {
auto callback = std::make_unique<Callback<T>>();
auto callbackPtr = callback.get(); auto callbackPtr = callback.get();
auto handle = consumeChannelWithCallback( auto handle = consumeChannelWithCallback(
std::move(receiver), std::move(receiver),
&executor_, &executor_,
[cbk = std::move(callback)]( [cbk = std::move(callback)](
folly::Try<int> resultTry) mutable -> folly::coro::Task<bool> { folly::Try<T> resultTry) mutable -> folly::coro::Task<bool> {
(*cbk)(std::move(resultTry)); (*cbk)(std::move(resultTry));
co_return true; co_return true;
}); });
...@@ -183,6 +185,41 @@ TEST_F(FanoutChannelFixture, ReceiversCancelled) { ...@@ -183,6 +185,41 @@ TEST_F(FanoutChannelFixture, ReceiversCancelled) {
EXPECT_FALSE(fanoutChannel.anyReceivers()); EXPECT_FALSE(fanoutChannel.anyReceivers());
} }
TEST_F(FanoutChannelFixture, VectorBool) {
auto [inputReceiver, sender] = Channel<bool>::create();
auto fanoutChannel =
createFanoutChannel(std::move(inputReceiver), &executor_);
auto [handle1, callback1] = processValues(fanoutChannel.getNewReceiver(
[] { return toVector(true); } /* getInitialValues */));
auto [handle2, callback2] = processValues(fanoutChannel.getNewReceiver(
[] { return toVector(false); } /* getInitialValues */));
EXPECT_CALL(*callback1, onValue(true));
EXPECT_CALL(*callback2, onValue(false));
executor_.drain();
EXPECT_TRUE(fanoutChannel.anyReceivers());
EXPECT_CALL(*callback1, onValue(true));
EXPECT_CALL(*callback2, onValue(true));
EXPECT_CALL(*callback1, onValue(false));
EXPECT_CALL(*callback2, onValue(false));
EXPECT_CALL(*callback1, onClosed());
EXPECT_CALL(*callback2, onClosed());
sender.write(true);
sender.write(false);
executor_.drain();
std::move(sender).close();
executor_.drain();
EXPECT_FALSE(fanoutChannel.anyReceivers());
}
class FanoutChannelFixtureStress : public Test { class FanoutChannelFixtureStress : public Test {
protected: protected:
FanoutChannelFixtureStress() FanoutChannelFixtureStress()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment