]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/third-party/fbson/FbsonWriter.h
build: use dgit for download target
[ceph.git] / ceph / src / rocksdb / third-party / fbson / FbsonWriter.h
CommitLineData
11fdf7f2
TL
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).
7c673cae
FG
5
6/*
7 * This file defines FbsonWriterT (template) and FbsonWriter.
8 *
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.
15 *
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).
20 *
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.
24 *
25 * @author Tian Xia <tianx@fb.com>
26 */
27
11fdf7f2 28#pragma once
7c673cae
FG
29
30#include <stack>
31#include "FbsonDocument.h"
32#include "FbsonStream.h"
33
11fdf7f2
TL
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
37#if defined(_MSC_VER)
38#pragma warning(disable : 4244)
39#endif
40
7c673cae
FG
41namespace fbson {
42
43template <class OS_TYPE>
44class FbsonWriterT {
45 public:
46 FbsonWriterT()
47 : alloc_(true), hasHdr_(false), kvState_(WS_Value), str_pos_(0) {
48 os_ = new OS_TYPE();
49 }
50
51 explicit FbsonWriterT(OS_TYPE& os)
52 : os_(&os),
53 alloc_(false),
54 hasHdr_(false),
55 kvState_(WS_Value),
56 str_pos_(0) {}
57
58 ~FbsonWriterT() {
59 if (alloc_) {
60 delete os_;
61 }
62 }
63
64 void reset() {
65 os_->clear();
66 os_->seekp(0);
67 hasHdr_ = false;
68 kvState_ = WS_Value;
69 for (; !stack_.empty(); stack_.pop())
70 ;
71 }
72
73 // write a key string (or key id if an external dict is provided)
74 uint32_t writeKey(const char* key,
75 uint8_t len,
76 hDictInsert handler = nullptr) {
77 if (len && !stack_.empty() && verifyKeyState()) {
78 int key_id = -1;
79 if (handler) {
80 key_id = handler(key, len);
81 }
82
83 uint32_t size = sizeof(uint8_t);
84 if (key_id < 0) {
85 os_->put(len);
86 os_->write(key, len);
87 size += len;
88 } else if (key_id <= FbsonKeyValue::sMaxKeyId) {
89 FbsonKeyValue::keyid_type idx = key_id;
90 os_->put(0);
91 os_->write((char*)&idx, sizeof(FbsonKeyValue::keyid_type));
92 size += sizeof(FbsonKeyValue::keyid_type);
93 } else { // key id overflow
94 assert(0);
95 return 0;
96 }
97
98 kvState_ = WS_Key;
99 return size;
100 }
101
102 return 0;
103 }
104
105 // write a key id
106 uint32_t writeKey(FbsonKeyValue::keyid_type idx) {
107 if (!stack_.empty() && verifyKeyState()) {
108 os_->put(0);
109 os_->write((char*)&idx, sizeof(FbsonKeyValue::keyid_type));
110 kvState_ = WS_Key;
111 return sizeof(uint8_t) + sizeof(FbsonKeyValue::keyid_type);
112 }
113
114 return 0;
115 }
116
117 uint32_t writeNull() {
118 if (!stack_.empty() && verifyValueState()) {
119 os_->put((FbsonTypeUnder)FbsonType::T_Null);
120 kvState_ = WS_Value;
121 return sizeof(FbsonValue);
122 }
123
124 return 0;
125 }
126
127 uint32_t writeBool(bool b) {
128 if (!stack_.empty() && verifyValueState()) {
129 if (b) {
130 os_->put((FbsonTypeUnder)FbsonType::T_True);
131 } else {
132 os_->put((FbsonTypeUnder)FbsonType::T_False);
133 }
134
135 kvState_ = WS_Value;
136 return sizeof(FbsonValue);
137 }
138
139 return 0;
140 }
141
142 uint32_t writeInt8(int8_t v) {
143 if (!stack_.empty() && verifyValueState()) {
144 os_->put((FbsonTypeUnder)FbsonType::T_Int8);
145 os_->put(v);
146 kvState_ = WS_Value;
147 return sizeof(Int8Val);
148 }
149
150 return 0;
151 }
152
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));
157 kvState_ = WS_Value;
158 return sizeof(Int16Val);
159 }
160
161 return 0;
162 }
163
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));
168 kvState_ = WS_Value;
169 return sizeof(Int32Val);
170 }
171
172 return 0;
173 }
174
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));
179 kvState_ = WS_Value;
180 return sizeof(Int64Val);
181 }
182
183 return 0;
184 }
185
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));
190 kvState_ = WS_Value;
191 return sizeof(DoubleVal);
192 }
193
194 return 0;
195 }
196
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();
202
203 // fill the size bytes with 0 for now
204 uint32_t size = 0;
205 os_->write((char*)&size, sizeof(uint32_t));
206
207 kvState_ = WS_String;
208 return true;
209 }
210
211 return false;
212 }
213
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));
219 assert(size >= 0);
220
221 os_->seekp(str_pos_);
222 os_->write((char*)&size, sizeof(uint32_t));
223 os_->seekp(cur_pos);
224
225 kvState_ = WS_Value;
226 return true;
227 }
228
229 return false;
230 }
231
232 uint32_t writeString(const char* str, uint32_t len) {
233 if (kvState_ == WS_String) {
234 os_->write(str, len);
235 return len;
236 }
237
238 return 0;
239 }
240
241 uint32_t writeString(char ch) {
242 if (kvState_ == WS_String) {
243 os_->put(ch);
244 return 1;
245 }
246
247 return 0;
248 }
249
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();
255
256 // fill the size bytes with 0 for now
257 uint32_t size = 0;
258 os_->write((char*)&size, sizeof(uint32_t));
259
260 kvState_ = WS_Binary;
261 return true;
262 }
263
264 return false;
265 }
266
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));
272 assert(size >= 0);
273
274 os_->seekp(str_pos_);
275 os_->write((char*)&size, sizeof(uint32_t));
276 os_->seekp(cur_pos);
277
278 kvState_ = WS_Value;
279 return true;
280 }
281
282 return false;
283 }
284
285 uint32_t writeBinary(const char* bin, uint32_t len) {
286 if (kvState_ == WS_Binary) {
287 os_->write(bin, len);
288 return len;
289 }
290
291 return 0;
292 }
293
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
299 if (!hasHdr_) {
300 writeHeader();
301 } else
302 return false;
303 }
304
305 os_->put((FbsonTypeUnder)FbsonType::T_Object);
306 // save the size position
307 stack_.push(WriteInfo({WS_Object, os_->tellp()}));
308
309 // fill the size bytes with 0 for now
310 uint32_t size = 0;
311 os_->write((char*)&size, sizeof(uint32_t));
312
313 kvState_ = WS_Value;
314 return true;
315 }
316
317 return false;
318 }
319
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));
327 assert(size >= 0);
328
329 os_->seekp(ci.sz_pos);
330 os_->write((char*)&size, sizeof(uint32_t));
331 os_->seekp(cur_pos);
332 stack_.pop();
333
334 return true;
335 }
336
337 return false;
338 }
339
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
345 if (!hasHdr_) {
346 writeHeader();
347 } else
348 return false;
349 }
350
351 os_->put((FbsonTypeUnder)FbsonType::T_Array);
352 // save the size position
353 stack_.push(WriteInfo({WS_Array, os_->tellp()}));
354
355 // fill the size bytes with 0 for now
356 uint32_t size = 0;
357 os_->write((char*)&size, sizeof(uint32_t));
358
359 kvState_ = WS_Value;
360 return true;
361 }
362
363 return false;
364 }
365
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));
373 assert(size >= 0);
374
375 os_->seekp(ci.sz_pos);
376 os_->write((char*)&size, sizeof(uint32_t));
377 os_->seekp(cur_pos);
378 stack_.pop();
379
380 return true;
381 }
382
383 return false;
384 }
385
386 OS_TYPE* getOutput() { return os_; }
387
388 private:
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);
394 }
395
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;
400 }
401
402 void writeHeader() {
403 os_->put(FBSON_VER);
404 hasHdr_ = true;
405 }
406
407 private:
408 enum WriteState {
409 WS_NONE,
410 WS_Array,
411 WS_Object,
412 WS_Key,
413 WS_Value,
414 WS_String,
415 WS_Binary,
416 };
417
418 struct WriteInfo {
419 WriteState state;
420 std::streampos sz_pos;
421 };
422
423 private:
424 OS_TYPE* os_;
425 bool alloc_;
426 bool hasHdr_;
427 WriteState kvState_; // key or value state
428 std::streampos str_pos_;
429 std::stack<WriteInfo> stack_;
430};
431
432typedef FbsonWriterT<FbsonOutStream> FbsonWriter;
433
434} // namespace fbson