Permalink
Browse files

- Added the source for PONSO support classes

  • Loading branch information...
1 parent 7104d99 commit 7d458b170610380b1dd932580681d41db0e0dbc8 @nikita-zhuk nikita-zhuk committed Jun 4, 2011
View
@@ -0,0 +1,47 @@
+/*
+ Copyright 2011 Marko Karppinen & Co. LLC.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ MKCDAGNode.h
+ Created by Nikita Zhuk on 22.1.2011.
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ Generic DAG (Directed Acyclic Graph) implementation
+ */
+@interface MKCDAGNode : NSObject
+{
+ id object;
+ NSMutableArray *nodes;
+}
+
+//! Generic payload object, not used in the algorithm. Can be nil.
+@property(nonatomic, retain) id object;
+
+//! All objects of nodes in topological order which are reachable from the receiver.
+@property(nonatomic, readonly) NSArray *objectsInTopologicalOrder;
+
+- (id)initWithObject:(id)object;
+
+/**
+ Creates dependency between receiver and the given node and adds the given node into the DAG.
+ The dependency direction is from the receiver to the given node, e.g. [a addNode:b] means that 'a' depends on 'b'.
+ If the new node would create a cycle in the DAG it's not added and NO is returned.
+ YES is returned otherwise.
+ */
+- (BOOL)addNode:(MKCDAGNode *)node;
+
+@end
View
@@ -0,0 +1,132 @@
+/*
+ Copyright 2011 Marko Karppinen & Co. LLC.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ MKCDAGNode.m
+ Created by Nikita Zhuk on 22.1.2011.
+ */
+
+#import "MKCDAGNode.h"
+
+@interface MKCDAGNode()
+/**
+ All nodes directly reachable from this node ( = nodes to which there is a directed edge from 'self' node)
+ */
+@property(nonatomic, retain) NSMutableArray *nodes;
+@end
+
+@implementation MKCDAGNode
+
+#pragma mark Algorithms
+
++ (BOOL)isCyclicNode:(MKCDAGNode *)node visitedNodes:(NSMutableSet *)visitedNodes
+{
+ if([visitedNodes intersectsSet:[NSSet setWithArray:node.nodes]])
+ {
+ // We've seen these nodes already - a cycle!
+ return YES;
+ }
+
+ for (MKCDAGNode *childNode in node.nodes)
+ {
+ [visitedNodes addObject:childNode];
+ BOOL childNodeIsCyclic = [self isCyclicNode:childNode visitedNodes:visitedNodes];
+ [visitedNodes removeObject:childNode];
+
+ if(childNodeIsCyclic)
+ {
+ return YES;
+ }
+ }
+
+ return NO;
+}
+
+// DAG topological order visitor, see http://en.wikipedia.org/wiki/Directed_acyclic_graph
+// 'visitedNodes' set is used to 'mark' visited nodes.
++ (void)visitNode:(MKCDAGNode *)node visitedNodes:(NSMutableSet *)visitedNodes orderedNodes:(NSMutableArray *)orderedNodes
+{
+ if([visitedNodes containsObject:node])
+ {
+ return;
+ }
+
+ [visitedNodes addObject:node];
+
+ for (MKCDAGNode *childNode in node.nodes)
+ {
+ [self visitNode:childNode visitedNodes:visitedNodes orderedNodes:orderedNodes];
+ }
+
+ [orderedNodes addObject:node];
+}
+
+#pragma mark Public
+
+- (id)initWithObject:(id)anObject
+{
+ if((self = [super init]))
+ {
+ self.nodes = [NSMutableArray array];
+ self.object = anObject;
+ }
+ return self;
+}
+
+- (NSArray *)objectsInTopologicalOrder
+{
+ NSMutableArray *orderedNodes = [NSMutableArray array];
+
+ [[self class] visitNode:self visitedNodes:[NSMutableSet set] orderedNodes:orderedNodes];
+
+ NSMutableArray *orderedObjects = [NSMutableArray array];
+ for (MKCDAGNode *node in orderedNodes)
+ {
+ if(node.object != nil)
+ {
+ [orderedObjects addObject:node.object];
+ }
+ }
+ return orderedObjects;
+}
+
+- (BOOL)addNode:(MKCDAGNode *)node
+{
+ if(node == nil)
+ return NO;
+
+ if(![self.nodes containsObject:node])
+ [self.nodes addObject:node];
+
+ // Check that this node didn't cause a cycle - if it did, remove it.
+ BOOL isCyclic = [[self class] isCyclicNode:node visitedNodes:[NSMutableSet set]];
+ if(isCyclic)
+ {
+ [self.nodes removeObject:node];
+ }
+
+ return !isCyclic;
+}
+
+- (void) dealloc
+{
+ self.nodes = nil;
+ self.object = nil;
+
+ [super dealloc];
+}
+
+@synthesize nodes;
+@synthesize object;
+@end
@@ -0,0 +1,28 @@
+/*
+ Copyright 2011 Marko Karppinen & Co. LLC.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ MKCNSEntityDescriptionAdditions.h
+ Created by Nikita Zhuk on 22.1.2011.
+ */
+
+#import <CoreData/CoreData.h>
+
+
+@interface NSEntityDescription(MKCNSEntityDescriptionAdditions)
+
+/** @TypeInfo NSAttributeDescription */
+@property(nonatomic, readonly) NSArray *noninheritedRelationshipsInIDKeyPathTopologicalOrder;
+
+@end
@@ -0,0 +1,83 @@
+/*
+ Copyright 2011 Marko Karppinen & Co. LLC.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ MKCNSEntityDescriptionAdditions.m
+ Created by Nikita Zhuk on 22.1.2011.
+ */
+
+
+#import "MKCNSEntityDescriptionAdditions.h"
+#import "MKCNSManagedObjectModelAdditions.h"
+
+@interface MKCNSRelationshipDescriptionIDKeyPathDependencyFilter : NSObject <MKCNSRelationshipDescriptionDependencyFilter> @end
+
+@implementation MKCNSRelationshipDescriptionIDKeyPathDependencyFilter
+
+- (BOOL)includeRelationship:(NSRelationshipDescription *)relationship
+{
+ if([[relationship entity] isEqual:[relationship destinationEntity]])
+ {
+ // Relationship from entity to itself - ignore.
+ return NO;
+ }
+
+ return [[[relationship userInfo] objectForKey:@"destinationEntityIDKeyPath"] length] > 0;
+}
+
+@end
+
+@implementation NSEntityDescription(MKCNSEntityDescriptionAdditions)
+
+/** @TypeInfo NSAttributeDescription */
+- (NSArray*)noninheritedRelationshipsInIDKeyPathTopologicalOrder
+{
+ NSArray *relationships = nil;
+
+ NSEntityDescription *superentity = [self superentity];
+ if (superentity != nil)
+ {
+ NSMutableArray *result = [[[[self relationshipsByName] allValues] mutableCopy] autorelease];
+ [result removeObjectsInArray:[[superentity relationshipsByName] allValues]];
+ relationships = result;
+ }
+ else
+ {
+ relationships = [[self relationshipsByName] allValues];
+ }
+
+ // Initially, sort relationships in alphabetical order.
+ relationships = [relationships sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]];
+
+ // Sort relationships in topological order by their destination entities including "IDKeyPath" relationships in dependencies.
+ // Although this is a bit naive O(n^2) sort, it should be fast enough since n (=number of relationships) is usually very low.
+ id IDKeyPathDependencyFilter = [[[MKCNSRelationshipDescriptionIDKeyPathDependencyFilter alloc] init] autorelease];
+ NSArray *allEntities = [[self managedObjectModel] entitiesInTopologicalOrderUsingDependencyFilter:IDKeyPathDependencyFilter];
+ NSMutableArray *sortedRelationships = [NSMutableArray arrayWithCapacity:[relationships count]];
+
+ for (NSEntityDescription *entity in allEntities)
+ {
+ for (NSRelationshipDescription *relationship in relationships)
+ {
+ if([[relationship destinationEntity] isEqual:entity])
+ {
+ [sortedRelationships addObject:relationship];
+ }
+ }
+ }
+
+ return sortedRelationships;
+}
+
+@end
@@ -0,0 +1,44 @@
+/*
+ Copyright 2011 Marko Karppinen & Co. LLC.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ MKCNSManagedObjectModelAdditions.h
+ Created by Nikita Zhuk on 22.1.2011.
+ */
+
+#import <CoreData/CoreData.h>
+
+
+@protocol MKCNSRelationshipDescriptionDependencyFilter<NSObject>
+- (BOOL)includeRelationship:(NSRelationshipDescription *)relationship;
+@end
+
+@interface NSManagedObjectModel(MKCNSManagedObjectModelAdditions)
+
+/**
+ Array of NSEntityDescription objects, sorted in topological order
+ based on relationships between entity descriptions.
+ If there are cyclic dependencies, a nil is returned.
+ This method counts all relationships as dependencies if they are not marked as being 'transient'.
+ */
+
+- (NSArray *) entitiesInTopologicalOrder;
+
+/*
+ Same as entitiesInTopologicalOrder, but uses the given dependencyFilter to decide whether a
+ relationship should be counted as dependency or not.
+ */
+- (NSArray *) entitiesInTopologicalOrderUsingDependencyFilter:(id<MKCNSRelationshipDescriptionDependencyFilter>) dependencyFilter;
+
+@end
Oops, something went wrong.

0 comments on commit 7d458b1

Please sign in to comment.