ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/dynbuf.C
Revision: 1.18
Committed: Thu Aug 16 06:36:56 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_2
Changes since 1.17: +13 -7 lines
Log Message:
first, untested, try at spicing up the message system

File Contents

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