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.24 by root, Mon Oct 12 14:00:59 2009 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines