OpenShot Audio Library | OpenShotAudio  0.6.0
juce_FloatVectorOperations.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2022 - Raw Material Software Limited
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 namespace FloatVectorHelpers
27 {
28  #define JUCE_INCREMENT_SRC_DEST dest += (16 / sizeof (*dest)); src += (16 / sizeof (*dest));
29  #define JUCE_INCREMENT_SRC1_SRC2_DEST dest += (16 / sizeof (*dest)); src1 += (16 / sizeof (*dest)); src2 += (16 / sizeof (*dest));
30  #define JUCE_INCREMENT_DEST dest += (16 / sizeof (*dest));
31 
32  #if JUCE_USE_SSE_INTRINSICS
33  static bool isAligned (const void* p) noexcept
34  {
35  return (((pointer_sized_int) p) & 15) == 0;
36  }
37 
38  struct BasicOps32
39  {
40  using Type = float;
41  using ParallelType = __m128;
42  using IntegerType = __m128;
43  enum { numParallel = 4 };
44 
45  // Integer and parallel types are the same for SSE. On neon they have different types
46  static forcedinline IntegerType toint (ParallelType v) noexcept { return v; }
47  static forcedinline ParallelType toflt (IntegerType v) noexcept { return v; }
48 
49  static forcedinline ParallelType load1 (Type v) noexcept { return _mm_load1_ps (&v); }
50  static forcedinline ParallelType loadA (const Type* v) noexcept { return _mm_load_ps (v); }
51  static forcedinline ParallelType loadU (const Type* v) noexcept { return _mm_loadu_ps (v); }
52  static forcedinline void storeA (Type* dest, ParallelType a) noexcept { _mm_store_ps (dest, a); }
53  static forcedinline void storeU (Type* dest, ParallelType a) noexcept { _mm_storeu_ps (dest, a); }
54 
55  static forcedinline ParallelType add (ParallelType a, ParallelType b) noexcept { return _mm_add_ps (a, b); }
56  static forcedinline ParallelType sub (ParallelType a, ParallelType b) noexcept { return _mm_sub_ps (a, b); }
57  static forcedinline ParallelType mul (ParallelType a, ParallelType b) noexcept { return _mm_mul_ps (a, b); }
58  static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return _mm_max_ps (a, b); }
59  static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return _mm_min_ps (a, b); }
60 
61  static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return _mm_and_ps (a, b); }
62  static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return _mm_andnot_ps (a, b); }
63  static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return _mm_or_ps (a, b); }
64  static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return _mm_xor_ps (a, b); }
65 
66  static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1], v[2], v[3]); }
67  static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1], v[2], v[3]); }
68  };
69 
70  struct BasicOps64
71  {
72  using Type = double;
73  using ParallelType = __m128d;
74  using IntegerType = __m128d;
75  enum { numParallel = 2 };
76 
77  // Integer and parallel types are the same for SSE. On neon they have different types
78  static forcedinline IntegerType toint (ParallelType v) noexcept { return v; }
79  static forcedinline ParallelType toflt (IntegerType v) noexcept { return v; }
80 
81  static forcedinline ParallelType load1 (Type v) noexcept { return _mm_load1_pd (&v); }
82  static forcedinline ParallelType loadA (const Type* v) noexcept { return _mm_load_pd (v); }
83  static forcedinline ParallelType loadU (const Type* v) noexcept { return _mm_loadu_pd (v); }
84  static forcedinline void storeA (Type* dest, ParallelType a) noexcept { _mm_store_pd (dest, a); }
85  static forcedinline void storeU (Type* dest, ParallelType a) noexcept { _mm_storeu_pd (dest, a); }
86 
87  static forcedinline ParallelType add (ParallelType a, ParallelType b) noexcept { return _mm_add_pd (a, b); }
88  static forcedinline ParallelType sub (ParallelType a, ParallelType b) noexcept { return _mm_sub_pd (a, b); }
89  static forcedinline ParallelType mul (ParallelType a, ParallelType b) noexcept { return _mm_mul_pd (a, b); }
90  static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return _mm_max_pd (a, b); }
91  static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return _mm_min_pd (a, b); }
92 
93  static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return _mm_and_pd (a, b); }
94  static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return _mm_andnot_pd (a, b); }
95  static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return _mm_or_pd (a, b); }
96  static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return _mm_xor_pd (a, b); }
97 
98  static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1]); }
99  static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1]); }
100  };
101 
102 
103 
104  #define JUCE_BEGIN_VEC_OP \
105  using Mode = FloatVectorHelpers::ModeType<sizeof(*dest)>::Mode; \
106  { \
107  const auto numLongOps = num / Mode::numParallel;
108 
109  #define JUCE_FINISH_VEC_OP(normalOp) \
110  num &= (Mode::numParallel - 1); \
111  if (num == 0) return; \
112  } \
113  for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
114 
115  #define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \
116  JUCE_BEGIN_VEC_OP \
117  setupOp \
118  if (FloatVectorHelpers::isAligned (dest)) JUCE_VEC_LOOP (vecOp, dummy, Mode::loadA, Mode::storeA, locals, JUCE_INCREMENT_DEST) \
119  else JUCE_VEC_LOOP (vecOp, dummy, Mode::loadU, Mode::storeU, locals, JUCE_INCREMENT_DEST) \
120  JUCE_FINISH_VEC_OP (normalOp)
121 
122  #define JUCE_PERFORM_VEC_OP_SRC_DEST(normalOp, vecOp, locals, increment, setupOp) \
123  JUCE_BEGIN_VEC_OP \
124  setupOp \
125  if (FloatVectorHelpers::isAligned (dest)) \
126  { \
127  if (FloatVectorHelpers::isAligned (src)) JUCE_VEC_LOOP (vecOp, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
128  else JUCE_VEC_LOOP (vecOp, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
129  }\
130  else \
131  { \
132  if (FloatVectorHelpers::isAligned (src)) JUCE_VEC_LOOP (vecOp, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
133  else JUCE_VEC_LOOP (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
134  } \
135  JUCE_FINISH_VEC_OP (normalOp)
136 
137  #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
138  JUCE_BEGIN_VEC_OP \
139  setupOp \
140  if (FloatVectorHelpers::isAligned (dest)) \
141  { \
142  if (FloatVectorHelpers::isAligned (src1)) \
143  { \
144  if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
145  else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadU, Mode::storeA, locals, increment) \
146  } \
147  else \
148  { \
149  if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
150  else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeA, locals, increment) \
151  } \
152  } \
153  else \
154  { \
155  if (FloatVectorHelpers::isAligned (src1)) \
156  { \
157  if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadA, Mode::storeU, locals, increment) \
158  else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
159  } \
160  else \
161  { \
162  if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadA, Mode::storeU, locals, increment) \
163  else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
164  } \
165  } \
166  JUCE_FINISH_VEC_OP (normalOp)
167 
168  #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \
169  JUCE_BEGIN_VEC_OP \
170  setupOp \
171  if (FloatVectorHelpers::isAligned (dest)) \
172  { \
173  if (FloatVectorHelpers::isAligned (src1)) \
174  { \
175  if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
176  else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
177  } \
178  else \
179  { \
180  if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
181  else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
182  } \
183  } \
184  else \
185  { \
186  if (FloatVectorHelpers::isAligned (src1)) \
187  { \
188  if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
189  else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
190  } \
191  else \
192  { \
193  if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
194  else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
195  } \
196  } \
197  JUCE_FINISH_VEC_OP (normalOp)
198 
199 
200  //==============================================================================
201  #elif JUCE_USE_ARM_NEON
202 
203  struct BasicOps32
204  {
205  using Type = float;
206  using ParallelType = float32x4_t;
207  using IntegerType = uint32x4_t;
208  union signMaskUnion { ParallelType f; IntegerType i; };
209  enum { numParallel = 4 };
210 
211  static forcedinline IntegerType toint (ParallelType v) noexcept { signMaskUnion u; u.f = v; return u.i; }
212  static forcedinline ParallelType toflt (IntegerType v) noexcept { signMaskUnion u; u.i = v; return u.f; }
213 
214  static forcedinline ParallelType load1 (Type v) noexcept { return vld1q_dup_f32 (&v); }
215  static forcedinline ParallelType loadA (const Type* v) noexcept { return vld1q_f32 (v); }
216  static forcedinline ParallelType loadU (const Type* v) noexcept { return vld1q_f32 (v); }
217  static forcedinline void storeA (Type* dest, ParallelType a) noexcept { vst1q_f32 (dest, a); }
218  static forcedinline void storeU (Type* dest, ParallelType a) noexcept { vst1q_f32 (dest, a); }
219 
220  static forcedinline ParallelType add (ParallelType a, ParallelType b) noexcept { return vaddq_f32 (a, b); }
221  static forcedinline ParallelType sub (ParallelType a, ParallelType b) noexcept { return vsubq_f32 (a, b); }
222  static forcedinline ParallelType mul (ParallelType a, ParallelType b) noexcept { return vmulq_f32 (a, b); }
223  static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return vmaxq_f32 (a, b); }
224  static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return vminq_f32 (a, b); }
225 
226  static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return toflt (vandq_u32 (toint (a), toint (b))); }
227  static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return toflt (vbicq_u32 (toint (a), toint (b))); }
228  static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return toflt (vorrq_u32 (toint (a), toint (b))); }
229  static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return toflt (veorq_u32 (toint (a), toint (b))); }
230 
231  static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1], v[2], v[3]); }
232  static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1], v[2], v[3]); }
233  };
234 
235  struct BasicOps64
236  {
237  using Type = double;
238  using ParallelType = double;
239  using IntegerType = uint64;
240  union signMaskUnion { ParallelType f; IntegerType i; };
241  enum { numParallel = 1 };
242 
243  static forcedinline IntegerType toint (ParallelType v) noexcept { signMaskUnion u; u.f = v; return u.i; }
244  static forcedinline ParallelType toflt (IntegerType v) noexcept { signMaskUnion u; u.i = v; return u.f; }
245 
246  static forcedinline ParallelType load1 (Type v) noexcept { return v; }
247  static forcedinline ParallelType loadA (const Type* v) noexcept { return *v; }
248  static forcedinline ParallelType loadU (const Type* v) noexcept { return *v; }
249  static forcedinline void storeA (Type* dest, ParallelType a) noexcept { *dest = a; }
250  static forcedinline void storeU (Type* dest, ParallelType a) noexcept { *dest = a; }
251 
252  static forcedinline ParallelType add (ParallelType a, ParallelType b) noexcept { return a + b; }
253  static forcedinline ParallelType sub (ParallelType a, ParallelType b) noexcept { return a - b; }
254  static forcedinline ParallelType mul (ParallelType a, ParallelType b) noexcept { return a * b; }
255  static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return jmax (a, b); }
256  static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return jmin (a, b); }
257 
258  static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) & toint (b)); }
259  static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return toflt ((~toint (a)) & toint (b)); }
260  static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) | toint (b)); }
261  static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) ^ toint (b)); }
262 
263  static forcedinline Type max (ParallelType a) noexcept { return a; }
264  static forcedinline Type min (ParallelType a) noexcept { return a; }
265  };
266 
267  #define JUCE_BEGIN_VEC_OP \
268  using Mode = FloatVectorHelpers::ModeType<sizeof(*dest)>::Mode; \
269  if (Mode::numParallel > 1) \
270  { \
271  const auto numLongOps = num / Mode::numParallel;
272 
273  #define JUCE_FINISH_VEC_OP(normalOp) \
274  num &= (Mode::numParallel - 1); \
275  if (num == 0) return; \
276  } \
277  for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
278 
279  #define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \
280  JUCE_BEGIN_VEC_OP \
281  setupOp \
282  JUCE_VEC_LOOP (vecOp, dummy, Mode::loadU, Mode::storeU, locals, JUCE_INCREMENT_DEST) \
283  JUCE_FINISH_VEC_OP (normalOp)
284 
285  #define JUCE_PERFORM_VEC_OP_SRC_DEST(normalOp, vecOp, locals, increment, setupOp) \
286  JUCE_BEGIN_VEC_OP \
287  setupOp \
288  JUCE_VEC_LOOP (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
289  JUCE_FINISH_VEC_OP (normalOp)
290 
291  #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
292  JUCE_BEGIN_VEC_OP \
293  setupOp \
294  JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
295  JUCE_FINISH_VEC_OP (normalOp)
296 
297  #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \
298  JUCE_BEGIN_VEC_OP \
299  setupOp \
300  JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
301  JUCE_FINISH_VEC_OP (normalOp)
302 
303 
304  //==============================================================================
305  #else
306  #define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \
307  for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
308 
309  #define JUCE_PERFORM_VEC_OP_SRC_DEST(normalOp, vecOp, locals, increment, setupOp) \
310  for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
311 
312  #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
313  for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
314 
315  #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \
316  for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
317 
318  #endif
319 
320  //==============================================================================
321  #define JUCE_VEC_LOOP(vecOp, srcLoad, dstLoad, dstStore, locals, increment) \
322  for (auto i = (decltype (numLongOps)) 0; i < numLongOps; ++i) \
323  { \
324  locals (srcLoad, dstLoad); \
325  dstStore (dest, vecOp); \
326  increment; \
327  }
328 
329  #define JUCE_VEC_LOOP_TWO_SOURCES(vecOp, src1Load, src2Load, dstStore, locals, increment) \
330  for (auto i = (decltype (numLongOps)) 0; i < numLongOps; ++i) \
331  { \
332  locals (src1Load, src2Load); \
333  dstStore (dest, vecOp); \
334  increment; \
335  }
336 
337  #define JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD(vecOp, src1Load, src2Load, dstLoad, dstStore, locals, increment) \
338  for (auto i = (decltype (numLongOps)) 0; i < numLongOps; ++i) \
339  { \
340  locals (src1Load, src2Load, dstLoad); \
341  dstStore (dest, vecOp); \
342  increment; \
343  }
344 
345  #define JUCE_LOAD_NONE(srcLoad, dstLoad)
346  #define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest);
347  #define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src);
348  #define JUCE_LOAD_SRC1_SRC2(src1Load, src2Load) const Mode::ParallelType s1 = src1Load (src1), s2 = src2Load (src2);
349  #define JUCE_LOAD_SRC1_SRC2_DEST(src1Load, src2Load, dstLoad) const Mode::ParallelType d = dstLoad (dest), s1 = src1Load (src1), s2 = src2Load (src2);
350  #define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src);
351 
352  union signMask32 { float f; uint32 i; };
353  union signMask64 { double d; uint64 i; };
354 
355  #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
356  template <int typeSize> struct ModeType { using Mode = BasicOps32; };
357  template <> struct ModeType<8> { using Mode = BasicOps64; };
358 
359  template <typename Mode>
360  struct MinMax
361  {
362  using Type = typename Mode::Type;
363  using ParallelType = typename Mode::ParallelType;
364 
365  template <typename Size>
366  static Type findMinOrMax (const Type* src, Size num, const bool isMinimum) noexcept
367  {
368  auto numLongOps = num / Mode::numParallel;
369 
370  if (numLongOps > 1)
371  {
372  ParallelType val;
373 
374  #if ! JUCE_USE_ARM_NEON
375  if (isAligned (src))
376  {
377  val = Mode::loadA (src);
378 
379  if (isMinimum)
380  {
381  while (--numLongOps > 0)
382  {
383  src += Mode::numParallel;
384  val = Mode::min (val, Mode::loadA (src));
385  }
386  }
387  else
388  {
389  while (--numLongOps > 0)
390  {
391  src += Mode::numParallel;
392  val = Mode::max (val, Mode::loadA (src));
393  }
394  }
395  }
396  else
397  #endif
398  {
399  val = Mode::loadU (src);
400 
401  if (isMinimum)
402  {
403  while (--numLongOps > 0)
404  {
405  src += Mode::numParallel;
406  val = Mode::min (val, Mode::loadU (src));
407  }
408  }
409  else
410  {
411  while (--numLongOps > 0)
412  {
413  src += Mode::numParallel;
414  val = Mode::max (val, Mode::loadU (src));
415  }
416  }
417  }
418 
419  Type result = isMinimum ? Mode::min (val)
420  : Mode::max (val);
421 
422  num &= (Mode::numParallel - 1);
423  src += Mode::numParallel;
424 
425  for (auto i = (decltype (num)) 0; i < num; ++i)
426  result = isMinimum ? jmin (result, src[i])
427  : jmax (result, src[i]);
428 
429  return result;
430  }
431 
432  if (num <= 0)
433  return 0;
434 
435  return isMinimum ? *std::min_element (src, src + num)
436  : *std::max_element (src, src + num);
437  }
438 
439  template <typename Size>
440  static Range<Type> findMinAndMax (const Type* src, Size num) noexcept
441  {
442  auto numLongOps = num / Mode::numParallel;
443 
444  if (numLongOps > 1)
445  {
446  ParallelType mn, mx;
447 
448  #if ! JUCE_USE_ARM_NEON
449  if (isAligned (src))
450  {
451  mn = Mode::loadA (src);
452  mx = mn;
453 
454  while (--numLongOps > 0)
455  {
456  src += Mode::numParallel;
457  const ParallelType v = Mode::loadA (src);
458  mn = Mode::min (mn, v);
459  mx = Mode::max (mx, v);
460  }
461  }
462  else
463  #endif
464  {
465  mn = Mode::loadU (src);
466  mx = mn;
467 
468  while (--numLongOps > 0)
469  {
470  src += Mode::numParallel;
471  const ParallelType v = Mode::loadU (src);
472  mn = Mode::min (mn, v);
473  mx = Mode::max (mx, v);
474  }
475  }
476 
477  Range<Type> result (Mode::min (mn),
478  Mode::max (mx));
479 
480  num &= (Mode::numParallel - 1);
481  src += Mode::numParallel;
482 
483  for (auto i = (decltype (num)) 0; i < num; ++i)
484  result = result.getUnionWith (src[i]);
485 
486  return result;
487  }
488 
489  return Range<Type>::findMinAndMax (src, num);
490  }
491  };
492  #endif
493 
494 //==============================================================================
495 namespace
496 {
497  template <typename Size>
498  void clear (float* dest, Size num) noexcept
499  {
500  #if JUCE_USE_VDSP_FRAMEWORK
501  vDSP_vclr (dest, 1, (vDSP_Length) num);
502  #else
503  zeromem (dest, (size_t) num * sizeof (float));
504  #endif
505  }
506 
507  template <typename Size>
508  void clear (double* dest, Size num) noexcept
509  {
510  #if JUCE_USE_VDSP_FRAMEWORK
511  vDSP_vclrD (dest, 1, (vDSP_Length) num);
512  #else
513  zeromem (dest, (size_t) num * sizeof (double));
514  #endif
515  }
516 
517  template <typename Size>
518  void fill (float* dest, float valueToFill, Size num) noexcept
519  {
520  #if JUCE_USE_VDSP_FRAMEWORK
521  vDSP_vfill (&valueToFill, dest, 1, (vDSP_Length) num);
522  #else
523  JUCE_PERFORM_VEC_OP_DEST (dest[i] = valueToFill,
524  val,
525  JUCE_LOAD_NONE,
526  const Mode::ParallelType val = Mode::load1 (valueToFill);)
527  #endif
528  }
529 
530  template <typename Size>
531  void fill (double* dest, double valueToFill, Size num) noexcept
532  {
533  #if JUCE_USE_VDSP_FRAMEWORK
534  vDSP_vfillD (&valueToFill, dest, 1, (vDSP_Length) num);
535  #else
536  JUCE_PERFORM_VEC_OP_DEST (dest[i] = valueToFill,
537  val,
538  JUCE_LOAD_NONE,
539  const Mode::ParallelType val = Mode::load1 (valueToFill);)
540  #endif
541  }
542 
543  template <typename Size>
544  void copyWithMultiply (float* dest, const float* src, float multiplier, Size num) noexcept
545  {
546  #if JUCE_USE_VDSP_FRAMEWORK
547  vDSP_vsmul (src, 1, &multiplier, dest, 1, (vDSP_Length) num);
548  #else
549  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier,
550  Mode::mul (mult, s),
551  JUCE_LOAD_SRC,
552  JUCE_INCREMENT_SRC_DEST,
553  const Mode::ParallelType mult = Mode::load1 (multiplier);)
554  #endif
555  }
556 
557  template <typename Size>
558  void copyWithMultiply (double* dest, const double* src, double multiplier, Size num) noexcept
559  {
560  #if JUCE_USE_VDSP_FRAMEWORK
561  vDSP_vsmulD (src, 1, &multiplier, dest, 1, (vDSP_Length) num);
562  #else
563  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier,
564  Mode::mul (mult, s),
565  JUCE_LOAD_SRC,
566  JUCE_INCREMENT_SRC_DEST,
567  const Mode::ParallelType mult = Mode::load1 (multiplier);)
568  #endif
569  }
570 
571  template <typename Size>
572  void add (float* dest, float amount, Size num) noexcept
573  {
574  #if JUCE_USE_VDSP_FRAMEWORK
575  vDSP_vsadd (dest, 1, &amount, dest, 1, (vDSP_Length) num);
576  #else
577  JUCE_PERFORM_VEC_OP_DEST (dest[i] += amount,
578  Mode::add (d, amountToAdd),
579  JUCE_LOAD_DEST,
580  const Mode::ParallelType amountToAdd = Mode::load1 (amount);)
581  #endif
582  }
583 
584  template <typename Size>
585  void add (double* dest, double amount, Size num) noexcept
586  {
587  JUCE_PERFORM_VEC_OP_DEST (dest[i] += amount,
588  Mode::add (d, amountToAdd),
589  JUCE_LOAD_DEST,
590  const Mode::ParallelType amountToAdd = Mode::load1 (amount);)
591  }
592 
593  template <typename Size>
594  void add (float* dest, const float* src, float amount, Size num) noexcept
595  {
596  #if JUCE_USE_VDSP_FRAMEWORK
597  vDSP_vsadd (src, 1, &amount, dest, 1, (vDSP_Length) num);
598  #else
599  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] + amount,
600  Mode::add (am, s),
601  JUCE_LOAD_SRC,
602  JUCE_INCREMENT_SRC_DEST,
603  const Mode::ParallelType am = Mode::load1 (amount);)
604  #endif
605  }
606 
607  template <typename Size>
608  void add (double* dest, const double* src, double amount, Size num) noexcept
609  {
610  #if JUCE_USE_VDSP_FRAMEWORK
611  vDSP_vsaddD (src, 1, &amount, dest, 1, (vDSP_Length) num);
612  #else
613  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] + amount,
614  Mode::add (am, s),
615  JUCE_LOAD_SRC,
616  JUCE_INCREMENT_SRC_DEST,
617  const Mode::ParallelType am = Mode::load1 (amount);)
618  #endif
619  }
620 
621  template <typename Size>
622  void add (float* dest, const float* src, Size num) noexcept
623  {
624  #if JUCE_USE_VDSP_FRAMEWORK
625  vDSP_vadd (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
626  #else
627  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i],
628  Mode::add (d, s),
629  JUCE_LOAD_SRC_DEST,
630  JUCE_INCREMENT_SRC_DEST, )
631  #endif
632  }
633 
634  template <typename Size>
635  void add (double* dest, const double* src, Size num) noexcept
636  {
637  #if JUCE_USE_VDSP_FRAMEWORK
638  vDSP_vaddD (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
639  #else
640  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i],
641  Mode::add (d, s),
642  JUCE_LOAD_SRC_DEST,
643  JUCE_INCREMENT_SRC_DEST, )
644  #endif
645  }
646 
647  template <typename Size>
648  void add (float* dest, const float* src1, const float* src2, Size num) noexcept
649  {
650  #if JUCE_USE_VDSP_FRAMEWORK
651  vDSP_vadd (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
652  #else
653  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] + src2[i],
654  Mode::add (s1, s2),
655  JUCE_LOAD_SRC1_SRC2,
656  JUCE_INCREMENT_SRC1_SRC2_DEST, )
657  #endif
658  }
659 
660  template <typename Size>
661  void add (double* dest, const double* src1, const double* src2, Size num) noexcept
662  {
663  #if JUCE_USE_VDSP_FRAMEWORK
664  vDSP_vaddD (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
665  #else
666  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] + src2[i],
667  Mode::add (s1, s2),
668  JUCE_LOAD_SRC1_SRC2,
669  JUCE_INCREMENT_SRC1_SRC2_DEST, )
670  #endif
671  }
672 
673  template <typename Size>
674  void subtract (float* dest, const float* src, Size num) noexcept
675  {
676  #if JUCE_USE_VDSP_FRAMEWORK
677  vDSP_vsub (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
678  #else
679  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i],
680  Mode::sub (d, s),
681  JUCE_LOAD_SRC_DEST,
682  JUCE_INCREMENT_SRC_DEST, )
683  #endif
684  }
685 
686  template <typename Size>
687  void subtract (double* dest, const double* src, Size num) noexcept
688  {
689  #if JUCE_USE_VDSP_FRAMEWORK
690  vDSP_vsubD (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
691  #else
692  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i],
693  Mode::sub (d, s),
694  JUCE_LOAD_SRC_DEST,
695  JUCE_INCREMENT_SRC_DEST, )
696  #endif
697  }
698 
699  template <typename Size>
700  void subtract (float* dest, const float* src1, const float* src2, Size num) noexcept
701  {
702  #if JUCE_USE_VDSP_FRAMEWORK
703  vDSP_vsub (src2, 1, src1, 1, dest, 1, (vDSP_Length) num);
704  #else
705  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] - src2[i],
706  Mode::sub (s1, s2),
707  JUCE_LOAD_SRC1_SRC2,
708  JUCE_INCREMENT_SRC1_SRC2_DEST, )
709  #endif
710  }
711 
712  template <typename Size>
713  void subtract (double* dest, const double* src1, const double* src2, Size num) noexcept
714  {
715  #if JUCE_USE_VDSP_FRAMEWORK
716  vDSP_vsubD (src2, 1, src1, 1, dest, 1, (vDSP_Length) num);
717  #else
718  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] - src2[i],
719  Mode::sub (s1, s2),
720  JUCE_LOAD_SRC1_SRC2,
721  JUCE_INCREMENT_SRC1_SRC2_DEST, )
722  #endif
723  }
724 
725  template <typename Size>
726  void addWithMultiply (float* dest, const float* src, float multiplier, Size num) noexcept
727  {
728  #if JUCE_USE_VDSP_FRAMEWORK
729  vDSP_vsma (src, 1, &multiplier, dest, 1, dest, 1, (vDSP_Length) num);
730  #else
731  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier,
732  Mode::add (d, Mode::mul (mult, s)),
733  JUCE_LOAD_SRC_DEST,
734  JUCE_INCREMENT_SRC_DEST,
735  const Mode::ParallelType mult = Mode::load1 (multiplier);)
736  #endif
737  }
738 
739  template <typename Size>
740  void addWithMultiply (double* dest, const double* src, double multiplier, Size num) noexcept
741  {
742  #if JUCE_USE_VDSP_FRAMEWORK
743  vDSP_vsmaD (src, 1, &multiplier, dest, 1, dest, 1, (vDSP_Length) num);
744  #else
745  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier,
746  Mode::add (d, Mode::mul (mult, s)),
747  JUCE_LOAD_SRC_DEST,
748  JUCE_INCREMENT_SRC_DEST,
749  const Mode::ParallelType mult = Mode::load1 (multiplier);)
750  #endif
751  }
752 
753  template <typename Size>
754  void addWithMultiply (float* dest, const float* src1, const float* src2, Size num) noexcept
755  {
756  #if JUCE_USE_VDSP_FRAMEWORK
757  vDSP_vma ((float*) src1, 1, (float*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num);
758  #else
759  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i],
760  Mode::add (d, Mode::mul (s1, s2)),
761  JUCE_LOAD_SRC1_SRC2_DEST,
762  JUCE_INCREMENT_SRC1_SRC2_DEST, )
763  #endif
764  }
765 
766  template <typename Size>
767  void addWithMultiply (double* dest, const double* src1, const double* src2, Size num) noexcept
768  {
769  #if JUCE_USE_VDSP_FRAMEWORK
770  vDSP_vmaD ((double*) src1, 1, (double*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num);
771  #else
772  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i],
773  Mode::add (d, Mode::mul (s1, s2)),
774  JUCE_LOAD_SRC1_SRC2_DEST,
775  JUCE_INCREMENT_SRC1_SRC2_DEST, )
776  #endif
777  }
778 
779  template <typename Size>
780  void subtractWithMultiply (float* dest, const float* src, float multiplier, Size num) noexcept
781  {
782  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i] * multiplier,
783  Mode::sub (d, Mode::mul (mult, s)),
784  JUCE_LOAD_SRC_DEST,
785  JUCE_INCREMENT_SRC_DEST,
786  const Mode::ParallelType mult = Mode::load1 (multiplier);)
787  }
788 
789  template <typename Size>
790  void subtractWithMultiply (double* dest, const double* src, double multiplier, Size num) noexcept
791  {
792  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i] * multiplier,
793  Mode::sub (d, Mode::mul (mult, s)),
794  JUCE_LOAD_SRC_DEST,
795  JUCE_INCREMENT_SRC_DEST,
796  const Mode::ParallelType mult = Mode::load1 (multiplier);)
797  }
798 
799  template <typename Size>
800  void subtractWithMultiply (float* dest, const float* src1, const float* src2, Size num) noexcept
801  {
802  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] -= src1[i] * src2[i],
803  Mode::sub (d, Mode::mul (s1, s2)),
804  JUCE_LOAD_SRC1_SRC2_DEST,
805  JUCE_INCREMENT_SRC1_SRC2_DEST, )
806  }
807 
808  template <typename Size>
809  void subtractWithMultiply (double* dest, const double* src1, const double* src2, Size num) noexcept
810  {
811  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] -= src1[i] * src2[i],
812  Mode::sub (d, Mode::mul (s1, s2)),
813  JUCE_LOAD_SRC1_SRC2_DEST,
814  JUCE_INCREMENT_SRC1_SRC2_DEST, )
815  }
816 
817  template <typename Size>
818  void multiply (float* dest, const float* src, Size num) noexcept
819  {
820  #if JUCE_USE_VDSP_FRAMEWORK
821  vDSP_vmul (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
822  #else
823  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] *= src[i],
824  Mode::mul (d, s),
825  JUCE_LOAD_SRC_DEST,
826  JUCE_INCREMENT_SRC_DEST, )
827  #endif
828  }
829 
830  template <typename Size>
831  void multiply (double* dest, const double* src, Size num) noexcept
832  {
833  #if JUCE_USE_VDSP_FRAMEWORK
834  vDSP_vmulD (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
835  #else
836  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] *= src[i],
837  Mode::mul (d, s),
838  JUCE_LOAD_SRC_DEST,
839  JUCE_INCREMENT_SRC_DEST, )
840  #endif
841  }
842 
843  template <typename Size>
844  void multiply (float* dest, const float* src1, const float* src2, Size num) noexcept
845  {
846  #if JUCE_USE_VDSP_FRAMEWORK
847  vDSP_vmul (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
848  #else
849  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] * src2[i],
850  Mode::mul (s1, s2),
851  JUCE_LOAD_SRC1_SRC2,
852  JUCE_INCREMENT_SRC1_SRC2_DEST, )
853  #endif
854  }
855 
856  template <typename Size>
857  void multiply (double* dest, const double* src1, const double* src2, Size num) noexcept
858  {
859  #if JUCE_USE_VDSP_FRAMEWORK
860  vDSP_vmulD (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
861  #else
862  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] * src2[i],
863  Mode::mul (s1, s2),
864  JUCE_LOAD_SRC1_SRC2,
865  JUCE_INCREMENT_SRC1_SRC2_DEST, )
866  #endif
867  }
868 
869  template <typename Size>
870  void multiply (float* dest, float multiplier, Size num) noexcept
871  {
872  #if JUCE_USE_VDSP_FRAMEWORK
873  vDSP_vsmul (dest, 1, &multiplier, dest, 1, (vDSP_Length) num);
874  #else
875  JUCE_PERFORM_VEC_OP_DEST (dest[i] *= multiplier,
876  Mode::mul (d, mult),
877  JUCE_LOAD_DEST,
878  const Mode::ParallelType mult = Mode::load1 (multiplier);)
879  #endif
880  }
881 
882  template <typename Size>
883  void multiply (double* dest, double multiplier, Size num) noexcept
884  {
885  #if JUCE_USE_VDSP_FRAMEWORK
886  vDSP_vsmulD (dest, 1, &multiplier, dest, 1, (vDSP_Length) num);
887  #else
888  JUCE_PERFORM_VEC_OP_DEST (dest[i] *= multiplier,
889  Mode::mul (d, mult),
890  JUCE_LOAD_DEST,
891  const Mode::ParallelType mult = Mode::load1 (multiplier);)
892  #endif
893  }
894 
895  template <typename Size>
896  void multiply (float* dest, const float* src, float multiplier, Size num) noexcept
897  {
898  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier,
899  Mode::mul (mult, s),
900  JUCE_LOAD_SRC,
901  JUCE_INCREMENT_SRC_DEST,
902  const Mode::ParallelType mult = Mode::load1 (multiplier);)
903  }
904 
905  template <typename Size>
906  void multiply (double* dest, const double* src, double multiplier, Size num) noexcept
907  {
908  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier,
909  Mode::mul (mult, s),
910  JUCE_LOAD_SRC,
911  JUCE_INCREMENT_SRC_DEST,
912  const Mode::ParallelType mult = Mode::load1 (multiplier);)
913  }
914 
915  template <typename Size>
916  void negate (float* dest, const float* src, Size num) noexcept
917  {
918  #if JUCE_USE_VDSP_FRAMEWORK
919  vDSP_vneg ((float*) src, 1, dest, 1, (vDSP_Length) num);
920  #else
921  copyWithMultiply (dest, src, -1.0f, num);
922  #endif
923  }
924 
925  template <typename Size>
926  void negate (double* dest, const double* src, Size num) noexcept
927  {
928  #if JUCE_USE_VDSP_FRAMEWORK
929  vDSP_vnegD ((double*) src, 1, dest, 1, (vDSP_Length) num);
930  #else
931  copyWithMultiply (dest, src, -1.0f, num);
932  #endif
933  }
934 
935  template <typename Size>
936  void abs (float* dest, const float* src, Size num) noexcept
937  {
938  #if JUCE_USE_VDSP_FRAMEWORK
939  vDSP_vabs ((float*) src, 1, dest, 1, (vDSP_Length) num);
940  #else
941  [[maybe_unused]] FloatVectorHelpers::signMask32 signMask;
942  signMask.i = 0x7fffffffUL;
943  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = std::abs (src[i]),
944  Mode::bit_and (s, mask),
945  JUCE_LOAD_SRC,
946  JUCE_INCREMENT_SRC_DEST,
947  const Mode::ParallelType mask = Mode::load1 (signMask.f);)
948  #endif
949  }
950 
951  template <typename Size>
952  void abs (double* dest, const double* src, Size num) noexcept
953  {
954  #if JUCE_USE_VDSP_FRAMEWORK
955  vDSP_vabsD ((double*) src, 1, dest, 1, (vDSP_Length) num);
956  #else
957  [[maybe_unused]] FloatVectorHelpers::signMask64 signMask;
958  signMask.i = 0x7fffffffffffffffULL;
959 
960  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = std::abs (src[i]),
961  Mode::bit_and (s, mask),
962  JUCE_LOAD_SRC,
963  JUCE_INCREMENT_SRC_DEST,
964  const Mode::ParallelType mask = Mode::load1 (signMask.d);)
965  #endif
966  }
967 
968  template <typename Size>
969  void min (float* dest, const float* src, float comp, Size num) noexcept
970  {
971  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp),
972  Mode::min (s, cmp),
973  JUCE_LOAD_SRC,
974  JUCE_INCREMENT_SRC_DEST,
975  const Mode::ParallelType cmp = Mode::load1 (comp);)
976  }
977 
978  template <typename Size>
979  void min (double* dest, const double* src, double comp, Size num) noexcept
980  {
981  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp),
982  Mode::min (s, cmp),
983  JUCE_LOAD_SRC,
984  JUCE_INCREMENT_SRC_DEST,
985  const Mode::ParallelType cmp = Mode::load1 (comp);)
986  }
987 
988  template <typename Size>
989  void min (float* dest, const float* src1, const float* src2, Size num) noexcept
990  {
991  #if JUCE_USE_VDSP_FRAMEWORK
992  vDSP_vmin ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num);
993  #else
994  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]),
995  Mode::min (s1, s2),
996  JUCE_LOAD_SRC1_SRC2,
997  JUCE_INCREMENT_SRC1_SRC2_DEST, )
998  #endif
999  }
1000 
1001  template <typename Size>
1002  void min (double* dest, const double* src1, const double* src2, Size num) noexcept
1003  {
1004  #if JUCE_USE_VDSP_FRAMEWORK
1005  vDSP_vminD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num);
1006  #else
1007  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]),
1008  Mode::min (s1, s2),
1009  JUCE_LOAD_SRC1_SRC2,
1010  JUCE_INCREMENT_SRC1_SRC2_DEST, )
1011  #endif
1012  }
1013 
1014  template <typename Size>
1015  void max (float* dest, const float* src, float comp, Size num) noexcept
1016  {
1017  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp),
1018  Mode::max (s, cmp),
1019  JUCE_LOAD_SRC,
1020  JUCE_INCREMENT_SRC_DEST,
1021  const Mode::ParallelType cmp = Mode::load1 (comp);)
1022  }
1023 
1024  template <typename Size>
1025  void max (double* dest, const double* src, double comp, Size num) noexcept
1026  {
1027  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp),
1028  Mode::max (s, cmp),
1029  JUCE_LOAD_SRC,
1030  JUCE_INCREMENT_SRC_DEST,
1031  const Mode::ParallelType cmp = Mode::load1 (comp);)
1032  }
1033 
1034  template <typename Size>
1035  void max (float* dest, const float* src1, const float* src2, Size num) noexcept
1036  {
1037  #if JUCE_USE_VDSP_FRAMEWORK
1038  vDSP_vmax ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num);
1039  #else
1040  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]),
1041  Mode::max (s1, s2),
1042  JUCE_LOAD_SRC1_SRC2,
1043  JUCE_INCREMENT_SRC1_SRC2_DEST, )
1044  #endif
1045  }
1046 
1047  template <typename Size>
1048  void max (double* dest, const double* src1, const double* src2, Size num) noexcept
1049  {
1050  #if JUCE_USE_VDSP_FRAMEWORK
1051  vDSP_vmaxD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num);
1052  #else
1053  JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]),
1054  Mode::max (s1, s2),
1055  JUCE_LOAD_SRC1_SRC2,
1056  JUCE_INCREMENT_SRC1_SRC2_DEST, )
1057  #endif
1058  }
1059 
1060  template <typename Size>
1061  void clip (float* dest, const float* src, float low, float high, Size num) noexcept
1062  {
1063  jassert (high >= low);
1064 
1065  #if JUCE_USE_VDSP_FRAMEWORK
1066  vDSP_vclip ((float*) src, 1, &low, &high, dest, 1, (vDSP_Length) num);
1067  #else
1068  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low),
1069  Mode::max (Mode::min (s, hi), lo),
1070  JUCE_LOAD_SRC,
1071  JUCE_INCREMENT_SRC_DEST,
1072  const Mode::ParallelType lo = Mode::load1 (low);
1073  const Mode::ParallelType hi = Mode::load1 (high);)
1074  #endif
1075  }
1076 
1077  template <typename Size>
1078  void clip (double* dest, const double* src, double low, double high, Size num) noexcept
1079  {
1080  jassert (high >= low);
1081 
1082  #if JUCE_USE_VDSP_FRAMEWORK
1083  vDSP_vclipD ((double*) src, 1, &low, &high, dest, 1, (vDSP_Length) num);
1084  #else
1085  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low),
1086  Mode::max (Mode::min (s, hi), lo),
1087  JUCE_LOAD_SRC,
1088  JUCE_INCREMENT_SRC_DEST,
1089  const Mode::ParallelType lo = Mode::load1 (low);
1090  const Mode::ParallelType hi = Mode::load1 (high);)
1091  #endif
1092  }
1093 
1094  template <typename Size>
1095  Range<float> findMinAndMax (const float* src, Size num) noexcept
1096  {
1097  #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1098  return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps32>::findMinAndMax (src, num);
1099  #else
1100  return Range<float>::findMinAndMax (src, num);
1101  #endif
1102  }
1103 
1104  template <typename Size>
1105  Range<double> findMinAndMax (const double* src, Size num) noexcept
1106  {
1107  #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1108  return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps64>::findMinAndMax (src, num);
1109  #else
1110  return Range<double>::findMinAndMax (src, num);
1111  #endif
1112  }
1113 
1114  template <typename Size>
1115  float findMinimum (const float* src, Size num) noexcept
1116  {
1117  #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1118  return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps32>::findMinOrMax (src, num, true);
1119  #else
1120  return juce::findMinimum (src, num);
1121  #endif
1122  }
1123 
1124  template <typename Size>
1125  double findMinimum (const double* src, Size num) noexcept
1126  {
1127  #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1128  return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps64>::findMinOrMax (src, num, true);
1129  #else
1130  return juce::findMinimum (src, num);
1131  #endif
1132  }
1133 
1134  template <typename Size>
1135  float findMaximum (const float* src, Size num) noexcept
1136  {
1137  #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1138  return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps32>::findMinOrMax (src, num, false);
1139  #else
1140  return juce::findMaximum (src, num);
1141  #endif
1142  }
1143 
1144  template <typename Size>
1145  double findMaximum (const double* src, Size num) noexcept
1146  {
1147  #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1148  return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps64>::findMinOrMax (src, num, false);
1149  #else
1150  return juce::findMaximum (src, num);
1151  #endif
1152  }
1153 
1154  template <typename Size>
1155  void convertFixedToFloat (float* dest, const int* src, float multiplier, Size num) noexcept
1156  {
1157  #if JUCE_USE_ARM_NEON
1158  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = (float) src[i] * multiplier,
1159  vmulq_n_f32 (vcvtq_f32_s32 (vld1q_s32 (src)), multiplier),
1160  JUCE_LOAD_NONE,
1161  JUCE_INCREMENT_SRC_DEST, )
1162  #else
1163  JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = (float) src[i] * multiplier,
1164  Mode::mul (mult, _mm_cvtepi32_ps (_mm_loadu_si128 (reinterpret_cast<const __m128i*> (src)))),
1165  JUCE_LOAD_NONE,
1166  JUCE_INCREMENT_SRC_DEST,
1167  const Mode::ParallelType mult = Mode::load1 (multiplier);)
1168  #endif
1169  }
1170 
1171 } // namespace
1172 } // namespace FloatVectorHelpers
1173 
1174 //==============================================================================
1175 template <typename FloatType, typename CountType>
1177  CountType numValues) noexcept
1178 {
1179  FloatVectorHelpers::clear (dest, numValues);
1180 }
1181 
1182 template <typename FloatType, typename CountType>
1183 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::fill (FloatType* dest,
1184  FloatType valueToFill,
1185  CountType numValues) noexcept
1186 {
1187  FloatVectorHelpers::fill (dest, valueToFill, numValues);
1188 }
1189 
1190 template <typename FloatType, typename CountType>
1191 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::copy (FloatType* dest,
1192  const FloatType* src,
1193  CountType numValues) noexcept
1194 {
1195  memcpy (dest, src, (size_t) numValues * sizeof (FloatType));
1196 }
1197 
1198 template <typename FloatType, typename CountType>
1200  const FloatType* src,
1201  FloatType multiplier,
1202  CountType numValues) noexcept
1203 {
1204  FloatVectorHelpers::copyWithMultiply (dest, src, multiplier, numValues);
1205 }
1206 
1207 template <typename FloatType, typename CountType>
1208 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::add (FloatType* dest,
1209  FloatType amountToAdd,
1210  CountType numValues) noexcept
1211 {
1212  FloatVectorHelpers::add (dest, amountToAdd, numValues);
1213 }
1214 
1215 template <typename FloatType, typename CountType>
1216 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::add (FloatType* dest,
1217  const FloatType* src,
1218  FloatType amount,
1219  CountType numValues) noexcept
1220 {
1221  FloatVectorHelpers::add (dest, src, amount, numValues);
1222 }
1223 
1224 template <typename FloatType, typename CountType>
1225 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::add (FloatType* dest,
1226  const FloatType* src,
1227  CountType numValues) noexcept
1228 {
1229  FloatVectorHelpers::add (dest, src, numValues);
1230 }
1231 
1232 template <typename FloatType, typename CountType>
1233 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::add (FloatType* dest,
1234  const FloatType* src1,
1235  const FloatType* src2,
1236  CountType num) noexcept
1237 {
1238  FloatVectorHelpers::add (dest, src1, src2, num);
1239 }
1240 
1241 template <typename FloatType, typename CountType>
1243  const FloatType* src,
1244  CountType numValues) noexcept
1245 {
1246  FloatVectorHelpers::subtract (dest, src, numValues);
1247 }
1248 
1249 template <typename FloatType, typename CountType>
1251  const FloatType* src1,
1252  const FloatType* src2,
1253  CountType num) noexcept
1254 {
1255  FloatVectorHelpers::subtract (dest, src1, src2, num);
1256 }
1257 
1258 template <typename FloatType, typename CountType>
1260  const FloatType* src,
1261  FloatType multiplier,
1262  CountType numValues) noexcept
1263 {
1264  FloatVectorHelpers::addWithMultiply (dest, src, multiplier, numValues);
1265 }
1266 
1267 template <typename FloatType, typename CountType>
1269  const FloatType* src1,
1270  const FloatType* src2,
1271  CountType num) noexcept
1272 {
1273  FloatVectorHelpers::addWithMultiply (dest, src1, src2, num);
1274 }
1275 
1276 template <typename FloatType, typename CountType>
1278  const FloatType* src,
1279  FloatType multiplier,
1280  CountType numValues) noexcept
1281 {
1282  FloatVectorHelpers::subtractWithMultiply (dest, src, multiplier, numValues);
1283 }
1284 
1285 template <typename FloatType, typename CountType>
1287  const FloatType* src1,
1288  const FloatType* src2,
1289  CountType num) noexcept
1290 {
1291  FloatVectorHelpers::subtractWithMultiply (dest, src1, src2, num);
1292 }
1293 
1294 template <typename FloatType, typename CountType>
1296  const FloatType* src,
1297  CountType numValues) noexcept
1298 {
1299  FloatVectorHelpers::multiply (dest, src, numValues);
1300 }
1301 
1302 template <typename FloatType, typename CountType>
1304  const FloatType* src1,
1305  const FloatType* src2,
1306  CountType numValues) noexcept
1307 {
1308  FloatVectorHelpers::multiply (dest, src1, src2, numValues);
1309 }
1310 
1311 template <typename FloatType, typename CountType>
1313  FloatType multiplier,
1314  CountType numValues) noexcept
1315 {
1316  FloatVectorHelpers::multiply (dest, multiplier, numValues);
1317 }
1318 
1319 template <typename FloatType, typename CountType>
1321  const FloatType* src,
1322  FloatType multiplier,
1323  CountType num) noexcept
1324 {
1325  FloatVectorHelpers::multiply (dest, src, multiplier, num);
1326 }
1327 
1328 template <typename FloatType, typename CountType>
1330  const FloatType* src,
1331  CountType numValues) noexcept
1332 {
1333  FloatVectorHelpers::negate (dest, src, numValues);
1334 }
1335 
1336 template <typename FloatType, typename CountType>
1337 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::abs (FloatType* dest,
1338  const FloatType* src,
1339  CountType numValues) noexcept
1340 {
1341  FloatVectorHelpers::abs (dest, src, numValues);
1342 }
1343 
1344 template <typename FloatType, typename CountType>
1345 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::min (FloatType* dest,
1346  const FloatType* src,
1347  FloatType comp,
1348  CountType num) noexcept
1349 {
1350  FloatVectorHelpers::min (dest, src, comp, num);
1351 }
1352 
1353 template <typename FloatType, typename CountType>
1354 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::min (FloatType* dest,
1355  const FloatType* src1,
1356  const FloatType* src2,
1357  CountType num) noexcept
1358 {
1359  FloatVectorHelpers::min (dest, src1, src2, num);
1360 }
1361 
1362 template <typename FloatType, typename CountType>
1363 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::max (FloatType* dest,
1364  const FloatType* src,
1365  FloatType comp,
1366  CountType num) noexcept
1367 {
1368  FloatVectorHelpers::max (dest, src, comp, num);
1369 }
1370 
1371 template <typename FloatType, typename CountType>
1372 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::max (FloatType* dest,
1373  const FloatType* src1,
1374  const FloatType* src2,
1375  CountType num) noexcept
1376 {
1377  FloatVectorHelpers::max (dest, src1, src2, num);
1378 }
1379 
1380 template <typename FloatType, typename CountType>
1381 void JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::clip (FloatType* dest,
1382  const FloatType* src,
1383  FloatType low,
1384  FloatType high,
1385  CountType num) noexcept
1386 {
1387  FloatVectorHelpers::clip (dest, src, low, high, num);
1388 }
1389 
1390 template <typename FloatType, typename CountType>
1392  CountType numValues) noexcept
1393 {
1394  return FloatVectorHelpers::findMinAndMax (src, numValues);
1395 }
1396 
1397 template <typename FloatType, typename CountType>
1398 FloatType JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::findMinimum (const FloatType* src,
1399  CountType numValues) noexcept
1400 {
1401  return FloatVectorHelpers::findMinimum (src, numValues);
1402 }
1403 
1404 template <typename FloatType, typename CountType>
1405 FloatType JUCE_CALLTYPE FloatVectorOperationsBase<FloatType, CountType>::findMaximum (const FloatType* src,
1406  CountType numValues) noexcept
1407 {
1408  return FloatVectorHelpers::findMaximum (src, numValues);
1409 }
1410 
1415 
1416 void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, size_t num) noexcept
1417 {
1418  FloatVectorHelpers::convertFixedToFloat (dest, src, multiplier, num);
1419 }
1420 
1421 void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept
1422 {
1423  FloatVectorHelpers::convertFixedToFloat (dest, src, multiplier, num);
1424 }
1425 
1426 intptr_t JUCE_CALLTYPE FloatVectorOperations::getFpStatusRegister() noexcept
1427 {
1428  intptr_t fpsr = 0;
1429  #if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
1430  fpsr = static_cast<intptr_t> (_mm_getcsr());
1431  #elif (JUCE_64BIT && JUCE_ARM) || JUCE_USE_ARM_NEON
1432  #if _MSC_VER
1433  // _control87 returns static values for x86 bits that don't exist on arm
1434  // to emulate x86 behaviour. We are only ever interested in de-normal bits
1435  // so mask out only those.
1436  fpsr = (intptr_t) (_control87 (0, 0) & _MCW_DN);
1437  #else
1438  #if JUCE_64BIT
1439  asm volatile("mrs %0, fpcr"
1440  : "=r"(fpsr));
1441  #elif JUCE_USE_ARM_NEON
1442  asm volatile("vmrs %0, fpscr"
1443  : "=r"(fpsr));
1444  #endif
1445  #endif
1446  #else
1447  #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
1448  jassertfalse; // No support for getting the floating point status register for your platform
1449  #endif
1450  #endif
1451 
1452  return fpsr;
1453 }
1454 
1455 void JUCE_CALLTYPE FloatVectorOperations::setFpStatusRegister ([[maybe_unused]] intptr_t fpsr) noexcept
1456 {
1457  #if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
1458  // the volatile keyword here is needed to workaround a bug in AppleClang 13.0
1459  // which aggressively optimises away the variable otherwise
1460  volatile auto fpsr_w = static_cast<uint32_t> (fpsr);
1461  _mm_setcsr (fpsr_w);
1462  #elif (JUCE_64BIT && JUCE_ARM) || JUCE_USE_ARM_NEON
1463  #if _MSC_VER
1464  _control87 ((unsigned int) fpsr, _MCW_DN);
1465  #else
1466  #if JUCE_64BIT
1467  asm volatile("msr fpcr, %0"
1468  :
1469  : "ri"(fpsr));
1470  #elif JUCE_USE_ARM_NEON
1471  asm volatile("vmsr fpscr, %0"
1472  :
1473  : "ri"(fpsr));
1474  #endif
1475  #endif
1476  #else
1477  #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
1478  jassertfalse; // No support for getting the floating point status register for your platform
1479  #endif
1480  #endif
1481 }
1482 
1483 void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode ([[maybe_unused]] bool shouldEnable) noexcept
1484 {
1485  #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
1486  #if JUCE_USE_SSE_INTRINSICS
1487  intptr_t mask = _MM_FLUSH_ZERO_MASK;
1488  #else /*JUCE_USE_ARM_NEON*/
1489  intptr_t mask = (1 << 24 /* FZ */);
1490  #endif
1491  setFpStatusRegister ((getFpStatusRegister() & (~mask)) | (shouldEnable ? mask : 0));
1492  #else
1493  #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
1494  jassertfalse; // No support for flush to zero mode on your platform
1495  #endif
1496  #endif
1497 }
1498 
1499 void JUCE_CALLTYPE FloatVectorOperations::disableDenormalisedNumberSupport ([[maybe_unused]] bool shouldDisable) noexcept
1500 {
1501  #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
1502  #if JUCE_USE_SSE_INTRINSICS
1503  intptr_t mask = 0x8040;
1504  #else /*JUCE_USE_ARM_NEON*/
1505  intptr_t mask = (1 << 24 /* FZ */);
1506  #endif
1507 
1508  setFpStatusRegister ((getFpStatusRegister() & (~mask)) | (shouldDisable ? mask : 0));
1509  #else
1510 
1511  #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
1512  jassertfalse; // No support for disable denormals mode on your platform
1513  #endif
1514  #endif
1515 }
1516 
1517 bool JUCE_CALLTYPE FloatVectorOperations::areDenormalsDisabled() noexcept
1518 {
1519  #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
1520  #if JUCE_USE_SSE_INTRINSICS
1521  intptr_t mask = 0x8040;
1522  #else /*JUCE_USE_ARM_NEON*/
1523  intptr_t mask = (1 << 24 /* FZ */);
1524  #endif
1525 
1526  return ((getFpStatusRegister() & mask) == mask);
1527  #else
1528  return false;
1529  #endif
1530 }
1531 
1532 ScopedNoDenormals::ScopedNoDenormals() noexcept
1533 {
1534  #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
1535  #if JUCE_USE_SSE_INTRINSICS
1536  intptr_t mask = 0x8040;
1537  #else /*JUCE_USE_ARM_NEON*/
1538  intptr_t mask = (1 << 24 /* FZ */);
1539  #endif
1540 
1541  fpsr = FloatVectorOperations::getFpStatusRegister();
1542  FloatVectorOperations::setFpStatusRegister (fpsr | mask);
1543  #endif
1544 }
1545 
1546 ScopedNoDenormals::~ScopedNoDenormals() noexcept
1547 {
1548  #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
1549  FloatVectorOperations::setFpStatusRegister (fpsr);
1550  #endif
1551 }
1552 
1553 
1554 //==============================================================================
1555 //==============================================================================
1556 #if JUCE_UNIT_TESTS
1557 
1558 class FloatVectorOperationsTests final : public UnitTest
1559 {
1560 public:
1561  FloatVectorOperationsTests()
1562  : UnitTest ("FloatVectorOperations", UnitTestCategories::audio)
1563  {}
1564 
1565  template <typename ValueType>
1566  struct TestRunner
1567  {
1568  static void runTest (UnitTest& u, Random random)
1569  {
1570  const int range = random.nextBool() ? 500 : 10;
1571  const int num = random.nextInt (range) + 1;
1572 
1573  HeapBlock<ValueType> buffer1 (num + 16), buffer2 (num + 16);
1574  HeapBlock<int> buffer3 (num + 16, true);
1575 
1576  #if JUCE_ARM
1577  ValueType* const data1 = buffer1;
1578  ValueType* const data2 = buffer2;
1579  int* const int1 = buffer3;
1580  #else
1581  // These tests deliberately operate on misaligned memory and will be flagged up by
1582  // checks for undefined behavior!
1583  ValueType* const data1 = addBytesToPointer (buffer1.get(), random.nextInt (16));
1584  ValueType* const data2 = addBytesToPointer (buffer2.get(), random.nextInt (16));
1585  int* const int1 = addBytesToPointer (buffer3.get(), random.nextInt (16));
1586  #endif
1587 
1588  fillRandomly (random, data1, num);
1589  fillRandomly (random, data2, num);
1590 
1591  Range<ValueType> minMax1 (FloatVectorOperations::findMinAndMax (data1, num));
1592  Range<ValueType> minMax2 (Range<ValueType>::findMinAndMax (data1, num));
1593  u.expect (minMax1 == minMax2);
1594 
1595  u.expect (valuesMatch (FloatVectorOperations::findMinimum (data1, num), juce::findMinimum (data1, num)));
1596  u.expect (valuesMatch (FloatVectorOperations::findMaximum (data1, num), juce::findMaximum (data1, num)));
1597 
1598  u.expect (valuesMatch (FloatVectorOperations::findMinimum (data2, num), juce::findMinimum (data2, num)));
1599  u.expect (valuesMatch (FloatVectorOperations::findMaximum (data2, num), juce::findMaximum (data2, num)));
1600 
1601  FloatVectorOperations::clear (data1, num);
1602  u.expect (areAllValuesEqual (data1, num, 0));
1603 
1604  FloatVectorOperations::fill (data1, (ValueType) 2, num);
1605  u.expect (areAllValuesEqual (data1, num, (ValueType) 2));
1606 
1607  FloatVectorOperations::add (data1, (ValueType) 2, num);
1608  u.expect (areAllValuesEqual (data1, num, (ValueType) 4));
1609 
1610  FloatVectorOperations::copy (data2, data1, num);
1611  u.expect (areAllValuesEqual (data2, num, (ValueType) 4));
1612 
1613  FloatVectorOperations::add (data2, data1, num);
1614  u.expect (areAllValuesEqual (data2, num, (ValueType) 8));
1615 
1616  FloatVectorOperations::copyWithMultiply (data2, data1, (ValueType) 4, num);
1617  u.expect (areAllValuesEqual (data2, num, (ValueType) 16));
1618 
1619  FloatVectorOperations::addWithMultiply (data2, data1, (ValueType) 4, num);
1620  u.expect (areAllValuesEqual (data2, num, (ValueType) 32));
1621 
1622  FloatVectorOperations::multiply (data1, (ValueType) 2, num);
1623  u.expect (areAllValuesEqual (data1, num, (ValueType) 8));
1624 
1625  FloatVectorOperations::multiply (data1, data2, num);
1626  u.expect (areAllValuesEqual (data1, num, (ValueType) 256));
1627 
1628  FloatVectorOperations::negate (data2, data1, num);
1629  u.expect (areAllValuesEqual (data2, num, (ValueType) -256));
1630 
1631  FloatVectorOperations::subtract (data1, data2, num);
1632  u.expect (areAllValuesEqual (data1, num, (ValueType) 512));
1633 
1634  FloatVectorOperations::abs (data1, data2, num);
1635  u.expect (areAllValuesEqual (data1, num, (ValueType) 256));
1636 
1637  FloatVectorOperations::abs (data2, data1, num);
1638  u.expect (areAllValuesEqual (data2, num, (ValueType) 256));
1639 
1640  fillRandomly (random, int1, num);
1641  doConversionTest (u, data1, data2, int1, num);
1642 
1643  FloatVectorOperations::fill (data1, (ValueType) 2, num);
1644  FloatVectorOperations::fill (data2, (ValueType) 3, num);
1645  FloatVectorOperations::addWithMultiply (data1, data1, data2, num);
1646  u.expect (areAllValuesEqual (data1, num, (ValueType) 8));
1647  }
1648 
1649  static void doConversionTest (UnitTest& u, float* data1, float* data2, int* const int1, int num)
1650  {
1651  FloatVectorOperations::convertFixedToFloat (data1, int1, 2.0f, num);
1652  convertFixed (data2, int1, 2.0f, num);
1653  u.expect (buffersMatch (data1, data2, num));
1654  }
1655 
1656  static void doConversionTest (UnitTest&, double*, double*, int*, int) {}
1657 
1658  static void fillRandomly (Random& random, ValueType* d, int num)
1659  {
1660  while (--num >= 0)
1661  *d++ = (ValueType) (random.nextDouble() * 1000.0);
1662  }
1663 
1664  static void fillRandomly (Random& random, int* d, int num)
1665  {
1666  while (--num >= 0)
1667  *d++ = random.nextInt();
1668  }
1669 
1670  static void convertFixed (float* d, const int* s, ValueType multiplier, int num)
1671  {
1672  while (--num >= 0)
1673  *d++ = (float) *s++ * multiplier;
1674  }
1675 
1676  static bool areAllValuesEqual (const ValueType* d, int num, ValueType target)
1677  {
1678  while (--num >= 0)
1679  if (! exactlyEqual (*d++, target))
1680  return false;
1681 
1682  return true;
1683  }
1684 
1685  static bool buffersMatch (const ValueType* d1, const ValueType* d2, int num)
1686  {
1687  while (--num >= 0)
1688  if (! valuesMatch (*d1++, *d2++))
1689  return false;
1690 
1691  return true;
1692  }
1693 
1694  static bool valuesMatch (ValueType v1, ValueType v2)
1695  {
1696  return std::abs (v1 - v2) < std::numeric_limits<ValueType>::epsilon();
1697  }
1698  };
1699 
1700  void runTest() override
1701  {
1702  beginTest ("FloatVectorOperations");
1703 
1704  for (int i = 1000; --i >= 0;)
1705  {
1706  TestRunner<float>::runTest (*this, getRandom());
1707  TestRunner<double>::runTest (*this, getRandom());
1708  }
1709  }
1710 };
1711 
1712 static FloatVectorOperationsTests vectorOpTests;
1713 
1714 #endif
1715 
1716 } // namespace juce
static void JUCE_CALLTYPE disableDenormalisedNumberSupport(bool shouldDisable=true) noexcept
static void JUCE_CALLTYPE enableFlushToZeroMode(bool shouldEnable) noexcept
static bool JUCE_CALLTYPE areDenormalsDisabled() noexcept
static Range findMinAndMax(const ValueType *values, Integral numValues) noexcept
Definition: juce_Range.h:279
static void JUCE_CALLTYPE add(FloatType *dest, FloatType amountToAdd, CountType numValues) noexcept
static void JUCE_CALLTYPE max(FloatType *dest, const FloatType *src, FloatType comp, CountType num) noexcept
static FloatType JUCE_CALLTYPE findMinimum(const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE multiply(FloatType *dest, const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE clear(FloatType *dest, CountType numValues) noexcept
static void JUCE_CALLTYPE addWithMultiply(FloatType *dest, const FloatType *src, FloatType multiplier, CountType numValues) noexcept
static Range< FloatType > JUCE_CALLTYPE findMinAndMax(const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE copy(FloatType *dest, const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE clip(FloatType *dest, const FloatType *src, FloatType low, FloatType high, CountType num) noexcept
static FloatType JUCE_CALLTYPE findMaximum(const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE subtractWithMultiply(FloatType *dest, const FloatType *src, FloatType multiplier, CountType numValues) noexcept
static void JUCE_CALLTYPE copyWithMultiply(FloatType *dest, const FloatType *src, FloatType multiplier, CountType numValues) noexcept
static void JUCE_CALLTYPE fill(FloatType *dest, FloatType valueToFill, CountType numValues) noexcept
static void JUCE_CALLTYPE subtract(FloatType *dest, const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE abs(FloatType *dest, const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE negate(FloatType *dest, const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE min(FloatType *dest, const FloatType *src, FloatType comp, CountType num) noexcept