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.8 by root, Mon Apr 23 18:21:54 2007 UTC vs.
Revision 1.27 by root, Wed Nov 4 00:08:44 2009 UTC

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
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;
9 32
10 first = last = (chunk *)salloc<char> (sizeof (chunk) + initial); 33 first = last = (chunk *)salloc<char> (sizeof (chunk) + initial);
11 first->alloc = sizeof (chunk) + initial; 34 first->alloc = sizeof (chunk) + initial;
12 first->next = 0; 35 first->next = 0;
13 36
14 room = initial;
15 ptr = first->data; 37 ptr = first->data;
38 end = ptr + initial;
16} 39}
17 40
18dynbuf::~dynbuf () 41// frees a full chain and sets the pointer to zero
42void
43dynbuf::free (chunk *&chain)
19{ 44{
20 clear (); 45 while (chain)
46 {
47 chunk *next = chain->next;
48
49 sfree<char> ((char *)chain, chain->alloc);
50 chain = next;
51 }
21} 52}
22 53
23void 54void
24dynbuf::clear () 55dynbuf::clear ()
25{ 56{
26 while (first) 57 cextend = extend;
27 { 58 free (first->next);
28 chunk *next = first->next;
29 59
30 sfree<char> ((char *)first, first->alloc); 60 _size = 0;
31 first = next; 61 ptr = first->data;
32 } 62 end = ptr + first->alloc - sizeof (chunk);
63 last = first;
33} 64}
34 65
35void 66void
36dynbuf::finish () 67dynbuf::finalise ()
37{ 68{
38 // finalise current chunk 69 // finalise current chunk
39 _size += last->size = ptr - last->data; 70 _size += last->size = ptr - last->data;
40} 71}
41 72
42void 73void
43dynbuf::_reserve (int size) 74dynbuf::reserve (int size)
44{ 75{
45 finish (); 76 finalise ();
46 77
47 do 78 do
48 { 79 {
49 ext += ext >> 1; 80 cextend += cextend >> 1;
50 ext = (ext + 15) & ~15; 81 cextend = (cextend + 15) & ~15;
51 } 82 }
52 while (ext < size); 83 while (cextend < size);
53 84
54 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + ext); 85 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + cextend);
55 add->alloc = sizeof (chunk) + ext; 86 add->alloc = sizeof (chunk) + cextend;
56 add->next = 0; 87 add->next = 0;
57 88
58 last->next = add; 89 last->next = add;
59 last = add; 90 last = add;
60 91
61 room = ext;
62 ptr = last->data; 92 ptr = last->data;
93 end = ptr + cextend;
63} 94}
64 95
65void 96void
66dynbuf::linearise (void *data) 97dynbuf::linearise (void *data)
67{ 98{
68 char *p = (char *) data;
69
70 last->size = ptr - last->data; 99 last->size = ptr - last->data;
71 100
72 for (chunk * c = first; c; c = c->next) 101 for (chunk *c = first; c; c = c->next)
73 { 102 {
74 memcpy (p, c->data, c->size); 103 memcpy (data, c->data, c->size);
75 p += c->size; 104 data = (void *)(((char *)data) + c->size);
76 } 105 }
77} 106}
78 107
79char * 108char *
80dynbuf::linearise () 109dynbuf::_linearise (int extra)
81{ 110{
82 if (first->next) 111 finalise ();
83 {
84 finish ();
85 112
86 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + _size); 113 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + _size + extra);
87 add->alloc = sizeof (chunk) + _size; 114 add->alloc = sizeof (chunk) + _size;
88 add->next = 0; 115 add->next = 0;
89 116
90 linearise ((void *)add->data); 117 linearise ((void *)add->data);
91 clear (); 118 free (first);
92 119
93 first = last = add; 120 first = last = add;
94 ptr = last->data + _size; 121 ptr = last->data + _size;
122 end = ptr + extra;
95 _size = 0; 123 _size = 0;
96 room = 0;
97 }
98 124
99 return first->data; 125 return first->data;
100} 126}
101 127
102dynbuf::operator std::string () 128dynbuf::operator std::string ()
104 // could optimise 130 // could optimise
105 return std::string (linearise (), size ()); 131 return std::string (linearise (), size ());
106} 132}
107 133
108void 134void
135dynbuf::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
159void
109dynbuf_text::printf (const char *format, ...) 160dynbuf_text::vprintf (const char *format, va_list ap)
110{ 161{
111 int len; 162 int len;
112 163
113 { 164 {
114 force (128); 165 force (128);
115 166
116 va_list ap; 167 va_list apc;
117 va_start (ap, format); 168 va_copy (apc, ap);
118 len = vsnprintf (ptr, room, format, ap); 169 len = vsnprintf (ptr, end - ptr, format, apc);
119 va_end (ap); 170 va_end (apc);
120 171
121 assert (len >= 0); // shield against broken vsnprintf's 172 assert (len >= 0); // shield against broken vsnprintf's
122 173
123 // was enough room available 174 // was enough room available
124 if (len < room) 175 if (ptr + len < end)
125 { 176 {
126 alloc (len); 177 ptr += len;
127 return; 178 return;
128 } 179 }
129 } 180 }
130 181
131 // longer, try harder 182 // longer, try harder
183 vsnprintf (force (len + 1), len + 1, format, ap);
184
185 ptr += len;
186}
187
188void
189dynbuf_text::printf (const char *format, ...)
190{
132 va_list ap; 191 va_list ap;
133 va_start (ap, format); 192 va_start (ap, format);
134 vsnprintf (force (len + 1), len + 1, format, ap); 193 vprintf (format, ap);
135 va_end (ap); 194 va_end (ap);
195}
136 196
137 alloc (len); 197// simply return a mask with "bits" bits set
198inline uint64
199m (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
207inline char *
208i2a_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;
138} 249}
139 250
140void 251void
141dynbuf_text::add (sint32 i) 252dynbuf_text::add (sint32 i)
142{ 253{
143 char buf[max_sint32_size]; 254 force (sint32_digits);
144 char *p = buf + sizeof (buf);
145 char neg;
146 255
147 uint32 val; 256 *ptr = '-'; ptr += i < 0 ? 1 : 0;
257 uint32 u = i < 0 ? -i : i;
148 258
149 if (i < 0) 259 if (expect_true (u < 10)) // we have a lot of single-digit numbers, so optimise
150 { 260 fadd (char (u + '0'));
151 neg = '-'; 261 else if (expect_true (u < 1000000000)) // 9 0's
152 val = -i; 262 ptr = i2a_9 (ptr, u, false);
153 }
154 else 263 else
155 { 264 {
156 neg = 0; 265 sint32 div = u / 1000000000;
157 val = i; 266 uint32 rem = u % 1000000000;
158 }
159 267
160 do 268 ptr = i2a_9 (ptr, div, false);
269 ptr = i2a_9 (ptr, rem, true);
161 { 270 }
162 uint32 div = val / 10;
163 *--p = '0' + char (val - div * 10);
164
165 val = div;
166 }
167 while (val);
168
169 if (neg)
170 *--p = neg;
171
172 add ((void *) p, buf + sizeof (buf) - p);
173} 271}
174 272
175void 273void
176dynbuf_text::add (sint64 i) 274dynbuf_text::add (sint64 i)
177{ 275{
178 if (i > -10000000 && i < 10000000) 276 force (sint64_digits);
179 { 277
180 add (sint32 (i)); 278 *ptr = '-'; ptr += i < 0 ? 1 : 0;
181 return; 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
182 } 291 {
292 sint32 div = u / 1000000000;
293 uint32 rem = u % 1000000000;
183 294
184 char buf[max_sint64_size]; 295 ptr = i2a_9 (ptr, div, false);
185 char *p = buf + sizeof (buf); 296 ptr = i2a_9 (ptr, rem, true);
186 char neg;
187
188 uint64 val;
189
190 if (i < 0)
191 {
192 neg = '-';
193 val = -i;
194 } 297 }
195 else 298 else
196 { 299 {
197 neg = 0; 300 // a biggy
198 val = i; 301 sint32 div = u / UINT64_C (1000000000000000000);
199 } 302 uint64 rem = u % UINT64_C (1000000000000000000);
200 303
201 do 304 fadd (char (div + '0'));
305 u = rem;
306
202 { 307 {
203 uint64 div = val / 10; 308 sint32 div = u / 1000000000;
204 *--p = '0' + char (val - div * 10); 309 uint32 rem = u % 1000000000;
205 310
206 val = div; 311 ptr = i2a_9 (ptr, div, true);
312 ptr = i2a_9 (ptr, rem, true);
207 } 313 }
208 while (val); 314 }
209
210 if (neg)
211 *--p = neg;
212
213 add ((void *) p, buf + sizeof (buf) - p);
214} 315}
316
317dynbuf_text::operator char *()
318{
319 *this << '\0';
320 linearise ();
321 --ptr;
322 return first->data;
323}
324
325void
326dynbuf_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 (int i = 0; i < NROFATTACKS; ++i)
335 if (abilities & (1 << i))
336 {
337 *this << sep; sep = ", ";
338 *this << attacks [i];
339 }
340
341 *this << ')';
342}
343
344void
345dynbuf_text::add_paths (const char *name, uint32 paths)
346{
347 if (!paths)
348 return;
349
350 *this << '(' << name;
351
352 const char *sep = ": ";
353 for (int i = 0; i < NRSPELLPATHS; ++i)
354 if (paths & (1 << i))
355 {
356 *this << sep; sep = ", ";
357 *this << spellpathnames [i];
358 }
359
360 *this << ')';
361}
362
363#if 0
364struct dynbuf_test_class {
365 dynbuf_test_class ()
366 {
367 sint64 s = 0;
368 for (int i = 0; i < 10000000; ++i)
369 {
370 char b1[256], b2[256];
371
372 dynbuf_text db;
373 db.add (s);
374 db.add (char (0));
375
376 db.linearise (b1);
377 sprintf (b2, "%ld", s);
378
379 if (strcmp (b1, b2))
380 printf ("<%s,%s>\n", b1, b2);
381
382 if (i < 20)
383 s = (sint64) pow (10., i);
384 else
385 s = (sint64) exp (random () * (43.6682723752766 / RAND_MAX));
386 }
387
388 exit (0);
389 }
390} dynbuf_test;
391#endif
392

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines