MongoDB C++ Driver legacy-1.0.1
Loading...
Searching...
No Matches
builder.h
1/* builder.h */
2
3/* Copyright 2009 10gen Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#pragma once
19
20#include <cfloat>
21#include <sstream>
22#include <stdio.h>
23#include <string>
24
25#include <boost/static_assert.hpp>
26
27#include "mongo/base/data_view.h"
28#include "mongo/base/string_data.h"
29#include "mongo/bson/inline_decls.h"
30#include "mongo/util/assert_util.h"
31
32namespace mongo {
33
34 /* Note the limit here is rather arbitrary and is simply a standard. generally the code works
35 with any object that fits in ram.
36
37 Also note that the server has some basic checks to enforce this limit but those checks are not exhaustive
38 for example need to check for size too big after
39 update $push (append) operation
40 various db.eval() type operations
41 */
42 const int BSONObjMaxUserSize = 16 * 1024 * 1024;
43
44 /*
45 Sometimes we need objects slightly larger - an object in the replication local.oplog
46 is slightly larger than a user object for example.
47 */
48 const int BSONObjMaxInternalSize = BSONObjMaxUserSize + ( 16 * 1024 );
49
50 const int BufferMaxSize = 64 * 1024 * 1024;
51
52 template <typename Allocator>
53 class StringBuilderImpl;
54
56 public:
57 void* Malloc(size_t sz) { return malloc(sz); }
58 void* Realloc(void *p, size_t sz) { return realloc(p, sz); }
59 void Free(void *p) { free(p); }
60 };
61
63 public:
64 enum { SZ = 512 };
65 void* Malloc(size_t sz) {
66 if( sz <= SZ ) return buf;
67 return malloc(sz);
68 }
69 void* Realloc(void *p, size_t sz) {
70 if( p == buf ) {
71 if( sz <= SZ ) return buf;
72 void *d = malloc(sz);
73 if ( d == 0 )
74 msgasserted( 15912 , "out of memory StackAllocator::Realloc" );
75 memcpy(d, p, SZ);
76 return d;
77 }
78 return realloc(p, sz);
79 }
80 void Free(void *p) {
81 if( p != buf )
82 free(p);
83 }
84 private:
85 char buf[SZ];
86 };
87
88 template< class Allocator >
90 // non-copyable, non-assignable
91 _BufBuilder( const _BufBuilder& );
92 _BufBuilder& operator=( const _BufBuilder& );
93 Allocator al;
94 public:
95 _BufBuilder(int initsize = 512) : size(initsize) {
96 if ( size > 0 ) {
97 data = (char *) al.Malloc(size);
98 if( data == 0 )
99 msgasserted(10000, "out of memory BufBuilder");
100 }
101 else {
102 data = 0;
103 }
104 l = 0;
105 reservedBytes = 0;
106 }
107 ~_BufBuilder() { kill(); }
108
109 void kill() {
110 if ( data ) {
111 al.Free(data);
112 data = 0;
113 }
114 }
115
116 void reset() {
117 l = 0;
118 reservedBytes = 0;
119 }
120 void reset( int maxSize ) {
121 l = 0;
122 reservedBytes = 0;
123 if ( maxSize && size > maxSize ) {
124 al.Free(data);
125 data = (char*)al.Malloc(maxSize);
126 if ( data == 0 )
127 msgasserted( 15913 , "out of memory BufBuilder::reset" );
128 size = maxSize;
129 }
130 }
131
135 char* skip(int n) { return grow(n); }
136
137 /* note this may be deallocated (realloced) if you keep writing. */
138 char* buf() { return data; }
139 const char* buf() const { return data; }
140
141 /* assume ownership of the buffer - you must then free() it */
142 void decouple() { data = 0; }
143
144 void appendUChar(unsigned char j) {
145 BOOST_STATIC_ASSERT(CHAR_BIT == 8);
146 appendNumImpl(j);
147 }
148 void appendChar(char j) {
149 appendNumImpl(j);
150 }
151 void appendNum(char j) {
152 appendNumImpl(j);
153 }
154 void appendNum(short j) {
155 BOOST_STATIC_ASSERT(sizeof(short) == 2);
156 appendNumImpl(j);
157 }
158 void appendNum(int j) {
159 BOOST_STATIC_ASSERT(sizeof(int) == 4);
160 appendNumImpl(j);
161 }
162 void appendNum(unsigned j) {
163 appendNumImpl(j);
164 }
165
166 // Bool does not have a well defined encoding.
167#if __cplusplus >= 201103L
168 void appendNum(bool j) = delete;
169#else
170 void appendNum(bool j) {
171 invariant(false);
172 }
173#endif
174
175 void appendNum(double j) {
176 BOOST_STATIC_ASSERT(sizeof(double) == 8);
177 appendNumImpl(j);
178 }
179 void appendNum(long long j) {
180 BOOST_STATIC_ASSERT(sizeof(long long) == 8);
181 appendNumImpl(j);
182 }
183 void appendNum(unsigned long long j) {
184 appendNumImpl(j);
185 }
186
187 void appendBuf(const void *src, size_t len) {
188 memcpy(grow((int) len), src, len);
189 }
190
191 template<class T>
192 void appendStruct(const T& s) {
193 appendBuf(&s, sizeof(T));
194 }
195
196 void appendStr(const StringData &str , bool includeEndingNull = true ) {
197 const int len = str.size() + ( includeEndingNull ? 1 : 0 );
198 str.copyTo( grow(len), includeEndingNull );
199 }
200
202 int len() const { return l; }
203 void setlen( int newLen ) { l = newLen; }
205 int getSize() const { return size; }
206
207 /* returns the pre-grow write position */
208 inline char* grow(int by) {
209 int oldlen = l;
210 int newLen = l + by;
211 int minSize = newLen + reservedBytes;
212 if ( minSize > size ) {
213 grow_reallocate(minSize);
214 }
215 l = newLen;
216 return data + oldlen;
217 }
218
222 void reserveBytes(int bytes) {
223 int minSize = l + reservedBytes + bytes;
224 if (minSize > size)
225 grow_reallocate(minSize);
226
227 // This must happen *after* any attempt to grow.
228 reservedBytes += bytes;
229 }
230
236 void claimReservedBytes(int bytes) {
237 invariant(reservedBytes >= bytes);
238 reservedBytes -= bytes;
239 }
240
241 private:
242 template<typename T>
243 void appendNumImpl(T t) {
244 // NOTE: For now, we assume that all things written
245 // by a BufBuilder are intended for external use: either written to disk
246 // or to the wire. Since all of our encoding formats are little endian,
247 // we bake that assumption in here. This decision should be revisited soon.
248 DataView(grow(sizeof(t))).writeLE(t);
249 }
250
251
252 /* "slow" portion of 'grow()' */
253 void NOINLINE_DECL grow_reallocate(int minSize) {
254 int a = 64;
255 while (a < minSize)
256 a = a * 2;
257
258 if ( a > BufferMaxSize ) {
259 std::stringstream ss;
260 ss << "BufBuilder attempted to grow() to " << a << " bytes, past the 64MB limit.";
261 msgasserted(13548, ss.str().c_str());
262 }
263 data = (char *) al.Realloc(data, a);
264 if ( data == NULL )
265 msgasserted( 16070 , "out of memory BufBuilder::grow_reallocate" );
266 size = a;
267 }
268
269 char *data;
270 int l;
271 int size;
272 int reservedBytes; // eagerly grow_reallocate to keep this many bytes of spare room.
273
274 friend class StringBuilderImpl<Allocator>;
275 };
276
277 typedef _BufBuilder<TrivialAllocator> BufBuilder;
278
286 class StackBufBuilder : public _BufBuilder<StackAllocator> {
287 public:
288 StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) { }
289 void decouple(); // not allowed. not implemented.
290 };
291
292#if defined(_WIN32)
293#pragma push_macro("snprintf")
294#define snprintf _snprintf
295#endif
296
298 template <typename Allocator>
300 public:
301 // Sizes are determined based on the number of characters in 64-bit + the trailing '\0'
302 static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP + 1;
303 static const size_t MONGO_S32_SIZE = 12;
304 static const size_t MONGO_U32_SIZE = 11;
305 static const size_t MONGO_S64_SIZE = 23;
306 static const size_t MONGO_U64_SIZE = 22;
307 static const size_t MONGO_S16_SIZE = 7;
308 static const size_t MONGO_PTR_SIZE = 19; // Accounts for the 0x prefix
309
311
312 StringBuilderImpl& operator<<( double x ) {
313 return SBNUM( x , MONGO_DBL_SIZE , "%g" );
314 }
315 StringBuilderImpl& operator<<( int x ) {
316 return SBNUM( x , MONGO_S32_SIZE , "%d" );
317 }
318 StringBuilderImpl& operator<<( unsigned x ) {
319 return SBNUM( x , MONGO_U32_SIZE , "%u" );
320 }
321 StringBuilderImpl& operator<<( long x ) {
322 return SBNUM( x , MONGO_S64_SIZE , "%ld" );
323 }
324 StringBuilderImpl& operator<<( unsigned long x ) {
325 return SBNUM( x , MONGO_U64_SIZE , "%lu" );
326 }
327 StringBuilderImpl& operator<<( long long x ) {
328 return SBNUM( x , MONGO_S64_SIZE , "%lld" );
329 }
330 StringBuilderImpl& operator<<( unsigned long long x ) {
331 return SBNUM( x , MONGO_U64_SIZE , "%llu" );
332 }
333 StringBuilderImpl& operator<<( short x ) {
334 return SBNUM( x , MONGO_S16_SIZE , "%hd" );
335 }
336 StringBuilderImpl& operator<<(const void* x) {
337 if (sizeof(x) == 8) {
338 return SBNUM(x, MONGO_PTR_SIZE, "0x%llX");
339 }
340 else {
341 return SBNUM(x, MONGO_PTR_SIZE, "0x%lX");
342 }
343 }
344 StringBuilderImpl& operator<<( char c ) {
345 _buf.grow( 1 )[0] = c;
346 return *this;
347 }
348 StringBuilderImpl& operator<<(const char* str) {
349 return *this << StringData(str);
350 }
351 StringBuilderImpl& operator<<(const StringData& str) {
352 append(str);
353 return *this;
354 }
355
356 void appendDoubleNice( double x ) {
357 const int prev = _buf.l;
358 const int maxSize = 32;
359 char * start = _buf.grow( maxSize );
360 int z = snprintf( start , maxSize , "%.16g" , x );
361 verify( z >= 0 );
362 verify( z < maxSize );
363 _buf.l = prev + z;
364 if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ) {
365 write( ".0" , 2 );
366 }
367 }
368
369 void write( const char* buf, int len) { memcpy( _buf.grow( len ) , buf , len ); }
370
371 void append( const StringData& str ) { str.copyTo( _buf.grow( str.size() ), false ); }
372
373 void reset( int maxSize = 0 ) { _buf.reset( maxSize ); }
374
375 std::string str() const { return std::string(_buf.data, _buf.l); }
376
378 int len() const { return _buf.l; }
379
380 private:
382
383 // non-copyable, non-assignable
385 StringBuilderImpl& operator=( const StringBuilderImpl& );
386
387 template <typename T>
388 StringBuilderImpl& SBNUM(T val,int maxSize,const char *macro) {
389 int prev = _buf.l;
390 int z = snprintf( _buf.grow(maxSize) , maxSize , macro , (val) );
391 verify( z >= 0 );
392 verify( z < maxSize );
393 _buf.l = prev + z;
394 return *this;
395 }
396 };
397
398 typedef StringBuilderImpl<TrivialAllocator> StringBuilder;
399 typedef StringBuilderImpl<StackAllocator> StackStringBuilder;
400
401#if defined(_WIN32)
402#undef snprintf
403#pragma pop_macro("snprintf")
404#endif
405} // namespace mongo
Definition builder.h:62
The StackBufBuilder builds smaller datasets on the stack instead of using malloc.
Definition builder.h:286
std::stringstream deals with locale so this is a lot faster than std::stringstream for UTF8
Definition builder.h:299
int len() const
size of current string
Definition builder.h:378
Definition builder.h:55
Definition builder.h:89
void reserveBytes(int bytes)
Reserve room for some number of bytes to be claimed at a later time.
Definition builder.h:222
char * skip(int n)
leave room for some stuff later
Definition builder.h:135
int getSize() const
Definition builder.h:205
int len() const
Definition builder.h:202
void claimReservedBytes(int bytes)
Claim an earlier reservation of some number of bytes.
Definition builder.h:236
the main MongoDB namespace
Definition bulk_operation_builder.h:24