diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j index 1f96bacdb..ba0dea1b0 100644 --- a/Foundation/CPIndexSet.j +++ b/Foundation/CPIndexSet.j @@ -483,28 +483,65 @@ return description; } -- (void)enumerateIndexesUsingBlock:(Function /*(int idx, @ref BOOL) */)aFunction +- (void)enumerateIndexesUsingBlock:(Function /*(int idx, @ref BOOL stop) */)aFunction +{ + [self enumerateIndexesWithOptions:CPEnumerationNormal usingBlock:aFunction]; +} + +- (void)enumerateIndexesWithOptions:(CPEnumerationOptions)options usingBlock:(Function /*(int idx, @ref BOOL stop)*/)aFunction { if (!_count) return; - var index = 0, - stop = NO; + var shouldStop = NO, + index, + stop, + increment; - for (var i = 0, count = _ranges.length; i < count; i++) + if (options & CPEnumerationReverse) { - var range = _ranges[i], - maximum = CPMaxRange(range); + index = _ranges.length - 1, + stop = -1, + increment = -1; + } + else + { + index = 0; + stop = _ranges.length; + increment = 1; + } - for (var j = range.location; j < maximum; j++) + for (; index !== stop; index += increment) + { + var range = _ranges[index]; + + var rangeIndex, + rangeStop, + rangeIncrement; + + if (options & CPEnumerationReverse) { - aFunction(j, AT_REF(stop)); - if (stop) + rangeIndex = CPMaxRange(range) - 1; + rangeStop = range.location - 1; + rangeIncrement = -1; + } + else + { + rangeIndex = range.location; + rangeStop = CPMaxRange(range); + rangeIncrement = 1; + } + + for (; rangeIndex !== rangeStop; rangeIndex += rangeIncrement) + { + aFunction(rangeIndex, AT_REF(shouldStop)); + if (shouldStop) return; } } } + @end @implementation CPIndexSet(CPMutableIndexSet) diff --git a/Tests/Foundation/CPIndexSetTest.j b/Tests/Foundation/CPIndexSetTest.j index 2ff470007..019114210 100644 --- a/Tests/Foundation/CPIndexSetTest.j +++ b/Tests/Foundation/CPIndexSetTest.j @@ -433,7 +433,7 @@ function descriptionWithoutEntity(aString) }; [set0 enumerateIndexesUsingBlock:aBlock]; - [self assert:0 equals:[visitedIndexes count] message:"enumerate empty set"]; + [self assert:[] equals:visitedIndexes message:"enumerate empty set"]; [set1 enumerateIndexesUsingBlock:aBlock]; [self assert:[3, 4] equals:visitedIndexes message:"enumerate " + [set1 description]]; @@ -443,6 +443,50 @@ function descriptionWithoutEntity(aString) [self assert:[0, 3, 4] equals:visitedIndexes message:"enumerate " + [set2 description]]; } +- (void)testEnumerateIndexesWithOptions_usingBlock_ +{ + var set0 = [CPIndexSet indexSet], + set1 = [CPMutableIndexSet indexSet], + set2 = [CPMutableIndexSet indexSet]; + + [set1 addIndexesInRange:CPMakeRange(3, 2)]; + + [set2 addIndexesInRange:CPMakeRange(3, 2)]; + [set2 addIndexesInRange:CPMakeRange(0, 1)]; + + var visitedIndexes = [], + aBlock; + + aBlock = function(idx) + { + visitedIndexes.push(idx); + }; + + [set0 enumerateIndexesWithOptions:CPEnumerationNormal usingBlock:aBlock]; + [self assert:[] equals:visitedIndexes message:"enumerate empty set"]; + + [set1 enumerateIndexesWithOptions:CPEnumerationNormal usingBlock:aBlock]; + [self assert:[3, 4] equals:visitedIndexes message:"enumerate " + [set1 description]]; + + visitedIndexes = []; + [set2 enumerateIndexesWithOptions:CPEnumerationNormal usingBlock:aBlock]; + [self assert:[0, 3, 4] equals:visitedIndexes message:"enumerate " + [set2 description]]; + + visitedIndexes = []; + [set0 enumerateIndexesWithOptions:CPEnumerationReverse usingBlock:aBlock]; + [self assert:[] equals:visitedIndexes message:"reverse enumerate empty set"]; + + visitedIndexes = []; + [set1 enumerateIndexesWithOptions:CPEnumerationReverse usingBlock:aBlock]; + [self assert:[4, 3] equals:visitedIndexes message:"reverse enumerate " + [set1 description]]; + + visitedIndexes = []; + [set2 enumerateIndexesWithOptions:CPEnumerationReverse usingBlock:aBlock]; + [self assert:[4, 3, 0] equals:visitedIndexes message:"reverse enumerate " + [set2 description]]; + +} + + - (void)tearDown { _set = nil;