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