2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-31 06:26:18 +00:00

Try to use const-ref better in rpl.

This commit is contained in:
John Preston
2017-09-14 22:27:41 +03:00
parent c302219f9e
commit fbcd5e2f1e
17 changed files with 171 additions and 61 deletions

View File

@@ -25,6 +25,28 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include <rpl/lifetime.h>
namespace rpl {
namespace details {
template <typename Arg>
const Arg &const_ref_val();
template <
typename Func,
typename Arg,
typename = decltype(std::declval<Func>()(const_ref_val<Arg>()))>
void const_ref_call_helper(Func &handler, const Arg &value, int) {
handler(value);
}
template <
typename Func,
typename Arg>
void const_ref_call_helper(Func &handler, const Arg &value, double) {
auto copy = value;
handler(std::move(copy));
}
} // namespace details
struct no_value {
no_value() = delete;
@@ -57,15 +79,27 @@ public:
bool put_next(Value &&value) const;
bool put_next_copy(const Value &value) const;
bool put_next_forward(Value &&value) const {
return put_next(std::move(value));
}
bool put_next_forward(const Value &value) const {
return put_next_copy(value);
}
void put_error(Error &&error) const;
void put_error_copy(const Error &error) const;
void put_error_forward(Error &&error) const {
return put_error(std::move(error));
}
void put_error_forward(const Error &error) const {
return put_error_copy(error);
}
void put_done() const;
void add_lifetime(lifetime &&lifetime) const;
template <typename Type, typename... Args>
Type *make_state(Args&& ...args) const;
void terminate() const;
bool operator==(const consumer &other) const {
@@ -108,7 +142,9 @@ template <typename Value, typename Error>
class consumer<Value, Error>::abstract_consumer_instance {
public:
virtual bool put_next(Value &&value) = 0;
virtual bool put_next_copy(const Value &value) = 0;
virtual void put_error(Error &&error) = 0;
virtual void put_error_copy(const Error &error) = 0;
virtual void put_done() = 0;
void add_lifetime(lifetime &&lifetime);
@@ -141,7 +177,9 @@ public:
}
bool put_next(Value &&value) override;
bool put_next_copy(const Value &value) override;
void put_error(Error &&error) override;
void put_error_copy(const Error &error) override;
void put_done() override;
private:
@@ -197,8 +235,13 @@ bool consumer<Value, Error>::put_next(Value &&value) const {
template <typename Value, typename Error>
bool consumer<Value, Error>::put_next_copy(const Value &value) const {
auto copy = value;
return put_next(std::move(copy));
if (_instance) {
if (_instance->put_next_copy(value)) {
return true;
}
_instance = nullptr;
}
return false;
}
template <typename Value, typename Error>
@@ -210,8 +253,9 @@ void consumer<Value, Error>::put_error(Error &&error) const {
template <typename Value, typename Error>
void consumer<Value, Error>::put_error_copy(const Error &error) const {
auto copy = error;
return put_error(std::move(error));
if (_instance) {
std::exchange(_instance, nullptr)->put_error_copy(error);
}
}
template <typename Value, typename Error>
@@ -293,6 +337,21 @@ bool consumer<Value, Error>::consumer_instance<OnNext, OnError, OnDone>::put_nex
return true;
}
template <typename Value, typename Error>
template <typename OnNext, typename OnError, typename OnDone>
bool consumer<Value, Error>::consumer_instance<OnNext, OnError, OnDone>::put_next_copy(
const Value &value) {
std::unique_lock<std::mutex> lock(this->_mutex);
if (this->_terminated) {
return false;
}
auto handler = this->_next;
lock.unlock();
details::const_ref_call_helper(handler, value, 0);
return true;
}
template <typename Value, typename Error>
template <typename OnNext, typename OnError, typename OnDone>
void consumer<Value, Error>::consumer_instance<OnNext, OnError, OnDone>::put_error(
@@ -307,6 +366,20 @@ void consumer<Value, Error>::consumer_instance<OnNext, OnError, OnDone>::put_err
}
}
template <typename Value, typename Error>
template <typename OnNext, typename OnError, typename OnDone>
void consumer<Value, Error>::consumer_instance<OnNext, OnError, OnDone>::put_error_copy(
const Error &error) {
std::unique_lock<std::mutex> lock(this->_mutex);
if (!this->_terminated) {
auto handler = std::move(this->_error);
lock.unlock();
details::const_ref_call_helper(handler, error, 0);
this->terminate();
}
}
template <typename Value, typename Error>
template <typename OnNext, typename OnError, typename OnDone>
void consumer<Value, Error>::consumer_instance<OnNext, OnError, OnDone>::put_done() {

View File

@@ -37,13 +37,13 @@ public:
base::optional<Value>
>();
return std::move(initial).start(
[consumer, previous](Value &&value) {
[consumer, previous](auto &&value) {
if (!(*previous) || (**previous) != value) {
*previous = value;
consumer.put_next(std::move(value));
consumer.put_next_forward(std::forward<decltype(value)>(value));
}
}, [consumer](Error &&error) {
consumer.put_error(std::move(error));
}, [consumer](auto &&error) {
consumer.put_error_forward(std::forward<decltype(error)>(error));
}, [consumer] {
consumer.put_done();
});

View File

@@ -37,10 +37,13 @@ public:
event_stream();
event_stream(event_stream &&other);
void fire(Value &&value);
template <typename OtherValue>
void fire_forward(OtherValue &&value);
void fire(Value &&value) {
return fire_forward(std::move(value));
}
void fire_copy(const Value &value) {
auto copy = value;
fire(std::move(copy));
return fire_forward(value);
}
producer<Value, no_error> events() const;
producer<Value, no_error> events_starting_with(
@@ -49,8 +52,7 @@ public:
}
producer<Value, no_error> events_starting_with_copy(
const Value &value) const {
auto copy = value;
return events_starting_with(std::move(copy));
return single(value) | then(events());
}
~event_stream();
@@ -72,7 +74,8 @@ event_stream<Value>::event_stream(event_stream &&other)
}
template <typename Value>
void event_stream<Value>::fire(Value &&value) {
template <typename OtherValue>
void event_stream<Value>::fire_forward(OtherValue &&value) {
if (!_consumers) {
return;
}
@@ -87,8 +90,8 @@ void event_stream<Value>::fire(Value &&value) {
return !consumer.put_next_copy(value);
});
// Move value for the last consumer.
if (prev->put_next(std::move(value))) {
// Perhaps move value for the last consumer.
if (prev->put_next_forward(std::forward<OtherValue>(value))) {
if (removeFrom != prev) {
*removeFrom++ = std::move(*prev);
} else {
@@ -152,8 +155,8 @@ event_stream<Value>::~event_stream() {
template <typename Value>
inline auto to_stream(event_stream<Value> &stream) {
return on_next([&stream](Value &&value) {
stream.fire(std::move(value));
return on_next([&stream](auto &&value) {
stream.fire_forward(std::forward<decltype(value)>(value));
});
}

View File

@@ -45,13 +45,13 @@ public:
[
consumer,
predicate = std::move(predicate)
](Value &&value) {
](auto &&value) {
const auto &immutable = value;
if (predicate(immutable)) {
consumer.put_next(std::move(value));
consumer.put_next_forward(std::forward<decltype(value)>(value));
}
}, [consumer](Error &&error) {
consumer.put_error(std::move(error));
}, [consumer](auto &&error) {
consumer.put_error_forward(std::forward<decltype(error)>(error));
}, [consumer] {
consumer.put_done();
});

View File

@@ -40,10 +40,10 @@ public:
[consumer, state](rpl::producer<Value, Error> &&inner) {
state->finished = false;
state->alive = std::move(inner).start(
[consumer](Value &&value) {
consumer.put_next(std::move(value));
}, [consumer](Error &&error) {
consumer.put_error(std::move(error));
[consumer](auto &&value) {
consumer.put_next_forward(std::forward<decltype(value)>(value));
}, [consumer](auto &&error) {
consumer.put_error_forward(std::forward<decltype(error)>(error));
}, [consumer, state] {
if (state->finished) {
consumer.put_done();
@@ -51,8 +51,8 @@ public:
state->finished = true;
}
});
}, [consumer](Error &&error) {
consumer.put_error(std::move(error));
}, [consumer](auto &&error) {
consumer.put_error_forward(std::forward<decltype(error)>(error));
}, [consumer, state] {
if (state->finished) {
consumer.put_done();

View File

@@ -25,6 +25,40 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
namespace rpl {
namespace details {
template <
typename Transform,
typename NewValue,
typename Error,
typename Value>
class map_transform_helper {
public:
map_transform_helper(
const consumer<NewValue, Error> &consumer,
Transform &&transform)
: _transform(std::move(transform))
, _consumer(consumer) {
}
template <
typename OtherValue,
typename = std::enable_if_t<
std::is_rvalue_reference_v<OtherValue&&>>>
void operator()(OtherValue &&value) const {
_consumer.put_next_forward(_transform(std::move(value)));
}
template <
typename OtherValue,
typename = decltype(
std::declval<Transform>()(const_ref_val<OtherValue>()))>
void operator()(const OtherValue &value) const {
_consumer.put_next_forward(_transform(value));
}
private:
consumer<NewValue, Error> _consumer;
Transform _transform;
};
template <typename Transform>
class map_helper {
public:
@@ -46,13 +80,11 @@ public:
transform = std::move(_transform)
](const consumer<NewValue, Error> &consumer) mutable {
return std::move(initial).start(
[
consumer,
transform = std::move(transform)
](Value &&value) {
consumer.put_next(transform(std::move(value)));
}, [consumer](Error &&error) {
consumer.put_error(std::move(error));
map_transform_helper<Transform, NewValue, Error, Value>(
consumer,
std::move(transform)
), [consumer](auto &&error) {
consumer.put_error_forward(std::forward<decltype(error)>(error));
}, [consumer] {
consumer.put_done();
});

View File

@@ -34,19 +34,19 @@ auto then(producer<Value, Error> &&following) {
following = std::move(following)
](const consumer<Value, Error> &consumer) mutable {
return std::move(initial).start(
[consumer](Value &&value) {
consumer.put_next(std::move(value));
}, [consumer](Error &&error) {
consumer.put_error(std::move(error));
[consumer](auto &&value) {
consumer.put_next_forward(std::forward<decltype(value)>(value));
}, [consumer](auto &&error) {
consumer.put_error_forward(std::forward<decltype(error)>(error));
}, [
consumer,
following = std::move(following)
]() mutable {
consumer.add_lifetime(std::move(following).start(
[consumer](Value &&value) {
consumer.put_next(std::move(value));
}, [consumer](Error &&error) {
consumer.put_error(std::move(error));
[consumer](auto &&value) {
consumer.put_next_forward(std::forward<decltype(value)>(value));
}, [consumer](auto &&error) {
consumer.put_error_forward(std::forward<decltype(error)>(error));
}, [consumer] {
consumer.put_done();
}));