brpc/include/mcpack2pb/parser-inl.h
2022-12-14 19:05:52 +08:00

268 lines
8.0 KiB
C++

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// mcpack2pb - Make protobuf be front-end of mcpack/compack
// Date: Mon Oct 19 17:17:36 CST 2015
#ifndef MCPACK2PB_MCPACK_PARSER_INL_H
#define MCPACK2PB_MCPACK_PARSER_INL_H
namespace mcpack2pb {
// Binary head before items of array/object except isomorphic array.
struct ItemsHead {
uint32_t item_count;
} __attribute__((__packed__));
inline size_t InputStream::popn(size_t n) {
const size_t saved_n = n;
do {
if (_size >= (int64_t)n) {
_data = (const char*)_data + n;
_size -= n;
_popped_bytes += saved_n;
return saved_n;
}
n -= _size;
} while (_zc_stream->Next(&_data, &_size));
_data = NULL;
_size = 0;
_popped_bytes += saved_n - n;
return saved_n - n;
}
inline size_t InputStream::cutn(void* out, size_t n) {
const size_t saved_n = n;
do {
if (_size >= (int64_t)n) {
memcpy(out, _data, n);
_data = (const char*)_data + n;
_size -= n;
_popped_bytes += saved_n;
return saved_n;
}
if (_size) {
memcpy(out, _data, _size);
out = (char*)out + _size;
n -= _size;
}
} while (_zc_stream->Next(&_data, &_size));
_data = NULL;
_size = 0;
_popped_bytes += saved_n - n;
return saved_n - n;
}
template <typename T>
inline size_t InputStream::cut_packed_pod(T* packed_pod) {
if (_size >= (int)sizeof(T)) {
*packed_pod = *(T*)_data;
_data = (const char*)_data + sizeof(T);
_size -= sizeof(T);
_popped_bytes += sizeof(T);
return sizeof(T);
}
return cutn(packed_pod, sizeof(T));
}
template <typename T>
inline T InputStream::cut_packed_pod() {
T packed_pod;
if (_size >= (int)sizeof(T)) {
packed_pod = *(T*)_data;
_data = (const char*)_data + sizeof(T);
_size -= sizeof(T);
_popped_bytes += sizeof(T);
return packed_pod;
}
cutn(&packed_pod, sizeof(T));
return packed_pod;
}
inline butil::StringPiece InputStream::ref_cut(std::string* aux, size_t n) {
if (_size >= (int64_t)n) {
butil::StringPiece ret((const char*)_data, n);
_data = (const char*)_data + n;
_size -= n;
_popped_bytes += n;
return ret;
}
aux->resize(n);
size_t m = cutn(&(*aux)[0], n);
if (m != n) {
aux->resize(m);
}
return *aux;
}
inline uint8_t InputStream::peek1() {
if (_size > 0) {
return *(const uint8_t*)_data;
}
while (_zc_stream->Next(&_data, &_size)) {
if (_size > 0) {
return *(const uint8_t*)_data;
}
}
return 0;
}
// Binary head before items of isomorphic array.
struct IsoItemsHead {
uint8_t type;
} __attribute__((__packed__));
inline ObjectIterator UnparsedValue::as_object() {
return ObjectIterator(_stream, _size);
}
inline ArrayIterator UnparsedValue::as_array() {
return ArrayIterator(_stream, _size);
}
inline ISOArrayIterator UnparsedValue::as_iso_array() {
return ISOArrayIterator(_stream, _size);
}
inline void ObjectIterator::init(InputStream* stream, size_t size) {
_field_count = 0;
_stream = stream;
_expected_popped_bytes = _stream->popped_bytes() + sizeof(ItemsHead);
_expected_popped_end = _stream->popped_bytes() + size;
ItemsHead items_head;
if (_stream->cut_packed_pod(&items_head) != sizeof(ItemsHead)) {
CHECK(false) << "buffer(size=" << size << ") is not enough";
return set_bad();
}
_field_count = items_head.item_count;
operator++();
}
inline void ArrayIterator::init(InputStream* stream, size_t size) {
_item_count = 0;
_stream = stream;
_expected_popped_bytes = _stream->popped_bytes() + sizeof(ItemsHead);
_expected_popped_end = _stream->popped_bytes() + size;
ItemsHead items_head;
if (_stream->cut_packed_pod(&items_head) != sizeof(ItemsHead)) {
CHECK(false) << "buffer(size=" << size << ") is not enough";
return set_bad();
}
_item_count = items_head.item_count;
operator++();
}
inline void ISOArrayIterator::init(InputStream* stream, size_t size) {
_buf_index = 0;
_buf_count = 0;
_stream = stream;
_item_type = (PrimitiveFieldType)0;
_item_size = 0;
_item_count = 0;
_left_item_count = 0;
IsoItemsHead items_head;
if (_stream->cut_packed_pod(&items_head) != sizeof(IsoItemsHead)) {
CHECK(false) << "Not enough data";
return set_bad();
}
_item_type = (PrimitiveFieldType)items_head.type;
_item_size = get_primitive_type_size(_item_type);
if (!_item_size) {
CHECK(false) << "type=" << type2str(_item_type)
<< " in primitive isoarray is not primitive";
return set_bad();
}
const size_t items_full_size = size - sizeof(IsoItemsHead);
_item_count = items_full_size / _item_size;
if (_item_count * _item_size != items_full_size) {
CHECK(false) << "inconsistent item_count(" << _item_count
<< ") and value_size(" << items_full_size
<< "), item_size=" << _item_size;
return set_bad();
}
_left_item_count = _item_count;
operator++();
}
inline void ISOArrayIterator::operator++() {
if (_buf_index + 1 < _buf_count) {
++_buf_index;
return;
}
// Iterate all items in isomorphic array. We have to do this
// right here because the items are lacking of headings.
// Call on_primitives in batch to reduce overhead.
if (_left_item_count == 0) {
set_end();
return;
}
_buf_count = std::min((uint32_t)sizeof(_item_buf) / _item_size, _left_item_count);
_buf_index = 0;
if (_stream->cutn(_item_buf, _buf_count * _item_size) !=
_buf_count * _item_size) {
CHECK(false) << "Not enough data";
return set_bad();
}
_left_item_count -= _buf_count;
}
template <typename T>
inline T ISOArrayIterator::as_integer() const {
const void* ptr = (_item_buf + _buf_index * _item_size);
switch ((PrimitiveFieldType)_item_type) {
case PRIMITIVE_FIELD_INT8:
return *static_cast<const int8_t*>(ptr);
case PRIMITIVE_FIELD_INT16:
return *static_cast<const int16_t*>(ptr);
case PRIMITIVE_FIELD_INT32:
return *static_cast<const int32_t*>(ptr);
case PRIMITIVE_FIELD_INT64:
return *static_cast<const int64_t*>(ptr);
case PRIMITIVE_FIELD_UINT8:
return *static_cast<const uint8_t*>(ptr);
case PRIMITIVE_FIELD_UINT16:
return *static_cast<const uint16_t*>(ptr);
case PRIMITIVE_FIELD_UINT32:
return *static_cast<const uint32_t*>(ptr);
case PRIMITIVE_FIELD_UINT64:
return *static_cast<const uint64_t*>(ptr);
case PRIMITIVE_FIELD_BOOL:
return *static_cast<const bool*>(ptr);
case PRIMITIVE_FIELD_FLOAT:
return 0;
case PRIMITIVE_FIELD_DOUBLE:
return 0;
}
return 0;
}
template <typename T>
inline T ISOArrayIterator::as_fp() const {
const void* ptr = (_item_buf + _buf_index * _item_size);
if (_item_type == PRIMITIVE_FIELD_FLOAT) {
return *static_cast<const float*>(ptr);
} else if (_item_type == PRIMITIVE_FIELD_DOUBLE) {
return *static_cast<const double*>(ptr);
}
return T();
}
} // namespace mcpack2pb
#endif // MCPACK2PB_MCPACK_PARSER_INL_H