@@ -28,9 +28,9 @@ struct Outbuffer
2828{
2929 @safe :
3030
31- ubyte * buf; // the buffer itself
32- ubyte * pend; // pointer past the end of the buffer
33- private ubyte * p; // current position in buffer
31+ ubyte * buf; // the buffer itself
32+ private ubyte * pend; // pointer past the end of the buffer
33+ private ubyte * p; // current position in buffer
3434
3535 nothrow :
3636 this (size_t initialSize)
@@ -43,17 +43,16 @@ struct Outbuffer
4343 @trusted
4444 void dtor ()
4545 {
46- if ( auto slice = this .extractSlice())
47- free(slice.ptr) ;
46+ free(buf);
47+ buf = p = pend = null ;
4848 }
4949
5050 void reset ()
5151 {
5252 p = buf;
5353 }
5454
55- // Returns: A slice to the data written so far
56- extern (D ) inout (ubyte )[] opSlice (size_t from, size_t to) inout
55+ private extern (D ) inout (ubyte )[] opSlice (size_t from, size_t to) inout
5756 @trusted pure nothrow @nogc
5857 {
5958 assert (this .buf, " Attempt to dereference a null pointer" );
@@ -62,10 +61,10 @@ struct Outbuffer
6261 return this .buf[from .. to];
6362 }
6463
65- // / Ditto
64+ // Returns: A slice to the data written so far
6665 extern (D ) inout (ubyte )[] opSlice () inout @trusted pure nothrow @nogc
6766 {
68- return this .buf[0 .. this .p - this .buf ];
67+ return this .buf[0 .. length ];
6968 }
7069
7170 extern (D ) ubyte [] extractSlice() @safe pure nothrow @nogc
@@ -83,38 +82,46 @@ struct Outbuffer
8382 */
8483 void reserve (size_t nbytes)
8584 {
85+ // non-inline function for the heavy/infrequent reallocation case
86+ @trusted static void enlarge(ref Outbuffer b, size_t nbytes)
87+ {
88+ pragma (inline, false ); // do not inline slow path
89+
90+ if (b.buf is null )
91+ {
92+ // Special-case the overwhelmingly most frequent situation
93+ if (nbytes < 64 )
94+ nbytes = 64 ;
95+ b.p = b.buf = cast (ubyte * ) malloc(nbytes);
96+ b.pend = b.buf + nbytes;
97+ }
98+ else
99+ {
100+ const size_t used = b.p - b.buf;
101+ const size_t oldlen = b.pend - b.buf;
102+ // Ensure exponential growth, oldlen * 2 for small sizes, oldlen * 1.5 for big sizes
103+ const size_t minlen = oldlen + (oldlen >> (oldlen > 1024 * 64 ));
104+
105+ size_t len = used + nbytes;
106+ if (len < minlen)
107+ len = minlen;
108+ // Round up to cache line size
109+ len = (len + 63 ) & ~ 63 ;
110+
111+ b.buf = cast (ubyte * ) realloc(b.buf, len);
112+
113+ b.pend = b.buf + len;
114+ b.p = b.buf + used;
115+ }
116+ if (! b.buf)
117+ err_nomem();
118+ }
119+
86120 // Keep small so it is inlined
87121 if (pend - p < nbytes)
88- enlarge(nbytes);
122+ enlarge(this , nbytes);
89123 }
90124
91- // Reserve nbytes in buffer
92- @trusted
93- void enlarge (size_t nbytes)
94- {
95- pragma (inline, false ); // do not inline slow path
96- const size_t oldlen = pend - buf;
97- const size_t used = p - buf;
98-
99- size_t len = used + nbytes;
100- // No need to reallocate
101- if (nbytes < (pend - p))
102- return ;
103-
104- const size_t newlen = oldlen + (oldlen >> 1 ); // oldlen * 1.5
105- if (len < newlen)
106- len = newlen;
107- len = (len + 15 ) & ~ 15 ;
108-
109- buf = cast (ubyte * ) realloc(buf,len);
110- if (! buf)
111- err_nomem();
112-
113- pend = buf + len;
114- p = buf + used;
115- }
116-
117-
118125 // Write n zeros; return pointer to start of zeros
119126 @trusted
120127 void * writezeros(size_t n)
@@ -203,64 +210,24 @@ struct Outbuffer
203210 write16n(v);
204211 }
205212
206- /**
207- * Writes a 32 bit int, no reserve check.
208- */
209- @trusted
210- void write32n (int v)
211- {
212- * cast (int * )p = v;
213- p += 4 ;
214- }
215-
216213 /**
217214 * Writes a 32 bit int.
218215 */
219- void write32 (int v)
216+ @trusted void write32(int v)
220217 {
221218 reserve (4 );
222- write32n(v);
223- }
224-
225- /**
226- * Writes a 64 bit long, no reserve check
227- */
228- @trusted
229- void write64n (long v)
230- {
231- * cast (long * )p = v;
232- p += 8 ;
219+ * cast (int * )p = v;
220+ p += 4 ;
233221 }
234222
235223 /**
236224 * Writes a 64 bit long.
237225 */
238- void write64 (long v)
226+ @trusted void write64(long v)
239227 {
240228 reserve (8 );
241- write64n(v);
242- }
243-
244- /**
245- * Writes a 32 bit float.
246- */
247- @trusted
248- void writeFloat (float v)
249- {
250- reserve (float .sizeof);
251- * cast (float * )p = v;
252- p += float .sizeof;
253- }
254-
255- /**
256- * Writes a 64 bit double.
257- */
258- @trusted
259- void writeDouble (double v)
260- {
261- reserve (double .sizeof);
262- * cast (double * )p = v;
263- p += double .sizeof;
229+ * cast (long * )p = v;
230+ p += 8 ;
264231 }
265232
266233 /**
0 commit comments