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) | 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(
char(value));
404 add_tagged_varint(tag, uint64_t(value));
414 add_tagged_varint(tag, uint64_t(value));
434 add_tagged_varint(tag, value);
444 add_tagged_varint(tag, 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
uint32_t pbf_tag_type
Definition types.hpp:33
uint32_t pbf_length_type
Definition types.hpp:62
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:170
pbf_wire_type
Definition types.hpp:40
constexpr uint32_t encode_zigzag32(int32_t value) noexcept
Definition varint.hpp:218
constexpr uint64_t encode_zigzag64(int64_t value) noexcept
Definition varint.hpp:225
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.