Merge commit '879f7eb04200d7d2c28af565229bf6e3d54274fd' into retry/libosmium
This commit is contained in:
+3
-3
@@ -28,7 +28,7 @@ namespace protozero {
|
||||
* be specialized to actually work.
|
||||
*/
|
||||
template <int N>
|
||||
inline void byteswap(const char* /*data*/, char* /*result*/) {
|
||||
inline void byteswap(const char* /*data*/, char* /*result*/) noexcept {
|
||||
static_assert(N == 1, "Can only swap 4 or 8 byte values");
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ inline void byteswap(const char* /*data*/, char* /*result*/) {
|
||||
* Swap 4 byte value (int32_t, uint32_t, float) between endianness formats.
|
||||
*/
|
||||
template <>
|
||||
inline void byteswap<4>(const char* data, char* result) {
|
||||
inline void byteswap<4>(const char* data, char* result) noexcept {
|
||||
#ifdef PROTOZERO_USE_BUILTIN_BSWAP
|
||||
*reinterpret_cast<uint32_t*>(result) = __builtin_bswap32(*reinterpret_cast<const uint32_t*>(data));
|
||||
#else
|
||||
@@ -51,7 +51,7 @@ inline void byteswap<4>(const char* data, char* result) {
|
||||
* Swap 8 byte value (int64_t, uint64_t, double) between endianness formats.
|
||||
*/
|
||||
template <>
|
||||
inline void byteswap<8>(const char* data, char* result) {
|
||||
inline void byteswap<8>(const char* data, char* result) noexcept {
|
||||
#ifdef PROTOZERO_USE_BUILTIN_BSWAP
|
||||
*reinterpret_cast<uint64_t*>(result) = __builtin_bswap64(*reinterpret_cast<const uint64_t*>(data));
|
||||
#else
|
||||
|
||||
+4
-4
@@ -29,7 +29,7 @@ namespace protozero {
|
||||
*/
|
||||
struct exception : std::exception {
|
||||
/// Returns the explanatory string.
|
||||
const char *what() const noexcept override { return "pbf exception"; }
|
||||
const char* what() const noexcept override { return "pbf exception"; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -38,7 +38,7 @@ struct exception : std::exception {
|
||||
*/
|
||||
struct varint_too_long_exception : exception {
|
||||
/// Returns the explanatory string.
|
||||
const char *what() const noexcept override { return "varint too long exception"; }
|
||||
const char* what() const noexcept override { return "varint too long exception"; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ struct varint_too_long_exception : exception {
|
||||
*/
|
||||
struct unknown_pbf_wire_type_exception : exception {
|
||||
/// Returns the explanatory string.
|
||||
const char *what() const noexcept override { return "unknown pbf field type exception"; }
|
||||
const char* what() const noexcept override { return "unknown pbf field type exception"; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -60,7 +60,7 @@ struct unknown_pbf_wire_type_exception : exception {
|
||||
*/
|
||||
struct end_of_buffer_exception : exception {
|
||||
/// Returns the explanatory string.
|
||||
const char *what() const noexcept override { return "end of buffer exception"; }
|
||||
const char* what() const noexcept override { return "end of buffer exception"; }
|
||||
};
|
||||
|
||||
} // end namespace protozero
|
||||
|
||||
@@ -0,0 +1,373 @@
|
||||
#ifndef PROTOZERO_ITERATORS_HPP
|
||||
#define PROTOZERO_ITERATORS_HPP
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
protozero - Minimalistic protocol buffer decoder and encoder in C++.
|
||||
|
||||
This file is from https://github.com/mapbox/protozero where you can find more
|
||||
documentation.
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file iterators.hpp
|
||||
*
|
||||
* @brief Contains the iterators for access to packed repeated fields.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
#include <protozero/config.hpp>
|
||||
#include <protozero/varint.hpp>
|
||||
|
||||
#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
|
||||
# include <protozero/byteswap.hpp>
|
||||
#endif
|
||||
|
||||
namespace protozero {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Copy N bytes from src to dest on little endian machines, on big
|
||||
// endian swap the bytes in the process.
|
||||
template <int N>
|
||||
inline void copy_or_byteswap(const char* src, void* dest) noexcept {
|
||||
#if PROTOZERO_BYTE_ORDER == PROTOZERO_LITTLE_ENDIAN
|
||||
std::memcpy(dest, src, N);
|
||||
#else
|
||||
byteswap<N>(src, reinterpret_cast<char*>(dest));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
/**
|
||||
* A range of iterators based on std::pair. Created from beginning and
|
||||
* end iterators. Used as a return type from some pbf_reader methods
|
||||
* that is easy to use with range-based for loops.
|
||||
*/
|
||||
template <typename T, typename P = std::pair<T, T>>
|
||||
class iterator_range :
|
||||
#ifdef PROTOZERO_STRICT_API
|
||||
protected
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
P {
|
||||
|
||||
public:
|
||||
|
||||
/// The type of the iterators in this range.
|
||||
using iterator = T;
|
||||
|
||||
/// The value type of the underlying iterator.
|
||||
using value_type = typename std::iterator_traits<T>::value_type;
|
||||
|
||||
/**
|
||||
* Default constructor. Create empty iterator_range.
|
||||
*/
|
||||
constexpr iterator_range() :
|
||||
P(iterator{}, iterator{}) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create iterator range from two iterators.
|
||||
*
|
||||
* @param first_iterator Iterator to beginning or range.
|
||||
* @param last_iterator Iterator to end or range.
|
||||
*/
|
||||
constexpr iterator_range(iterator&& first_iterator, iterator&& last_iterator) :
|
||||
P(std::forward<iterator>(first_iterator),
|
||||
std::forward<iterator>(last_iterator)) {
|
||||
}
|
||||
|
||||
/// Return iterator to beginning of range.
|
||||
constexpr iterator begin() const noexcept {
|
||||
return this->first;
|
||||
}
|
||||
|
||||
/// Return iterator to end of range.
|
||||
constexpr iterator end() const noexcept {
|
||||
return this->second;
|
||||
}
|
||||
|
||||
/// Return iterator to beginning of range.
|
||||
constexpr iterator cbegin() const noexcept {
|
||||
return this->first;
|
||||
}
|
||||
|
||||
/// Return iterator to end of range.
|
||||
constexpr iterator cend() const noexcept {
|
||||
return this->second;
|
||||
}
|
||||
|
||||
/// Return true if this range is empty.
|
||||
constexpr std::size_t empty() const noexcept {
|
||||
return begin() == end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get element at the beginning of the range.
|
||||
*
|
||||
* @pre Range must not be empty.
|
||||
*/
|
||||
value_type front() const {
|
||||
protozero_assert(!empty());
|
||||
return *(this->first);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance beginning of range by one.
|
||||
*
|
||||
* @pre Range must not be empty.
|
||||
*/
|
||||
void drop_front() {
|
||||
protozero_assert(!empty());
|
||||
++this->first;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap the contents of this range with the other.
|
||||
*
|
||||
* @param other Other range to swap data with.
|
||||
*/
|
||||
void swap(iterator_range& other) noexcept {
|
||||
using std::swap;
|
||||
swap(this->first, other.first);
|
||||
swap(this->second, other.second);
|
||||
}
|
||||
|
||||
}; // struct iterator_range
|
||||
|
||||
/**
|
||||
* Swap two iterator_ranges.
|
||||
*
|
||||
* @param lhs First range.
|
||||
* @param rhs Second range.
|
||||
*/
|
||||
template <typename T>
|
||||
inline void swap(iterator_range<T>& lhs, iterator_range<T>& rhs) noexcept {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
#ifdef PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED
|
||||
|
||||
template <typename T>
|
||||
using const_fixed_iterator = const T*;
|
||||
|
||||
/**
|
||||
* Create iterator_range from char pointers to beginning and end of range.
|
||||
*
|
||||
* @param first Beginning of range.
|
||||
* @param last End of range.
|
||||
*/
|
||||
template <typename T>
|
||||
inline iterator_range<const_fixed_iterator<T>> create_fixed_iterator_range(const char* first, const char* last) {
|
||||
return iterator_range<const_fixed_iterator<T>>{reinterpret_cast<const T*>(first),
|
||||
reinterpret_cast<const T*>(last)};
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
* A forward iterator used for accessing packed repeated fields of fixed
|
||||
* length (fixed32, sfixed32, float, double).
|
||||
*/
|
||||
template <typename T>
|
||||
class const_fixed_iterator {
|
||||
|
||||
/// Pointer to current iterator position
|
||||
const char* m_data;
|
||||
|
||||
/// Pointer to end iterator position
|
||||
const char* m_end;
|
||||
|
||||
public:
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = T;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
const_fixed_iterator() noexcept :
|
||||
m_data(nullptr),
|
||||
m_end(nullptr) {
|
||||
}
|
||||
|
||||
const_fixed_iterator(const char* data, const char* end) noexcept :
|
||||
m_data(data),
|
||||
m_end(end) {
|
||||
}
|
||||
|
||||
const_fixed_iterator(const const_fixed_iterator&) noexcept = default;
|
||||
const_fixed_iterator(const_fixed_iterator&&) noexcept = default;
|
||||
|
||||
const_fixed_iterator& operator=(const const_fixed_iterator&) noexcept = default;
|
||||
const_fixed_iterator& operator=(const_fixed_iterator&&) noexcept = default;
|
||||
|
||||
~const_fixed_iterator() noexcept = default;
|
||||
|
||||
value_type operator*() const {
|
||||
value_type result;
|
||||
detail::copy_or_byteswap<sizeof(value_type)>(m_data , &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
const_fixed_iterator& operator++() {
|
||||
m_data += sizeof(value_type);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_fixed_iterator operator++(int) {
|
||||
const const_fixed_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const const_fixed_iterator& rhs) const noexcept {
|
||||
return m_data == rhs.m_data && m_end == rhs.m_end;
|
||||
}
|
||||
|
||||
bool operator!=(const const_fixed_iterator& rhs) const noexcept {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
}; // class const_fixed_iterator
|
||||
|
||||
/**
|
||||
* Create iterator_range from char pointers to beginning and end of range.
|
||||
*
|
||||
* @param first Beginning of range.
|
||||
* @param last End of range.
|
||||
*/
|
||||
template <typename T>
|
||||
inline iterator_range<const_fixed_iterator<T>> create_fixed_iterator_range(const char* first, const char* last) {
|
||||
return iterator_range<const_fixed_iterator<T>>{const_fixed_iterator<T>(first, last),
|
||||
const_fixed_iterator<T>(last, last)};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A forward iterator used for accessing packed repeated varint fields
|
||||
* (int32, uint32, int64, uint64, bool, enum).
|
||||
*/
|
||||
template <typename T>
|
||||
class const_varint_iterator {
|
||||
|
||||
protected:
|
||||
|
||||
/// Pointer to current iterator position
|
||||
const char* m_data;
|
||||
|
||||
/// Pointer to end iterator position
|
||||
const char* m_end;
|
||||
|
||||
public:
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = T;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
const_varint_iterator() noexcept :
|
||||
m_data(nullptr),
|
||||
m_end(nullptr) {
|
||||
}
|
||||
|
||||
const_varint_iterator(const char* data, const char* end) noexcept :
|
||||
m_data(data),
|
||||
m_end(end) {
|
||||
}
|
||||
|
||||
const_varint_iterator(const const_varint_iterator&) noexcept = default;
|
||||
const_varint_iterator(const_varint_iterator&&) noexcept = default;
|
||||
|
||||
const_varint_iterator& operator=(const const_varint_iterator&) noexcept = default;
|
||||
const_varint_iterator& operator=(const_varint_iterator&&) noexcept = default;
|
||||
|
||||
~const_varint_iterator() noexcept = default;
|
||||
|
||||
value_type operator*() const {
|
||||
const char* d = m_data; // will be thrown away
|
||||
return static_cast<value_type>(decode_varint(&d, m_end));
|
||||
}
|
||||
|
||||
const_varint_iterator& operator++() {
|
||||
skip_varint(&m_data, m_end);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_varint_iterator operator++(int) {
|
||||
const const_varint_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const const_varint_iterator& rhs) const noexcept {
|
||||
return m_data == rhs.m_data && m_end == rhs.m_end;
|
||||
}
|
||||
|
||||
bool operator!=(const const_varint_iterator& rhs) const noexcept {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
}; // class const_varint_iterator
|
||||
|
||||
/**
|
||||
* A forward iterator used for accessing packed repeated svarint fields
|
||||
* (sint32, sint64).
|
||||
*/
|
||||
template <typename T>
|
||||
class const_svarint_iterator : public const_varint_iterator<T> {
|
||||
|
||||
public:
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = T;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
const_svarint_iterator() noexcept :
|
||||
const_varint_iterator<T>() {
|
||||
}
|
||||
|
||||
const_svarint_iterator(const char* data, const char* end) noexcept :
|
||||
const_varint_iterator<T>(data, end) {
|
||||
}
|
||||
|
||||
const_svarint_iterator(const const_svarint_iterator&) = default;
|
||||
const_svarint_iterator(const_svarint_iterator&&) = default;
|
||||
|
||||
const_svarint_iterator& operator=(const const_svarint_iterator&) = default;
|
||||
const_svarint_iterator& operator=(const_svarint_iterator&&) = default;
|
||||
|
||||
~const_svarint_iterator() = default;
|
||||
|
||||
value_type operator*() const {
|
||||
const char* d = this->m_data; // will be thrown away
|
||||
return static_cast<value_type>(decode_zigzag64(decode_varint(&d, this->m_end)));
|
||||
}
|
||||
|
||||
const_svarint_iterator& operator++() {
|
||||
skip_varint(&this->m_data, this->m_end);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_svarint_iterator operator++(int) {
|
||||
const const_svarint_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
}; // class const_svarint_iterator
|
||||
|
||||
} // end namespace protozero
|
||||
|
||||
#endif // PROTOZERO_ITERATORS_HPP
|
||||
+10
-10
@@ -57,7 +57,7 @@ public:
|
||||
|
||||
/// @cond INTERNAL
|
||||
#define PROTOZERO_WRITER_WRAP_ADD_SCALAR(name, type) \
|
||||
inline void add_##name(T tag, type value) { \
|
||||
void add_##name(T tag, type value) { \
|
||||
pbf_writer::add_##name(pbf_tag_type(tag), value); \
|
||||
}
|
||||
|
||||
@@ -79,38 +79,38 @@ public:
|
||||
#undef PROTOZERO_WRITER_WRAP_ADD_SCALAR
|
||||
/// @endcond
|
||||
|
||||
inline void add_bytes(T tag, const char* value, std::size_t size) {
|
||||
void add_bytes(T tag, const char* value, std::size_t size) {
|
||||
pbf_writer::add_bytes(pbf_tag_type(tag), value, size);
|
||||
}
|
||||
|
||||
inline void add_bytes(T tag, const std::string& value) {
|
||||
void add_bytes(T tag, const std::string& value) {
|
||||
pbf_writer::add_bytes(pbf_tag_type(tag), value);
|
||||
}
|
||||
|
||||
inline void add_string(T tag, const char* value, std::size_t size) {
|
||||
void add_string(T tag, const char* value, std::size_t size) {
|
||||
pbf_writer::add_string(pbf_tag_type(tag), value, size);
|
||||
}
|
||||
|
||||
inline void add_string(T tag, const std::string& value) {
|
||||
void add_string(T tag, const std::string& value) {
|
||||
pbf_writer::add_string(pbf_tag_type(tag), value);
|
||||
}
|
||||
|
||||
inline void add_string(T tag, const char* value) {
|
||||
void add_string(T tag, const char* value) {
|
||||
pbf_writer::add_string(pbf_tag_type(tag), value);
|
||||
}
|
||||
|
||||
inline void add_message(T tag, const char* value, std::size_t size) {
|
||||
void add_message(T tag, const char* value, std::size_t size) {
|
||||
pbf_writer::add_message(pbf_tag_type(tag), value, size);
|
||||
}
|
||||
|
||||
inline void add_message(T tag, const std::string& value) {
|
||||
void add_message(T tag, const std::string& value) {
|
||||
pbf_writer::add_message(pbf_tag_type(tag), value);
|
||||
}
|
||||
|
||||
/// @cond INTERNAL
|
||||
#define PROTOZERO_WRITER_WRAP_ADD_PACKED(name) \
|
||||
template <typename InputIterator> \
|
||||
inline void add_packed_##name(T tag, InputIterator first, InputIterator last) { \
|
||||
void add_packed_##name(T tag, InputIterator first, InputIterator last) { \
|
||||
pbf_writer::add_packed_##name(pbf_tag_type(tag), first, last); \
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
#undef PROTOZERO_WRITER_WRAP_ADD_PACKED
|
||||
/// @endcond
|
||||
|
||||
};
|
||||
}; // class pbf_builder
|
||||
|
||||
} // end namespace protozero
|
||||
|
||||
|
||||
+5
-5
@@ -13,7 +13,7 @@ documentation.
|
||||
/**
|
||||
* @file pbf_message.hpp
|
||||
*
|
||||
* @brief Contains the pbf_message class.
|
||||
* @brief Contains the pbf_message template class.
|
||||
*/
|
||||
|
||||
#include <type_traits>
|
||||
@@ -75,19 +75,19 @@ public:
|
||||
pbf_reader(std::forward<Args>(args)...) {
|
||||
}
|
||||
|
||||
inline bool next() {
|
||||
bool next() {
|
||||
return pbf_reader::next();
|
||||
}
|
||||
|
||||
inline bool next(T tag) {
|
||||
bool next(T tag) {
|
||||
return pbf_reader::next(pbf_tag_type(tag));
|
||||
}
|
||||
|
||||
inline T tag() const noexcept {
|
||||
T tag() const noexcept {
|
||||
return T(pbf_reader::tag());
|
||||
}
|
||||
|
||||
};
|
||||
}; // class pbf_message
|
||||
|
||||
} // end namespace protozero
|
||||
|
||||
|
||||
+292
-493
File diff suppressed because it is too large
Load Diff
+168
-76
@@ -22,6 +22,7 @@ documentation.
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <protozero/config.hpp>
|
||||
#include <protozero/types.hpp>
|
||||
@@ -68,38 +69,38 @@ class pbf_writer {
|
||||
// parent to the position where the data of the submessage is written to.
|
||||
std::size_t m_pos = 0;
|
||||
|
||||
inline void add_varint(uint64_t value) {
|
||||
void add_varint(uint64_t value) {
|
||||
protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
|
||||
protozero_assert(m_data);
|
||||
write_varint(std::back_inserter(*m_data), value);
|
||||
}
|
||||
|
||||
inline void add_field(pbf_tag_type tag, pbf_wire_type type) {
|
||||
void add_field(pbf_tag_type tag, pbf_wire_type type) {
|
||||
protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1 << 29) - 1))) && "tag out of range");
|
||||
uint32_t b = (tag << 3) | uint32_t(type);
|
||||
const uint32_t b = (tag << 3) | uint32_t(type);
|
||||
add_varint(b);
|
||||
}
|
||||
|
||||
inline void add_tagged_varint(pbf_tag_type tag, uint64_t value) {
|
||||
void add_tagged_varint(pbf_tag_type tag, uint64_t value) {
|
||||
add_field(tag, pbf_wire_type::varint);
|
||||
add_varint(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void add_fixed(T value) {
|
||||
void add_fixed(T value) {
|
||||
protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
|
||||
protozero_assert(m_data);
|
||||
#if PROTOZERO_BYTE_ORDER == PROTOZERO_LITTLE_ENDIAN
|
||||
m_data->append(reinterpret_cast<const char*>(&value), sizeof(T));
|
||||
#else
|
||||
auto size = m_data->size();
|
||||
const auto size = m_data->size();
|
||||
m_data->resize(size + sizeof(T));
|
||||
byteswap<sizeof(T)>(reinterpret_cast<const char*>(&value), const_cast<char*>(m_data->data() + size));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T, typename It>
|
||||
inline void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag) {
|
||||
void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag) {
|
||||
if (first == last) {
|
||||
return;
|
||||
}
|
||||
@@ -112,12 +113,12 @@ class pbf_writer {
|
||||
}
|
||||
|
||||
template <typename T, typename It>
|
||||
inline void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag) {
|
||||
void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag) {
|
||||
if (first == last) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto length = std::distance(first, last);
|
||||
const auto length = std::distance(first, last);
|
||||
add_length_varint(tag, sizeof(T) * pbf_length_type(length));
|
||||
reserve(sizeof(T) * std::size_t(length));
|
||||
|
||||
@@ -127,7 +128,7 @@ class pbf_writer {
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
inline void add_packed_varint(pbf_tag_type tag, It first, It last) {
|
||||
void add_packed_varint(pbf_tag_type tag, It first, It last) {
|
||||
if (first == last) {
|
||||
return;
|
||||
}
|
||||
@@ -140,7 +141,7 @@ class pbf_writer {
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
inline void add_packed_svarint(pbf_tag_type tag, It first, It last) {
|
||||
void add_packed_svarint(pbf_tag_type tag, It first, It last) {
|
||||
if (first == last) {
|
||||
return;
|
||||
}
|
||||
@@ -155,14 +156,18 @@ class pbf_writer {
|
||||
// The number of bytes to reserve for the varint holding the length of
|
||||
// a length-delimited field. The length has to fit into pbf_length_type,
|
||||
// and a varint needs 8 bit for every 7 bit.
|
||||
static const int reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1;
|
||||
enum constant_reserve_bytes : int {
|
||||
reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1
|
||||
};
|
||||
|
||||
// If m_rollpack_pos is set to this special value, it means that when
|
||||
// the submessage is closed, nothing needs to be done, because the length
|
||||
// of the submessage has already been written correctly.
|
||||
static const std::size_t size_is_known = std::numeric_limits<std::size_t>::max();
|
||||
enum constant_size_is_known : std::size_t {
|
||||
size_is_known = std::numeric_limits<std::size_t>::max()
|
||||
};
|
||||
|
||||
inline void open_submessage(pbf_tag_type tag, std::size_t size) {
|
||||
void open_submessage(pbf_tag_type tag, std::size_t size) {
|
||||
protozero_assert(m_pos == 0);
|
||||
protozero_assert(m_data);
|
||||
if (size == 0) {
|
||||
@@ -177,7 +182,7 @@ class pbf_writer {
|
||||
m_pos = m_data->size();
|
||||
}
|
||||
|
||||
inline void rollback_submessage() {
|
||||
void rollback_submessage() {
|
||||
protozero_assert(m_pos != 0);
|
||||
protozero_assert(m_rollback_pos != size_is_known);
|
||||
protozero_assert(m_data);
|
||||
@@ -185,20 +190,20 @@ class pbf_writer {
|
||||
m_pos = 0;
|
||||
}
|
||||
|
||||
inline void commit_submessage() {
|
||||
void commit_submessage() {
|
||||
protozero_assert(m_pos != 0);
|
||||
protozero_assert(m_rollback_pos != size_is_known);
|
||||
protozero_assert(m_data);
|
||||
auto length = pbf_length_type(m_data->size() - m_pos);
|
||||
const auto length = pbf_length_type(m_data->size() - m_pos);
|
||||
|
||||
protozero_assert(m_data->size() >= m_pos - reserve_bytes);
|
||||
auto n = write_varint(m_data->begin() + long(m_pos) - reserve_bytes, length);
|
||||
const auto n = write_varint(m_data->begin() + long(m_pos) - reserve_bytes, length);
|
||||
|
||||
m_data->erase(m_data->begin() + long(m_pos) - reserve_bytes + n, m_data->begin() + long(m_pos));
|
||||
m_pos = 0;
|
||||
}
|
||||
|
||||
inline void close_submessage() {
|
||||
void close_submessage() {
|
||||
protozero_assert(m_data);
|
||||
if (m_pos == 0 || m_rollback_pos == size_is_known) {
|
||||
return;
|
||||
@@ -210,7 +215,7 @@ class pbf_writer {
|
||||
}
|
||||
}
|
||||
|
||||
inline void add_length_varint(pbf_tag_type tag, pbf_length_type length) {
|
||||
void add_length_varint(pbf_tag_type tag, pbf_length_type length) {
|
||||
add_field(tag, pbf_wire_type::length_delimited);
|
||||
add_varint(length);
|
||||
}
|
||||
@@ -222,7 +227,7 @@ public:
|
||||
* stores a reference to that string and adds all data to it. The string
|
||||
* doesn't have to be empty. The pbf_writer will just append data.
|
||||
*/
|
||||
inline explicit pbf_writer(std::string& data) noexcept :
|
||||
explicit pbf_writer(std::string& data) noexcept :
|
||||
m_data(&data),
|
||||
m_parent_writer(nullptr),
|
||||
m_pos(0) {
|
||||
@@ -232,7 +237,7 @@ public:
|
||||
* Create a writer without a data store. In this form the writer can not
|
||||
* be used!
|
||||
*/
|
||||
inline pbf_writer() noexcept :
|
||||
pbf_writer() noexcept :
|
||||
m_data(nullptr),
|
||||
m_parent_writer(nullptr),
|
||||
m_pos(0) {
|
||||
@@ -248,7 +253,7 @@ public:
|
||||
* Setting this allows some optimizations but is only possible in
|
||||
* a few very specific cases.
|
||||
*/
|
||||
inline pbf_writer(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size=0) :
|
||||
pbf_writer(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size=0) :
|
||||
m_data(parent_writer.m_data),
|
||||
m_parent_writer(&parent_writer),
|
||||
m_pos(0) {
|
||||
@@ -262,17 +267,30 @@ public:
|
||||
pbf_writer& operator=(const pbf_writer&) noexcept = default;
|
||||
|
||||
/// A pbf_writer object can be moved
|
||||
inline pbf_writer(pbf_writer&&) noexcept = default;
|
||||
pbf_writer(pbf_writer&&) noexcept = default;
|
||||
|
||||
/// A pbf_writer object can be moved
|
||||
inline pbf_writer& operator=(pbf_writer&&) noexcept = default;
|
||||
pbf_writer& operator=(pbf_writer&&) noexcept = default;
|
||||
|
||||
inline ~pbf_writer() {
|
||||
~pbf_writer() {
|
||||
if (m_parent_writer) {
|
||||
m_parent_writer->close_submessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap the contents of this object with the other.
|
||||
*
|
||||
* @param other Other object to swap data with.
|
||||
*/
|
||||
void swap(pbf_writer& other) noexcept {
|
||||
using std::swap;
|
||||
swap(m_data, other.m_data);
|
||||
swap(m_parent_writer, other.m_parent_writer);
|
||||
swap(m_rollback_pos, other.m_rollback_pos);
|
||||
swap(m_pos, other.m_pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve size bytes in the underlying message store in addition to
|
||||
* whatever the message store already holds. So unlike
|
||||
@@ -286,7 +304,14 @@ public:
|
||||
m_data->reserve(m_data->size() + size);
|
||||
}
|
||||
|
||||
inline void rollback() {
|
||||
/**
|
||||
* Cancel writing of this submessage. The complete submessage will be
|
||||
* removed as if it was never created and no fields were added.
|
||||
*
|
||||
* @pre Must be a pbf_writer of a submessage, ie one opened with the
|
||||
* pbf_writer constructor taking a parent message.
|
||||
*/
|
||||
void rollback() {
|
||||
protozero_assert(m_parent_writer && "you can't call rollback() on a pbf_writer without a parent");
|
||||
protozero_assert(m_pos == 0 && "you can't call rollback() on a pbf_writer that has an open nested submessage");
|
||||
m_parent_writer->rollback_submessage();
|
||||
@@ -304,7 +329,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_bool(pbf_tag_type tag, bool value) {
|
||||
void add_bool(pbf_tag_type tag, bool value) {
|
||||
add_field(tag, pbf_wire_type::varint);
|
||||
protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
|
||||
protozero_assert(m_data);
|
||||
@@ -317,7 +342,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_enum(pbf_tag_type tag, int32_t value) {
|
||||
void add_enum(pbf_tag_type tag, int32_t value) {
|
||||
add_tagged_varint(tag, uint64_t(value));
|
||||
}
|
||||
|
||||
@@ -327,7 +352,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_int32(pbf_tag_type tag, int32_t value) {
|
||||
void add_int32(pbf_tag_type tag, int32_t value) {
|
||||
add_tagged_varint(tag, uint64_t(value));
|
||||
}
|
||||
|
||||
@@ -337,7 +362,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_sint32(pbf_tag_type tag, int32_t value) {
|
||||
void add_sint32(pbf_tag_type tag, int32_t value) {
|
||||
add_tagged_varint(tag, encode_zigzag32(value));
|
||||
}
|
||||
|
||||
@@ -347,7 +372,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_uint32(pbf_tag_type tag, uint32_t value) {
|
||||
void add_uint32(pbf_tag_type tag, uint32_t value) {
|
||||
add_tagged_varint(tag, value);
|
||||
}
|
||||
|
||||
@@ -357,7 +382,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_int64(pbf_tag_type tag, int64_t value) {
|
||||
void add_int64(pbf_tag_type tag, int64_t value) {
|
||||
add_tagged_varint(tag, uint64_t(value));
|
||||
}
|
||||
|
||||
@@ -367,7 +392,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_sint64(pbf_tag_type tag, int64_t value) {
|
||||
void add_sint64(pbf_tag_type tag, int64_t value) {
|
||||
add_tagged_varint(tag, encode_zigzag64(value));
|
||||
}
|
||||
|
||||
@@ -377,7 +402,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_uint64(pbf_tag_type tag, uint64_t value) {
|
||||
void add_uint64(pbf_tag_type tag, uint64_t value) {
|
||||
add_tagged_varint(tag, value);
|
||||
}
|
||||
|
||||
@@ -387,7 +412,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_fixed32(pbf_tag_type tag, uint32_t value) {
|
||||
void add_fixed32(pbf_tag_type tag, uint32_t value) {
|
||||
add_field(tag, pbf_wire_type::fixed32);
|
||||
add_fixed<uint32_t>(value);
|
||||
}
|
||||
@@ -398,7 +423,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_sfixed32(pbf_tag_type tag, int32_t value) {
|
||||
void add_sfixed32(pbf_tag_type tag, int32_t value) {
|
||||
add_field(tag, pbf_wire_type::fixed32);
|
||||
add_fixed<int32_t>(value);
|
||||
}
|
||||
@@ -409,7 +434,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_fixed64(pbf_tag_type tag, uint64_t value) {
|
||||
void add_fixed64(pbf_tag_type tag, uint64_t value) {
|
||||
add_field(tag, pbf_wire_type::fixed64);
|
||||
add_fixed<uint64_t>(value);
|
||||
}
|
||||
@@ -420,7 +445,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_sfixed64(pbf_tag_type tag, int64_t value) {
|
||||
void add_sfixed64(pbf_tag_type tag, int64_t value) {
|
||||
add_field(tag, pbf_wire_type::fixed64);
|
||||
add_fixed<int64_t>(value);
|
||||
}
|
||||
@@ -431,7 +456,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_float(pbf_tag_type tag, float value) {
|
||||
void add_float(pbf_tag_type tag, float value) {
|
||||
add_field(tag, pbf_wire_type::fixed32);
|
||||
add_fixed<float>(value);
|
||||
}
|
||||
@@ -442,7 +467,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_double(pbf_tag_type tag, double value) {
|
||||
void add_double(pbf_tag_type tag, double value) {
|
||||
add_field(tag, pbf_wire_type::fixed64);
|
||||
add_fixed<double>(value);
|
||||
}
|
||||
@@ -454,7 +479,7 @@ public:
|
||||
* @param value Pointer to value to be written
|
||||
* @param size Number of bytes to be written
|
||||
*/
|
||||
inline void add_bytes(pbf_tag_type tag, const char* value, std::size_t size) {
|
||||
void add_bytes(pbf_tag_type tag, const char* value, std::size_t size) {
|
||||
protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
|
||||
protozero_assert(m_data);
|
||||
protozero_assert(size <= std::numeric_limits<pbf_length_type>::max());
|
||||
@@ -468,7 +493,17 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_bytes(pbf_tag_type tag, const std::string& value) {
|
||||
void add_bytes(pbf_tag_type tag, const data_view& value) {
|
||||
add_bytes(tag, value.data(), value.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "bytes" field to data.
|
||||
*
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
void add_bytes(pbf_tag_type tag, const std::string& value) {
|
||||
add_bytes(tag, value.data(), value.size());
|
||||
}
|
||||
|
||||
@@ -479,7 +514,7 @@ public:
|
||||
* @param value Pointer to value to be written
|
||||
* @param size Number of bytes to be written
|
||||
*/
|
||||
inline void add_string(pbf_tag_type tag, const char* value, std::size_t size) {
|
||||
void add_string(pbf_tag_type tag, const char* value, std::size_t size) {
|
||||
add_bytes(tag, value, size);
|
||||
}
|
||||
|
||||
@@ -489,7 +524,17 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
inline void add_string(pbf_tag_type tag, const std::string& value) {
|
||||
void add_string(pbf_tag_type tag, const data_view& value) {
|
||||
add_bytes(tag, value.data(), value.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "string" field to data.
|
||||
*
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written
|
||||
*/
|
||||
void add_string(pbf_tag_type tag, const std::string& value) {
|
||||
add_bytes(tag, value.data(), value.size());
|
||||
}
|
||||
|
||||
@@ -500,7 +545,7 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Pointer to value to be written
|
||||
*/
|
||||
inline void add_string(pbf_tag_type tag, const char* value) {
|
||||
void add_string(pbf_tag_type tag, const char* value) {
|
||||
add_bytes(tag, value, std::strlen(value));
|
||||
}
|
||||
|
||||
@@ -511,7 +556,7 @@ public:
|
||||
* @param value Pointer to message to be written
|
||||
* @param size Length of the message
|
||||
*/
|
||||
inline void add_message(pbf_tag_type tag, const char* value, std::size_t size) {
|
||||
void add_message(pbf_tag_type tag, const char* value, std::size_t size) {
|
||||
add_bytes(tag, value, size);
|
||||
}
|
||||
|
||||
@@ -521,7 +566,17 @@ public:
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written. The value must be a complete message.
|
||||
*/
|
||||
inline void add_message(pbf_tag_type tag, const std::string& value) {
|
||||
void add_message(pbf_tag_type tag, const data_view& value) {
|
||||
add_bytes(tag, value.data(), value.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "message" field to data.
|
||||
*
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param value Value to be written. The value must be a complete message.
|
||||
*/
|
||||
void add_message(pbf_tag_type tag, const std::string& value) {
|
||||
add_bytes(tag, value.data(), value.size());
|
||||
}
|
||||
|
||||
@@ -535,126 +590,126 @@ public:
|
||||
/**
|
||||
* Add "repeated packed bool" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to bool.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_varint(tag, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "repeated packed enum" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to int32_t.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_varint(tag, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "repeated packed int32" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to int32_t.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_varint(tag, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "repeated packed sint32" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to int32_t.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_svarint(tag, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "repeated packed uint32" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to uint32_t.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_varint(tag, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "repeated packed int64" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to int64_t.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_varint(tag, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "repeated packed sint64" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to int64_t.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_svarint(tag, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "repeated packed uint64" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to uint64_t.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_varint(tag, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "repeated packed fixed32" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to uint32_t.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_fixed<uint32_t, InputIterator>(tag, first, last,
|
||||
typename std::iterator_traits<InputIterator>::iterator_category());
|
||||
}
|
||||
@@ -662,14 +717,14 @@ public:
|
||||
/**
|
||||
* Add "repeated packed sfixed32" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to int32_t.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_fixed<int32_t, InputIterator>(tag, first, last,
|
||||
typename std::iterator_traits<InputIterator>::iterator_category());
|
||||
}
|
||||
@@ -677,14 +732,14 @@ public:
|
||||
/**
|
||||
* Add "repeated packed fixed64" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to uint64_t.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_fixed<uint64_t, InputIterator>(tag, first, last,
|
||||
typename std::iterator_traits<InputIterator>::iterator_category());
|
||||
}
|
||||
@@ -692,14 +747,14 @@ public:
|
||||
/**
|
||||
* Add "repeated packed sfixed64" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to int64_t.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_fixed<int64_t, InputIterator>(tag, first, last,
|
||||
typename std::iterator_traits<InputIterator>::iterator_category());
|
||||
}
|
||||
@@ -707,14 +762,14 @@ public:
|
||||
/**
|
||||
* Add "repeated packed float" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to float.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_fixed<float, InputIterator>(tag, first, last,
|
||||
typename std::iterator_traits<InputIterator>::iterator_category());
|
||||
}
|
||||
@@ -722,14 +777,14 @@ public:
|
||||
/**
|
||||
* Add "repeated packed double" field to data.
|
||||
*
|
||||
* @tparam InputIterator An type satisfying the InputIterator concept.
|
||||
* @tparam InputIterator A type satisfying the InputIterator concept.
|
||||
* Dereferencing the iterator must yield a type assignable to double.
|
||||
* @param tag Tag (field number) of the field
|
||||
* @param first Iterator pointing to the beginning of the data
|
||||
* @param last Iterator pointing one past the end of data
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
inline void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last) {
|
||||
add_packed_fixed<double, InputIterator>(tag, first, last,
|
||||
typename std::iterator_traits<InputIterator>::iterator_category());
|
||||
}
|
||||
@@ -742,6 +797,16 @@ public:
|
||||
|
||||
}; // class pbf_writer
|
||||
|
||||
/**
|
||||
* Swap two pbf_writer objects.
|
||||
*
|
||||
* @param lhs First object.
|
||||
* @param rhs Second object.
|
||||
*/
|
||||
inline void swap(pbf_writer& lhs, pbf_writer& rhs) noexcept {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
class packed_field {
|
||||
@@ -817,19 +882,46 @@ namespace detail {
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
/// Class for generating packed repeated bool fields.
|
||||
using packed_field_bool = detail::packed_field_varint<bool>;
|
||||
|
||||
/// Class for generating packed repeated enum fields.
|
||||
using packed_field_enum = detail::packed_field_varint<int32_t>;
|
||||
|
||||
/// Class for generating packed repeated int32 fields.
|
||||
using packed_field_int32 = detail::packed_field_varint<int32_t>;
|
||||
|
||||
/// Class for generating packed repeated sint32 fields.
|
||||
using packed_field_sint32 = detail::packed_field_svarint<int32_t>;
|
||||
|
||||
/// Class for generating packed repeated uint32 fields.
|
||||
using packed_field_uint32 = detail::packed_field_varint<uint32_t>;
|
||||
|
||||
/// Class for generating packed repeated int64 fields.
|
||||
using packed_field_int64 = detail::packed_field_varint<int64_t>;
|
||||
|
||||
/// Class for generating packed repeated sint64 fields.
|
||||
using packed_field_sint64 = detail::packed_field_svarint<int64_t>;
|
||||
|
||||
/// Class for generating packed repeated uint64 fields.
|
||||
using packed_field_uint64 = detail::packed_field_varint<uint64_t>;
|
||||
|
||||
/// Class for generating packed repeated fixed32 fields.
|
||||
using packed_field_fixed32 = detail::packed_field_fixed<uint32_t>;
|
||||
|
||||
/// Class for generating packed repeated sfixed32 fields.
|
||||
using packed_field_sfixed32 = detail::packed_field_fixed<int32_t>;
|
||||
|
||||
/// Class for generating packed repeated fixed64 fields.
|
||||
using packed_field_fixed64 = detail::packed_field_fixed<uint64_t>;
|
||||
|
||||
/// Class for generating packed repeated sfixed64 fields.
|
||||
using packed_field_sfixed64 = detail::packed_field_fixed<int64_t>;
|
||||
|
||||
/// Class for generating packed repeated float fields.
|
||||
using packed_field_float = detail::packed_field_fixed<float>;
|
||||
|
||||
/// Class for generating packed repeated double fields.
|
||||
using packed_field_double = detail::packed_field_fixed<double>;
|
||||
|
||||
} // end namespace protozero
|
||||
|
||||
+157
-17
@@ -16,33 +16,173 @@ documentation.
|
||||
* @brief Contains the declaration of low-level types used in the pbf format.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <protozero/config.hpp>
|
||||
|
||||
namespace protozero {
|
||||
|
||||
/**
|
||||
* The type used for field tags (field numbers).
|
||||
*/
|
||||
typedef uint32_t pbf_tag_type;
|
||||
/**
|
||||
* The type used for field tags (field numbers).
|
||||
*/
|
||||
using pbf_tag_type = uint32_t;
|
||||
|
||||
/**
|
||||
* The type used to encode type information.
|
||||
* See the table on
|
||||
* https://developers.google.com/protocol-buffers/docs/encoding
|
||||
*/
|
||||
enum class pbf_wire_type : uint32_t {
|
||||
varint = 0, // int32/64, uint32/64, sint32/64, bool, enum
|
||||
fixed64 = 1, // fixed64, sfixed64, double
|
||||
length_delimited = 2, // string, bytes, embedded messages,
|
||||
// packed repeated fields
|
||||
fixed32 = 5, // fixed32, sfixed32, float
|
||||
unknown = 99 // used for default setting in this library
|
||||
};
|
||||
|
||||
/**
|
||||
* The type used for length values, such as the length of a field.
|
||||
*/
|
||||
using pbf_length_type = uint32_t;
|
||||
|
||||
#ifdef PROTOZERO_USE_VIEW
|
||||
using data_view = PROTOZERO_USE_VIEW;
|
||||
#else
|
||||
|
||||
/**
|
||||
* Holds a pointer to some data and a length.
|
||||
*
|
||||
* This class is supposed to be compatible with the std::string_view
|
||||
* that will be available in C++17.
|
||||
*/
|
||||
class data_view {
|
||||
|
||||
const char* m_data;
|
||||
std::size_t m_size;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* The type used to encode type information.
|
||||
* See the table on
|
||||
* https://developers.google.com/protocol-buffers/docs/encoding
|
||||
* Default constructor. Construct an empty data_view.
|
||||
*/
|
||||
enum class pbf_wire_type : uint32_t {
|
||||
varint = 0, // int32/64, uint32/64, sint32/64, bool, enum
|
||||
fixed64 = 1, // fixed64, sfixed64, double
|
||||
length_delimited = 2, // string, bytes, embedded messages,
|
||||
// packed repeated fields
|
||||
fixed32 = 5, // fixed32, sfixed32, float
|
||||
unknown = 99 // used for default setting in this library
|
||||
};
|
||||
constexpr data_view() noexcept
|
||||
: m_data(nullptr),
|
||||
m_size(0) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The type used for length values, such as the length of a field.
|
||||
* Create data_view from pointer and size.
|
||||
*
|
||||
* @param data Pointer to the data.
|
||||
* @param size Length of the data.
|
||||
*/
|
||||
typedef uint32_t pbf_length_type;
|
||||
constexpr data_view(const char* data, std::size_t size) noexcept
|
||||
: m_data(data),
|
||||
m_size(size) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create data_view from string.
|
||||
*
|
||||
* @param str String with the data.
|
||||
*/
|
||||
data_view(const std::string& str) noexcept
|
||||
: m_data(str.data()),
|
||||
m_size(str.size()) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create data_view from zero-terminated string.
|
||||
*
|
||||
* @param data Pointer to the data.
|
||||
*/
|
||||
data_view(const char* data) noexcept
|
||||
: m_data(data),
|
||||
m_size(std::strlen(data)) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap the contents of this object with the other.
|
||||
*
|
||||
* @param other Other object to swap data with.
|
||||
*/
|
||||
void swap(data_view& other) noexcept {
|
||||
using std::swap;
|
||||
swap(m_data, other.m_data);
|
||||
swap(m_size, other.m_size);
|
||||
}
|
||||
|
||||
/// Return pointer to data.
|
||||
constexpr const char* data() const noexcept {
|
||||
return m_data;
|
||||
}
|
||||
|
||||
/// Return length of data in bytes.
|
||||
constexpr std::size_t size() const noexcept {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert data view to string.
|
||||
*
|
||||
* @pre Must not be default constructed data_view.
|
||||
*/
|
||||
std::string to_string() const {
|
||||
protozero_assert(m_data);
|
||||
return std::string{m_data, m_size};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert data view to string.
|
||||
*
|
||||
* @pre Must not be default constructed data_view.
|
||||
*/
|
||||
explicit operator std::string() const {
|
||||
protozero_assert(m_data);
|
||||
return std::string{m_data, m_size};
|
||||
}
|
||||
|
||||
}; // class data_view
|
||||
|
||||
/**
|
||||
* Swap two data_view objects.
|
||||
*
|
||||
* @param lhs First object.
|
||||
* @param rhs Second object.
|
||||
*/
|
||||
inline void swap(data_view& lhs, data_view& rhs) noexcept {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Two data_view instances are equal if they have the same size and the
|
||||
* same content.
|
||||
*
|
||||
* @param lhs First object.
|
||||
* @param rhs Second object.
|
||||
*/
|
||||
inline bool operator==(data_view& lhs, data_view& rhs) noexcept {
|
||||
return lhs.size() == rhs.size() && !std::strcmp(lhs.data(), rhs.data());
|
||||
}
|
||||
|
||||
/**
|
||||
* Two data_view instances are not equal if they have different sizes or the
|
||||
* content differs.
|
||||
*
|
||||
* @param lhs First object.
|
||||
* @param rhs Second object.
|
||||
*/
|
||||
inline bool operator!=(data_view& lhs, data_view& rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
} // end namespace protozero
|
||||
|
||||
|
||||
+95
-40
@@ -23,13 +23,54 @@ documentation.
|
||||
namespace protozero {
|
||||
|
||||
/**
|
||||
* The maximum length of a 64bit varint.
|
||||
* The maximum length of a 64 bit varint.
|
||||
*/
|
||||
constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1;
|
||||
|
||||
// from https://github.com/facebook/folly/blob/master/folly/Varint.h
|
||||
namespace detail {
|
||||
|
||||
// from https://github.com/facebook/folly/blob/master/folly/Varint.h
|
||||
inline uint64_t decode_varint_impl(const char** data, const char* end) {
|
||||
const int8_t* begin = reinterpret_cast<const int8_t*>(*data);
|
||||
const int8_t* iend = reinterpret_cast<const int8_t*>(end);
|
||||
const int8_t* p = begin;
|
||||
uint64_t val = 0;
|
||||
|
||||
if (iend - begin >= max_varint_length) { // fast path
|
||||
do {
|
||||
int64_t b;
|
||||
b = *p++; val = uint64_t((b & 0x7f) ); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 7); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 14); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 21); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 28); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 35); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 42); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 49); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 56); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 63); if (b >= 0) break;
|
||||
throw varint_too_long_exception();
|
||||
} while (false);
|
||||
} else {
|
||||
int shift = 0;
|
||||
while (p != iend && *p < 0) {
|
||||
val |= uint64_t(*p++ & 0x7f) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
if (p == iend) {
|
||||
throw end_of_buffer_exception();
|
||||
}
|
||||
val |= uint64_t(*p++) << shift;
|
||||
}
|
||||
|
||||
*data = reinterpret_cast<const char*>(p);
|
||||
return val;
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
/**
|
||||
* Decode a 64bit varint.
|
||||
* Decode a 64 bit varint.
|
||||
*
|
||||
* Strong exception guarantee: if there is an exception the data pointer will
|
||||
* not be changed.
|
||||
@@ -39,54 +80,68 @@ constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1;
|
||||
* @param[in] end Pointer one past the end of the input data.
|
||||
* @returns The decoded integer
|
||||
* @throws varint_too_long_exception if the varint is longer then the maximum
|
||||
* length that would fit in a 64bit int. Usually this means your data
|
||||
* length that would fit in a 64 bit int. Usually this means your data
|
||||
* is corrupted or you are trying to read something as a varint that
|
||||
* isn't.
|
||||
* @throws end_of_buffer_exception if the *end* of the buffer was reached
|
||||
* before the end of the varint.
|
||||
*/
|
||||
inline uint64_t decode_varint(const char** data, const char* end) {
|
||||
const int8_t* begin = reinterpret_cast<const int8_t*>(*data);
|
||||
const int8_t* iend = reinterpret_cast<const int8_t*>(end);
|
||||
const int8_t* p = begin;
|
||||
uint64_t val = 0;
|
||||
|
||||
if (iend - begin >= max_varint_length) { // fast path
|
||||
do {
|
||||
int64_t b;
|
||||
b = *p++; val = uint64_t((b & 0x7f) ); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 7); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 14); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 21); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 28); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 35); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 42); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 49); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 56); if (b >= 0) break;
|
||||
b = *p++; val |= uint64_t((b & 0x7f) << 63); if (b >= 0) break;
|
||||
throw varint_too_long_exception();
|
||||
} while (false);
|
||||
} else {
|
||||
int shift = 0;
|
||||
while (p != iend && *p < 0) {
|
||||
val |= uint64_t(*p++ & 0x7f) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
if (p == iend) {
|
||||
throw end_of_buffer_exception();
|
||||
}
|
||||
val |= uint64_t(*p++) << shift;
|
||||
// If this is a one-byte varint, decode it here.
|
||||
if (end != *data && ((**data & 0x80) == 0)) {
|
||||
uint64_t val = uint64_t(**data);
|
||||
++(*data);
|
||||
return val;
|
||||
}
|
||||
|
||||
*data = reinterpret_cast<const char*>(p);
|
||||
return val;
|
||||
// If this varint is more than one byte, defer to complete implementation.
|
||||
return detail::decode_varint_impl(data, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Varint-encode a 64bit integer.
|
||||
* Skip over a varint.
|
||||
*
|
||||
* Strong exception guarantee: if there is an exception the data pointer will
|
||||
* not be changed.
|
||||
*
|
||||
* @param[in,out] data Pointer to pointer to the input data. After the function
|
||||
* returns this will point to the next data to be read.
|
||||
* @param[in] end Pointer one past the end of the input data.
|
||||
* @throws end_of_buffer_exception if the *end* of the buffer was reached
|
||||
* before the end of the varint.
|
||||
*/
|
||||
template <typename OutputIterator>
|
||||
inline int write_varint(OutputIterator data, uint64_t value) {
|
||||
inline void skip_varint(const char** data, const char* end) {
|
||||
const int8_t* begin = reinterpret_cast<const int8_t*>(*data);
|
||||
const int8_t* iend = reinterpret_cast<const int8_t*>(end);
|
||||
const int8_t* p = begin;
|
||||
|
||||
while (p != iend && *p < 0) {
|
||||
++p;
|
||||
}
|
||||
|
||||
if (p >= begin + max_varint_length) {
|
||||
throw varint_too_long_exception();
|
||||
}
|
||||
|
||||
if (p == iend) {
|
||||
throw end_of_buffer_exception();
|
||||
}
|
||||
|
||||
++p;
|
||||
|
||||
*data = reinterpret_cast<const char*>(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Varint encode a 64 bit integer.
|
||||
*
|
||||
* @tparam T An output iterator type.
|
||||
* @param data Output iterator the varint encoded value will be written to
|
||||
* byte by byte.
|
||||
* @param value The integer that will be encoded.
|
||||
* @throws Any exception thrown by increment or dereference operator on data.
|
||||
*/
|
||||
template <typename T>
|
||||
inline int write_varint(T data, uint64_t value) {
|
||||
int n=1;
|
||||
|
||||
while (value >= 0x80) {
|
||||
|
||||
+17
-4
@@ -10,13 +10,26 @@ documentation.
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#define PROTOZERO_VERSION_MAJOR 1
|
||||
#define PROTOZERO_VERSION_MINOR 3
|
||||
#define PROTOZERO_VERSION_PATCH 0
|
||||
/**
|
||||
* @file version.hpp
|
||||
*
|
||||
* @brief Contains macros defining the protozero version.
|
||||
*/
|
||||
|
||||
/// The major version number
|
||||
#define PROTOZERO_VERSION_MAJOR 1
|
||||
|
||||
/// The minor version number
|
||||
#define PROTOZERO_VERSION_MINOR 4
|
||||
|
||||
/// The patch number
|
||||
#define PROTOZERO_VERSION_PATCH 2
|
||||
|
||||
/// The complete version number
|
||||
#define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH)
|
||||
|
||||
#define PROTOZERO_VERSION_STRING "1.3.0"
|
||||
/// Version number as string
|
||||
#define PROTOZERO_VERSION_STRING "1.4.2"
|
||||
|
||||
|
||||
#endif // PROTOZERO_VERSION_HPP
|
||||
|
||||
Reference in New Issue
Block a user