Add remaining files
[juce-lv2.git] / juce / source / src / containers / juce_SortedSet.h
blob1bf620134080f8ed9e47353926b9c0b40db45187
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #ifndef __JUCE_SORTEDSET_JUCEHEADER__
27 #define __JUCE_SORTEDSET_JUCEHEADER__
29 #include "juce_ArrayAllocationBase.h"
30 #include "../threads/juce_CriticalSection.h"
32 #if JUCE_MSVC
33 #pragma warning (push)
34 #pragma warning (disable: 4512)
35 #endif
38 //==============================================================================
39 /**
40 Holds a set of unique primitive objects, such as ints or doubles.
42 A set can only hold one item with a given value, so if for example it's a
43 set of integers, attempting to add the same integer twice will do nothing
44 the second time.
46 Internally, the list of items is kept sorted (which means that whatever
47 kind of primitive type is used must support the ==, <, >, <= and >= operators
48 to determine the order), and searching the set for known values is very fast
49 because it uses a binary-chop method.
51 Note that if you're using a class or struct as the element type, it must be
52 capable of being copied or moved with a straightforward memcpy, rather than
53 needing construction and destruction code.
55 To make all the set's methods thread-safe, pass in "CriticalSection" as the templated
56 TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
58 @see Array, OwnedArray, ReferenceCountedArray, StringArray, CriticalSection
60 template <class ElementType, class TypeOfCriticalSectionToUse = DummyCriticalSection>
61 class SortedSet
63 public:
64 //==============================================================================
65 /** Creates an empty set. */
66 SortedSet() noexcept
67 : numUsed (0)
71 /** Creates a copy of another set.
72 @param other the set to copy
74 SortedSet (const SortedSet& other) noexcept
76 const ScopedLockType lock (other.getLock());
77 numUsed = other.numUsed;
78 data.setAllocatedSize (other.numUsed);
79 memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType));
82 /** Destructor. */
83 ~SortedSet() noexcept
87 /** Copies another set over this one.
88 @param other the set to copy
90 SortedSet& operator= (const SortedSet& other) noexcept
92 if (this != &other)
94 const ScopedLockType lock1 (other.getLock());
95 const ScopedLockType lock2 (getLock());
97 data.ensureAllocatedSize (other.size());
98 numUsed = other.numUsed;
99 memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType));
100 minimiseStorageOverheads();
103 return *this;
106 //==============================================================================
107 /** Compares this set to another one.
109 Two sets are considered equal if they both contain the same set of
110 elements.
112 @param other the other set to compare with
114 bool operator== (const SortedSet<ElementType>& other) const noexcept
116 const ScopedLockType lock (getLock());
118 if (numUsed != other.numUsed)
119 return false;
121 for (int i = numUsed; --i >= 0;)
122 if (! (data.elements[i] == other.data.elements[i]))
123 return false;
125 return true;
128 /** Compares this set to another one.
130 Two sets are considered equal if they both contain the same set of
131 elements.
133 @param other the other set to compare with
135 bool operator!= (const SortedSet<ElementType>& other) const noexcept
137 return ! operator== (other);
140 //==============================================================================
141 /** Removes all elements from the set.
143 This will remove all the elements, and free any storage that the set is
144 using. To clear it without freeing the storage, use the clearQuick()
145 method instead.
147 @see clearQuick
149 void clear() noexcept
151 const ScopedLockType lock (getLock());
152 data.setAllocatedSize (0);
153 numUsed = 0;
156 /** Removes all elements from the set without freeing the array's allocated storage.
158 @see clear
160 void clearQuick() noexcept
162 const ScopedLockType lock (getLock());
163 numUsed = 0;
166 //==============================================================================
167 /** Returns the current number of elements in the set.
169 inline int size() const noexcept
171 return numUsed;
174 /** Returns one of the elements in the set.
176 If the index passed in is beyond the range of valid elements, this
177 will return zero.
179 If you're certain that the index will always be a valid element, you
180 can call getUnchecked() instead, which is faster.
182 @param index the index of the element being requested (0 is the first element in the set)
183 @see getUnchecked, getFirst, getLast
185 inline ElementType operator[] (const int index) const noexcept
187 const ScopedLockType lock (getLock());
188 return isPositiveAndBelow (index, numUsed) ? data.elements [index]
189 : ElementType();
192 /** Returns one of the elements in the set, without checking the index passed in.
193 Unlike the operator[] method, this will try to return an element without
194 checking that the index is within the bounds of the set, so should only
195 be used when you're confident that it will always be a valid index.
197 @param index the index of the element being requested (0 is the first element in the set)
198 @see operator[], getFirst, getLast
200 inline ElementType getUnchecked (const int index) const noexcept
202 const ScopedLockType lock (getLock());
203 jassert (isPositiveAndBelow (index, numUsed));
204 return data.elements [index];
207 /** Returns a direct reference to one of the elements in the set, without checking the index passed in.
209 This is like getUnchecked, but returns a direct reference to the element, so that
210 you can alter it directly. Obviously this can be dangerous, so only use it when
211 absolutely necessary.
213 @param index the index of the element being requested (0 is the first element in the array)
215 inline ElementType& getReference (const int index) const noexcept
217 const ScopedLockType lock (getLock());
218 jassert (isPositiveAndBelow (index, numUsed));
219 return data.elements [index];
222 /** Returns the first element in the set, or 0 if the set is empty.
224 @see operator[], getUnchecked, getLast
226 inline ElementType getFirst() const noexcept
228 const ScopedLockType lock (getLock());
229 return numUsed > 0 ? data.elements [0] : ElementType();
232 /** Returns the last element in the set, or 0 if the set is empty.
234 @see operator[], getUnchecked, getFirst
236 inline ElementType getLast() const noexcept
238 const ScopedLockType lock (getLock());
239 return numUsed > 0 ? data.elements [numUsed - 1] : ElementType();
242 //==============================================================================
243 /** Returns a pointer to the first element in the set.
244 This method is provided for compatibility with standard C++ iteration mechanisms.
246 inline ElementType* begin() const noexcept
248 return data.elements;
251 /** Returns a pointer to the element which follows the last element in the set.
252 This method is provided for compatibility with standard C++ iteration mechanisms.
254 inline ElementType* end() const noexcept
256 return data.elements + numUsed;
259 //==============================================================================
260 /** Finds the index of the first element which matches the value passed in.
262 This will search the set for the given object, and return the index
263 of its first occurrence. If the object isn't found, the method will return -1.
265 @param elementToLookFor the value or object to look for
266 @returns the index of the object, or -1 if it's not found
268 int indexOf (const ElementType elementToLookFor) const noexcept
270 const ScopedLockType lock (getLock());
272 int start = 0;
273 int end_ = numUsed;
275 for (;;)
277 if (start >= end_)
279 return -1;
281 else if (elementToLookFor == data.elements [start])
283 return start;
285 else
287 const int halfway = (start + end_) >> 1;
289 if (halfway == start)
290 return -1;
291 else if (elementToLookFor < data.elements [halfway])
292 end_ = halfway;
293 else
294 start = halfway;
299 /** Returns true if the set contains at least one occurrence of an object.
301 @param elementToLookFor the value or object to look for
302 @returns true if the item is found
304 bool contains (const ElementType elementToLookFor) const noexcept
306 const ScopedLockType lock (getLock());
308 int start = 0;
309 int end_ = numUsed;
311 for (;;)
313 if (start >= end_)
315 return false;
317 else if (elementToLookFor == data.elements [start])
319 return true;
321 else
323 const int halfway = (start + end_) >> 1;
325 if (halfway == start)
326 return false;
327 else if (elementToLookFor < data.elements [halfway])
328 end_ = halfway;
329 else
330 start = halfway;
335 //==============================================================================
336 /** Adds a new element to the set, (as long as it's not already in there).
338 @param newElement the new object to add to the set
339 @see set, insert, addIfNotAlreadyThere, addSorted, addSet, addArray
341 void add (const ElementType newElement) noexcept
343 const ScopedLockType lock (getLock());
345 int start = 0;
346 int end_ = numUsed;
348 for (;;)
350 if (start >= end_)
352 jassert (start <= end_);
353 insertInternal (start, newElement);
354 break;
356 else if (newElement == data.elements [start])
358 break;
360 else
362 const int halfway = (start + end_) >> 1;
364 if (halfway == start)
366 if (newElement < data.elements [halfway])
367 insertInternal (start, newElement);
368 else
369 insertInternal (start + 1, newElement);
371 break;
373 else if (newElement < data.elements [halfway])
374 end_ = halfway;
375 else
376 start = halfway;
381 /** Adds elements from an array to this set.
383 @param elementsToAdd the array of elements to add
384 @param numElementsToAdd how many elements are in this other array
385 @see add
387 void addArray (const ElementType* elementsToAdd,
388 int numElementsToAdd) noexcept
390 const ScopedLockType lock (getLock());
392 while (--numElementsToAdd >= 0)
393 add (*elementsToAdd++);
396 /** Adds elements from another set to this one.
398 @param setToAddFrom the set from which to copy the elements
399 @param startIndex the first element of the other set to start copying from
400 @param numElementsToAdd how many elements to add from the other set. If this
401 value is negative or greater than the number of available elements,
402 all available elements will be copied.
403 @see add
405 template <class OtherSetType>
406 void addSet (const OtherSetType& setToAddFrom,
407 int startIndex = 0,
408 int numElementsToAdd = -1) noexcept
410 const typename OtherSetType::ScopedLockType lock1 (setToAddFrom.getLock());
413 const ScopedLockType lock2 (getLock());
414 jassert (this != &setToAddFrom);
416 if (this != &setToAddFrom)
418 if (startIndex < 0)
420 jassertfalse;
421 startIndex = 0;
424 if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size())
425 numElementsToAdd = setToAddFrom.size() - startIndex;
427 addArray (setToAddFrom.elements + startIndex, numElementsToAdd);
433 //==============================================================================
434 /** Removes an element from the set.
436 This will remove the element at a given index.
437 If the index passed in is out-of-range, nothing will happen.
439 @param indexToRemove the index of the element to remove
440 @returns the element that has been removed
441 @see removeValue, removeRange
443 ElementType remove (const int indexToRemove) noexcept
445 const ScopedLockType lock (getLock());
447 if (isPositiveAndBelow (indexToRemove, numUsed))
449 --numUsed;
451 ElementType* const e = data.elements + indexToRemove;
452 ElementType const removed = *e;
453 const int numberToShift = numUsed - indexToRemove;
455 if (numberToShift > 0)
456 memmove (e, e + 1, numberToShift * sizeof (ElementType));
458 if ((numUsed << 1) < data.numAllocated)
459 minimiseStorageOverheads();
461 return removed;
464 return ElementType();
467 /** Removes an item from the set.
469 This will remove the given element from the set, if it's there.
471 @param valueToRemove the object to try to remove
472 @see remove, removeRange
474 void removeValue (const ElementType valueToRemove) noexcept
476 const ScopedLockType lock (getLock());
477 remove (indexOf (valueToRemove));
480 /** Removes any elements which are also in another set.
482 @param otherSet the other set in which to look for elements to remove
483 @see removeValuesNotIn, remove, removeValue, removeRange
485 template <class OtherSetType>
486 void removeValuesIn (const OtherSetType& otherSet) noexcept
488 const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
489 const ScopedLockType lock2 (getLock());
491 if (this == &otherSet)
493 clear();
495 else
497 if (otherSet.size() > 0)
499 for (int i = numUsed; --i >= 0;)
500 if (otherSet.contains (data.elements [i]))
501 remove (i);
506 /** Removes any elements which are not found in another set.
508 Only elements which occur in this other set will be retained.
510 @param otherSet the set in which to look for elements NOT to remove
511 @see removeValuesIn, remove, removeValue, removeRange
513 template <class OtherSetType>
514 void removeValuesNotIn (const OtherSetType& otherSet) noexcept
516 const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
517 const ScopedLockType lock2 (getLock());
519 if (this != &otherSet)
521 if (otherSet.size() <= 0)
523 clear();
525 else
527 for (int i = numUsed; --i >= 0;)
528 if (! otherSet.contains (data.elements [i]))
529 remove (i);
534 //==============================================================================
535 /** Reduces the amount of storage being used by the set.
537 Sets typically allocate slightly more storage than they need, and after
538 removing elements, they may have quite a lot of unused space allocated.
539 This method will reduce the amount of allocated storage to a minimum.
541 void minimiseStorageOverheads() noexcept
543 const ScopedLockType lock (getLock());
544 data.shrinkToNoMoreThan (numUsed);
547 /** Increases the set's internal storage to hold a minimum number of elements.
549 Calling this before adding a large known number of elements means that
550 the set won't have to keep dynamically resizing itself as the elements
551 are added, and it'll therefore be more efficient.
553 void ensureStorageAllocated (const int minNumElements)
555 const ScopedLockType lock (getLock());
556 data.ensureAllocatedSize (minNumElements);
559 //==============================================================================
560 /** Returns the CriticalSection that locks this array.
561 To lock, you can call getLock().enter() and getLock().exit(), or preferably use
562 an object of ScopedLockType as an RAII lock for it.
564 inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data; }
566 /** Returns the type of scoped lock to use for locking this array */
567 typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
570 private:
571 //==============================================================================
572 ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse> data;
573 int numUsed;
575 void insertInternal (const int indexToInsertAt, const ElementType newElement) noexcept
577 data.ensureAllocatedSize (numUsed + 1);
579 ElementType* const insertPos = data.elements + indexToInsertAt;
580 const int numberToMove = numUsed - indexToInsertAt;
582 if (numberToMove > 0)
583 memmove (insertPos + 1, insertPos, numberToMove * sizeof (ElementType));
585 *insertPos = newElement;
586 ++numUsed;
590 #if JUCE_MSVC
591 #pragma warning (pop)
592 #endif
594 #endif // __JUCE_SORTEDSET_JUCEHEADER__