ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/dynbuf.C
Revision: 1.29
Committed: Wed Nov 11 03:52:45 2009 UTC (14 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.28: +5 -6 lines
Log Message:
fix icecube thawing bug

File Contents

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