ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/include/dynbuf.h
Revision: 1.39
Committed: Wed Dec 5 19:03:26 2018 UTC (5 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.38: +1 -1 lines
Log Message:
some bugfixes

File Contents

# User Rev Content
1 root 1.11 /*
2 root 1.15 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 root 1.34 *
4 root 1.38 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 root 1.35 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 root 1.30 * Copyright (©) 2002 Mark Wedel & Crossfire Development Team
7     * Copyright (©) 1992 Frank Tore Johansen
8 root 1.34 *
9 root 1.22 * Deliantra is free software: you can redistribute it and/or modify it under
10     * the terms of the Affero GNU General Public License as published by the
11     * Free Software Foundation, either version 3 of the License, or (at your
12     * option) any later version.
13 root 1.34 *
14 root 1.12 * This program is distributed in the hope that it will be useful,
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     * GNU General Public License for more details.
18 root 1.34 *
19 root 1.22 * You should have received a copy of the Affero GNU General Public License
20     * and the GNU General Public License along with this program. If not, see
21     * <http://www.gnu.org/licenses/>.
22 root 1.34 *
23 root 1.15 * The authors can be reached via e-mail to <support@deliantra.net>
24 root 1.11 */
25    
26 root 1.1 #ifndef DYNBUF_H__
27     #define DYNBUF_H__
28    
29     #include <cstring>
30     #include <cassert>
31    
32 root 1.28 #include "compiler.h"
33 root 1.8 #include "util.h"
34 root 1.4 #include "shstr.h"
35    
36 root 1.1 // this is a "buffer" that can grow fast
37     // and is still somewhat space-efficient.
38     // unlike obstacks or other data structures,
39     // it never moves data around. basically,
40     // this is a fast strstream without the overhead.
41    
42 root 1.4 struct dynbuf
43 root 1.1 {
44 root 1.4 protected:
45 root 1.1 struct chunk
46     {
47     chunk *next;
48 root 1.5 int alloc;
49 root 1.1 int size;
50     char data[0];
51     };
52    
53 root 1.6 char *ptr, *end;
54 root 1.1 int _size;
55    
56 root 1.19 int extend, cextend;
57 root 1.1 chunk *first, *last;
58    
59 root 1.13 void reserve (int size);
60     void init (int initial); // allocate sinitial chunk
61     void free (chunk *&chain); // free chain of chunks
62 root 1.26 char *_linearise (int extra = 0);
63 root 1.13 void finalise ();
64 root 1.1
65     public:
66    
67 root 1.13 // initial - the size of the initial chunk to be allocated
68     // extend - first incremental step when buffer size exceeded
69     dynbuf (int initial = 4096, int extend = 16384)
70     : extend (extend)
71     {
72     init (initial);
73     }
74    
75     ~dynbuf ()
76     {
77     free (first);
78     }
79    
80     // resets the dynbuf, but does not free the first chunk
81     // which is either of size "initial" or the size of the last
82     // linearise
83     void clear ();
84 root 1.1
85 root 1.6 int size () const { return _size + (ptr - last->data); }
86     bool empty () const { return !size (); }
87 root 1.1
88     void linearise (void *data);
89 root 1.13 char *linearise () // does not 0-terminate(!)
90 root 1.36 {
91 root 1.13 return first->next ? _linearise () : first->data;
92     }
93 root 1.6
94     int room () const { return end - ptr; }
95 root 1.1
96 root 1.26 // make sure we have "size" extra room
97 root 1.1 char *force (int size)
98     {
99 root 1.39 if (ecb_expect_false (ptr + size > end))
100 root 1.13 reserve (size);
101 root 1.1
102 root 1.37 ecb_assume (ptr + size <= end);
103 root 1.28
104 root 1.1 return ptr;
105     }
106    
107 root 1.29 // used for force + alloc combo
108     void alloc (char *p)
109     {
110     ptr = p;
111     }
112    
113 root 1.26 // allocate size bytes and return pointer to them (caller must force())
114 root 1.10 char *falloc (int size)
115 root 1.1 {
116 root 1.10 char *res = ptr;
117 root 1.9 ptr += size;
118 root 1.1 return res;
119     }
120    
121 root 1.26 // allocate size bytes and return pointer to them
122 root 1.10 char *alloc (int size)
123     {
124     force (size);
125     return falloc (size);
126     }
127    
128 root 1.6 void fadd (char c) { *ptr++ = c; }
129 root 1.2 void fadd (unsigned char c) { fadd (char (c)); }
130 root 1.10 void fadd (const void *p, int len)
131     {
132     memcpy (falloc (len), p, len);
133     }
134 root 1.1
135     void add (const void *p, int len)
136     {
137 root 1.10 force (len);
138     fadd (p, len);
139 root 1.1 }
140    
141     void add (char c)
142     {
143 root 1.3 alloc (1)[0] = c;
144 root 1.1 }
145    
146     void add (const char *s)
147     {
148     add (s, strlen (s));
149     }
150    
151 root 1.21 void add (shstr_tmp s)
152 root 1.4 {
153     add (s.s, s.length ());
154     }
155 root 1.1
156 root 1.26 // rather inefficient
157     void splice (int offset, int olen, const char *s, int slen);
158     void splice (int offset, int olen) { splice (offset, olen, "", 0); }
159    
160 root 1.1 //TODO
161     //void add_destructive (dynbuf &buf);
162    
163     dynbuf &operator << (char c) { add (c); return *this; }
164     dynbuf &operator << (unsigned char c) { return *this << char (c); }
165     dynbuf &operator << (const char *s) { add (s); return *this; }
166 root 1.21 dynbuf &operator << (shstr_tmp s) { add (s); return *this; }
167 root 1.4 dynbuf &operator << (const std::string &s) { add (s.data(), s.size ()); return *this; }
168    
169     operator std::string ();
170     };
171    
172     struct dynbuf_text : dynbuf
173     {
174     dynbuf_text (int initial = 4096, int extend = 16384)
175     : dynbuf (initial, extend)
176     { }
177    
178     using dynbuf::add;
179     void add (sint32 i);
180     void add (sint64 i);
181    
182 root 1.16 //TODO: should optimise the case printf "(name %+d)" as it comes up extremely often
183 root 1.13
184 root 1.20 //using dynbuf::operator <<; // doesn't work, sometimes C++ just suxx
185 root 1.18 // instead we use an ugly template function
186     template<typename T>
187     dynbuf_text &operator << (T c) { *(dynbuf *)this << c; return *this; }
188    
189 root 1.16 dynbuf_text &operator << (sint16 i) { add (sint32 (i)); return *this; }
190     dynbuf_text &operator << (uint16 i) { add (sint32 (i)); return *this; }
191     dynbuf_text &operator << (sint32 i) { add (sint32 (i)); return *this; }
192     dynbuf_text &operator << (sint64 i) { add (sint64 (i)); return *this; }
193     dynbuf_text &operator << (uint32 i) { add (sint64 (i)); return *this; }
194     dynbuf_text &operator << (uint64 i) { add (sint64 (i)); return *this; }
195 root 1.13
196 root 1.37 void printf (const char *format, ...) ecb_attribute ((format (printf, 2, 3)));
197 root 1.14 void vprintf (const char *format, va_list ap);
198 root 1.13
199     void add_abilities (const char *name, uint32 abilities);
200     void add_paths (const char *name, uint32 paths);
201    
202 root 1.26 // we need to redefine, to keep the API :/
203     using dynbuf::splice;
204     void splice (int offset, int olen, const char *s)
205     {
206     dynbuf::splice (offset, olen, s, strlen (s));
207     }
208    
209 root 1.13 // returns the string, linearised and with trailing \0
210 root 1.23 operator char *();
211 root 1.1 };
212    
213     #endif
214 root 1.6