Line data Source code
1 0 : /*
2 :
3 : OODeepCopy.m
4 :
5 :
6 : Copyright (C) 2009-2013 Jens Ayton
7 :
8 : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : of this software and associated documentation files (the "Software"), to deal
10 : in the Software without restriction, including without limitation the rights
11 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : copies of the Software, and to permit persons to whom the Software is
13 : furnished to do so, subject to the following conditions:
14 :
15 : The above copyright notice and this permission notice shall be included in all
16 : copies or substantial portions of the Software.
17 :
18 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : SOFTWARE.
25 :
26 : */
27 :
28 : #import "OODeepCopy.h"
29 :
30 :
31 0 : id OODeepCopy(id object)
32 : {
33 : NSAutoreleasePool *pool = nil;
34 : NSMutableSet *objects = nil;
35 :
36 : if (object == nil) return nil;
37 :
38 : pool = [[NSAutoreleasePool alloc] init];
39 : objects = [NSMutableSet set];
40 :
41 : object = [object ooDeepCopyWithSharedObjects:objects];
42 :
43 : [pool release];
44 :
45 : return object;
46 : }
47 :
48 :
49 : @implementation NSObject (OODeepCopy)
50 :
51 : - (id) ooDeepCopyWithSharedObjects:(NSMutableSet *)objects
52 : {
53 : if ([self conformsToProtocol:@protocol(NSCopying)])
54 : {
55 : return [self copy];
56 : }
57 : else
58 : {
59 : return [self retain];
60 : }
61 : }
62 :
63 : @end
64 :
65 :
66 : @implementation NSString (OODeepCopy)
67 :
68 0 : - (id) ooDeepCopyWithSharedObjects:(NSMutableSet *)objects
69 : {
70 : NSUInteger length = [self length];
71 : if (length == 0) return [[NSString string] retain];
72 : if (length > 128) return [self copy];
73 :
74 : id object = [objects member:self];
75 : if (object != nil && [object isKindOfClass:[NSString class]])
76 : {
77 : return [object retain];
78 : }
79 : else
80 : {
81 : object = [self copy];
82 : [objects addObject:object];
83 : return object;
84 : }
85 : }
86 :
87 : @end
88 :
89 :
90 : @implementation NSValue (OODeepCopy) // Includes NSNumber
91 :
92 0 : - (id) ooDeepCopyWithSharedObjects:(NSMutableSet *)objects
93 : {
94 : id object = [objects member:self];
95 : if (object != nil && [object isKindOfClass:[NSValue class]])
96 : {
97 : return [object retain];
98 : }
99 : else
100 : {
101 : object = [self copy];
102 : [objects addObject:object];
103 : return object;
104 : }
105 : }
106 :
107 : @end
108 :
109 :
110 : @implementation NSArray (OODeepCopy)
111 :
112 0 : - (id) ooDeepCopyWithSharedObjects:(NSMutableSet *)objects
113 : {
114 : NSUInteger i, count;
115 : id *members = NULL;
116 : NSArray *result = nil;
117 : BOOL tempObjects = NO;
118 :
119 : count = [self count];
120 : if (count == 0) return [[NSArray array] retain];
121 :
122 : members = calloc(sizeof *members, count);
123 : if (members == NULL)
124 : {
125 : [NSException raise:NSMallocException format:@"Failed to allocate space for %lu objects in %s.", (unsigned long)count, __PRETTY_FUNCTION__];
126 : }
127 :
128 : // Ensure there's an objects set even if passed nil.
129 : if (objects == nil)
130 : {
131 : objects = [[NSMutableSet alloc] init];
132 : tempObjects = YES;
133 : }
134 :
135 : [self getObjects:members];
136 : @try
137 : {
138 : // Deep copy members.
139 : for (i = 0; i < count; i++)
140 : {
141 : members[i] = [members[i] ooDeepCopyWithSharedObjects:objects];
142 : }
143 :
144 : // Make NSArray of results.
145 : result = [[NSArray alloc] initWithObjects:members count:count];
146 : }
147 : @finally
148 : {
149 : // Release objects.
150 : for (i = 0; i < count; i++)
151 : {
152 : [members[i] release];
153 : }
154 :
155 : free(members);
156 : if (tempObjects) [objects release];
157 : }
158 :
159 : // Collections are not reused because comparing them is arbitrarily slow.
160 : return result;
161 : }
162 :
163 : @end
164 :
165 :
166 : @implementation NSSet (OODeepCopy)
167 :
168 0 : - (id) ooDeepCopyWithSharedObjects:(NSMutableSet *)objects
169 : {
170 : NSUInteger i, count;
171 : id *members = NULL;
172 : NSSet *result = nil;
173 : BOOL tempObjects = NO;
174 :
175 : count = [self count];
176 : if (count == 0) return [[NSSet set] retain];
177 :
178 : members = malloc(sizeof *members * count);
179 : if (members == NULL)
180 : {
181 : [NSException raise:NSMallocException format:@"Failed to allocate space for %lu objects in %s.", (unsigned long)count, __PRETTY_FUNCTION__];
182 : }
183 :
184 : // Ensure there's an objects set even if passed nil.
185 : if (objects == nil)
186 : {
187 : objects = [[NSMutableSet alloc] init];
188 : tempObjects = YES;
189 : }
190 :
191 : @try
192 : {
193 : i = 0;
194 : id member = nil;
195 : // Deep copy members.
196 : foreach (member, self)
197 : {
198 : members[i] = [member ooDeepCopyWithSharedObjects:objects];
199 : i++;
200 : }
201 :
202 : // Make NSSet of results.
203 : result = [[NSSet alloc] initWithObjects:members count:count];
204 : }
205 : @finally
206 : {
207 : // Release objects.
208 : for (i = 0; i < count; i++)
209 : {
210 : [members[i] release];
211 : }
212 :
213 : free(members);
214 : if (tempObjects) [objects release];
215 : }
216 :
217 : // Collections are not reused because comparing them is arbitrarily slow.
218 : return result;
219 : }
220 :
221 : @end
222 :
223 :
224 : @implementation NSDictionary (OODeepCopy)
225 :
226 0 : - (id) ooDeepCopyWithSharedObjects:(NSMutableSet *)objects
227 : {
228 : NSUInteger i, count;
229 : id *keys = NULL;
230 : id *values = NULL;
231 : NSDictionary *result = nil;
232 : BOOL tempObjects = NO;
233 :
234 : count = [self count];
235 : if (count == 0) return [[NSDictionary dictionary] retain];
236 :
237 : keys = malloc(sizeof *keys * count);
238 : values = malloc(sizeof *values * count);
239 : if (keys == NULL || values == NULL)
240 : {
241 : free(keys);
242 : free(values);
243 : [NSException raise:NSMallocException format:@"Failed to allocate space for %lu objects in %s.", (unsigned long)count, __PRETTY_FUNCTION__];
244 : }
245 :
246 : // Ensure there's an objects set even if passed nil.
247 : if (objects == nil)
248 : {
249 : objects = [[NSMutableSet alloc] init];
250 : tempObjects = YES;
251 : }
252 :
253 : @try
254 : {
255 : i = 0;
256 : id key = nil;
257 : // Deep copy members.
258 : foreachkey (key, self)
259 : {
260 : keys[i] = [key ooDeepCopyWithSharedObjects:objects];
261 : values[i] = [[self objectForKey:key] ooDeepCopyWithSharedObjects:objects];
262 : i++;
263 : }
264 :
265 : // Make NSDictionary of results.
266 : result = [[NSDictionary alloc] initWithObjects:values forKeys:keys count:count];
267 : }
268 : @finally
269 : {
270 : // Release objects.
271 : for (i = 0; i < count; i++)
272 : {
273 : [keys[i] release];
274 : [values[i] release];
275 : }
276 :
277 : free(keys);
278 : free(values);
279 : if (tempObjects) [objects release];
280 : }
281 :
282 : // Collections are not reused because comparing them is arbitrarily slow.
283 : return result;
284 : }
285 :
286 : @end
|