MongoDB C++ Driver legacy-1.0.0
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 }
106 ~_BufBuilder() { kill(); }
107
108 void kill() {
109 if ( data ) {
110 al.Free(data);
111 data = 0;
112 }
113 }
114
115 void reset() {
116 l = 0;
117 }
118 void reset( int maxSize ) {
119 l = 0;
120 if ( maxSize && size > maxSize ) {
121 al.Free(data);
122 data = (char*)al.Malloc(maxSize);
123 if ( data == 0 )
124 msgasserted( 15913 , "out of memory BufBuilder::reset" );
125 size = maxSize;
126 }
127 }
128
132 char* skip(int n) { return grow(n); }
133
134 /* note this may be deallocated (realloced) if you keep writing. */
135 char* buf() { return data; }
136 const char* buf() const { return data; }
137
138 /* assume ownership of the buffer - you must then free() it */
139 void decouple() { data = 0; }
140
141 void appendUChar(unsigned char j) {
142 BOOST_STATIC_ASSERT(CHAR_BIT == 8);
143 appendNumImpl(j);
144 }
145 void appendChar(char j) {
146 appendNumImpl(j);
147 }
148 void appendNum(char j) {
149 appendNumImpl(j);
150 }
151 void appendNum(short j) {
152 BOOST_STATIC_ASSERT(sizeof(short) == 2);
153 appendNumImpl(j);
154 }
155 void appendNum(int j) {
156 BOOST_STATIC_ASSERT(sizeof(int) == 4);
157 appendNumImpl(j);
158 }
159 void appendNum(unsigned j) {
160 appendNumImpl(j);
161 }
162
163 // Bool does not have a well defined encoding.
164#if __cplusplus >= 201103L
165 void appendNum(bool j) = delete;
166#else
167 void appendNum(bool j) {
168 invariant(false);
169 }
170#endif
171
172 void appendNum(double j) {
173 BOOST_STATIC_ASSERT(sizeof(double) == 8);
174 appendNumImpl(j);
175 }
176 void appendNum(long long j) {
177 BOOST_STATIC_ASSERT(sizeof(long long) == 8);
178 appendNumImpl(j);
179 }
180 void appendNum(unsigned long long j) {
181 appendNumImpl(j);
182 }
183
184 void appendBuf(const void *src, size_t len) {
185 memcpy(grow((int) len), src, len);
186 }
187
188 template<class T>
189 void appendStruct(const T& s) {
190 appendBuf(&s, sizeof(T));
191 }
192
193 void appendStr(const StringData &str , bool includeEndingNull = true ) {
194 const int len = str.size() + ( includeEndingNull ? 1 : 0 );
195 str.copyTo( grow(len), includeEndingNull );
196 }
197
199 int len() const { return l; }
200 void setlen( int newLen ) { l = newLen; }
202 int getSize() const { return size; }
203
204 /* returns the pre-grow write position */
205 inline char* grow(int by) {
206 int oldlen = l;
207 int newLen = l + by;
208 if ( newLen > size ) {
209 grow_reallocate(newLen);
210 }
211 l = newLen;
212 return data + oldlen;
213 }
214
215 private:
216 template<typename T>
217 void appendNumImpl(T t) {
218 // NOTE: For now, we assume that all things written
219 // by a BufBuilder are intended for external use: either written to disk
220 // or to the wire. Since all of our encoding formats are little endian,
221 // we bake that assumption in here. This decision should be revisited soon.
222 DataView(grow(sizeof(t))).writeLE(t);
223 }
224
225
226 /* "slow" portion of 'grow()' */
227 void NOINLINE_DECL grow_reallocate(int newLen) {
228 int a = 64;
229 while( a < newLen )
230 a = a * 2;
231 if ( a > BufferMaxSize ) {
232 std::stringstream ss;
233 ss << "BufBuilder attempted to grow() to " << a << " bytes, past the 64MB limit.";
234 msgasserted(13548, ss.str().c_str());
235 }
236 data = (char *) al.Realloc(data, a);
237 if ( data == NULL )
238 msgasserted( 16070 , "out of memory BufBuilder::grow_reallocate" );
239 size = a;
240 }
241
242 char *data;
243 int l;
244 int size;
245
246 friend class StringBuilderImpl<Allocator>;
247 };
248
249 typedef _BufBuilder<TrivialAllocator> BufBuilder;
250
258 class StackBufBuilder : public _BufBuilder<StackAllocator> {
259 public:
260 StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) { }
261 void decouple(); // not allowed. not implemented.
262 };
263
264#if defined(_WIN32)
265#pragma push_macro("snprintf")
266#define snprintf _snprintf
267#endif
268
270 template <typename Allocator>
272 public:
273 // Sizes are determined based on the number of characters in 64-bit + the trailing '\0'
274 static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP + 1;
275 static const size_t MONGO_S32_SIZE = 12;
276 static const size_t MONGO_U32_SIZE = 11;
277 static const size_t MONGO_S64_SIZE = 23;
278 static const size_t MONGO_U64_SIZE = 22;
279 static const size_t MONGO_S16_SIZE = 7;
280 static const size_t MONGO_PTR_SIZE = 19; // Accounts for the 0x prefix
281
283
284 StringBuilderImpl& operator<<( double x ) {
285 return SBNUM( x , MONGO_DBL_SIZE , "%g" );
286 }
287 StringBuilderImpl& operator<<( int x ) {
288 return SBNUM( x , MONGO_S32_SIZE , "%d" );
289 }
290 StringBuilderImpl& operator<<( unsigned x ) {
291 return SBNUM( x , MONGO_U32_SIZE , "%u" );
292 }
293 StringBuilderImpl& operator<<( long x ) {
294 return SBNUM( x , MONGO_S64_SIZE , "%ld" );
295 }
296 StringBuilderImpl& operator<<( unsigned long x ) {
297 return SBNUM( x , MONGO_U64_SIZE , "%lu" );
298 }
299 StringBuilderImpl& operator<<( long long x ) {
300 return SBNUM( x , MONGO_S64_SIZE , "%lld" );
301 }
302 StringBuilderImpl& operator<<( unsigned long long x ) {
303 return SBNUM( x , MONGO_U64_SIZE , "%llu" );
304 }
305 StringBuilderImpl& operator<<( short x ) {
306 return SBNUM( x , MONGO_S16_SIZE , "%hd" );
307 }
308 StringBuilderImpl& operator<<(const void* x) {
309 if (sizeof(x) == 8) {
310 return SBNUM(x, MONGO_PTR_SIZE, "0x%llX");
311 }
312 else {
313 return SBNUM(x, MONGO_PTR_SIZE, "0x%lX");
314 }
315 }
316 StringBuilderImpl& operator<<( char c ) {
317 _buf.grow( 1 )[0] = c;
318 return *this;
319 }
320 StringBuilderImpl& operator<<(const char* str) {
321 return *this << StringData(str);
322 }
323 StringBuilderImpl& operator<<(const StringData& str) {
324 append(str);
325 return *this;
326 }
327
328 void appendDoubleNice( double x ) {
329 const int prev = _buf.l;
330 const int maxSize = 32;
331 char * start = _buf.grow( maxSize );
332 int z = snprintf( start , maxSize , "%.16g" , x );
333 verify( z >= 0 );
334 verify( z < maxSize );
335 _buf.l = prev + z;
336 if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ) {
337 write( ".0" , 2 );
338 }
339 }
340
341 void write( const char* buf, int len) { memcpy( _buf.grow( len ) , buf , len ); }
342
343 void append( const StringData& str ) { str.copyTo( _buf.grow( str.size() ), false ); }
344
345 void reset( int maxSize = 0 ) { _buf.reset( maxSize ); }
346
347 std::string str() const { return std::string(_buf.data, _buf.l); }
348
350 int len() const { return _buf.l; }
351
352 private:
354
355 // non-copyable, non-assignable
357 StringBuilderImpl& operator=( const StringBuilderImpl& );
358
359 template <typename T>
360 StringBuilderImpl& SBNUM(T val,int maxSize,const char *macro) {
361 int prev = _buf.l;
362 int z = snprintf( _buf.grow(maxSize) , maxSize , macro , (val) );
363 verify( z >= 0 );
364 verify( z < maxSize );
365 _buf.l = prev + z;
366 return *this;
367 }
368 };
369
370 typedef StringBuilderImpl<TrivialAllocator> StringBuilder;
371 typedef StringBuilderImpl<StackAllocator> StackStringBuilder;
372
373#if defined(_WIN32)
374#undef snprintf
375#pragma pop_macro("snprintf")
376#endif
377} // namespace mongo
Definition builder.h:62
The StackBufBuilder builds smaller datasets on the stack instead of using malloc.
Definition builder.h:258
std::stringstream deals with locale so this is a lot faster than std::stringstream for UTF8
Definition builder.h:271
int len() const
size of current string
Definition builder.h:350
Definition builder.h:55
Definition builder.h:89
char * skip(int n)
leave room for some stuff later
Definition builder.h:132
int getSize() const
Definition builder.h:202
int len() const
Definition builder.h:199
the main MongoDB namespace
Definition bulk_operation_builder.h:24