MongoDB C++ Driver legacy-1.1.2
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
38 exhaustive for example need to check for size too big after
39 update $push (append) operation
40 various db.eval() type operations
41*/
42const 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*/
48const int BSONObjMaxInternalSize = BSONObjMaxUserSize + (16 * 1024);
49
50const int BufferMaxSize = 64 * 1024 * 1024;
51
52template <typename Allocator>
53class StringBuilderImpl;
54
56public:
57 void* Malloc(size_t sz) {
58 return malloc(sz);
59 }
60 void* Realloc(void* p, size_t sz) {
61 return realloc(p, sz);
62 }
63 void Free(void* p) {
64 free(p);
65 }
66};
67
69public:
70 enum { SZ = 512 };
71 void* Malloc(size_t sz) {
72 if (sz <= SZ)
73 return buf;
74 return malloc(sz);
75 }
76 void* Realloc(void* p, size_t sz) {
77 if (p == buf) {
78 if (sz <= SZ)
79 return buf;
80 void* d = malloc(sz);
81 if (d == 0)
82 msgasserted(15912, "out of memory StackAllocator::Realloc");
83 memcpy(d, p, SZ);
84 return d;
85 }
86 return realloc(p, sz);
87 }
88 void Free(void* p) {
89 if (p != buf)
90 free(p);
91 }
92
93private:
94 char buf[SZ];
95};
96
97template <class Allocator>
99 // non-copyable, non-assignable
100 _BufBuilder(const _BufBuilder&);
101 _BufBuilder& operator=(const _BufBuilder&);
102 Allocator al;
103
104public:
105 _BufBuilder(int initsize = 512) : size(initsize) {
106 if (size > 0) {
107 data = (char*)al.Malloc(size);
108 if (data == 0)
109 msgasserted(10000, "out of memory BufBuilder");
110 } else {
111 data = 0;
112 }
113 l = 0;
114 reservedBytes = 0;
115 }
116 ~_BufBuilder() {
117 kill();
118 }
119
120 void kill() {
121 if (data) {
122 al.Free(data);
123 data = 0;
124 }
125 }
126
127 void reset() {
128 l = 0;
129 reservedBytes = 0;
130 }
131 void reset(int maxSize) {
132 l = 0;
133 reservedBytes = 0;
134 if (maxSize && size > maxSize) {
135 al.Free(data);
136 data = (char*)al.Malloc(maxSize);
137 if (data == 0)
138 msgasserted(15913, "out of memory BufBuilder::reset");
139 size = maxSize;
140 }
141 }
142
147 char* skip(int n) {
148 return grow(n);
149 }
150
151 /* note this may be deallocated (realloced) if you keep writing. */
152 char* buf() {
153 return data;
154 }
155 const char* buf() const {
156 return data;
157 }
158
159 /* assume ownership of the buffer - you must then free() it */
160 void decouple() {
161 data = 0;
162 }
163
164 void appendUChar(unsigned char j) {
165 BOOST_STATIC_ASSERT(CHAR_BIT == 8);
166 appendNumImpl(j);
167 }
168 void appendChar(char j) {
169 appendNumImpl(j);
170 }
171 void appendNum(char j) {
172 appendNumImpl(j);
173 }
174 void appendNum(short j) {
175 BOOST_STATIC_ASSERT(sizeof(short) == 2);
176 appendNumImpl(j);
177 }
178 void appendNum(int j) {
179 BOOST_STATIC_ASSERT(sizeof(int) == 4);
180 appendNumImpl(j);
181 }
182 void appendNum(unsigned j) {
183 appendNumImpl(j);
184 }
185
186// Bool does not have a well defined encoding.
187#if __cplusplus >= 201103L
188 void appendNum(bool j) = delete;
189#else
190 void appendNum(bool j) {
191 invariant(false);
192 }
193#endif
194
195 void appendNum(double j) {
196 BOOST_STATIC_ASSERT(sizeof(double) == 8);
197 appendNumImpl(j);
198 }
199 void appendNum(long long j) {
200 BOOST_STATIC_ASSERT(sizeof(long long) == 8);
201 appendNumImpl(j);
202 }
203 void appendNum(unsigned long long j) {
204 appendNumImpl(j);
205 }
206
207 void appendBuf(const void* src, size_t len) {
208 memcpy(grow((int)len), src, len);
209 }
210
211 template <class T>
212 void appendStruct(const T& s) {
213 appendBuf(&s, sizeof(T));
214 }
215
216 void appendStr(const StringData& str, bool includeEndingNull = true) {
217 const int len = str.size() + (includeEndingNull ? 1 : 0);
218 str.copyTo(grow(len), includeEndingNull);
219 }
220
222 int len() const {
223 return l;
224 }
225 void setlen(int newLen) {
226 l = newLen;
227 }
229 int getSize() const {
230 return size;
231 }
232
233 /* returns the pre-grow write position */
234 inline char* grow(int by) {
235 int oldlen = l;
236 int newLen = l + by;
237 int minSize = newLen + reservedBytes;
238 if (minSize > size) {
239 grow_reallocate(minSize);
240 }
241 l = newLen;
242 return data + oldlen;
243 }
244
248 void reserveBytes(int bytes) {
249 int minSize = l + reservedBytes + bytes;
250 if (minSize > size)
251 grow_reallocate(minSize);
252
253 // This must happen *after* any attempt to grow.
254 reservedBytes += bytes;
255 }
256
262 void claimReservedBytes(int bytes) {
263 invariant(reservedBytes >= bytes);
264 reservedBytes -= bytes;
265 }
266
267private:
268 template <typename T>
269 void appendNumImpl(T t) {
270 // NOTE: For now, we assume that all things written
271 // by a BufBuilder are intended for external use: either written to disk
272 // or to the wire. Since all of our encoding formats are little endian,
273 // we bake that assumption in here. This decision should be revisited soon.
274 DataView(grow(sizeof(t))).writeLE(t);
275 }
276
277
278 /* "slow" portion of 'grow()' */
279 void NOINLINE_DECL grow_reallocate(int minSize) {
280 int a = 64;
281 while (a < minSize)
282 a = a * 2;
283
284 if (a > BufferMaxSize) {
285 std::stringstream ss;
286 ss << "BufBuilder attempted to grow() to " << a << " bytes, past the 64MB limit.";
287 msgasserted(13548, ss.str().c_str());
288 }
289 data = (char*)al.Realloc(data, a);
290 if (data == NULL)
291 msgasserted(16070, "out of memory BufBuilder::grow_reallocate");
292 size = a;
293 }
294
295 char* data;
296 int l;
297 int size;
298 int reservedBytes; // eagerly grow_reallocate to keep this many bytes of spare room.
299
300 friend class StringBuilderImpl<Allocator>;
301};
302
303typedef _BufBuilder<TrivialAllocator> BufBuilder;
304
312class StackBufBuilder : public _BufBuilder<StackAllocator> {
313public:
314 StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) {}
315 void decouple(); // not allowed. not implemented.
316};
317
318#if defined(_WIN32)
319#pragma push_macro("snprintf")
320#define snprintf _snprintf
321#endif
322
324template <typename Allocator>
326public:
327 // Sizes are determined based on the number of characters in 64-bit + the trailing '\0'
328 static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP + 1;
329 static const size_t MONGO_S32_SIZE = 12;
330 static const size_t MONGO_U32_SIZE = 11;
331 static const size_t MONGO_S64_SIZE = 23;
332 static const size_t MONGO_U64_SIZE = 22;
333 static const size_t MONGO_S16_SIZE = 7;
334 static const size_t MONGO_PTR_SIZE = 19; // Accounts for the 0x prefix
335
337
338 StringBuilderImpl& operator<<(double x) {
339 return SBNUM(x, MONGO_DBL_SIZE, "%g");
340 }
341 StringBuilderImpl& operator<<(int x) {
342 return SBNUM(x, MONGO_S32_SIZE, "%d");
343 }
344 StringBuilderImpl& operator<<(unsigned x) {
345 return SBNUM(x, MONGO_U32_SIZE, "%u");
346 }
347 StringBuilderImpl& operator<<(long x) {
348 return SBNUM(x, MONGO_S64_SIZE, "%ld");
349 }
350 StringBuilderImpl& operator<<(unsigned long x) {
351 return SBNUM(x, MONGO_U64_SIZE, "%lu");
352 }
353 StringBuilderImpl& operator<<(long long x) {
354 return SBNUM(x, MONGO_S64_SIZE, "%lld");
355 }
356 StringBuilderImpl& operator<<(unsigned long long x) {
357 return SBNUM(x, MONGO_U64_SIZE, "%llu");
358 }
359 StringBuilderImpl& operator<<(short x) {
360 return SBNUM(x, MONGO_S16_SIZE, "%hd");
361 }
362 StringBuilderImpl& operator<<(const void* x) {
363 if (sizeof(x) == 8) {
364 return SBNUM(x, MONGO_PTR_SIZE, "0x%llX");
365 } else {
366 return SBNUM(x, MONGO_PTR_SIZE, "0x%lX");
367 }
368 }
369 StringBuilderImpl& operator<<(char c) {
370 _buf.grow(1)[0] = c;
371 return *this;
372 }
373 StringBuilderImpl& operator<<(const char* str) {
374 return *this << StringData(str);
375 }
376 StringBuilderImpl& operator<<(const StringData& str) {
377 append(str);
378 return *this;
379 }
380
381 void appendDoubleNice(double x) {
382 const int prev = _buf.l;
383 const int maxSize = 32;
384 char* start = _buf.grow(maxSize);
385 int z = snprintf(start, maxSize, "%.16g", x);
386 verify(z >= 0);
387 verify(z < maxSize);
388 _buf.l = prev + z;
389 if (strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0) {
390 write(".0", 2);
391 }
392 }
393
394 void write(const char* buf, int len) {
395 memcpy(_buf.grow(len), buf, len);
396 }
397
398 void append(const StringData& str) {
399 str.copyTo(_buf.grow(str.size()), false);
400 }
401
402 void reset(int maxSize = 0) {
403 _buf.reset(maxSize);
404 }
405
406 std::string str() const {
407 return std::string(_buf.data, _buf.l);
408 }
409
411 int len() const {
412 return _buf.l;
413 }
414
415private:
417
418 // non-copyable, non-assignable
420 StringBuilderImpl& operator=(const StringBuilderImpl&);
421
422 template <typename T>
423 StringBuilderImpl& SBNUM(T val, int maxSize, const char* macro) {
424 int prev = _buf.l;
425 int z = snprintf(_buf.grow(maxSize), maxSize, macro, (val));
426 verify(z >= 0);
427 verify(z < maxSize);
428 _buf.l = prev + z;
429 return *this;
430 }
431};
432
433typedef StringBuilderImpl<TrivialAllocator> StringBuilder;
434typedef StringBuilderImpl<StackAllocator> StackStringBuilder;
435
436#if defined(_WIN32)
437#undef snprintf
438#pragma pop_macro("snprintf")
439#endif
440} // namespace mongo
Definition data_view.h:71
Definition builder.h:68
The StackBufBuilder builds smaller datasets on the stack instead of using malloc.
Definition builder.h:312
std::stringstream deals with locale so this is a lot faster than std::stringstream for UTF8
Definition builder.h:325
int len() const
size of current string
Definition builder.h:411
A StringData object wraps a 'const string&' or a 'const char*' without copying its contents.
Definition string_data.h:43
Definition builder.h:55
Definition builder.h:98
void reserveBytes(int bytes)
Reserve room for some number of bytes to be claimed at a later time.
Definition builder.h:248
char * skip(int n)
leave room for some stuff later
Definition builder.h:147
int getSize() const
Definition builder.h:229
int len() const
Definition builder.h:222
void claimReservedBytes(int bytes)
Claim an earlier reservation of some number of bytes.
Definition builder.h:262
Utility functions for parsing numbers from strings.
Definition compare_numbers.h:20