LMMS
Loading...
Searching...
No Matches
OwnedArray.h
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the Water library.
5 Copyright (c) 2016 ROLI Ltd.
6 Copyright (C) 2017-2022 Filipe Coelho <falktx@falktx.com>
7
8 Permission is granted to use this software under the terms of the ISC license
9 http://www.isc.org/downloads/software-support-policy/isc-license/
10
11 Permission to use, copy, modify, and/or distribute this software for any
12 purpose with or without fee is hereby granted, provided that the above
13 copyright notice and this permission notice appear in all copies.
14
15 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
16 TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
18 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 OF THIS SOFTWARE.
22
23 ==============================================================================
24*/
25
26#ifndef WATER_OWNEDARRAY_H_INCLUDED
27#define WATER_OWNEDARRAY_H_INCLUDED
28
29#include "ArrayAllocationBase.h"
30
31#include "CarlaScopeUtils.hpp"
32
33namespace water {
34
35//==============================================================================
54template <class ObjectClass>
55
57{
58public:
59 //==============================================================================
62 : numUsed (0)
63 {
64 }
65
72 {
74 }
75
76 //==============================================================================
78 void clear (bool deleteObjects = true)
79 {
80 if (deleteObjects)
82
83 data.setAllocatedSize (0);
84 numUsed = 0;
85 }
86
87 //==============================================================================
89 void clearQuick (bool deleteObjects)
90 {
91 if (deleteObjects)
93
94 numUsed = 0;
95 }
96
97 //==============================================================================
101 inline size_t size() const noexcept
102 {
103 return numUsed;
104 }
105
107 inline bool isEmpty() const noexcept
108 {
109 return size() == 0;
110 }
111
120 inline ObjectClass* operator[] (const size_t index) const noexcept
121 {
122 if (index < numUsed)
123 {
124 CARLA_SAFE_ASSERT_RETURN(data.elements != nullptr, nullptr);
125 return data.elements [index];
126 }
127
128 return nullptr;
129 }
130
136 inline ObjectClass* getUnchecked (const int index) const noexcept
137 {
138 return data.elements [index];
139 }
140
146 inline ObjectClass* getFirst() const noexcept
147 {
148 if (numUsed > 0)
149 {
150 CARLA_SAFE_ASSERT_RETURN(data.elements != nullptr, nullptr);
151 return data.elements [0];
152 }
153
154 return nullptr;
155 }
156
162 inline ObjectClass* getLast() const noexcept
163 {
164 if (numUsed > 0)
165 {
166 CARLA_SAFE_ASSERT_RETURN(data.elements != nullptr, nullptr);
167 return data.elements [numUsed - 1];
168 }
169
170 return nullptr;
171 }
172
177 inline ObjectClass** getRawDataPointer() noexcept
178 {
179 return data.elements;
180 }
181
182 //==============================================================================
186 inline ObjectClass** begin() const noexcept
187 {
188 return data.elements;
189 }
190
194 inline ObjectClass** end() const noexcept
195 {
196 #ifdef DEBUG
197 if (data.elements == nullptr || numUsed <= 0) // (to keep static analysers happy)
198 return data.elements;
199 #endif
200
201 return data.elements + numUsed;
202 }
203
204 //==============================================================================
210 int indexOf (const ObjectClass* objectToLookFor) const noexcept
211 {
212 ObjectClass* const* e = data.elements.getData();
213 ObjectClass* const* const end_ = e + numUsed;
214
215 for (; e != end_; ++e)
216 if (objectToLookFor == *e)
217 return static_cast<int> (e - data.elements.getData());
218
219 return -1;
220 }
221
227 bool contains (const ObjectClass* objectToLookFor) const noexcept
228 {
229 ObjectClass* const* e = data.elements.getData();
230 ObjectClass* const* const end_ = e + numUsed;
231
232 for (; e != end_; ++e)
233 if (objectToLookFor == *e)
234 return true;
235
236 return false;
237 }
238
239 //==============================================================================
252 ObjectClass* add (ObjectClass* newObject) noexcept
253 {
254 if (! data.ensureAllocatedSize (numUsed + 1))
255 return nullptr;
256
257 data.elements [numUsed++] = newObject;
258 return newObject;
259 }
260
279 ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject) noexcept
280 {
281 if (indexToInsertAt < 0)
282 return add (newObject);
283
284 size_t uindexToInsertAt = static_cast<size_t>(indexToInsertAt);
285
286 if (uindexToInsertAt > numUsed)
287 uindexToInsertAt = numUsed;
288
289 if (! data.ensureAllocatedSize (numUsed + 1))
290 return nullptr;
291
292 ObjectClass** const e = data.elements + uindexToInsertAt;
293 const int numToMove = numUsed - uindexToInsertAt;
294
295 if (numToMove > 0)
296 std::memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
297
298 *e = newObject;
299 ++numUsed;
300 return newObject;
301 }
302
315 void insertArray (const size_t indexToInsertAt,
316 ObjectClass* const* newObjects,
317 const size_t numberOfElements)
318 {
319 if (numberOfElements > 0)
320 {
321 data.ensureAllocatedSize (numUsed + numberOfElements);
322 ObjectClass** insertPos = data.elements;
323
324 if (indexToInsertAt < numUsed)
325 {
326 insertPos += indexToInsertAt;
327 const size_t numberToMove = numUsed - indexToInsertAt;
328 std::memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ObjectClass*));
329 }
330 else
331 {
332 insertPos += numUsed;
333 }
334
335 numUsed += numberOfElements;
336
337 for (size_t i=0; i < numberOfElements; ++i)
338 *insertPos++ = *newObjects++;
339 }
340 }
341
350 bool addIfNotAlreadyThere (ObjectClass* newObject) noexcept
351 {
352 if (contains (newObject))
353 return false;
354
355 return add (newObject) != nullptr;
356 }
357
371 ObjectClass* set (int indexToChange, ObjectClass* newObject, bool deleteOldElement = true)
372 {
373 if (indexToChange >= 0)
374 {
375 CarlaScopedPointer<ObjectClass> toDelete;
376
377 {
378 if (indexToChange < numUsed)
379 {
380 if (deleteOldElement)
381 {
382 toDelete = data.elements [indexToChange];
383
384 if (toDelete == newObject)
385 toDelete.release();
386 }
387
388 data.elements [indexToChange] = newObject;
389 }
390 else
391 {
392 data.ensureAllocatedSize (numUsed + 1);
393 data.elements [numUsed++] = newObject;
394 }
395 }
396 }
397 else
398 {
399 wassertfalse; // you're trying to set an object at a negative index, which doesn't have
400 // any effect - but since the object is not being added, it may be leaking..
401 }
402
403 return newObject;
404 }
405
415 template <class OtherArrayType>
416 void addArray (const OtherArrayType& arrayToAddFrom,
417 int startIndex = 0,
418 int numElementsToAdd = -1)
419 {
420 if (startIndex < 0)
421 {
423 startIndex = 0;
424 }
425
426 if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
427 numElementsToAdd = arrayToAddFrom.size() - startIndex;
428
429 data.ensureAllocatedSize (numUsed + numElementsToAdd);
430 wassert (numElementsToAdd <= 0 || data.elements != nullptr);
431
432 while (--numElementsToAdd >= 0)
433 {
434 data.elements [numUsed] = arrayToAddFrom.getUnchecked (startIndex++);
435 ++numUsed;
436 }
437 }
438
453 template <class OtherArrayType>
454 void addCopiesOf (const OtherArrayType& arrayToAddFrom,
455 size_t startIndex = 0,
456 int numElementsToAdd = -1)
457 {
458 if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
459 numElementsToAdd = arrayToAddFrom.size() - startIndex;
460
461 data.ensureAllocatedSize (numUsed + numElementsToAdd);
462 wassert (numElementsToAdd <= 0 || data.elements != nullptr);
463
464 while (--numElementsToAdd >= 0)
465 data.elements [numUsed++] = createCopyIfNotNull (arrayToAddFrom.getUnchecked (startIndex++));
466 }
467
480 template <class ElementComparator>
481 int addSorted (ElementComparator& comparator, ObjectClass* const newObject) noexcept
482 {
483 ignoreUnused (comparator); // if you pass in an object with a static compareElements() method, this
484 // avoids getting warning messages about the parameter being unused
485 const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
486 insert (index, newObject);
487 return index;
488 }
489
502 template <typename ElementComparator>
503 int indexOfSorted (ElementComparator& comparator, const ObjectClass* const objectToLookFor) const noexcept
504 {
505 ignoreUnused (comparator);
506 int s = 0, e = numUsed;
507
508 while (s < e)
509 {
510 if (comparator.compareElements (objectToLookFor, data.elements [s]) == 0)
511 return s;
512
513 const int halfway = (s + e) / 2;
514 if (halfway == s)
515 break;
516
517 if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0)
518 s = halfway;
519 else
520 e = halfway;
521 }
522
523 return -1;
524 }
525
526 //==============================================================================
537 void remove (const size_t indexToRemove, bool deleteObject = true)
538 {
539 CarlaScopedPointer<ObjectClass> toDelete;
540
541 if (indexToRemove < numUsed)
542 {
543 ObjectClass** const e = data.elements + indexToRemove;
544
545 if (deleteObject)
546 toDelete = *e;
547
548 --numUsed;
549 const size_t numToShift = numUsed - indexToRemove;
550
551 if (numToShift > 0)
552 std::memmove (e, e + 1, sizeof (ObjectClass*) * numToShift);
553 }
554
555 if ((numUsed << 1) < data.numAllocated)
557 }
558
568 ObjectClass* removeAndReturn (const size_t indexToRemove)
569 {
570 ObjectClass* removedItem = nullptr;
571 if (indexToRemove < numUsed)
572 {
573 ObjectClass** const e = data.elements + indexToRemove;
574 removedItem = *e;
575
576 --numUsed;
577 const size_t numToShift = numUsed - indexToRemove;
578
579 if (numToShift > 0)
580 std::memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numToShift);
581
582 if ((numUsed << 1) < data.numAllocated)
584 }
585
586 return removedItem;
587 }
588
597 void removeObject (const ObjectClass* objectToRemove, bool deleteObject = true)
598 {
599 ObjectClass** const e = data.elements.getData();
600
601 for (int i = 0; i < numUsed; ++i)
602 {
603 if (objectToRemove == e[i])
604 {
605 remove (i, deleteObject);
606 break;
607 }
608 }
609 }
610
624 void removeRange (size_t startIndex, const size_t numberToRemove, bool deleteObjects = true)
625 {
626 const size_t endIndex = jlimit ((size_t)0U, numUsed, startIndex + numberToRemove);
627 startIndex = jlimit ((size_t)0U, numUsed, startIndex);
628
629 if (endIndex > startIndex)
630 {
631 if (deleteObjects)
632 {
633 for (int i = startIndex; i < endIndex; ++i)
634 {
635 delete data.elements [i];
636 data.elements [i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
637 }
638 }
639
640 const size_t rangeSize = endIndex - startIndex;
641 ObjectClass** e = data.elements + startIndex;
642 size_t numToShift = numUsed - endIndex;
643 numUsed -= rangeSize;
644
645 for (size_t i=0; i < numToShift; ++i)
646 {
647 *e = e [rangeSize];
648 ++e;
649 }
650
651 if ((numUsed << 1) < data.numAllocated)
653 }
654 }
655
662 void removeLast (int howManyToRemove = 1,
663 bool deleteObjects = true)
664 {
665 if (howManyToRemove >= numUsed)
666 clear (deleteObjects);
667 else
668 removeRange (numUsed - howManyToRemove, howManyToRemove, deleteObjects);
669 }
670
676 void swap (const size_t index1,
677 const size_t index2) noexcept
678 {
679 if (index1 < numUsed && index2 < numUsed)
680 {
681 std::swap (data.elements [index1],
682 data.elements [index2]);
683 }
684 }
685
699 void move (const size_t currentIndex, size_t newIndex) noexcept
700 {
701 if (currentIndex != newIndex)
702 {
703 if (currentIndex < numUsed)
704 {
705 if (newIndex >= numUsed)
706 newIndex = numUsed - 1;
707
708 ObjectClass* const value = data.elements [currentIndex];
709
710 if (newIndex > currentIndex)
711 {
712 std::memmove (data.elements + currentIndex,
713 data.elements + currentIndex + 1,
714 sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
715 }
716 else
717 {
718 std::memmove (data.elements + newIndex + 1,
719 data.elements + newIndex,
720 sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
721 }
722
723 data.elements [newIndex] = value;
724 }
725 }
726 }
727
733 template <class OtherArrayType>
734 void swapWith (OtherArrayType& otherArray) noexcept
735 {
736 data.swapWith (otherArray.data);
737 std::swap (numUsed, otherArray.numUsed);
738 }
739
740 //==============================================================================
748 {
749 return data.shrinkToNoMoreThan (numUsed);
750 }
751
758 bool ensureStorageAllocated (const int minNumElements) noexcept
759 {
760 return data.ensureAllocatedSize (minNumElements);
761 }
762
763 //==============================================================================
789 template <class ElementComparator>
790 void sort (ElementComparator& comparator,
791 bool retainOrderOfEquivalentItems = false) const noexcept
792 {
793 ignoreUnused (comparator); // if you pass in an object with a static compareElements() method, this
794 // avoids getting warning messages about the parameter being unused
795
796 sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
797 }
798
799private:
800 //==============================================================================
801 ArrayAllocationBase <ObjectClass*> data;
802 size_t numUsed;
803
805 {
806 while (numUsed > 0)
807 delete data.elements [--numUsed];
808 }
809
811};
812
813}
814
815#endif // WATER_OWNEDARRAY_H_INCLUDED
#define CARLA_SAFE_ASSERT_RETURN(cond, ret)
Definition CarlaDefines.h:190
#define CARLA_DECLARE_NON_COPYABLE(ClassName)
Definition CarlaDefines.h:242
#define noexcept
Definition DistrhoDefines.h:72
Definition OwnedArray.h:57
ArrayAllocationBase< ObjectClass * > data
Definition OwnedArray.h:801
bool contains(const ObjectClass *objectToLookFor) const noexcept
Definition OwnedArray.h:227
size_t numUsed
Definition OwnedArray.h:802
void clear(bool deleteObjects=true)
Definition OwnedArray.h:78
ObjectClass * getUnchecked(const int index) const noexcept
Definition OwnedArray.h:136
void clearQuick(bool deleteObjects)
Definition OwnedArray.h:89
ObjectClass * getFirst() const noexcept
Definition OwnedArray.h:146
ObjectClass * set(int indexToChange, ObjectClass *newObject, bool deleteOldElement=true)
Definition OwnedArray.h:371
void removeLast(int howManyToRemove=1, bool deleteObjects=true)
Definition OwnedArray.h:662
ObjectClass ** end() const noexcept
Definition OwnedArray.h:194
bool ensureStorageAllocated(const int minNumElements) noexcept
Definition OwnedArray.h:758
ObjectClass * removeAndReturn(const size_t indexToRemove)
Definition OwnedArray.h:568
ObjectClass ** getRawDataPointer() noexcept
Definition OwnedArray.h:177
ObjectClass * operator[](const size_t index) const noexcept
Definition OwnedArray.h:120
int indexOf(const ObjectClass *objectToLookFor) const noexcept
Definition OwnedArray.h:210
ObjectClass ** begin() const noexcept
Definition OwnedArray.h:186
void addCopiesOf(const OtherArrayType &arrayToAddFrom, size_t startIndex=0, int numElementsToAdd=-1)
Definition OwnedArray.h:454
bool isEmpty() const noexcept
Definition OwnedArray.h:107
void removeRange(size_t startIndex, const size_t numberToRemove, bool deleteObjects=true)
Definition OwnedArray.h:624
void sort(ElementComparator &comparator, bool retainOrderOfEquivalentItems=false) const noexcept
Definition OwnedArray.h:790
ObjectClass * insert(int indexToInsertAt, ObjectClass *newObject) noexcept
Definition OwnedArray.h:279
void deleteAllObjects()
Definition OwnedArray.h:804
void remove(const size_t indexToRemove, bool deleteObject=true)
Definition OwnedArray.h:537
size_t size() const noexcept
Definition OwnedArray.h:101
void insertArray(const size_t indexToInsertAt, ObjectClass *const *newObjects, const size_t numberOfElements)
Definition OwnedArray.h:315
OwnedArray() noexcept
Definition OwnedArray.h:61
int indexOfSorted(ElementComparator &comparator, const ObjectClass *const objectToLookFor) const noexcept
Definition OwnedArray.h:503
ObjectClass * getLast() const noexcept
Definition OwnedArray.h:162
int addSorted(ElementComparator &comparator, ObjectClass *const newObject) noexcept
Definition OwnedArray.h:481
void addArray(const OtherArrayType &arrayToAddFrom, int startIndex=0, int numElementsToAdd=-1)
Definition OwnedArray.h:416
void removeObject(const ObjectClass *objectToRemove, bool deleteObject=true)
Definition OwnedArray.h:597
void swapWith(OtherArrayType &otherArray) noexcept
Definition OwnedArray.h:734
bool minimiseStorageOverheads() noexcept
Definition OwnedArray.h:747
ObjectClass * add(ObjectClass *newObject) noexcept
Definition OwnedArray.h:252
void move(const size_t currentIndex, size_t newIndex) noexcept
Definition OwnedArray.h:699
~OwnedArray()
Definition OwnedArray.h:71
bool addIfNotAlreadyThere(ObjectClass *newObject) noexcept
Definition OwnedArray.h:350
void swap(const size_t index1, const size_t index2) noexcept
Definition OwnedArray.h:676
* e
Definition inflate.c:1404
register unsigned i
Definition inflate.c:1575
unsigned s
Definition inflate.c:1555
#define U(x)
Definition fmopl.c:132
static PuglViewHint int value
Definition pugl.h:1708
#define wassertfalse
#define wassert(expression)
Definition AudioSampleBuffer.h:33
static int findInsertIndexInSortedArray(ElementComparator &comparator, ElementType *const array, const ElementType newElement, int firstElement, int lastElement)
Definition ElementComparator.h:119
void ignoreUnused(const Type1 &) noexcept
Definition MathsFunctions.h:237
Type jlimit(const Type lowerLimit, const Type upperLimit, const Type valueToConstrain) noexcept
Definition MathsFunctions.h:169
Type * createCopyIfNotNull(const Type *objectToCopy)
Definition Memory.h:68
static void sortArray(ElementComparator &comparator, ElementType *const array, int firstElement, int lastElement, const bool retainOrderOfEquivalentItems)
Definition ElementComparator.h:79
#define const
Definition zconf.h:137