Reduce memory usage of the static flatbuffer API

This contains a couple of changes, which work together and are a bit
hard to separate out.

1) Instead of requiring the whole contents of a sub-message or vector to
   be aligned, split the alignment requirement up into an alignment
   requirement at an offset into the message.  This lets us leave the
   length field in a message, for example, at 4 byte alignment when the
   body requires 8 byte alignment.  This enables better packing of
   fields.
2) From James, don't pre-reserve space for vectors with 0 length.  They
   will trigger a re-allocation anyways when they are used since there
   is no space allocated, so pre-allocating doesn't help.
3) Remove padding at the end of messages and require the allocator to
   handle it instead.  We used to allocate kSize + kAlign and then
   manually align things, which resulted in wasted space.
4) Automatically add any extra padding after a vector to the vector.
   For some small vectors, this lets us use the padding for the vector
   rather than allocating more space.
5) Shrink the code generated for the object offsets by adding constexpr
   variables with the previous object size rather than inlining it.
   This results in a much faster build since clang-format was fighting
   the large fields at build time.
6) Sort fields in a flatbuffer by alignment to pack them better.

Change-Id: I5af440855e3425be31fa7f30c68af552fcf06cb2
Signed-off-by: Austin Schuh <austin.schuh@bluerivertech.com>
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/flatbuffers/base.h b/aos/flatbuffers/base.h
index a98d730..045fce3 100644
--- a/aos/flatbuffers/base.h
+++ b/aos/flatbuffers/base.h
@@ -26,13 +26,17 @@
 using ::flatbuffers::uoffset_t;
 using ::flatbuffers::voffset_t;
 
-// Returns the smallest multiple of alignment that is greater than or equal to
-// size.
-constexpr size_t PaddedSize(size_t size, size_t alignment) {
+// Returns the offset into the buffer needed to provide 'alignment' alignment
+// 'aligned_offset' bytes after the returned offset.  This assumes that the
+// first 'starting_offset' bytes are spoken for.
+constexpr size_t AlignOffset(size_t starting_offset, size_t alignment,
+                             size_t aligned_offset = 0) {
   // We can be clever with bitwise operations by assuming that aligment is a
   // power of two. Or we can just be clearer about what we mean and eat a few
   // integer divides.
-  return (((size - 1) / alignment) + 1) * alignment;
+  return (((starting_offset + aligned_offset - 1) / alignment) + 1) *
+             alignment -
+         aligned_offset;
 }
 
 // Used as a parameter to methods where we are messing with memory and may or
@@ -116,11 +120,6 @@
   ResizeableObject(ResizeableObject &&other);
   // Required alignment of this object.
   virtual size_t Alignment() const = 0;
-  // Offset from the start of buffer() to the actual start of the object in
-  // question (this is important for vectors, where the vector itself cannot
-  // have internal padding, and so the start of the vector may be offset from
-  // the start of the buffer to handle alignment).
-  virtual size_t AbsoluteOffsetOffset() const = 0;
   // Causes bytes bytes to be inserted between insertion_point - 1 and
   // insertion_point.
   // If requested, the new bytes will be cleared to zero; otherwise they will be
@@ -130,9 +129,10 @@
   // implementation, and is merely a requirement that any buffer growth occur
   // only on the inside or past the end of the vector, and not prior to the
   // start of the vector.
-  // Returns true on success, false on failure (e.g., if the allocator has no
-  // memory available).
-  bool InsertBytes(void *insertion_point, size_t bytes, SetZero set_zero);
+  // Returns a span of the inserted bytes on success, nullopt on failure (e.g.,
+  // if the allocator has no memory available).
+  std::optional<std::span<uint8_t>> InsertBytes(void *insertion_point,
+                                                size_t bytes, SetZero set_zero);
   // Called *after* the internal buffer_ has been swapped out and *after* the
   // object tree has been traversed and fixed.
   virtual void ObserveBufferModification() {}
@@ -151,12 +151,9 @@
   const void *PointerForAbsoluteOffset(const size_t absolute_offset) {
     return buffer_.data() + absolute_offset;
   }
-  // Returns a span at the requested offset into the buffer. terminal_alignment
-  // does not align the start of the buffer; instead, it ensures that the memory
-  // from absolute_offset + size until the next multiple of terminal_alignment
-  // is set to all zeroes.
-  std::span<uint8_t> BufferForObject(size_t absolute_offset, size_t size,
-                                     size_t terminal_alignment);
+  // Returns a span at the requested offset into the buffer for the requested
+  // size.
+  std::span<uint8_t> BufferForObject(size_t absolute_offset, size_t size);
   // When memory has been inserted/removed, this iterates over the sub-objects
   // and notifies/adjusts them appropriately.
   // This will be called after buffer_ has been updated, and: