ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/dynbuf.C
Revision: 1.23
Committed: Thu Sep 11 21:36:07 2008 UTC (15 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_80, rel-2_72, rel-2_73, rel-2_71, rel-2_76, rel-2_77, rel-2_74, rel-2_75, rel-2_79, rel-2_78
Changes since 1.22: +8 -6 lines
Log Message:
*** empty log message ***

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