]> err.no Git - sope/blob - sope-core/NGExtensions/NGMerging.m
renamed packages as discussed in the developer list
[sope] / sope-core / NGExtensions / NGMerging.m
1 /*
2   Copyright (C) 2000-2003 SKYRIX Software AG
3
4   This file is part of OGo
5
6   OGo 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   OGo 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 OGo; 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 // $Id$
22
23 #include "NGMerging.h"
24 #include "common.h"
25 #import <Foundation/Foundation.h>
26 #import <Foundation/NSObject.h>
27
28 static NSString *NGCannotMergeWithObjectException =
29   @"NGCannotMergeWithObjectException";
30
31 @implementation NSObject(NGMerging)
32
33 - (BOOL)canMergeWithObject:(id)_object {
34   return ((_object == nil) || (_object == self)) ? YES : NO;
35 }
36
37 - (id)_makeMergeCopyWithZone:(NSZone *)_zone {
38   return [(id<NSCopying>)self copyWithZone:_zone];
39 }
40
41 - (id)mergeWithObject:(id)_object zone:(NSZone *)_zone {
42   if ((_object == nil) || (_object == self))
43     return [self _makeMergeCopyWithZone:_zone];
44   
45   [NSException raise:NGCannotMergeWithObjectException
46                format:@"cannot merge objects of class %@ and %@",
47                  NSStringFromClass([self class]),
48                  NSStringFromClass([_object class])];
49   return nil;
50 }
51
52 - (id)mergeWithObject:(id)_object {
53   return [self mergeWithObject:_object zone:NULL];
54 }
55
56 @end
57
58 @implementation NSDictionary(NGMerging)
59
60 - (BOOL)canMergeWithObject:(id)_object {
61   if ((self == _object) || (_object == nil))
62     return YES;
63
64   if ([_object isKindOfClass:[NSDictionary class]])
65     return YES;
66
67   return NO;
68 }
69
70 - (id)_makeMergeCopyWithZone:(NSZone *)_zone {
71   return [self retain];
72 }
73
74 - (id)mergeWithDictionary:(NSDictionary *)_object zone:(NSZone *)_zone {
75   NSMutableDictionary *result;
76   NSArray *aKeys, *bKeys;
77   int i, count;
78   
79   if ((self == _object) || (_object == nil))
80     return [self _makeMergeCopyWithZone:_zone];
81
82   aKeys = [self allKeys];
83   bKeys = [_object allKeys];
84   result = [NSMutableDictionary dictionary];
85
86   /* merge all keys of a */
87   for (i = 0, count = [aKeys count]; i < count; i++) {
88     id key;
89     id av, bv;
90
91     key = [aKeys objectAtIndex:i];
92     av = [self    objectForKey:key];
93     bv = [_object objectForKey:key];
94
95     if (bv == nil) {
96       /* key is only in a */
97       [result setObject:av forKey:key];
98     }
99     else {
100       /* key is in both - need to merge */
101       if ([av canMergeWithObject:bv]) {
102         av = [av mergeWithObject:bv zone:_zone];
103         [result setObject:av forKey:key];
104       }
105       else
106         // if objects cannot be merged, av wins
107         [result setObject:av forKey:key];
108     }
109   }
110
111   /* add remaining keys in b */
112   for (i = 0, count = [bKeys count]; i < count; i++) {
113     id key;
114
115     key = [bKeys objectAtIndex:i];
116     if ([result objectForKey:key])
117       // already merged key ..
118       continue;
119
120     [result setObject:[_object objectForKey:key] forKey:key];
121   }
122
123   return result;
124 }
125
126 - (id)mergeWithObject:(id)_object zone:(NSZone *)_zone {
127   if ((self == _object) || (_object == nil))
128     return [self _makeMergeCopyWithZone:_zone];
129   
130   if ([_object isKindOfClass:[NSDictionary class]])
131     return [self mergeWithDictionary:_object zone:_zone];
132
133   [NSException raise:NGCannotMergeWithObjectException
134                format:@"cannot merge %@ with %@",
135                  NSStringFromClass([self class]),
136                  NSStringFromClass([_object class])];
137   return nil;
138 }
139
140 @end
141
142 @implementation NSMutableDictionary(NGMerging)
143
144 - (id)_makeMergeCopyWithZone:(NSZone *)_zone {
145   return [self copyWithZone:_zone];
146 }
147
148 @end
149
150 @implementation NSArray(NGMerging)
151
152 - (BOOL)canMergeWithObject:(id)_object {
153   if ((self == _object) || (_object == nil))
154     return YES;
155
156   if ([_object respondsToSelector:@selector(objectEnumerator)])
157     return YES;
158   
159   return NO;
160 }
161
162 - (id)_makeMergeCopyWithZone:(NSZone *)_zone {
163   return [self retain];
164 }
165
166 - (id)mergeWithEnumeration:(NSEnumerator *)_object zone:(NSZone *)_zone {
167   NSMutableArray *result;
168   id value;
169
170   if (_object == nil)
171     return [self _makeMergeCopyWithZone:_zone];
172
173   /* make copy of self */
174   result = [[self mutableCopyWithZone:_zone] autorelease];
175
176   /* add other elements */
177   while ((value = [_object nextObject]))
178     [result addObject:value];
179
180   return result;
181 }
182
183 - (id)mergeWithArray:(NSArray *)_object zone:(NSZone *)_zone {
184   if (_object == nil)
185     return [self _makeMergeCopyWithZone:_zone];
186   
187   return [self arrayByAddingObjectsFromArray:_object];
188 }
189
190 - (id)mergeWithObject:(id)_object zone:(NSZone *)_zone {
191   if (_object == nil)
192     return [self _makeMergeCopyWithZone:_zone];
193   
194   if ([_object respondsToSelector:@selector(objectEnumerator)])
195     return [self mergeWithEnumeration:[_object objectEnumerator] zone:_zone];
196
197   [NSException raise:NGCannotMergeWithObjectException
198                format:@"cannot merge %@ with %@",
199                  NSStringFromClass([self class]),
200                  NSStringFromClass([_object class])];
201   return nil;
202 }
203
204 @end
205
206 @implementation NSMutableArray(NGMerging)
207
208 - (id)_makeMergeCopyWithZone:(NSZone *)_zone {
209   return [self copyWithZone:_zone];
210 }
211
212 @end
213
214 // for static linking
215
216 void __link_NGExtensions_NGMerging(void) {
217   __link_NGExtensions_NGMerging();
218 }