diff --git a/benchmarks/src/vector_bool_transform.cpp b/benchmarks/src/vector_bool_transform.cpp index 4f54882c18..585db6ead4 100644 --- a/benchmarks/src/vector_bool_transform.cpp +++ b/benchmarks/src/vector_bool_transform.cpp @@ -48,6 +48,7 @@ void common_args(auto bm) { BENCHMARK(transform_two_inputs_aligned>)->Apply(common_args); BENCHMARK(transform_two_inputs_aligned>)->Apply(common_args); +BENCHMARK(transform_two_inputs_aligned>)->Apply(common_args); BENCHMARK(transform_one_input_aligned>)->Apply(common_args); BENCHMARK_MAIN(); diff --git a/stl/inc/algorithm b/stl/inc/algorithm index cb5511d574..3d32a2704c 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -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 && _Is_vb_iterator + && !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); @@ -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 && _Is_vb_iterator + && _Is_vb_iterator && !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); diff --git a/stl/inc/functional b/stl/inc/functional index 48feddd89c..6530b97c91 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -268,8 +268,48 @@ struct _Bit_xnor { using is_transparent = int; }; +struct _Bit_imply { + template + _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 + _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 + _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 + _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 -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 struct _Map_vb_functor> { @@ -306,6 +346,26 @@ struct _Map_vb_functor> { using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_xnor, void>; }; +template +struct _Map_vb_functor> { + using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_imply, void>; +}; + +template +struct _Map_vb_functor> { + using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_cimply, void>; +}; + +template +struct _Map_vb_functor> { + using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_cnimply, void>; +}; + +template +struct _Map_vb_functor> { + using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_nimply, void>; +}; + template struct _Map_vb_functor> { using type = conditional_t<_Is_vbool_functor_arg<_Ty>, bit_not<>, void>; diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp index 41e73cff35..6e14badc9d 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -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 source1(source_raw, source_raw + length); @@ -91,18 +99,30 @@ CONSTEXPR20 void test_transform_helper(const size_t length) { vector or_expected(or_expected_raw, or_expected_raw + length); vector xor_expected(xor_expected_raw, xor_expected_raw + length); vector xnor_expected(xnor_expected_raw, xnor_expected_raw + length); + vector less_expected(l_expected_raw, l_expected_raw + length); + vector less_equal_expected(le_expected_raw, le_expected_raw + length); + vector greater_expected(g_expected_raw, g_expected_raw + length); + vector greater_equal_expected(ge_expected_raw, ge_expected_raw + length); vector 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 and_actual(length + 3); vector or_actual(length + 3); vector xor_actual(length + 3); vector xnor_actual(length + 3); + vector less_actual(length + 3); + vector less_equal_actual(length + 3); + vector greater_actual(length + 3); + vector greater_equal_actual(length + 3); vector not_actual(length + 3); // Also test combinations of vector::iterator and vector::const_iterator for the inputs. @@ -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);