Skip to content

Commit

Permalink
Add mask_reads.
Browse files Browse the repository at this point in the history
  • Loading branch information
tmadden committed Sep 4, 2020
1 parent d566b56 commit a1f784c
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 1 deletion.
58 changes: 57 additions & 1 deletion src/alia/signals/adaptors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ mask_writes(Signal signal, WritabilityFlag writability_flag)
}

// disable_writes(s), where :s is a signal, yields a wrapper for :s where
// writes are disabled. Like mask_signal, this doesn't change the capabilities
// writes are disabled. Like mask_writes, this doesn't change the capabilities
// of :s.
template<class Signal>
auto
Expand All @@ -438,6 +438,62 @@ disable_writes(Signal s)
return mask_writes(std::move(s), false);
}

// mask_reads(signal, readality_flag) masks reads to :signal according to the
// value of :readality_flag.
//
// :readality_flag can be either a signal or a raw value. If it evaluates to
// true (in a boolean context), the mask evaluates to a signal equivalent to
// :signal. Otherwise, it evaluates to one with equivalent writing behavior but
// with reading disabled.
//
// Note that in either case, the masked version has the same capabilities as
// :signal.
//
template<class Primary, class Mask>
struct read_masking_signal
: signal_wrapper<read_masking_signal<Primary, Mask>, Primary>
{
read_masking_signal()
{
}
read_masking_signal(Primary primary, Mask mask)
: read_masking_signal::signal_wrapper(std::move(primary)),
mask_(std::move(mask))
{
}
bool
has_value() const
{
return mask_.has_value() && mask_.read() && this->wrapped_.has_value();
}

private:
Mask mask_;
};
template<class Signal, class ReadabilityFlag>
auto
make_read_masking_signal(Signal signal, ReadabilityFlag readability_flag)
{
return read_masking_signal<Signal, ReadabilityFlag>(
std::move(signal), std::move(readability_flag));
}
template<class Signal, class ReadabilityFlag>
auto
mask_reads(Signal signal, ReadabilityFlag readability_flag)
{
return make_read_masking_signal(
std::move(signal), signalize(std::move(readability_flag)));
}

// disable_reads(s), where :s is a signal, yields a wrapper for :s where reads
// are disabled. Like mask_reads, this doesn't change the capabilities of :s.
template<class Signal>
auto
disable_reads(Signal s)
{
return mask_reads(std::move(s), false);
}

// unwrap(signal), where :signal is a signal carrying a std::optional value,
// yields a signal that directly carries the value wrapped inside the optional.
template<class Wrapped>
Expand Down
69 changes: 69 additions & 0 deletions unit_tests/signals/adaptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,75 @@ TEST_CASE("mask/disable_writes", "[signals][adaptors]")
}
}

TEST_CASE("mask/disable_reads", "[signals][adaptors]")
{
// duplex signal, unmasked
{
int x = 1;
auto wrapped = direct(x);
auto s = mask_reads(wrapped, value(true));

typedef decltype(s) signal_t;
REQUIRE(signal_is_readable<signal_t>::value);
REQUIRE(signal_is_writable<signal_t>::value);

REQUIRE(signal_has_value(s));
REQUIRE(read_signal(s) == 1);
REQUIRE(s.value_id() == wrapped.value_id());
REQUIRE(signal_ready_to_write(s));
write_signal(s, 0);
REQUIRE(x == 0);
}

// duplex signal, masked (via disable_reads)
{
int x = 1;
auto wrapped = direct(x);
auto s = disable_reads(wrapped);

typedef decltype(s) signal_t;
REQUIRE(signal_is_readable<signal_t>::value);
REQUIRE(signal_is_writable<signal_t>::value);

REQUIRE(!signal_has_value(s));
REQUIRE(signal_ready_to_write(s));
write_signal(s, 0);
REQUIRE(x == 0);
}

// duplex signal, masked (via empty signal)
{
int x = 1;
auto wrapped = direct(x);
auto s = mask_reads(wrapped, empty<bool>());

typedef decltype(s) signal_t;
REQUIRE(signal_is_readable<signal_t>::value);
REQUIRE(signal_is_writable<signal_t>::value);

REQUIRE(!signal_has_value(s));
REQUIRE(signal_ready_to_write(s));
write_signal(s, 0);
REQUIRE(x == 0);
}

// duplex signal, masked (via raw flag)
{
int x = 1;
auto wrapped = direct(x);
auto s = mask_reads(wrapped, false);

typedef decltype(s) signal_t;
REQUIRE(signal_is_readable<signal_t>::value);
REQUIRE(signal_is_writable<signal_t>::value);

REQUIRE(!signal_has_value(s));
REQUIRE(signal_ready_to_write(s));
write_signal(s, 0);
REQUIRE(x == 0);
}
}

#if __cplusplus >= 201703L

#include <optional>
Expand Down

0 comments on commit a1f784c

Please sign in to comment.