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