mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-09 18:30:59 +00:00
Began work on rewriting CPIndexSet.
Reviewed by me.
This commit is contained in:
1 parent
ca1ea3721f
commit
d165761740
2 files changed
+215
-200
No files matched your search
@@ -574,7 +574,9 @@ CPTableViewSelectionHighlightStyleSourceList = 1;
|
||||
// O(Columns) if table view contains hidden columns
|
||||
- (CPInteger)columnAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
if (!CGRectContainsPoint([self bounds], aPoint))
|
||||
var bounds = [self bounds];
|
||||
|
||||
if (!_CGRectContainsPoint(bounds, aPoint))
|
||||
return CPNotFound;
|
||||
|
||||
if (_dirtyTableColumnRangeIndex !== CPNotFound)
|
||||
@@ -895,7 +897,7 @@ CPTableViewSelectionHighlightStyleSourceList = 1;
|
||||
// remove?
|
||||
return;
|
||||
}
|
||||
|
||||
console.profile("cell-load");
|
||||
// SLOWMO
|
||||
/* var subviews = [self subviews],
|
||||
count = [subviews count];
|
||||
@@ -923,6 +925,7 @@ CPTableViewSelectionHighlightStyleSourceList = 1;
|
||||
[self r:previouslyExposedRows c:newlyExposedColumns];
|
||||
[self r:newlyExposedRows c:previouslyExposedColumns];
|
||||
[self r:newlyExposedRows c:newlyExposedColumns];
|
||||
console.profileEnd("cell-load");
|
||||
}
|
||||
|
||||
- (void)r:(CPIndexSet)rows c:(CPIndexSet)columns
|
||||
|
||||
+210
-198
@@ -35,7 +35,6 @@
|
||||
@implementation CPIndexSet : CPObject
|
||||
{
|
||||
unsigned _count;
|
||||
unsigned _cachedRangeIndex;
|
||||
CPArray _ranges;
|
||||
}
|
||||
|
||||
@@ -75,7 +74,6 @@
|
||||
{
|
||||
_count = 0;
|
||||
_ranges = [];
|
||||
_cachedRangeIndex = 0;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -92,8 +90,7 @@
|
||||
if (self)
|
||||
{
|
||||
_count = 1;
|
||||
_ranges = [CPArray arrayWithObject:CPMakeRange(anIndex, 1)];
|
||||
_cachedRangeIndex = 0;
|
||||
_ranges = [CPMakeRange(anIndex, 1)];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -111,8 +108,7 @@
|
||||
if (self)
|
||||
{
|
||||
_count = aRange.length;
|
||||
_ranges = [CPArray arrayWithObject:aRange];
|
||||
_cachedRangeIndex = 0;
|
||||
_ranges = [aRange];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -131,13 +127,12 @@
|
||||
{
|
||||
_count = [anIndexSet count];
|
||||
_ranges = [];
|
||||
_cachedRangeIndex = 0;
|
||||
|
||||
var index = 0,
|
||||
count = anIndexSet._ranges.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
_ranges.push(CPCopyRange(anIndexSet._ranges[index]));
|
||||
|
||||
var otherRanges = anIndexSet._ranges,
|
||||
otherRangesCount = otherRanges.length;
|
||||
|
||||
while (otherRangesCount--)
|
||||
_ranges[otherRangesCount] = CPCopyRange(otherRanges[otherRangesCount]);
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -151,24 +146,26 @@
|
||||
*/
|
||||
- (BOOL)isEqualToIndexSet:(CPIndexSet)anIndexSet
|
||||
{
|
||||
if (!anIndexSet)
|
||||
return NO;
|
||||
|
||||
// Comparisons to ourself are always return YES.
|
||||
if (self == anIndexSet)
|
||||
if (self === anIndexSet)
|
||||
return YES;
|
||||
|
||||
var i = 0,
|
||||
count = _ranges.length;
|
||||
|
||||
var rangesCount = _ranges.length,
|
||||
otherRanges = anIndexSet._ranges;
|
||||
|
||||
|
||||
// If we have a discrepency in the number of ranges or the number of indexes,
|
||||
// simply return NO.
|
||||
if (count != otherRanges.length || _count != [anIndexSet count])
|
||||
return NO;
|
||||
|
||||
for (; i < count; ++i)
|
||||
if (!CPEqualRanges(_ranges[i], otherRanges[i]))
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
if (rangesCount !== otherRanges.length || _count !== anIndexSet._count)
|
||||
return NO;
|
||||
|
||||
while (count--)
|
||||
if (!CPEqualRanges(_ranges[count], otherRanges[count]))
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -178,7 +175,7 @@
|
||||
*/
|
||||
- (BOOL)containsIndex:(unsigned)anIndex
|
||||
{
|
||||
return [self containsIndexesInRange:CPMakeRange(anIndex, 1)];
|
||||
return positionOfIndex(_ranges, anIndex) !== CPNotFound;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -187,29 +184,24 @@
|
||||
*/
|
||||
- (BOOL)containsIndexesInRange:(CPRange)aRange
|
||||
{
|
||||
if(!_count)
|
||||
if (aRange.length <= 0)
|
||||
return NO;
|
||||
|
||||
var i = SOERangeIndex(self, aRange.location),
|
||||
lower = aRange.location,
|
||||
upper = CPMaxRange(aRange),
|
||||
count = _ranges.length;
|
||||
// If we have less total indexes than aRange, we can't possibly contain aRange.
|
||||
if(_count < aRange.length)
|
||||
return NO;
|
||||
|
||||
// Stop if the location is ever bigger than or equal to our
|
||||
// non-inclusive upper bound
|
||||
for(;i < count && _ranges[i].location < upper; ++i)
|
||||
// The range must be a subset of one our ranges.
|
||||
if (_ranges[i].location <= lower && CPMaxRange(_ranges[i]) >= upper)
|
||||
{
|
||||
_cachedRangeIndex = i;
|
||||
return YES;
|
||||
}
|
||||
|
||||
// The value isn't here, but values greater than anIndex should
|
||||
// start from here regardless.
|
||||
_cachedRangeIndex = i;
|
||||
|
||||
return NO;
|
||||
// Search for first location
|
||||
var rangeIndex = positionOfIndex(_ranges, aRange.location);
|
||||
|
||||
// If we don't have the first location, then we don't contain aRange.
|
||||
if (rangeIndex === CPNotFound)
|
||||
return NO;
|
||||
|
||||
var range = _ranges[rangeIndex];
|
||||
|
||||
// The intersection must contain all the indexes from the original range.
|
||||
return CPIntersectionRange(range, aRange).length === aRange.length;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -218,22 +210,22 @@
|
||||
*/
|
||||
- (BOOL)containsIndexes:(CPIndexSet)anIndexSet
|
||||
{
|
||||
// Return YES if anIndexSet has no indexes
|
||||
if(![anIndexSet count])
|
||||
var otherCount = anIndexSet._count;
|
||||
|
||||
if(otherCount <= 0)
|
||||
return YES;
|
||||
|
||||
// Return NO if we have no indexes.
|
||||
if(!_count)
|
||||
|
||||
// If we have less total indexes than anIndexSet, we can't possibly contain aRange.
|
||||
if (_count < otherCount)
|
||||
return NO;
|
||||
|
||||
var i = 0,
|
||||
count = _ranges.length;
|
||||
|
||||
// This is fast thanks to the _cachedIndexRange.
|
||||
for(; i < count; ++i)
|
||||
if (![anIndexSet containsIndexesInRange:_ranges[i]])
|
||||
var otherRanges = anIndexSet._ranges,
|
||||
otherRangesCount = otherRanges.length;
|
||||
|
||||
while (otherRangesCount--)
|
||||
if (![self containsIndexesInRange:otherRanges[otherRangesCount]])
|
||||
return NO;
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -275,7 +267,10 @@
|
||||
*/
|
||||
- (int)firstIndex
|
||||
{
|
||||
return _count ? _ranges[0].location : CPNotFound;
|
||||
if (_count > 0)
|
||||
return _ranges[0].location;
|
||||
|
||||
return CPNotFound;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -283,32 +278,41 @@
|
||||
*/
|
||||
- (int)lastIndex
|
||||
{
|
||||
return _count ? CPMaxRange(_ranges[_ranges.length - 1]) - 1 : CPNotFound;
|
||||
if (_count > 0)
|
||||
return CPMaxRange(_ranges[_ranges.length - 1]) - 1;
|
||||
|
||||
return CPNotFound;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the first index value in the receiver which is greater than <code>anIndex</code>.
|
||||
@return the closest index or CPNotFound if no match was found
|
||||
*/
|
||||
- (unsigned)indexGreaterThanIndex:(unsigned)anIndex
|
||||
- (CPInteger)indexGreaterThanIndex:(CPInteger)anIndex
|
||||
{
|
||||
if(!_count)
|
||||
return CPNotFound;
|
||||
|
||||
var i = SOERangeIndex(self, anIndex++),
|
||||
count = _ranges.length;
|
||||
|
||||
for(; i < count && anIndex >= CPMaxRange(_ranges[i]); ++i) ;
|
||||
// The first possible index that would satisfy this requirement.
|
||||
++anIndex;
|
||||
|
||||
if (i == count)
|
||||
return CPNotFound;
|
||||
|
||||
_cachedRangeIndex = i;
|
||||
|
||||
if (anIndex < _ranges[i].location)
|
||||
return _ranges[i].location;
|
||||
// Attempt to find it or something bigger.
|
||||
var rangeIndex = assumedPositionOfIndex(_ranges, anIndex);
|
||||
|
||||
return anIndex;
|
||||
// Nothing at all found?
|
||||
if (rangeIndex === CPNotFound)
|
||||
return CPNotFound;
|
||||
|
||||
rangeIndex = CEIL(rangeIndex);
|
||||
|
||||
if (rangeIndex >= _ranges.length)
|
||||
return CPNotFound;
|
||||
|
||||
var range = _ranges[rangeIndex];
|
||||
|
||||
// Check if it's actually in this range.
|
||||
if (CPLocationInRange(anIndex, range))
|
||||
return anIndex;
|
||||
|
||||
// If not, it must be the first element of this range.
|
||||
return range.location;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -317,25 +321,29 @@
|
||||
*/
|
||||
- (unsigned)indexLessThanIndex:(unsigned)anIndex
|
||||
{
|
||||
if (!_count)
|
||||
return CPNotFound;
|
||||
|
||||
var i = GOERangeIndex(self, anIndex--);
|
||||
|
||||
for (; i >= 0 && anIndex < _ranges[i].location; --i) ;
|
||||
// The first possible index that would satisfy this requirement.
|
||||
--anIndex;
|
||||
|
||||
if(i < 0)
|
||||
return CPNotFound;
|
||||
|
||||
_cachedRangeIndex = i;
|
||||
// Attempt to find it or something smaller.
|
||||
var rangeIndex = assumedPositionOfIndex(_ranges, anIndex);
|
||||
|
||||
if (CPLocationInRange(anIndex, _ranges[i]))
|
||||
// Nothing at all found?
|
||||
if (rangeIndex === CPNotFound)
|
||||
return CPNotFound;
|
||||
|
||||
rangeIndex = FLOOR(rangeIndex);
|
||||
|
||||
if (rangeIndex < 0)
|
||||
return CPNotFound;
|
||||
|
||||
var range = _ranges[rangeIndex];
|
||||
|
||||
// Check if it's actually in this range.
|
||||
if (CPLocationInRange(anIndex, range))
|
||||
return anIndex;
|
||||
|
||||
if (CPMaxRange(_ranges[i]) - 1 < anIndex)
|
||||
return CPMaxRange(_ranges[i]) - 1;
|
||||
|
||||
return CPNotFound;
|
||||
// If not, it must be the first element of this range.
|
||||
return CPMaxRange(range) - 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -422,7 +430,7 @@
|
||||
for (i = 0; i < _ranges.length; i++)
|
||||
{
|
||||
desc += _ranges[i].location;
|
||||
if (_ranges[i].length > 1) desc += "-" + (CPMaxRange(_ranges[i])-1) + ":"+_ranges[i].length+":";
|
||||
if (_ranges[i].length > 1) desc += "-" + (CPMaxRange(_ranges[i])-1) + "["+_ranges[i].length+"]";
|
||||
if (i+1 < _ranges.length) desc += " ";
|
||||
}
|
||||
desc += ")]";
|
||||
@@ -452,13 +460,12 @@
|
||||
*/
|
||||
- (void)addIndexes:(CPIndexSet)anIndexSet
|
||||
{
|
||||
var i = 0,
|
||||
ranges = anIndexSet._ranges,
|
||||
count = ranges.length;
|
||||
|
||||
var otherRanges = anIndexSet._ranges,
|
||||
otherRangesCount = otherRanges.length;
|
||||
|
||||
// Simply add each range within anIndexSet.
|
||||
for(; i < count; ++i)
|
||||
[self addIndexesInRange:ranges[i]];
|
||||
while (otherRangesCount--)
|
||||
[self addIndexesInRange:otherRanges[otherRangesCount]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -467,91 +474,52 @@
|
||||
*/
|
||||
- (void)addIndexesInRange:(CPRange)aRange
|
||||
{
|
||||
if (_ranges.length == 0)
|
||||
// If empty range, bail.
|
||||
if (aRange.length <= 0)
|
||||
return;
|
||||
|
||||
// If we currently don't have any indexes, this represents our entire set.
|
||||
if (_count <= 0)
|
||||
{
|
||||
_count = aRange.length;
|
||||
_ranges = [aRange];
|
||||
|
||||
return [_ranges addObject:CPCopyRange(aRange)];
|
||||
return;
|
||||
}
|
||||
var x = aRange.location - 1, y = CPMaxRange(aRange);
|
||||
var rangeCount = _ranges.length,
|
||||
lhsRangeIndex = assumedPositionOfIndex(_ranges, aRange.location - 1),
|
||||
lhsRangeIndexCEIL = CEIL(lhsRangeIndex);
|
||||
try{
|
||||
if (lhsRangeIndexCEIL === lhsRangeIndex && lhsRangeIndexCEIL < rangeCount)
|
||||
aRange = CPUnionRange(aRange, _ranges[lhsRangeIndexCEIL]);
|
||||
}catch(e) { alert("123456789 " + lhsRangeIndexCEIL + " " + rangeCount + " " + lhsRangeIndex);}
|
||||
var rhsRangeIndex = assumedPositionOfIndex(_ranges, CPMaxRange(aRange)),
|
||||
rhsRangeIndexFLOOR = FLOOR(rhsRangeIndex);
|
||||
|
||||
if (rhsRangeIndexFLOOR === rhsRangeIndex && rhsRangeIndexFLOOR > 0)
|
||||
aRange = CPUnionRange(aRange, _ranges[rhsRangeIndexFLOOR]);
|
||||
//print("the returned indxes were for searching for " + x + " to " + y + " are " + lhsRangeIndex + " and " + rhsRangeIndex);
|
||||
var removalCount = rhsRangeIndexFLOOR - lhsRangeIndexCEIL + 1;
|
||||
|
||||
if (removalCount === 1)
|
||||
{
|
||||
if (lhsRangeIndexCEIL < _ranges.length)
|
||||
_count -= _ranges[lhsRangeIndexCEIL].length;
|
||||
|
||||
_count += aRange.length;
|
||||
_ranges[lhsRangeIndexCEIL] = aRange;
|
||||
}
|
||||
|
||||
// FIXME: Should we really use SOERangeIndex here? There is no real
|
||||
// reason the cached index would be a better guess than 0, and it
|
||||
// would avoid a function call.
|
||||
var i = SOERangeIndex(self, aRange.location),
|
||||
count = _ranges.length,
|
||||
padded = CPMakeRange(aRange.location - 1, aRange.length + 2),
|
||||
maximum = CPMaxRange(aRange);
|
||||
|
||||
// If our range won't intersect with the last range, just append it to the end.
|
||||
if (count && CPMaxRange(_ranges[count - 1]) < aRange.location)
|
||||
[_ranges addObject:CPCopyRange(aRange)];
|
||||
else
|
||||
for (; i < count; ++i)
|
||||
{
|
||||
// This range is completely independent of existing ranges,
|
||||
// simply add it to the array.
|
||||
if (maximum < _ranges[i].location)
|
||||
{
|
||||
_count += aRange.length;
|
||||
|
||||
// Keep _cachedRangeIndex relevant.
|
||||
if (i < _cachedRangeIndex) ++_cachedRangeIndex;
|
||||
|
||||
return [_ranges insertObject:CPCopyRange(aRange) atIndex:i];
|
||||
}
|
||||
|
||||
if (CPIntersectionRange(_ranges[i], padded).length)
|
||||
{
|
||||
var union = CPUnionRange(_ranges[i], aRange);
|
||||
|
||||
// We already contain all the indexes in this range.
|
||||
if (union.length == _ranges[i].length)
|
||||
return;
|
||||
|
||||
// Pad the length to collapse with later ranges.
|
||||
++union.length;
|
||||
|
||||
// We only need to check if we now intersect with any following
|
||||
// ranges since if we now intersected with the previous range,
|
||||
// it would have already been handled. We start at i and not i + 1
|
||||
// to make sure we subtract i's length.
|
||||
var j = i;
|
||||
|
||||
for(; j < count; ++j)
|
||||
// Bail as soon as we don't find an intersection.
|
||||
if(CPIntersectionRange(union, _ranges[j]).length)
|
||||
_count -= _ranges[j].length;
|
||||
else
|
||||
break;
|
||||
|
||||
// Remove the padding now that we are done.
|
||||
// NOTE: We could have set _ranges[i] = CPCopyRange(union),
|
||||
// and then not had to bother decerementing here, but this avoids
|
||||
// a lookup above during unioning, and a function call (CPCopyRange).
|
||||
--union.length;
|
||||
_ranges[i] = union;
|
||||
|
||||
// Now remove indexes [i + 1, j - 1]
|
||||
if (j - i - 1 > 0)
|
||||
{
|
||||
var remove = CPMakeRange(i + 1, j - i - 1);
|
||||
|
||||
_ranges[i] = CPUnionRange(_ranges[i], _ranges[j - 1]);
|
||||
[_ranges removeObjectsInRange:remove];
|
||||
|
||||
// Keep _cachedRangeIndex relevant.
|
||||
if (_cachedRangeIndex >= CPMaxRange(remove)) _cachedRangedIndex -= remove.length;
|
||||
else if (CPLocationInRange(_cachedRangeIndex, remove)) _cachedRangeIndex = i;
|
||||
}
|
||||
|
||||
// Update count.
|
||||
_count += _ranges[i].length;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_count += aRange.length;
|
||||
{
|
||||
if (removalCount > 0)
|
||||
[_ranges removeObjectsInRange:CPMakeRange(lhsRangeIndexCEIL, removalCount)];
|
||||
|
||||
[_ranges insertObject:aRange atIndex:lhsRangeIndexCEIL];
|
||||
|
||||
//FIXME COUNT!
|
||||
}
|
||||
}
|
||||
|
||||
// Removing Indexes
|
||||
@@ -571,13 +539,12 @@
|
||||
*/
|
||||
- (void)removeIndexes:(CPIndexSet)anIndexSet
|
||||
{
|
||||
var i = 0,
|
||||
ranges = anIndexSet._ranges,
|
||||
count = ranges.length;
|
||||
var otherRanges = anIndexSet._ranges,
|
||||
otherRangesCount = otherRanges.length;
|
||||
|
||||
// Simply remove each index from anIndexSet
|
||||
for(; i < count; ++i)
|
||||
[self removeIndexesInRange:ranges[i]];
|
||||
while (otherRangesCount--)
|
||||
[self removeIndexesInRange:otherRanges[otherRangesCount]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -587,7 +554,6 @@
|
||||
{
|
||||
_ranges = [];
|
||||
_count = 0;
|
||||
_cachedRangeIndex = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -830,26 +796,72 @@ var CPIndexSetCountKey = @"CPIndexSetCountKey",
|
||||
|
||||
@end
|
||||
|
||||
var SOERangeIndex = function(anIndexSet, anIndex)
|
||||
var positionOfIndex = function(ranges, anIndex)
|
||||
{
|
||||
var ranges = anIndexSet._ranges,
|
||||
cachedRangeIndex = 0;//anIndexSet._cachedRangeIndex;
|
||||
|
||||
if(cachedRangeIndex < ranges.length && anIndex >= ranges[cachedRangeIndex].location)
|
||||
return cachedRangeIndex;
|
||||
var low = 0,
|
||||
high = ranges.length - 1;
|
||||
|
||||
return 0;
|
||||
while (low <= high)
|
||||
{
|
||||
var middle = FLOOR(low + (high - low) / 2),
|
||||
range = ranges[middle];
|
||||
|
||||
if (anIndex < range.location)
|
||||
high = middle - 1;
|
||||
|
||||
else if (anIndex >= CPMaxRange(range))
|
||||
low = middle + 1;
|
||||
|
||||
else
|
||||
return middle;
|
||||
}
|
||||
|
||||
return CPNotFound;
|
||||
}
|
||||
|
||||
var GOERangeIndex = function(anIndexSet, anIndex)
|
||||
var assumedPositionOfIndex = function(ranges, anIndex)
|
||||
{
|
||||
var ranges = anIndexSet._ranges,
|
||||
cachedRangeIndex = anIndexSet._ranges.length;//anIndexSet._cachedRangeIndex;
|
||||
var count = ranges.length;
|
||||
|
||||
if (count <= 0)
|
||||
return CPNotFound;
|
||||
|
||||
var low = 0,
|
||||
high = count * 2;
|
||||
|
||||
while (low <= high)
|
||||
{
|
||||
var middle = FLOOR(low + (high - low) / 2),
|
||||
position = middle / 2,
|
||||
positionFLOOR = FLOOR(position);
|
||||
|
||||
if(cachedRangeIndex < ranges.length && anIndex <= ranges[cachedRangeIndex].location)
|
||||
return cachedRangeIndex;
|
||||
|
||||
return ranges.length - 1;
|
||||
if (position === positionFLOOR)
|
||||
{try{
|
||||
if (positionFLOOR - 1 >= 0 && anIndex < CPMaxRange(ranges[positionFLOOR - 1]))
|
||||
high = middle - 1;
|
||||
|
||||
else if (positionFLOOR < count && anIndex >= ranges[positionFLOOR].location)
|
||||
low = middle + 1;
|
||||
|
||||
else
|
||||
return positionFLOOR - 0.5;}catch(e) { alert("here!");}
|
||||
}
|
||||
else
|
||||
{try{
|
||||
var range = ranges[positionFLOOR];
|
||||
|
||||
if (anIndex < range.location)
|
||||
high = middle - 1;
|
||||
|
||||
else if (anIndex >= CPMaxRange(range))
|
||||
low = middle + 1;
|
||||
|
||||
else
|
||||
return positionFLOOR;}catch(e){alert("yes!");}
|
||||
}
|
||||
}
|
||||
|
||||
return CPNotFound;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in new issue
Block a user