OpenShot Audio Library | OpenShotAudio: juce_ArrayBase.h Source File

OpenShot Audio Library | OpenShotAudio 0.3.0

Loading...
Searching...
No Matches
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
23namespace juce
24{
25
39template <class ElementType, class TypeOfCriticalSectionToUse>
40 class ArrayBase : public TypeOfCriticalSectionToUse
41{
42private:
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
49public:
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>>
86 ArrayBase (ArrayBase<OtherElementType, OtherCriticalSection>&& other) noexcept
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>>
103 ArrayBase& operator= (ArrayBase<OtherElementType, OtherCriticalSection>&& other) noexcept
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
394private:
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
juce::ArrayBase
Definition: juce_ArrayBase.h:41
juce::ArrayBase::ArrayBase
ArrayBase(ArrayBase< OtherElementType, OtherCriticalSection > &&other) noexcept
Definition: juce_ArrayBase.h:86