Upgrade to protozero 1.7.1 (#5)

* Upgrade to protozero 1.7.1

* Bump version number
This commit is contained in:
Erica Fischer
2022-09-13 11:24:01 -07:00
committed by GitHub
parent 073700aa38
commit 8e46650da7
19 changed files with 2650 additions and 1387 deletions
+95 -70
View File
@@ -16,21 +16,23 @@ documentation.
* @brief Contains the pbf_reader class.
*/
#include <cstddef>
#include <cstdint>
#include <string>
#include <utility>
#include <protozero/config.hpp>
#include <protozero/exception.hpp>
#include <protozero/iterators.hpp>
#include <protozero/types.hpp>
#include <protozero/varint.hpp>
#include "config.hpp"
#include "data_view.hpp"
#include "exception.hpp"
#include "iterators.hpp"
#include "types.hpp"
#include "varint.hpp"
#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
# include <protozero/byteswap.hpp>
#endif
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#include <utility>
namespace protozero {
/**
@@ -41,13 +43,13 @@ namespace protozero {
* @code
* std::string buffer;
* // fill buffer...
* pbf_reader message(buffer.data(), buffer.size());
* pbf_reader message{buffer.data(), buffer.size()};
* @endcode
*
* Sub-messages are created using get_message():
*
* @code
* pbf_reader message(...);
* pbf_reader message{...};
* message.next();
* pbf_reader submessage = message.get_message();
* @endcode
@@ -74,10 +76,11 @@ class pbf_reader {
template <typename T>
T get_fixed() {
T result;
const char* data = m_data;
skip_bytes(sizeof(T));
std::memcpy(&result, m_data - sizeof(T), sizeof(T));
std::memcpy(&result, data, sizeof(T));
#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
detail::byteswap_inplace(&result);
byteswap_inplace(&result);
#endif
return result;
}
@@ -86,14 +89,17 @@ class pbf_reader {
iterator_range<const_fixed_iterator<T>> packed_fixed() {
protozero_assert(tag() != 0 && "call next() before accessing field value");
const auto len = get_len_and_skip();
protozero_assert(len % sizeof(T) == 0);
return iterator_range<const_fixed_iterator<T>>{const_fixed_iterator<T>(m_data - len, m_data),
const_fixed_iterator<T>(m_data, m_data)};
if (len % sizeof(T) != 0) {
throw invalid_length_exception{};
}
return {const_fixed_iterator<T>(m_data - len),
const_fixed_iterator<T>(m_data)};
}
template <typename T>
T get_varint() {
return static_cast<T>(decode_varint(&m_data, m_end));
const auto val = static_cast<T>(decode_varint(&m_data, m_end));
return val;
}
template <typename T>
@@ -107,14 +113,14 @@ class pbf_reader {
}
void skip_bytes(pbf_length_type len) {
if (m_data + len > m_end) {
throw end_of_buffer_exception();
if (m_end - m_data < static_cast<ptrdiff_t>(len)) {
throw end_of_buffer_exception{};
}
m_data += len;
// In debug builds reset the tag to zero so that we can detect (some)
// wrong code.
#ifndef NDEBUG
// In debug builds reset the tag to zero so that we can detect (some)
// wrong code.
m_tag = 0;
#endif
}
@@ -129,8 +135,8 @@ class pbf_reader {
iterator_range<T> get_packed() {
protozero_assert(tag() != 0 && "call next() before accessing field value");
const auto len = get_len_and_skip();
return iterator_range<T>{T{m_data - len, m_data},
T{m_data, m_data}};
return {T{m_data - len, m_data},
T{m_data, m_data}};
}
public:
@@ -146,10 +152,8 @@ public:
* @post There is no current field.
*/
explicit pbf_reader(const data_view& view) noexcept
: m_data(view.data()),
m_end(view.data() + view.size()),
m_wire_type(pbf_wire_type::unknown),
m_tag(0) {
: m_data{view.data()},
m_end{view.data() + view.size()} {
}
/**
@@ -163,12 +167,11 @@ public:
* @post There is no current field.
*/
pbf_reader(const char* data, std::size_t size) noexcept
: m_data(data),
m_end(data + size),
m_wire_type(pbf_wire_type::unknown),
m_tag(0) {
: m_data{data},
m_end{data + size} {
}
#ifndef PROTOZERO_STRICT_API
/**
* Construct a pbf_reader message from a data pointer and a length. The
* pointer will be stored inside the pbf_reader object, no data is copied.
@@ -178,13 +181,13 @@ public:
* The buffer must contain a complete protobuf message.
*
* @post There is no current field.
* @deprecated Use one of the other constructors.
*/
explicit pbf_reader(const std::pair<const char*, std::size_t>& data) noexcept
: m_data(data.first),
m_end(data.first + data.second),
m_wire_type(pbf_wire_type::unknown),
m_tag(0) {
: m_data{data.first},
m_end{data.first + data.second} {
}
#endif
/**
* Construct a pbf_reader message from a std::string. A pointer to the
@@ -197,10 +200,8 @@ public:
* @post There is no current field.
*/
explicit pbf_reader(const std::string& data) noexcept
: m_data(data.data()),
m_end(data.data() + data.size()),
m_wire_type(pbf_wire_type::unknown),
m_tag(0) {
: m_data{data.data()},
m_end{data.data() + data.size()} {
}
/**
@@ -241,8 +242,15 @@ public:
* are still fields available and to `false` if the last field has been
* read.
*/
operator bool() const noexcept {
return m_data < m_end;
operator bool() const noexcept { // NOLINT(google-explicit-constructor, hicpp-explicit-conversions)
return m_data != m_end;
}
/**
* Get a view of the not yet read data.
*/
data_view data() const noexcept {
return {m_data, static_cast<std::size_t>(m_end - m_data)};
}
/**
@@ -279,14 +287,15 @@ public:
}
const auto value = get_varint<uint32_t>();
m_tag = pbf_tag_type(value >> 3);
m_tag = pbf_tag_type(value >> 3U);
// tags 0 and 19000 to 19999 are not allowed as per
// https://developers.google.com/protocol-buffers/docs/proto
protozero_assert(((m_tag > 0 && m_tag < 19000) ||
(m_tag > 19999 && m_tag <= ((1 << 29) - 1))) && "tag out of range");
// https://developers.google.com/protocol-buffers/docs/proto#assigning-tags
if (m_tag == 0 || (m_tag >= 19000 && m_tag <= 19999)) {
throw invalid_tag_exception{};
}
m_wire_type = pbf_wire_type(value & 0x07);
m_wire_type = pbf_wire_type(value & 0x07U);
switch (m_wire_type) {
case pbf_wire_type::varint:
case pbf_wire_type::fixed64:
@@ -294,7 +303,7 @@ public:
case pbf_wire_type::fixed32:
break;
default:
throw unknown_pbf_wire_type_exception();
throw unknown_pbf_wire_type_exception{};
}
return true;
@@ -306,7 +315,7 @@ public:
* loop for repeated fields:
*
* @code
* pbf_reader message(...);
* pbf_reader message{...};
* while (message.next(17)) {
* // handle field
* }
@@ -315,7 +324,7 @@ public:
* or you can call it just once to get the one field with this tag:
*
* @code
* pbf_reader message(...);
* pbf_reader message{...};
* if (message.next(17)) {
* // handle field
* }
@@ -332,9 +341,8 @@ public:
while (next()) {
if (m_tag == next_tag) {
return true;
} else {
skip();
}
skip();
}
return false;
}
@@ -345,7 +353,7 @@ public:
* called in a while loop for repeated fields:
*
* @code
* pbf_reader message(...);
* pbf_reader message{...};
* while (message.next(17, pbf_wire_type::varint)) {
* // handle field
* }
@@ -354,7 +362,7 @@ public:
* or you can call it just once to get the one field with this tag:
*
* @code
* pbf_reader message(...);
* pbf_reader message{...};
* if (message.next(17, pbf_wire_type::varint)) {
* // handle field
* }
@@ -371,9 +379,8 @@ public:
while (next()) {
if (m_tag == next_tag && m_wire_type == type) {
return true;
} else {
skip();
}
skip();
}
return false;
}
@@ -417,7 +424,7 @@ public:
* Use it like this:
*
* @code
* pbf_reader message(...);
* pbf_reader message{...};
* while (message.next()) {
* switch (message.tag_and_type()) {
* case tag_and_type(17, pbf_wire_type::length_delimited):
@@ -468,7 +475,7 @@ public:
skip_bytes(4);
break;
default:
protozero_assert(false && "can not be here because next() should have thrown already");
break;
}
}
@@ -487,9 +494,9 @@ public:
bool get_bool() {
protozero_assert(tag() != 0 && "call next() before accessing field value");
protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
protozero_assert((*m_data & 0x80) == 0 && "not a 1 byte varint");
skip_bytes(1);
return m_data[-1] != 0; // -1 okay because we incremented m_data the line before
const bool result = m_data[0] != 0;
skip_varint(&m_data, m_end);
return result;
}
/**
@@ -667,7 +674,7 @@ public:
protozero_assert(tag() != 0 && "call next() before accessing field value");
protozero_assert(has_wire_type(pbf_wire_type::length_delimited) && "not of type string, bytes or message");
const auto len = get_len_and_skip();
return data_view{m_data - len, len};
return {m_data - len, len};
}
#ifndef PROTOZERO_STRICT_API
@@ -683,7 +690,7 @@ public:
protozero_assert(tag() != 0 && "call next() before accessing field value");
protozero_assert(has_wire_type(pbf_wire_type::length_delimited) && "not of type string, bytes or message");
const auto len = get_len_and_skip();
return std::make_pair(m_data - len, len);
return {m_data - len, len};
}
#endif
@@ -717,7 +724,7 @@ public:
* @post The current field was consumed and there is no current field now.
*/
pbf_reader get_message() {
return pbf_reader(get_view());
return pbf_reader{get_view()};
}
///@}
@@ -746,6 +753,24 @@ public:
/// Forward iterator for iterating over uint64 (varint) values.
using const_uint64_iterator = const_varint_iterator<uint64_t>;
/// Forward iterator for iterating over fixed32 values.
using const_fixed32_iterator = const_fixed_iterator<uint32_t>;
/// Forward iterator for iterating over sfixed32 values.
using const_sfixed32_iterator = const_fixed_iterator<int32_t>;
/// Forward iterator for iterating over fixed64 values.
using const_fixed64_iterator = const_fixed_iterator<uint64_t>;
/// Forward iterator for iterating over sfixed64 values.
using const_sfixed64_iterator = const_fixed_iterator<int64_t>;
/// Forward iterator for iterating over float values.
using const_float_iterator = const_fixed_iterator<float>;
/// Forward iterator for iterating over double values.
using const_double_iterator = const_fixed_iterator<double>;
///@{
/**
* @name Repeated packed field accessor functions
@@ -864,7 +889,7 @@ public:
* @pre The current field must be of type "repeated packed fixed32".
* @post The current field was consumed and there is no current field now.
*/
auto get_packed_fixed32() -> decltype(packed_fixed<uint32_t>()) {
iterator_range<pbf_reader::const_fixed32_iterator> get_packed_fixed32() {
return packed_fixed<uint32_t>();
}
@@ -877,7 +902,7 @@ public:
* @pre The current field must be of type "repeated packed sfixed32".
* @post The current field was consumed and there is no current field now.
*/
auto get_packed_sfixed32() -> decltype(packed_fixed<int32_t>()) {
iterator_range<pbf_reader::const_sfixed32_iterator> get_packed_sfixed32() {
return packed_fixed<int32_t>();
}
@@ -890,7 +915,7 @@ public:
* @pre The current field must be of type "repeated packed fixed64".
* @post The current field was consumed and there is no current field now.
*/
auto get_packed_fixed64() -> decltype(packed_fixed<uint64_t>()) {
iterator_range<pbf_reader::const_fixed64_iterator> get_packed_fixed64() {
return packed_fixed<uint64_t>();
}
@@ -903,7 +928,7 @@ public:
* @pre The current field must be of type "repeated packed sfixed64".
* @post The current field was consumed and there is no current field now.
*/
auto get_packed_sfixed64() -> decltype(packed_fixed<int64_t>()) {
iterator_range<pbf_reader::const_sfixed64_iterator> get_packed_sfixed64() {
return packed_fixed<int64_t>();
}
@@ -916,7 +941,7 @@ public:
* @pre The current field must be of type "repeated packed float".
* @post The current field was consumed and there is no current field now.
*/
auto get_packed_float() -> decltype(packed_fixed<float>()) {
iterator_range<pbf_reader::const_float_iterator> get_packed_float() {
return packed_fixed<float>();
}
@@ -929,7 +954,7 @@ public:
* @pre The current field must be of type "repeated packed double".
* @post The current field was consumed and there is no current field now.
*/
auto get_packed_double() -> decltype(packed_fixed<double>()) {
iterator_range<pbf_reader::const_double_iterator> get_packed_double() {
return packed_fixed<double>();
}