OpenShot Library | libopenshot-audio  0.1.9
juce_ArrayBase.h
1 
2 /** @weakgroup juce_core-containers
3  * @{
4  */
5 /*
6  ==============================================================================
7 
8  This file is part of the JUCE library.
9  Copyright (c) 2017 - ROLI Ltd.
10 
11  JUCE is an open source library subject to commercial or open-source
12  licensing.
13 
14  The code included in this file is provided under the terms of the ISC license
15  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
16  To use, copy, modify, and/or distribute this software for any purpose with or
17  without fee is hereby granted provided that the above copyright notice and
18  this permission notice appear in all copies.
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 
30 /**
31  A basic object container.
32 
33  This class isn't really for public use - it's used by the other
34  array classes, but might come in handy for some purposes.
35 
36  It inherits from a critical section class to allow the arrays to use
37  the "empty base class optimisation" pattern to reduce their footprint.
38 
39  @see Array, OwnedArray, ReferenceCountedArray
40 
41  @tags{Core}
42 */
43 template <class ElementType, class TypeOfCriticalSectionToUse>
44 class ArrayBase : public TypeOfCriticalSectionToUse
45 {
46 private:
47  using ParameterType = typename TypeHelpers::ParameterType<ElementType>::type;
48 
49  template <class OtherElementType, class OtherCriticalSection>
50  using AllowConversion = typename std::enable_if<! std::is_same<std::tuple<ElementType, TypeOfCriticalSectionToUse>,
51  std::tuple<OtherElementType, OtherCriticalSection>>::value>::type;
52 
53 public:
54  //==============================================================================
55  ArrayBase() = default;
56 
57  ~ArrayBase()
58  {
59  clear();
60  }
61 
62  ArrayBase (ArrayBase&& other) noexcept
63  : elements (std::move (other.elements)),
64  numAllocated (other.numAllocated),
65  numUsed (other.numUsed)
66  {
67  other.numAllocated = 0;
68  other.numUsed = 0;
69  }
70 
71  ArrayBase& operator= (ArrayBase&& other) noexcept
72  {
73  if (this != &other)
74  {
75  auto tmp (std::move (other));
76  swapWith (tmp);
77  }
78 
79  return *this;
80  }
81 
82  /** Converting move constructor.
83  Only enabled when the other array has a different type to this one.
84  If you see a compile error here, it's probably because you're attempting a conversion that
85  HeapBlock won't allow.
86  */
87  template <class OtherElementType,
88  class OtherCriticalSection,
89  typename = AllowConversion<OtherElementType, OtherCriticalSection>>
91  : elements (std::move (other.elements)),
92  numAllocated (other.numAllocated),
93  numUsed (other.numUsed)
94  {
95  other.numAllocated = 0;
96  other.numUsed = 0;
97  }
98 
99  /** Converting move assignment operator.
100  Only enabled when the other array has a different type to this one.
101  If you see a compile error here, it's probably because you're attempting a conversion that
102  HeapBlock won't allow.
103  */
104  template <class OtherElementType,
105  class OtherCriticalSection,
106  typename = AllowConversion<OtherElementType, OtherCriticalSection>>
108  {
109  // No need to worry about assignment to *this, because 'other' must be of a different type.
110  elements = std::move (other.elements);
111  numAllocated = other.numAllocated;
112  numUsed = other.numUsed;
113 
114  other.numAllocated = 0;
115  other.numUsed = 0;
116 
117  return *this;
118  }
119 
120  //==============================================================================
121  template <class OtherArrayType>
122  bool operator== (const OtherArrayType& other) const noexcept
123  {
124  if (size() != (int) other.size())
125  return false;
126 
127  auto* e = begin();
128 
129  for (auto& o : other)
130  if (! (*e++ == o))
131  return false;
132 
133  return true;
134  }
135 
136  template <class OtherArrayType>
137  bool operator!= (const OtherArrayType& other) const noexcept
138  {
139  return ! operator== (other);
140  }
141 
142  //==============================================================================
143  inline ElementType& operator[] (const int index) const noexcept
144  {
145  jassert (elements != nullptr);
146  jassert (isPositiveAndBelow (index, numUsed));
147  return elements[index];
148  }
149 
150  inline ElementType getValueWithDefault (const int index) const noexcept
151  {
152  return isPositiveAndBelow (index, numUsed) ? elements[index] : ElementType();
153  }
154 
155  inline ElementType getFirst() const noexcept
156  {
157  return numUsed > 0 ? elements[0] : ElementType();
158  }
159 
160  inline ElementType getLast() const noexcept
161  {
162  return numUsed > 0 ? elements[numUsed - 1] : ElementType();
163  }
164 
165  //==============================================================================
166  inline ElementType* begin() const noexcept
167  {
168  return elements;
169  }
170 
171  inline ElementType* end() const noexcept
172  {
173  return elements + numUsed;
174  }
175 
176  inline ElementType* data() const noexcept
177  {
178  return elements;
179  }
180 
181  inline int size() const noexcept
182  {
183  return numUsed;
184  }
185 
186  inline int capacity() const noexcept
187  {
188  return numAllocated;
189  }
190 
191  //==============================================================================
192  void setAllocatedSize (int numElements)
193  {
194  jassert (numElements >= numUsed);
195 
196  if (numAllocated != numElements)
197  {
198  if (numElements > 0)
199  setAllocatedSizeInternal (numElements);
200  else
201  elements.free();
202  }
203 
204  numAllocated = numElements;
205  }
206 
207  void ensureAllocatedSize (int minNumElements)
208  {
209  if (minNumElements > numAllocated)
210  setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
211 
212  jassert (numAllocated <= 0 || elements != nullptr);
213  }
214 
215  void shrinkToNoMoreThan (int maxNumElements)
216  {
217  if (maxNumElements < numAllocated)
218  setAllocatedSize (maxNumElements);
219  }
220 
221  void clear()
222  {
223  for (int i = 0; i < numUsed; ++i)
224  elements[i].~ElementType();
225 
226  numUsed = 0;
227  }
228 
229  //==============================================================================
230  void swapWith (ArrayBase& other) noexcept
231  {
232  elements.swapWith (other.elements);
233  std::swap (numAllocated, other.numAllocated);
234  std::swap (numUsed, other.numUsed);
235  }
236 
237  //==============================================================================
238  void add (const ElementType& newElement)
239  {
240  checkSourceIsNotAMember (&newElement);
241  ensureAllocatedSize (numUsed + 1);
242  addAssumingCapacityIsReady (newElement);
243  }
244 
245  void add (ElementType&& newElement)
246  {
247  checkSourceIsNotAMember (&newElement);
248  ensureAllocatedSize (numUsed + 1);
249  addAssumingCapacityIsReady (std::move (newElement));
250  }
251 
252  template <typename... OtherElements>
253  void add (const ElementType& firstNewElement, OtherElements... otherElements)
254  {
255  checkSourceIsNotAMember (&firstNewElement);
256  ensureAllocatedSize (numUsed + 1 + (int) sizeof... (otherElements));
257  addAssumingCapacityIsReady (firstNewElement, otherElements...);
258  }
259 
260  template <typename... OtherElements>
261  void add (ElementType&& firstNewElement, OtherElements... otherElements)
262  {
263  checkSourceIsNotAMember (&firstNewElement);
264  ensureAllocatedSize (numUsed + 1 + (int) sizeof... (otherElements));
265  addAssumingCapacityIsReady (std::move (firstNewElement), otherElements...);
266  }
267 
268  //==============================================================================
269  template <typename Type>
270  void addArray (const Type* elementsToAdd, int numElementsToAdd)
271  {
272  ensureAllocatedSize (numUsed + numElementsToAdd);
273  addArrayInternal (elementsToAdd, numElementsToAdd);
274  numUsed += numElementsToAdd;
275  }
276 
277  template <typename TypeToCreateFrom>
278  void addArray (const std::initializer_list<TypeToCreateFrom>& items)
279  {
280  ensureAllocatedSize (numUsed + (int) items.size());
281 
282  for (auto& item : items)
283  new (elements + numUsed++) ElementType (item);
284  }
285 
286  template <class OtherArrayType>
287  void addArray (const OtherArrayType& arrayToAddFrom)
288  {
289  jassert ((const void*) this != (const void*) &arrayToAddFrom); // can't add from our own elements!
290  ensureAllocatedSize (numUsed + (int) arrayToAddFrom.size());
291 
292  for (auto& e : arrayToAddFrom)
293  addAssumingCapacityIsReady (e);
294  }
295 
296  template <class OtherArrayType>
297  typename std::enable_if<! std::is_pointer<OtherArrayType>::value, int>::type
298  addArray (const OtherArrayType& arrayToAddFrom,
299  int startIndex, int numElementsToAdd = -1)
300  {
301  jassert ((const void*) this != (const void*) &arrayToAddFrom); // can't add from our own elements!
302 
303  if (startIndex < 0)
304  {
305  jassertfalse;
306  startIndex = 0;
307  }
308 
309  if (numElementsToAdd < 0 || startIndex + numElementsToAdd > (int) arrayToAddFrom.size())
310  numElementsToAdd = (int) arrayToAddFrom.size() - startIndex;
311 
312  addArray (arrayToAddFrom.data() + startIndex, numElementsToAdd);
313 
314  return numElementsToAdd;
315  }
316 
317  //==============================================================================
318  void insert (int indexToInsertAt, ParameterType newElement, int numberOfTimesToInsertIt)
319  {
320  checkSourceIsNotAMember (&newElement);
321  auto* space = createInsertSpace (indexToInsertAt, numberOfTimesToInsertIt);
322 
323  for (int i = 0; i < numberOfTimesToInsertIt; ++i)
324  new (space++) ElementType (newElement);
325 
326  numUsed += numberOfTimesToInsertIt;
327  }
328 
329  void insertArray (int indexToInsertAt, const ElementType* newElements, int numberOfElements)
330  {
331  auto* space = createInsertSpace (indexToInsertAt, numberOfElements);
332 
333  for (int i = 0; i < numberOfElements; ++i)
334  new (space++) ElementType (*(newElements++));
335 
336  numUsed += numberOfElements;
337  }
338 
339  //==============================================================================
340  void removeElements (int indexToRemoveAt, int numElementsToRemove)
341  {
342  jassert (indexToRemoveAt >= 0);
343  jassert (numElementsToRemove >= 0);
344  jassert (indexToRemoveAt + numElementsToRemove <= numUsed);
345 
346  if (numElementsToRemove > 0)
347  {
348  removeElementsInternal (indexToRemoveAt, numElementsToRemove);
349  numUsed -= numElementsToRemove;
350  }
351  }
352 
353  //==============================================================================
354  void swap (int index1, int index2)
355  {
356  if (isPositiveAndBelow (index1, numUsed)
357  && isPositiveAndBelow (index2, numUsed))
358  {
359  std::swap (elements[index1],
360  elements[index2]);
361  }
362  }
363 
364  //==============================================================================
365  void move (int currentIndex, int newIndex) noexcept
366  {
367  if (isPositiveAndBelow (currentIndex, numUsed))
368  {
369  if (! isPositiveAndBelow (newIndex, numUsed))
370  newIndex = numUsed - 1;
371 
372  moveInternal (currentIndex, newIndex);
373  }
374  }
375 
376 private:
377  //==============================================================================
378  template <typename T>
379  #if defined(__GNUC__) && __GNUC__ < 5 && ! defined(__clang__)
380  using IsTriviallyCopyable = std::is_scalar<T>;
381  #else
382  using IsTriviallyCopyable = std::is_trivially_copyable<T>;
383  #endif
384 
385  template <typename T>
386  using TriviallyCopyableVoid = typename std::enable_if<IsTriviallyCopyable<T>::value, void>::type;
387 
388  template <typename T>
389  using NonTriviallyCopyableVoid = typename std::enable_if<! IsTriviallyCopyable<T>::value, void>::type;
390 
391  //==============================================================================
392  template <typename T = ElementType>
393  TriviallyCopyableVoid<T> addArrayInternal (const ElementType* otherElements, int numElements)
394  {
395  memcpy (elements + numUsed, otherElements, (size_t) numElements * sizeof (ElementType));
396  }
397 
398  template <typename Type, typename T = ElementType>
399  TriviallyCopyableVoid<T> addArrayInternal (const Type* otherElements, int numElements)
400  {
401  auto* start = elements + numUsed;
402 
403  while (--numElements >= 0)
404  new (start++) ElementType (*(otherElements++));
405  }
406 
407  template <typename Type, typename T = ElementType>
408  NonTriviallyCopyableVoid<T> addArrayInternal (const Type* otherElements, int numElements)
409  {
410  auto* start = elements + numUsed;
411 
412  while (--numElements >= 0)
413  new (start++) ElementType (*(otherElements++));
414  }
415 
416  //==============================================================================
417  template <typename T = ElementType>
418  TriviallyCopyableVoid<T> setAllocatedSizeInternal (int numElements)
419  {
420  elements.realloc ((size_t) numElements);
421  }
422 
423  template <typename T = ElementType>
424  NonTriviallyCopyableVoid<T> setAllocatedSizeInternal (int numElements)
425  {
426  HeapBlock<ElementType> newElements (numElements);
427 
428  for (int i = 0; i < numUsed; ++i)
429  {
430  new (newElements + i) ElementType (std::move (elements[i]));
431  elements[i].~ElementType();
432  }
433 
434  elements = std::move (newElements);
435  }
436 
437  //==============================================================================
438  ElementType* createInsertSpace (int indexToInsertAt, int numElements)
439  {
440  ensureAllocatedSize (numUsed + numElements);
441 
442  if (! isPositiveAndBelow (indexToInsertAt, numUsed))
443  return elements + numUsed;
444 
445  createInsertSpaceInternal (indexToInsertAt, numElements);
446 
447  return elements + indexToInsertAt;
448  }
449 
450  template <typename T = ElementType>
451  TriviallyCopyableVoid<T> createInsertSpaceInternal (int indexToInsertAt, int numElements)
452  {
453  auto* start = elements + indexToInsertAt;
454  auto numElementsToShift = numUsed - indexToInsertAt;
455  memmove (start + numElements, start, (size_t) numElementsToShift * sizeof (ElementType));
456  }
457 
458  template <typename T = ElementType>
459  NonTriviallyCopyableVoid<T> createInsertSpaceInternal (int indexToInsertAt, int numElements)
460  {
461  auto* end = elements + numUsed;
462  auto* newEnd = end + numElements;
463  auto numElementsToShift = numUsed - indexToInsertAt;
464 
465  for (int i = 0; i < numElementsToShift; ++i)
466  {
467  new (--newEnd) ElementType (std::move (*(--end)));
468  end->~ElementType();
469  }
470  }
471 
472  //==============================================================================
473  template <typename T = ElementType>
474  TriviallyCopyableVoid<T> removeElementsInternal (int indexToRemoveAt, int numElementsToRemove)
475  {
476  auto* start = elements + indexToRemoveAt;
477  auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
478  memmove (start, start + numElementsToRemove, (size_t) numElementsToShift * sizeof (ElementType));
479  }
480 
481  template <typename T = ElementType>
482  NonTriviallyCopyableVoid<T> removeElementsInternal (int indexToRemoveAt, int numElementsToRemove)
483  {
484  auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
485  auto* destination = elements + indexToRemoveAt;
486  auto* source = destination + numElementsToRemove;
487 
488  for (int i = 0; i < numElementsToShift; ++i)
489  moveAssignElement (destination++, std::move (*(source++)));
490 
491  for (int i = 0; i < numElementsToRemove; ++i)
492  (destination++)->~ElementType();
493  }
494 
495  //==============================================================================
496  template <typename T = ElementType>
497  TriviallyCopyableVoid<T> moveInternal (int currentIndex, int newIndex) noexcept
498  {
499  char tempCopy[sizeof (ElementType)];
500  memcpy (tempCopy, elements + currentIndex, sizeof (ElementType));
501 
502  if (newIndex > currentIndex)
503  {
504  memmove (elements + currentIndex,
505  elements + currentIndex + 1,
506  sizeof (ElementType) * (size_t) (newIndex - currentIndex));
507  }
508  else
509  {
510  memmove (elements + newIndex + 1,
511  elements + newIndex,
512  sizeof (ElementType) * (size_t) (currentIndex - newIndex));
513  }
514 
515  memcpy (elements + newIndex, tempCopy, sizeof (ElementType));
516  }
517 
518  template <typename T = ElementType>
519  NonTriviallyCopyableVoid<T> moveInternal (int currentIndex, int newIndex) noexcept
520  {
521  auto* e = elements + currentIndex;
522  ElementType tempCopy (std::move (*e));
523  auto delta = newIndex - currentIndex;
524 
525  if (delta > 0)
526  {
527  for (int i = 0; i < delta; ++i)
528  {
529  moveAssignElement (e, std::move (*(e + 1)));
530  ++e;
531  }
532  }
533  else
534  {
535  for (int i = 0; i < -delta; ++i)
536  {
537  moveAssignElement (e, std::move (*(e - 1)));
538  --e;
539  }
540  }
541 
542  moveAssignElement (e, std::move (tempCopy));
543  }
544 
545  //==============================================================================
546  void addAssumingCapacityIsReady (const ElementType& element) { new (elements + numUsed++) ElementType (element); }
547  void addAssumingCapacityIsReady (ElementType&& element) { new (elements + numUsed++) ElementType (std::move (element)); }
548 
549  template <typename... OtherElements>
550  void addAssumingCapacityIsReady (const ElementType& firstNewElement, OtherElements... otherElements)
551  {
552  addAssumingCapacityIsReady (firstNewElement);
553  addAssumingCapacityIsReady (otherElements...);
554  }
555 
556  template <typename... OtherElements>
557  void addAssumingCapacityIsReady (ElementType&& firstNewElement, OtherElements... otherElements)
558  {
559  addAssumingCapacityIsReady (std::move (firstNewElement));
560  addAssumingCapacityIsReady (otherElements...);
561  }
562 
563  //==============================================================================
564  template <typename T = ElementType>
565  typename std::enable_if<std::is_move_assignable<T>::value, void>::type
566  moveAssignElement (ElementType* destination, ElementType&& source)
567  {
568  *destination = std::move (source);
569  }
570 
571  template <typename T = ElementType>
572  typename std::enable_if<! std::is_move_assignable<T>::value, void>::type
573  moveAssignElement (ElementType* destination, ElementType&& source)
574  {
575  destination->~ElementType();
576  new (destination) ElementType (std::move (source));
577  }
578 
579  void checkSourceIsNotAMember (const ElementType* element)
580  {
581  // when you pass a reference to an existing element into a method like add() which
582  // may need to reallocate the array to make more space, the incoming reference may
583  // be deleted indirectly during the reallocation operation! To work around this,
584  // make a local copy of the item you're trying to add (and maybe use std::move to
585  // move it into the add() method to avoid any extra overhead)
586  jassert (element < begin() || element >= end());
587  ignoreUnused (element);
588  }
589 
590  //==============================================================================
591  HeapBlock<ElementType> elements;
592  int numAllocated = 0, numUsed = 0;
593 
594  template <class OtherElementType, class OtherCriticalSection>
595  friend class ArrayBase;
596 
597  JUCE_DECLARE_NON_COPYABLE (ArrayBase)
598 };
599 
600 } // namespace juce
601 
602 /** @}*/
ArrayBase(ArrayBase< OtherElementType, OtherCriticalSection > &&other) noexcept
Converting move constructor.
void realloc(SizeType newNumElements, size_t elementSize=sizeof(ElementType))
Re-allocates a specified amount of memory.
A basic object container.
void free() noexcept
Frees any currently-allocated data.
void swapWith(HeapBlock< ElementType, otherBlockThrows > &other) noexcept
Swaps this object&#39;s data with the data of another HeapBlock.