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;
58 template <
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;
935 template <
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) {
1054 #endif // PROTOZERO_BASIC_PBF_WRITER_HPP