OpenShot Audio Library | OpenShotAudio  0.3.2
juce_ArrayBase.h
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - 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 
39 template <class ElementType, class TypeOfCriticalSectionToUse>
40 class ArrayBase : public TypeOfCriticalSectionToUse
41 {
42 private:
43  using ParameterType = typename TypeHelpers::ParameterType<ElementType>::type;
44 
45  template <class OtherElementType, class OtherCriticalSection>
46  using AllowConversion = typename std::enable_if<! std::is_same<std::tuple<ElementType, TypeOfCriticalSectionToUse>,
47  std::tuple<OtherElementType, OtherCriticalSection>>::value>::type;
48 
49 public:
50  //==============================================================================
51  ArrayBase() = default;
52 
53  ~ArrayBase()
54  {
55  clear();
56  }
57 
58  ArrayBase (ArrayBase&& other) noexcept
59  : elements (std::move (other.elements)),
60  numAllocated (other.numAllocated),
61  numUsed (other.numUsed)
62  {
63  other.numAllocated = 0;
64  other.numUsed = 0;
65  }
66 
67  ArrayBase& operator= (ArrayBase&& other) noexcept
68  {
69  if (this != &other)
70  {
71  auto tmp (std::move (other));
72  swapWith (tmp);
73  }
74 
75  return *this;
76  }
77 
83  template <class OtherElementType,
84  class OtherCriticalSection,
85  typename = AllowConversion<OtherElementType, OtherCriticalSection>>
87  : elements (std::move (other.elements)),
88  numAllocated (other.numAllocated),
89  numUsed (other.numUsed)
90  {
91  other.numAllocated = 0;
92  other.numUsed = 0;
93  }
94 
100  template <class OtherElementType,
101  class OtherCriticalSection,
102  typename = AllowConversion<OtherElementType, OtherCriticalSection>>
104  {
105  // No need to worry about assignment to *this, because 'other' must be of a different type.
106  elements = std::move (other.elements);
107  numAllocated = other.numAllocated;
108  numUsed = other.numUsed;
109 
110  other.numAllocated = 0;
111  other.numUsed = 0;
112 
113  return *this;
114  }
115 
116  //==============================================================================
117  template <class OtherArrayType>
118  bool operator== (const OtherArrayType& other) const noexcept
119  {
120  if (size() != (int) other.size())
121  return false;
122 
123  auto* e = begin();
124 
125  for (auto& o : other)
126  if (! (*e++ == o))
127  return false;
128 
129  return true;
130  }
131 
132  template <class OtherArrayType>
133  bool operator!= (const OtherArrayType& other) const noexcept
134  {
135  return ! operator== (other);
136  }
137 
138  //==============================================================================
139  inline ElementType& operator[] (const int index) noexcept
140  {
141  jassert (elements != nullptr);
142  jassert (isPositiveAndBelow (index, numUsed));
143  return elements[index];
144  }
145 
146  inline const ElementType& operator[] (const int index) const noexcept
147  {
148  jassert (elements != nullptr);
149  jassert (isPositiveAndBelow (index, numUsed));
150  return elements[index];
151  }
152 
153  inline ElementType getValueWithDefault (const int index) const noexcept
154  {
155  return isPositiveAndBelow (index, numUsed) ? elements[index] : ElementType();
156  }
157 
158  inline ElementType getFirst() const noexcept
159  {
160  return numUsed > 0 ? elements[0] : ElementType();
161  }
162 
163  inline ElementType getLast() const noexcept
164  {
165  return numUsed > 0 ? elements[numUsed - 1] : ElementType();
166  }
167 
168  //==============================================================================
169  inline ElementType* begin() noexcept
170  {
171  return elements;
172  }
173 
174  inline const ElementType* begin() const noexcept
175  {
176  return elements;
177  }
178 
179  inline ElementType* end() noexcept
180  {
181  return elements + numUsed;
182  }
183 
184  inline const ElementType* end() const noexcept
185  {
186  return elements + numUsed;
187  }
188 
189  inline ElementType* data() noexcept
190  {
191  return elements;
192  }
193 
194  inline const ElementType* data() const noexcept
195  {
196  return elements;
197  }
198 
199  inline int size() const noexcept
200  {
201  return numUsed;
202  }
203 
204  inline int capacity() const noexcept
205  {
206  return numAllocated;
207  }
208 
209  //==============================================================================
210  void setAllocatedSize (int numElements)
211  {
212  jassert (numElements >= numUsed);
213 
214  if (numAllocated != numElements)
215  {
216  if (numElements > 0)
217  setAllocatedSizeInternal (numElements);
218  else
219  elements.free();
220  }
221 
222  numAllocated = numElements;
223  }
224 
225  void ensureAllocatedSize (int minNumElements)
226  {
227  if (minNumElements > numAllocated)
228  setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
229 
230  jassert (numAllocated <= 0 || elements != nullptr);
231  }
232 
233  void shrinkToNoMoreThan (int maxNumElements)
234  {
235  if (maxNumElements < numAllocated)
236  setAllocatedSize (maxNumElements);
237  }
238 
239  void clear()
240  {
241  for (int i = 0; i < numUsed; ++i)
242  elements[i].~ElementType();
243 
244  numUsed = 0;
245  }
246 
247  //==============================================================================
248  void swapWith (ArrayBase& other) noexcept
249  {
250  elements.swapWith (other.elements);
251  std::swap (numAllocated, other.numAllocated);
252  std::swap (numUsed, other.numUsed);
253  }
254 
255  //==============================================================================
256  void add (const ElementType& newElement)
257  {
258  checkSourceIsNotAMember (&newElement);
259  ensureAllocatedSize (numUsed + 1);
260  addAssumingCapacityIsReady (newElement);
261  }
262 
263  void add (ElementType&& newElement)
264  {
265  checkSourceIsNotAMember (&newElement);
266  ensureAllocatedSize (numUsed + 1);
267  addAssumingCapacityIsReady (std::move (newElement));
268  }
269 
270  template <typename... OtherElements>
271  void add (const ElementType& firstNewElement, OtherElements... otherElements)
272  {
273  checkSourceIsNotAMember (&firstNewElement);
274  ensureAllocatedSize (numUsed + 1 + (int) sizeof... (otherElements));
275  addAssumingCapacityIsReady (firstNewElement, otherElements...);
276  }
277 
278  template <typename... OtherElements>
279  void add (ElementType&& firstNewElement, OtherElements... otherElements)
280  {
281  checkSourceIsNotAMember (&firstNewElement);
282  ensureAllocatedSize (numUsed + 1 + (int) sizeof... (otherElements));
283  addAssumingCapacityIsReady (std::move (firstNewElement), otherElements...);
284  }
285 
286  //==============================================================================
287  template <typename Type>
288  void addArray (const Type* elementsToAdd, int numElementsToAdd)
289  {
290  ensureAllocatedSize (numUsed + numElementsToAdd);
291  addArrayInternal (elementsToAdd, numElementsToAdd);
292  numUsed += numElementsToAdd;
293  }
294 
295  template <typename TypeToCreateFrom>
296  void addArray (const std::initializer_list<TypeToCreateFrom>& items)
297  {
298  ensureAllocatedSize (numUsed + (int) items.size());
299 
300  for (auto& item : items)
301  new (elements + numUsed++) ElementType (item);
302  }
303 
304  template <class OtherArrayType>
305  void addArray (const OtherArrayType& arrayToAddFrom)
306  {
307  jassert ((const void*) this != (const void*) &arrayToAddFrom); // can't add from our own elements!
308  ensureAllocatedSize (numUsed + (int) arrayToAddFrom.size());
309 
310  for (auto& e : arrayToAddFrom)
311  addAssumingCapacityIsReady (e);
312  }
313 
314  template <class OtherArrayType>
315  typename std::enable_if<! std::is_pointer<OtherArrayType>::value, int>::type
316  addArray (const OtherArrayType& arrayToAddFrom,
317  int startIndex, int numElementsToAdd = -1)
318  {
319  jassert ((const void*) this != (const void*) &arrayToAddFrom); // can't add from our own elements!
320 
321  if (startIndex < 0)
322  {
323  jassertfalse;
324  startIndex = 0;
325  }
326 
327  if (numElementsToAdd < 0 || startIndex + numElementsToAdd > (int) arrayToAddFrom.size())
328  numElementsToAdd = (int) arrayToAddFrom.size() - startIndex;
329 
330  addArray (arrayToAddFrom.data() + startIndex, numElementsToAdd);
331 
332  return numElementsToAdd;
333  }
334 
335  //==============================================================================
336  void insert (int indexToInsertAt, ParameterType newElement, int numberOfTimesToInsertIt)
337  {
338  checkSourceIsNotAMember (&newElement);
339  auto* space = createInsertSpace (indexToInsertAt, numberOfTimesToInsertIt);
340 
341  for (int i = 0; i < numberOfTimesToInsertIt; ++i)
342  new (space++) ElementType (newElement);
343 
344  numUsed += numberOfTimesToInsertIt;
345  }
346 
347  void insertArray (int indexToInsertAt, const ElementType* newElements, int numberOfElements)
348  {
349  auto* space = createInsertSpace (indexToInsertAt, numberOfElements);
350 
351  for (int i = 0; i < numberOfElements; ++i)
352  new (space++) ElementType (*(newElements++));
353 
354  numUsed += numberOfElements;
355  }
356 
357  //==============================================================================
358  void removeElements (int indexToRemoveAt, int numElementsToRemove)
359  {
360  jassert (indexToRemoveAt >= 0);
361  jassert (numElementsToRemove >= 0);
362  jassert (indexToRemoveAt + numElementsToRemove <= numUsed);
363 
364  if (numElementsToRemove > 0)
365  {
366  removeElementsInternal (indexToRemoveAt, numElementsToRemove);
367  numUsed -= numElementsToRemove;
368  }
369  }
370 
371  //==============================================================================
372  void swap (int index1, int index2)
373  {
374  if (isPositiveAndBelow (index1, numUsed)
375  && isPositiveAndBelow (index2, numUsed))
376  {
377  std::swap (elements[index1],
378  elements[index2]);
379  }
380  }
381 
382  //==============================================================================
383  void move (int currentIndex, int newIndex) noexcept
384  {
385  if (isPositiveAndBelow (currentIndex, numUsed))
386  {
387  if (! isPositiveAndBelow (newIndex, numUsed))
388  newIndex = numUsed - 1;
389 
390  moveInternal (currentIndex, newIndex);
391  }
392  }
393 
394 private:
395  //==============================================================================
396  template <typename T>
397  #if defined(__GNUC__) && __GNUC__ < 5 && ! defined(__clang__)
398  using IsTriviallyCopyable = std::is_scalar<T>;
399  #else
400  using IsTriviallyCopyable = std::is_trivially_copyable<T>;
401  #endif
402 
403  template <typename T>
404  using TriviallyCopyableVoid = typename std::enable_if<IsTriviallyCopyable<T>::value, void>::type;
405 
406  template <typename T>
407  using NonTriviallyCopyableVoid = typename std::enable_if<! IsTriviallyCopyable<T>::value, void>::type;
408 
409  //==============================================================================
410  template <typename T = ElementType>
411  TriviallyCopyableVoid<T> addArrayInternal (const ElementType* otherElements, int numElements)
412  {
413  memcpy (elements + numUsed, otherElements, (size_t) numElements * sizeof (ElementType));
414  }
415 
416  template <typename Type, typename T = ElementType>
417  TriviallyCopyableVoid<T> addArrayInternal (const Type* otherElements, int numElements)
418  {
419  auto* start = elements + numUsed;
420 
421  while (--numElements >= 0)
422  new (start++) ElementType (*(otherElements++));
423  }
424 
425  template <typename Type, typename T = ElementType>
426  NonTriviallyCopyableVoid<T> addArrayInternal (const Type* otherElements, int numElements)
427  {
428  auto* start = elements + numUsed;
429 
430  while (--numElements >= 0)
431  new (start++) ElementType (*(otherElements++));
432  }
433 
434  //==============================================================================
435  template <typename T = ElementType>
436  TriviallyCopyableVoid<T> setAllocatedSizeInternal (int numElements)
437  {
438  elements.realloc ((size_t) numElements);
439  }
440 
441  template <typename T = ElementType>
442  NonTriviallyCopyableVoid<T> setAllocatedSizeInternal (int numElements)
443  {
444  HeapBlock<ElementType> newElements (numElements);
445 
446  for (int i = 0; i < numUsed; ++i)
447  {
448  new (newElements + i) ElementType (std::move (elements[i]));
449  elements[i].~ElementType();
450  }
451 
452  elements = std::move (newElements);
453  }
454 
455  //==============================================================================
456  ElementType* createInsertSpace (int indexToInsertAt, int numElements)
457  {
458  ensureAllocatedSize (numUsed + numElements);
459 
460  if (! isPositiveAndBelow (indexToInsertAt, numUsed))
461  return elements + numUsed;
462 
463  createInsertSpaceInternal (indexToInsertAt, numElements);
464 
465  return elements + indexToInsertAt;
466  }
467 
468  template <typename T = ElementType>
469  TriviallyCopyableVoid<T> createInsertSpaceInternal (int indexToInsertAt, int numElements)
470  {
471  auto* start = elements + indexToInsertAt;
472  auto numElementsToShift = numUsed - indexToInsertAt;
473  memmove (start + numElements, start, (size_t) numElementsToShift * sizeof (ElementType));
474  }
475 
476  template <typename T = ElementType>
477  NonTriviallyCopyableVoid<T> createInsertSpaceInternal (int indexToInsertAt, int numElements)
478  {
479  auto* end = elements + numUsed;
480  auto* newEnd = end + numElements;
481  auto numElementsToShift = numUsed - indexToInsertAt;
482 
483  for (int i = 0; i < numElementsToShift; ++i)
484  {
485  new (--newEnd) ElementType (std::move (*(--end)));
486  end->~ElementType();
487  }
488  }
489 
490  //==============================================================================
491  template <typename T = ElementType>
492  TriviallyCopyableVoid<T> removeElementsInternal (int indexToRemoveAt, int numElementsToRemove)
493  {
494  auto* start = elements + indexToRemoveAt;
495  auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
496  memmove (start, start + numElementsToRemove, (size_t) numElementsToShift * sizeof (ElementType));
497  }
498 
499  template <typename T = ElementType>
500  NonTriviallyCopyableVoid<T> removeElementsInternal (int indexToRemoveAt, int numElementsToRemove)
501  {
502  auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
503  auto* destination = elements + indexToRemoveAt;
504  auto* source = destination + numElementsToRemove;
505 
506  for (int i = 0; i < numElementsToShift; ++i)
507  moveAssignElement (destination++, std::move (*(source++)));
508 
509  for (int i = 0; i < numElementsToRemove; ++i)
510  (destination++)->~ElementType();
511  }
512 
513  //==============================================================================
514  template <typename T = ElementType>
515  TriviallyCopyableVoid<T> moveInternal (int currentIndex, int newIndex) noexcept
516  {
517  char tempCopy[sizeof (ElementType)];
518  memcpy (tempCopy, elements + currentIndex, sizeof (ElementType));
519 
520  if (newIndex > currentIndex)
521  {
522  memmove (elements + currentIndex,
523  elements + currentIndex + 1,
524  (size_t) (newIndex - currentIndex) * sizeof (ElementType));
525  }
526  else
527  {
528  memmove (elements + newIndex + 1,
529  elements + newIndex,
530  (size_t) (currentIndex - newIndex) * sizeof (ElementType));
531  }
532 
533  memcpy (elements + newIndex, tempCopy, sizeof (ElementType));
534  }
535 
536  template <typename T = ElementType>
537  NonTriviallyCopyableVoid<T> moveInternal (int currentIndex, int newIndex) noexcept
538  {
539  auto* e = elements + currentIndex;
540  ElementType tempCopy (std::move (*e));
541  auto delta = newIndex - currentIndex;
542 
543  if (delta > 0)
544  {
545  for (int i = 0; i < delta; ++i)
546  {
547  moveAssignElement (e, std::move (*(e + 1)));
548  ++e;
549  }
550  }
551  else
552  {
553  for (int i = 0; i < -delta; ++i)
554  {
555  moveAssignElement (e, std::move (*(e - 1)));
556  --e;
557  }
558  }
559 
560  moveAssignElement (e, std::move (tempCopy));
561  }
562 
563  //==============================================================================
564  void addAssumingCapacityIsReady (const ElementType& element) { new (elements + numUsed++) ElementType (element); }
565  void addAssumingCapacityIsReady (ElementType&& element) { new (elements + numUsed++) ElementType (std::move (element)); }
566 
567  template <typename... OtherElements>
568  void addAssumingCapacityIsReady (const ElementType& firstNewElement, OtherElements... otherElements)
569  {
570  addAssumingCapacityIsReady (firstNewElement);
571  addAssumingCapacityIsReady (otherElements...);
572  }
573 
574  template <typename... OtherElements>
575  void addAssumingCapacityIsReady (ElementType&& firstNewElement, OtherElements... otherElements)
576  {
577  addAssumingCapacityIsReady (std::move (firstNewElement));
578  addAssumingCapacityIsReady (otherElements...);
579  }
580 
581  //==============================================================================
582  template <typename T = ElementType>
583  typename std::enable_if<std::is_move_assignable<T>::value, void>::type
584  moveAssignElement (ElementType* destination, ElementType&& source)
585  {
586  *destination = std::move (source);
587  }
588 
589  template <typename T = ElementType>
590  typename std::enable_if<! std::is_move_assignable<T>::value, void>::type
591  moveAssignElement (ElementType* destination, ElementType&& source)
592  {
593  destination->~ElementType();
594  new (destination) ElementType (std::move (source));
595  }
596 
597  void checkSourceIsNotAMember (const ElementType* element)
598  {
599  // when you pass a reference to an existing element into a method like add() which
600  // may need to reallocate the array to make more space, the incoming reference may
601  // be deleted indirectly during the reallocation operation! To work around this,
602  // make a local copy of the item you're trying to add (and maybe use std::move to
603  // move it into the add() method to avoid any extra overhead)
604  jassert (element < begin() || element >= end());
605  ignoreUnused (element);
606  }
607 
608  //==============================================================================
609  HeapBlock<ElementType> elements;
610  int numAllocated = 0, numUsed = 0;
611 
612  template <class OtherElementType, class OtherCriticalSection>
613  friend class ArrayBase;
614 
615  JUCE_DECLARE_NON_COPYABLE (ArrayBase)
616 };
617 
618 } // namespace juce
ArrayBase(ArrayBase< OtherElementType, OtherCriticalSection > &&other) noexcept