]> err.no Git - sope/blob - sope-core/NGExtensions/NGMerging.m
Drop apache 1 build-dependency
[sope] / sope-core / NGExtensions / NGMerging.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "NGMerging.h"
23 #include "common.h"
24 #import <Foundation/Foundation.h>
25 #import <Foundation/NSObject.h>
26
27 static NSString *NGCannotMergeWithObjectException =
28   @"NGCannotMergeWithObjectException";
29
30 @implementation NSObject(NGMerging)
31
32 - (BOOL)canMergeWithObject:(id)_object {
33   return ((_object == nil) || (_object == self)) ? YES : NO;
34 }
35
36 - (id)_makeMergeCopyWithZone:(NSZone *)_zone {
37   return [(id<NSCopying>)self copyWithZone:_zone];
38 }
39
40 - (id)mergeWithObject:(id)_object zone:(NSZone *)_zone {
41   if ((_object == nil) || (_object == self))
42     return [self _makeMergeCopyWithZone:_zone];
43   
44   [NSException raise:NGCannotMergeWithObjectException
45                format:@"cannot merge objects of class %@ and %@",
46                  NSStringFromClass([self class]),
47                  NSStringFromClass([_object class])];
48   return nil;
49 }
50
51 - (id)mergeWithObject:(id)_object {
52   return [self mergeWithObject:_object zone:NULL];
53 }
54
55 @end
56
57 @implementation NSDictionary(NGMerging)
58
59 - (BOOL)canMergeWithObject:(id)_object {
60   if ((self == _object) || (_object == nil))
61     return YES;
62
63   if ([_object isKindOfClass:[NSDictionary class]])
64     return YES;
65
66   return NO;
67 }
68
69 - (id)_makeMergeCopyWithZone:(NSZone *)_zone {
70   return [self retain];
71 }
72
73 - (id)mergeWithDictionary:(NSDictionary *)_object zone:(NSZone *)_zone {
74   NSMutableDictionary *result;
75   NSArray *aKeys, *bKeys;
76   int i, count;
77   
78   if ((self == _object) || (_object == nil))
79     return [self _makeMergeCopyWithZone:_zone];
80
81   aKeys = [self allKeys];
82   bKeys = [_object allKeys];
83   result = [NSMutableDictionary dictionary];
84
85   /* merge all keys of a */
86   for (i = 0, count = [aKeys count]; i < count; i++) {
87     id key;
88     id av, bv;
89
90     key = [aKeys objectAtIndex:i];
91     av = [self    objectForKey:key];
92     bv = [_object objectForKey:key];
93
94     if (bv == nil) {
95       /* key is only in a */
96       [result setObject:av forKey:key];
97     }
98     else {
99       /* key is in both - need to merge */
100       if ([av canMergeWithObject:bv]) {
101         av = [av mergeWithObject:bv zone:_zone];
102         [result setObject:av forKey:key];
103       }
104       else
105         // if objects cannot be merged, av wins
106         [result setObject:av forKey:key];
107     }
108   }
109
110   /* add remaining keys in b */
111   for (i = 0, count = [bKeys count]; i < count; i++) {
112     id key;
113
114     key = [bKeys objectAtIndex:i];
115     if ([result objectForKey:key])
116       // already merged key ..
117       continue;
118
119     [result setObject:[_object objectForKey:key] forKey:key];
120   }
121
122   return result;
123 }
124
125 - (id)mergeWithObject:(id)_object zone:(NSZone *)_zone {
126   if ((self == _object) || (_object == nil))
127     return [self _makeMergeCopyWithZone:_zone];
128   
129   if ([_object isKindOfClass:[NSDictionary class]])
130     return [self mergeWithDictionary:_object zone:_zone];
131
132   [NSException raise:NGCannotMergeWithObjectException
133                format:@"cannot merge %@ with %@",
134                  NSStringFromClass([self class]),
135                  NSStringFromClass([_object class])];
136   return nil;
137 }
138
139 @end
140
141 @implementation NSMutableDictionary(NGMerging)
142
143 - (id)_makeMergeCopyWithZone:(NSZone *)_zone {
144   return [self copyWithZone:_zone];
145 }
146
147 @end
148
149 @implementation NSArray(NGMerging)
150
151 - (BOOL)canMergeWithObject:(id)_object {
152   if ((self == _object) || (_object == nil))
153     return YES;
154
155   if ([_object respondsToSelector:@selector(objectEnumerator)])
156     return YES;
157   
158   return NO;
159 }
160
161 - (id)_makeMergeCopyWithZone:(NSZone *)_zone {
162   return [self retain];
163 }
164
165 - (id)mergeWithEnumeration:(NSEnumerator *)_object zone:(NSZone *)_zone {
166   NSMutableArray *result;
167   id value;
168
169   if (_object == nil)
170     return [self _makeMergeCopyWithZone:_zone];
171
172   /* make copy of self */
173   result = [[self mutableCopyWithZone:_zone] autorelease];
174
175   /* add other elements */
176   while ((value = [_object nextObject]))
177     [result addObject:value];
178
179   return result;
180 }
181
182 - (id)mergeWithArray:(NSArray *)_object zone:(NSZone *)_zone {
183   if (_object == nil)
184     return [self _makeMergeCopyWithZone:_zone];
185   
186   return [self arrayByAddingObjectsFromArray:_object];
187 }
188
189 - (id)mergeWithObject:(id)_object zone:(NSZone *)_zone {
190   if (_object == nil)
191     return [self _makeMergeCopyWithZone:_zone];
192   
193   if ([_object respondsToSelector:@selector(objectEnumerator)])
194     return [self mergeWithEnumeration:[_object objectEnumerator] zone:_zone];
195
196   [NSException raise:NGCannotMergeWithObjectException
197                format:@"cannot merge %@ with %@",
198                  NSStringFromClass([self class]),
199                  NSStringFromClass([_object class])];
200   return nil;
201 }
202
203 @end
204
205 @implementation NSMutableArray(NGMerging)
206
207 - (id)_makeMergeCopyWithZone:(NSZone *)_zone {
208   return [self copyWithZone:_zone];
209 }
210
211 @end
212
213 // for static linking
214
215 void __link_NGExtensions_NGMerging(void) {
216   __link_NGExtensions_NGMerging();
217 }