ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/dynbuf.C
Revision: 1.29
Committed: Wed Nov 11 03:52:45 2009 UTC (14 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.28: +5 -6 lines
Log Message:
fix icecube thawing bug

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.27 * Copyright (©) 2005,2006,2007,2008,2009 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     *ptr++ = char (u >> (bits - 0)) + '0'; u = (u & m (bits - 0)) * 5;
222     *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     fadd (char (u + '0'));
261     else if (expect_true (u < 1000000000)) // 9 0's
262     ptr = i2a_9 (ptr, u, false);
263     else
264 root 1.1 {
265 root 1.11 sint32 div = u / 1000000000;
266     uint32 rem = u % 1000000000;
267 root 1.5
268 root 1.11 ptr = i2a_9 (ptr, div, false);
269     ptr = i2a_9 (ptr, rem, true);
270 root 1.1 }
271     }
272    
273 root 1.5 void
274 root 1.7 dynbuf_text::add (sint64 i)
275 root 1.1 {
276 root 1.14 force (sint64_digits);
277 root 1.11
278     *ptr = '-'; ptr += i < 0 ? 1 : 0;
279     uint64 u = i < 0 ? -i : i;
280    
281     // split the number into a 1-digit part
282     // (#19) and two 9 digit parts (9..18 and 0..8)
283 root 1.4
284 root 1.11 // good compilers will only use multiplications here
285 root 1.2
286 root 1.11 if (u < 10) // we have a lot of single-digit numbers, so optimise
287     fadd (char (u + '0'));
288     else if (expect_true (u < 1000000000)) // 9 0's
289     ptr = i2a_9 (ptr, u, false);
290     else if (expect_true (u < UINT64_C (1000000000000000000))) // 18 0's
291 root 1.1 {
292 root 1.11 sint32 div = u / 1000000000;
293     uint32 rem = u % 1000000000;
294    
295     ptr = i2a_9 (ptr, div, false);
296     ptr = i2a_9 (ptr, rem, true);
297 root 1.1 }
298 root 1.2 else
299 root 1.1 {
300 root 1.11 // a biggy
301     sint32 div = u / UINT64_C (1000000000000000000);
302     uint64 rem = u % UINT64_C (1000000000000000000);
303    
304     fadd (char (div + '0'));
305     u = rem;
306    
307     {
308     sint32 div = u / 1000000000;
309     uint32 rem = u % 1000000000;
310    
311     ptr = i2a_9 (ptr, div, true);
312     ptr = i2a_9 (ptr, rem, true);
313     }
314 root 1.1 }
315 root 1.11 }
316 root 1.1
317 root 1.25 dynbuf_text::operator char *()
318 root 1.17 {
319     *this << '\0';
320     linearise ();
321     --ptr;
322     return first->data;
323     }
324    
325     void
326     dynbuf_text::add_abilities (const char *name, uint32 abilities)
327     {
328     if (!abilities)
329     return;
330    
331     *this << '(' << name;
332    
333     const char *sep = ": ";
334 root 1.29 for_all_bits_sparse_32 (abilities, i)
335     {
336     *this << sep; sep = ", ";
337     *this << attacks [i];
338     }
339 root 1.17
340     *this << ')';
341     }
342    
343     void
344     dynbuf_text::add_paths (const char *name, uint32 paths)
345     {
346     if (!paths)
347     return;
348    
349     *this << '(' << name;
350    
351     const char *sep = ": ";
352     for (int i = 0; i < NRSPELLPATHS; ++i)
353     if (paths & (1 << i))
354     {
355     *this << sep; sep = ", ";
356     *this << spellpathnames [i];
357     }
358    
359     *this << ')';
360     }
361    
362 root 1.11 #if 0
363     struct dynbuf_test_class {
364     dynbuf_test_class ()
365     {
366     sint64 s = 0;
367     for (int i = 0; i < 10000000; ++i)
368     {
369     char b1[256], b2[256];
370    
371     dynbuf_text db;
372     db.add (s);
373     db.add (char (0));
374    
375     db.linearise (b1);
376     sprintf (b2, "%ld", s);
377    
378     if (strcmp (b1, b2))
379     printf ("<%s,%s>\n", b1, b2);
380    
381     if (i < 20)
382     s = (sint64) pow (10., i);
383     else
384     s = (sint64) exp (random () * (43.6682723752766 / RAND_MAX));
385     }
386    
387     exit (0);
388     }
389     } dynbuf_test;
390     #endif
391 root 1.17