]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/third-party/fbson/FbsonWriter.h
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / rocksdb / third-party / fbson / FbsonWriter.h
1 /*
2 * Copyright (c) 2011-present, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11 /*
12 * This file defines FbsonWriterT (template) and FbsonWriter.
13 *
14 * FbsonWriterT is a template class which implements an FBSON serializer.
15 * Users call various write functions of FbsonWriterT object to write values
16 * directly to FBSON packed bytes. All write functions of value or key return
17 * the number of bytes written to FBSON, or 0 if there is an error. To write an
18 * object, an array, or a string, you must call writeStart[..] before writing
19 * values or key, and call writeEnd[..] after finishing at the end.
20 *
21 * By default, an FbsonWriterT object creates an output stream buffer.
22 * Alternatively, you can also pass any output stream object to a writer, as
23 * long as the stream object implements some basic functions of std::ostream
24 * (such as FbsonOutStream, see FbsonStream.h).
25 *
26 * FbsonWriter specializes FbsonWriterT with FbsonOutStream type (see
27 * FbsonStream.h). So unless you want to provide own a different output stream
28 * type, use FbsonParser object.
29 *
30 * @author Tian Xia <tianx@fb.com>
31 */
32
33 #ifndef FBSON_FBSONWRITER_H
34 #define FBSON_FBSONWRITER_H
35
36 #include <stack>
37 #include "FbsonDocument.h"
38 #include "FbsonStream.h"
39
40 namespace fbson {
41
42 template <class OS_TYPE>
43 class FbsonWriterT {
44 public:
45 FbsonWriterT()
46 : alloc_(true), hasHdr_(false), kvState_(WS_Value), str_pos_(0) {
47 os_ = new OS_TYPE();
48 }
49
50 explicit FbsonWriterT(OS_TYPE& os)
51 : os_(&os),
52 alloc_(false),
53 hasHdr_(false),
54 kvState_(WS_Value),
55 str_pos_(0) {}
56
57 ~FbsonWriterT() {
58 if (alloc_) {
59 delete os_;
60 }
61 }
62
63 void reset() {
64 os_->clear();
65 os_->seekp(0);
66 hasHdr_ = false;
67 kvState_ = WS_Value;
68 for (; !stack_.empty(); stack_.pop())
69 ;
70 }
71
72 // write a key string (or key id if an external dict is provided)
73 uint32_t writeKey(const char* key,
74 uint8_t len,
75 hDictInsert handler = nullptr) {
76 if (len && !stack_.empty() && verifyKeyState()) {
77 int key_id = -1;
78 if (handler) {
79 key_id = handler(key, len);
80 }
81
82 uint32_t size = sizeof(uint8_t);
83 if (key_id < 0) {
84 os_->put(len);
85 os_->write(key, len);
86 size += len;
87 } else if (key_id <= FbsonKeyValue::sMaxKeyId) {
88 FbsonKeyValue::keyid_type idx = key_id;
89 os_->put(0);
90 os_->write((char*)&idx, sizeof(FbsonKeyValue::keyid_type));
91 size += sizeof(FbsonKeyValue::keyid_type);
92 } else { // key id overflow
93 assert(0);
94 return 0;
95 }
96
97 kvState_ = WS_Key;
98 return size;
99 }
100
101 return 0;
102 }
103
104 // write a key id
105 uint32_t writeKey(FbsonKeyValue::keyid_type idx) {
106 if (!stack_.empty() && verifyKeyState()) {
107 os_->put(0);
108 os_->write((char*)&idx, sizeof(FbsonKeyValue::keyid_type));
109 kvState_ = WS_Key;
110 return sizeof(uint8_t) + sizeof(FbsonKeyValue::keyid_type);
111 }
112
113 return 0;
114 }
115
116 uint32_t writeNull() {
117 if (!stack_.empty() && verifyValueState()) {
118 os_->put((FbsonTypeUnder)FbsonType::T_Null);
119 kvState_ = WS_Value;
120 return sizeof(FbsonValue);
121 }
122
123 return 0;
124 }
125
126 uint32_t writeBool(bool b) {
127 if (!stack_.empty() && verifyValueState()) {
128 if (b) {
129 os_->put((FbsonTypeUnder)FbsonType::T_True);
130 } else {
131 os_->put((FbsonTypeUnder)FbsonType::T_False);
132 }
133
134 kvState_ = WS_Value;
135 return sizeof(FbsonValue);
136 }
137
138 return 0;
139 }
140
141 uint32_t writeInt8(int8_t v) {
142 if (!stack_.empty() && verifyValueState()) {
143 os_->put((FbsonTypeUnder)FbsonType::T_Int8);
144 os_->put(v);
145 kvState_ = WS_Value;
146 return sizeof(Int8Val);
147 }
148
149 return 0;
150 }
151
152 uint32_t writeInt16(int16_t v) {
153 if (!stack_.empty() && verifyValueState()) {
154 os_->put((FbsonTypeUnder)FbsonType::T_Int16);
155 os_->write((char*)&v, sizeof(int16_t));
156 kvState_ = WS_Value;
157 return sizeof(Int16Val);
158 }
159
160 return 0;
161 }
162
163 uint32_t writeInt32(int32_t v) {
164 if (!stack_.empty() && verifyValueState()) {
165 os_->put((FbsonTypeUnder)FbsonType::T_Int32);
166 os_->write((char*)&v, sizeof(int32_t));
167 kvState_ = WS_Value;
168 return sizeof(Int32Val);
169 }
170
171 return 0;
172 }
173
174 uint32_t writeInt64(int64_t v) {
175 if (!stack_.empty() && verifyValueState()) {
176 os_->put((FbsonTypeUnder)FbsonType::T_Int64);
177 os_->write((char*)&v, sizeof(int64_t));
178 kvState_ = WS_Value;
179 return sizeof(Int64Val);
180 }
181
182 return 0;
183 }
184
185 uint32_t writeDouble(double v) {
186 if (!stack_.empty() && verifyValueState()) {
187 os_->put((FbsonTypeUnder)FbsonType::T_Double);
188 os_->write((char*)&v, sizeof(double));
189 kvState_ = WS_Value;
190 return sizeof(DoubleVal);
191 }
192
193 return 0;
194 }
195
196 // must call writeStartString before writing a string val
197 bool writeStartString() {
198 if (!stack_.empty() && verifyValueState()) {
199 os_->put((FbsonTypeUnder)FbsonType::T_String);
200 str_pos_ = os_->tellp();
201
202 // fill the size bytes with 0 for now
203 uint32_t size = 0;
204 os_->write((char*)&size, sizeof(uint32_t));
205
206 kvState_ = WS_String;
207 return true;
208 }
209
210 return false;
211 }
212
213 // finish writing a string val
214 bool writeEndString() {
215 if (kvState_ == WS_String) {
216 std::streampos cur_pos = os_->tellp();
217 int32_t size = (int32_t)(cur_pos - str_pos_ - sizeof(uint32_t));
218 assert(size >= 0);
219
220 os_->seekp(str_pos_);
221 os_->write((char*)&size, sizeof(uint32_t));
222 os_->seekp(cur_pos);
223
224 kvState_ = WS_Value;
225 return true;
226 }
227
228 return false;
229 }
230
231 uint32_t writeString(const char* str, uint32_t len) {
232 if (kvState_ == WS_String) {
233 os_->write(str, len);
234 return len;
235 }
236
237 return 0;
238 }
239
240 uint32_t writeString(char ch) {
241 if (kvState_ == WS_String) {
242 os_->put(ch);
243 return 1;
244 }
245
246 return 0;
247 }
248
249 // must call writeStartBinary before writing a binary val
250 bool writeStartBinary() {
251 if (!stack_.empty() && verifyValueState()) {
252 os_->put((FbsonTypeUnder)FbsonType::T_Binary);
253 str_pos_ = os_->tellp();
254
255 // fill the size bytes with 0 for now
256 uint32_t size = 0;
257 os_->write((char*)&size, sizeof(uint32_t));
258
259 kvState_ = WS_Binary;
260 return true;
261 }
262
263 return false;
264 }
265
266 // finish writing a binary val
267 bool writeEndBinary() {
268 if (kvState_ == WS_Binary) {
269 std::streampos cur_pos = os_->tellp();
270 int32_t size = (int32_t)(cur_pos - str_pos_ - sizeof(uint32_t));
271 assert(size >= 0);
272
273 os_->seekp(str_pos_);
274 os_->write((char*)&size, sizeof(uint32_t));
275 os_->seekp(cur_pos);
276
277 kvState_ = WS_Value;
278 return true;
279 }
280
281 return false;
282 }
283
284 uint32_t writeBinary(const char* bin, uint32_t len) {
285 if (kvState_ == WS_Binary) {
286 os_->write(bin, len);
287 return len;
288 }
289
290 return 0;
291 }
292
293 // must call writeStartObject before writing an object val
294 bool writeStartObject() {
295 if (stack_.empty() || verifyValueState()) {
296 if (stack_.empty()) {
297 // if this is a new FBSON, write the header
298 if (!hasHdr_) {
299 writeHeader();
300 } else
301 return false;
302 }
303
304 os_->put((FbsonTypeUnder)FbsonType::T_Object);
305 // save the size position
306 stack_.push(WriteInfo({WS_Object, os_->tellp()}));
307
308 // fill the size bytes with 0 for now
309 uint32_t size = 0;
310 os_->write((char*)&size, sizeof(uint32_t));
311
312 kvState_ = WS_Value;
313 return true;
314 }
315
316 return false;
317 }
318
319 // finish writing an object val
320 bool writeEndObject() {
321 if (!stack_.empty() && stack_.top().state == WS_Object &&
322 kvState_ == WS_Value) {
323 WriteInfo& ci = stack_.top();
324 std::streampos cur_pos = os_->tellp();
325 int32_t size = (int32_t)(cur_pos - ci.sz_pos - sizeof(uint32_t));
326 assert(size >= 0);
327
328 os_->seekp(ci.sz_pos);
329 os_->write((char*)&size, sizeof(uint32_t));
330 os_->seekp(cur_pos);
331 stack_.pop();
332
333 return true;
334 }
335
336 return false;
337 }
338
339 // must call writeStartArray before writing an array val
340 bool writeStartArray() {
341 if (stack_.empty() || verifyValueState()) {
342 if (stack_.empty()) {
343 // if this is a new FBSON, write the header
344 if (!hasHdr_) {
345 writeHeader();
346 } else
347 return false;
348 }
349
350 os_->put((FbsonTypeUnder)FbsonType::T_Array);
351 // save the size position
352 stack_.push(WriteInfo({WS_Array, os_->tellp()}));
353
354 // fill the size bytes with 0 for now
355 uint32_t size = 0;
356 os_->write((char*)&size, sizeof(uint32_t));
357
358 kvState_ = WS_Value;
359 return true;
360 }
361
362 return false;
363 }
364
365 // finish writing an array val
366 bool writeEndArray() {
367 if (!stack_.empty() && stack_.top().state == WS_Array &&
368 kvState_ == WS_Value) {
369 WriteInfo& ci = stack_.top();
370 std::streampos cur_pos = os_->tellp();
371 int32_t size = (int32_t)(cur_pos - ci.sz_pos - sizeof(uint32_t));
372 assert(size >= 0);
373
374 os_->seekp(ci.sz_pos);
375 os_->write((char*)&size, sizeof(uint32_t));
376 os_->seekp(cur_pos);
377 stack_.pop();
378
379 return true;
380 }
381
382 return false;
383 }
384
385 OS_TYPE* getOutput() { return os_; }
386
387 private:
388 // verify we are in the right state before writing a value
389 bool verifyValueState() {
390 assert(!stack_.empty());
391 return (stack_.top().state == WS_Object && kvState_ == WS_Key) ||
392 (stack_.top().state == WS_Array && kvState_ == WS_Value);
393 }
394
395 // verify we are in the right state before writing a key
396 bool verifyKeyState() {
397 assert(!stack_.empty());
398 return stack_.top().state == WS_Object && kvState_ == WS_Value;
399 }
400
401 void writeHeader() {
402 os_->put(FBSON_VER);
403 hasHdr_ = true;
404 }
405
406 private:
407 enum WriteState {
408 WS_NONE,
409 WS_Array,
410 WS_Object,
411 WS_Key,
412 WS_Value,
413 WS_String,
414 WS_Binary,
415 };
416
417 struct WriteInfo {
418 WriteState state;
419 std::streampos sz_pos;
420 };
421
422 private:
423 OS_TYPE* os_;
424 bool alloc_;
425 bool hasHdr_;
426 WriteState kvState_; // key or value state
427 std::streampos str_pos_;
428 std::stack<WriteInfo> stack_;
429 };
430
431 typedef FbsonWriterT<FbsonOutStream> FbsonWriter;
432
433 } // namespace fbson
434
435 #endif // FBSON_FBSONWRITER_H