diff options
author | Joshua Haberman <jhaberman@gmail.com> | 2018-12-08 09:54:09 +0100 |
---|---|---|
committer | Joshua Haberman <jhaberman@gmail.com> | 2018-12-08 09:54:09 +0100 |
commit | 14c96a143c63a01c1080a23d9e1c0196d06f0e5e (patch) | |
tree | f59388c3d84b175c335581a0f065e2c31d22834a /upbc/message_layout.h | |
parent | e77ab811ba3e1ed069822cb5dccb4d643d3e56d3 (diff) | |
parent | 35fa3df8ecc3f451af0512e70a03f89ee407c85c (diff) |
Merge branch 'cmake-mac-fixes' into defcleanup
Diffstat (limited to 'upbc/message_layout.h')
-rw-r--r-- | upbc/message_layout.h | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/upbc/message_layout.h b/upbc/message_layout.h new file mode 100644 index 0000000..bdcc336 --- /dev/null +++ b/upbc/message_layout.h @@ -0,0 +1,104 @@ + +#ifndef UPBC_MESSAGE_LAYOUT_H +#define UPBC_MESSAGE_LAYOUT_H + +#include <unordered_map> +#include "absl/base/macros.h" +#include "google/protobuf/descriptor.h" + +namespace upbc { + +class MessageLayout { + public: + struct Size { + void Add(const Size& other) { + size32 += other.size32; + size64 += other.size64; + } + + void MaxFrom(const Size& other) { + size32 = std::max(size32, other.size32); + size64 = std::max(size64, other.size64); + } + + void AlignUp(const Size& align) { + size32 = Align(size32, align.size32); + size64 = Align(size64, align.size64); + } + + int64_t size32; + int64_t size64; + }; + + struct SizeAndAlign { + Size size; + Size align; + + void MaxFrom(const SizeAndAlign& other) { + size.MaxFrom(other.size); + align.MaxFrom(other.align); + } + }; + + MessageLayout(const google::protobuf::Descriptor* descriptor) { + ComputeLayout(descriptor); + } + + Size GetFieldOffset(const google::protobuf::FieldDescriptor* field) const { + return GetMapValue(field_offsets_, field); + } + + Size GetOneofCaseOffset( + const google::protobuf::OneofDescriptor* oneof) const { + return GetMapValue(oneof_case_offsets_, oneof); + } + + int GetHasbitIndex(const google::protobuf::FieldDescriptor* field) const { + return GetMapValue(hasbit_indexes_, field); + } + + Size message_size() const { return size_; } + + static bool HasHasbit(const google::protobuf::FieldDescriptor* field); + + private: + void ComputeLayout(const google::protobuf::Descriptor* descriptor); + void PlaceNonOneofFields(const google::protobuf::Descriptor* descriptor); + void PlaceOneofFields(const google::protobuf::Descriptor* descriptor); + Size Place(SizeAndAlign size_and_align); + + template <class K, class V> + static V GetMapValue(const std::unordered_map<K, V>& map, K key) { + auto iter = map.find(key); + if (iter == map.end()) { + fprintf(stderr, "No value for field.\n"); + abort(); + } + return iter->second; + } + + static bool IsPowerOfTwo(size_t val) { + return (val & (val - 1)) == 0; + } + + static size_t Align(size_t val, size_t align) { + ABSL_ASSERT(IsPowerOfTwo(align)); + return (val + align - 1) & ~(align - 1); + } + + static SizeAndAlign SizeOf(const google::protobuf::FieldDescriptor* field); + static int64_t FieldLayoutRank(const google::protobuf::FieldDescriptor* field); + + std::unordered_map<const google::protobuf::FieldDescriptor*, Size> + field_offsets_; + std::unordered_map<const google::protobuf::FieldDescriptor*, int> + hasbit_indexes_; + std::unordered_map<const google::protobuf::OneofDescriptor*, Size> + oneof_case_offsets_; + Size maxalign_; + Size size_; +}; + +} // namespace upbc + +#endif // UPBC_MESSAGE_LAYOUT_H |