Moves Allocate() and Deallocate() into AbidingObjectPool's public interface.

Protected by refactoring, no functional change; not protected.

PiperOrigin-RevId: 989864629
diff --git a/quiche/common/abiding_object_pool.h b/quiche/common/abiding_object_pool.h
index cc4ef5f..5205f86 100644
--- a/quiche/common/abiding_object_pool.h
+++ b/quiche/common/abiding_object_pool.h
@@ -111,6 +111,17 @@
   size_t num_free_slots() const noexcept { return total_free_slots_; }
   bool empty() const noexcept { return total_free_slots_ == total_capacity(); }
 
+  // Allocate() and Deallocate() can be used in cases where existing systems
+  // manage objects via bare pointers, and migrating to smart pointers is
+  // infeasible.
+
+  // Returns the next available memory region that can hold an object of size T,
+  // allocating a new Slab if necessary.
+  void* Allocate();
+  // Deallocates a previously allocated memory region. May result in the owning
+  // Slab being freed.
+  void Deallocate(void* ptr) noexcept;
+
  private:
   // Intrusive node overlaid on unallocated slot memory.
   struct FreeNode {
@@ -211,103 +222,6 @@
     }
   }
 
-  // Returns the next available slot, allocating a new Slab if necessary.
-  void* Allocate() {
-    if (non_full_slabs_ == nullptr) {
-      Slab* slab = nullptr;
-      if (spare_empty_slab_ != nullptr) {
-        slab = spare_empty_slab_;
-        spare_empty_slab_ = nullptr;
-      } else {
-        slab = CreateSlab();
-      }
-      PushFront(non_full_slabs_, slab);
-    }
-    Slab* slab = non_full_slabs_;
-    void* slot = nullptr;
-
-    // 1. Reuse from intrusive freelist if available.
-    if (slab->free_head != nullptr) {
-      FreeNode* node = slab->free_head;
-
-#ifdef ABSL_HAVE_ADDRESS_SANITIZER
-      ASAN_UNPOISON_MEMORY_REGION(node, kSlotSize);
-#endif
-
-      slab->free_head = node->next;
-      slot = static_cast<void*>(node);
-    } else {
-      // 2. Bump-allocate from uninitialized slot range.
-      QUICHE_DCHECK(slab->allocated_high_watermark < kSlotsPerSlab);
-      slot = SlotAddress(slab, slab->allocated_high_watermark);
-
-#ifdef ABSL_HAVE_ADDRESS_SANITIZER
-      ASAN_UNPOISON_MEMORY_REGION(slot, kSlotSize);
-#endif
-
-      ++slab->allocated_high_watermark;
-    }
-
-    ++slab->live_objects;
-    --total_free_slots_;
-
-    // If slab reached capacity, move it to full_slabs_.
-    if (slab->live_objects == kSlotsPerSlab) {
-      RemoveFromList(non_full_slabs_, slab);
-      PushFront(full_slabs_, slab);
-    }
-
-    return slot;
-  }
-
-  // Deallocates a slot. May result in the owning Slab being freed.
-  void Deallocate(void* ptr) noexcept {
-    // The owning slab can be found with a simple bitmask operation.
-    Slab* slab = reinterpret_cast<Slab*>(reinterpret_cast<uintptr_t>(ptr) &
-                                         ~(SlabSizeBytes - 1));
-    QUICHE_DCHECK(slab != nullptr);
-
-    auto* node = static_cast<FreeNode*>(ptr);
-    node->next = slab->free_head;
-    slab->free_head = node;
-
-#ifdef ABSL_HAVE_ADDRESS_SANITIZER
-    ASAN_POISON_MEMORY_REGION(ptr, kSlotSize);
-#endif
-
-    const bool was_full = (slab->live_objects == kSlotsPerSlab);
-    --slab->live_objects;
-    ++total_free_slots_;
-
-    if (slab->live_objects == 0) {
-      // Slab has no more live objects.
-      if (was_full) {
-        RemoveFromList(full_slabs_, slab);
-      } else {
-        RemoveFromList(non_full_slabs_, slab);
-      }
-      if (spare_empty_slab_ == nullptr) {
-        spare_empty_slab_ = slab;
-      } else {
-        DestroySlab(slab);
-      }
-      return;
-    }
-
-    if (was_full) {
-      // Move from full_slabs_ to front of non_full_slabs_ (as the fullest
-      // partial slab).
-      RemoveFromList(full_slabs_, slab);
-      PushFront(non_full_slabs_, slab);
-    } else {
-      // Keep non_full_slabs_ ordered by descending live_objects.
-      while (slab->next != nullptr &&
-             slab->live_objects < slab->next->live_objects) {
-        SwapWithNext(non_full_slabs_, slab);
-      }
-    }
-  }
-
   // Allocates memory for and initializes a Slab.
   Slab* CreateSlab() {
     void* memory =
@@ -340,6 +254,108 @@
   size_t total_free_slots_ = 0;
 };
 
+// Returns the next available slot, allocating a new Slab if necessary.
+template <typename T, size_t SlabSizeBytes>
+void* AbidingObjectPool<T, SlabSizeBytes>::Allocate() {
+  if (non_full_slabs_ == nullptr) {
+    Slab* slab = nullptr;
+    if (spare_empty_slab_ != nullptr) {
+      slab = spare_empty_slab_;
+      spare_empty_slab_ = nullptr;
+    } else {
+      slab = CreateSlab();
+    }
+    PushFront(non_full_slabs_, slab);
+  }
+  Slab* slab = non_full_slabs_;
+  void* slot = nullptr;
+
+  // 1. Reuse from intrusive freelist if available.
+  if (slab->free_head != nullptr) {
+    FreeNode* node = slab->free_head;
+
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+    ASAN_UNPOISON_MEMORY_REGION(node, kSlotSize);
+#endif
+
+    slab->free_head = node->next;
+    slot = static_cast<void*>(node);
+  } else {
+    // 2. Bump-allocate from uninitialized slot range.
+    QUICHE_DCHECK(slab->allocated_high_watermark < kSlotsPerSlab);
+    slot = SlotAddress(slab, slab->allocated_high_watermark);
+
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+    ASAN_UNPOISON_MEMORY_REGION(slot, kSlotSize);
+#endif
+
+    ++slab->allocated_high_watermark;
+  }
+
+  ++slab->live_objects;
+  --total_free_slots_;
+
+  // If slab reached capacity, move it to full_slabs_.
+  if (slab->live_objects == kSlotsPerSlab) {
+    RemoveFromList(non_full_slabs_, slab);
+    PushFront(full_slabs_, slab);
+  }
+
+  return slot;
+}
+
+// Deallocates a slot. May result in the owning Slab being freed.
+template <typename T, size_t SlabSizeBytes>
+void AbidingObjectPool<T, SlabSizeBytes>::Deallocate(void* ptr) noexcept {
+  if (ptr == nullptr) {
+    return;
+  }
+  // The owning slab can be found with a simple bitmask operation.
+  Slab* slab = reinterpret_cast<Slab*>(reinterpret_cast<uintptr_t>(ptr) &
+                                       ~(SlabSizeBytes - 1));
+  QUICHE_DCHECK(slab != nullptr);
+
+  auto* node = static_cast<FreeNode*>(ptr);
+  node->next = slab->free_head;
+  slab->free_head = node;
+
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+  ASAN_POISON_MEMORY_REGION(ptr, kSlotSize);
+#endif
+
+  const bool was_full = (slab->live_objects == kSlotsPerSlab);
+  --slab->live_objects;
+  ++total_free_slots_;
+
+  if (slab->live_objects == 0) {
+    // Slab has no more live objects.
+    if (was_full) {
+      RemoveFromList(full_slabs_, slab);
+    } else {
+      RemoveFromList(non_full_slabs_, slab);
+    }
+    if (spare_empty_slab_ == nullptr) {
+      spare_empty_slab_ = slab;
+    } else {
+      DestroySlab(slab);
+    }
+    return;
+  }
+
+  if (was_full) {
+    // Move from full_slabs_ to front of non_full_slabs_ (as the fullest
+    // partial slab).
+    RemoveFromList(full_slabs_, slab);
+    PushFront(non_full_slabs_, slab);
+  } else {
+    // Keep non_full_slabs_ ordered by descending live_objects.
+    while (slab->next != nullptr &&
+           slab->live_objects < slab->next->live_objects) {
+      SwapWithNext(non_full_slabs_, slab);
+    }
+  }
+}
+
 }  // namespace quiche
 
 #endif  // QUICHE_COMMON_ABIDING_OBJECT_POOL_H_