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.5 by root, Sun Sep 10 15:59:57 2006 UTC vs.
Revision 1.35 by root, Tue Jan 3 11:25:36 2012 UTC

1#define __STDC_CONSTANT_MACROS 1/*
2#include <stdint.h> 2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 3 *
4#ifndef UINT64_C 4 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5# error missing c99 support, define UINT64_C yourself 5 *
6# define UINT64_C(c) c ## LL 6 * Deliantra is free software: you can redistribute it and/or modify it under
7#endif 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 */
8 22
9#include "global.h" 23#include "global.h"
10 24
11#include <cstdio> 25#include <cstdio>
12 26
13dynbuf::dynbuf (int initial, int extend) 27void
28dynbuf::init (int initial)
14{ 29{
30 cextend = extend;
15 _size = 0; 31 _size = 0;
16 ext = extend; 32
17 first = last = (chunk *) new char[sizeof (chunk) + initial]; 33 first = last = (chunk *)salloc<char> (sizeof (chunk) + initial);
18 34 first->alloc = sizeof (chunk) + initial;
19 first->next = 0; 35 first->next = 0;
20 room = initial; 36
21 ptr = first->data; 37 ptr = first->data;
38 end = ptr + initial;
22} 39}
23 40
24dynbuf::~dynbuf () 41// frees a full chain and sets the pointer to zero
42void
43dynbuf::free (chunk *&chain)
25{ 44{
26 clear (); 45 while (chain)
46 {
47 chunk *next = chain->next;
48
49 sfree<char> ((char *)chain, chain->alloc);
50 chain = next;
51 }
27} 52}
28 53
29void 54void
30dynbuf::clear () 55dynbuf::clear ()
31{ 56{
32 while (first) 57 cextend = extend;
33 { 58 free (first->next);
34 chunk *next = first->next;
35 59
36 delete[](char *) first; 60 _size = 0;
37 first = next; 61 ptr = first->data;
38 } 62 end = ptr + first->alloc - sizeof (chunk);
63 last = first;
39} 64}
40 65
41void 66void
42dynbuf::finish () 67dynbuf::finalise ()
43{ 68{
44 // finalise current chunk 69 // finalise current chunk
45 _size += last->size = ptr - last->data; 70 _size += last->size = ptr - last->data;
46} 71}
47 72
48void 73void
49dynbuf::_reserve (int size) 74dynbuf::reserve (int size)
50{ 75{
51 finish (); 76 finalise ();
52 77
53 do 78 do
54 { 79 {
55 ext += ext >> 1; 80 cextend += cextend >> 1;
56 ext = (ext + 15) & ~15; 81 cextend = (cextend + 15) & ~15;
57 } 82 }
58 while (ext < size); 83 while (cextend < size);
59 84
60 chunk *add = (chunk *) new char[sizeof (chunk) + ext]; 85 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + cextend);
61 86 add->alloc = sizeof (chunk) + cextend;
62 add->next = 0; 87 add->next = 0;
63 88
64 last->next = add; 89 last->next = add;
65 last = add; 90 last = add;
66 91
67 room = ext;
68 ptr = last->data; 92 ptr = last->data;
93 end = ptr + cextend;
69} 94}
70 95
71void 96void
72dynbuf::linearise (void *data) 97dynbuf::linearise (void *data)
73{ 98{
74 char *p = (char *) data;
75
76 last->size = ptr - last->data; 99 last->size = ptr - last->data;
77 100
78 for (chunk * c = first; c; c = c->next) 101 for (chunk *c = first; c; c = c->next)
79 { 102 {
80 memcpy (p, c->data, c->size); 103 memcpy (data, c->data, c->size);
81 p += c->size; 104 data = (void *)(((char *)data) + c->size);
82 } 105 }
83} 106}
84 107
85char * 108char *
86dynbuf::linearise () 109dynbuf::_linearise (int extra)
87{ 110{
88 if (first->next) 111 finalise ();
89 {
90 finish ();
91 112
92 chunk *add = (chunk *) new char[sizeof (chunk) + _size]; 113 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + _size + extra);
93 114 add->alloc = sizeof (chunk) + _size;
94 add->next = 0; 115 add->next = 0;
116
95 linearise ((void *) add->data); 117 linearise ((void *)add->data);
96 clear (); 118 free (first);
97 119
98 first = last = add; 120 first = last = add;
99 ptr = last->data + _size; 121 ptr = last->data + _size;
122 end = ptr + extra;
100 _size = 0; 123 _size = 0;
101 room = 0;
102 }
103 124
104 return first->data; 125 return first->data;
105} 126}
106 127
107void 128dynbuf::operator std::string ()
108dynbuf::add (sint32 i)
109{ 129{
110 char buf[max_sint32_size]; 130 // could optimise
111 char *p = buf + sizeof (buf); 131 return std::string (linearise (), size ());
112 char neg; 132}
113 133
114 uint32 val; 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;
115 139
116 if (i < 0) 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
160dynbuf_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)
117 { 176 {
118 neg = '-'; 177 ptr += len;
119 val = -i; 178 return;
179 }
180 }
181
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{
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
198static inline 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
207static inline 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';
120 } 230 }
121 else 231 else
122 { 232 {
123 neg = 0; 233 // do not output leading zeroes (except if v == 0)
124 val = i; 234 // good compilers will compile this into completely branchless code
125 } 235 char digit, nz = 0;
126 236
127 do 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;
128 { 246 }
129 uint32 div = val / 10;
130 *--p = '0' + char (val - div * 10);
131 247
132 val = div; 248 return ptr;
133 }
134 while (val);
135
136 if (neg)
137 *--p = neg;
138
139 add ((void *) p, buf + sizeof (buf) - p);
140} 249}
141 250
142void 251void
143dynbuf::add (sint64 i) 252dynbuf_text::add (sint32 i)
144{ 253{
145 if (i > -10000000 && i < 10000000) 254 force (sint32_digits);
146 { 255
147 add (sint32 (i)); 256 *ptr = '-'; ptr += i < 0 ? 1 : 0;
148 return; 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 *ptr++ = u + '0';
261 else if (expect_true (u < 100)) // we have a lot of double-digit numbers, too :)
149 } 262 {
150 263 // let the compiler figure out sth. efficient here
151 char buf[max_sint64_size]; 264 *ptr++ = u / 10 + '0';
152 char *p = buf + sizeof (buf); 265 *ptr++ = u % 10 + '0';
153 char neg;
154
155 uint64 val;
156
157 if (i < 0)
158 { 266 }
159 neg = '-'; 267 else if (expect_true (u < 1000000000)) // 9 0's
160 val = -i; 268 ptr = i2a_9 (ptr, u, false);
161 }
162 else 269 else
163 { 270 {
164 neg = 0; 271 uint32 div = u / 1000000000;
165 val = i; 272 uint32 rem = u % 1000000000;
273
274 ptr = i2a_9 (ptr, div, false);
275 ptr = i2a_9 (ptr, rem, true);
276 }
277}
278
279void
280dynbuf_text::add (sint64 i)
281{
282 force (sint64_digits);
283
284 *ptr = '-'; ptr += i < 0 ? 1 : 0;
285 uint64 u = i < 0 ? -i : i;
286
287 // split the number into a 1-digit part
288 // (#19) and two 9 digit parts (9..18 and 0..8)
289
290 // good compilers will only use multiplications here
291
292 if (u < 10) // we have a lot of single-digit numbers, so optimise
293 *ptr++ = u + '0';
294 else if (expect_true (u < 1000000000)) // 9 0's
295 ptr = i2a_9 (ptr, u, false);
296 else if (expect_true (u < UINT64_C (1000000000000000000))) // 18 0's
166 } 297 {
298 uint32 div = u / 1000000000;
299 uint32 rem = u % 1000000000;
167 300
168 do 301 ptr = i2a_9 (ptr, div, false);
302 ptr = i2a_9 (ptr, rem, true);
303 }
304 else
305 {
306 // a biggy, split off the topmost digit
307 uint32 div = u / UINT64_C (1000000000000000000);
308 uint64 rem = u % UINT64_C (1000000000000000000);
309
310 *ptr++ = div + '0';
311
312 u = rem;
313
169 { 314 {
170 uint64 div = val / 10; 315 uint32 div = u / 1000000000;
171 *--p = '0' + char (val - div * 10); 316 uint32 rem = u % 1000000000;
172 317
173 val = div; 318 ptr = i2a_9 (ptr, div, true);
319 ptr = i2a_9 (ptr, rem, true);
174 } 320 }
175 while (val); 321 }
176
177 if (neg)
178 *--p = neg;
179
180 add ((void *) p, buf + sizeof (buf) - p);
181} 322}
323
324dynbuf_text::operator char *()
325{
326 *this << '\0';
327 linearise ();
328 --ptr;
329 return first->data;
330}
331
332void
333dynbuf_text::add_abilities (const char *name, uint32 abilities)
334{
335 if (!abilities)
336 return;
337
338 *this << '(' << name;
339
340 const char *sep = ": ";
341 for_all_bits_sparse_32 (abilities, i)
342 {
343 *this << sep; sep = ", ";
344 *this << attacks [i];
345 }
346
347 *this << ')';
348}
349
350void
351dynbuf_text::add_paths (const char *name, uint32 paths)
352{
353 if (!paths)
354 return;
355
356 *this << '(' << name;
357
358 const char *sep = ": ";
359 for (int i = 0; i < NRSPELLPATHS; ++i)
360 if (paths & (1 << i))
361 {
362 *this << sep; sep = ", ";
363 *this << spellpathnames [i];
364 }
365
366 *this << ')';
367}
368
369#if 0
370struct dynbuf_test_class {
371 dynbuf_test_class ()
372 {
373 sint64 s = 0;
374 for (int i = 0; i < 10000000; ++i)
375 {
376 char b1[256], b2[256];
377
378 dynbuf_text db;
379 db.add (s);
380 db.add (char (0));
381
382 db.linearise (b1);
383 sprintf (b2, "%ld", s);
384
385 if (strcmp (b1, b2))
386 printf ("<%s,%s>\n", b1, b2);
387
388 if (i < 20)
389 s = (sint64) pow (10., i);
390 else
391 s = (sint64) exp (random () * (43.6682723752766 / RAND_MAX));
392 }
393
394 exit (0);
395 }
396} dynbuf_test;
397#endif
398

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines