mirror of
https://github.com/facebook/rocksdb.git
synced 2024-11-27 02:44:18 +00:00
64324e329e
Summary: As you know, almost all compilers support "pragma once" keyword instead of using include guards. To be keep consistency between header files, all header files are edited. Besides this, try to fix some warnings about loss of data. Pull Request resolved: https://github.com/facebook/rocksdb/pull/4339 Differential Revision: D9654990 Pulled By: ajkr fbshipit-source-id: c2cf3d2d03a599847684bed81378c401920ca848
435 lines
10 KiB
C++
435 lines
10 KiB
C++
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
// (found in the LICENSE.Apache file in the root directory).
|
|
|
|
/*
|
|
* This file defines FbsonWriterT (template) and FbsonWriter.
|
|
*
|
|
* FbsonWriterT is a template class which implements an FBSON serializer.
|
|
* Users call various write functions of FbsonWriterT object to write values
|
|
* directly to FBSON packed bytes. All write functions of value or key return
|
|
* the number of bytes written to FBSON, or 0 if there is an error. To write an
|
|
* object, an array, or a string, you must call writeStart[..] before writing
|
|
* values or key, and call writeEnd[..] after finishing at the end.
|
|
*
|
|
* By default, an FbsonWriterT object creates an output stream buffer.
|
|
* Alternatively, you can also pass any output stream object to a writer, as
|
|
* long as the stream object implements some basic functions of std::ostream
|
|
* (such as FbsonOutStream, see FbsonStream.h).
|
|
*
|
|
* FbsonWriter specializes FbsonWriterT with FbsonOutStream type (see
|
|
* FbsonStream.h). So unless you want to provide own a different output stream
|
|
* type, use FbsonParser object.
|
|
*
|
|
* @author Tian Xia <tianx@fb.com>
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <stack>
|
|
#include "FbsonDocument.h"
|
|
#include "FbsonStream.h"
|
|
|
|
// conversion' conversion from 'type1' to 'type2', possible loss of data
|
|
// Can not restore at the header end as the warnings are emitted at the point of
|
|
// template instantiation
|
|
#if defined(_MSC_VER)
|
|
#pragma warning(disable : 4244)
|
|
#endif
|
|
|
|
namespace fbson {
|
|
|
|
template <class OS_TYPE>
|
|
class FbsonWriterT {
|
|
public:
|
|
FbsonWriterT()
|
|
: alloc_(true), hasHdr_(false), kvState_(WS_Value), str_pos_(0) {
|
|
os_ = new OS_TYPE();
|
|
}
|
|
|
|
explicit FbsonWriterT(OS_TYPE& os)
|
|
: os_(&os),
|
|
alloc_(false),
|
|
hasHdr_(false),
|
|
kvState_(WS_Value),
|
|
str_pos_(0) {}
|
|
|
|
~FbsonWriterT() {
|
|
if (alloc_) {
|
|
delete os_;
|
|
}
|
|
}
|
|
|
|
void reset() {
|
|
os_->clear();
|
|
os_->seekp(0);
|
|
hasHdr_ = false;
|
|
kvState_ = WS_Value;
|
|
for (; !stack_.empty(); stack_.pop())
|
|
;
|
|
}
|
|
|
|
// write a key string (or key id if an external dict is provided)
|
|
uint32_t writeKey(const char* key,
|
|
uint8_t len,
|
|
hDictInsert handler = nullptr) {
|
|
if (len && !stack_.empty() && verifyKeyState()) {
|
|
int key_id = -1;
|
|
if (handler) {
|
|
key_id = handler(key, len);
|
|
}
|
|
|
|
uint32_t size = sizeof(uint8_t);
|
|
if (key_id < 0) {
|
|
os_->put(len);
|
|
os_->write(key, len);
|
|
size += len;
|
|
} else if (key_id <= FbsonKeyValue::sMaxKeyId) {
|
|
FbsonKeyValue::keyid_type idx = key_id;
|
|
os_->put(0);
|
|
os_->write((char*)&idx, sizeof(FbsonKeyValue::keyid_type));
|
|
size += sizeof(FbsonKeyValue::keyid_type);
|
|
} else { // key id overflow
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
|
|
kvState_ = WS_Key;
|
|
return size;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// write a key id
|
|
uint32_t writeKey(FbsonKeyValue::keyid_type idx) {
|
|
if (!stack_.empty() && verifyKeyState()) {
|
|
os_->put(0);
|
|
os_->write((char*)&idx, sizeof(FbsonKeyValue::keyid_type));
|
|
kvState_ = WS_Key;
|
|
return sizeof(uint8_t) + sizeof(FbsonKeyValue::keyid_type);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t writeNull() {
|
|
if (!stack_.empty() && verifyValueState()) {
|
|
os_->put((FbsonTypeUnder)FbsonType::T_Null);
|
|
kvState_ = WS_Value;
|
|
return sizeof(FbsonValue);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t writeBool(bool b) {
|
|
if (!stack_.empty() && verifyValueState()) {
|
|
if (b) {
|
|
os_->put((FbsonTypeUnder)FbsonType::T_True);
|
|
} else {
|
|
os_->put((FbsonTypeUnder)FbsonType::T_False);
|
|
}
|
|
|
|
kvState_ = WS_Value;
|
|
return sizeof(FbsonValue);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t writeInt8(int8_t v) {
|
|
if (!stack_.empty() && verifyValueState()) {
|
|
os_->put((FbsonTypeUnder)FbsonType::T_Int8);
|
|
os_->put(v);
|
|
kvState_ = WS_Value;
|
|
return sizeof(Int8Val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t writeInt16(int16_t v) {
|
|
if (!stack_.empty() && verifyValueState()) {
|
|
os_->put((FbsonTypeUnder)FbsonType::T_Int16);
|
|
os_->write((char*)&v, sizeof(int16_t));
|
|
kvState_ = WS_Value;
|
|
return sizeof(Int16Val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t writeInt32(int32_t v) {
|
|
if (!stack_.empty() && verifyValueState()) {
|
|
os_->put((FbsonTypeUnder)FbsonType::T_Int32);
|
|
os_->write((char*)&v, sizeof(int32_t));
|
|
kvState_ = WS_Value;
|
|
return sizeof(Int32Val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t writeInt64(int64_t v) {
|
|
if (!stack_.empty() && verifyValueState()) {
|
|
os_->put((FbsonTypeUnder)FbsonType::T_Int64);
|
|
os_->write((char*)&v, sizeof(int64_t));
|
|
kvState_ = WS_Value;
|
|
return sizeof(Int64Val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t writeDouble(double v) {
|
|
if (!stack_.empty() && verifyValueState()) {
|
|
os_->put((FbsonTypeUnder)FbsonType::T_Double);
|
|
os_->write((char*)&v, sizeof(double));
|
|
kvState_ = WS_Value;
|
|
return sizeof(DoubleVal);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// must call writeStartString before writing a string val
|
|
bool writeStartString() {
|
|
if (!stack_.empty() && verifyValueState()) {
|
|
os_->put((FbsonTypeUnder)FbsonType::T_String);
|
|
str_pos_ = os_->tellp();
|
|
|
|
// fill the size bytes with 0 for now
|
|
uint32_t size = 0;
|
|
os_->write((char*)&size, sizeof(uint32_t));
|
|
|
|
kvState_ = WS_String;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// finish writing a string val
|
|
bool writeEndString() {
|
|
if (kvState_ == WS_String) {
|
|
std::streampos cur_pos = os_->tellp();
|
|
int32_t size = (int32_t)(cur_pos - str_pos_ - sizeof(uint32_t));
|
|
assert(size >= 0);
|
|
|
|
os_->seekp(str_pos_);
|
|
os_->write((char*)&size, sizeof(uint32_t));
|
|
os_->seekp(cur_pos);
|
|
|
|
kvState_ = WS_Value;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
uint32_t writeString(const char* str, uint32_t len) {
|
|
if (kvState_ == WS_String) {
|
|
os_->write(str, len);
|
|
return len;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t writeString(char ch) {
|
|
if (kvState_ == WS_String) {
|
|
os_->put(ch);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// must call writeStartBinary before writing a binary val
|
|
bool writeStartBinary() {
|
|
if (!stack_.empty() && verifyValueState()) {
|
|
os_->put((FbsonTypeUnder)FbsonType::T_Binary);
|
|
str_pos_ = os_->tellp();
|
|
|
|
// fill the size bytes with 0 for now
|
|
uint32_t size = 0;
|
|
os_->write((char*)&size, sizeof(uint32_t));
|
|
|
|
kvState_ = WS_Binary;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// finish writing a binary val
|
|
bool writeEndBinary() {
|
|
if (kvState_ == WS_Binary) {
|
|
std::streampos cur_pos = os_->tellp();
|
|
int32_t size = (int32_t)(cur_pos - str_pos_ - sizeof(uint32_t));
|
|
assert(size >= 0);
|
|
|
|
os_->seekp(str_pos_);
|
|
os_->write((char*)&size, sizeof(uint32_t));
|
|
os_->seekp(cur_pos);
|
|
|
|
kvState_ = WS_Value;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
uint32_t writeBinary(const char* bin, uint32_t len) {
|
|
if (kvState_ == WS_Binary) {
|
|
os_->write(bin, len);
|
|
return len;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// must call writeStartObject before writing an object val
|
|
bool writeStartObject() {
|
|
if (stack_.empty() || verifyValueState()) {
|
|
if (stack_.empty()) {
|
|
// if this is a new FBSON, write the header
|
|
if (!hasHdr_) {
|
|
writeHeader();
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
os_->put((FbsonTypeUnder)FbsonType::T_Object);
|
|
// save the size position
|
|
stack_.push(WriteInfo({WS_Object, os_->tellp()}));
|
|
|
|
// fill the size bytes with 0 for now
|
|
uint32_t size = 0;
|
|
os_->write((char*)&size, sizeof(uint32_t));
|
|
|
|
kvState_ = WS_Value;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// finish writing an object val
|
|
bool writeEndObject() {
|
|
if (!stack_.empty() && stack_.top().state == WS_Object &&
|
|
kvState_ == WS_Value) {
|
|
WriteInfo& ci = stack_.top();
|
|
std::streampos cur_pos = os_->tellp();
|
|
int32_t size = (int32_t)(cur_pos - ci.sz_pos - sizeof(uint32_t));
|
|
assert(size >= 0);
|
|
|
|
os_->seekp(ci.sz_pos);
|
|
os_->write((char*)&size, sizeof(uint32_t));
|
|
os_->seekp(cur_pos);
|
|
stack_.pop();
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// must call writeStartArray before writing an array val
|
|
bool writeStartArray() {
|
|
if (stack_.empty() || verifyValueState()) {
|
|
if (stack_.empty()) {
|
|
// if this is a new FBSON, write the header
|
|
if (!hasHdr_) {
|
|
writeHeader();
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
os_->put((FbsonTypeUnder)FbsonType::T_Array);
|
|
// save the size position
|
|
stack_.push(WriteInfo({WS_Array, os_->tellp()}));
|
|
|
|
// fill the size bytes with 0 for now
|
|
uint32_t size = 0;
|
|
os_->write((char*)&size, sizeof(uint32_t));
|
|
|
|
kvState_ = WS_Value;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// finish writing an array val
|
|
bool writeEndArray() {
|
|
if (!stack_.empty() && stack_.top().state == WS_Array &&
|
|
kvState_ == WS_Value) {
|
|
WriteInfo& ci = stack_.top();
|
|
std::streampos cur_pos = os_->tellp();
|
|
int32_t size = (int32_t)(cur_pos - ci.sz_pos - sizeof(uint32_t));
|
|
assert(size >= 0);
|
|
|
|
os_->seekp(ci.sz_pos);
|
|
os_->write((char*)&size, sizeof(uint32_t));
|
|
os_->seekp(cur_pos);
|
|
stack_.pop();
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
OS_TYPE* getOutput() { return os_; }
|
|
|
|
private:
|
|
// verify we are in the right state before writing a value
|
|
bool verifyValueState() {
|
|
assert(!stack_.empty());
|
|
return (stack_.top().state == WS_Object && kvState_ == WS_Key) ||
|
|
(stack_.top().state == WS_Array && kvState_ == WS_Value);
|
|
}
|
|
|
|
// verify we are in the right state before writing a key
|
|
bool verifyKeyState() {
|
|
assert(!stack_.empty());
|
|
return stack_.top().state == WS_Object && kvState_ == WS_Value;
|
|
}
|
|
|
|
void writeHeader() {
|
|
os_->put(FBSON_VER);
|
|
hasHdr_ = true;
|
|
}
|
|
|
|
private:
|
|
enum WriteState {
|
|
WS_NONE,
|
|
WS_Array,
|
|
WS_Object,
|
|
WS_Key,
|
|
WS_Value,
|
|
WS_String,
|
|
WS_Binary,
|
|
};
|
|
|
|
struct WriteInfo {
|
|
WriteState state;
|
|
std::streampos sz_pos;
|
|
};
|
|
|
|
private:
|
|
OS_TYPE* os_;
|
|
bool alloc_;
|
|
bool hasHdr_;
|
|
WriteState kvState_; // key or value state
|
|
std::streampos str_pos_;
|
|
std::stack<WriteInfo> stack_;
|
|
};
|
|
|
|
typedef FbsonWriterT<FbsonOutStream> FbsonWriter;
|
|
|
|
} // namespace fbson
|