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_SPARSESET_JUCEHEADER__
27 #define __JUCE_SPARSESET_JUCEHEADER__
29 #include "../maths/juce_Range.h"
30 #include "../threads/juce_CriticalSection.h"
33 //==============================================================================
35 Holds a set of primitive values, storing them as a set of ranges.
37 This container acts like an array, but can efficiently hold large continguous
38 ranges of values. It's quite a specialised class, mostly useful for things
39 like keeping the set of selected rows in a listbox.
41 The type used as a template paramter must be an integer type, such as int, short,
48 //==============================================================================
49 /** Creates a new empty set. */
54 /** Creates a copy of another SparseSet. */
55 SparseSet (const SparseSet
<Type
>& other
)
56 : values (other
.values
)
60 //==============================================================================
61 /** Clears the set. */
67 /** Checks whether the set is empty.
69 This is much quicker than using (size() == 0).
71 bool isEmpty() const noexcept
73 return values
.size() == 0;
76 /** Returns the number of values in the set.
78 Because of the way the data is stored, this method can take longer if there
79 are a lot of items in the set. Use isEmpty() for a quick test of whether there
86 for (int i
= 0; i
< values
.size(); i
+= 2)
87 total
+= values
.getUnchecked (i
+ 1) - values
.getUnchecked (i
);
92 /** Returns one of the values in the set.
94 @param index the index of the value to retrieve, in the range 0 to (size() - 1).
95 @returns the value at this index, or 0 if it's out-of-range
97 Type
operator[] (Type index
) const
99 for (int i
= 0; i
< values
.size(); i
+= 2)
101 const Type
start (values
.getUnchecked (i
));
102 const Type
len (values
.getUnchecked (i
+ 1) - start
);
105 return start
+ index
;
113 /** Checks whether a particular value is in the set. */
114 bool contains (const Type valueToLookFor
) const
116 for (int i
= 0; i
< values
.size(); ++i
)
117 if (valueToLookFor
< values
.getUnchecked(i
))
123 //==============================================================================
124 /** Returns the number of contiguous blocks of values.
127 int getNumRanges() const noexcept
129 return values
.size() >> 1;
132 /** Returns one of the contiguous ranges of values stored.
133 @param rangeIndex the index of the range to look up, between 0
134 and (getNumRanges() - 1)
137 const Range
<Type
> getRange (const int rangeIndex
) const
139 if (isPositiveAndBelow (rangeIndex
, getNumRanges()))
140 return Range
<Type
> (values
.getUnchecked (rangeIndex
<< 1),
141 values
.getUnchecked ((rangeIndex
<< 1) + 1));
143 return Range
<Type
>();
146 /** Returns the range between the lowest and highest values in the set.
149 const Range
<Type
> getTotalRange() const
151 if (values
.size() > 0)
153 jassert ((values
.size() & 1) == 0);
154 return Range
<Type
> (values
.getUnchecked (0),
155 values
.getUnchecked (values
.size() - 1));
158 return Range
<Type
>();
161 //==============================================================================
162 /** Adds a range of contiguous values to the set.
163 e.g. addRange (Range \<int\> (10, 14)) will add (10, 11, 12, 13) to the set.
165 void addRange (const Range
<Type
>& range
)
167 jassert (range
.getLength() >= 0);
168 if (range
.getLength() > 0)
172 values
.addUsingDefaultSort (range
.getStart());
173 values
.addUsingDefaultSort (range
.getEnd());
179 /** Removes a range of values from the set.
180 e.g. removeRange (Range\<int\> (10, 14)) will remove (10, 11, 12, 13) from the set.
182 void removeRange (const Range
<Type
>& rangeToRemove
)
184 jassert (rangeToRemove
.getLength() >= 0);
186 if (rangeToRemove
.getLength() > 0
188 && rangeToRemove
.getStart() < values
.getUnchecked (values
.size() - 1)
189 && values
.getUnchecked(0) < rangeToRemove
.getEnd())
191 const bool onAtStart
= contains (rangeToRemove
.getStart() - 1);
192 const Type
lastValue (jmin (rangeToRemove
.getEnd(), values
.getLast()));
193 const bool onAtEnd
= contains (lastValue
);
195 for (int i
= values
.size(); --i
>= 0;)
197 if (values
.getUnchecked(i
) <= lastValue
)
199 while (values
.getUnchecked(i
) >= rangeToRemove
.getStart())
211 if (onAtStart
) values
.addUsingDefaultSort (rangeToRemove
.getStart());
212 if (onAtEnd
) values
.addUsingDefaultSort (lastValue
);
218 /** Does an XOR of the values in a given range. */
219 void invertRange (const Range
<Type
>& range
)
222 newItems
.addRange (range
);
225 for (i
= getNumRanges(); --i
>= 0;)
226 newItems
.removeRange (getRange (i
));
230 for (i
= newItems
.getNumRanges(); --i
>= 0;)
231 addRange (newItems
.getRange(i
));
234 /** Checks whether any part of a given range overlaps any part of this set. */
235 bool overlapsRange (const Range
<Type
>& range
)
237 if (range
.getLength() > 0)
239 for (int i
= getNumRanges(); --i
>= 0;)
241 if (values
.getUnchecked ((i
<< 1) + 1) <= range
.getStart())
244 if (values
.getUnchecked (i
<< 1) < range
.getEnd())
252 /** Checks whether the whole of a given range is contained within this one. */
253 bool containsRange (const Range
<Type
>& range
)
255 if (range
.getLength() > 0)
257 for (int i
= getNumRanges(); --i
>= 0;)
259 if (values
.getUnchecked ((i
<< 1) + 1) <= range
.getStart())
262 if (values
.getUnchecked (i
<< 1) <= range
.getStart()
263 && range
.getEnd() <= values
.getUnchecked ((i
<< 1) + 1))
271 //==============================================================================
272 bool operator== (const SparseSet
<Type
>& other
) noexcept
274 return values
== other
.values
;
277 bool operator!= (const SparseSet
<Type
>& other
) noexcept
279 return values
!= other
.values
;
283 //==============================================================================
284 // alternating start/end values of ranges of values that are present.
285 Array
<Type
, DummyCriticalSection
> values
;
289 jassert ((values
.size() & 1) == 0);
291 for (int i
= values
.size(); --i
> 0;)
292 if (values
.getUnchecked(i
) == values
.getUnchecked (i
- 1))
293 values
.removeRange (--i
, 2);
299 #endif // __JUCE_SPARSESET_JUCEHEADER__