Revert "Pulled @each out into a separate feature branch, so as to not conflict with the 0.8 work: http://github.com/280north/cappuccino/tree/@each ."

This reverts commit 7433c38d92.
This commit is contained in:
Francisco Ryan Tolmasky I
2010-02-22 02:25:39 -08:00
parent d879b25458
commit 458481af4e
9 changed files with 509 additions and 0 deletions
+197
View File
@@ -87,6 +87,40 @@
[_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES];
}
- (CPEnumerator)preOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPreOrder];
}
- (CPEnumerator)inOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorInOrder];
}
- (CPEnumerator)postOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPostOrder];
}
- (CPEnumerator)levelOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorLevelOrder];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
// FIXME: Change this to inorder when implemented?
var count = [[self preOrder] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
}
@end
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
@@ -117,3 +151,166 @@ var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
}
@end
var _CPTreeNodeEnumeratorPreOrder = 0,
_CPTreeNodeEnumeratorInOrder = 1,
_CPTreeNodeEnumeratorPostOrder = 2,
_CPTreeNodeEnumeratorLevelOrder = 3;
@implementation _CPTreeNodeEnumerator : CPEnumerator
{
int _order;
Object _state;
CPTreeNode _treeNode;
}
+ (_CPTreeNodeEnumerator)enumeratorWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
return [[self alloc] initWithTreeNode:aTreeNode order:anOrder];
}
- (id)initWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
self = [super init];
if (self)
{
_order = anOrder
_state = [self _newState];
_treeNode = aTreeNode;
}
return self;
}
- (id)_newState
{
return { stack:[_treeNode], visited:[CPSet set] };
}
- (id)_preOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = stack.pop(),
childNodes = currentNode._childNodes,
count = childNodes.length;
while (count--)
stack.push(childNodes[count]);
if (shouldReturnAllObjects)
allObjects.push(currentNode);
else
return currentNode;
}
return allObjects;
}
- (id)_inOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)_postOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
var visited = state.visited;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = [stack lastObject],
childNodes = currentNode._childNodes,
originalCount = stack.length,
count = childNodes.length;
while (count--)
{
var treeNode = childNodes[count];
if ([visited containsObject:treeNode])
continue;
else
stack.push(treeNode);
}
if (originalCount === stack.length)
{
[visited addObject:currentNode];
if (shouldReturnAllObjects)
allObjects.push(stack.pop());
else
return stack.pop();
}
}
return allObjects;
}
- (id)_levelOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)nextObject
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:NO];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (CPArray)allObjects
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:YES];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
var count = [[self allObjects] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
}
@end
+30
View File
@@ -55,6 +55,11 @@
return [_array objectAtIndex:_index];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
return [_array countByEnumeratingWithState:aState objects:objects count:aCount];
}
@end
/* @ignore */
@@ -1206,6 +1211,31 @@
@end
@implementation CPArray (CPFastEnumeration)
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
var count = [self count],
index = aState.state;
if (index >= count)
return 0;
var indexIndex = 0,
last = MIN(index + aCount, count);
aCount = last - index;
for (; index < last; ++index, ++indexIndex)
objects[indexIndex] = [self objectAtIndex:index];
aState.state = last;
return aCount;
}
@end
@implementation CPArray (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
+25
View File
@@ -546,6 +546,31 @@
@end
@implementation CPDictionary (CPFastEnumeration)
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
var count = [self count];
if (aState.state >= count)
return 0;
var keys = [self allKeys],
index = count,
objects = new Array(count);
while (index--)
objects[index] = [self objectForKey:keys[index]];
aState.items0 = objects;
aState.items1 = keys;
aState.state = count;
return count;
}
@end
/*!
@class CPMutableDictionary
@ingroup compatability
+7
View File
@@ -56,4 +56,11 @@
return [];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
// This is pretty terrible, but what do you expect.
return [[self allObjects] countByEnumeratingWithState:aState objects:objects count:aCount];
}
@end
+26
View File
@@ -834,6 +834,32 @@ var CPIndexSetCountKey = @"CPIndexSetCountKey",
@end
@implementation CPIndexSet (CPFastEnumeration)
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
var rangeIndex = aState.state;
if (aState.state >= _ranges.length)
return 0;
var range = _ranges[rangeIndex],
index = 0,
start = range.location,
end = start + range.length,
indexes = new Array(range.length);
while (start < end)
indexes[index++] = start++;
aState.items = indexes;
++aState.state;
return range.length;
}
@end
/*!
@class CPMutableIndexSet
@ingroup compatability
+9
View File
@@ -58,3 +58,12 @@ var CPNullSharedNull = nil;
}
@end
@implementation CPNull (CPFastEnumeration)
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
return 0;
}
@end
+16
View File
@@ -499,6 +499,22 @@ var CPSetObjectsKey = @"CPSetObjectsKey";
@end
@implementation CPSet (CPFastEnumeration)
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
var count = [self count];
if (aState.state >= count)
return 0;
count = [[self allObjects] countByEnumeratingWithState:aState objects:objects count:aCount];
return count;
}
@end
/*!
@class CPMutableSet
@ingroup compatability
+96
View File
@@ -321,6 +321,9 @@ Preprocessor.prototype.directive = function(tokens, aStringBuffer, allowedDirect
else if (token === TOKEN_IMPORT)
this._import(tokens);
else if (token === TOKEN_EACH)
this.each(tokens, buffer);
// @selector
else if (token === TOKEN_SELECTOR)
this.selector(tokens, buffer);
@@ -329,6 +332,99 @@ Preprocessor.prototype.directive = function(tokens, aStringBuffer, allowedDirect
return buffer;
}
var fastEnumeratorCount = 0;
Preprocessor.prototype.each = function(tokens, /*StringBuffer*/ aStringBuffer)
{
var token = tokens.skip_whitespace();
// If we reach an open parenthesis, we are declaring a category.
if (token !== TOKEN_OPEN_PARENTHESIS)
throw new SyntaxError(this.error_message("*** Expecting (, found: \"" + token + "\"."));
var identifiers = [],
isVared = NO;
do
{
token = tokens.skip_whitespace();
if (identifiers.length === 0 && token === TOKEN_VAR)
{
isVared = YES;
token = tokens.skip_whitespace();
}
if (!TOKEN_IDENTIFIER.test(token))
throw new SyntaxError(this.error_message("*** Expecting identifier, found: \"" + token + "\"."));
identifiers.push(token);
token = tokens.skip_whitespace();
if (token !== TOKEN_COMMA && token !== TOKEN_IN)
throw new SyntaxError(this.error_message("*** Expecting \",\", found: \"" + token + "\"."));
} while (token && token === TOKEN_COMMA);
if (token !== TOKEN_IN)
throw new SyntaxError(this.error_message("*** Expecting \"in\", found: \"" + token + "\"."));
var generatedFastEnumeratorName = "$OBJJ_GENERATED_FAST_ENUMERATOR_" + fastEnumeratorCount++;
CONCAT(aStringBuffer, "var ");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, " = new objj_fastEnumerator(");
this.preprocess(tokens, aStringBuffer, TOKEN_CLOSE_PARENTHESIS, TOKEN_OPEN_PARENTHESIS);
CONCAT(aStringBuffer, ", ");
CONCAT(aStringBuffer, identifiers.length);
CONCAT(aStringBuffer, ");\n");
// var $E = new objj_fastEnumerator(expression);
// for ([[var] arg1[, arg2[, ... argN]]];
// $E.i < $E.l || $E.e() && ((arg1 = $E.o0[$E.i][, $E.o1[$E.i][, ... $E.oN[$E.i]]]) || YES);
// ++$E.i)
CONCAT(aStringBuffer, "for (");
if (isVared)
{
CONCAT(aStringBuffer, "var ");
CONCAT(aStringBuffer, identifiers.join(", "));
}
CONCAT(aStringBuffer, ";(");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".i < ");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".l || ");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".e()) && ((");
// Man don't you wish we had fast enumeration here!!
for (var index = 0, count = identifiers.length; index < count; ++index)
{
CONCAT(aStringBuffer, identifiers[index]);
CONCAT(aStringBuffer, " = ");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".o");
CONCAT(aStringBuffer, index);
CONCAT(aStringBuffer, "[");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".i]");
if (index + 1 < count)
CONCAT(aStringBuffer, ", ");
}
CONCAT(aStringBuffer, ") || YES); ++");
CONCAT(aStringBuffer, generatedFastEnumeratorName);
CONCAT(aStringBuffer, ".i)");
}
Preprocessor.prototype.implementation = function(tokens, /*StringBuffer*/ aStringBuffer)
{
var buffer = aStringBuffer,
+103
View File
@@ -530,3 +530,106 @@ GLOBAL(sel_registerName) = function(/*String*/ aName)
{
return aName;
}
var fastEnumerationSelector = sel_getUid("countByEnumeratingWithState:objects:count:");
GLOBAL(objj_fastEnumerator) = function(/*Object*/ anObject, /*Integer*/ anAssigneeCount)
{
// If this object doesn't respond to countByEnumeratingWithState:objects:count:
// (which is obviously the case for non-Objective-J objects), then just iterate
// this one object.
if (anObject && (!anObject.isa || !class_getInstanceMethod(anObject.isa, fastEnumerationSelector)))
this._target = [anObject];
// Else, use it's implementation.
else
this._target = anObject;
this._state = { state:0, assigneeCount:anAssigneeCount };
this._index = 0;
// Nothing to iterate in this case.
if (!anObject)
{
this.i = 0;
this.l = 0;
}
else
this.e();
}
objj_fastEnumerator.prototype.e = function()
{
var object = this._target;
// Nothing to iterate, don't iterate
if (!object)
return NO;
var state = this._state,
index = state.assigneeCount;
while (index--)
state["items" + index] = nil;
this.i = 0;
// We optimize the array case.
if (CPArray && object.isa === CPArray)
{
if (this.l)
return NO;
this.o0 = object;
this.l = object.length;
}
else
{
// Clear out all the old state.
state.items = nil;
state.itemsPtr = nil;
this.o0 = [];
this.l = objj_msgSend(object, fastEnumerationSelector, state, this.o0, 16);
// We're flexible on this.
this.o0 = state.items || state.itemsPtr || state.items0 || this.o0;
// We allow the user to not explictly return anything in countByEnumeratingWithState:objects:count:
if (this.l === undefined)
this.l = this.o0.length;
}
var assigneeCount = state.assigneeCount;
index = assigneeCount - 1;
// Handle all items from [1 .. assigneeCount - 1]
while (index-- > 1)
this["o" + index] = state["items" + index] || [];
var lastAssigneeIndex = assigneeCount - 1;
// Autogenerate the indexes if this was left blank.
if (lastAssigneeIndex > 0)
if (state["items" + lastAssigneeIndex])
this["o" + lastAssigneeIndex] = state["items" + lastAssigneeIndex];
else
{
var count = this.l,
indexIndex = 0,
indexes = new Array(count)
for (; indexIndex < count; ++indexIndex, ++this._index)
indexes[indexIndex] = this._index;
this["o" + lastAssigneeIndex] = indexes;
}
// If this is the last iteration, set target to nil so that we don't call the
// fast enumeration method again.
return this.l > 0;
}