1 #ifndef PROTOZERO_PBF_WRITER_HPP 2 #define PROTOZERO_PBF_WRITER_HPP 22 #include <initializer_list> 32 #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN 40 template <
typename T>
class packed_field_varint;
41 template <
typename T>
class packed_field_svarint;
42 template <
typename T>
class packed_field_fixed;
57 std::string* m_data =
nullptr;
67 std::size_t m_rollback_pos = 0;
71 std::size_t m_pos = 0;
73 void add_varint(uint64_t value) {
74 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");
75 protozero_assert(m_data);
80 protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1 << 29) - 1))) &&
"tag out of range");
81 const uint32_t b = (tag << 3) | uint32_t(type);
85 void add_tagged_varint(
pbf_tag_type tag, uint64_t value) {
86 add_field(tag, pbf_wire_type::varint);
91 void add_fixed(T value) {
92 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");
93 protozero_assert(m_data);
94 #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN 95 detail::byteswap_inplace(&value);
97 m_data->append(reinterpret_cast<const char*>(&value),
sizeof(T));
100 template <
typename T,
typename It>
101 void add_packed_fixed(
pbf_tag_type tag, It first, It last, std::input_iterator_tag ) {
108 while (first != last) {
109 sw.add_fixed<T>(*first++);
113 template <
typename T,
typename It>
114 void add_packed_fixed(
pbf_tag_type tag, It first, It last, std::forward_iterator_tag ) {
119 const auto length = std::distance(first, last);
121 reserve(
sizeof(T) * std::size_t(length));
123 while (first != last) {
124 add_fixed<T>(*first++);
128 template <
typename It>
129 void add_packed_varint(
pbf_tag_type tag, It first, It last) {
136 while (first != last) {
137 sw.add_varint(uint64_t(*first++));
141 template <
typename It>
142 void add_packed_svarint(
pbf_tag_type tag, It first, It last) {
149 while (first != last) {
157 enum constant_reserve_bytes :
int {
164 enum constant_size_is_known : std::size_t {
165 size_is_known = std::numeric_limits<std::size_t>::max()
168 void open_submessage(
pbf_tag_type tag, std::size_t size) {
169 protozero_assert(m_pos == 0);
170 protozero_assert(m_data);
172 m_rollback_pos = m_data->size();
173 add_field(tag, pbf_wire_type::length_delimited);
174 m_data->append(std::size_t(reserve_bytes),
'\0');
176 m_rollback_pos = size_is_known;
180 m_pos = m_data->size();
183 void rollback_submessage() {
184 protozero_assert(m_pos != 0);
185 protozero_assert(m_rollback_pos != size_is_known);
186 protozero_assert(m_data);
187 m_data->resize(m_rollback_pos);
191 void commit_submessage() {
192 protozero_assert(m_pos != 0);
193 protozero_assert(m_rollback_pos != size_is_known);
194 protozero_assert(m_data);
197 protozero_assert(m_data->size() >= m_pos - reserve_bytes);
198 const auto n =
write_varint(m_data->begin() + int64_t(m_pos) - reserve_bytes, length);
200 m_data->erase(m_data->begin() + int64_t(m_pos) - reserve_bytes + n, m_data->begin() + int64_t(m_pos));
204 void close_submessage() {
205 protozero_assert(m_data);
206 if (m_pos == 0 || m_rollback_pos == size_is_known) {
209 if (m_data->size() - m_pos == 0) {
210 rollback_submessage();
217 add_field(tag, pbf_wire_type::length_delimited);
249 m_data(parent_writer.m_data),
250 m_parent_writer(&parent_writer) {
251 m_parent_writer->open_submessage(tag, size);
265 m_data(other.m_data),
266 m_parent_writer(other.m_parent_writer),
267 m_rollback_pos(other.m_rollback_pos),
269 other.m_data =
nullptr;
270 other.m_parent_writer =
nullptr;
271 other.m_rollback_pos = 0;
280 m_data = other.m_data;
281 m_parent_writer = other.m_parent_writer;
282 m_rollback_pos = other.m_rollback_pos;
284 other.m_data =
nullptr;
285 other.m_parent_writer =
nullptr;
286 other.m_rollback_pos = 0;
292 if (m_parent_writer !=
nullptr) {
293 m_parent_writer->close_submessage();
303 return m_data !=
nullptr;
313 swap(m_data, other.m_data);
314 swap(m_parent_writer, other.m_parent_writer);
315 swap(m_rollback_pos, other.m_rollback_pos);
316 swap(m_pos, other.m_pos);
328 protozero_assert(m_data);
329 m_data->reserve(m_data->size() + size);
341 protozero_assert(m_parent_writer &&
"you can't call commit() on a pbf_writer without a parent");
342 protozero_assert(m_pos == 0 &&
"you can't call commit() on a pbf_writer that has an open nested submessage");
343 m_parent_writer->close_submessage();
344 m_parent_writer =
nullptr;
357 protozero_assert(m_parent_writer &&
"you can't call rollback() on a pbf_writer without a parent");
358 protozero_assert(m_pos == 0 &&
"you can't call rollback() on a pbf_writer that has an open nested submessage");
359 m_parent_writer->rollback_submessage();
360 m_parent_writer =
nullptr;
376 add_field(tag, pbf_wire_type::varint);
377 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");
378 protozero_assert(m_data);
379 m_data->append(1,
char(value));
389 add_tagged_varint(tag, uint64_t(value));
399 add_tagged_varint(tag, uint64_t(value));
419 add_tagged_varint(tag, value);
429 add_tagged_varint(tag, uint64_t(value));
449 add_tagged_varint(tag, value);
459 add_field(tag, pbf_wire_type::fixed32);
460 add_fixed<uint32_t>(value);
470 add_field(tag, pbf_wire_type::fixed32);
471 add_fixed<int32_t>(value);
481 add_field(tag, pbf_wire_type::fixed64);
482 add_fixed<uint64_t>(value);
492 add_field(tag, pbf_wire_type::fixed64);
493 add_fixed<int64_t>(value);
503 add_field(tag, pbf_wire_type::fixed32);
504 add_fixed<float>(value);
514 add_field(tag, pbf_wire_type::fixed64);
515 add_fixed<double>(value);
526 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");
527 protozero_assert(m_data);
528 protozero_assert(size <= std::numeric_limits<pbf_length_type>::max());
530 m_data->append(value, size);
540 add_bytes(tag, value.
data(), value.
size());
550 add_bytes(tag, value.data(), value.size());
561 add_bytes(tag, value, std::strlen(value));
583 template <
typename... Ts>
585 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");
586 protozero_assert(m_data);
588 (void)std::initializer_list<size_t>{sum_size += values.size()...};
589 protozero_assert(sum_size <= std::numeric_limits<pbf_length_type>::max());
591 m_data->reserve(m_data->size() + sum_size);
592 (void)std::initializer_list<int>{(m_data->append(values.data(), values.size()), 0)...};
603 add_bytes(tag, value, size);
613 add_bytes(tag, value.
data(), value.
size());
623 add_bytes(tag, value.data(), value.size());
634 add_bytes(tag, value, std::strlen(value));
645 add_bytes(tag, value, size);
655 add_bytes(tag, value.
data(), value.
size());
665 add_bytes(tag, value.data(), value.size());
684 template <
typename InputIterator>
686 add_packed_varint(tag, first, last);
698 template <
typename InputIterator>
700 add_packed_varint(tag, first, last);
712 template <
typename InputIterator>
714 add_packed_varint(tag, first, last);
726 template <
typename InputIterator>
728 add_packed_svarint(tag, first, last);
740 template <
typename InputIterator>
742 add_packed_varint(tag, first, last);
754 template <
typename InputIterator>
756 add_packed_varint(tag, first, last);
768 template <
typename InputIterator>
770 add_packed_svarint(tag, first, last);
782 template <
typename InputIterator>
784 add_packed_varint(tag, first, last);
796 template <
typename InputIterator>
798 add_packed_fixed<uint32_t, InputIterator>(tag, first, last,
799 typename std::iterator_traits<InputIterator>::iterator_category());
811 template <
typename InputIterator>
813 add_packed_fixed<int32_t, InputIterator>(tag, first, last,
814 typename std::iterator_traits<InputIterator>::iterator_category());
826 template <
typename InputIterator>
828 add_packed_fixed<uint64_t, InputIterator>(tag, first, last,
829 typename std::iterator_traits<InputIterator>::iterator_category());
841 template <
typename InputIterator>
843 add_packed_fixed<int64_t, InputIterator>(tag, first, last,
844 typename std::iterator_traits<InputIterator>::iterator_category());
856 template <
typename InputIterator>
858 add_packed_fixed<float, InputIterator>(tag, first, last,
859 typename std::iterator_traits<InputIterator>::iterator_category());
871 template <
typename InputIterator>
873 add_packed_fixed<double, InputIterator>(tag, first, last,
874 typename std::iterator_traits<InputIterator>::iterator_category());
879 template <
typename T>
friend class detail::packed_field_varint;
880 template <
typename T>
friend class detail::packed_field_svarint;
881 template <
typename T>
friend class detail::packed_field_fixed;
905 packed_field(
const packed_field&) =
delete;
906 packed_field& operator=(
const packed_field&) =
delete;
908 packed_field(packed_field&&) noexcept =
default;
909 packed_field& operator=(packed_field&&) noexcept =
default;
911 packed_field() =
default;
914 m_writer(parent_writer, tag) {
918 m_writer(parent_writer, tag, size) {
921 ~packed_field() noexcept =
default;
923 bool valid()
const noexcept {
924 return m_writer.valid();
937 template <
typename T>
938 class packed_field_fixed :
public packed_field {
942 packed_field_fixed() :
946 template <
typename P>
947 packed_field_fixed(
pbf_writer& parent_writer, P tag) :
948 packed_field(parent_writer, static_cast<pbf_tag_type>(tag)) {
951 template <
typename P>
952 packed_field_fixed(
pbf_writer& parent_writer, P tag, std::size_t size) :
953 packed_field(parent_writer, static_cast<pbf_tag_type>(tag), size *
sizeof(T)) {
956 void add_element(T value) {
957 m_writer.add_fixed<T>(value);
962 template <
typename T>
963 class packed_field_varint :
public packed_field {
967 packed_field_varint() :
971 template <
typename P>
972 packed_field_varint(
pbf_writer& parent_writer, P tag) :
973 packed_field(parent_writer, static_cast<pbf_tag_type>(tag)) {
976 void add_element(T value) {
977 m_writer.add_varint(uint64_t(value));
982 template <
typename T>
983 class packed_field_svarint :
public packed_field {
987 packed_field_svarint() :
991 template <
typename P>
992 packed_field_svarint(
pbf_writer& parent_writer, P tag) :
993 packed_field(parent_writer, static_cast<pbf_tag_type>(tag)) {
996 void add_element(T value) {
1048 #endif // PROTOZERO_PBF_WRITER_HPP void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:827
void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:727
detail::packed_field_fixed< float > packed_field_float
Class for generating packed repeated float fields.
Definition: pbf_writer.hpp:1041
void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:769
void add_string(pbf_tag_type tag, const char *value)
Definition: pbf_writer.hpp:633
void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:842
void rollback()
Definition: pbf_writer.hpp:356
void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:812
constexpr uint64_t encode_zigzag64(int64_t value) noexcept
Definition: varint.hpp:167
void reserve(std::size_t size)
Definition: pbf_writer.hpp:327
void add_sint64(pbf_tag_type tag, int64_t value)
Definition: pbf_writer.hpp:438
void add_message(pbf_tag_type tag, const char *value, std::size_t size)
Definition: pbf_writer.hpp:644
pbf_writer(pbf_writer &&other) noexcept
Definition: pbf_writer.hpp:264
detail::packed_field_varint< int64_t > packed_field_int64
Class for generating packed repeated int64 fields.
Definition: pbf_writer.hpp:1020
void add_sfixed64(pbf_tag_type tag, int64_t value)
Definition: pbf_writer.hpp:491
void add_uint32(pbf_tag_type tag, uint32_t value)
Definition: pbf_writer.hpp:418
void add_bytes(pbf_tag_type tag, const std::string &value)
Definition: pbf_writer.hpp:549
void add_string(pbf_tag_type tag, const char *value, std::size_t size)
Definition: pbf_writer.hpp:602
void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:699
detail::packed_field_fixed< int64_t > packed_field_sfixed64
Class for generating packed repeated sfixed64 fields.
Definition: pbf_writer.hpp:1038
void add_message(pbf_tag_type tag, const data_view &value)
Definition: pbf_writer.hpp:654
Definition: pbf_writer.hpp:52
void add_int64(pbf_tag_type tag, int64_t value)
Definition: pbf_writer.hpp:428
Contains macro checks for different configurations.
detail::packed_field_varint< bool > packed_field_bool
Class for generating packed repeated bool fields.
Definition: pbf_writer.hpp:1005
detail::packed_field_fixed< double > packed_field_double
Class for generating packed repeated double fields.
Definition: pbf_writer.hpp:1044
Contains the declaration of low-level types used in the pbf format.
constexpr uint32_t encode_zigzag32(int32_t value) noexcept
Definition: varint.hpp:160
void add_int32(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:398
void add_string(pbf_tag_type tag, const std::string &value)
Definition: pbf_writer.hpp:622
pbf_writer & operator=(pbf_writer &&other) noexcept
Definition: pbf_writer.hpp:279
int write_varint(T data, uint64_t value)
Definition: varint.hpp:144
void swap(iterator_range< T > &lhs, iterator_range< T > &rhs) noexcept
Definition: iterators.hpp:151
void add_uint64(pbf_tag_type tag, uint64_t value)
Definition: pbf_writer.hpp:448
constexpr std::size_t size() const noexcept
Return length of data in bytes.
Definition: types.hpp:135
void add_string(pbf_tag_type tag, const data_view &value)
Definition: pbf_writer.hpp:612
detail::packed_field_varint< int32_t > packed_field_int32
Class for generating packed repeated int32 fields.
Definition: pbf_writer.hpp:1011
pbf_wire_type
Definition: types.hpp:40
void add_message(pbf_tag_type tag, const std::string &value)
Definition: pbf_writer.hpp:664
void add_float(pbf_tag_type tag, float value)
Definition: pbf_writer.hpp:502
void swap(pbf_writer &other) noexcept
Definition: pbf_writer.hpp:311
void add_enum(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:388
detail::packed_field_svarint< int64_t > packed_field_sint64
Class for generating packed repeated sint64 fields.
Definition: pbf_writer.hpp:1023
void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:783
void add_bytes_vectored(pbf_tag_type tag, Ts &&... values)
Definition: pbf_writer.hpp:584
Contains functions to swap bytes in values (for different endianness).
void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:741
void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:755
void add_fixed64(pbf_tag_type tag, uint64_t value)
Definition: pbf_writer.hpp:480
uint32_t pbf_length_type
Definition: types.hpp:63
void add_bool(pbf_tag_type tag, bool value)
Definition: pbf_writer.hpp:375
void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:685
detail::packed_field_fixed< uint64_t > packed_field_fixed64
Class for generating packed repeated fixed64 fields.
Definition: pbf_writer.hpp:1035
detail::packed_field_fixed< int32_t > packed_field_sfixed32
Class for generating packed repeated sfixed32 fields.
Definition: pbf_writer.hpp:1032
uint32_t pbf_tag_type
Definition: types.hpp:33
detail::packed_field_varint< uint32_t > packed_field_uint32
Class for generating packed repeated uint32 fields.
Definition: pbf_writer.hpp:1017
void commit()
Definition: pbf_writer.hpp:340
void swap(pbf_writer &lhs, pbf_writer &rhs) noexcept
Definition: pbf_writer.hpp:891
void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:872
void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:857
detail::packed_field_varint< uint64_t > packed_field_uint64
Class for generating packed repeated uint64 fields.
Definition: pbf_writer.hpp:1026
void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:713
pbf_writer(pbf_writer &parent_writer, pbf_tag_type tag, std::size_t size=0)
Definition: pbf_writer.hpp:248
constexpr const char * data() const noexcept
Return pointer to data.
Definition: types.hpp:130
void add_sfixed32(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:469
pbf_writer(std::string &data) noexcept
Definition: pbf_writer.hpp:228
Contains low-level varint and zigzag encoding and decoding functions.
void add_sint32(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:408
detail::packed_field_varint< int32_t > packed_field_enum
Class for generating packed repeated enum fields.
Definition: pbf_writer.hpp:1008
void add_fixed32(pbf_tag_type tag, uint32_t value)
Definition: pbf_writer.hpp:458
detail::packed_field_fixed< uint32_t > packed_field_fixed32
Class for generating packed repeated fixed32 fields.
Definition: pbf_writer.hpp:1029
void add_bytes(pbf_tag_type tag, const data_view &value)
Definition: pbf_writer.hpp:539
bool valid() const noexcept
Definition: pbf_writer.hpp:302
void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:797
void add_double(pbf_tag_type tag, double value)
Definition: pbf_writer.hpp:513
detail::packed_field_svarint< int32_t > packed_field_sint32
Class for generating packed repeated sint32 fields.
Definition: pbf_writer.hpp:1014
void add_bytes(pbf_tag_type tag, const char *value)
Definition: pbf_writer.hpp:560
void add_bytes(pbf_tag_type tag, const char *value, std::size_t size)
Definition: pbf_writer.hpp:525
All parts of the protozero header-only library are in this namespace.
Definition: byteswap.hpp:24