Adding stack allocated protobuf arena class.
Change-Id: I1ee15b79fdb54b787b94b3d424e4df36c82ad849
diff --git a/aos/protobuf/BUILD b/aos/protobuf/BUILD
new file mode 100644
index 0000000..c5439c3
--- /dev/null
+++ b/aos/protobuf/BUILD
@@ -0,0 +1,22 @@
+package(default_visibility = ['//visibility:public'])
+
+cc_library(
+ name = "stack_arena",
+ srcs = ["stack_arena.cc"],
+ hdrs = ["stack_arena.h"],
+ deps = [
+ "//aos/common/logging:logging",
+ "//third_party/protobuf",
+ ],
+)
+
+cc_test(
+ name = "stack_arena_test",
+ srcs = ["stack_arena_test.cc"],
+ deps = [
+ ":stack_arena",
+ "//aos/testing:test_logging",
+ "//aos/common/logging:logging",
+ "//aos/testing:googletest",
+ ],
+)
diff --git a/aos/protobuf/stack_arena.cc b/aos/protobuf/stack_arena.cc
new file mode 100644
index 0000000..d1a69d6
--- /dev/null
+++ b/aos/protobuf/stack_arena.cc
@@ -0,0 +1,15 @@
+#include "aos/common/logging/logging.h"
+
+namespace aos {
+namespace protobuf {
+
+void FatalArenaBlockAlloc(size_t) {
+ LOG(FATAL, "trying to allocate in arena code");
+}
+
+void FatalArenaBlockDealloc(void*, size_t) {
+ LOG(FATAL, "trying to deallocate in arena code");
+}
+
+} // namespace protobuf
+} // namespace aos
diff --git a/aos/protobuf/stack_arena.h b/aos/protobuf/stack_arena.h
new file mode 100644
index 0000000..28c933c
--- /dev/null
+++ b/aos/protobuf/stack_arena.h
@@ -0,0 +1,52 @@
+#ifndef AOS_PROTOBUF_STACK_ARENA_H_
+#define AOS_PROTOBUF_STACK_ARENA_H_
+#include "google/protobuf/arena.h"
+
+namespace aos {
+namespace protobuf {
+
+void* FatalArenaBlockAlloc(size_t);
+
+void FatalArenaBlockDealloc(void*, size_t);
+
+// This class manages a protobuf arena which uses an internal buffer
+// (allocated as part of the object) of size buffer_size.
+//
+// Protos allocated from this arena must not use more than buffer_size
+// worth of data.
+//
+// Also worth noting is that sizeof(google::protobuf::Arena::Block)
+// is used up out of the buffer for internal protobuf related usage, so
+// overallocate accordingly.
+template <size_t buffer_size>
+class StackProtoArena {
+ public:
+ StackProtoArena() :
+ arena_(GetArenaOptions(&data_[0])) {}
+
+ google::protobuf::Arena* arena() { return &arena_; }
+
+ // For convienence:
+ template <typename T>
+ T* CreateMessage() {
+ return google::protobuf::Arena::CreateMessage<T>(&arena_);
+ }
+ private:
+ static google::protobuf::ArenaOptions GetArenaOptions(char* data) {
+ // Expecting RVO to kick in.
+ google::protobuf::ArenaOptions options;
+ options.initial_block = data;
+ options.initial_block_size = buffer_size;
+ options.block_alloc = &FatalArenaBlockAlloc;
+ options.block_dealloc = FatalArenaBlockDealloc;
+ return options;
+ }
+
+ char data_[buffer_size];
+ google::protobuf::Arena arena_;
+};
+
+} // namespace protobuf
+} // namespace aos
+
+#endif // AOS_PROTOBUF_STACK_ARENA_H_
diff --git a/aos/protobuf/stack_arena_test.cc b/aos/protobuf/stack_arena_test.cc
new file mode 100644
index 0000000..dfd9151
--- /dev/null
+++ b/aos/protobuf/stack_arena_test.cc
@@ -0,0 +1,30 @@
+#include "gtest/gtest.h"
+
+#include "aos/common/logging/logging.h"
+#include "aos/protobuf/stack_arena.h"
+#include "aos/testing/test_logging.h"
+
+namespace aos {
+namespace protobuf {
+namespace {
+
+struct TestStruct {
+ int a;
+ int b;
+ int c;
+};
+
+class StackProtoArenaTest : public ::testing::Test {};
+
+TEST_F(StackProtoArenaTest, Basic) {
+ ::aos::testing::EnableTestLogging();
+ StackProtoArena<164> stack_arena;
+
+ TestStruct* msg =
+ google::protobuf::Arena::Create<TestStruct>(stack_arena.arena());
+ CHECK_NOTNULL(msg);
+}
+
+} // namespace
+} // namespace protobuf
+} // namespace aos