VCTR
Loading...
Searching...
No Matches
BinaryCaseDistinction.h
1/*
2 ==============================================================================
3 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
5 Copyright 2026 - by sonible GmbH.
6
7 This file is part of VCTR - Versatile Container Templates Reconceptualized.
8
9 VCTR is free software: you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License version 3
11 only, as published by the Free Software Foundation.
12
13 VCTR is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License version 3 for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 version 3 along with VCTR. If not, see <https://www.gnu.org/licenses/>.
20 ==============================================================================
21*/
22
23namespace vctr
24{
25
33template <const auto& caseTrueExpression, CompareOp op, is::constant Threshold, const auto& caseFalseExpression>
35{
36 static constexpr auto& caseTrue = caseTrueExpression;
37 static constexpr auto& caseFalse = caseFalseExpression;
38
39 static constexpr auto compareOp = op;
40
41 using ThresholdValue = Threshold;
42};
43}
44
45namespace vctr::is
46{
47
49template <class T>
50concept binaryCaseDistinctionConfig = requires (const T& t) { [] <const auto& b, CompareOp op, class Th, const auto& a> (const BinaryCaseDistinctionConfig<b, op, Th, a>&) {} (t); };
51
52}
53
54namespace vctr::expressions
55{
56template <size_t extent, class SrcType, is::binaryCaseDistinctionConfig CaseConfig>
57requires is::comparableBy<ValueType<SrcType>, CaseConfig::compareOp>
59{
60public:
61 using value_type = ValueType<SrcType>;
62
63private:
64 using Expression = ExpressionTypes<value_type, SrcType>;
65 SrcType src;
66
67 using CaseTrueExpressionChainBuilder = decltype (CaseConfig::caseTrue << std::declval<SrcType>());
68 using CaseFalseExpressionChainBuilder = decltype (CaseConfig::caseFalse << std::declval<SrcType>());
69
70 CaseTrueExpressionChainBuilder caseTrue;
71 CaseFalseExpressionChainBuilder caseFalse;
72
73 static constexpr value_type threshold = CaseConfig::ThresholdValue::value;
74 mutable SIMDRegisterUnion<Expression> thresholdSIMDConst;
75
76public:
77 template <class Src>
78 constexpr BinaryCaseDistinction (Src&& s)
79 : src (std::forward<Src>(s)),
80 caseTrue (CaseConfig::caseTrue << src),
81 caseFalse (CaseConfig::caseFalse << src)
82 {
83 // Any expression altering the size of the input won't work here
84 VCTR_ASSERT (caseTrue.size() == src.size());
85 VCTR_ASSERT (caseFalse.size() == src.size());
86 }
87
88 constexpr const auto& getStorageInfo() const
89 {
90 VCTR_ASSERT (&caseTrue.getStorageInfo() == &src.getStorageInfo());
91 VCTR_ASSERT (&caseFalse.getStorageInfo() == &src.getStorageInfo());
92
93 return src.getStorageInfo();
94 }
95
96 constexpr bool isNotAliased (const void *other) const
97 {
98 // Optimization potential: Probably both cases are unary so no way for them to be aliased. How to assert that property?
99 return caseTrue.isNotAliased (other) && caseFalse.isNotAliased (other) && src.isNotAliased (other);
100 }
101
102 constexpr size_t size() const { return src.size(); }
103
104 template<size_t i, class RuntimeArgs>
105 constexpr void iterateOverRuntimeArgChain(const RuntimeArgs &rtArgs) {
106 tryApplyingRuntimeArgsToThisExpression<i>(rtArgs, *this);
107 tryApplyingRuntimeArgsToSrc<i + 1>(rtArgs, src);
108 }
109
110 VCTR_FORCEDINLINE constexpr value_type operator[] (size_t i) const
111 {
112 return scalarCompare<CaseConfig::compareOp> (src[i], threshold) ? caseTrue[i] : caseFalse[i];
113 }
114
115 //==============================================================================
116
117 VCTR_FORCEDINLINE VCTR_TARGET ("avx") void prepareAVXEvaluation() const
119 {
120 src.prepareAVXEvaluation();
121 caseTrue.prepareAVXEvaluation();
122 caseFalse.prepareAVXEvaluation();
123
124 thresholdSIMDConst.avx = Expression::AVX::broadcast (threshold);
125 }
126
127 VCTR_FORCEDINLINE VCTR_TARGET ("avx2") AVXRegister<value_type> getAVX (size_t i) const
129 {
130 auto caseTrueResult = caseTrue.getAVX (i);
131 auto caseFalseResult = caseFalse.getAVX (i);
132
133 auto compareResult = Expression::AVX::template compare<CaseConfig::compareOp> (src.getAVX (i), thresholdSIMDConst.avx);
134
135 return Expression::AVX::bitwiseBlend (caseFalseResult, caseTrueResult, compareResult);
136 }
137
138 VCTR_FORCEDINLINE VCTR_TARGET ("fma") AVXRegister<value_type> getAVX (size_t i) const
139 requires archX64 && has::getAVX<SrcType> && has::getAVX<CaseTrueExpressionChainBuilder> && has::getAVX<CaseFalseExpressionChainBuilder> && Expression::CommonElement::isRealFloat
140 {
141 auto caseTrueResult = caseTrue.getAVX (i);
142 auto caseFalseResult = caseFalse.getAVX (i);
143
144 auto compareResult = Expression::AVX::template compare<CaseConfig::compareOp> (src.getAVX (i), thresholdSIMDConst.avx);
145
146 return Expression::AVX::bitwiseBlend (caseFalseResult, caseTrueResult, compareResult);
147 }
148
149 // Todo: Currently no compare operation for SSE implemented, so no SSE version implented here
150
151 VCTR_FORCEDINLINE void prepareNeonEvaluation() const
153 {
154 src.prepareNeonEvaluation();
155 caseTrue.prepareNeonEvaluation();
156 caseFalse.prepareNeonEvaluation();
157
158 thresholdSIMDConst.neon = Expression::Neon::broadcast (threshold);
159 }
160
161 VCTR_FORCEDINLINE NeonRegister<value_type> getNeon (size_t i) const
163 {
164 auto caseTrueResult = caseTrue.getNeon (i);
165 auto caseFalseResult = caseFalse.getNeon (i);
166
167 auto compareResult = Expression::Neon::template compare<CaseConfig::compareOp> (src.getNeon (i), thresholdSIMDConst.neon);
168
169 return Expression::Neon::bitwiseBlend (caseFalseResult, caseTrueResult, compareResult);
170 }
171};
172}
173
174namespace vctr
175{
192template <const auto& caseTrueExpression, CompareOp compareOp, const auto& threshold, const auto& caseFalseExpression>
194}
195
Definition: BinaryCaseDistinction.h:59
Constrains a type to have a member function getAVX (size_t) const.
Definition: ContainerAndExpressionConcepts.h:92
Constrains a type to have a member function getNeon (size_t) const.
Definition: ContainerAndExpressionConcepts.h:84
Constrains a type to have a member function prepareAVXEvaluation() const.
Definition: ContainerAndExpressionConcepts.h:88
Constrains a type to have a member function prepareNeonEvaluation() const.
Definition: ContainerAndExpressionConcepts.h:80
Constrains T to be any instance of BinaryCaseDistinctionConfig.
Definition: BinaryCaseDistinction.h:50
Constrains two instances of T to be comparable by the operation specified by op.
Definition: CompareOp.h:65
constexpr ExpressionChainBuilder< expressions::BinaryCaseDistinction, BinaryCaseDistinctionConfig< caseTrueExpression, compareOp, ConstantRef< threshold >, caseFalseExpression > > binaryCaseDistinction
Evaluates one of two expressions depending on a binary condition.
Definition: BinaryCaseDistinction.h:193
The main namespace of the VCTR project.
Definition: Array.h:24
typename detail::ValueType< std::remove_cvref_t< T > >::Type ValueType
If T is an expression template, it equals its return type, if it's a type that defines value_type as ...
Definition: Traits.h:201
CompareOp
Possible types of (SIMD) compare operations.
Definition: CompareOp.h:41
Definition: AVXRegister.h:28
Helper struct to pass multiple partly non-type template parameters to a BinaryCaseDistinction express...
Definition: BinaryCaseDistinction.h:35
An expression chain builder is an object which supplies various operator<< overloads which build chai...
Definition: ExpressionChainBuilder.h:170
Supplies some handy typedefs and traits needed when implementing expression templates.
Definition: ExpressionTemplate.h:41
The base class to every expression template.
Definition: ExpressionTemplate.h:37
Definition: NeonRegister.h:28
Helper template to define a union of all supported SIMD types.
Definition: ExpressionTemplate.h:123