VCTR
Loading...
Searching...
No Matches
Clamp.h
1/*
2 ==============================================================================
3 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
5 Copyright 2022- 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::expressions
24{
25
26template <size_t extent, class SrcType, is::constantWithType<bool> ClampLow, is::constantWithType<bool> ClampHigh>
28{
29public:
30 using value_type = ValueType<SrcType>;
31
32 VCTR_COMMON_UNARY_EXPRESSION_MEMBERS (Clamp, src)
33
34 static constexpr bool clampLow = ClampLow::value;
35 static constexpr bool clampHigh = ClampHigh::value;
36
37 constexpr void applyRuntimeArgs (value_type newLowerBound, value_type newUpperBound)
38 {
39 lowerBound = newLowerBound;
40 upperBound = newUpperBound;
41 }
42
43 VCTR_FORCEDINLINE constexpr value_type operator[] (size_t i) const
44 {
45 assertBoundsAreSet();
46
47 if constexpr (clampLow && clampHigh)
48 return std::clamp (src[i], lowerBound, upperBound);
49
50 if constexpr (clampLow && ! clampHigh)
51 return std::max (src[i], lowerBound);
52
53 if constexpr (! clampLow && clampHigh)
54 return std::min (src[i], upperBound);
55 }
56
57 //==============================================================================
58 // Platform Vector Operation Implementation
59 VCTR_FORCEDINLINE const value_type* evalNextVectorOpInExpressionChain (value_type* dst) const
61 {
62 assertBoundsAreSet();
63
64 if constexpr (clampLow && ! clampHigh)
65 Expression::Accelerate::clampLow (src.evalNextVectorOpInExpressionChain (dst), lowerBound, dst, size());
66
67 if constexpr (clampHigh)
68 {
69 auto l = clampLow ? lowerBound : std::numeric_limits<value_type>::lowest();
70 Expression::Accelerate::clamp (src.evalNextVectorOpInExpressionChain (dst), l, upperBound, dst, size());
71 }
72
73 return dst;
74 }
75
76 VCTR_FORCEDINLINE const value_type* evalNextVectorOpInExpressionChain (value_type* dst) const
78 {
79 assertBoundsAreSet();
80 const auto* s = src.evalNextVectorOpInExpressionChain (dst);
81
82 if constexpr (clampLow)
83 {
84 Expression::IPP::clampLow (s, lowerBound, dst, sizeToInt (size()));
85
86 if constexpr (clampHigh)
87 s = dst;
88 }
89
90 if constexpr (clampHigh)
91 Expression::IPP::clampHigh (s, upperBound, dst, sizeToInt (size()));
92
93 return dst;
94 }
95
96private:
97 void assertBoundsAreSet() const
98 {
99 // If you hit one of the assertions here, applyRuntimeArgs has not been called as expected.
100 // This should not happen under normal circumstances
101 if constexpr (clampLow)
102 VCTR_ASSERT (lowerBound != std::numeric_limits<value_type>::max());
103
104 if constexpr (clampHigh)
105 VCTR_ASSERT (upperBound != std::numeric_limits<value_type>::max());
106 }
107
108 value_type lowerBound = std::numeric_limits<value_type>::max();
109 value_type upperBound = std::numeric_limits<value_type>::max();
110};
111
112template <size_t extent, class SrcType>
114
115template <size_t extent, class SrcType>
117
118template <size_t extent, class SrcType>
120
121template <size_t extent, class SrcType, is::constant LowerBound, is::constant UpperBound>
123{
124public:
125 using value_type = ValueType<SrcType>;
126
127 static constexpr value_type lowerBound = LowerBound::value;
128 static constexpr value_type upperBound = UpperBound::value;
129
130 static constexpr bool clampLow = ! is::disabledConstant<LowerBound>;
131 static constexpr bool clampHigh = ! is::disabledConstant<UpperBound>;
132
133 VCTR_COMMON_UNARY_EXPRESSION_MEMBERS (ClampByConstant, src)
134
135 VCTR_FORCEDINLINE constexpr value_type operator[] (size_t i) const
136 {
137 if constexpr (clampLow && clampHigh)
138 return std::clamp (src[i], lowerBound, upperBound);
139
140 if constexpr (clampLow && ! clampHigh)
141 return std::max (src[i], lowerBound);
142
143 if constexpr (! clampLow && clampHigh)
144 return std::min (src[i], upperBound);
145
146 return std::max (lowerBound, src[i]);
147 }
148
149 //==============================================================================
150 // AVX Implementation
151 VCTR_FORCEDINLINE VCTR_TARGET ("avx") void prepareAVXEvaluation() const
152 requires (has::prepareAVXEvaluation<SrcType> && Expression::CommonElement::isRealFloat)
153 {
154 src.prepareAVXEvaluation();
155
156 if constexpr (clampLow)
157 lowerBoundSIMD.avx = Expression::AVX::broadcast (lowerBound);
158
159 if constexpr (clampHigh)
160 upperBoundSIMD.avx = Expression::AVX::broadcast (upperBound);
161 }
162
163 VCTR_FORCEDINLINE VCTR_TARGET ("fma") AVXRegister<value_type> getAVX (size_t i) const
164 requires (archX64 && has::getAVX<SrcType> && Expression::allElementTypesSame && Expression::CommonElement::isRealFloat)
165 {
166 auto x = src.getAVX (i);
167
168 if constexpr (clampLow)
169 x = Expression::AVX::max (lowerBoundSIMD.avx, x);
170
171 if constexpr (clampHigh)
172 x = Expression::AVX::min (x, upperBoundSIMD.avx);
173
174 return x;
175 }
176
177 //==============================================================================
178 // SSE Implementation
179 VCTR_FORCEDINLINE VCTR_TARGET ("sse4.1") void prepareSSEEvaluation() const
180 requires (has::prepareSSEEvaluation<SrcType> && Expression::CommonElement::isRealFloat)
181 {
182 src.prepareSSEEvaluation();
183
184 if constexpr (clampLow)
185 lowerBoundSIMD.sse = Expression::SSE::broadcast (lowerBound);
186
187 if constexpr (clampHigh)
188 upperBoundSIMD.sse = Expression::SSE::broadcast (upperBound);
189 }
190
191 VCTR_FORCEDINLINE VCTR_TARGET ("sse4.1") SSERegister<value_type> getSSE (size_t i) const
192 requires (archX64 && has::getSSE<SrcType> && Expression::allElementTypesSame && Expression::CommonElement::isRealFloat)
193 {
194 auto x = src.getSSE (i);
195
196 if constexpr (clampLow)
197 x = Expression::SSE::max (lowerBoundSIMD.sse, x);
198
199 if constexpr (clampHigh)
200 x = Expression::SSE::min (x, upperBoundSIMD.sse);
201
202 return x;
203 }
204
205 //==============================================================================
206 // Neon Implementation
207 void prepareNeonEvaluation() const
208 requires (archARM && has::prepareNeonEvaluation<SrcType> && Expression::CommonElement::isRealFloat)
209 {
210 src.prepareNeonEvaluation();
211
212 if constexpr (clampLow)
213 lowerBoundSIMD.neon = Expression::Neon::broadcast (lowerBound);
214
215 if constexpr (clampHigh)
216 upperBoundSIMD.neon = Expression::Neon::broadcast (upperBound);
217 }
218
219 NeonRegister<value_type> getNeon (size_t i) const
220 requires (archARM && has::getNeon<SrcType> && Expression::allElementTypesSame && Expression::CommonElement::isRealFloat)
221 {
222 auto x = src.getNeon (i);
223
224 if constexpr (clampLow)
225 x = Expression::Neon::max (lowerBoundSIMD.neon, x);
226
227 if constexpr (clampHigh)
228 x = Expression::Neon::min (x, upperBoundSIMD.neon);
229
230 return x;
231 }
232
233 //==============================================================================
234 // Platform Vector Operation Implementation
235 VCTR_FORCEDINLINE const value_type* evalNextVectorOpInExpressionChain (value_type* dst) const
237 {
238 if constexpr (clampLow && ! clampHigh)
239 Expression::Accelerate::clampLow (src.evalNextVectorOpInExpressionChain (dst), lowerBound, dst, size());
240
241 if constexpr (clampHigh)
242 {
243 auto l = clampLow ? lowerBound : std::numeric_limits<value_type>::lowest();
244 Expression::Accelerate::clamp (src.evalNextVectorOpInExpressionChain (dst), l, upperBound, dst, size());
245 }
246
247 return dst;
248 }
249
250 VCTR_FORCEDINLINE const value_type* evalNextVectorOpInExpressionChain (value_type* dst) const
252 {
253 const auto* s = src.evalNextVectorOpInExpressionChain (dst);
254
255 if constexpr (clampLow)
256 {
257 Expression::IPP::clampLow (s, lowerBound, dst, sizeToInt (size()));
258
259 if constexpr (clampHigh)
260 s = dst;
261 }
262
263 if constexpr (clampHigh)
264 Expression::IPP::clampHigh (s, upperBound, dst, sizeToInt (size()));
265
266 return dst;
267 }
268
269private:
270 mutable SIMDRegisterUnion<Expression> upperBoundSIMD;
271 mutable SIMDRegisterUnion<Expression> lowerBoundSIMD;
272};
273
274} // namespace vctr::expressions
275
276namespace vctr
277{
278
286template <class T>
287constexpr auto clampLow (T lowerBound)
288{
289 return makeExpressionChainBuilderWithRuntimeArgs<expressions::ClampLow> (lowerBound, std::numeric_limits<T>::max());
290}
291
299template <class T>
300constexpr auto clampHigh (T upperBound)
301{
302 return makeExpressionChainBuilderWithRuntimeArgs<expressions::ClampHigh> (std::numeric_limits<T>::max(), upperBound);
303}
304
312template <class T>
313constexpr auto clamp (T lowerBound, T upperBound)
314{
315 return makeExpressionChainBuilderWithRuntimeArgs<expressions::ClampLowHigh> (lowerBound, upperBound);
316}
317
325template <is::range Range>
326constexpr auto clamp (const Range& range)
327{
328 return makeExpressionChainBuilderWithRuntimeArgs<expressions::ClampLowHigh> (range.getStart(), range.getEnd());
329}
330
331
340template <auto lowerBound>
342
351template <auto upperBound>
353
362template <auto lowerBound, auto upperBound>
364
369template <const auto& range>
370requires is::range<decltype (range)>
372
373} // namespace vctr
A simple range class.
Definition: Range.h:32
constexpr ValueType getStart() const noexcept
Returns the start of the range.
Definition: Range.h:74
constexpr ValueType getEnd() const noexcept
Returns the end of the range.
Definition: Range.h:80
Definition: Clamp.h:123
Definition: Clamp.h:28
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 getSSE (size_t) const.
Definition: ContainerAndExpressionConcepts.h:100
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 a type to have a member function prepareSSEEvaluation() const.
Definition: ContainerAndExpressionConcepts.h:96
Constrains a type to be of the type DisabledConstant.
Definition: NumericTypeConcepts.h:99
Constrains the type to be a range, this is a class with a getStart, getLength and getEnd member funct...
Definition: GenericConcepts.h:125
A combined concept to check if Apple Accelerate is a suitable option for a real valued floating point...
Definition: ContainerAndExpressionConcepts.h:260
A combined concept to check if Intel IPP is a suitable option for a real valued floating point vector...
Definition: ContainerAndExpressionConcepts.h:284
constexpr ExpressionChainBuilder< expressions::ClampByConstant, DisabledConstant, Constant< upperBound > > clampHighByConstant
Ensures that the elements are not higher than upperBound.
Definition: Clamp.h:352
constexpr auto clampLow(T lowerBound)
Ensures that the elements are not lower than lowerBound.
Definition: Clamp.h:287
constexpr ExpressionChainBuilder< expressions::ClampByConstant, Constant< lowerBound >, Constant< upperBound > > clampByConstant
Ensures that the elements are not lower than lowerBound and not higher than upperBound.
Definition: Clamp.h:363
constexpr auto clampHigh(T upperBound)
Ensures that the elements are not greater than upperBound.
Definition: Clamp.h:300
constexpr ExpressionChainBuilder< expressions::ClampByConstant, Constant< lowerBound >, DisabledConstant > clampLowByConstant
Ensures that the elements are not lower than lowerBound.
Definition: Clamp.h:341
constexpr ExpressionChainBuilder< expressions::ClampByConstant, ConstantRangeStart< range >, ConstantRangeEnd< range > > clampToRange
Ensures that the elements are within the range.
Definition: Clamp.h:371
constexpr auto clamp(T lowerBound, T upperBound)
Ensures that the elements are not lower than lowerBound and not higher than upperBound.
Definition: Clamp.h:313
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
int sizeToInt(size_t size)
Casts the size_t argument to an int.
Definition: PlatformVectorOpsHelpers.h:27
Definition: AVXRegister.h:28
Evaluates the return value of getEnd called on the constant reference template argument and wraps tha...
Definition: ExpressionChainBuilder.h:124
Evaluates the return value of getStart called on the constant reference template argument and wraps t...
Definition: ExpressionChainBuilder.h:114
A helper struct to pass a constant as argument wrapped in a struct with a single public static conste...
Definition: ExpressionChainBuilder.h:104
A helper struct to indicate that a constant template should be considered disabled.
Definition: ExpressionChainBuilder.h:131
An expression chain builder is an object which supplies various operator<< overloads which build chai...
Definition: ExpressionChainBuilder.h:157
The base class to every expression template.
Definition: ExpressionTemplate.h:37
Definition: NeonRegister.h:28
Definition: SSERegister.h:28
Helper template to define a union of all supported SIMD types.
Definition: ExpressionTemplate.h:123