1 #ifndef PROTOZERO_PBF_WRITER_HPP 2 #define PROTOZERO_PBF_WRITER_HPP 24 #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN 31 #include <initializer_list> 41 template <
typename T>
class packed_field_varint;
42 template <
typename T>
class packed_field_svarint;
43 template <
typename T>
class packed_field_fixed;
58 std::string* m_data =
nullptr;
68 std::size_t m_rollback_pos = 0;
72 std::size_t m_pos = 0;
74 void add_varint(uint64_t value) {
75 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");
76 protozero_assert(m_data);
81 protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1u << 29u) - 1))) &&
"tag out of range");
82 const uint32_t b = (tag << 3u) | uint32_t(type);
86 void add_tagged_varint(
pbf_tag_type tag, uint64_t value) {
87 add_field(tag, pbf_wire_type::varint);
92 void add_fixed(T value) {
93 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");
94 protozero_assert(m_data);
95 #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN 96 byteswap_inplace(&value);
98 m_data->append(reinterpret_cast<const char*>(&value),
sizeof(T));
101 template <
typename T,
typename It>
102 void add_packed_fixed(
pbf_tag_type tag, It first, It last, std::input_iterator_tag ) {
109 while (first != last) {
110 sw.add_fixed<T>(*first++);
114 template <
typename T,
typename It>
115 void add_packed_fixed(
pbf_tag_type tag, It first, It last, std::forward_iterator_tag ) {
120 const auto length = std::distance(first, last);
122 reserve(
sizeof(T) * std::size_t(length));
124 while (first != last) {
125 add_fixed<T>(*first++);
129 template <
typename It>
130 void add_packed_varint(
pbf_tag_type tag, It first, It last) {
137 while (first != last) {
138 sw.add_varint(uint64_t(*first++));
142 template <
typename It>
143 void add_packed_svarint(
pbf_tag_type tag, It first, It last) {
150 while (first != last) {
158 enum constant_reserve_bytes :
int {
165 enum constant_size_is_known : std::size_t {
166 size_is_known = std::numeric_limits<std::size_t>::max()
169 void open_submessage(
pbf_tag_type tag, std::size_t size) {
170 protozero_assert(m_pos == 0);
171 protozero_assert(m_data);
173 m_rollback_pos = m_data->size();
174 add_field(tag, pbf_wire_type::length_delimited);
175 m_data->append(std::size_t(reserve_bytes),
'\0');
177 m_rollback_pos = size_is_known;
181 m_pos = m_data->size();
184 void rollback_submessage() {
185 protozero_assert(m_pos != 0);
186 protozero_assert(m_rollback_pos != size_is_known);
187 protozero_assert(m_data);
188 m_data->resize(m_rollback_pos);
192 void commit_submessage() {
193 protozero_assert(m_pos != 0);
194 protozero_assert(m_rollback_pos != size_is_known);
195 protozero_assert(m_data);
198 protozero_assert(m_data->size() >= m_pos - reserve_bytes);
199 const auto n =
write_varint(m_data->begin() + int64_t(m_pos) - reserve_bytes, length);
201 m_data->erase(m_data->begin() + int64_t(m_pos) - reserve_bytes + n, m_data->begin() + int64_t(m_pos));
205 void close_submessage() {
206 protozero_assert(m_data);
207 if (m_pos == 0 || m_rollback_pos == size_is_known) {
210 if (m_data->size() - m_pos == 0) {
211 rollback_submessage();
218 add_field(tag, pbf_wire_type::length_delimited);
250 m_data(parent_writer.m_data),
251 m_parent_writer(&parent_writer) {
252 m_parent_writer->open_submessage(tag, size);
266 m_data(other.m_data),
267 m_parent_writer(other.m_parent_writer),
268 m_rollback_pos(other.m_rollback_pos),
270 other.m_data =
nullptr;
271 other.m_parent_writer =
nullptr;
272 other.m_rollback_pos = 0;
281 m_data = other.m_data;
282 m_parent_writer = other.m_parent_writer;
283 m_rollback_pos = other.m_rollback_pos;
285 other.m_data =
nullptr;
286 other.m_parent_writer =
nullptr;
287 other.m_rollback_pos = 0;
293 if (m_parent_writer !=
nullptr) {
294 m_parent_writer->close_submessage();
304 return m_data !=
nullptr;
314 swap(m_data, other.m_data);
315 swap(m_parent_writer, other.m_parent_writer);
316 swap(m_rollback_pos, other.m_rollback_pos);
317 swap(m_pos, other.m_pos);
329 protozero_assert(m_data);
330 m_data->reserve(m_data->size() + size);
342 protozero_assert(m_parent_writer &&
"you can't call commit() on a pbf_writer without a parent");
343 protozero_assert(m_pos == 0 &&
"you can't call commit() on a pbf_writer that has an open nested submessage");
344 m_parent_writer->close_submessage();
345 m_parent_writer =
nullptr;
358 protozero_assert(m_parent_writer &&
"you can't call rollback() on a pbf_writer without a parent");
359 protozero_assert(m_pos == 0 &&
"you can't call rollback() on a pbf_writer that has an open nested submessage");
360 m_parent_writer->rollback_submessage();
361 m_parent_writer =
nullptr;
377 add_field(tag, pbf_wire_type::varint);
378 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");
379 protozero_assert(m_data);
380 m_data->append(1,
char(value));
390 add_tagged_varint(tag, uint64_t(value));
400 add_tagged_varint(tag, uint64_t(value));
420 add_tagged_varint(tag, value);
430 add_tagged_varint(tag, uint64_t(value));
450 add_tagged_varint(tag, value);
460 add_field(tag, pbf_wire_type::fixed32);
461 add_fixed<uint32_t>(value);
471 add_field(tag, pbf_wire_type::fixed32);
472 add_fixed<int32_t>(value);
482 add_field(tag, pbf_wire_type::fixed64);
483 add_fixed<uint64_t>(value);
493 add_field(tag, pbf_wire_type::fixed64);
494 add_fixed<int64_t>(value);
504 add_field(tag, pbf_wire_type::fixed32);
505 add_fixed<float>(value);
515 add_field(tag, pbf_wire_type::fixed64);
516 add_fixed<double>(value);
527 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");
528 protozero_assert(m_data);
529 protozero_assert(size <= std::numeric_limits<pbf_length_type>::max());
531 m_data->append(value, size);
551 add_bytes(tag, value.data(), value.size());
562 add_bytes(tag, value, std::strlen(value));
584 template <
typename... Ts>
586 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");
587 protozero_assert(m_data);
589 (void)std::initializer_list<size_t>{sum_size += values.size()...};
590 protozero_assert(sum_size <= std::numeric_limits<pbf_length_type>::max());
592 m_data->reserve(m_data->size() + sum_size);
593 (void)std::initializer_list<int>{(m_data->append(values.data(), values.size()), 0)...};
624 add_bytes(tag, value.data(), value.size());
635 add_bytes(tag, value, std::strlen(value));
666 add_bytes(tag, value.data(), value.size());
685 template <
typename InputIterator>
687 add_packed_varint(tag, first, last);
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_svarint(tag, first, last);
741 template <
typename InputIterator>
743 add_packed_varint(tag, first, last);
755 template <
typename InputIterator>
757 add_packed_varint(tag, first, last);
769 template <
typename InputIterator>
771 add_packed_svarint(tag, first, last);
783 template <
typename InputIterator>
785 add_packed_varint(tag, first, last);
797 template <
typename InputIterator>
799 add_packed_fixed<uint32_t, InputIterator>(tag, first, last,
800 typename std::iterator_traits<InputIterator>::iterator_category());
812 template <
typename InputIterator>
814 add_packed_fixed<int32_t, InputIterator>(tag, first, last,
815 typename std::iterator_traits<InputIterator>::iterator_category());
827 template <
typename InputIterator>
829 add_packed_fixed<uint64_t, InputIterator>(tag, first, last,
830 typename std::iterator_traits<InputIterator>::iterator_category());
842 template <
typename InputIterator>
844 add_packed_fixed<int64_t, InputIterator>(tag, first, last,
845 typename std::iterator_traits<InputIterator>::iterator_category());
857 template <
typename InputIterator>
859 add_packed_fixed<float, InputIterator>(tag, first, last,
860 typename std::iterator_traits<InputIterator>::iterator_category());
872 template <
typename InputIterator>
874 add_packed_fixed<double, InputIterator>(tag, first, last,
875 typename std::iterator_traits<InputIterator>::iterator_category());
880 template <
typename T>
friend class detail::packed_field_varint;
881 template <
typename T>
friend class detail::packed_field_svarint;
882 template <
typename T>
friend class detail::packed_field_fixed;
902 pbf_writer m_writer{};
906 packed_field(
const packed_field&) =
delete;
907 packed_field& operator=(
const packed_field&) =
delete;
909 packed_field(packed_field&&) noexcept = default;
910 packed_field& operator=(packed_field&&) noexcept = default;
912 packed_field() = default;
914 packed_field(pbf_writer& parent_writer,
pbf_tag_type tag) :
915 m_writer(parent_writer, tag) {
918 packed_field(pbf_writer& parent_writer,
pbf_tag_type tag, std::size_t size) :
919 m_writer(parent_writer, tag, size) {
922 ~packed_field() noexcept = default;
924 bool valid() const noexcept {
925 return m_writer.valid();
938 template <
typename T>
939 class packed_field_fixed :
public packed_field {
943 packed_field_fixed() :
947 template <
typename P>
948 packed_field_fixed(pbf_writer& parent_writer, P tag) :
949 packed_field(parent_writer, static_cast<
pbf_tag_type>(tag)) {
952 template <
typename P>
953 packed_field_fixed(pbf_writer& parent_writer, P tag, std::size_t size) :
954 packed_field(parent_writer, static_cast<
pbf_tag_type>(tag), size * sizeof(T)) {
957 void add_element(T value) {
958 m_writer.add_fixed<T>(value);
963 template <
typename T>
964 class packed_field_varint :
public packed_field {
968 packed_field_varint() :
972 template <
typename P>
973 packed_field_varint(pbf_writer& parent_writer, P tag) :
974 packed_field(parent_writer, static_cast<
pbf_tag_type>(tag)) {
977 void add_element(T value) {
978 m_writer.add_varint(uint64_t(value));
983 template <
typename T>
984 class packed_field_svarint :
public packed_field {
988 packed_field_svarint() :
992 template <
typename P>
993 packed_field_svarint(pbf_writer& parent_writer, P tag) :
994 packed_field(parent_writer, static_cast<
pbf_tag_type>(tag)) {
997 void add_element(T value) {
1049 #endif // PROTOZERO_PBF_WRITER_HPP void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:828
void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:728
detail::packed_field_fixed< float > packed_field_float
Class for generating packed repeated float fields.
Definition: pbf_writer.hpp:1042
void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:770
void add_string(pbf_tag_type tag, const char *value)
Definition: pbf_writer.hpp:634
void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:843
void rollback()
Definition: pbf_writer.hpp:357
void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:813
constexpr uint64_t encode_zigzag64(int64_t value) noexcept
Definition: varint.hpp:168
pbf_writer & operator=(const pbf_writer &)=delete
A pbf_writer object can not be copied.
void reserve(std::size_t size)
Definition: pbf_writer.hpp:328
void add_sint64(pbf_tag_type tag, int64_t value)
Definition: pbf_writer.hpp:439
void add_message(pbf_tag_type tag, const char *value, std::size_t size)
Definition: pbf_writer.hpp:645
pbf_writer(pbf_writer &&other) noexcept
Definition: pbf_writer.hpp:265
detail::packed_field_varint< int64_t > packed_field_int64
Class for generating packed repeated int64 fields.
Definition: pbf_writer.hpp:1021
void add_sfixed64(pbf_tag_type tag, int64_t value)
Definition: pbf_writer.hpp:492
void add_uint32(pbf_tag_type tag, uint32_t value)
Definition: pbf_writer.hpp:419
void add_bytes(pbf_tag_type tag, const std::string &value)
Definition: pbf_writer.hpp:550
void add_string(pbf_tag_type tag, const char *value, std::size_t size)
Definition: pbf_writer.hpp:603
void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:700
Definition: iterators.hpp:416
detail::packed_field_fixed< int64_t > packed_field_sfixed64
Class for generating packed repeated sfixed64 fields.
Definition: pbf_writer.hpp:1039
void add_message(pbf_tag_type tag, const data_view &value)
Definition: pbf_writer.hpp:655
Definition: pbf_writer.hpp:53
void add_int64(pbf_tag_type tag, int64_t value)
Definition: pbf_writer.hpp:429
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:1006
detail::packed_field_fixed< double > packed_field_double
Class for generating packed repeated double fields.
Definition: pbf_writer.hpp:1045
Contains the declaration of low-level types used in the pbf format.
constexpr uint32_t encode_zigzag32(int32_t value) noexcept
Definition: varint.hpp:161
void add_int32(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:399
void add_string(pbf_tag_type tag, const std::string &value)
Definition: pbf_writer.hpp:623
pbf_writer & operator=(pbf_writer &&other) noexcept
Definition: pbf_writer.hpp:280
int write_varint(T data, uint64_t value)
Definition: varint.hpp:145
void add_uint64(pbf_tag_type tag, uint64_t value)
Definition: pbf_writer.hpp:449
constexpr std::size_t size() const noexcept
Return length of data in bytes.
Definition: data_view.hpp:99
void add_string(pbf_tag_type tag, const data_view &value)
Definition: pbf_writer.hpp:613
detail::packed_field_varint< int32_t > packed_field_int32
Class for generating packed repeated int32 fields.
Definition: pbf_writer.hpp:1012
pbf_wire_type
Definition: types.hpp:40
void add_message(pbf_tag_type tag, const std::string &value)
Definition: pbf_writer.hpp:665
void add_float(pbf_tag_type tag, float value)
Definition: pbf_writer.hpp:503
Contains the implementation of the data_view class.
void swap(pbf_writer &other) noexcept
Definition: pbf_writer.hpp:312
void add_enum(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:389
detail::packed_field_svarint< int64_t > packed_field_sint64
Class for generating packed repeated sint64 fields.
Definition: pbf_writer.hpp:1024
void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:784
void add_bytes_vectored(pbf_tag_type tag, Ts &&... values)
Definition: pbf_writer.hpp:585
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:742
void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:756
void add_fixed64(pbf_tag_type tag, uint64_t value)
Definition: pbf_writer.hpp:481
uint32_t pbf_length_type
Definition: types.hpp:62
void add_bool(pbf_tag_type tag, bool value)
Definition: pbf_writer.hpp:376
void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:686
detail::packed_field_fixed< uint64_t > packed_field_fixed64
Class for generating packed repeated fixed64 fields.
Definition: pbf_writer.hpp:1036
detail::packed_field_fixed< int32_t > packed_field_sfixed32
Class for generating packed repeated sfixed32 fields.
Definition: pbf_writer.hpp:1033
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:1018
void commit()
Definition: pbf_writer.hpp:341
void swap(pbf_writer &lhs, pbf_writer &rhs) noexcept
Definition: pbf_writer.hpp:892
void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:873
Definition: data_view.hpp:39
void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:858
detail::packed_field_varint< uint64_t > packed_field_uint64
Class for generating packed repeated uint64 fields.
Definition: pbf_writer.hpp:1027
void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:714
constexpr const char * data() const noexcept
Return pointer to data.
Definition: data_view.hpp:94
void add_sfixed32(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:470
pbf_writer(std::string &data) noexcept
Definition: pbf_writer.hpp:229
Contains low-level varint and zigzag encoding and decoding functions.
void add_sint32(pbf_tag_type tag, int32_t value)
Definition: pbf_writer.hpp:409
detail::packed_field_varint< int32_t > packed_field_enum
Class for generating packed repeated enum fields.
Definition: pbf_writer.hpp:1009
void add_fixed32(pbf_tag_type tag, uint32_t value)
Definition: pbf_writer.hpp:459
detail::packed_field_fixed< uint32_t > packed_field_fixed32
Class for generating packed repeated fixed32 fields.
Definition: pbf_writer.hpp:1030
void add_bytes(pbf_tag_type tag, const data_view &value)
Definition: pbf_writer.hpp:540
bool valid() const noexcept
Definition: pbf_writer.hpp:303
void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last)
Definition: pbf_writer.hpp:798
void add_double(pbf_tag_type tag, double value)
Definition: pbf_writer.hpp:514
detail::packed_field_svarint< int32_t > packed_field_sint32
Class for generating packed repeated sint32 fields.
Definition: pbf_writer.hpp:1015
void add_bytes(pbf_tag_type tag, const char *value)
Definition: pbf_writer.hpp:561
void add_bytes(pbf_tag_type tag, const char *value, std::size_t size)
Definition: pbf_writer.hpp:526
All parts of the protozero header-only library are in this namespace.
Definition: byteswap.hpp:23
pbf_writer() noexcept=default
void swap(data_view &lhs, data_view &rhs) noexcept
Definition: data_view.hpp:165