YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

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