Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos committed Apr 7, 2024
1 parent 50cc22f commit 81f1eac
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 38 deletions.
92 changes: 92 additions & 0 deletions iguana/pb_util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#pragma once
#include <cassert>
#include <cstring>
#include <map>
#include <string>
#include <vector>

namespace iguana {
namespace detail {
[[nodiscard]] inline uint32_t encode_zigzag(int32_t v) {
return (static_cast<uint32_t>(v) << 1U) ^
static_cast<uint32_t>(
-static_cast<int32_t>(static_cast<uint32_t>(v) >> 31U));
}
[[nodiscard]] inline uint64_t encode_zigzag(int64_t v) {
return (static_cast<uint64_t>(v) << 1U) ^
static_cast<uint64_t>(
-static_cast<int64_t>(static_cast<uint64_t>(v) >> 63U));
}

[[nodiscard]] inline int64_t decode_zigzag(uint64_t u) {
return static_cast<int64_t>((u >> 1U)) ^
static_cast<uint64_t>(-static_cast<int64_t>(u & 1U));
}
[[nodiscard]] inline int64_t decode_zigzag(uint32_t u) {
return static_cast<int64_t>((u >> 1U)) ^
static_cast<uint64_t>(-static_cast<int64_t>(u & 1U));
}

[[nodiscard]] inline bool decode_varint(const char* data, std::size_t& pos_,
std::size_t size_, uint64_t& v) {
// fix test failed on arm due to different char definition
const signed char* data_ = reinterpret_cast<const signed char*>(data);
// from https://github.com/facebook/folly/blob/main/folly/Varint.h
if (pos_ < size_ && (static_cast<uint64_t>(data_[pos_]) & 0x80U) == 0) {
v = static_cast<uint64_t>(data_[pos_]);
pos_++;
return true;
}
constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1;
uint64_t val = 0;
if (size_ - pos_ >= max_varint_length) [[likely]] {
do {
// clang-format off
int64_t b = data_[pos_++];
val = ((uint64_t(b) & 0x7fU) ); if (b >= 0) { break; }
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 7U); if (b >= 0) { break; }
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 14U); if (b >= 0) { break; }
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 21U); if (b >= 0) { break; }
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 28U); if (b >= 0) { break; }
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 35U); if (b >= 0) { break; }
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 42U); if (b >= 0) { break; }
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 49U); if (b >= 0) { break; }
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 56U); if (b >= 0) { break; }
b = data_[pos_++]; val |= ((uint64_t(b) & 0x01U) << 63U); if (b >= 0) { break; }
// clang-format on
return false;
} while (false);
}
else {
unsigned int shift = 0;
while (pos_ != size_ && int64_t(data_[pos_]) < 0) {
val |= (uint64_t(data_[pos_++]) & 0x7fU) << shift;
shift += 7;
}
if (pos_ == size_) {
return false;
}
val |= uint64_t(data_[pos_++]) << shift;
}
v = val;
return true;
}

template <typename Stream>
inline void serialize_varint(uint64_t v, Stream& out) {
while (v >= 0x80) {
out.push_back(static_cast<uint8_t>(v | 0x80));
v >>= 7;
}
out.push_back(static_cast<uint8_t>(v));
}
[[nodiscard]] inline bool deserialize_varint(const char* data, std::size_t& pos,
std::size_t size, uint64_t& v) {
return decode_varint(data, pos, size, v);
}
[[nodiscard]] inline bool read_tag(const char* data, std::size_t& pos,
std::size_t size, uint64_t& tag) {
return deserialize_varint(data, pos, size, tag);
}
} // namespace detail
} // namespace iguana
46 changes: 8 additions & 38 deletions iguana/struct_pb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
#include <utility>
#include <variant>

#include "pb_util.hpp"
#include "reflection.hpp"

namespace iguana {
namespace detail {
enum class WireType : uint32_t {
Expand All @@ -19,53 +21,21 @@ enum class WireType : uint32_t {
Fixed32 = 5,
};

template <class To, class From>
inline To bit_cast(From from) {
static_assert(sizeof(To) == sizeof(From), "");
static_assert(std::is_trivially_copyable_v<To>, "");
static_assert(std::is_trivially_copyable_v<From>, "");

To to;
std::memcpy(&to, &from, sizeof(from));
return to;
}

inline void write_varint(uint32_t value, auto& out) {
uint8_t b[5]{};
for (size_t i = 0; i < 5; ++i) {
b[i] = value & 0b0111'1111;
value >>= 7;
if (value) {
b[i] |= 0b1000'0000;
}
else {
out.append((const char*)b, i + 1);
// out.write(b, i + 1);
break;
}
}
}

inline void write_varint(int32_t value, auto& out) {
write_varint(bit_cast<uint32_t>(value), out);
}

inline uint32_t make_tag_wire_type(uint32_t tag, WireType wire_type) {
return (tag << 3) | static_cast<uint32_t>(wire_type);
}

inline void write_tag_wire_type(uint32_t tag, WireType wire_type, auto& out) {
write_varint(make_tag_wire_type(tag, wire_type), out);
}

struct varint_serializer {
static void serialize(uint32_t tag, int32_t value, auto& out) {
template <typename T>
static void serialize(uint32_t field_number, int32_t value, T& out) {
if (value == 0) {
return;
}

write_tag_wire_type(tag, WireType::Varint, out);
write_varint(value, out);
uint32_t key =
(field_number << 3) | static_cast<uint32_t>(WireType::Varint);
serialize_varint(key, out);
serialize_varint(value, out);
}
};
} // namespace detail
Expand Down

0 comments on commit 81f1eac

Please sign in to comment.