]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WOElementID.m
minor fixes
[sope] / sope-appserver / NGObjWeb / WOElementID.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 "WOElementID.h"
24 #include "common.h"
25
26 // TODO: do not keep the array in the ivars, but use malloc
27
28 //#define PROF_ELEMID 1
29
30 @implementation WOElementID
31
32 - (id)initWithString:(NSString *)_rid {  
33   NSArray *reid;
34   int     i;
35   
36   reid = [_rid componentsSeparatedByString:@"."];
37   if ((self->elementIdCount = [reid count]) == 0) {
38     [self release];
39     return nil;
40   }
41   if (self->elementIdCount > NGObjWeb_MAX_ELEMENT_ID_COUNT) {
42     [self logWithFormat:@"ERROR: request element ID is too long (%i parts)",
43             self->elementIdCount];
44     [self release];
45     return nil;
46   }
47   for (i = 0; i < self->elementIdCount; i++)
48     self->elementId[i].string = [[reid objectAtIndex:i] copy];
49   return self;
50 }
51
52 - (void)dealloc {
53   int i;
54   
55   [self->cs release];
56   for (i = 0; i < self->elementIdCount; i++) {
57     [self->elementId[i].string release];
58     [self->elementId[i].fqn    release];
59   }
60   [super dealloc];
61 }
62
63 /* methods */
64
65 #if PROF_ELEMID
66 static int prioCacheHit    = 0;
67 static int prioStrCacheHit = 0;
68 static int prioConstruct   = 0;
69 static int callCount       = 0;
70 #endif
71
72 - (NSString *)elementID {
73   /* 
74     TODO: increase performance (~24% of -componentActionURL [was 50%]) 
75     Prof: 1.9% -appendString
76           18%  -stringByAppendingString
77           1.9% -copy
78   */
79   static NSString *nums[30] = {
80     @".0", @".1", @".2", @".3", @".4", @".5", @".6", @".7", @".8", @".9",
81     @".10", @".11", @".12", @".13", @".14", 
82     @".15", @".16", @".17", @".18", @".19",
83     @".20", @".21", @".22", @".23", @".24", 
84     @".25", @".26", @".27", @".28", @".29",
85   };
86   NSString *e;
87   int i;
88 #if PROF_ELEMID
89   if (callCount % 10 == 0) {
90     printf("ElementIDProfing: #calls=%i "
91            "#priohits=%i(string=%i), #prioconstructs=%i\n",
92            callCount, prioCacheHit, prioStrCacheHit, prioConstruct);
93   }
94   callCount++;
95 #endif
96   
97   if (self->elementIdCount == 0) {
98     return nil;
99   }
100   else if (self->elementIdCount == 1) {
101     /* a single part in element id (the ctx-id) ... (rare case ...) */
102     if ((e = self->elementId[0].string))
103       return e;
104     
105     return [NSString stringWithFormat:@"%d", self->elementId[0].number];
106   }
107   else if ((e = self->elementId[(self->elementIdCount - 2)].fqn)) {
108     /* the prior part has a cached fqn */
109     /* TODO cache prior string as C-string ! */
110     NSString *o;
111 #if PROF_ELEMID
112     prioCacheHit++;
113 #endif
114     
115     if ((o = self->elementId[self->elementIdCount - 1].string)) {
116       NSMutableString *eid;
117 #if PROF_ELEMID
118       prioStrCacheHit++;
119 #endif
120       eid = [e mutableCopy];
121       [eid appendString:@"."];
122       [eid appendString:o];
123       return [eid autorelease];
124     }
125     else {
126       i = self->elementId[self->elementIdCount - 1].number;
127       if (i >= 0 && i < 30)
128         return [e stringByAppendingString:nums[i]];
129       return [e stringByAppendingFormat:@".%i", i];
130     }
131   }
132   if (self->cs == nil) {
133     self->cs = [[NSMutableString alloc] initWithCapacity:64];
134     self->addStr = [self->cs methodForSelector:@selector(appendString:)];
135   }
136   else
137     [self->cs setString:@""];
138
139   for (i = 0; i < self->elementIdCount; i++) {
140     register id o;
141     
142     if (i == (self->elementIdCount - 1)) {
143       /* the last iteration, cache the fqn of the *prior* element ! */
144       self->elementId[i - 1].fqn = [self->cs copy];
145 #if PROF_ELEMID
146       prioConstruct++;
147 #endif
148     }
149     
150     if ((o = self->elementId[i].string)) {
151       /* some identity comparison for faster NSNumber->NSString conversion */
152       if (i != 0) addStr(self->cs, @selector(appendString:), @".");
153       addStr(self->cs, @selector(appendString:), o);
154     }
155     else {
156       register int n;
157       
158       n = self->elementId[i].number;
159       if (n >= 0 && n < 30) {
160         if (i != 0)
161           addStr(self->cs, @selector(appendString:), nums[n]);
162         else
163           /* very rare, the first id is almost always a string (ctx-id!) */
164           [self->cs appendFormat:@"%i", n];
165       }
166       else {
167         [self->cs appendFormat:(i != 0 ? @".%i" : @"%i"), n];
168       }
169     }
170   }
171   return [[self->cs copy] autorelease];
172 }
173
174 - (void)appendElementIDComponent:(NSString *)_eid {
175   self->elementId[(int)self->elementIdCount].string = [_eid copy];
176   self->elementIdCount++;
177   NSAssert(self->elementIdCount < NGObjWeb_MAX_ELEMENT_ID_COUNT,
178            @"element id size exceeded !");
179 }
180 - (void)appendIntElementIDComponent:(int)_eid {
181   self->elementId[(int)self->elementIdCount].number = _eid;
182   self->elementIdCount++;
183   NSAssert(self->elementIdCount < NGObjWeb_MAX_ELEMENT_ID_COUNT,
184            @"element id size exceeded !");
185 }
186
187 - (void)appendZeroElementIDComponent {
188   self->elementId[(int)self->elementIdCount].number = 0;
189   self->elementIdCount++;
190   NSAssert(self->elementIdCount < NGObjWeb_MAX_ELEMENT_ID_COUNT,
191            @"element id size exceeded !");
192 }
193
194 - (void)deleteAllElementIDComponents {
195   int i;
196   for (i = 0; i < self->elementIdCount; i++) {
197     [self->elementId[i].string release];
198     self->elementId[i].string = nil;
199     [self->elementId[i].fqn release];
200     self->elementId[i].fqn = nil;
201   }
202   self->elementIdCount = 0;
203 }
204
205 - (void)deleteLastElementIDComponent {
206   if (self->elementIdCount == 0)
207     return;
208   
209   self->elementIdCount--;
210   [self->elementId[(int)self->elementIdCount].string release];
211   self->elementId[(int)(self->elementIdCount)].string = nil;
212   [self->elementId[(int)self->elementIdCount].fqn release];
213   self->elementId[(int)(self->elementIdCount)].fqn = nil;
214 }
215
216 - (void)incrementLastElementIDComponent {
217   register WOElementIDPart *p;
218   id v;
219   
220   if (self->elementIdCount < 1) {
221     [self logWithFormat:
222             @"WARNING: tried to increment a non-existing element-id"];
223     return;
224   }
225   else if (self->elementIdCount >= NGObjWeb_MAX_ELEMENT_ID_COUNT) {
226     [self logWithFormat:
227             @"ERROR: exceeded element-id restriction (max=%i)", 
228             NGObjWeb_MAX_ELEMENT_ID_COUNT];
229     return;
230   }
231   
232   // TODO: range check ?
233   p = &(self->elementId[(int)(self->elementIdCount - 1)]);
234   
235   [p->fqn release]; p->fqn = nil;
236   if ((v = p->string)) {
237     p->number = [v intValue] + 1;
238     [p->string release]; p->string = nil;
239   }
240   else
241     p->number++;
242 }
243
244 /* request ID processing */
245
246 - (id)currentElementID {
247   return (self->idPos >= self->elementIdCount)
248     ? nil
249     : self->elementId[(int)self->idPos].string;
250 }
251 - (id)consumeElementID {
252   (self->idPos)++;
253   return [self currentElementID];
254 }
255
256 @end /* WOElementID */