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.40 by root, Tue May 10 11:02:56 2022 UTC

1/*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 *
7 * Deliantra is free software: you can redistribute it and/or modify it under
8 * the terms of the Affero GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the Affero GNU General Public License
18 * and the GNU General Public License along with this program. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <support@deliantra.net>
22 */
23
1#include "global.h" 24#include "global.h"
2 25
3#include <cstdio> 26#include <cstdio>
4 27
5dynbuf::dynbuf (int initial, int extend) 28void
29dynbuf::init (int initial)
6{ 30{
31 cextend = extend;
7 _size = 0; 32 _size = 0;
8 ext = extend;
9 33
10 first = last = (chunk *)salloc<char> (sizeof (chunk) + initial); 34 first = last = (chunk *)salloc<char> (sizeof (chunk) + initial);
11 first->alloc = sizeof (chunk) + initial; 35 first->alloc = sizeof (chunk) + initial;
12 first->next = 0; 36 first->next = 0;
13 37
14 room = initial;
15 ptr = first->data; 38 ptr = first->data;
39 end = ptr + initial;
16} 40}
17 41
18dynbuf::~dynbuf () 42// frees a full chain and sets the pointer to zero
43void
44dynbuf::free (chunk *&chain)
19{ 45{
20 clear (); 46 while (chain)
47 {
48 chunk *next = chain->next;
49
50 sfree<char> ((char *)chain, chain->alloc);
51 chain = next;
52 }
21} 53}
22 54
23void 55void
24dynbuf::clear () 56dynbuf::clear ()
25{ 57{
26 while (first) 58 cextend = extend;
27 { 59 free (first->next);
28 chunk *next = first->next;
29 60
30 sfree<char> ((char *)first, first->alloc); 61 _size = 0;
31 first = next; 62 ptr = first->data;
32 } 63 end = ptr + first->alloc - sizeof (chunk);
64 last = first;
33} 65}
34 66
35void 67void
36dynbuf::finish () 68dynbuf::finalise ()
37{ 69{
38 // finalise current chunk 70 // finalise current chunk
39 _size += last->size = ptr - last->data; 71 _size += last->size = ptr - last->data;
40} 72}
41 73
42void 74void
43dynbuf::_reserve (int size) 75dynbuf::reserve (int size)
44{ 76{
45 finish (); 77 finalise ();
46 78
47 do 79 do
48 { 80 {
49 ext += ext >> 1; 81 cextend += cextend >> 1;
50 ext = (ext + 15) & ~15; 82 cextend = (cextend + 15) & ~15;
51 } 83 }
52 while (ext < size); 84 while (cextend < size);
53 85
54 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + ext); 86 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + cextend);
55 add->alloc = sizeof (chunk) + ext; 87 add->alloc = sizeof (chunk) + cextend;
56 add->next = 0; 88 add->next = 0;
57 89
58 last->next = add; 90 last->next = add;
59 last = add; 91 last = add;
60 92
61 room = ext;
62 ptr = last->data; 93 ptr = last->data;
94 end = ptr + cextend;
63} 95}
64 96
65void 97void
66dynbuf::linearise (void *data) 98dynbuf::linearise (void *data)
67{ 99{
68 char *p = (char *) data;
69
70 last->size = ptr - last->data; 100 last->size = ptr - last->data;
71 101
72 for (chunk * c = first; c; c = c->next) 102 for (chunk *c = first; c; c = c->next)
73 { 103 {
74 memcpy (p, c->data, c->size); 104 memcpy (data, c->data, c->size);
75 p += c->size; 105 data = (void *)(((char *)data) + c->size);
76 } 106 }
77} 107}
78 108
79char * 109char *
80dynbuf::linearise () 110dynbuf::_linearise (int extra)
81{ 111{
82 if (first->next) 112 finalise ();
83 {
84 finish ();
85 113
86 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + _size); 114 chunk *add = (chunk *) salloc<char> (sizeof (chunk) + _size + extra);
87 add->alloc = sizeof (chunk) + _size; 115 add->alloc = sizeof (chunk) + _size;
88 add->next = 0; 116 add->next = 0;
89 117
90 linearise ((void *)add->data); 118 linearise ((void *)add->data);
91 clear (); 119 free (first);
92 120
93 first = last = add; 121 first = last = add;
94 ptr = last->data + _size; 122 ptr = last->data + _size;
123 end = ptr + extra;
95 _size = 0; 124 _size = 0;
96 room = 0;
97 }
98 125
99 return first->data; 126 return first->data;
100} 127}
101 128
102dynbuf::operator std::string () 129dynbuf::operator std::string ()
104 // could optimise 131 // could optimise
105 return std::string (linearise (), size ()); 132 return std::string (linearise (), size ());
106} 133}
107 134
108void 135void
136dynbuf::splice (int offset, int olen, const char *s, int slen)
137{
138 // how much bytes to extend (negative if shrinking)
139 int adjust = slen - olen;
140
141 // linearise, unless everything fits in the last chunk
142 if (offset < _size || room () < adjust)
143 _linearise (max (adjust, 0));
144
145 offset -= _size; // offset into chunk
146
147 // now move tail to final position
148 char *pos = last->data + offset;
149 char *src = pos + olen;
150 char *dst = pos + slen;
151 memmove (dst, src, ptr - src);
152
153 // now copy new content
154 memcpy (pos, s, slen);
155
156 // finally adjust length
157 ptr += adjust;
158}
159
160void
109dynbuf_text::printf (const char *format, ...) 161dynbuf_text::vprintf (const char *format, va_list ap)
110{ 162{
111 int len; 163 int len;
112 164
113 { 165 {
114 force (128); 166 force (128);
115 167
116 va_list ap; 168 va_list apc;
117 va_start (ap, format); 169 va_copy (apc, ap);
118 len = vsnprintf (ptr, room, format, ap); 170 len = vsnprintf (ptr, end - ptr, format, apc);
119 va_end (ap); 171 va_end (apc);
120 172
121 assert (len >= 0); // shield against broken vsnprintf's 173 assert (len >= 0); // shield against broken vsnprintf's
122 174
123 // was enough room available 175 // was enough room available
124 if (len < room) 176 if (ptr + len < end)
125 { 177 {
126 alloc (len); 178 ptr += len;
127 return; 179 return;
128 } 180 }
129 } 181 }
130 182
131 // longer, try harder 183 // longer, try harder
184 vsnprintf (force (len + 1), len + 1, format, ap);
185
186 ptr += len;
187}
188
189void
190dynbuf_text::printf (const char *format, ...)
191{
132 va_list ap; 192 va_list ap;
133 va_start (ap, format); 193 va_start (ap, format);
134 vsnprintf (force (len + 1), len + 1, format, ap); 194 vprintf (format, ap);
135 va_end (ap); 195 va_end (ap);
196}
136 197
137 alloc (len); 198// simply return a mask with "bits" bits set
199static inline uint64
200m (int b)
201{
202 return (uint64 (1) << b) - 1;
203}
204
205// convert 9 digits to ascii, using only a single multiplication
206// (depending on cpu and compiler).
207// will generate a single 0 as output when v=lz=0
208static inline char *
209i2a_9 (char *ptr, uint32 v, bool lz)
210{
211 // convert to 4.56 fixed-point representation
212 // this should be optimal on 64 bit cpus, and rather
213 // slow on 32 bit cpus. go figure :)
214 // 56 bit is good up to 1160869954, 60 is good up to 2932500666 (> 2**31)
215 // that emans we can do signed 32 in one go, but we are too lazy
216 const int bits = 7*8;
217
218 uint64 u = v * ((m (bits) + 100000000) / 100000000); // 10**8
219
220 if (lz)
221 {
222 // output leading zeros
223 // good compilers will compile this into only shifts, masks and adds
224 *ptr++ = char (u >> (bits - 0)) + '0'; u = (u & m (bits - 0)) * 5;
225 *ptr++ = char (u >> (bits - 1)) + '0'; u = (u & m (bits - 1)) * 5;
226 *ptr++ = char (u >> (bits - 2)) + '0'; u = (u & m (bits - 2)) * 5;
227 *ptr++ = char (u >> (bits - 3)) + '0'; u = (u & m (bits - 3)) * 5;
228 *ptr++ = char (u >> (bits - 4)) + '0'; u = (u & m (bits - 4)) * 5;
229 *ptr++ = char (u >> (bits - 5)) + '0'; u = (u & m (bits - 5)) * 5;
230 *ptr++ = char (u >> (bits - 6)) + '0'; u = (u & m (bits - 6)) * 5;
231 *ptr++ = char (u >> (bits - 7)) + '0'; u = (u & m (bits - 7)) * 5;
232 *ptr++ = char (u >> (bits - 8)) + '0';
233 }
234 else
235 {
236 // do not output leading zeroes (except if v == 0)
237 // good compilers will compile this into completely branchless code
238 char digit, nz = 0;
239
240 digit = (u >> (bits - 0)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 0)) * 5;
241 digit = (u >> (bits - 1)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 1)) * 5;
242 digit = (u >> (bits - 2)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 2)) * 5;
243 digit = (u >> (bits - 3)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 3)) * 5;
244 digit = (u >> (bits - 4)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 4)) * 5;
245 digit = (u >> (bits - 5)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 5)) * 5;
246 digit = (u >> (bits - 6)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 6)) * 5;
247 digit = (u >> (bits - 7)); *ptr = digit + '0'; nz |= digit; ptr += nz ? 1 : 0; u = (u & m (bits - 7)) * 5;
248 digit = (u >> (bits - 8)); *ptr = digit + '0'; nz |= digit; ptr += 1;
249 }
250
251 return ptr;
138} 252}
139 253
140void 254void
141dynbuf_text::add (sint32 i) 255dynbuf_text::add (sint32 i)
142{ 256{
143 char buf[max_sint32_size]; 257 force (sint32_digits);
144 char *p = buf + sizeof (buf);
145 char neg;
146 258
147 uint32 val; 259 *ptr = '-'; ptr += i < 0 ? 1 : 0;
260 uint32 u = i < 0 ? -i : i;
148 261
149 if (i < 0) 262 if (ecb_expect_true (u < 10)) // we have a lot of single-digit numbers, so optimise
150 { 263 *ptr++ = u + '0';
151 neg = '-'; 264 else if (ecb_expect_true (u < 100)) // we have a lot of double-digit numbers, too :)
152 val = -i;
153 } 265 {
266 // let the compiler figure out sth. efficient here
267 *ptr++ = u / 10 + '0';
268 *ptr++ = u % 10 + '0';
269 }
270 else if (ecb_expect_true (u < 1000000000)) // 9 0's
271 ptr = i2a_9 (ptr, u, false);
154 else 272 else
155 { 273 {
156 neg = 0;
157 val = i;
158 }
159
160 do
161 {
162 uint32 div = val / 10; 274 uint32 div = u / 1000000000;
163 *--p = '0' + char (val - div * 10); 275 uint32 rem = u % 1000000000;
164 276
165 val = div; 277 ptr = i2a_9 (ptr, div, false);
278 ptr = i2a_9 (ptr, rem, true);
166 } 279 }
167 while (val);
168
169 if (neg)
170 *--p = neg;
171
172 add ((void *) p, buf + sizeof (buf) - p);
173} 280}
174 281
175void 282void
176dynbuf_text::add (sint64 i) 283dynbuf_text::add (sint64 i)
177{ 284{
178 if (i > -10000000 && i < 10000000) 285 force (sint64_digits);
179 { 286
180 add (sint32 (i)); 287 *ptr = '-'; ptr += i < 0 ? 1 : 0;
181 return; 288 uint64 u = i < 0 ? -i : i;
289
290 // split the number into a 1-digit part
291 // (#19) and two 9 digit parts (9..18 and 0..8)
292
293 // good compilers will only use multiplications here
294
295 if (u < 10) // we have a lot of single-digit numbers, so optimise
296 *ptr++ = u + '0';
297 else if (ecb_expect_true (u < 1000000000)) // 9 0's
298 ptr = i2a_9 (ptr, u, false);
299 else if (ecb_expect_true (u < UINT64_C (1000000000000000000))) // 18 0's
182 } 300 {
301 uint32 div = u / 1000000000;
302 uint32 rem = u % 1000000000;
183 303
184 char buf[max_sint64_size]; 304 ptr = i2a_9 (ptr, div, false);
185 char *p = buf + sizeof (buf); 305 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 } 306 }
195 else 307 else
196 { 308 {
197 neg = 0; 309 // a biggy, split off the topmost digit
198 val = i; 310 uint32 div = u / UINT64_C (1000000000000000000);
199 } 311 uint64 rem = u % UINT64_C (1000000000000000000);
200 312
201 do 313 *ptr++ = div + '0';
314
315 u = rem;
316
202 { 317 {
203 uint64 div = val / 10; 318 uint32 div = u / 1000000000;
204 *--p = '0' + char (val - div * 10); 319 uint32 rem = u % 1000000000;
205 320
206 val = div; 321 ptr = i2a_9 (ptr, div, true);
322 ptr = i2a_9 (ptr, rem, true);
207 } 323 }
208 while (val); 324 }
209
210 if (neg)
211 *--p = neg;
212
213 add ((void *) p, buf + sizeof (buf) - p);
214} 325}
326
327dynbuf_text::operator char *()
328{
329 *this << '\0';
330 linearise ();
331 --ptr;
332 return first->data;
333}
334
335void
336dynbuf_text::add_abilities (const char *name, uint32 abilities)
337{
338 if (!abilities)
339 return;
340
341 *this << '(' << name;
342
343 const char *sep = ": ";
344 for_all_bits_sparse_32 (abilities, i)
345 {
346 *this << sep; sep = ", ";
347 *this << attacks [i];
348 }
349
350 *this << ')';
351}
352
353void
354dynbuf_text::add_paths (const char *name, uint32 paths)
355{
356 if (!paths)
357 return;
358
359 *this << '(' << name;
360
361 const char *sep = ": ";
362 for (int i = 0; i < NRSPELLPATHS; ++i)
363 if (paths & (1 << i))
364 {
365 *this << sep; sep = ", ";
366 *this << spellpathnames [i];
367 }
368
369 *this << ')';
370}
371
372#if 0
373struct dynbuf_test_class {
374 dynbuf_test_class ()
375 {
376 sint64 s = 0;
377 for (int i = 0; i < 10000000; ++i)
378 {
379 char b1[256], b2[256];
380
381 dynbuf_text db;
382 db.add (s);
383 db.add (char (0));
384
385 db.linearise (b1);
386 sprintf (b2, "%ld", s);
387
388 if (strcmp (b1, b2))
389 printf ("<%s,%s>\n", b1, b2);
390
391 if (i < 20)
392 s = (sint64) pow (10., i);
393 else
394 s = (sint64) exp (random () * (43.6682723752766 / RAND_MAX));
395 }
396
397 exit (0);
398 }
399} dynbuf_test;
400#endif
401

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines