pbf_writer.hpp
Go to the documentation of this file.
#ifndef PROTOZERO_PBF_WRITER_HPP
#define PROTOZERO_PBF_WRITER_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.
*****************************************************************************/
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <iterator>
#include <limits>
#include <string>
#include <protozero/config.hpp>
#include <protozero/pbf_types.hpp>
#include <protozero/varint.hpp>
#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
# include <protozero/byteswap.hpp>
#endif
namespace protozero {
class pbf_writer {
std::string* m_data;
pbf_writer* m_parent_writer;
size_t m_pos = 0;
inline 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) {
protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1 << 29) - 1))) && "tag out of range");
uint32_t b = (tag << 3) | uint32_t(type);
add_varint(b);
}
inline 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) {
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();
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) {
if (first == last) {
return;
}
pbf_writer sw(*this, tag);
while (first != last) {
sw.add_fixed<T>(*first++);
}
}
template <typename T, typename It>
inline void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag) {
if (first == last) {
return;
}
add_length_varint(tag, sizeof(T) * pbf_length_type(std::distance(first, last)));
while (first != last) {
add_fixed<T>(*first++);
}
}
template <typename It>
inline void add_packed_varint(pbf_tag_type tag, It first, It last) {
if (first == last) {
return;
}
pbf_writer sw(*this, tag);
while (first != last) {
sw.add_varint(uint64_t(*first++));
}
}
template <typename It>
inline void add_packed_svarint(pbf_tag_type tag, It first, It last) {
if (first == last) {
return;
}
pbf_writer sw(*this, tag);
while (first != last) {
sw.add_varint(encode_zigzag64(*first++));
}
}
// 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;
inline void open_submessage(pbf_tag_type tag) {
protozero_assert(m_pos == 0);
protozero_assert(m_data);
add_field(tag, pbf_wire_type::length_delimited);
m_data->append(size_t(reserve_bytes), '\0');
m_pos = m_data->size();
}
inline void close_submessage() {
protozero_assert(m_pos != 0);
protozero_assert(m_data);
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);
m_data->erase(m_data->begin() + long(m_pos) - reserve_bytes + n, m_data->begin() + long(m_pos));
m_pos = 0;
}
inline void add_length_varint(pbf_tag_type tag, pbf_length_type length) {
add_field(tag, pbf_wire_type::length_delimited);
add_varint(length);
}
public:
inline explicit pbf_writer(std::string& data) noexcept :
m_data(&data),
m_parent_writer(nullptr),
m_pos(0) {
}
inline pbf_writer() noexcept :
m_data(nullptr),
m_parent_writer(nullptr),
m_pos(0) {
}
inline pbf_writer(pbf_writer& parent_writer, pbf_tag_type tag) :
m_data(parent_writer.m_data),
m_parent_writer(&parent_writer),
m_pos(0) {
m_parent_writer->open_submessage(tag);
}
pbf_writer(const pbf_writer&) noexcept = default;
pbf_writer& operator=(const pbf_writer&) noexcept = default;
inline pbf_writer(pbf_writer&&) noexcept = default;
inline pbf_writer& operator=(pbf_writer&&) noexcept = default;
inline ~pbf_writer() {
if (m_parent_writer) {
m_parent_writer->close_submessage();
}
}
inline 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);
m_data->append(1, value);
}
inline void add_enum(pbf_tag_type tag, int32_t value) {
add_tagged_varint(tag, uint64_t(value));
}
inline void add_int32(pbf_tag_type tag, int32_t value) {
add_tagged_varint(tag, uint64_t(value));
}
inline void add_sint32(pbf_tag_type tag, int32_t value) {
add_tagged_varint(tag, encode_zigzag32(value));
}
inline void add_uint32(pbf_tag_type tag, uint32_t value) {
add_tagged_varint(tag, value);
}
inline void add_int64(pbf_tag_type tag, int64_t value) {
add_tagged_varint(tag, uint64_t(value));
}
inline void add_sint64(pbf_tag_type tag, int64_t value) {
add_tagged_varint(tag, encode_zigzag64(value));
}
inline void add_uint64(pbf_tag_type tag, uint64_t value) {
add_tagged_varint(tag, value);
}
inline void add_fixed32(pbf_tag_type tag, uint32_t value) {
add_field(tag, pbf_wire_type::fixed32);
add_fixed<uint32_t>(value);
}
inline void add_sfixed32(pbf_tag_type tag, int32_t value) {
add_field(tag, pbf_wire_type::fixed32);
add_fixed<int32_t>(value);
}
inline void add_fixed64(pbf_tag_type tag, uint64_t value) {
add_field(tag, pbf_wire_type::fixed64);
add_fixed<uint64_t>(value);
}
inline void add_sfixed64(pbf_tag_type tag, int64_t value) {
add_field(tag, pbf_wire_type::fixed64);
add_fixed<int64_t>(value);
}
inline void add_float(pbf_tag_type tag, float value) {
add_field(tag, pbf_wire_type::fixed32);
add_fixed<float>(value);
}
inline void add_double(pbf_tag_type tag, double value) {
add_field(tag, pbf_wire_type::fixed64);
add_fixed<double>(value);
}
inline void add_bytes(pbf_tag_type tag, const char* value, 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());
add_length_varint(tag, pbf_length_type(size));
m_data->append(value, size);
}
inline void add_bytes(pbf_tag_type tag, const std::string& value) {
add_bytes(tag, value.data(), value.size());
}
inline void add_string(pbf_tag_type tag, const char* value, size_t size) {
add_bytes(tag, value, size);
}
inline void add_string(pbf_tag_type tag, const std::string& value) {
add_bytes(tag, value.data(), value.size());
}
inline void add_string(pbf_tag_type tag, const char* value) {
add_bytes(tag, value, std::strlen(value));
}
inline void add_message(pbf_tag_type tag, const char* value, size_t size) {
add_bytes(tag, value, size);
}
inline void add_message(pbf_tag_type tag, const std::string& value) {
add_bytes(tag, value.data(), value.size());
}
template <typename InputIterator>
inline void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last) {
add_packed_varint(tag, first, last);
}
template <typename InputIterator>
inline void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last) {
add_packed_varint(tag, first, last);
}
template <typename InputIterator>
inline void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last) {
add_packed_varint(tag, first, last);
}
template <typename InputIterator>
inline void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last) {
add_packed_svarint(tag, first, last);
}
template <typename InputIterator>
inline void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last) {
add_packed_varint(tag, first, last);
}
template <typename InputIterator>
inline void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last) {
add_packed_varint(tag, first, last);
}
template <typename InputIterator>
inline void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last) {
add_packed_svarint(tag, first, last);
}
template <typename InputIterator>
inline void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last) {
add_packed_varint(tag, first, last);
}
template <typename InputIterator>
inline 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());
}
template <typename InputIterator>
inline 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());
}
template <typename InputIterator>
inline 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());
}
template <typename InputIterator>
inline 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());
}
template <typename InputIterator>
inline 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());
}
template <typename InputIterator>
inline 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());
}
}; // class pbf_writer
} // end namespace protozero
#endif // PROTOZERO_PBF_WRITER_HPP
protozero::pbf_writer::add_packed_fixed64
void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:605
protozero::pbf_writer::add_packed_sint32
void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:505
protozero::pbf_writer::add_packed_sint64
void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:547
protozero::pbf_writer::add_string
void add_string(pbf_tag_type tag, const char *value)
Definition: pbf_writer.hpp:421
protozero::pbf_writer::add_packed_sfixed64
void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:620
protozero::pbf_writer::add_packed_sfixed32
void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:590
protozero::pbf_length_type
uint32_t pbf_length_type
Definition: pbf_types.hpp:45
protozero::encode_zigzag64
uint64_t encode_zigzag64(int64_t value) noexcept
Definition: varint.hpp:112
protozero::pbf_writer::add_sint64
void add_sint64(pbf_tag_type tag, int64_t value)
Definition: pbf_writer.hpp:288
protozero::pbf_writer::add_sfixed64
void add_sfixed64(pbf_tag_type tag, int64_t value)
Definition: pbf_writer.hpp:341
protozero::pbf_writer::add_uint32
void add_uint32(pbf_tag_type tag, uint32_t value)
Definition: pbf_writer.hpp:268
protozero::pbf_writer::add_bytes
void add_bytes(pbf_tag_type tag, const std::string &value)
Definition: pbf_writer.hpp:389
protozero::pbf_writer::add_packed_enum
void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:477
protozero::pbf_writer
Definition: pbf_writer.hpp:42
protozero::pbf_writer::add_int64
void add_int64(pbf_tag_type tag, int64_t value)
Definition: pbf_writer.hpp:278
config.hpp
Contains macro checks for different configurations.
protozero::pbf_writer::add_int32
void add_int32(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:248
protozero::pbf_writer::add_string
void add_string(pbf_tag_type tag, const std::string &value)
Definition: pbf_writer.hpp:410
protozero::pbf_writer::add_uint64
void add_uint64(pbf_tag_type tag, uint64_t value)
Definition: pbf_writer.hpp:298
protozero::pbf_wire_type
pbf_wire_type
Definition: pbf_types.hpp:33
pbf_types.hpp
Contains the declaration of low-level types used in the pbf format.
protozero::pbf_writer::add_message
void add_message(pbf_tag_type tag, const std::string &value)
Definition: pbf_writer.hpp:442
protozero::pbf_writer::add_float
void add_float(pbf_tag_type tag, float value)
Definition: pbf_writer.hpp:352
protozero::pbf_tag_type
uint32_t pbf_tag_type
Definition: pbf_types.hpp:26
protozero::pbf_writer::add_enum
void add_enum(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:238
protozero::pbf_writer::add_packed_uint64
void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:561
protozero::pbf_writer::pbf_writer
pbf_writer() noexcept
Definition: pbf_writer.hpp:176
protozero::pbf_writer::add_bytes
void add_bytes(pbf_tag_type tag, const char *value, size_t size)
Definition: pbf_writer.hpp:375
byteswap.hpp
Contains functions to swap bytes in values (for different endianness).
protozero::pbf_writer::add_packed_uint32
void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:519
protozero::encode_zigzag32
uint32_t encode_zigzag32(int32_t value) noexcept
Definition: varint.hpp:105
protozero::pbf_writer::add_packed_int64
void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:533
protozero::pbf_writer::add_string
void add_string(pbf_tag_type tag, const char *value, size_t size)
Definition: pbf_writer.hpp:400
protozero::pbf_writer::add_fixed64
void add_fixed64(pbf_tag_type tag, uint64_t value)
Definition: pbf_writer.hpp:330
protozero::pbf_writer::add_bool
void add_bool(pbf_tag_type tag, bool value)
Definition: pbf_writer.hpp:225
protozero::pbf_writer::add_packed_bool
void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:463
protozero::pbf_writer::add_packed_double
void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:650
protozero::write_varint
int write_varint(OutputIterator data, uint64_t value)
Definition: varint.hpp:89
protozero::pbf_writer::add_packed_float
void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:635
protozero::pbf_writer::pbf_writer
pbf_writer(pbf_writer &parent_writer, pbf_tag_type tag)
Definition: pbf_writer.hpp:189
protozero::pbf_writer::add_packed_int32
void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:491
protozero::pbf_writer::add_sfixed32
void add_sfixed32(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:319
protozero::pbf_writer::pbf_writer
pbf_writer(std::string &data) noexcept
Definition: pbf_writer.hpp:166
varint.hpp
Contains low-level varint and zigzag encoding and decoding functions.
protozero::pbf_writer::add_sint32
void add_sint32(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:258
protozero::pbf_writer::add_fixed32
void add_fixed32(pbf_tag_type tag, uint32_t value)
Definition: pbf_writer.hpp:308
protozero::pbf_writer::add_packed_fixed32
void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:575
protozero::pbf_writer::add_message
void add_message(pbf_tag_type tag, const char *value, size_t size)
Definition: pbf_writer.hpp:432
protozero::pbf_writer::add_double
void add_double(pbf_tag_type tag, double value)
Definition: pbf_writer.hpp:363
protozero
All parts of the protozero header-only library are in this namespace.
Definition: byteswap.hpp:24