This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository protozero.
commit 7773fddd2ed050f080b54a5a53ccb572afb61a57 Author: Bas Couwenberg <sebas...@xs4all.nl> Date: Sat Aug 22 22:06:52 2015 +0200 Imported Upstream version 1.1.0 --- .gitignore | 4 +- CHANGELOG.md | 25 +++ Makefile | 11 +- bench/data/README.md | 13 ++ bench/data/enf-14-4824-6157.vector.pbf | Bin 0 -> 494060 bytes .../data/mapbox-streets-v6-14-8714-8017.vector.pbf | Bin 0 -> 129144 bytes include/protozero/byteswap.hpp | 49 +++++ include/protozero/pbf_builder.hpp | 111 ++++++++++ include/protozero/pbf_message.hpp | 50 +++++ include/protozero/pbf_reader.hpp | 232 +++++++++++++-------- include/protozero/pbf_writer.hpp | 43 ++-- include/protozero/varint.hpp | 4 - include/protozero/version.hpp | 22 ++ test/include/test.hpp | 6 +- 14 files changed, 454 insertions(+), 116 deletions(-) diff --git a/.gitignore b/.gitignore index 18430a8..ccd5ce5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,9 @@ coverage out protozero.Makefile tests.target.mk - +*.o +*.gcno +*.gcno #Visual Studio files and folders Release Debug diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..218d50b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,25 @@ + +# Change Log + +All notable changes to this project will be documented in this file. +This project adheres to [Semantic Versioning](http://semver.org/). + +## [unreleased] - + +### Added + +### Changed + +### Fixed + + +## [1.1.0] - 2015-08-22 + +### Changed + +- Make pbf reader and writer code endianess-aware. + + +[unreleased]: https://github.com/osmcode/libosmium/compare/v1.1.0...HEAD +[1.1.0]: https://github.com/osmcode/libosmium/compare/v1.0.0...v1.1.0 + diff --git a/Makefile b/Makefile index fb1774a..c771dc9 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,14 @@ COMMON_FLAGS := -fvisibility-inlines-hidden -std=c++11 $(WARNING_FLAGS) RELEASE_FLAGS := -O3 -DNDEBUG -march=native DEBUG_FLAGS := -O0 -g -fno-inline-functions +PTHREAD_FLAGS = OS:=$(shell uname -s) + +ifeq ($(OS),Linux) + PTHREAD_FLAGS = -pthread +endif + ifeq ($(OS),Darwin) CXXFLAGS += -stdlib=libc++ LDFLAGS += -stdlib=libc++ @@ -31,7 +37,8 @@ PROTO_FILES_CC := $(subst .proto,.pb.cc,$(PROTO_FILES)) PROTO_FILES_H := $(subst .proto,.pb.h,$(PROTO_FILES)) PROTO_FILES_O := $(subst .proto,.pb.o,$(PROTO_FILES)) -HPP_FILES := include/protozero/exception.hpp \ +HPP_FILES := include/protozero/byteswap.hpp \ + include/protozero/exception.hpp \ include/protozero/varint.hpp \ include/protozero/pbf_types.hpp \ include/protozero/pbf_reader.hpp \ @@ -64,7 +71,7 @@ all: ./test/tests test/writer_tests $(CXX) -c -I. -Iinclude -Itest/include $(CXXFLAGS) $(COMMON_FLAGS) $(DEBUG_FLAGS) $< -o $@ ./test/writer_tests: test/writer_tests.o $(PROTO_FILES_O) $(WRITER_TEST_CASES_O) - $(CXX) $(LDFLAGS) $(LDFLAGS_PROTOBUF) $^ -lprotobuf-lite -pthread -o $@ + $(CXX) $(LDFLAGS) $(LDFLAGS_PROTOBUF) $^ -lprotobuf-lite $(PTHREAD_FLAGS) -o $@ test: all ./test/tests diff --git a/bench/data/README.md b/bench/data/README.md new file mode 100644 index 0000000..202f94d --- /dev/null +++ b/bench/data/README.md @@ -0,0 +1,13 @@ + + +mapbox-streets-v6/14/8714/8017.vector.pbf + + - http://c.tile.openstreetmap.org/14/8714/8017.png + - https://a.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/14/8714/8017.vector.pbf + - https://www.mapbox.com/developers/vector-tiles/mapbox-streets/ + +enf-14-4824-6157.vector.pbf + + - enf.8k273nmi + - https://b.tiles.mapbox.com/v4/enf.c3a2de35/14/4824/6...@2x.png + - https://www.mapbox.com/blog/twitter-map-every-tweet/ \ No newline at end of file diff --git a/bench/data/enf-14-4824-6157.vector.pbf b/bench/data/enf-14-4824-6157.vector.pbf new file mode 100644 index 0000000..dcd8717 Binary files /dev/null and b/bench/data/enf-14-4824-6157.vector.pbf differ diff --git a/bench/data/mapbox-streets-v6-14-8714-8017.vector.pbf b/bench/data/mapbox-streets-v6-14-8714-8017.vector.pbf new file mode 100644 index 0000000..9553b22 Binary files /dev/null and b/bench/data/mapbox-streets-v6-14-8714-8017.vector.pbf differ diff --git a/include/protozero/byteswap.hpp b/include/protozero/byteswap.hpp new file mode 100644 index 0000000..d019c28 --- /dev/null +++ b/include/protozero/byteswap.hpp @@ -0,0 +1,49 @@ +#ifndef PROTOZERO_BYTESWAP_HPP +#define PROTOZERO_BYTESWAP_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +#include <cassert> + +namespace protozero { + +template <int N> +inline void byteswap(const char* /*data*/, char* /*result*/) { + assert(false); +} + +template <> +inline void byteswap<1>(const char* data, char* result) { + result[0] = data[0]; +} + +template <> +inline void byteswap<4>(const char* data, char* result) { + result[3] = data[0]; + result[2] = data[1]; + result[1] = data[2]; + result[0] = data[3]; +} + +template <> +inline void byteswap<8>(const char* data, char* result) { + result[7] = data[0]; + result[6] = data[1]; + result[5] = data[2]; + result[4] = data[3]; + result[3] = data[4]; + result[2] = data[5]; + result[1] = data[6]; + result[0] = data[7]; +} + +} // end namespace protozero + +#endif // PROTOZERO_BYTESWAP_HPP diff --git a/include/protozero/pbf_builder.hpp b/include/protozero/pbf_builder.hpp new file mode 100644 index 0000000..d49a7ba --- /dev/null +++ b/include/protozero/pbf_builder.hpp @@ -0,0 +1,111 @@ +#ifndef PROTOZERO_PBF_BUILDER_HPP +#define PROTOZERO_PBF_BUILDER_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +#include <type_traits> + +#include <protozero/pbf_types.hpp> +#include <protozero/pbf_writer.hpp> + +namespace protozero { + +template <typename T> +class pbf_builder : public pbf_writer { + + static_assert(std::is_same<pbf_tag_type, typename std::underlying_type<T>::type>::value, "T must be enum with underlying type protozero::pbf_tag_type"); + +public: + + using enum_type = T; + + pbf_builder(std::string& data) noexcept : + pbf_writer(data) { + } + + template <typename P> + pbf_builder(pbf_writer& parent_writer, P tag) noexcept : + pbf_writer(parent_writer, pbf_tag_type(tag)) { + } + +#define PROTOZERO_WRITER_WRAP_ADD_SCALAR(name, type) \ + inline void add_##name(T tag, type value) { \ + pbf_writer::add_##name(pbf_tag_type(tag), value); \ + } + + PROTOZERO_WRITER_WRAP_ADD_SCALAR(bool, bool) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(enum, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(int32, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint32, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint32, uint32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(int64, int64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint64, int64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint64, uint64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed32, uint32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed32, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed64, uint64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed64, int64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(float, float) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(double, double) + + inline void add_bytes(T tag, const char* value, size_t size) { + pbf_writer::add_bytes(pbf_tag_type(tag), value, size); + } + + inline void add_bytes(T tag, const std::string& value) { + pbf_writer::add_bytes(pbf_tag_type(tag), value); + } + + inline void add_string(T tag, const char* value, size_t size) { + pbf_writer::add_string(pbf_tag_type(tag), value, size); + } + + inline void add_string(T tag, const std::string& value) { + pbf_writer::add_string(pbf_tag_type(tag), value); + } + + inline void add_string(T tag, const char* value) { + pbf_writer::add_string(pbf_tag_type(tag), value); + } + + inline void add_message(T tag, const char* value, size_t size) { + pbf_writer::add_message(pbf_tag_type(tag), value, size); + } + + inline void add_message(T tag, const std::string& value) { + pbf_writer::add_message(pbf_tag_type(tag), value); + } + +#define PROTOZERO_WRITER_WRAP_ADD_PACKED(name) \ + template <typename InputIterator> \ + inline void add_packed_##name(T tag, InputIterator first, InputIterator last) { \ + pbf_writer::add_packed_##name(pbf_tag_type(tag), first, last); \ + } + + PROTOZERO_WRITER_WRAP_ADD_PACKED(bool) + PROTOZERO_WRITER_WRAP_ADD_PACKED(enum) + PROTOZERO_WRITER_WRAP_ADD_PACKED(int32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sint32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(uint32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(int64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sint64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(uint64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(float) + PROTOZERO_WRITER_WRAP_ADD_PACKED(double) + +}; + +} // end namespace protozero + +#endif // PROTOZERO_PBF_BUILDER_HPP diff --git a/include/protozero/pbf_message.hpp b/include/protozero/pbf_message.hpp new file mode 100644 index 0000000..af29a00 --- /dev/null +++ b/include/protozero/pbf_message.hpp @@ -0,0 +1,50 @@ +#ifndef PROTOZERO_PBF_MESSAGE_HPP +#define PROTOZERO_PBF_MESSAGE_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +#include <type_traits> + +#include <protozero/pbf_reader.hpp> +#include <protozero/pbf_types.hpp> + +namespace protozero { + +template <typename T> +class pbf_message : public pbf_reader { + + static_assert(std::is_same<pbf_tag_type, typename std::underlying_type<T>::type>::value, "T must be enum with underlying type protozero::pbf_tag_type"); + +public: + + using enum_type = T; + + template <typename... Args> + pbf_message(Args&&... args) noexcept : + pbf_reader(std::forward<Args>(args)...) { + } + + inline bool next() { + return pbf_reader::next(); + } + + inline bool next(T tag) { + return pbf_reader::next(pbf_tag_type(tag)); + } + + inline T tag() const noexcept { + return T(pbf_reader::tag()); + } + +}; + +} // end namespace protozero + +#endif // PROTOZERO_PBF_MESSAGE_HPP diff --git a/include/protozero/pbf_reader.hpp b/include/protozero/pbf_reader.hpp index b9426d4..1c5ed0d 100644 --- a/include/protozero/pbf_reader.hpp +++ b/include/protozero/pbf_reader.hpp @@ -16,10 +16,6 @@ documentation. * @brief Contains the pbf_reader class. */ -#if __BYTE_ORDER != __LITTLE_ENDIAN -# error "This code only works on little endian machines." -#endif - #include <cassert> #include <cstddef> #include <cstdint> @@ -32,9 +28,13 @@ documentation. #include <protozero/exception.hpp> #include <protozero/varint.hpp> +#if __BYTE_ORDER != __LITTLE_ENDIAN +# include <protozero/byteswap.hpp> +#endif + /// Wrapper for assert() used for testing -#ifndef pbf_assert -# define pbf_assert(x) assert(x) +#ifndef protozero_assert +# define protozero_assert(x) assert(x) #endif namespace protozero { @@ -77,10 +77,94 @@ class pbf_reader { // The tag of the current field. pbf_tag_type m_tag = 0; - template <typename T> inline T get_fixed(); + template <typename T> + inline T get_fixed() { + T result; + skip_bytes(sizeof(T)); +#if __BYTE_ORDER == __LITTLE_ENDIAN + memcpy(&result, m_data - sizeof(T), sizeof(T)); +#else + byteswap<sizeof(T)>(m_data - sizeof(T), reinterpret_cast<char*>(&result)); +#endif + return result; + } + +#if __BYTE_ORDER == __LITTLE_ENDIAN + template <typename T> + inline std::pair<const T*, const T*> packed_fixed() { + protozero_assert(tag() != 0 && "call next() before accessing field value"); + auto len = get_len_and_skip(); + protozero_assert(len % sizeof(T) == 0); + return std::make_pair(reinterpret_cast<const T*>(m_data-len), reinterpret_cast<const T*>(m_data)); + } + +#else + + template <typename T> + class const_fixed_iterator : public std::iterator<std::forward_iterator_tag, T> { + + const char* m_data; + const char* m_end; + + public: + + const_fixed_iterator() noexcept : + m_data(nullptr), + m_end(nullptr) { + } + + const_fixed_iterator(const char *data, const char* end) noexcept : + m_data(data), + m_end(end) { + } + + const_fixed_iterator(const const_fixed_iterator&) noexcept = default; + const_fixed_iterator(const_fixed_iterator&&) noexcept = default; + + const_fixed_iterator& operator=(const const_fixed_iterator&) noexcept = default; + const_fixed_iterator& operator=(const_fixed_iterator&&) noexcept = default; + + ~const_fixed_iterator() noexcept = default; + + T operator*() { + T result; + byteswap<sizeof(T)>(m_data, reinterpret_cast<char*>(&result)); + return result; + } + + const_fixed_iterator& operator++() { + m_data += sizeof(T); + return *this; + } + + const_fixed_iterator operator++(int) { + const const_fixed_iterator tmp(*this); + ++(*this); + return tmp; + } + + bool operator==(const const_fixed_iterator& rhs) const noexcept { + return m_data == rhs.m_data && m_end == rhs.m_end; + } + + bool operator!=(const const_fixed_iterator& rhs) const noexcept { + return !(*this == rhs); + } + + }; // class const_fixed_iterator + + template <typename T> + inline std::pair<const_fixed_iterator<T>, const_fixed_iterator<T>> packed_fixed() { + protozero_assert(tag() != 0 && "call next() before accessing field value"); + auto len = get_len_and_skip(); + protozero_assert(len % sizeof(T) == 0); + return std::make_pair(const_fixed_iterator<T>(m_data-len, m_data), + const_fixed_iterator<T>(m_data, m_data)); + } +#endif + template <typename T> inline T get_varint(); template <typename T> inline T get_svarint(); - template <typename T> inline std::pair<const T*, const T*> packed_fixed(); inline pbf_length_type get_length() { return get_varint<pbf_length_type>(); } @@ -273,7 +357,7 @@ public: * @post The current field was consumed and there is no current field now. */ inline int32_t get_enum() { - pbf_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); + protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); return get_varint<int32_t>(); } @@ -285,7 +369,7 @@ public: * @post The current field was consumed and there is no current field now. */ inline int32_t get_int32() { - pbf_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); + protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); return get_varint<int32_t>(); } @@ -297,7 +381,7 @@ public: * @post The current field was consumed and there is no current field now. */ inline int32_t get_sint32() { - pbf_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); + protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); return get_svarint<int32_t>(); } @@ -309,7 +393,7 @@ public: * @post The current field was consumed and there is no current field now. */ inline uint32_t get_uint32() { - pbf_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); + protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); return get_varint<uint32_t>(); } @@ -321,7 +405,7 @@ public: * @post The current field was consumed and there is no current field now. */ inline int64_t get_int64() { - pbf_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); + protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); return get_varint<int64_t>(); } @@ -333,7 +417,7 @@ public: * @post The current field was consumed and there is no current field now. */ inline int64_t get_sint64() { - pbf_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); + protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); return get_svarint<int64_t>(); } @@ -345,7 +429,7 @@ public: * @post The current field was consumed and there is no current field now. */ inline uint64_t get_uint64() { - pbf_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); + protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); return get_varint<uint64_t>(); } @@ -671,7 +755,9 @@ public: * @pre The current field must be of type "repeated packed fixed32". * @post The current field was consumed and there is no current field now. */ - inline std::pair<const uint32_t*, const uint32_t*> get_packed_fixed32(); + inline auto get_packed_fixed32() -> decltype(packed_fixed<uint32_t>()) { + return packed_fixed<uint32_t>(); + } /** * Consume current "repeated packed sfixed32" field. @@ -682,7 +768,9 @@ public: * @pre The current field must be of type "repeated packed sfixed32". * @post The current field was consumed and there is no current field now. */ - inline std::pair<const int32_t*, const int32_t*> get_packed_sfixed32(); + inline auto get_packed_sfixed32() -> decltype(packed_fixed<int32_t>()) { + return packed_fixed<int32_t>(); + } /** * Consume current "repeated packed fixed64" field. @@ -693,7 +781,9 @@ public: * @pre The current field must be of type "repeated packed fixed64". * @post The current field was consumed and there is no current field now. */ - inline std::pair<const uint64_t*, const uint64_t*> get_packed_fixed64(); + inline auto get_packed_fixed64() -> decltype(packed_fixed<uint64_t>()) { + return packed_fixed<uint64_t>(); + } /** * Consume current "repeated packed sfixed64" field. @@ -704,7 +794,9 @@ public: * @pre The current field must be of type "repeated packed sfixed64". * @post The current field was consumed and there is no current field now. */ - inline std::pair<const int64_t*, const int64_t*> get_packed_sfixed64(); + inline auto get_packed_sfixed64() -> decltype(packed_fixed<int64_t>()) { + return packed_fixed<int64_t>(); + } /** * Consume current "repeated packed float" field. @@ -715,7 +807,9 @@ public: * @pre The current field must be of type "repeated packed float". * @post The current field was consumed and there is no current field now. */ - inline std::pair<const float*, const float*> get_packed_float(); + inline auto get_packed_float() -> decltype(packed_fixed<float>()) { + return packed_fixed<float>(); + } /** * Consume current "repeated packed double" field. @@ -726,7 +820,9 @@ public: * @pre The current field must be of type "repeated packed double". * @post The current field was consumed and there is no current field now. */ - inline std::pair<const double*, const double*> get_packed_double(); + inline auto get_packed_double() -> decltype(packed_fixed<double>()) { + return packed_fixed<double>(); + } ///@} @@ -767,11 +863,11 @@ bool pbf_reader::next() { // tags 0 and 19000 to 19999 are not allowed as per // https://developers.google.com/protocol-buffers/docs/proto - pbf_assert(((m_tag > 0 && m_tag < 19000) || (m_tag > 19999 && m_tag <= ((1 << 29) - 1))) && "tag out of range"); + protozero_assert(((m_tag > 0 && m_tag < 19000) || (m_tag > 19999 && m_tag <= ((1 << 29) - 1))) && "tag out of range"); m_wire_type = pbf_wire_type(value & 0x07); // XXX do we want this check? or should it throw an exception? -// pbf_assert((m_wire_type <=2 || m_wire_type == 5) && "illegal wire type"); +// protozero_assert((m_wire_type <=2 || m_wire_type == 5) && "illegal wire type"); return true; } @@ -812,7 +908,7 @@ void pbf_reader::skip_bytes(pbf_length_type len) { } void pbf_reader::skip() { - pbf_assert(tag() != 0 && "call next() before calling skip()"); + protozero_assert(tag() != 0 && "call next() before calling skip()"); switch (wire_type()) { case pbf_wire_type::varint: (void)get_uint32(); // called for the side-effect of skipping value @@ -844,65 +940,57 @@ T pbf_reader::get_varint() { template <typename T> T pbf_reader::get_svarint() { - pbf_assert((has_wire_type(pbf_wire_type::varint) || has_wire_type(pbf_wire_type::length_delimited)) && "not a varint"); + protozero_assert((has_wire_type(pbf_wire_type::varint) || has_wire_type(pbf_wire_type::length_delimited)) && "not a varint"); return static_cast<T>(decode_zigzag64(decode_varint(&m_data, m_end))); } -template <typename T> -T pbf_reader::get_fixed() { - T result; - skip_bytes(sizeof(T)); - memcpy(&result, m_data - sizeof(T), sizeof(T)); - return result; -} - uint32_t pbf_reader::get_fixed32() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); - pbf_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed"); return get_fixed<uint32_t>(); } int32_t pbf_reader::get_sfixed32() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); - pbf_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed"); return get_fixed<int32_t>(); } uint64_t pbf_reader::get_fixed64() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); - pbf_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed"); return get_fixed<uint64_t>(); } int64_t pbf_reader::get_sfixed64() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); - pbf_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed"); return get_fixed<int64_t>(); } float pbf_reader::get_float() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); - pbf_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed"); return get_fixed<float>(); } double pbf_reader::get_double() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); - pbf_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed"); return get_fixed<double>(); } bool pbf_reader::get_bool() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); - pbf_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); - pbf_assert((*m_data & 0x80) == 0 && "not a 1 byte varint"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); + protozero_assert((*m_data & 0x80) == 0 && "not a 1 byte varint"); skip_bytes(1); return m_data[-1] != 0; // -1 okay because we incremented m_data the line before } std::pair<const char*, pbf_length_type> pbf_reader::get_data() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); - pbf_assert(has_wire_type(pbf_wire_type::length_delimited) && "not of type string, bytes or message"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(has_wire_type(pbf_wire_type::length_delimited) && "not of type string, bytes or message"); auto len = get_len_and_skip(); return std::make_pair(m_data-len, len); } @@ -916,38 +1004,6 @@ std::string pbf_reader::get_string() { return get_bytes(); } -template <typename T> -std::pair<const T*, const T*> pbf_reader::packed_fixed() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); - auto len = get_len_and_skip(); - pbf_assert(len % sizeof(T) == 0); - return std::make_pair(reinterpret_cast<const T*>(m_data-len), reinterpret_cast<const T*>(m_data)); -} - -std::pair<const uint32_t*, const uint32_t*> pbf_reader::get_packed_fixed32() { - return packed_fixed<uint32_t>(); -} - -std::pair<const uint64_t*, const uint64_t*> pbf_reader::get_packed_fixed64() { - return packed_fixed<uint64_t>(); -} - -std::pair<const int32_t*, const int32_t*> pbf_reader::get_packed_sfixed32() { - return packed_fixed<int32_t>(); -} - -std::pair<const int64_t*, const int64_t*> pbf_reader::get_packed_sfixed64() { - return packed_fixed<int64_t>(); -} - -std::pair<const float*, const float*> pbf_reader::get_packed_float() { - return packed_fixed<float>(); -} - -std::pair<const double*, const double*> pbf_reader::get_packed_double() { - return packed_fixed<double>(); -} - std::pair<pbf_reader::const_bool_iterator, pbf_reader::const_bool_iterator> pbf_reader::get_packed_bool() { return get_packed_int32(); } @@ -957,42 +1013,42 @@ std::pair<pbf_reader::const_enum_iterator, pbf_reader::const_enum_iterator> pbf_ } std::pair<pbf_reader::const_int32_iterator, pbf_reader::const_int32_iterator> pbf_reader::get_packed_int32() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); auto len = get_len_and_skip(); return std::make_pair(pbf_reader::const_int32_iterator(m_data-len, m_data), pbf_reader::const_int32_iterator(m_data, m_data)); } std::pair<pbf_reader::const_uint32_iterator, pbf_reader::const_uint32_iterator> pbf_reader::get_packed_uint32() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); auto len = get_len_and_skip(); return std::make_pair(pbf_reader::const_uint32_iterator(m_data-len, m_data), pbf_reader::const_uint32_iterator(m_data, m_data)); } std::pair<pbf_reader::const_sint32_iterator, pbf_reader::const_sint32_iterator> pbf_reader::get_packed_sint32() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); auto len = get_len_and_skip(); return std::make_pair(pbf_reader::const_sint32_iterator(m_data-len, m_data), pbf_reader::const_sint32_iterator(m_data, m_data)); } std::pair<pbf_reader::const_int64_iterator, pbf_reader::const_int64_iterator> pbf_reader::get_packed_int64() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); auto len = get_len_and_skip(); return std::make_pair(pbf_reader::const_int64_iterator(m_data-len, m_data), pbf_reader::const_int64_iterator(m_data, m_data)); } std::pair<pbf_reader::const_uint64_iterator, pbf_reader::const_uint64_iterator> pbf_reader::get_packed_uint64() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); auto len = get_len_and_skip(); return std::make_pair(pbf_reader::const_uint64_iterator(m_data-len, m_data), pbf_reader::const_uint64_iterator(m_data, m_data)); } std::pair<pbf_reader::const_sint64_iterator, pbf_reader::const_sint64_iterator> pbf_reader::get_packed_sint64() { - pbf_assert(tag() != 0 && "call next() before accessing field value"); + protozero_assert(tag() != 0 && "call next() before accessing field value"); auto len = get_len_and_skip(); return std::make_pair(pbf_reader::const_sint64_iterator(m_data-len, m_data), pbf_reader::const_sint64_iterator(m_data, m_data)); diff --git a/include/protozero/pbf_writer.hpp b/include/protozero/pbf_writer.hpp index 14b0856..53cbfdf 100644 --- a/include/protozero/pbf_writer.hpp +++ b/include/protozero/pbf_writer.hpp @@ -16,23 +16,24 @@ documentation. * @brief Contains the pbf_writer class. */ -#if __BYTE_ORDER != __LITTLE_ENDIAN -# error "This code only works on little endian machines." -#endif - #include <cassert> #include <cstddef> #include <cstdint> #include <cstring> #include <iterator> +#include <limits> #include <string> #include <protozero/pbf_types.hpp> #include <protozero/varint.hpp> +#if __BYTE_ORDER != __LITTLE_ENDIAN +# include <protozero/byteswap.hpp> +#endif + /// Wrapper for assert() used for testing -#ifndef pbf_assert -# define pbf_assert(x) assert(x) +#ifndef protozero_assert +# define protozero_assert(x) assert(x) #endif namespace protozero { @@ -50,13 +51,13 @@ class pbf_writer { size_t m_pos = 0; inline void add_varint(uint64_t value) { - pbf_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - pbf_assert(m_data); + 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"); + protozero_assert(m_data); write_varint(std::back_inserter(*m_data), value); } inline void add_field(pbf_tag_type tag, pbf_wire_type type) { - pbf_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1 << 29) - 1))) && "tag out of range"); + protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1 << 29) - 1))) && "tag out of range"); uint32_t b = (tag << 3) | uint32_t(type); add_varint(b); } @@ -68,9 +69,15 @@ class pbf_writer { template <typename T> inline void add_fixed(T value) { - pbf_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - pbf_assert(m_data); + 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"); + protozero_assert(m_data); +#if __BYTE_ORDER == __LITTLE_ENDIAN m_data->append(reinterpret_cast<const char*>(&value), sizeof(T)); +#else + auto size = m_data->size(); + m_data->resize(size + sizeof(T)); + byteswap<sizeof(T)>(reinterpret_cast<const char*>(&value), const_cast<char*>(m_data->data() + size)); +#endif } template <typename T, typename It> @@ -131,19 +138,19 @@ class pbf_writer { static const int reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1; inline void open_submessage(pbf_tag_type tag) { - pbf_assert(m_pos == 0); - pbf_assert(m_data); + protozero_assert(m_pos == 0); + protozero_assert(m_data); add_field(tag, pbf_wire_type::length_delimited); m_data->append(size_t(reserve_bytes), '\0'); m_pos = m_data->size(); } inline void close_submessage() { - pbf_assert(m_pos != 0); - pbf_assert(m_data); + protozero_assert(m_pos != 0); + protozero_assert(m_data); auto length = pbf_length_type(m_data->size() - m_pos); - pbf_assert(m_data->size() >= m_pos - reserve_bytes); + protozero_assert(m_data->size() >= m_pos - reserve_bytes); auto n = write_varint(m_data->begin() + long(m_pos) - reserve_bytes, length); m_data->erase(m_data->begin() + long(m_pos) - reserve_bytes + n, m_data->begin() + long(m_pos)); @@ -369,8 +376,8 @@ public: * @param size Number of bytes to be written */ inline void add_bytes(pbf_tag_type tag, const char* value, size_t size) { - pbf_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - pbf_assert(m_data); + 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"); + protozero_assert(m_data); assert(size <= std::numeric_limits<pbf_length_type>::max()); add_length_varint(tag, pbf_length_type(size)); m_data->append(value, size); diff --git a/include/protozero/varint.hpp b/include/protozero/varint.hpp index bc9c329..27536fd 100644 --- a/include/protozero/varint.hpp +++ b/include/protozero/varint.hpp @@ -16,10 +16,6 @@ documentation. * @brief Contains low-level varint and zigzag encoding and decoding functions. */ -#if __BYTE_ORDER != __LITTLE_ENDIAN -# error "This code only works on little endian machines." -#endif - #include <cstdint> #include <protozero/exception.hpp> diff --git a/include/protozero/version.hpp b/include/protozero/version.hpp new file mode 100644 index 0000000..098492e --- /dev/null +++ b/include/protozero/version.hpp @@ -0,0 +1,22 @@ +#ifndef PROTOZERO_VERSION_HPP +#define PROTOZERO_VERSION_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +#define PROTOZERO_VERSION_MAJOR 1 +#define PROTOZERO_VERSION_MINOR 1 +#define PROTOZERO_VERSION_PATCH 0 + +#define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH) + +#define PROTOZERO_VERSION_STRING "1.1.0" + + +#endif // PROTOZERO_VERSION_HPP diff --git a/test/include/test.hpp b/test/include/test.hpp index a6a0b0c..33527a2 100644 --- a/test/include/test.hpp +++ b/test/include/test.hpp @@ -2,13 +2,13 @@ #include <catch.hpp> #include <stdexcept> -// Define pbf_assert() to throw this error. This allows the tests to check that -// the assert fails. +// Define protozero_assert() to throw this error. This allows the tests to +// check that the assert fails. struct assert_error : public std::runtime_error { assert_error(const char* what_arg) : std::runtime_error(what_arg) { } }; -#define pbf_assert(x) if (!(x)) { throw(assert_error(#x)); } +#define protozero_assert(x) if (!(x)) { throw(assert_error(#x)); } #include <protozero/pbf_reader.hpp> #include <protozero/pbf_writer.hpp> -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/protozero.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel