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
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) 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
398private:
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/** @}*/
A basic object container.
ArrayBase(ArrayBase< OtherElementType, OtherCriticalSection > &&other) noexcept
Converting move constructor.