hessian2/basic_codec/list_codec.cc (197 lines of code) (raw):
#include "hessian2/basic_codec/list_codec.hpp"
namespace Hessian2 {
// # typed list/vector
// ::= x55 type value* 'Z' # variable-length list
// ::= 'V' type int value* # fixed-length list
// ::= [x70-77] type value* # fixed-length typed list
template <>
std::unique_ptr<TypedListObject> Decoder::decode() {
std::string type;
Object::TypedList obj_list;
auto result = std::make_unique<TypedListObject>();
values_ref_.push_back(result.get());
auto ret = reader_->read<uint8_t>();
if (!ret.first) {
return nullptr;
}
auto code = ret.second;
auto ReadNumsObject = [&](int nums) -> bool {
for (int i = 0; i < nums; i++) {
auto o = decode<Object>();
if (!o) {
return false;
}
obj_list.values_.emplace_back(std::move(o));
}
return true;
};
auto ReadObjectUntilEnd = [&]() -> bool {
auto ret = reader_->peek<uint8_t>();
if (!ret.first) {
return false;
}
while (ret.second != 'Z') {
auto o = decode<Object>();
if (!o) {
return false;
}
obj_list.values_.emplace_back(std::move(o));
ret = reader_->peek<uint8_t>();
if (!ret.first) {
return false;
}
}
// Skip last 'Z'
reader_->read<uint8_t>();
return true;
};
auto type_str = decode<Object::TypeRef>();
if (!type_str) {
return nullptr;
}
obj_list.type_name_ = std::move(type_str->type_);
switch (code) {
case 0x55: {
if (!ReadObjectUntilEnd()) {
return nullptr;
}
break;
}
case 'V': {
auto ret = decode<int32_t>();
if (!ret) {
return nullptr;
}
if (!ReadNumsObject(*ret)) {
return nullptr;
}
break;
}
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x76:
case 0x77: {
if (!ReadNumsObject(code - 0x70)) {
return nullptr;
}
break;
}
default:
return nullptr;
}
result->setTypedList(std::move(obj_list));
return result;
}
// ::= x57 value* 'Z' # variable-length untyped list
// ::= x58 int value* # fixed-length untyped list
// ::= [x78-7f] value* # fixed-length untyped list
template <>
std::unique_ptr<UntypedListObject> Decoder::decode() {
Object::UntypedList obj_list;
auto result = std::make_unique<UntypedListObject>();
values_ref_.push_back(result.get());
auto ret = reader_->read<uint8_t>();
if (!ret.first) {
return nullptr;
}
auto code = ret.second;
auto ReadNumsObject = [&](int nums) -> bool {
for (int i = 0; i < nums; i++) {
auto o = decode<Object>();
if (!o) {
return false;
}
obj_list.emplace_back(std::move(o));
}
return true;
};
auto ReadObjectUntilEnd = [&]() -> bool {
auto ret = reader_->peek<uint8_t>();
if (!ret.first) {
return false;
}
while (ret.second != 'Z') {
auto o = decode<Object>();
if (!o) {
return false;
}
obj_list.emplace_back(std::move(o));
ret = reader_->peek<uint8_t>();
if (!ret.first) {
return false;
}
}
// Skip last 'Z'
reader_->read<uint8_t>();
return true;
};
switch (code) {
case 0x57: {
if (!ReadObjectUntilEnd()) {
return nullptr;
}
break;
}
case 0x58: {
auto ret = decode<int32_t>();
if (!ret) {
return nullptr;
}
if (!ReadNumsObject(*ret)) {
return nullptr;
}
break;
}
case 0x78:
case 0x79:
case 0x7a:
case 0x7b:
case 0x7c:
case 0x7d:
case 0x7e:
case 0x7f: {
if (!ReadNumsObject(code - 0x78)) {
return nullptr;
}
break;
}
}
result->setUntypedList(std::move(obj_list));
return result;
}
template <>
bool Encoder::encode(const TypedListObject& value) {
values_ref_.emplace(&value, values_ref_.size());
auto typed_list = value.toTypedList();
ABSL_ASSERT(typed_list.has_value());
auto& typed_list_value = typed_list.value().get();
Object::TypeRef type_ref(typed_list_value.type_name_);
auto len = typed_list_value.values_.size();
if (len <= 7) {
writer_->writeByte(static_cast<uint8_t>(0x70 + len));
} else {
writer_->writeByte('V');
}
encode<Object::TypeRef>(type_ref);
if (len > 7) {
encode<int32_t>(len);
}
for (size_t i = 0; i < len; i++) {
encode<Object>(*typed_list_value.values_[i]);
}
return true;
}
template <>
bool Encoder::encode(const UntypedListObject& value) {
values_ref_.emplace(&value, values_ref_.size());
auto untyped_list = value.toUntypedList();
ABSL_ASSERT(untyped_list.has_value());
auto& untyped_list_value = untyped_list.value().get();
auto len = untyped_list_value.size();
if (len <= 7) {
writer_->writeByte(static_cast<uint8_t>(0x78 + len));
} else {
writer_->writeByte(static_cast<uint8_t>(0x58));
encode<int32_t>(len);
}
for (size_t i = 0; i < len; i++) {
encode<Object>(*(untyped_list_value)[i]);
}
return true;
}
} // namespace Hessian2