diff options
author | aarongreen <aarongreen@google.com> | 2023-11-09 16:22:58 +0000 |
---|---|---|
committer | CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-11-09 16:22:58 +0000 |
commit | 023d64acda3b9750da4514ec6ff41ace9aeeb346 (patch) | |
tree | af4d6a14d3e6f93b6fe9fe2c533f753d7bce4175 | |
parent | 09c9783126f13241f88949e1f430c1ace830b916 (diff) | |
download | pigweed-023d64acda3b9750da4514ec6ff41ace9aeeb346.tar.gz |
pw_allocator: Update interface based on final SEED-0110 design
This CL removes the `...Unchecked` methods from
`pw::allocator::Allocator`, and modifies the NVI-style `Do...` methods
to take `Layout` parameters.
Change-Id: I48de73933ea18ae75dbadb1287780c54fe29873b
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/176754
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
Commit-Queue: Aaron Green <aarongreen@google.com>
Reviewed-by: Taylor Cramer <cramertj@google.com>
18 files changed, 156 insertions, 263 deletions
diff --git a/pw_allocator/allocator.cc b/pw_allocator/allocator.cc index 15cca58bc..f63bacd69 100644 --- a/pw_allocator/allocator.cc +++ b/pw_allocator/allocator.cc @@ -22,23 +22,20 @@ namespace pw::allocator { -void* Allocator::DoReallocate(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) { +void* Allocator::DoReallocate(void* ptr, Layout layout, size_t new_size) { if (new_size == 0) { return nullptr; } - if (DoResize(ptr, old_size, old_alignment, new_size)) { + if (Resize(ptr, layout, new_size)) { return ptr; } - void* new_ptr = DoAllocate(new_size, old_alignment); + void* new_ptr = DoAllocate(Layout(new_size, layout.alignment())); if (new_ptr == nullptr) { return nullptr; } - if (ptr != nullptr && old_size != 0) { - std::memcpy(new_ptr, ptr, old_size); - DoDeallocate(ptr, old_size, old_alignment); + if (ptr != nullptr && layout.size() != 0) { + std::memcpy(new_ptr, ptr, layout.size()); + DoDeallocate(ptr, layout); } return new_ptr; } diff --git a/pw_allocator/allocator_metric_proxy.cc b/pw_allocator/allocator_metric_proxy.cc index 98f3bc930..10ca68d3a 100644 --- a/pw_allocator/allocator_metric_proxy.cc +++ b/pw_allocator/allocator_metric_proxy.cc @@ -31,20 +31,18 @@ void AllocatorMetricProxy::Initialize(Allocator& allocator) { memusage_.Add(count_); } -Status AllocatorMetricProxy::DoQuery(const void* ptr, - size_t size, - size_t alignment) const { +Status AllocatorMetricProxy::DoQuery(const void* ptr, Layout layout) const { PW_DCHECK_NOTNULL(allocator_); - return allocator_->QueryUnchecked(ptr, size, alignment); + return allocator_->Query(ptr, layout); } -void* AllocatorMetricProxy::DoAllocate(size_t size, size_t alignment) { +void* AllocatorMetricProxy::DoAllocate(Layout layout) { PW_DCHECK_NOTNULL(allocator_); - void* ptr = allocator_->AllocateUnchecked(size, alignment); + void* ptr = allocator_->Allocate(layout); if (ptr == nullptr) { return nullptr; } - used_.Increment(size); + used_.Increment(layout.size()); if (used_.value() > peak_.value()) { peak_.Set(used_.value()); } @@ -52,30 +50,25 @@ void* AllocatorMetricProxy::DoAllocate(size_t size, size_t alignment) { return ptr; } -void AllocatorMetricProxy::DoDeallocate(void* ptr, - size_t size, - size_t alignment) { +void AllocatorMetricProxy::DoDeallocate(void* ptr, Layout layout) { PW_DCHECK_NOTNULL(allocator_); - allocator_->DeallocateUnchecked(ptr, size, alignment); + allocator_->Deallocate(ptr, layout); if (ptr == nullptr) { return; } - PW_DCHECK_UINT_GE(used_.value(), size); + PW_DCHECK_UINT_GE(used_.value(), layout.size()); PW_DCHECK_UINT_NE(count_.value(), 0); - used_.Set(used_.value() - size); + used_.Set(used_.value() - layout.size()); count_.Set(count_.value() - 1); } -bool AllocatorMetricProxy::DoResize(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) { +bool AllocatorMetricProxy::DoResize(void* ptr, Layout layout, size_t new_size) { PW_DCHECK_NOTNULL(allocator_); - if (!allocator_->ResizeUnchecked(ptr, old_size, old_alignment, new_size)) { + if (!allocator_->Resize(ptr, layout, new_size)) { return false; } - PW_DCHECK_UINT_GE(used_.value(), old_size); - used_.Set(used_.value() - old_size + new_size); + PW_DCHECK_UINT_GE(used_.value(), layout.size()); + used_.Set(used_.value() - layout.size() + new_size); if (used_.value() > peak_.value()) { peak_.Set(used_.value()); } diff --git a/pw_allocator/allocator_test.cc b/pw_allocator/allocator_test.cc index f0bd1981d..c41356ca8 100644 --- a/pw_allocator/allocator_test.cc +++ b/pw_allocator/allocator_test.cc @@ -43,11 +43,6 @@ TEST_F(AllocatorTest, ReallocateNull) { size_t new_size = old_layout.size(); void* new_ptr = allocator.Reallocate(nullptr, old_layout, new_size); - // Reallocate should call Resize. - EXPECT_EQ(allocator.resize_ptr(), nullptr); - EXPECT_EQ(allocator.resize_old_size(), old_layout.size()); - EXPECT_EQ(allocator.resize_new_size(), new_size); - // Resize should fail and Reallocate should call Allocate. EXPECT_EQ(allocator.allocate_size(), new_size); diff --git a/pw_allocator/allocator_testing.cc b/pw_allocator/allocator_testing.cc index 47d046aae..269c47d1d 100644 --- a/pw_allocator/allocator_testing.cc +++ b/pw_allocator/allocator_testing.cc @@ -56,31 +56,26 @@ void AllocatorForTest::DeallocateAll() { ResetParameters(); } -Status AllocatorForTest::DoQuery(const void* ptr, - size_t size, - size_t alignment) const { - return allocator_.QueryUnchecked(ptr, size, alignment); +Status AllocatorForTest::DoQuery(const void* ptr, Layout layout) const { + return allocator_.Query(ptr, layout); } -void* AllocatorForTest::DoAllocate(size_t size, size_t alignment) { - allocate_size_ = size; - return allocator_.AllocateUnchecked(size, alignment); +void* AllocatorForTest::DoAllocate(Layout layout) { + allocate_size_ = layout.size(); + return allocator_.Allocate(layout); } -void AllocatorForTest::DoDeallocate(void* ptr, size_t size, size_t alignment) { +void AllocatorForTest::DoDeallocate(void* ptr, Layout layout) { deallocate_ptr_ = ptr; - deallocate_size_ = size; - return allocator_.DeallocateUnchecked(ptr, size, alignment); + deallocate_size_ = layout.size(); + return allocator_.Deallocate(ptr, layout); } -bool AllocatorForTest::DoResize(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) { +bool AllocatorForTest::DoResize(void* ptr, Layout layout, size_t new_size) { resize_ptr_ = ptr; - resize_old_size_ = old_size; + resize_old_size_ = layout.size(); resize_new_size_ = new_size; - return allocator_.ResizeUnchecked(ptr, old_size, old_alignment, new_size); + return allocator_.Resize(ptr, layout, new_size); } } // namespace pw::allocator::test diff --git a/pw_allocator/fallback_allocator.cc b/pw_allocator/fallback_allocator.cc index cfa7bd120..1e3faf666 100644 --- a/pw_allocator/fallback_allocator.cc +++ b/pw_allocator/fallback_allocator.cc @@ -24,39 +24,32 @@ void FallbackAllocator::Initialize(Allocator& primary, Allocator& secondary) { secondary_ = &secondary; } -Status FallbackAllocator::DoQuery(const void* ptr, - size_t size, - size_t alignment) const { +Status FallbackAllocator::DoQuery(const void* ptr, Layout layout) const { PW_DCHECK(primary_ != nullptr && secondary_ != nullptr); - auto status = primary_->QueryUnchecked(ptr, size, alignment); - return status.ok() ? status - : secondary_->QueryUnchecked(ptr, size, alignment); + auto status = primary_->Query(ptr, layout); + return status.ok() ? status : secondary_->Query(ptr, layout); } -void* FallbackAllocator::DoAllocate(size_t size, size_t alignment) { +void* FallbackAllocator::DoAllocate(Layout layout) { PW_DCHECK(primary_ != nullptr && secondary_ != nullptr); - void* ptr = primary_->AllocateUnchecked(size, alignment); - return ptr != nullptr ? ptr : secondary_->AllocateUnchecked(size, alignment); + void* ptr = primary_->Allocate(layout); + return ptr != nullptr ? ptr : secondary_->Allocate(layout); } -void FallbackAllocator::DoDeallocate(void* ptr, size_t size, size_t alignment) { +void FallbackAllocator::DoDeallocate(void* ptr, Layout layout) { PW_DCHECK(primary_ != nullptr && secondary_ != nullptr); - if (primary_->QueryUnchecked(ptr, size, alignment).ok()) { - primary_->DeallocateUnchecked(ptr, size, alignment); + if (primary_->Query(ptr, layout).ok()) { + primary_->Deallocate(ptr, layout); } else { - secondary_->DeallocateUnchecked(ptr, size, alignment); + secondary_->Deallocate(ptr, layout); } } -bool FallbackAllocator::DoResize(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) { +bool FallbackAllocator::DoResize(void* ptr, Layout layout, size_t new_size) { PW_DCHECK(primary_ != nullptr && secondary_ != nullptr); - return primary_->QueryUnchecked(ptr, old_size, old_alignment).ok() - ? primary_->ResizeUnchecked(ptr, old_size, old_alignment, new_size) - : secondary_->ResizeUnchecked( - ptr, old_size, old_alignment, new_size); + return primary_->Query(ptr, layout).ok() + ? primary_->Resize(ptr, layout, new_size) + : secondary_->Resize(ptr, layout, new_size); } } // namespace pw::allocator diff --git a/pw_allocator/libc_allocator.cc b/pw_allocator/libc_allocator.cc index c848d6c9f..8469bcdae 100644 --- a/pw_allocator/libc_allocator.cc +++ b/pw_allocator/libc_allocator.cc @@ -24,27 +24,26 @@ namespace pw::allocator { -void* LibCAllocator::DoAllocate(size_t size, size_t alignment) { +void* LibCAllocator::DoAllocate(Layout layout) { // TODO: b/301930507 - `aligned_alloc` is not portable. Return null for larger // allocations for now. - return alignment <= alignof(std::max_align_t) ? std::malloc(size) : nullptr; + return layout.alignment() <= alignof(std::max_align_t) + ? std::malloc(layout.size()) + : nullptr; } -void LibCAllocator::DoDeallocate(void* ptr, size_t, size_t) { std::free(ptr); } +void LibCAllocator::DoDeallocate(void* ptr, Layout) { std::free(ptr); } -bool LibCAllocator::DoResize(void*, size_t old_size, size_t, size_t new_size) { +bool LibCAllocator::DoResize(void*, Layout layout, size_t new_size) { // `realloc` may move memory, even when shrinking. Only return true if no // change is needed. - return old_size == new_size; + return layout.size() == new_size; } -void* LibCAllocator::DoReallocate(void* ptr, - size_t, - size_t old_alignment, - size_t new_size) { +void* LibCAllocator::DoReallocate(void* ptr, Layout layout, size_t new_size) { // TODO: b/301930507 - `aligned_alloc` is not portable. Return null for larger // allocations for now. - return old_alignment <= alignof(std::max_align_t) + return layout.alignment() <= alignof(std::max_align_t) ? std::realloc(ptr, new_size) : nullptr; } diff --git a/pw_allocator/libc_allocator_test.cc b/pw_allocator/libc_allocator_test.cc index 967a1069d..15eaac212 100644 --- a/pw_allocator/libc_allocator_test.cc +++ b/pw_allocator/libc_allocator_test.cc @@ -43,7 +43,7 @@ TEST_F(LibCAllocatorTest, AllocateLargeAlignment) { /// allocator has a maximum alignment of `std::align_max_t`. size_t size = 16; size_t alignment = alignof(std::max_align_t) * 2; - void* ptr = allocator.AllocateUnchecked(size, alignment); + void* ptr = allocator.Allocate(Layout(size, alignment)); EXPECT_EQ(ptr, nullptr); } diff --git a/pw_allocator/null_allocator_test.cc b/pw_allocator/null_allocator_test.cc index a257e2658..0b319646a 100644 --- a/pw_allocator/null_allocator_test.cc +++ b/pw_allocator/null_allocator_test.cc @@ -23,7 +23,7 @@ TEST(NullAllocatorTest, Allocate) { // Allocate should fail, regardless of size and alignment. for (size_t size = 1; size < 0x100; size <<= 1) { for (size_t alignment = 1; alignment < 0x100; alignment <<= 1) { - EXPECT_EQ(allocator.AllocateUnchecked(size, alignment), nullptr); + EXPECT_EQ(allocator.Allocate(Layout(size, alignment)), nullptr); } } } diff --git a/pw_allocator/public/pw_allocator/allocator.h b/pw_allocator/public/pw_allocator/allocator.h index 0441409ca..a36d3ea3e 100644 --- a/pw_allocator/public/pw_allocator/allocator.h +++ b/pw_allocator/public/pw_allocator/allocator.h @@ -36,19 +36,23 @@ namespace pw::allocator { /// @endcode class Layout { public: + constexpr Layout(size_t size, size_t alignment = alignof(std::max_align_t)) + : size_(size), alignment_(alignment) {} + /// Creates a Layout for the given type. template <typename T> static constexpr Layout Of() { return Layout(sizeof(T), alignof(T)); } + constexpr Layout Extend(size_t size) { + return Layout(size_ + size, alignment_); + } + size_t size() const { return size_; } size_t alignment() const { return alignment_; } private: - constexpr Layout(size_t size, size_t alignment) - : size_(size), alignment_(alignment) {} - size_t size_; size_t alignment_; }; @@ -97,15 +101,7 @@ class Allocator { /// object. /// @retval OK This object can re/deallocate the pointer. Status Query(const void* ptr, Layout layout) const { - return DoQuery(ptr, layout.size(), layout.alignment()); - } - - /// Like `Query`, but takes its parameters directly instead of as a `Layout`. - /// - /// Callers should almost always prefer `Query`. This method is meant for use - /// by tests and other allocators implementing the virtual functions below. - Status QueryUnchecked(const void* ptr, size_t size, size_t alignment) const { - return DoQuery(ptr, size, alignment); + return DoQuery(ptr, layout); } /// Allocates a block of memory with the specified size and alignment. @@ -114,9 +110,7 @@ class Allocator { /// size of 0. /// /// @param[in] layout Describes the memory to be allocated. - void* Allocate(Layout layout) { - return DoAllocate(layout.size(), layout.alignment()); - } + void* Allocate(Layout layout) { return DoAllocate(layout); } template <typename T, typename... Args> std::optional<UniquePtr<T>> MakeUnique(Args&&... args) { @@ -130,16 +124,6 @@ class Allocator { UniquePtr<T>::kPrivateConstructor, ptr, &kStaticLayout, this); } - /// Like `Allocate`, but takes its parameters directly instead of as a - /// `Layout`. - /// - /// Callers should almost always prefer `Allocate`. This method is meant for - /// use by tests and other allocators implementing the virtual functions - /// below. - void* AllocateUnchecked(size_t size, size_t alignment) { - return DoAllocate(size, alignment); - } - /// Releases a previously-allocated block of memory. /// /// The given pointer must have been previously obtained from a call to either @@ -148,17 +132,7 @@ class Allocator { /// @param[in] ptr Pointer to previously-allocated memory. /// @param[in] layout Describes the memory to be deallocated. void Deallocate(void* ptr, Layout layout) { - return DoDeallocate(ptr, layout.size(), layout.alignment()); - } - - /// Like `Deallocate`, but takes its parameters directly instead of as a - /// `Layout`. - /// - /// Callers should almost always prefer `Deallocate`. This method is meant for - /// use by tests and other allocators implementing the virtual functions - /// below. - void DeallocateUnchecked(void* ptr, size_t size, size_t alignment) { - return DoDeallocate(ptr, size, alignment); + return DoDeallocate(ptr, layout); } /// Modifies the size of an previously-allocated block of memory without @@ -174,19 +148,11 @@ class Allocator { /// @param[in] ptr Pointer to previously-allocated memory. /// @param[in] old_layout Describes the previously-allocated memory. /// @param[in] new_size Requested new size for the memory allocation. - bool Resize(void* ptr, Layout old_layout, size_t new_size) { - return DoResize(ptr, old_layout.size(), old_layout.alignment(), new_size); - } - - /// Like `Resize`, but takes its parameters directly instead of as a `Layout`. - /// - /// Callers should almost always prefer `Resize`. This method is meant for use - /// by tests and other allocators implementing the virtual functions below. - bool ResizeUnchecked(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) { - return DoResize(ptr, old_size, old_alignment, new_size); + bool Resize(void* ptr, Layout layout, size_t new_size) { + if (ptr == nullptr || layout.size() == 0 || new_size == 0) { + return false; + } + return DoResize(ptr, layout, new_size); } /// Modifies the size of a previously-allocated block of memory. @@ -206,24 +172,10 @@ class Allocator { /// 0 will return a new allocation. /// /// @param[in] ptr Pointer to previously-allocated memory. - /// @param[in] old_layout Describes the previously-allocated memory. + /// @param[in] layout Describes the previously-allocated memory. /// @param[in] new_size Requested new size for the memory allocation. - void* Reallocate(void* ptr, Layout old_layout, size_t new_size) { - return DoReallocate( - ptr, old_layout.size(), old_layout.alignment(), new_size); - } - - /// Like `Reallocate`, but takes its parameters directly instead of as a - /// `Layout`. - /// - /// Callers should almost always prefer `Reallocate`. This method is meant for - /// use by tests and other allocators implementing the virtual functions - /// below. - void* ReallocateUnchecked(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) { - return DoReallocate(ptr, old_size, old_alignment, new_size); + void* Reallocate(void* ptr, Layout layout, size_t new_size) { + return DoReallocate(ptr, layout, new_size); } private: @@ -233,31 +185,30 @@ class Allocator { /// Allocators which dispatch to other allocators need to override this method /// in order to be able to direct reallocations and deallocations to /// appropriate allocator. - virtual Status DoQuery(const void*, size_t, size_t) const { + virtual Status DoQuery(const void*, Layout) const { return Status::Unimplemented(); } /// Virtual `Allocate` function implemented by derived classes. - virtual void* DoAllocate(size_t size, size_t alignment) = 0; + virtual void* DoAllocate(Layout layout) = 0; /// Virtual `Deallocate` function implemented by derived classes. - virtual void DoDeallocate(void* ptr, size_t size, size_t alignment) = 0; + virtual void DoDeallocate(void* ptr, Layout layout) = 0; /// Virtual `Resize` function implemented by derived classes. - virtual bool DoResize(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) = 0; + /// + /// The default implementation simply returns `false`, indicating that + /// resizing is not supported. + virtual bool DoResize(void* /*ptr*/, Layout /*layout*/, size_t /*new_size*/) { + return false; + } /// Virtual `Reallocate` function that can be overridden by derived classes. /// /// The default implementation will first try to `Resize` the data. If that is /// unsuccessful, it will allocate an entirely new block, copy existing data, /// and deallocate the given block. - virtual void* DoReallocate(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size); + virtual void* DoReallocate(void* ptr, Layout layout, size_t new_size); }; /// An RAII pointer to a value of type ``T`` stored within an ``Allocator``. diff --git a/pw_allocator/public/pw_allocator/allocator_metric_proxy.h b/pw_allocator/public/pw_allocator/allocator_metric_proxy.h index 045d89545..b4cc3a561 100644 --- a/pw_allocator/public/pw_allocator/allocator_metric_proxy.h +++ b/pw_allocator/public/pw_allocator/allocator_metric_proxy.h @@ -50,19 +50,16 @@ class AllocatorMetricProxy : public Allocator { private: /// @copydoc Allocator::Query - Status DoQuery(const void* ptr, size_t size, size_t alignment) const override; + Status DoQuery(const void* ptr, Layout layout) const override; /// @copydoc Allocator::Allocate - void* DoAllocate(size_t size, size_t alignment) override; + void* DoAllocate(Layout layout) override; /// @copydoc Allocator::Deallocate - void DoDeallocate(void* ptr, size_t size, size_t alignment) override; + void DoDeallocate(void* ptr, Layout layout) override; /// @copydoc Allocator::Resize - bool DoResize(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) override; + bool DoResize(void* ptr, Layout layout, size_t new_size) override; metric::Group memusage_; Allocator* allocator_ = nullptr; diff --git a/pw_allocator/public/pw_allocator/allocator_testing.h b/pw_allocator/public/pw_allocator/allocator_testing.h index 41077522d..f5c84c9ee 100644 --- a/pw_allocator/public/pw_allocator/allocator_testing.h +++ b/pw_allocator/public/pw_allocator/allocator_testing.h @@ -56,19 +56,16 @@ class AllocatorForTest : public Allocator { using BlockType = Block<>; /// @copydoc Allocator::Query - Status DoQuery(const void* ptr, size_t size, size_t alignment) const override; + Status DoQuery(const void* ptr, Layout layout) const override; /// @copydoc Allocator::Allocate - void* DoAllocate(size_t size, size_t alignment) override; + void* DoAllocate(Layout layout) override; /// @copydoc Allocator::Deallocate - void DoDeallocate(void* ptr, size_t size, size_t alignment) override; + void DoDeallocate(void* ptr, Layout layout) override; /// @copydoc Allocator::Resize - bool DoResize(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) override; + bool DoResize(void* ptr, Layout layout, size_t new_size) override; SimpleAllocator allocator_; size_t allocate_size_ = 0; diff --git a/pw_allocator/public/pw_allocator/fallback_allocator.h b/pw_allocator/public/pw_allocator/fallback_allocator.h index 61c20fd2b..5707c1aee 100644 --- a/pw_allocator/public/pw_allocator/fallback_allocator.h +++ b/pw_allocator/public/pw_allocator/fallback_allocator.h @@ -33,19 +33,16 @@ class FallbackAllocator : public Allocator { private: /// @copydoc Allocator::Query - Status DoQuery(const void* ptr, size_t size, size_t alignment) const override; + Status DoQuery(const void* ptr, Layout layout) const override; /// @copydoc Allocator::Allocate - void* DoAllocate(size_t size, size_t alignment) override; + void* DoAllocate(Layout layout) override; /// @copydoc Allocator::Deallocate - void DoDeallocate(void* ptr, size_t size, size_t alignment) override; + void DoDeallocate(void* ptr, Layout layout) override; /// @copydoc Allocator::Resize - bool DoResize(void* ptr, - size_t old_size, - size_t alignment, - size_t new_size) override; + bool DoResize(void* ptr, Layout layout, size_t new_size) override; Allocator* primary_ = nullptr; Allocator* secondary_ = nullptr; diff --git a/pw_allocator/public/pw_allocator/libc_allocator.h b/pw_allocator/public/pw_allocator/libc_allocator.h index 9f2fcd6da..70f67f286 100644 --- a/pw_allocator/public/pw_allocator/libc_allocator.h +++ b/pw_allocator/public/pw_allocator/libc_allocator.h @@ -27,22 +27,16 @@ class LibCAllocator : public Allocator { private: /// @copydoc Allocator::Allocate - void* DoAllocate(size_t size, size_t alignment) override; + void* DoAllocate(Layout layout) override; /// @copydoc Allocator::Deallocate - void DoDeallocate(void* ptr, size_t size, size_t alignment) override; + void DoDeallocate(void* ptr, Layout layout) override; /// @copydoc Allocator::Resize - bool DoResize(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) override; + bool DoResize(void* ptr, Layout layout, size_t new_size) override; /// @copydoc Allocator::Reallocate - void* DoReallocate(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) override; + void* DoReallocate(void* ptr, Layout layout, size_t new_size) override; }; } // namespace pw::allocator diff --git a/pw_allocator/public/pw_allocator/null_allocator.h b/pw_allocator/public/pw_allocator/null_allocator.h index 55a7f62f4..b4c3ba6aa 100644 --- a/pw_allocator/public/pw_allocator/null_allocator.h +++ b/pw_allocator/public/pw_allocator/null_allocator.h @@ -29,13 +29,13 @@ class NullAllocator : public Allocator { private: /// @copydoc Allocator::Allocate - void* DoAllocate(size_t, size_t) override { return nullptr; } + void* DoAllocate(Layout) override { return nullptr; } /// @copydoc Allocator::Deallocate - void DoDeallocate(void*, size_t, size_t) override {} + void DoDeallocate(void*, Layout) override {} /// @copydoc Allocator::Resize - bool DoResize(void*, size_t, size_t, size_t) override { return false; } + bool DoResize(void*, Layout, size_t) override { return false; } }; } // namespace pw::allocator diff --git a/pw_allocator/public/pw_allocator/simple_allocator.h b/pw_allocator/public/pw_allocator/simple_allocator.h index 98513426e..73662d452 100644 --- a/pw_allocator/public/pw_allocator/simple_allocator.h +++ b/pw_allocator/public/pw_allocator/simple_allocator.h @@ -41,7 +41,7 @@ class SimpleAllocator : public Allocator { private: /// @copydoc Allocator::Query - Status DoQuery(const void* ptr, size_t, size_t) const override { + Status DoQuery(const void* ptr, Layout) const override { for (auto* block : Range(blocks_)) { if (block->UsableSpace() == ptr) { return OkStatus(); @@ -51,9 +51,9 @@ class SimpleAllocator : public Allocator { } /// @copydoc Allocator::Allocate - void* DoAllocate(size_t size, size_t alignment) override { + void* DoAllocate(Layout layout) override { for (auto* block : Range(blocks_)) { - if (Block::AllocFirst(block, size, alignment).ok()) { + if (Block::AllocFirst(block, layout.size(), layout.alignment()).ok()) { return block->UsableSpace(); } } @@ -61,7 +61,7 @@ class SimpleAllocator : public Allocator { } /// @copydoc Allocator::Deallocate - void DoDeallocate(void* ptr, size_t, size_t) override { + void DoDeallocate(void* ptr, Layout) override { if (ptr == nullptr) { return; } @@ -71,7 +71,7 @@ class SimpleAllocator : public Allocator { } /// @copydoc Allocator::Resize - bool DoResize(void* ptr, size_t, size_t, size_t new_size) override { + bool DoResize(void* ptr, Layout, size_t new_size) override { if (ptr == nullptr) { return false; } diff --git a/pw_allocator/public/pw_allocator/split_free_list_allocator.h b/pw_allocator/public/pw_allocator/split_free_list_allocator.h index 4ad221ae3..46fd9d971 100644 --- a/pw_allocator/public/pw_allocator/split_free_list_allocator.h +++ b/pw_allocator/public/pw_allocator/split_free_list_allocator.h @@ -90,10 +90,10 @@ class SplitFreeListAllocator : public BaseSplitFreeListAllocator { using ReverseRange = typename BlockType::ReverseRange; /// @copydoc Allocator::Dispatch - Status DoQuery(const void* ptr, size_t size, size_t alignment) const override; + Status DoQuery(const void* ptr, Layout layout) const override; /// @copydoc Allocator::Allocate - void* DoAllocate(size_t size, size_t alignment) override; + void* DoAllocate(Layout layout) override; /// Allocate a large chunk of memory. /// @@ -101,9 +101,8 @@ class SplitFreeListAllocator : public BaseSplitFreeListAllocator { /// addresses. If a block needs to be fragmented, the returned pointer will be /// from the lower-addressed part of the block. /// - /// @param[in] size Length of requested memory. - /// @param[in] alignment Boundary to align the returned memory to. - void* DoAllocateLarge(size_t size, size_t alignment); + /// @param[in] layout Describes the memory to be allocated. + void* DoAllocateLarge(Layout layout); /// Allocate a small chunk of memory. /// @@ -111,18 +110,14 @@ class SplitFreeListAllocator : public BaseSplitFreeListAllocator { /// addresses. If a block needs to be fragmented, the returned pointer will be /// from the higher-addressed part of the block. /// - /// @param[in] size Length of requested memory. - /// @param[in] alignment Boundary to align the returned memory to. - void* DoAllocateSmall(size_t size, size_t alignment); + /// @param[in] layout Describes the memory to be allocated. + void* DoAllocateSmall(Layout layout); /// @copydoc Allocator::Deallocate - void DoDeallocate(void* ptr, size_t size, size_t alignment) override; + void DoDeallocate(void* ptr, Layout layout) override; /// @copydoc Allocator::Resize - bool DoResize(void* ptr, - size_t old_size, - size_t old_alignment, - size_t new_size) override; + bool DoResize(void* ptr, Layout layout, size_t new_size) override; // Represents the entire memory region for this allocator. void* begin_ = nullptr; @@ -189,34 +184,30 @@ Status SplitFreeListAllocator<BlockType>::Init(ByteSpan region, template <typename BlockType> Status SplitFreeListAllocator<BlockType>::DoQuery(const void* ptr, - size_t, - size_t) const { + Layout) const { return (ptr < begin_ || end_ <= ptr) ? Status::OutOfRange() : OkStatus(); } template <typename BlockType> -void* SplitFreeListAllocator<BlockType>::DoAllocate(size_t size, - size_t alignment) { - if (begin_ == nullptr || size == 0) { +void* SplitFreeListAllocator<BlockType>::DoAllocate(Layout layout) { + if (begin_ == nullptr || layout.size() == 0) { return nullptr; } - void* ptr = size < threshold_ ? DoAllocateSmall(size, alignment) - : DoAllocateLarge(size, alignment); - - // Update the first and last free blocks. - return ptr; + size_t size = layout.size(); + size_t alignment = std::max(layout.alignment(), BlockType::kAlignment); + layout = Layout(size, alignment); + return size < threshold_ ? DoAllocateSmall(layout) : DoAllocateLarge(layout); } template <typename BlockType> -void* SplitFreeListAllocator<BlockType>::DoAllocateSmall(size_t size, - size_t alignment) { +void* SplitFreeListAllocator<BlockType>::DoAllocateSmall(Layout layout) { // Update the cached last free block. while (last_free_->Used() && first_free_ != last_free_) { last_free_ = last_free_->Prev(); } // Search backwards for the first block that can hold this allocation. for (auto* block : ReverseRange(last_free_, first_free_)) { - if (BlockType::AllocLast(block, size, alignment).ok()) { + if (BlockType::AllocLast(block, layout.size(), layout.alignment()).ok()) { return block->UsableSpace(); } } @@ -225,15 +216,14 @@ void* SplitFreeListAllocator<BlockType>::DoAllocateSmall(size_t size, } template <typename BlockType> -void* SplitFreeListAllocator<BlockType>::DoAllocateLarge(size_t size, - size_t alignment) { +void* SplitFreeListAllocator<BlockType>::DoAllocateLarge(Layout layout) { // Update the cached first free block. while (first_free_->Used() && first_free_ != last_free_) { first_free_ = first_free_->Next(); } // Search forwards for the first block that can hold this allocation. for (auto* block : Range(first_free_, last_free_)) { - if (BlockType::AllocFirst(block, size, alignment).ok()) { + if (BlockType::AllocFirst(block, layout.size(), layout.alignment()).ok()) { // A new last free block may be split off the end of the allocated block. if (last_free_ <= block) { last_free_ = block->Last() ? block : block->Next(); @@ -246,9 +236,7 @@ void* SplitFreeListAllocator<BlockType>::DoAllocateLarge(size_t size, } template <typename BlockType> -void SplitFreeListAllocator<BlockType>::DoDeallocate(void* ptr, - size_t, - size_t) { +void SplitFreeListAllocator<BlockType>::DoDeallocate(void* ptr, Layout) { // Do nothing if uninitialized or no memory block pointer. if (begin_ == nullptr || ptr < begin_ || end_ <= ptr) { return; @@ -270,12 +258,10 @@ void SplitFreeListAllocator<BlockType>::DoDeallocate(void* ptr, template <typename BlockType> bool SplitFreeListAllocator<BlockType>::DoResize(void* ptr, - size_t old_size, - size_t old_alignment, + Layout layout, size_t new_size) { // Fail to resize is uninitialized or invalid parameters. - if (begin_ == nullptr || ptr == nullptr || old_size == 0 || new_size == 0 || - !DoQuery(ptr, old_size, old_alignment).ok()) { + if (begin_ == nullptr || !DoQuery(ptr, layout).ok()) { return false; } diff --git a/pw_allocator/split_free_list_allocator_test.cc b/pw_allocator/split_free_list_allocator_test.cc index ab4bab42b..c519849d6 100644 --- a/pw_allocator/split_free_list_allocator_test.cc +++ b/pw_allocator/split_free_list_allocator_test.cc @@ -118,15 +118,15 @@ TEST_F(SplitFreeListAllocatorTest, AllocateTooLarge) { TEST_F(SplitFreeListAllocatorTest, AllocateLargeAlignment) { constexpr size_t kSize = sizeof(uint32_t); constexpr size_t kAlignment = 64; - ptrs_[0] = allocator_->AllocateUnchecked(kSize, kAlignment); + ptrs_[0] = allocator_->Allocate(Layout(kSize, kAlignment)); ASSERT_NE(ptrs_[0], nullptr); EXPECT_EQ(reinterpret_cast<uintptr_t>(ptrs_[0]) % kAlignment, 0U); UseMemory(ptrs_[0], kSize); - ptrs_[1] = allocator_->AllocateUnchecked(kSize, kAlignment); + ptrs_[1] = allocator_->Allocate(Layout(kSize, kAlignment)); ASSERT_NE(ptrs_[1], nullptr); EXPECT_EQ(reinterpret_cast<uintptr_t>(ptrs_[1]) % kAlignment, 0U); - UseMemory(ptrs_[0], kSize); + UseMemory(ptrs_[1], kSize); } TEST_F(SplitFreeListAllocatorTest, AllocateFromUnaligned) { @@ -165,26 +165,27 @@ TEST_F(SplitFreeListAllocatorTest, AllocateAlignmentFailure) { outer_size - (BlockType::kBlockOverhead * 3 + inner_size1 + inner_size2); // Allocate all the blocks. - ptrs_[0] = allocator_->AllocateUnchecked(inner_size1, 1); + ptrs_[0] = allocator_->Allocate(Layout(inner_size1, 1)); ASSERT_NE(ptrs_[0], nullptr); - ptrs_[1] = allocator_->AllocateUnchecked(inner_size2, 1); + ptrs_[1] = allocator_->Allocate(Layout(inner_size2, 1)); ASSERT_NE(ptrs_[1], nullptr); - ptrs_[2] = allocator_->AllocateUnchecked(inner_size3, 1); + ptrs_[2] = allocator_->Allocate(Layout(inner_size3, 1)); ASSERT_NE(ptrs_[2], nullptr); // If done correctly, the second block's usable space should be unaligned. EXPECT_NE(reinterpret_cast<uintptr_t>(ptrs_[1]) % kAlignment, 0U); // Free the second region. This leaves an unaligned region available. - allocator_->DeallocateUnchecked(ptrs_[1], inner_size2, 1); + allocator_->Deallocate(ptrs_[1], Layout(inner_size2, 1)); ptrs_[1] = nullptr; // The allocator should be unable to create an aligned region.. - ptrs_[3] = allocator_->AllocateUnchecked(inner_size2, kAlignment); + ptrs_[3] = allocator_->Allocate(Layout(inner_size2, kAlignment)); EXPECT_EQ(ptrs_[3], nullptr); } + TEST_F(SplitFreeListAllocatorTest, DeallocateNull) { constexpr Layout layout = Layout::Of<uint8_t>(); allocator_->Deallocate(nullptr, layout); diff --git a/pw_multibuf/public/pw_multibuf/internal/test_utils.h b/pw_multibuf/public/pw_multibuf/internal/test_utils.h index 3e713fff8..07e325016 100644 --- a/pw_multibuf/public/pw_multibuf/internal/test_utils.h +++ b/pw_multibuf/public/pw_multibuf/internal/test_utils.h @@ -41,17 +41,16 @@ class TrackingAllocator : public pw::allocator::Allocator { size_t used() const { return alloc_stats_.used(); } protected: - void* DoAllocate(size_t size, size_t alignment) override { - return alloc_stats_.AllocateUnchecked(size, alignment); + void* DoAllocate(allocator::Layout layout) override { + return alloc_stats_.Allocate(layout); } bool DoResize(void* ptr, - size_t old_size, - size_t old_align, + allocator::Layout old_layout, size_t new_size) override { - return alloc_stats_.ResizeUnchecked(ptr, old_size, old_align, new_size); + return alloc_stats_.Resize(ptr, old_layout, new_size); } - void DoDeallocate(void* ptr, size_t size, size_t alignment) override { - alloc_stats_.DeallocateUnchecked(ptr, size, alignment); + void DoDeallocate(void* ptr, allocator::Layout layout) override { + alloc_stats_.Deallocate(ptr, layout); } private: @@ -70,17 +69,16 @@ class TrackingAllocatorWithMemory : public pw::allocator::Allocator { TrackingAllocatorWithMemory() : mem_(), alloc_(mem_) {} size_t count() const { return alloc_.count(); } size_t used() const { return alloc_.used(); } - void* DoAllocate(size_t size, size_t alignment) override { - return alloc_.AllocateUnchecked(size, alignment); + void* DoAllocate(allocator::Layout layout) override { + return alloc_.Allocate(layout); } bool DoResize(void* ptr, - size_t old_size, - size_t old_align, + allocator::Layout old_layout, size_t new_size) override { - return alloc_.ResizeUnchecked(ptr, old_size, old_align, new_size); + return alloc_.Resize(ptr, old_layout, new_size); } - void DoDeallocate(void* ptr, size_t size, size_t alignment) override { - alloc_.DeallocateUnchecked(ptr, size, alignment); + void DoDeallocate(void* ptr, allocator::Layout layout) override { + alloc_.Deallocate(ptr, layout); } private: @@ -121,9 +119,9 @@ class HeaderChunkRegionTracker final : public ChunkRegionTracker { /// or ``nullptr`` if the allocation failed. static HeaderChunkRegionTracker* AllocateRegion( pw::allocator::Allocator* alloc, size_t size) { - const size_t alloc_size = size + sizeof(HeaderChunkRegionTracker); - const size_t align = alignof(HeaderChunkRegionTracker); - void* ptr = alloc->AllocateUnchecked(alloc_size, align); + auto layout = + allocator::Layout::Of<HeaderChunkRegionTracker>().Extend(size); + void* ptr = alloc->Allocate(layout); if (ptr == nullptr) { return nullptr; } @@ -138,11 +136,11 @@ class HeaderChunkRegionTracker final : public ChunkRegionTracker { protected: void Destroy() final { std::byte* ptr = reinterpret_cast<std::byte*>(this); - const size_t size = sizeof(HeaderChunkRegionTracker) + region_.size(); - const size_t align = alignof(HeaderChunkRegionTracker); + auto layout = allocator::Layout::Of<HeaderChunkRegionTracker>().Extend( + region_.size()); auto alloc = alloc_; std::destroy_at(this); - alloc->DeallocateUnchecked(ptr, size, align); + alloc->Deallocate(ptr, layout); } void* AllocateChunkClass() final { return alloc_->Allocate(pw::allocator::Layout::Of<Chunk>()); |