]>
git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/third-party/fbson/FbsonWriter.h
2 * Copyright (c) 2011-present, Facebook, Inc.
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.
12 * This file defines FbsonWriterT (template) and FbsonWriter.
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.
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).
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.
30 * @author Tian Xia <tianx@fb.com>
33 #ifndef FBSON_FBSONWRITER_H
34 #define FBSON_FBSONWRITER_H
37 #include "FbsonDocument.h"
38 #include "FbsonStream.h"
42 template <class OS_TYPE
>
46 : alloc_(true), hasHdr_(false), kvState_(WS_Value
), str_pos_(0) {
50 explicit FbsonWriterT(OS_TYPE
& os
)
68 for (; !stack_
.empty(); stack_
.pop())
72 // write a key string (or key id if an external dict is provided)
73 uint32_t writeKey(const char* key
,
75 hDictInsert handler
= nullptr) {
76 if (len
&& !stack_
.empty() && verifyKeyState()) {
79 key_id
= handler(key
, len
);
82 uint32_t size
= sizeof(uint8_t);
87 } else if (key_id
<= FbsonKeyValue::sMaxKeyId
) {
88 FbsonKeyValue::keyid_type idx
= key_id
;
90 os_
->write((char*)&idx
, sizeof(FbsonKeyValue::keyid_type
));
91 size
+= sizeof(FbsonKeyValue::keyid_type
);
92 } else { // key id overflow
105 uint32_t writeKey(FbsonKeyValue::keyid_type idx
) {
106 if (!stack_
.empty() && verifyKeyState()) {
108 os_
->write((char*)&idx
, sizeof(FbsonKeyValue::keyid_type
));
110 return sizeof(uint8_t) + sizeof(FbsonKeyValue::keyid_type
);
116 uint32_t writeNull() {
117 if (!stack_
.empty() && verifyValueState()) {
118 os_
->put((FbsonTypeUnder
)FbsonType::T_Null
);
120 return sizeof(FbsonValue
);
126 uint32_t writeBool(bool b
) {
127 if (!stack_
.empty() && verifyValueState()) {
129 os_
->put((FbsonTypeUnder
)FbsonType::T_True
);
131 os_
->put((FbsonTypeUnder
)FbsonType::T_False
);
135 return sizeof(FbsonValue
);
141 uint32_t writeInt8(int8_t v
) {
142 if (!stack_
.empty() && verifyValueState()) {
143 os_
->put((FbsonTypeUnder
)FbsonType::T_Int8
);
146 return sizeof(Int8Val
);
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));
157 return sizeof(Int16Val
);
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));
168 return sizeof(Int32Val
);
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));
179 return sizeof(Int64Val
);
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));
190 return sizeof(DoubleVal
);
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();
202 // fill the size bytes with 0 for now
204 os_
->write((char*)&size
, sizeof(uint32_t));
206 kvState_
= WS_String
;
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));
220 os_
->seekp(str_pos_
);
221 os_
->write((char*)&size
, sizeof(uint32_t));
231 uint32_t writeString(const char* str
, uint32_t len
) {
232 if (kvState_
== WS_String
) {
233 os_
->write(str
, len
);
240 uint32_t writeString(char ch
) {
241 if (kvState_
== WS_String
) {
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();
255 // fill the size bytes with 0 for now
257 os_
->write((char*)&size
, sizeof(uint32_t));
259 kvState_
= WS_Binary
;
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));
273 os_
->seekp(str_pos_
);
274 os_
->write((char*)&size
, sizeof(uint32_t));
284 uint32_t writeBinary(const char* bin
, uint32_t len
) {
285 if (kvState_
== WS_Binary
) {
286 os_
->write(bin
, len
);
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
304 os_
->put((FbsonTypeUnder
)FbsonType::T_Object
);
305 // save the size position
306 stack_
.push(WriteInfo({WS_Object
, os_
->tellp()}));
308 // fill the size bytes with 0 for now
310 os_
->write((char*)&size
, sizeof(uint32_t));
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));
328 os_
->seekp(ci
.sz_pos
);
329 os_
->write((char*)&size
, sizeof(uint32_t));
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
350 os_
->put((FbsonTypeUnder
)FbsonType::T_Array
);
351 // save the size position
352 stack_
.push(WriteInfo({WS_Array
, os_
->tellp()}));
354 // fill the size bytes with 0 for now
356 os_
->write((char*)&size
, sizeof(uint32_t));
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));
374 os_
->seekp(ci
.sz_pos
);
375 os_
->write((char*)&size
, sizeof(uint32_t));
385 OS_TYPE
* getOutput() { return os_
; }
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
);
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
;
419 std::streampos sz_pos
;
426 WriteState kvState_
; // key or value state
427 std::streampos str_pos_
;
428 std::stack
<WriteInfo
> stack_
;
431 typedef FbsonWriterT
<FbsonOutStream
> FbsonWriter
;
435 #endif // FBSON_FBSONWRITER_H