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

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 *
6 * Deliantra is free software: you can redistribute it and/or modify
7 * 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 *
11 * 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 *
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 *
19 * The authors can be reached via e-mail to <support@deliantra.net>
20 */
21
22 #include "global.h"
23
24 #include <cstdio>
25
26 void
27 dynbuf::init (int initial)
28 {
29 cextend = extend;
30 _size = 0;
31
32 first = last = (chunk *)salloc<char> (sizeof (chunk) + initial);
33 first->alloc = sizeof (chunk) + initial;
34 first->next = 0;
35
36 ptr = first->data;
37 end = ptr + initial;
38 }
39
40 // frees a full chain and sets the pointer to zero
41 void
42 dynbuf::free (chunk *&chain)
43 {
44 while (chain)
45 {
46 chunk *next = chain->next;
47
48 sfree<char> ((char *)chain, chain->alloc);
49 chain = next;
50 }
51 }
52
53 void
54 dynbuf::clear ()
55 {
56 cextend = extend;
57 free (first->next);
58
59 _size = 0;
60 ptr = first->data;
61 end = ptr + first->alloc - sizeof (chunk);
62 last = first;
63 }
64
65 void
66 dynbuf::finalise ()
67 {
68 // finalise current chunk
69 _size += last->size = ptr - last->data;
70 }
71
72 void
73 dynbuf::reserve (int size)
74 {
75 finalise ();
76
77 do
78 {
79 cextend += cextend >> 1;
80 cextend = (cextend + 15) & ~15;
81 }
82 while (cextend < size);
83
84 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + cextend);
85 add->alloc = sizeof (chunk) + cextend;
86 add->next = 0;
87
88 last->next = add;
89 last = add;
90
91 ptr = last->data;
92 end = ptr + cextend;
93 }
94
95 void
96 dynbuf::linearise (void *data)
97 {
98 last->size = ptr - last->data;
99
100 for (chunk *c = first; c; c = c->next)
101 {
102 memcpy (data, c->data, c->size);
103 data = (void *)(((char *)data) + c->size);
104 }
105 }
106
107 char *
108 dynbuf::_linearise ()
109 {
110 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
119 first = last = add;
120 ptr = last->data + _size;
121 end = ptr;
122 _size = 0;
123
124 return first->data;
125 }
126
127 dynbuf::operator std::string ()
128 {
129 // could optimise
130 return std::string (linearise (), size ());
131 }
132
133 void
134 dynbuf_text::vprintf (const char *format, va_list ap)
135 {
136 int len;
137
138 {
139 force (128);
140
141 va_list apc;
142 va_copy (apc, ap);
143 len = vsnprintf (ptr, end - ptr, format, apc);
144 va_end (apc);
145
146 assert (len >= 0); // shield against broken vsnprintf's
147
148 // was enough room available
149 if (ptr + len < end)
150 {
151 ptr += len;
152 return;
153 }
154 }
155
156 // longer, try harder
157 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 va_list ap;
166 va_start (ap, format);
167 vprintf (format, ap);
168 va_end (ap);
169 }
170
171 // simply return a mask with "bits" bits set
172 inline uint64
173 m (int b)
174 {
175 return (uint64 (1) << b) - 1;
176 }
177
178 // 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 const int bits = 7*8; // 7 bits per post-comma digit
188
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 }
205 else
206 {
207 // 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 }
221
222 return ptr;
223 }
224
225 void
226 dynbuf_text::add (sint32 i)
227 {
228 force (sint32_digits);
229
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 {
239 sint32 div = u / 1000000000;
240 uint32 rem = u % 1000000000;
241
242 ptr = i2a_9 (ptr, div, false);
243 ptr = i2a_9 (ptr, rem, true);
244 }
245 }
246
247 void
248 dynbuf_text::add (sint64 i)
249 {
250 force (sint64_digits);
251
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
258 // good compilers will only use multiplications here
259
260 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 {
266 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 }
272 else
273 {
274 // 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 }
289 }
290
291 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 #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