OpenShot Library | OpenShotAudio  0.2.2
juce_ArrayBase.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2018 - ROLI Ltd.
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 #if JUCE_UNIT_TESTS
27 
28 namespace ArrayBaseTestsHelpers
29 {
30  class TriviallyCopyableType
31  {
32  public:
33  TriviallyCopyableType() = default;
34 
35  TriviallyCopyableType (int v)
36  : value (v)
37  {}
38 
39  TriviallyCopyableType (float v)
40  : value ((int) v)
41  {}
42 
43  bool operator== (const TriviallyCopyableType& other) const
44  {
45  return getValue() == other.getValue();
46  }
47 
48  int getValue() const { return value; }
49 
50  private:
51  int value { -1111 };
52  };
53 
54  class NonTriviallyCopyableType
55  {
56  public:
57  NonTriviallyCopyableType() = default;
58 
59  NonTriviallyCopyableType (int v)
60  : value (v)
61  {}
62 
63  NonTriviallyCopyableType (float v)
64  : value ((int) v)
65  {}
66 
67  NonTriviallyCopyableType (const NonTriviallyCopyableType& other)
68  : value (other.value)
69  {}
70 
71  NonTriviallyCopyableType& operator= (const NonTriviallyCopyableType& other)
72  {
73  value = other.value;
74  return *this;
75  }
76 
77  bool operator== (const NonTriviallyCopyableType& other) const
78  {
79  return getValue() == other.getValue();
80  }
81 
82  int getValue() const { return *ptr; }
83 
84  private:
85  int value { -1111 };
86  int* ptr = &value;
87  };
88 }
89 
90 bool operator== (const ArrayBaseTestsHelpers::TriviallyCopyableType& tct,
91  const ArrayBaseTestsHelpers::NonTriviallyCopyableType& ntct)
92 {
93  return tct.getValue() == ntct.getValue();
94 }
95 
96 bool operator== (const ArrayBaseTestsHelpers::NonTriviallyCopyableType& ntct,
97  const ArrayBaseTestsHelpers::TriviallyCopyableType& tct)
98 {
99  return tct == ntct;
100 }
101 
102 class ArrayBaseTests : public UnitTest
103 {
104  using CopyableType = ArrayBaseTestsHelpers::TriviallyCopyableType;
105  using NoncopyableType = ArrayBaseTestsHelpers::NonTriviallyCopyableType;
106 
107  #if ! (defined(__GNUC__) && __GNUC__ < 5 && ! defined(__clang__))
108  static_assert (std::is_trivially_copyable<CopyableType>::value,
109  "Test TriviallyCopyableType is not trivially copyable");
110  static_assert (! std::is_trivially_copyable<NoncopyableType>::value,
111  "Test NonTriviallyCopyableType is trivially copyable");
112  #endif
113 
114 public:
115  ArrayBaseTests()
116  : UnitTest ("ArrayBase", UnitTestCategories::containers)
117  {}
118 
119  void runTest() override
120  {
121  beginTest ("grow capacity");
122  {
123  std::vector<CopyableType> referenceContainer;
124  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
125  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
126 
127  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
128 
129  int originalCapacity = 4;
130  referenceContainer.reserve ((size_t) originalCapacity);
131  expectEquals ((int) referenceContainer.capacity(), originalCapacity);
132  copyableContainer.setAllocatedSize (originalCapacity);
133  expectEquals (copyableContainer.capacity(), originalCapacity);
134  noncopyableContainer.setAllocatedSize (originalCapacity);
135  expectEquals (noncopyableContainer.capacity(), originalCapacity);
136 
137  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
138 
139  addData (referenceContainer, copyableContainer, noncopyableContainer, 33);
140 
141  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
142 
143  expect ((int) referenceContainer.capacity() != originalCapacity);
144  expect (copyableContainer.capacity() != originalCapacity);
145  expect (noncopyableContainer.capacity() != originalCapacity);
146  }
147 
148  beginTest ("shrink capacity");
149  {
150  std::vector<CopyableType> referenceContainer;
151  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
152  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
153 
154  int numElements = 45;
155  addData (referenceContainer, copyableContainer, noncopyableContainer, numElements);
156 
157  copyableContainer.shrinkToNoMoreThan (numElements);
158  noncopyableContainer.setAllocatedSize (numElements + 1);
159 
160  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
161 
162  referenceContainer.clear();
163  copyableContainer.removeElements (0, numElements);
164  noncopyableContainer.removeElements (0, numElements);
165 
166  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
167 
168  copyableContainer.setAllocatedSize (0);
169  noncopyableContainer.setAllocatedSize (0);
170 
171  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
172 
173  addData (referenceContainer, copyableContainer, noncopyableContainer, numElements);
174 
175  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
176  }
177 
178  beginTest ("equality");
179  {
180  std::vector<int> referenceContainer = { 1, 2, 3 };
181  ArrayBase<int, DummyCriticalSection> testContainer1, testContainer2;
182 
183  for (auto i : referenceContainer)
184  {
185  testContainer1.add (i);
186  testContainer2.add (i);
187  }
188 
189  expect (testContainer1 == referenceContainer);
190  expect (testContainer2 == testContainer1);
191 
192  testContainer1.ensureAllocatedSize (257);
193  referenceContainer.shrink_to_fit();
194 
195  expect (testContainer1 == referenceContainer);
196  expect (testContainer2 == testContainer1);
197 
198  testContainer1.removeElements (0, 1);
199 
200  expect (testContainer1 != referenceContainer);
201  expect (testContainer2 != testContainer1);
202  }
203 
204  beginTest ("accessors");
205  {
206  std::vector<CopyableType> referenceContainer;
207  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
208  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
209 
210  addData (referenceContainer, copyableContainer, noncopyableContainer, 3);
211 
212  int testValue = -123;
213  referenceContainer[0] = testValue;
214  copyableContainer[0] = testValue;
215  noncopyableContainer[0] = testValue;
216 
217  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
218 
219  expect (copyableContainer .getFirst().getValue() == testValue);
220  expect (noncopyableContainer.getFirst().getValue() == testValue);
221 
222  auto last = referenceContainer.back().getValue();
223 
224  expectEquals (copyableContainer .getLast().getValue(), last);
225  expectEquals (noncopyableContainer.getLast().getValue(), last);
226 
227  ArrayBase<CopyableType, DummyCriticalSection> copyableEmpty;
228  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableEmpty;
229 
230  auto defualtValue = CopyableType().getValue();
231  expectEquals (defualtValue, NoncopyableType().getValue());
232 
233  expectEquals (copyableEmpty .getFirst().getValue(), defualtValue);
234  expectEquals (noncopyableEmpty.getFirst().getValue(), defualtValue);
235  expectEquals (copyableEmpty .getLast() .getValue(), defualtValue);
236  expectEquals (noncopyableEmpty.getLast() .getValue(), defualtValue);
237 
238  ArrayBase<float*, DummyCriticalSection> floatPointers;
239  expect (floatPointers.getValueWithDefault (-3) == nullptr);
240  }
241 
242  beginTest ("add moved");
243  {
244  std::vector<CopyableType> referenceContainer;
245  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
246  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
247 
248  for (int i = 0; i < 5; ++i)
249  {
250  CopyableType ref (-i);
251  CopyableType ct (-i);
252  NoncopyableType nct (-i);
253  referenceContainer.push_back (std::move (ref));
254  copyableContainer.add (std::move (ct));
255  noncopyableContainer.add (std::move (nct));
256  }
257 
258  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
259  }
260 
261  beginTest ("add multiple");
262  {
263  std::vector<CopyableType> referenceContainer;
264  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
265  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
266 
267  for (int i = 4; i < 7; ++i)
268  referenceContainer.push_back ({ -i });
269 
270  copyableContainer.add (CopyableType (-4), CopyableType (-5), CopyableType (-6));
271  noncopyableContainer.add (NoncopyableType (-4), NoncopyableType (-5), NoncopyableType (-6));
272 
273  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
274  }
275 
276  beginTest ("add array from a pointer");
277  {
278  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
279  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
280 
281  std::vector<CopyableType> copyableData = { 3, 4, 5 };
282  std::vector<NoncopyableType> noncopyableData = { 3, 4, 5 };
283 
284  copyableContainer.addArray (copyableData.data(), (int) copyableData.size());
285  noncopyableContainer.addArray (noncopyableData.data(), (int) noncopyableData.size());
286 
287  checkEqual (copyableContainer, noncopyableContainer, copyableData);
288  }
289 
290  beginTest ("add array from a pointer of a different type");
291  {
292  std::vector<CopyableType> referenceContainer;
293  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
294  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
295 
296  std::vector<float> floatData = { 1.4f, 2.5f, 3.6f };
297 
298  for (auto f : floatData)
299  referenceContainer.push_back ({ f });
300 
301  copyableContainer.addArray (floatData.data(), (int) floatData.size());
302  noncopyableContainer.addArray (floatData.data(), (int) floatData.size());
303 
304  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
305  }
306 
307  beginTest ("add array from initializer_list");
308  {
309  std::vector<CopyableType> referenceContainer;
310  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
311  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
312 
313  std::initializer_list<CopyableType> ilct { { 3 }, { 4 }, { 5 } };
314  std::initializer_list<NoncopyableType> ilnct { { 3 }, { 4 }, { 5 } };
315 
316  for (auto v : ilct)
317  referenceContainer.push_back ({ v });
318 
319  copyableContainer.addArray (ilct);
320  noncopyableContainer.addArray (ilnct);
321 
322  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
323  }
324 
325  beginTest ("add array from containers");
326  {
327  std::vector<CopyableType> referenceContainer;
328  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
329  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
330 
331  addData (referenceContainer, copyableContainer, noncopyableContainer, 5);
332 
333  std::vector<CopyableType> referenceContainerCopy (referenceContainer);
334  std::vector<NoncopyableType> noncopyableReferenceContainerCopy;
335  ArrayBase<CopyableType, DummyCriticalSection> copyableContainerCopy;
336  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainerCopy;
337 
338  for (auto& v : referenceContainerCopy)
339  noncopyableReferenceContainerCopy.push_back ({ v.getValue() });
340 
341  for (size_t i = 0; i < referenceContainerCopy.size(); ++i)
342  {
343  auto value = referenceContainerCopy[i].getValue();
344  copyableContainerCopy.add ({ value });
345  noncopyableContainerCopy.add ({ value });
346  }
347 
348  // From self-types
349  copyableContainer.addArray (copyableContainerCopy);
350  noncopyableContainer.addArray (noncopyableContainerCopy);
351 
352  for (auto v : referenceContainerCopy)
353  referenceContainer.push_back (v);
354 
355  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
356 
357  // From std containers
358  copyableContainer.addArray (referenceContainerCopy);
359  noncopyableContainer.addArray (noncopyableReferenceContainerCopy);
360 
361  for (auto v : referenceContainerCopy)
362  referenceContainer.push_back (v);
363 
364  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
365 
366  // From std containers with offset
367  int offset = 5;
368  copyableContainer.addArray (referenceContainerCopy, offset);
369  noncopyableContainer.addArray (noncopyableReferenceContainerCopy, offset);
370 
371  for (size_t i = 5; i < referenceContainerCopy.size(); ++i)
372  referenceContainer.push_back (referenceContainerCopy[i]);
373 
374  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
375  }
376 
377  beginTest ("insert");
378  {
379  std::vector<CopyableType> referenceContainer;
380  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
381  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
382 
383  addData (referenceContainer, copyableContainer, noncopyableContainer, 8);
384 
385  referenceContainer.insert (referenceContainer.begin(), -4);
386  copyableContainer.insert (0, -4, 1);
387  noncopyableContainer.insert (0, -4, 1);
388 
389  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
390 
391  for (int i = 0; i < 3; ++i)
392  referenceContainer.insert (referenceContainer.begin() + 1, -3);
393 
394  copyableContainer.insert (1, -3, 3);
395  noncopyableContainer.insert (1, -3, 3);
396 
397  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
398 
399  for (int i = 0; i < 50; ++i)
400  referenceContainer.insert (referenceContainer.end() - 1, -9);
401 
402  copyableContainer.insert (copyableContainer.size() - 2, -9, 50);
403  noncopyableContainer.insert (noncopyableContainer.size() - 2, -9, 50);
404  }
405 
406  beginTest ("insert array");
407  {
408  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
409  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
410 
411  std::vector<CopyableType> copyableData = { 3, 4, 5, 6, 7, 8 };
412  std::vector<NoncopyableType> noncopyableData = { 3, 4, 5, 6, 7, 8 };
413 
414  std::vector<CopyableType> referenceContainer { copyableData };
415 
416  copyableContainer.insertArray (0, copyableData.data(), (int) copyableData.size());
417  noncopyableContainer.insertArray (0, noncopyableData.data(), (int) noncopyableData.size());
418 
419  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
420 
421  int insertPos = copyableContainer.size() - 1;
422 
423  for (auto it = copyableData.end(); it != copyableData.begin(); --it)
424  referenceContainer.insert (referenceContainer.begin() + insertPos, CopyableType (*(it - 1)));
425 
426  copyableContainer.insertArray (insertPos, copyableData.data(), (int) copyableData.size());
427  noncopyableContainer.insertArray (insertPos, noncopyableData.data(), (int) noncopyableData.size());
428 
429  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
430  }
431 
432  beginTest ("remove");
433  {
434  std::vector<CopyableType> referenceContainer;
435  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
436  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
437 
438  addData (referenceContainer, copyableContainer, noncopyableContainer, 17);
439 
440  for (int i = 0; i < 4; ++i)
441  {
442  referenceContainer.erase (referenceContainer.begin() + i);
443  copyableContainer.removeElements (i, 1);
444  noncopyableContainer.removeElements (i, 1);
445  }
446 
447  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
448 
449  addData (referenceContainer, copyableContainer, noncopyableContainer, 17);
450  int blockSize = 3;
451 
452  for (int i = 0; i < 4; ++i)
453  {
454  for (int j = 0; j < blockSize; ++j)
455  referenceContainer.erase (referenceContainer.begin() + i);
456 
457  copyableContainer.removeElements (i, blockSize);
458  noncopyableContainer.removeElements (i, blockSize);
459  }
460 
461  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
462 
463  auto numToRemove = copyableContainer.size() - 2;
464 
465  for (int i = 0; i < numToRemove; ++i)
466  referenceContainer.erase (referenceContainer.begin() + 1);
467 
468  copyableContainer.removeElements (1, numToRemove);
469  noncopyableContainer.removeElements (1, numToRemove);
470 
471  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
472  }
473 
474  beginTest ("move");
475  {
476  std::vector<CopyableType> referenceContainer;
477  ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
478  ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
479 
480  addData (referenceContainer, copyableContainer, noncopyableContainer, 6);
481 
482  std::vector<std::pair<int, int>> testValues;
483  testValues.emplace_back (2, 4);
484  testValues.emplace_back (0, 5);
485  testValues.emplace_back (4, 1);
486  testValues.emplace_back (5, 0);
487 
488  for (auto p : testValues)
489  {
490  if (p.second > p.first)
491  std::rotate (referenceContainer.begin() + p.first,
492  referenceContainer.begin() + p.first + 1,
493  referenceContainer.begin() + p.second + 1);
494  else
495  std::rotate (referenceContainer.begin() + p.second,
496  referenceContainer.begin() + p.first,
497  referenceContainer.begin() + p.first + 1);
498 
499  copyableContainer.move (p.first, p.second);
500  noncopyableContainer.move (p.first, p.second);
501 
502  checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
503  }
504  }
505 
506  beginTest ("After converting move construction, ownership is transferred");
507  {
508  Derived obj;
509  ArrayBase<Derived*, DummyCriticalSection> derived;
510  derived.setAllocatedSize (5);
511  derived.add (&obj);
512 
513  ArrayBase<Base*, DummyCriticalSection> base { std::move (derived) };
514 
515  expectEquals (base.capacity(), 5);
516  expectEquals (base.size(), 1);
517  expect (base.getFirst() == &obj);
518  expectEquals (derived.capacity(), 0);
519  expectEquals (derived.size(), 0);
520  expect (derived.data() == nullptr);
521  }
522 
523  beginTest ("After converting move assignment, ownership is transferred");
524  {
525  Derived obj;
526  ArrayBase<Derived*, DummyCriticalSection> derived;
527  derived.setAllocatedSize (5);
528  derived.add (&obj);
529  ArrayBase<Base*, DummyCriticalSection> base;
530 
531  base = std::move (derived);
532 
533  expectEquals (base.capacity(), 5);
534  expectEquals (base.size(), 1);
535  expect (base.getFirst() == &obj);
536  expectEquals (derived.capacity(), 0);
537  expectEquals (derived.size(), 0);
538  expect (derived.data() == nullptr);
539  }
540  }
541 
542 private:
543  struct Base
544  {
545  virtual ~Base() = default;
546  };
547 
548  struct Derived : Base
549  {
550  };
551 
552  static void addData (std::vector<CopyableType>& referenceContainer,
553  ArrayBase<CopyableType, DummyCriticalSection>& copyableContainer,
554  ArrayBase<NoncopyableType, DummyCriticalSection>& NoncopyableContainer,
555  int numValues)
556  {
557  for (int i = 0; i < numValues; ++i)
558  {
559  referenceContainer.push_back ({ i });
560  copyableContainer.add ({ i });
561  NoncopyableContainer.add ({ i });
562  }
563  }
564 
565  template<typename A, typename B>
566  void checkEqual (const ArrayBase<A, DummyCriticalSection>& a,
567  const ArrayBase<B, DummyCriticalSection>& b)
568  {
569  expectEquals ((int) a.size(), (int) b.size());
570 
571  for (int i = 0; i < (int) a.size(); ++i)
572  expect (a[i] == b[i]);
573  }
574 
575  template<typename A, typename B>
576  void checkEqual (ArrayBase<A, DummyCriticalSection>& a,
577  std::vector<B>& b)
578  {
579  expectEquals ((int) a.size(), (int) b.size());
580 
581  for (int i = 0; i < (int) a.size(); ++i)
582  expect (a[i] == b[(size_t) i]);
583  }
584 
585  template<typename A, typename B, typename C>
586  void checkEqual (ArrayBase<A, DummyCriticalSection>& a,
587  ArrayBase<B, DummyCriticalSection>& b,
588  std::vector<C>& c)
589  {
590  checkEqual (a, b);
591  checkEqual (a, c);
592  checkEqual (b, c);
593  }
594 };
595 
596 static ArrayBaseTests arrayBaseTests;
597 
598 #endif
599 
600 } // namespace juce