1#ifndef PROTOZERO_BASIC_PBF_WRITER_HPP 
    2#define PROTOZERO_BASIC_PBF_WRITER_HPP 
   25#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN 
   32#include <initializer_list> 
   42    template <
typename B, 
typename T> 
class packed_field_varint;
 
   43    template <
typename B, 
typename T> 
class packed_field_svarint;
 
   44    template <
typename B, 
typename T> 
class packed_field_fixed;
 
   58template <
typename TBuffer>
 
   64    TBuffer* m_data = 
nullptr;
 
   74    std::size_t m_rollback_pos = 0;
 
   78    std::size_t m_pos = 0;
 
   80    void add_varint(uint64_t value) {
 
   81        protozero_assert(m_pos == 0 && 
"you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage");
 
   82        protozero_assert(m_data);
 
   87        protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1U << 29U) - 1))) && 
"tag out of range");
 
   88        const uint32_t b = (tag << 3U) | static_cast<uint32_t>(type);
 
   92    void add_tagged_varint(
pbf_tag_type tag, uint64_t value) {
 
   93        add_field(tag, pbf_wire_type::varint);
 
   98    void add_fixed(T value) {
 
   99        protozero_assert(m_pos == 0 && 
"you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage");
 
  100        protozero_assert(m_data);
 
  101#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN 
  104        buffer_customization<TBuffer>::append(m_data, 
reinterpret_cast<const char*
>(&value), 
sizeof(T));
 
  107    template <
typename T, 
typename It>
 
  108    void add_packed_fixed(
pbf_tag_type tag, It first, It last, std::input_iterator_tag ) { 
 
  115        while (first != last) {
 
  116            sw.add_fixed<T>(*first++);
 
  120    template <
typename T, 
typename It>
 
  121    void add_packed_fixed(
pbf_tag_type tag, It first, It last, std::forward_iterator_tag ) { 
 
  126        const auto length = std::distance(first, last);
 
  128        reserve(
sizeof(T) * std::size_t(length));
 
  130        while (first != last) {
 
  131            add_fixed<T>(*first++);
 
  135    template <
typename It>
 
  136    void add_packed_varint(
pbf_tag_type tag, It first, It last) { 
 
  143        while (first != last) {
 
  144            sw.add_varint(uint64_t(*first++));
 
  148    template <
typename It>
 
  149    void add_packed_svarint(
pbf_tag_type tag, It first, It last) { 
 
  156        while (first != last) {
 
  172        size_is_known = std::numeric_limits<std::size_t>::max()
 
  175    void open_submessage(
pbf_tag_type tag, std::size_t size) {
 
  176        protozero_assert(m_pos == 0);
 
  177        protozero_assert(m_data);
 
  179            m_rollback_pos = buffer_customization<TBuffer>::size(m_data);
 
  180            add_field(tag, pbf_wire_type::length_delimited);
 
  181            buffer_customization<TBuffer>::append_zeros(m_data, std::size_t(reserve_bytes));
 
  183            m_rollback_pos = size_is_known;
 
  187        m_pos = buffer_customization<TBuffer>::size(m_data);
 
  190    void rollback_submessage() {
 
  191        protozero_assert(m_pos != 0);
 
  192        protozero_assert(m_rollback_pos != size_is_known);
 
  193        protozero_assert(m_data);
 
  194        buffer_customization<TBuffer>::resize(m_data, m_rollback_pos);
 
  198    void commit_submessage() {
 
  199        protozero_assert(m_pos != 0);
 
  200        protozero_assert(m_rollback_pos != size_is_known);
 
  201        protozero_assert(m_data);
 
  202        const auto length = 
pbf_length_type(buffer_customization<TBuffer>::size(m_data) - m_pos);
 
  204        protozero_assert(buffer_customization<TBuffer>::size(m_data) >= m_pos - reserve_bytes);
 
  205        const auto n = 
add_varint_to_buffer(buffer_customization<TBuffer>::at_pos(m_data, m_pos - reserve_bytes), length);
 
  207        buffer_customization<TBuffer>::erase_range(m_data, m_pos - reserve_bytes + n, m_pos);
 
  211    void close_submessage() {
 
  212        protozero_assert(m_data);
 
  213        if (m_pos == 0 || m_rollback_pos == size_is_known) {
 
  216        if (buffer_customization<TBuffer>::size(m_data) - m_pos == 0) {
 
  217            rollback_submessage();
 
  224        add_field(tag, pbf_wire_type::length_delimited);
 
  257        m_data{parent_writer.m_data},
 
  258        m_parent_writer{&parent_writer} {
 
  259        m_parent_writer->open_submessage(tag, size);
 
 
  273        m_data{other.m_data},
 
  274        m_parent_writer{other.m_parent_writer},
 
  275        m_rollback_pos{other.m_rollback_pos},
 
  277        other.m_data = 
nullptr;
 
  278        other.m_parent_writer = 
nullptr;
 
  279        other.m_rollback_pos = 0;
 
 
  288        m_data = other.m_data;
 
  289        m_parent_writer = other.m_parent_writer;
 
  290        m_rollback_pos = other.m_rollback_pos;
 
  292        other.m_data = 
nullptr;
 
  293        other.m_parent_writer = 
nullptr;
 
  294        other.m_rollback_pos = 0;
 
 
  301            if (m_parent_writer != 
nullptr) {
 
  302                m_parent_writer->close_submessage();
 
  318        return m_data != 
nullptr;
 
 
  328        swap(m_data, other.m_data);
 
  329        swap(m_parent_writer, other.m_parent_writer);
 
  330        swap(m_rollback_pos, other.m_rollback_pos);
 
  331        swap(m_pos, other.m_pos);
 
 
  343        protozero_assert(m_data);
 
  344        buffer_customization<TBuffer>::reserve_additional(m_data, size);
 
 
  356        protozero_assert(m_parent_writer && 
"you can't call commit() on a basic_pbf_writer without a parent");
 
  357        protozero_assert(m_pos == 0 && 
"you can't call commit() on a basic_pbf_writer that has an open nested submessage");
 
  358        m_parent_writer->close_submessage();
 
  359        m_parent_writer = 
nullptr;
 
 
  372        protozero_assert(m_parent_writer && 
"you can't call rollback() on a basic_pbf_writer without a parent");
 
  373        protozero_assert(m_pos == 0 && 
"you can't call rollback() on a basic_pbf_writer that has an open nested submessage");
 
  374        m_parent_writer->rollback_submessage();
 
  375        m_parent_writer = 
nullptr;
 
 
  391        add_field(tag, pbf_wire_type::varint);
 
  392        protozero_assert(m_pos == 0 && 
"you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage");
 
  393        protozero_assert(m_data);
 
  394        m_data->push_back(
static_cast<char>(value));
 
 
  404        add_tagged_varint(tag, 
static_cast<uint64_t
>(value));
 
 
  414        add_tagged_varint(tag, 
static_cast<uint64_t
>(value));
 
 
  434        add_tagged_varint(tag, value);
 
 
  444        add_tagged_varint(tag, 
static_cast<uint64_t
>(value));
 
 
  464        add_tagged_varint(tag, value);
 
 
  474        add_field(tag, pbf_wire_type::fixed32);
 
  475        add_fixed<uint32_t>(value);
 
 
  485        add_field(tag, pbf_wire_type::fixed32);
 
  486        add_fixed<int32_t>(value);
 
 
  496        add_field(tag, pbf_wire_type::fixed64);
 
  497        add_fixed<uint64_t>(value);
 
 
  507        add_field(tag, pbf_wire_type::fixed64);
 
  508        add_fixed<int64_t>(value);
 
 
  518        add_field(tag, pbf_wire_type::fixed32);
 
  519        add_fixed<float>(value);
 
 
  529        add_field(tag, pbf_wire_type::fixed64);
 
  530        add_fixed<double>(value);
 
 
  541        protozero_assert(m_pos == 0 && 
"you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage");
 
  542        protozero_assert(m_data);
 
  543        protozero_assert(size <= std::numeric_limits<pbf_length_type>::max());
 
  545        buffer_customization<TBuffer>::append(m_data, value, size);
 
 
  565        add_bytes(tag, value.data(), value.size());
 
 
  576        add_bytes(tag, value, std::strlen(value));
 
 
  598    template <
typename... Ts>
 
  600        protozero_assert(m_pos == 0 && 
"you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage");
 
  601        protozero_assert(m_data);
 
  603        (void)std::initializer_list<size_t>{sum_size += values.size()...};
 
  604        protozero_assert(sum_size <= std::numeric_limits<pbf_length_type>::max());
 
  606        buffer_customization<TBuffer>::reserve_additional(m_data, sum_size);
 
  607        (void)std::initializer_list<int>{(buffer_customization<TBuffer>::append(m_data, values.data(), values.size()), 0)...};
 
 
  638        add_bytes(tag, value.data(), value.size());
 
 
  649        add_bytes(tag, value, std::strlen(value));
 
 
  680        add_bytes(tag, value.data(), value.size());
 
 
  699    template <
typename InputIterator>
 
  701        add_packed_varint(tag, first, last);
 
 
  713    template <
typename InputIterator>
 
  715        add_packed_varint(tag, first, last);
 
 
  727    template <
typename InputIterator>
 
  729        add_packed_varint(tag, first, last);
 
 
  741    template <
typename InputIterator>
 
  743        add_packed_svarint(tag, first, last);
 
 
  755    template <
typename InputIterator>
 
  757        add_packed_varint(tag, first, last);
 
 
  769    template <
typename InputIterator>
 
  771        add_packed_varint(tag, first, last);
 
 
  783    template <
typename InputIterator>
 
  785        add_packed_svarint(tag, first, last);
 
 
  797    template <
typename InputIterator>
 
  799        add_packed_varint(tag, first, last);
 
 
  819    template <
typename ValueType, 
typename InputIterator>
 
  821        static_assert(std::is_same<ValueType, uint32_t>::value ||
 
  822                      std::is_same<ValueType, int32_t>::value ||
 
  823                      std::is_same<ValueType, int64_t>::value ||
 
  824                      std::is_same<ValueType, uint64_t>::value ||
 
  825                      std::is_same<ValueType, double>::value ||
 
  826                      std::is_same<ValueType, float>::value, 
"Only some types are allowed");
 
  827        add_packed_fixed<ValueType, InputIterator>(tag, first, last,
 
  828            typename std::iterator_traits<InputIterator>::iterator_category{});
 
 
  840    template <
typename InputIterator>
 
  842        add_packed_fixed<uint32_t, InputIterator>(tag, first, last,
 
  843            typename std::iterator_traits<InputIterator>::iterator_category{});
 
 
  855    template <
typename InputIterator>
 
  857        add_packed_fixed<int32_t, InputIterator>(tag, first, last,
 
  858            typename std::iterator_traits<InputIterator>::iterator_category{});
 
 
  870    template <
typename InputIterator>
 
  872        add_packed_fixed<uint64_t, InputIterator>(tag, first, last,
 
  873            typename std::iterator_traits<InputIterator>::iterator_category{});
 
 
  885    template <
typename InputIterator>
 
  887        add_packed_fixed<int64_t, InputIterator>(tag, first, last,
 
  888            typename std::iterator_traits<InputIterator>::iterator_category{});
 
 
  900    template <
typename InputIterator>
 
  902        add_packed_fixed<float, InputIterator>(tag, first, last,
 
  903            typename std::iterator_traits<InputIterator>::iterator_category{});
 
 
  915    template <
typename InputIterator>
 
  917        add_packed_fixed<double, InputIterator>(tag, first, last,
 
  918            typename std::iterator_traits<InputIterator>::iterator_category{});
 
 
  923    template <
typename B, 
typename T> 
friend class detail::packed_field_varint;
 
  924    template <
typename B, 
typename T> 
friend class detail::packed_field_svarint;
 
  925    template <
typename B, 
typename T> 
friend class detail::packed_field_fixed;
 
 
  935template <
typename TBuffer>
 
  942    template <
typename TBuffer>
 
  945        basic_pbf_writer<TBuffer> m_writer{};
 
  949        packed_field(
const packed_field&) = 
delete;
 
  950        packed_field& operator=(
const packed_field&) = 
delete;
 
  952        packed_field(packed_field&&) noexcept = default;
 
  953        packed_field& operator=(packed_field&&) noexcept = default;
 
  955        packed_field() = default;
 
  957        packed_field(basic_pbf_writer<TBuffer>& parent_writer, 
pbf_tag_type tag) :
 
  958            m_writer{parent_writer, tag} {
 
  961        packed_field(basic_pbf_writer<TBuffer>& parent_writer, 
pbf_tag_type tag, std::size_t size) :
 
  962            m_writer{parent_writer, tag, size} {
 
  965        ~packed_field() noexcept = default;
 
  967        bool valid() const noexcept {
 
  968            return m_writer.valid();
 
  979        basic_pbf_writer<TBuffer>& writer() noexcept {
 
  985    template <
typename TBuffer, 
typename T>
 
  986    class packed_field_fixed : 
public packed_field<TBuffer> {
 
  990        packed_field_fixed() :
 
  991            packed_field<TBuffer>{} {
 
  994        template <
typename P>
 
  995        packed_field_fixed(basic_pbf_writer<TBuffer>& parent_writer, P tag) :
 
  996            packed_field<TBuffer>{parent_writer, 
static_cast<pbf_tag_type>(tag)} {
 
  999        template <
typename P>
 
 1000        packed_field_fixed(basic_pbf_writer<TBuffer>& parent_writer, P tag, std::size_t size) :
 
 1001            packed_field<TBuffer>{parent_writer, 
static_cast<pbf_tag_type>(tag), size * 
sizeof(T)} {
 
 1004        void add_element(T value) {
 
 1005            this->writer().template add_fixed<T>(value);
 
 1010    template <
typename TBuffer, 
typename T>
 
 1011    class packed_field_varint : 
public packed_field<TBuffer> {
 
 1015        packed_field_varint() :
 
 1016            packed_field<TBuffer>{} {
 
 1019        template <
typename P>
 
 1020        packed_field_varint(basic_pbf_writer<TBuffer>& parent_writer, P tag) :
 
 1021            packed_field<TBuffer>{parent_writer, 
static_cast<pbf_tag_type>(tag)} {
 
 1024        void add_element(T value) {
 
 1025            this->writer().add_varint(uint64_t(value));
 
 1030    template <
typename TBuffer, 
typename T>
 
 1031    class packed_field_svarint : 
public packed_field<TBuffer> {
 
 1035        packed_field_svarint() :
 
 1036            packed_field<TBuffer>{} {
 
 1039        template <
typename P>
 
 1040        packed_field_svarint(basic_pbf_writer<TBuffer>& parent_writer, P tag) :
 
 1041            packed_field<TBuffer>{parent_writer, 
static_cast<pbf_tag_type>(tag)} {
 
 1044        void add_element(T value) {
 
Contains the customization points for buffer implementations.
Contains functions to swap bytes in values (for different endianness).
Definition basic_pbf_writer.hpp:59
void rollback()
Definition basic_pbf_writer.hpp:371
void add_string(pbf_tag_type tag, const char *value, std::size_t size)
Definition basic_pbf_writer.hpp:617
void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:886
void add_bytes(pbf_tag_type tag, const char *value, std::size_t size)
Definition basic_pbf_writer.hpp:540
void add_enum(pbf_tag_type tag, int32_t value)
Definition basic_pbf_writer.hpp:403
void add_packed_fixed(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:820
void add_uint32(pbf_tag_type tag, uint32_t value)
Definition basic_pbf_writer.hpp:433
void add_float(pbf_tag_type tag, float value)
Definition basic_pbf_writer.hpp:517
void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:742
basic_pbf_writer(basic_pbf_writer &&other) noexcept
Definition basic_pbf_writer.hpp:272
void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:901
void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:856
void add_fixed32(pbf_tag_type tag, uint32_t value)
Definition basic_pbf_writer.hpp:473
void add_bytes_vectored(pbf_tag_type tag, Ts &&... values)
Definition basic_pbf_writer.hpp:599
void add_fixed64(pbf_tag_type tag, uint64_t value)
Definition basic_pbf_writer.hpp:495
basic_pbf_writer(TBuffer &buffer) noexcept
Definition basic_pbf_writer.hpp:236
void commit()
Definition basic_pbf_writer.hpp:355
void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:770
void add_message(pbf_tag_type tag, const data_view &value)
Definition basic_pbf_writer.hpp:669
void reserve(std::size_t size)
Definition basic_pbf_writer.hpp:342
void add_sfixed32(pbf_tag_type tag, int32_t value)
Definition basic_pbf_writer.hpp:484
void add_string(pbf_tag_type tag, const std::string &value)
Definition basic_pbf_writer.hpp:637
void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:714
basic_pbf_writer & operator=(const basic_pbf_writer &)=delete
A basic_pbf_writer object can not be copied.
void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:798
void add_bool(pbf_tag_type tag, bool value)
Definition basic_pbf_writer.hpp:390
basic_pbf_writer & operator=(basic_pbf_writer &&other) noexcept
Definition basic_pbf_writer.hpp:287
void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:916
void add_message(pbf_tag_type tag, const std::string &value)
Definition basic_pbf_writer.hpp:679
void add_bytes(pbf_tag_type tag, const data_view &value)
Definition basic_pbf_writer.hpp:554
basic_pbf_writer(const basic_pbf_writer &)=delete
A basic_pbf_writer object can not be copied.
void add_bytes(pbf_tag_type tag, const std::string &value)
Definition basic_pbf_writer.hpp:564
void add_uint64(pbf_tag_type tag, uint64_t value)
Definition basic_pbf_writer.hpp:463
void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:841
basic_pbf_writer() noexcept=default
void add_bytes(pbf_tag_type tag, const char *value)
Definition basic_pbf_writer.hpp:575
void add_string(pbf_tag_type tag, const data_view &value)
Definition basic_pbf_writer.hpp:627
void add_sint32(pbf_tag_type tag, int32_t value)
Definition basic_pbf_writer.hpp:423
void add_int64(pbf_tag_type tag, int64_t value)
Definition basic_pbf_writer.hpp:443
void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:756
void add_int32(pbf_tag_type tag, int32_t value)
Definition basic_pbf_writer.hpp:413
void add_sfixed64(pbf_tag_type tag, int64_t value)
Definition basic_pbf_writer.hpp:506
void swap(basic_pbf_writer &other) noexcept
Definition basic_pbf_writer.hpp:326
void add_string(pbf_tag_type tag, const char *value)
Definition basic_pbf_writer.hpp:648
bool valid() const noexcept
Definition basic_pbf_writer.hpp:317
void add_double(pbf_tag_type tag, double value)
Definition basic_pbf_writer.hpp:528
void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:871
void add_sint64(pbf_tag_type tag, int64_t value)
Definition basic_pbf_writer.hpp:453
void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:728
void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:700
void add_message(pbf_tag_type tag, const char *value, std::size_t size)
Definition basic_pbf_writer.hpp:659
void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition basic_pbf_writer.hpp:784
Definition data_view.hpp:39
constexpr std::size_t size() const noexcept
Return length of data in bytes.
Definition data_view.hpp:99
constexpr const char * data() const noexcept
Return pointer to data.
Definition data_view.hpp:94
Contains macro checks for different configurations.
Contains the implementation of the data_view class.
All parts of the protozero header-only library are in this namespace.
Definition basic_pbf_builder.hpp:24
void swap(basic_pbf_writer< TBuffer > &lhs, basic_pbf_writer< TBuffer > &rhs) noexcept
Definition basic_pbf_writer.hpp:936
void add_varint_to_buffer(TBuffer *buffer, uint64_t value)
Definition varint.hpp:169
pbf_wire_type
Definition types.hpp:40
uint32_t pbf_length_type
Definition types.hpp:62
constexpr uint32_t encode_zigzag32(int32_t value) noexcept
Definition varint.hpp:217
constexpr uint64_t encode_zigzag64(int64_t value) noexcept
Definition varint.hpp:224
uint32_t pbf_tag_type
Definition types.hpp:33
void byteswap_inplace(uint32_t *ptr) noexcept
byteswap the data pointed to by ptr in-place.
Definition byteswap.hpp:56
Contains the declaration of low-level types used in the pbf format.
Contains low-level varint and zigzag encoding and decoding functions.