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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines