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