ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/dynbuf.C
Revision: 1.35
Committed: Tue Jan 3 11:25:36 2012 UTC (12 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.34: +1 -1 lines
Log Message:
update copyrights to 2012

File Contents

# User Rev Content
1 root 1.15 /*
2 root 1.20 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 root 1.15 *
4 root 1.35 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.15 *
6 root 1.24 * Deliantra is free software: you can redistribute it and/or modify it under
7     * the terms of the Affero GNU General Public License as published by the
8     * Free Software Foundation, either version 3 of the License, or (at your
9     * option) any later version.
10 root 1.15 *
11 root 1.16 * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15 root 1.15 *
16 root 1.24 * You should have received a copy of the Affero GNU General Public License
17     * and the GNU General Public License along with this program. If not, see
18     * <http://www.gnu.org/licenses/>.
19 root 1.15 *
20 root 1.20 * The authors can be reached via e-mail to <support@deliantra.net>
21 root 1.15 */
22    
23 root 1.1 #include "global.h"
24    
25     #include <cstdio>
26    
27 root 1.17 void
28     dynbuf::init (int initial)
29 root 1.1 {
30 root 1.23 cextend = extend;
31 root 1.1 _size = 0;
32 root 1.5
33 root 1.8 first = last = (chunk *)salloc<char> (sizeof (chunk) + initial);
34     first->alloc = sizeof (chunk) + initial;
35 root 1.1 first->next = 0;
36 root 1.8
37 root 1.5 ptr = first->data;
38 root 1.9 end = ptr + initial;
39 root 1.1 }
40    
41 root 1.22 // frees a full chain and sets the pointer to zero
42 root 1.5 void
43 root 1.17 dynbuf::free (chunk *&chain)
44 root 1.1 {
45 root 1.17 while (chain)
46 root 1.1 {
47 root 1.17 chunk *next = chain->next;
48 root 1.5
49 root 1.17 sfree<char> ((char *)chain, chain->alloc);
50     chain = next;
51 root 1.1 }
52 root 1.5 }
53 root 1.1
54 root 1.5 void
55 root 1.10 dynbuf::clear ()
56     {
57 root 1.23 cextend = extend;
58 root 1.17 free (first->next);
59    
60 root 1.10 _size = 0;
61     ptr = first->data;
62 root 1.17 end = ptr + first->alloc - sizeof (chunk);
63 root 1.22 last = first;
64 root 1.10 }
65    
66     void
67 root 1.17 dynbuf::finalise ()
68 root 1.1 {
69     // finalise current chunk
70     _size += last->size = ptr - last->data;
71     }
72    
73 root 1.5 void
74 root 1.17 dynbuf::reserve (int size)
75 root 1.1 {
76 root 1.17 finalise ();
77 root 1.1
78     do
79     {
80 root 1.23 cextend += cextend >> 1;
81     cextend = (cextend + 15) & ~15;
82 root 1.1 }
83 root 1.23 while (cextend < size);
84 root 1.1
85 root 1.23 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + cextend);
86     add->alloc = sizeof (chunk) + cextend;
87 root 1.1 add->next = 0;
88    
89     last->next = add;
90     last = add;
91    
92 root 1.5 ptr = last->data;
93 root 1.23 end = ptr + cextend;
94 root 1.1 }
95    
96 root 1.5 void
97     dynbuf::linearise (void *data)
98 root 1.1 {
99     last->size = ptr - last->data;
100    
101 root 1.10 for (chunk *c = first; c; c = c->next)
102 root 1.1 {
103 root 1.10 memcpy (data, c->data, c->size);
104     data = (void *)(((char *)data) + c->size);
105 root 1.1 }
106     }
107    
108 root 1.5 char *
109 root 1.26 dynbuf::_linearise (int extra)
110 root 1.1 {
111 root 1.17 finalise ();
112    
113 root 1.26 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + _size + extra);
114 root 1.17 add->alloc = sizeof (chunk) + _size;
115     add->next = 0;
116    
117     linearise ((void *)add->data);
118     free (first);
119 root 1.1
120 root 1.17 first = last = add;
121     ptr = last->data + _size;
122 root 1.26 end = ptr + extra;
123 root 1.17 _size = 0;
124 root 1.1
125     return first->data;
126     }
127    
128 root 1.7 dynbuf::operator std::string ()
129     {
130     // could optimise
131     return std::string (linearise (), size ());
132     }
133    
134     void
135 root 1.26 dynbuf::splice (int offset, int olen, const char *s, int slen)
136     {
137     // how much bytes to extend (negative if shrinking)
138     int adjust = slen - olen;
139    
140     // linearise, unless everything fits in the last chunk
141     if (offset < _size || room () < adjust)
142     _linearise (max (adjust, 0));
143    
144     offset -= _size; // offset into chunk
145    
146     // now move tail to final position
147     char *pos = last->data + offset;
148     char *src = pos + olen;
149     char *dst = pos + slen;
150     memmove (dst, src, ptr - src);
151    
152     // now copy new content
153     memcpy (pos, s, slen);
154    
155     // finally adjust length
156     ptr += adjust;
157     }
158    
159     void
160 root 1.18 dynbuf_text::vprintf (const char *format, va_list ap)
161 root 1.7 {
162     int len;
163    
164     {
165     force (128);
166    
167 root 1.18 va_list apc;
168     va_copy (apc, ap);
169 root 1.19 len = vsnprintf (ptr, end - ptr, format, apc);
170 root 1.18 va_end (apc);
171 root 1.7
172     assert (len >= 0); // shield against broken vsnprintf's
173    
174     // was enough room available
175 root 1.9 if (ptr + len < end)
176 root 1.7 {
177 root 1.13 ptr += len;
178 root 1.7 return;
179     }
180     }
181    
182     // longer, try harder
183 root 1.18 vsnprintf (force (len + 1), len + 1, format, ap);
184    
185     ptr += len;
186     }
187    
188     void
189     dynbuf_text::printf (const char *format, ...)
190     {
191 root 1.7 va_list ap;
192     va_start (ap, format);
193 root 1.18 vprintf (format, ap);
194 root 1.7 va_end (ap);
195     }
196    
197 root 1.11 // simply return a mask with "bits" bits set
198 root 1.28 static inline uint64
199 root 1.11 m (int b)
200 root 1.1 {
201 root 1.11 return (uint64 (1) << b) - 1;
202     }
203 root 1.1
204 root 1.11 // convert 9 digits to ascii, using only a single multiplication
205     // (depending on cpu and compiler).
206     // will generate a single 0 as output when v=lz=0
207 root 1.28 static inline char *
208 root 1.11 i2a_9 (char *ptr, uint32 v, bool lz)
209     {
210     // convert to 4.56 fixed-point representation
211     // this should be optimal on 64 bit cpus, and rather
212     // slow on 32 bit cpus. go figure :)
213 root 1.12 const int bits = 7*8; // 7 bits per post-comma digit
214 root 1.11
215     uint64 u = v * ((m (bits) + 100000000) / 100000000); // 10**8
216    
217     if (lz)
218     {
219     // output leading zeros
220     // good compilers will compile this into only shifts, masks and adds
221 root 1.33 *ptr++ = char (u >> (bits - 0)) + '0'; u = (u & m (bits - 0)) * 5;
222 root 1.11 *ptr++ = char (u >> (bits - 1)) + '0'; u = (u & m (bits - 1)) * 5;
223     *ptr++ = char (u >> (bits - 2)) + '0'; u = (u & m (bits - 2)) * 5;
224     *ptr++ = char (u >> (bits - 3)) + '0'; u = (u & m (bits - 3)) * 5;
225     *ptr++ = char (u >> (bits - 4)) + '0'; u = (u & m (bits - 4)) * 5;
226     *ptr++ = char (u >> (bits - 5)) + '0'; u = (u & m (bits - 5)) * 5;
227     *ptr++ = char (u >> (bits - 6)) + '0'; u = (u & m (bits - 6)) * 5;
228     *ptr++ = char (u >> (bits - 7)) + '0'; u = (u & m (bits - 7)) * 5;
229     *ptr++ = char (u >> (bits - 8)) + '0';
230 root 1.1 }
231     else
232 root 1.4 {
233 root 1.11 // do not output leading zeroes (except if v == 0)
234     // good compilers will compile this into completely branchless code
235     char digit, nz = 0;
236    
237     digit = (u >> (bits - 0)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 0)) * 5;
238     digit = (u >> (bits - 1)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 1)) * 5;
239     digit = (u >> (bits - 2)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 2)) * 5;
240     digit = (u >> (bits - 3)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 3)) * 5;
241     digit = (u >> (bits - 4)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 4)) * 5;
242     digit = (u >> (bits - 5)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 5)) * 5;
243     digit = (u >> (bits - 6)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 6)) * 5;
244     digit = (u >> (bits - 7)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 7)) * 5;
245     digit = (u >> (bits - 8)); *ptr = digit + '0'; nz |= digit; ptr += 1;
246 root 1.4 }
247 root 1.1
248 root 1.11 return ptr;
249     }
250    
251     void
252     dynbuf_text::add (sint32 i)
253     {
254 root 1.14 force (sint32_digits);
255 root 1.11
256     *ptr = '-'; ptr += i < 0 ? 1 : 0;
257     uint32 u = i < 0 ? -i : i;
258    
259     if (expect_true (u < 10)) // we have a lot of single-digit numbers, so optimise
260 root 1.30 *ptr++ = u + '0';
261     else if (expect_true (u < 100)) // we have a lot of double-digit numbers, too :)
262     {
263     // let the compiler figure out sth. efficient here
264     *ptr++ = u / 10 + '0';
265     *ptr++ = u % 10 + '0';
266     }
267 root 1.11 else if (expect_true (u < 1000000000)) // 9 0's
268     ptr = i2a_9 (ptr, u, false);
269     else
270 root 1.1 {
271 root 1.30 uint32 div = u / 1000000000;
272 root 1.11 uint32 rem = u % 1000000000;
273 root 1.5
274 root 1.11 ptr = i2a_9 (ptr, div, false);
275     ptr = i2a_9 (ptr, rem, true);
276 root 1.1 }
277     }
278    
279 root 1.5 void
280 root 1.7 dynbuf_text::add (sint64 i)
281 root 1.1 {
282 root 1.14 force (sint64_digits);
283 root 1.11
284     *ptr = '-'; ptr += i < 0 ? 1 : 0;
285     uint64 u = i < 0 ? -i : i;
286    
287     // split the number into a 1-digit part
288     // (#19) and two 9 digit parts (9..18 and 0..8)
289 root 1.4
290 root 1.11 // good compilers will only use multiplications here
291 root 1.2
292 root 1.11 if (u < 10) // we have a lot of single-digit numbers, so optimise
293 root 1.30 *ptr++ = u + '0';
294 root 1.11 else if (expect_true (u < 1000000000)) // 9 0's
295     ptr = i2a_9 (ptr, u, false);
296     else if (expect_true (u < UINT64_C (1000000000000000000))) // 18 0's
297 root 1.1 {
298 root 1.30 uint32 div = u / 1000000000;
299 root 1.11 uint32 rem = u % 1000000000;
300    
301     ptr = i2a_9 (ptr, div, false);
302     ptr = i2a_9 (ptr, rem, true);
303 root 1.1 }
304 root 1.2 else
305 root 1.1 {
306 root 1.30 // a biggy, split off the topmost digit
307     uint32 div = u / UINT64_C (1000000000000000000);
308 root 1.11 uint64 rem = u % UINT64_C (1000000000000000000);
309    
310 root 1.30 *ptr++ = div + '0';
311    
312 root 1.11 u = rem;
313    
314     {
315 root 1.30 uint32 div = u / 1000000000;
316 root 1.11 uint32 rem = u % 1000000000;
317    
318     ptr = i2a_9 (ptr, div, true);
319     ptr = i2a_9 (ptr, rem, true);
320     }
321 root 1.1 }
322 root 1.11 }
323 root 1.1
324 root 1.25 dynbuf_text::operator char *()
325 root 1.17 {
326     *this << '\0';
327     linearise ();
328     --ptr;
329     return first->data;
330     }
331    
332     void
333     dynbuf_text::add_abilities (const char *name, uint32 abilities)
334     {
335     if (!abilities)
336     return;
337    
338     *this << '(' << name;
339    
340     const char *sep = ": ";
341 root 1.29 for_all_bits_sparse_32 (abilities, i)
342     {
343     *this << sep; sep = ", ";
344     *this << attacks [i];
345     }
346 root 1.17
347     *this << ')';
348     }
349    
350     void
351     dynbuf_text::add_paths (const char *name, uint32 paths)
352     {
353     if (!paths)
354     return;
355    
356     *this << '(' << name;
357    
358     const char *sep = ": ";
359     for (int i = 0; i < NRSPELLPATHS; ++i)
360     if (paths & (1 << i))
361     {
362     *this << sep; sep = ", ";
363     *this << spellpathnames [i];
364     }
365    
366     *this << ')';
367     }
368    
369 root 1.11 #if 0
370     struct dynbuf_test_class {
371     dynbuf_test_class ()
372     {
373     sint64 s = 0;
374     for (int i = 0; i < 10000000; ++i)
375     {
376     char b1[256], b2[256];
377    
378     dynbuf_text db;
379     db.add (s);
380     db.add (char (0));
381    
382     db.linearise (b1);
383     sprintf (b2, "%ld", s);
384    
385     if (strcmp (b1, b2))
386     printf ("<%s,%s>\n", b1, b2);
387    
388     if (i < 20)
389     s = (sint64) pow (10., i);
390     else
391     s = (sint64) exp (random () * (43.6682723752766 / RAND_MAX));
392     }
393    
394     exit (0);
395     }
396     } dynbuf_test;
397     #endif
398 root 1.17