ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/dynbuf.C
(Generate patch)

Comparing deliantra/server/server/dynbuf.C (file contents):
Revision 1.6 by root, Tue Dec 26 08:54:59 2006 UTC vs.
Revision 1.17 by root, Tue Jul 10 05:51:38 2007 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines