Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions benchmarks/src/vector_bool_transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ void common_args(auto bm) {

BENCHMARK(transform_two_inputs_aligned<logical_and<>>)->Apply(common_args);
BENCHMARK(transform_two_inputs_aligned<logical_or<>>)->Apply(common_args);
BENCHMARK(transform_two_inputs_aligned<less<>>)->Apply(common_args);
BENCHMARK(transform_one_input_aligned<logical_not<>>)->Apply(common_args);

BENCHMARK_MAIN();
7 changes: 4 additions & 3 deletions stl/inc/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -4118,7 +4118,8 @@ _CONSTEXPR20 _OutIt transform(const _InIt _First, const _InIt _Last, _OutIt _Des
const auto _ULast = _STD _Get_unwrapped(_Last);
auto _UDest = _STD _Get_unwrapped_n(_Dest, _STD _Idl_distance<_InIt>(_UFirst, _ULast));

if constexpr (_Is_vb_iterator<_InIt> && _Is_vb_iterator<_OutIt, true> && !is_same_v<_Map_vb_functor_t<_Fn>, void>) {
if constexpr (_Is_vb_iterator<decltype(_UFirst)> && _Is_vb_iterator<decltype(_UDest), true>
&& !is_void_v<_Map_vb_functor_t<_Fn>>) {
if (_UFirst._Myoff == 0 && _UDest._Myoff == 0) {
_UDest = _Transform_vbool_aligned(_UFirst, _ULast, _UDest, _Map_vb_functor_t<_Fn>{});
_STD _Seek_wrapped(_Dest, _UDest);
Expand Down Expand Up @@ -4150,8 +4151,8 @@ _CONSTEXPR20 _OutIt transform(
auto _UFirst2 = _STD _Get_unwrapped_n(_First2, _Count);
auto _UDest = _STD _Get_unwrapped_n(_Dest, _Count);

if constexpr (_Is_vb_iterator<_InIt1> && _Is_vb_iterator<_InIt2> && _Is_vb_iterator<_OutIt, true>
&& !is_same_v<_Map_vb_functor_t<_Fn>, void>) {
if constexpr (_Is_vb_iterator<decltype(_UFirst1)> && _Is_vb_iterator<decltype(_UFirst2)>
&& _Is_vb_iterator<decltype(_UDest), true> && !is_void_v<_Map_vb_functor_t<_Fn>>) {
if (_UFirst1._Myoff == 0 && _UFirst2._Myoff == 0 && _UDest._Myoff == 0) {
_UDest = _Transform_vbool_aligned(_UFirst1, _ULast1, _UFirst2, _UDest, _Map_vb_functor_t<_Fn>{});
_STD _Seek_wrapped(_Dest, _UDest);
Expand Down
62 changes: 61 additions & 1 deletion stl/inc/functional
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,48 @@ struct _Bit_xnor {
using is_transparent = int;
};

struct _Bit_imply {
template <class _Ty1, class _Ty2>
_NODISCARD constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const //
-> decltype(~_STD forward<_Ty1>(_Left) | _STD forward<_Ty2>(_Right)) {
return ~_STD forward<_Ty1>(_Left) | _STD forward<_Ty2>(_Right);
}

using is_transparent = int;
};

struct _Bit_cimply {
template <class _Ty1, class _Ty2>
_NODISCARD constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const //
-> decltype(_STD forward<_Ty1>(_Left) | ~_STD forward<_Ty2>(_Right)) {
return _STD forward<_Ty1>(_Left) | ~_STD forward<_Ty2>(_Right);
}

using is_transparent = int;
};

struct _Bit_nimply {
template <class _Ty1, class _Ty2>
_NODISCARD constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const //
-> decltype(_STD forward<_Ty1>(_Left) & ~_STD forward<_Ty2>(_Right)) {
return _STD forward<_Ty1>(_Left) & ~_STD forward<_Ty2>(_Right);
}

using is_transparent = int;
};

struct _Bit_cnimply {
template <class _Ty1, class _Ty2>
_NODISCARD constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const //
-> decltype(~_STD forward<_Ty1>(_Left) & _STD forward<_Ty2>(_Right)) {
return ~_STD forward<_Ty1>(_Left) & _STD forward<_Ty2>(_Right);
}

using is_transparent = int;
};

template <class _Ty>
constexpr bool _Is_vbool_functor_arg = is_same_v<_Ty, void> || is_integral_v<_Ty>;
constexpr bool _Is_vbool_functor_arg = is_void_v<_Ty> || is_integral_v<_Ty>;

template <class _Ty>
struct _Map_vb_functor<logical_and<_Ty>> {
Expand Down Expand Up @@ -306,6 +346,26 @@ struct _Map_vb_functor<equal_to<_Ty>> {
using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_xnor, void>;
};

template <class _Ty>
struct _Map_vb_functor<less_equal<_Ty>> {
using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_imply, void>;
};

template <class _Ty>
struct _Map_vb_functor<greater_equal<_Ty>> {
using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_cimply, void>;
};

template <class _Ty>
struct _Map_vb_functor<less<_Ty>> {
using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_cnimply, void>;
};

template <class _Ty>
struct _Map_vb_functor<greater<_Ty>> {
using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_nimply, void>;
};

template <class _Ty>
struct _Map_vb_functor<logical_not<_Ty>> {
using type = conditional_t<_Is_vbool_functor_arg<_Ty>, bit_not<>, void>;
Expand Down
45 changes: 45 additions & 0 deletions tests/std/tests/GH_000625_vector_bool_optimization/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,20 @@ CONSTEXPR20 void test_transform_helper(const size_t length) {
bool or_expected_raw[size(source_raw)];
bool xor_expected_raw[size(source_raw)];
bool xnor_expected_raw[size(source_raw)];
bool l_expected_raw[size(source_raw)];
bool le_expected_raw[size(source_raw)];
bool g_expected_raw[size(source_raw)];
bool ge_expected_raw[size(source_raw)];
bool not_expected_raw[size(source_raw)];

transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(and_expected_raw), logical_and<>{});
transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(or_expected_raw), logical_or<>{});
transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(xor_expected_raw), not_equal_to<>{});
transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(xnor_expected_raw), equal_to<>{});
transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(l_expected_raw), less<>{});
transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(le_expected_raw), less_equal<>{});
transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(g_expected_raw), greater<>{});
transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(ge_expected_raw), greater_equal<>{});
transform(begin(source_raw), end(source_raw), begin(not_expected_raw), logical_not<>{});

const vector<bool> source1(source_raw, source_raw + length);
Expand All @@ -91,18 +99,30 @@ CONSTEXPR20 void test_transform_helper(const size_t length) {
vector<bool> or_expected(or_expected_raw, or_expected_raw + length);
vector<bool> xor_expected(xor_expected_raw, xor_expected_raw + length);
vector<bool> xnor_expected(xnor_expected_raw, xnor_expected_raw + length);
vector<bool> less_expected(l_expected_raw, l_expected_raw + length);
vector<bool> less_equal_expected(le_expected_raw, le_expected_raw + length);
vector<bool> greater_expected(g_expected_raw, g_expected_raw + length);
vector<bool> greater_equal_expected(ge_expected_raw, ge_expected_raw + length);
vector<bool> not_expected(not_expected_raw, not_expected_raw + length);

and_expected.resize(length + 3, false);
or_expected.resize(length + 3, false);
xor_expected.resize(length + 3, false);
xnor_expected.resize(length + 3, false);
less_expected.resize(length + 3, false);
less_equal_expected.resize(length + 3, false);
greater_expected.resize(length + 3, false);
greater_equal_expected.resize(length + 3, false);
not_expected.resize(length + 3, false);

vector<bool> and_actual(length + 3);
vector<bool> or_actual(length + 3);
vector<bool> xor_actual(length + 3);
vector<bool> xnor_actual(length + 3);
vector<bool> less_actual(length + 3);
vector<bool> less_equal_actual(length + 3);
vector<bool> greater_actual(length + 3);
vector<bool> greater_equal_actual(length + 3);
vector<bool> not_actual(length + 3);

// Also test combinations of vector<bool>::iterator and vector<bool>::const_iterator for the inputs.
Expand Down Expand Up @@ -157,6 +177,31 @@ CONSTEXPR20 void test_transform_helper(const size_t length) {
// bit_xnor doesn't exist in the Standard
}

{
const auto less_ret = transform(cfirst1, clast1, cfirst2, less_actual.begin(), less<>{});
assert(less_actual == less_expected);
assert(less_ret == less_actual.begin() + length);
}

{
const auto less_equal_ret = transform(cfirst1, clast1, cfirst2, less_equal_actual.begin(), less_equal<>{});
assert(less_equal_actual == less_equal_expected);
assert(less_equal_ret == less_equal_actual.begin() + length);
}

{
const auto greater_ret = transform(cfirst1, clast1, cfirst2, greater_actual.begin(), greater<>{});
assert(greater_actual == greater_expected);
assert(greater_ret == greater_actual.begin() + length);
}

{
const auto greater_equal_ret =
transform(cfirst1, clast1, cfirst2, greater_equal_actual.begin(), greater_equal<>{});
assert(greater_equal_actual == greater_equal_expected);
assert(greater_equal_ret == greater_equal_actual.begin() + length);
}

{
auto not_ret = transform(first1, last1, not_actual.begin(), logical_not<>{});
assert(not_actual == not_expected);
Expand Down