1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #pragma once
32 
33 #include "mongo/base/string_data.h"
34 #include "mongo/bson/util/builder.h"
35 
36 namespace mongo {
37 
38 /** a page-aligned BufBuilder. */
39 class AlignedBuilder {
40 public:
41     AlignedBuilder(unsigned init_size);
~AlignedBuilder()42     ~AlignedBuilder() {
43         kill();
44     }
45 
46     /** reset with a hint as to the upcoming needed size specified */
47     void reset(unsigned sz);
48 
49     /** reset for a re-use. shrinks if > 128MB */
50     void reset();
51 
52     /** note this may be deallocated (realloced) if you keep writing or reset(). */
buf()53     const char* buf() const {
54         return _p._data;
55     }
56 
57     /** leave room for some stuff later
58         @return offset in the buffer that was our current position
59     */
skip(unsigned n)60     size_t skip(unsigned n) {
61         unsigned l = len();
62         grow(n);
63         return l;
64     }
65 
66     /** if buffer grows pointer no longer valid */
atOfs(unsigned ofs)67     char* atOfs(unsigned ofs) {
68         return _p._data + ofs;
69     }
70 
71     /** if buffer grows pointer no longer valid */
cur()72     char* cur() {
73         return _p._data + _len;
74     }
75 
appendChar(char j)76     void appendChar(char j) {
77         *((char*)grow(sizeof(char))) = j;
78     }
appendNum(char j)79     void appendNum(char j) {
80         *((char*)grow(sizeof(char))) = j;
81     }
appendNum(short j)82     void appendNum(short j) {
83         *((short*)grow(sizeof(short))) = j;
84     }
appendNum(int j)85     void appendNum(int j) {
86         *((int*)grow(sizeof(int))) = j;
87     }
appendNum(unsigned j)88     void appendNum(unsigned j) {
89         *((unsigned*)grow(sizeof(unsigned))) = j;
90     }
appendNum(bool j)91     void appendNum(bool j) {
92         *((bool*)grow(sizeof(bool))) = j;
93     }
appendNum(double j)94     void appendNum(double j) {
95         *((double*)grow(sizeof(double))) = j;
96     }
appendNum(long long j)97     void appendNum(long long j) {
98         *((long long*)grow(sizeof(long long))) = j;
99     }
appendNum(unsigned long long j)100     void appendNum(unsigned long long j) {
101         *((unsigned long long*)grow(sizeof(unsigned long long))) = j;
102     }
103 
appendBuf(const void * src,size_t len)104     void appendBuf(const void* src, size_t len) {
105         memcpy(grow((unsigned)len), src, len);
106     }
107 
108     template <class T>
appendStruct(const T & s)109     void appendStruct(const T& s) {
110         appendBuf(&s, sizeof(T));
111     }
112 
113     void appendStr(StringData str, bool includeEOO = true) {
114         const unsigned len = str.size() + (includeEOO ? 1 : 0);
115         verify(len < (unsigned)BSONObjMaxUserSize);
116         str.copyTo(grow(len), includeEOO);
117     }
118 
119     /** @return the in-use length */
len()120     unsigned len() const {
121         return _len;
122     }
123 
124 private:
125     static const unsigned Alignment = 8192;
126 
127     /** returns the pre-grow write position */
grow(unsigned by)128     inline char* grow(unsigned by) {
129         unsigned oldlen = _len;
130         _len += by;
131         if (MONGO_unlikely(_len > _p._size)) {
132             growReallocate(oldlen);
133         }
134         return _p._data + oldlen;
135     }
136 
137     void growReallocate(unsigned oldLenInUse);
138     void kill();
139     void mallocSelfAligned(unsigned sz);
140     void _malloc(unsigned sz);
141     void _realloc(unsigned newSize, unsigned oldLenInUse);
142     void _free(void*);
143 
144     struct AllocationInfo {
145         char* _data;
146         void* _allocationAddress;
147         unsigned _size;
148     } _p;
149     unsigned _len;  // bytes in use
150 };
151 }
152