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

# 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 _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 // frees a full chain and sets the pointer to zero
40 void
41 dynbuf::free (chunk *&chain)
42 {
43 while (chain)
44 {
45 chunk *next = chain->next;
46
47 sfree<char> ((char *)chain, chain->alloc);
48 chain = next;
49 }
50 }
51
52 void
53 dynbuf::clear ()
54 {
55 free (first->next);
56
57 _size = 0;
58 ptr = first->data;
59 end = ptr + first->alloc - sizeof (chunk);
60 last = first;
61 }
62
63 void
64 dynbuf::finalise ()
65 {
66 // finalise current chunk
67 _size += last->size = ptr - last->data;
68 }
69
70 void
71 dynbuf::reserve (int size)
72 {
73 finalise ();
74
75 do
76 {
77 extend += extend >> 1;
78 extend = (extend + 15) & ~15;
79 }
80 while (extend < size);
81
82 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + extend);
83 add->alloc = sizeof (chunk) + extend;
84 add->next = 0;
85
86 last->next = add;
87 last = add;
88
89 ptr = last->data;
90 end = ptr + extend;
91 }
92
93 void
94 dynbuf::linearise (void *data)
95 {
96 last->size = ptr - last->data;
97
98 for (chunk *c = first; c; c = c->next)
99 {
100 memcpy (data, c->data, c->size);
101 data = (void *)(((char *)data) + c->size);
102 }
103 }
104
105 char *
106 dynbuf::_linearise ()
107 {
108 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
117 first = last = add;
118 ptr = last->data + _size;
119 end = ptr;
120 _size = 0;
121
122 return first->data;
123 }
124
125 dynbuf::operator std::string ()
126 {
127 // could optimise
128 return std::string (linearise (), size ());
129 }
130
131 void
132 dynbuf_text::vprintf (const char *format, va_list ap)
133 {
134 int len;
135
136 {
137 force (128);
138
139 va_list apc;
140 va_copy (apc, ap);
141 len = vsnprintf (ptr, end - ptr, format, apc);
142 va_end (apc);
143
144 assert (len >= 0); // shield against broken vsnprintf's
145
146 // was enough room available
147 if (ptr + len < end)
148 {
149 ptr += len;
150 return;
151 }
152 }
153
154 // longer, try harder
155 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 va_list ap;
164 va_start (ap, format);
165 vprintf (format, ap);
166 va_end (ap);
167 }
168
169 // simply return a mask with "bits" bits set
170 inline uint64
171 m (int b)
172 {
173 return (uint64 (1) << b) - 1;
174 }
175
176 // 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 const int bits = 7*8; // 7 bits per post-comma digit
186
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 }
203 else
204 {
205 // 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 }
219
220 return ptr;
221 }
222
223 void
224 dynbuf_text::add (sint32 i)
225 {
226 force (sint32_digits);
227
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 {
237 sint32 div = u / 1000000000;
238 uint32 rem = u % 1000000000;
239
240 ptr = i2a_9 (ptr, div, false);
241 ptr = i2a_9 (ptr, rem, true);
242 }
243 }
244
245 void
246 dynbuf_text::add (sint64 i)
247 {
248 force (sint64_digits);
249
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
256 // good compilers will only use multiplications here
257
258 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 {
264 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 }
270 else
271 {
272 // 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 }
287 }
288
289 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 #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