rocksdb/thrift/lib/cpp/protocol/neutronium/Decoder.h
Dhruba Borthakur 80c663882a Create leveldb server via Thrift.
Summary:
First draft.
Unit tests pass.

Test Plan: unit tests attached

Reviewers: heyongqiang

Reviewed By: heyongqiang

Differential Revision: https://reviews.facebook.net/D3969
2012-07-07 09:42:39 -07:00

240 lines
6.0 KiB
C++

/**
* Copyright 2012 Facebook
* @author Tudor Bosman (tudorb@fb.com)
*/
#ifndef THRIFT_LIB_CPP_PROTOCOL_NEUTRONIUM_DECODER_H_
#define THRIFT_LIB_CPP_PROTOCOL_NEUTRONIUM_DECODER_H_
#include "thrift/lib/cpp/protocol/neutronium/Utils.h"
#include "thrift/lib/cpp/protocol/neutronium/InternTable.h"
#include "thrift/lib/cpp/protocol/neutronium/Schema.h"
#include "thrift/lib/cpp/protocol/TProtocol.h"
#include "folly/FBString.h"
#include "folly/Range.h"
#include "folly/small_vector.h"
#include "folly/experimental/io/Cursor.h"
namespace apache {
namespace thrift {
namespace protocol {
namespace neutronium {
class Decoder {
public:
explicit Decoder(const Schema* schema, const InternTable* internTable,
folly::IOBuf* buf);
void setRootType(int64_t type);
void readStructBegin();
void readStructEnd();
void readFieldBegin(TType& fieldType, int16_t& fieldId);
void readFieldEnd();
void readMapBegin(TType& keyType, TType& valType, uint32_t& size);
void readMapEnd();
void readListBegin(TType& elemType, uint32_t& size);
void readListEnd();
void readSetBegin(TType& elemType, uint32_t& size);
void readSetEnd();
void readBool(bool& value);
void readByte(int8_t& value);
void readI16(int16_t& value);
void readI32(int32_t& i32);
void readI64(int64_t& i64);
void readDouble(double& dub);
template <typename StrType>
void readString(StrType& str);
void readBinary(std::string& str) {
readString(str);
}
size_t bytesRead() const {
return bytesRead_;
}
private:
bool beginReadString(); // returns true if interned
const Schema* schema_;
const InternTable* internTable_;
folly::io::RWPrivateCursor cursor_;
int64_t rootType_;
enum State {
IN_STRUCT,
IN_FIELD,
IN_MAP_KEY,
IN_MAP_VALUE,
IN_LIST_VALUE,
IN_SET_VALUE,
};
static const int64_t kVariableLength = -1;
static const int64_t kTerminated = -2;
struct TypeInfo {
TypeInfo()
: typeVal(reflection::TYPE_VOID),
length(kVariableLength),
dataType(nullptr),
terminator('\0') { }
TypeInfo(const Schema* schema, int64_t t);
/* implicit */ TypeInfo(int64_t t);
reflection::Type type() const {
return reflection::getType(typeVal);
}
TType ttype() const {
return toTType(type());
}
int64_t typeVal;
int64_t length;
const DataType* dataType;
char terminator;
};
static const size_t kIntInline = 8;
static const size_t kInt64Inline = 8;
static const size_t kByteInline = 8;
static const size_t kFixedInt16Inline = 8;
static const size_t kFixedInt32Inline = 8;
static const size_t kFixedInt64Inline = 8;
static const size_t kBoolInline = 8;
static const size_t kStringInline = 8;
struct DecoderState {
DecoderState(const Schema* schema, int64_t type,
const DataType* dataType, uint32_t size);
DecoderState(DecoderState&&) = default;
DecoderState& operator=(DecoderState&&) = default;
enum FieldState {
FS_START,
FS_INT,
FS_INT64,
FS_BYTE,
FS_BOOL,
FS_STRICT_ENUM,
FS_INTERNED_STRING,
FS_STRING,
FS_END
};
const DataType* dataType;
State state;
TypeInfo type;
size_t bytesRead;
struct TypeStateBase {
TypeStateBase() : count(0), index(-1) { }
size_t count;
ssize_t index;
};
template <class T, size_t kInlineCount=8>
struct TypeState : public TypeStateBase {
folly::small_vector<T, kInlineCount> values;
};
TypeState<uint32_t> ints; // int16_t, int32_t
TypeState<uint64_t> int64s; // int64_t, double
TypeState<uint8_t> bytes; // int8_t
size_t boolStartBit; // offset of first bit from bools in bools.values
TypeState<uint8_t, byteCount(8)> bools; // bool
TypeState<uint32_t> strictEnums;
size_t totalStrictEnumBits;
TypeState<uint32_t> vars; // variable-length
TypeState<folly::StringPiece> internedStrings;
TypeStateBase strings; // non-interned strings and user-defined types
// TODO(tudorb): Make Struct and List into a union, but as these types are
// non-POD, the union would have a deleted copy/move constructor,
// copy/move assignment operator, and destructor, which meanns that
// DecoderState would have to have them user-defined in order to insert
// DecoderState in containers, bleh.
typedef
folly::small_vector<std::pair<int16_t, reflection::Type>, 8>
TagVec;
typedef
folly::small_vector<std::pair<int16_t, TypeInfo>, 8>
FullTagVec;
struct Struct {
FieldState fieldState;
int16_t tag;
TagVec intTags;
TagVec int64Tags;
TagVec byteTags;
TagVec boolTags;
FullTagVec strictEnumTags;
FullTagVec stringTags;
FullTagVec internedStringTags;
TagVec fixedInt16Tags;
TagVec fixedInt32Tags;
TagVec fixedInt64Tags;
} str;
struct List {
uint32_t remaining;
TypeInfo mapKeyType;
TypeInfo valueType;
} list;
template <typename T>
void setStateList(T& ts);
template <typename TS, typename TV>
bool setStateStruct(TS& ts, const TV& tv, FieldState nextState);
bool nextField();
void nextValue();
void addType(TypeInfo& tinfo,
const StructField& field, int16_t tag, uint32_t count);
private:
void setLength();
void nextList();
bool nextStruct();
};
size_t bytesRead_;
static const size_t kStackInline = 8;
folly::small_vector<DecoderState, kStackInline> stack_;
void readBoolsAndStrictEnums(size_t skipBits);
void read();
void push(reflection::Type expected, int64_t type, uint32_t size);
void pop();
DecoderState& top();
uint32_t peekElementCount();
int64_t nextType();
std::pair<const uint8_t*, size_t> ensure(size_t n);
};
} // namespace neutronium
} // namespace protocol
} // namespace thrift
} // namespace apache
#define THRIFT_INCLUDE_DECODER_INL
#include "thrift/lib/cpp/protocol/neutronium/Decoder-inl.h"
#undef THRIFT_INCLUDE_DECODER_INL
#endif /* THRIFT_LIB_CPP_PROTOCOL_NEUTRONIUM_DECODER_H_ */