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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines