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