OpenShot Library | libopenshot-audio 0.2.0
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
27namespace 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*/
43template <class ElementType, class TypeOfCriticalSectionToUse>
44class ArrayBase : public TypeOfCriticalSectionToUse
45{
46private:
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
53public:
54 //==============================================================================
55 ArrayBase() = default;
56
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
376private:
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/** @}*/
A basic object container.
ArrayBase(ArrayBase< OtherElementType, OtherCriticalSection > &&other) noexcept
Converting move constructor.