Merge pull request #5570 from harfbuzz/alloc-pool-improvements

[alloc-pool] Implement alignment
diff --git a/src/hb-alloc-pool.hh b/src/hb-alloc-pool.hh
index bf954ca..efa7e52 100644
--- a/src/hb-alloc-pool.hh
+++ b/src/hb-alloc-pool.hh
@@ -42,10 +42,14 @@
 {
   unsigned ChunkSize = 65536 - 2 * sizeof (void *);
 
-  void *alloc (size_t size)
+  void *alloc (size_t size, unsigned alignment = 2 * sizeof (void *))
   {
     if (unlikely (chunks.in_error ())) return nullptr;
 
+    assert (alignment > 0);
+    assert (alignment <= 2 * sizeof (void *));
+    assert ((alignment & (alignment - 1)) == 0); /* power of two */
+
     if (size > (ChunkSize) / 4)
     {
       /* Big chunk, allocate separately.  */
@@ -63,8 +67,11 @@
       return ret;
     }
 
+    unsigned pad = current_chunk.length & (alignment - 1);
+    if (pad) pad = alignment - pad;
+
     // Small chunk, allocate from the last chunk.
-    if (current_chunk.length < size)
+    if (current_chunk.length < pad + size)
     {
       chunks.push ();
       if (unlikely (chunks.in_error ())) return nullptr;
@@ -72,6 +79,8 @@
       if (unlikely (!chunk.resize (ChunkSize))) return nullptr;
       current_chunk = chunk;
     }
+    else
+      current_chunk += pad;
 
     assert (current_chunk.length >= size);
     void *ret = current_chunk.arrayZ;
@@ -79,6 +88,14 @@
     return ret;
   }
 
+  void discard (void *p_, size_t size)
+  {
+    // Reclaim memory if we can.
+    char *p = (char *) p_;
+    if (current_chunk.arrayZ == p + size && current_chunk.backwards_length >= size)
+      current_chunk -= size;
+  }
+
   private:
   hb_vector_t<hb_vector_t<char>> chunks;
   hb_array_t<char> current_chunk;
diff --git a/src/hb-ot-var-common.hh b/src/hb-ot-var-common.hh
index 1881251..a8c8858 100644
--- a/src/hb-ot-var-common.hh
+++ b/src/hb-ot-var-common.hh
@@ -523,7 +523,7 @@
     o->tupleIndex = flag;
 
     unsigned total_header_len = 4 + (peak_count + interim_count) * (F2DOT14::static_size);
-    compiled_tuple_header.shrink (total_header_len, false);
+    compiled_tuple_header.shrink_back_to_pool (pool, total_header_len);
     return true;
   }
 
@@ -600,7 +600,7 @@
       if (j != rounded_deltas.length) return false;
       encoded_len += compile_deltas (compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
     }
-    compiled_deltas.shrink (encoded_len, false);
+    compiled_deltas.shrink_back_to_pool (pool, encoded_len);
     return true;
   }
 
diff --git a/src/hb-vector.hh b/src/hb-vector.hh
index d24ae0b..dc34f41 100644
--- a/src/hb-vector.hh
+++ b/src/hb-vector.hh
@@ -548,7 +548,7 @@
     if (allocator)
     {
       assert (!length && !allocated);
-      arrayZ = (Type *) allocator->alloc (size * sizeof (Type));
+      arrayZ = (Type *) allocator->alloc (size * sizeof (Type), alignof (Type));
       if (unlikely (!arrayZ))
       {
 	set_error ();
@@ -574,6 +574,17 @@
     return true;
   }
 
+  template <typename allocator_t>
+  void shrink_back_to_pool (allocator_t *allocator, int size)
+  {
+    unsigned orig_length = length;
+
+    shrink (size, false);
+
+    if (allocator && !is_owned ())
+      allocator->discard (arrayZ + length, (orig_length - length) * sizeof (Type));
+  }
+
   HB_ALWAYS_INLINE_VECTOR_ALLOCS
   bool resize_full (int size_, bool initialize, bool exact)
   {