]>
git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/third-party/fbson/FbsonWriter.h
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
7 * This file defines FbsonWriterT (template) and FbsonWriter.
9 * FbsonWriterT is a template class which implements an FBSON serializer.
10 * Users call various write functions of FbsonWriterT object to write values
11 * directly to FBSON packed bytes. All write functions of value or key return
12 * the number of bytes written to FBSON, or 0 if there is an error. To write an
13 * object, an array, or a string, you must call writeStart[..] before writing
14 * values or key, and call writeEnd[..] after finishing at the end.
16 * By default, an FbsonWriterT object creates an output stream buffer.
17 * Alternatively, you can also pass any output stream object to a writer, as
18 * long as the stream object implements some basic functions of std::ostream
19 * (such as FbsonOutStream, see FbsonStream.h).
21 * FbsonWriter specializes FbsonWriterT with FbsonOutStream type (see
22 * FbsonStream.h). So unless you want to provide own a different output stream
23 * type, use FbsonParser object.
25 * @author Tian Xia <tianx@fb.com>
31 #include "FbsonDocument.h"
32 #include "FbsonStream.h"
34 // conversion' conversion from 'type1' to 'type2', possible loss of data
35 // Can not restore at the header end as the warnings are emitted at the point of
36 // template instantiation
38 #pragma warning(disable : 4244)
43 template <class OS_TYPE
>
47 : alloc_(true), hasHdr_(false), kvState_(WS_Value
), str_pos_(0) {
51 explicit FbsonWriterT(OS_TYPE
& os
)
69 for (; !stack_
.empty(); stack_
.pop())
73 // write a key string (or key id if an external dict is provided)
74 uint32_t writeKey(const char* key
,
76 hDictInsert handler
= nullptr) {
77 if (len
&& !stack_
.empty() && verifyKeyState()) {
80 key_id
= handler(key
, len
);
83 uint32_t size
= sizeof(uint8_t);
88 } else if (key_id
<= FbsonKeyValue::sMaxKeyId
) {
89 FbsonKeyValue::keyid_type idx
= key_id
;
91 os_
->write((char*)&idx
, sizeof(FbsonKeyValue::keyid_type
));
92 size
+= sizeof(FbsonKeyValue::keyid_type
);
93 } else { // key id overflow
106 uint32_t writeKey(FbsonKeyValue::keyid_type idx
) {
107 if (!stack_
.empty() && verifyKeyState()) {
109 os_
->write((char*)&idx
, sizeof(FbsonKeyValue::keyid_type
));
111 return sizeof(uint8_t) + sizeof(FbsonKeyValue::keyid_type
);
117 uint32_t writeNull() {
118 if (!stack_
.empty() && verifyValueState()) {
119 os_
->put((FbsonTypeUnder
)FbsonType::T_Null
);
121 return sizeof(FbsonValue
);
127 uint32_t writeBool(bool b
) {
128 if (!stack_
.empty() && verifyValueState()) {
130 os_
->put((FbsonTypeUnder
)FbsonType::T_True
);
132 os_
->put((FbsonTypeUnder
)FbsonType::T_False
);
136 return sizeof(FbsonValue
);
142 uint32_t writeInt8(int8_t v
) {
143 if (!stack_
.empty() && verifyValueState()) {
144 os_
->put((FbsonTypeUnder
)FbsonType::T_Int8
);
147 return sizeof(Int8Val
);
153 uint32_t writeInt16(int16_t v
) {
154 if (!stack_
.empty() && verifyValueState()) {
155 os_
->put((FbsonTypeUnder
)FbsonType::T_Int16
);
156 os_
->write((char*)&v
, sizeof(int16_t));
158 return sizeof(Int16Val
);
164 uint32_t writeInt32(int32_t v
) {
165 if (!stack_
.empty() && verifyValueState()) {
166 os_
->put((FbsonTypeUnder
)FbsonType::T_Int32
);
167 os_
->write((char*)&v
, sizeof(int32_t));
169 return sizeof(Int32Val
);
175 uint32_t writeInt64(int64_t v
) {
176 if (!stack_
.empty() && verifyValueState()) {
177 os_
->put((FbsonTypeUnder
)FbsonType::T_Int64
);
178 os_
->write((char*)&v
, sizeof(int64_t));
180 return sizeof(Int64Val
);
186 uint32_t writeDouble(double v
) {
187 if (!stack_
.empty() && verifyValueState()) {
188 os_
->put((FbsonTypeUnder
)FbsonType::T_Double
);
189 os_
->write((char*)&v
, sizeof(double));
191 return sizeof(DoubleVal
);
197 // must call writeStartString before writing a string val
198 bool writeStartString() {
199 if (!stack_
.empty() && verifyValueState()) {
200 os_
->put((FbsonTypeUnder
)FbsonType::T_String
);
201 str_pos_
= os_
->tellp();
203 // fill the size bytes with 0 for now
205 os_
->write((char*)&size
, sizeof(uint32_t));
207 kvState_
= WS_String
;
214 // finish writing a string val
215 bool writeEndString() {
216 if (kvState_
== WS_String
) {
217 std::streampos cur_pos
= os_
->tellp();
218 int32_t size
= (int32_t)(cur_pos
- str_pos_
- sizeof(uint32_t));
221 os_
->seekp(str_pos_
);
222 os_
->write((char*)&size
, sizeof(uint32_t));
232 uint32_t writeString(const char* str
, uint32_t len
) {
233 if (kvState_
== WS_String
) {
234 os_
->write(str
, len
);
241 uint32_t writeString(char ch
) {
242 if (kvState_
== WS_String
) {
250 // must call writeStartBinary before writing a binary val
251 bool writeStartBinary() {
252 if (!stack_
.empty() && verifyValueState()) {
253 os_
->put((FbsonTypeUnder
)FbsonType::T_Binary
);
254 str_pos_
= os_
->tellp();
256 // fill the size bytes with 0 for now
258 os_
->write((char*)&size
, sizeof(uint32_t));
260 kvState_
= WS_Binary
;
267 // finish writing a binary val
268 bool writeEndBinary() {
269 if (kvState_
== WS_Binary
) {
270 std::streampos cur_pos
= os_
->tellp();
271 int32_t size
= (int32_t)(cur_pos
- str_pos_
- sizeof(uint32_t));
274 os_
->seekp(str_pos_
);
275 os_
->write((char*)&size
, sizeof(uint32_t));
285 uint32_t writeBinary(const char* bin
, uint32_t len
) {
286 if (kvState_
== WS_Binary
) {
287 os_
->write(bin
, len
);
294 // must call writeStartObject before writing an object val
295 bool writeStartObject() {
296 if (stack_
.empty() || verifyValueState()) {
297 if (stack_
.empty()) {
298 // if this is a new FBSON, write the header
305 os_
->put((FbsonTypeUnder
)FbsonType::T_Object
);
306 // save the size position
307 stack_
.push(WriteInfo({WS_Object
, os_
->tellp()}));
309 // fill the size bytes with 0 for now
311 os_
->write((char*)&size
, sizeof(uint32_t));
320 // finish writing an object val
321 bool writeEndObject() {
322 if (!stack_
.empty() && stack_
.top().state
== WS_Object
&&
323 kvState_
== WS_Value
) {
324 WriteInfo
& ci
= stack_
.top();
325 std::streampos cur_pos
= os_
->tellp();
326 int32_t size
= (int32_t)(cur_pos
- ci
.sz_pos
- sizeof(uint32_t));
329 os_
->seekp(ci
.sz_pos
);
330 os_
->write((char*)&size
, sizeof(uint32_t));
340 // must call writeStartArray before writing an array val
341 bool writeStartArray() {
342 if (stack_
.empty() || verifyValueState()) {
343 if (stack_
.empty()) {
344 // if this is a new FBSON, write the header
351 os_
->put((FbsonTypeUnder
)FbsonType::T_Array
);
352 // save the size position
353 stack_
.push(WriteInfo({WS_Array
, os_
->tellp()}));
355 // fill the size bytes with 0 for now
357 os_
->write((char*)&size
, sizeof(uint32_t));
366 // finish writing an array val
367 bool writeEndArray() {
368 if (!stack_
.empty() && stack_
.top().state
== WS_Array
&&
369 kvState_
== WS_Value
) {
370 WriteInfo
& ci
= stack_
.top();
371 std::streampos cur_pos
= os_
->tellp();
372 int32_t size
= (int32_t)(cur_pos
- ci
.sz_pos
- sizeof(uint32_t));
375 os_
->seekp(ci
.sz_pos
);
376 os_
->write((char*)&size
, sizeof(uint32_t));
386 OS_TYPE
* getOutput() { return os_
; }
389 // verify we are in the right state before writing a value
390 bool verifyValueState() {
391 assert(!stack_
.empty());
392 return (stack_
.top().state
== WS_Object
&& kvState_
== WS_Key
) ||
393 (stack_
.top().state
== WS_Array
&& kvState_
== WS_Value
);
396 // verify we are in the right state before writing a key
397 bool verifyKeyState() {
398 assert(!stack_
.empty());
399 return stack_
.top().state
== WS_Object
&& kvState_
== WS_Value
;
420 std::streampos sz_pos
;
427 WriteState kvState_
; // key or value state
428 std::streampos str_pos_
;
429 std::stack
<WriteInfo
> stack_
;
432 typedef FbsonWriterT
<FbsonOutStream
> FbsonWriter
;