Skip to content

Commit

Permalink
Allow arena allocator to be used with alternative memory resource (#486)
Browse files Browse the repository at this point in the history
* Allow arena allocator to be used with alternative memory resource

* Fixing compiler errors

* Re-organizing tests
  • Loading branch information
jatinchowdhury18 authored Jan 29, 2024
1 parent a69e6f1 commit 19fd177
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace chowdsp
{
/** A simple arena allocator */
template <typename MemoryResourceType = std::vector<std::byte>>
class ArenaAllocator
{
public:
Expand Down Expand Up @@ -100,7 +101,7 @@ class ArenaAllocator
}

private:
std::vector<std::byte> raw_data {};
MemoryResourceType raw_data {};
size_t bytes_used = 0;
};
} // namespace chowdsp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class ChainedArenaAllocator
}

/** Returns the arena currently being used */
ArenaAllocator& get_current_arena()
ArenaAllocator<>& get_current_arena()
{
jassert (current_arena != arenas.end());
return *current_arena;
Expand Down Expand Up @@ -111,8 +111,8 @@ class ChainedArenaAllocator
}

ChainedArenaAllocator& alloc;
const std::forward_list<ArenaAllocator>::iterator arena_at_start;
ArenaAllocator::Frame arena_frame;
const std::forward_list<ArenaAllocator<>>::iterator arena_at_start;
ArenaAllocator<>::Frame arena_frame;
};

/** Creates a frame for this allocator */
Expand All @@ -139,8 +139,8 @@ class ChainedArenaAllocator
get_current_arena().clear();
}

std::forward_list<ArenaAllocator> arenas {};
std::forward_list<ArenaAllocator>::iterator current_arena {};
std::forward_list<ArenaAllocator<>> arenas {};
std::forward_list<ArenaAllocator<>>::iterator current_arena {};
size_t arena_size_bytes = 0;
size_t arena_count = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class GainComputer
*/
void processBlock (const BufferView<const SampleType>& levelBuffer,
const BufferView<SampleType>& gainBuffer,
ArenaAllocator* arena = nullptr) noexcept
ArenaAllocator<>* arena = nullptr) noexcept
{
jassert (levelBuffer.getNumSamples() == gainBuffer.getNumSamples());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::setRampLength (double
}

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSamples, ArenaAllocator& alloc)
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSamples, ArenaAllocator<>& alloc)
{
bufferData = alloc.allocate<FloatType> (numSamples, bufferAlignment);
jassert (bufferData != nullptr); // arena allocator is out of memory!
Expand Down Expand Up @@ -114,7 +114,7 @@ void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSample
}

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (FloatType value, int numSamples, ArenaAllocator& alloc)
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (FloatType value, int numSamples, ArenaAllocator<>& alloc)
{
bufferData = alloc.allocate<FloatType> (numSamples, bufferAlignment);
jassert (bufferData != nullptr); // arena allocator is out of memory!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ class SmoothedBufferValue
* Please don't call this function if the parameter handle hasn't been set!
*/
void process (int numSamples);
void process (int numSamples, ArenaAllocator& alloc);
void process (int numSamples, ArenaAllocator<>& alloc);

/**
* Process smoothing for the input value.
* If smoothing an audio parameter, it is recommended to use a parameter handle instead!
*/
void process (FloatType value, int numSamples);
void process (FloatType value, int numSamples, ArenaAllocator& alloc);
void process (FloatType value, int numSamples, ArenaAllocator<>& alloc);

/** Returns a pointer to the current smoothed buffer. */
[[nodiscard]] const FloatType* getSmoothedBuffer() const { return bufferData; }
Expand Down
106 changes: 78 additions & 28 deletions tests/common_tests/chowdsp_data_structures_test/ArenaAllocatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,92 @@

TEST_CASE ("Arena Allocator Test", "[common][data-structures]")
{
chowdsp::ArenaAllocator allocator { 150 };

// allocate doubles
SECTION ("With std::vector<std::byte>")
{
auto* some_doubles = allocator.allocate<double> (10);
REQUIRE ((void*) some_doubles == allocator.data<void> (0));
REQUIRE (allocator.get_bytes_used() == 80);
}
chowdsp::ArenaAllocator allocator { 150 };

// allocate doubles
{
auto* some_doubles = allocator.allocate<double> (10);
REQUIRE ((void*) some_doubles == allocator.data<void> (0));
REQUIRE (allocator.get_bytes_used() == 80);
}

// allocate ints
{
auto* some_ints = allocator.allocate<int32_t> (10);
REQUIRE ((void*) some_ints == allocator.data<void> (80));
REQUIRE (allocator.get_bytes_used() == 120);
}

// allocate with stack frame
{
const auto frame = allocator.create_frame();
auto* some_chars = allocator.allocate<char> (30);
juce::ignoreUnused (some_chars);
REQUIRE (allocator.get_bytes_used() == 150);
}

// allocate ints
{
auto* some_ints = allocator.allocate<int32_t> (10);
REQUIRE ((void*) some_ints == allocator.data<void> (80));
REQUIRE (allocator.get_bytes_used() == 120);

// aligned allocation
{
auto* some_data = allocator.allocate<float> (1, 16);
REQUIRE (juce::snapPointerToAlignment (some_data, (size_t) 16) == some_data);
}

// overfull allocation
REQUIRE (allocator.allocate<double> (100) == nullptr);

// clear allocator
allocator.clear();
REQUIRE (allocator.get_bytes_used() == 0);
}

// allocate with stack frame
SECTION ("With std::array<std::byte>")
{
const auto frame = allocator.create_frame();
auto* some_chars = allocator.allocate<char> (30);
juce::ignoreUnused (some_chars);
REQUIRE (allocator.get_bytes_used() == 150);
}
struct ArrayMemoryResource : std::array<std::byte, 150>
{
void resize (size_t N, std::byte value = {}) { juce::ignoreUnused (N, value); } // NOLINT
};

REQUIRE (allocator.get_bytes_used() == 120);
chowdsp::ArenaAllocator<ArrayMemoryResource> allocator { 150 };

// aligned allocation
{
auto* some_data = allocator.allocate<float> (1, 16);
REQUIRE (juce::snapPointerToAlignment (some_data, (size_t) 16) == some_data);
}
// allocate doubles
{
auto* some_doubles = allocator.allocate<double> (10);
REQUIRE ((void*) some_doubles == allocator.data<void> (0));
REQUIRE (allocator.get_bytes_used() == 80);
}

// overfull allocation
REQUIRE (allocator.allocate<double> (100) == nullptr);
// allocate ints
{
auto* some_ints = allocator.allocate<int32_t> (10);
REQUIRE ((void*) some_ints == allocator.data<void> (80));
REQUIRE (allocator.get_bytes_used() == 120);
}

// clear allocator
allocator.clear();
REQUIRE (allocator.get_bytes_used() == 0);
// allocate with stack frame
{
const auto frame = allocator.create_frame();
auto* some_chars = allocator.allocate<char> (30);
juce::ignoreUnused (some_chars);
REQUIRE (allocator.get_bytes_used() == 150);
}

REQUIRE (allocator.get_bytes_used() == 120);

// aligned allocation
{
auto* some_data = allocator.allocate<float> (1, 16);
REQUIRE (juce::snapPointerToAlignment (some_data, (size_t) 16) == some_data);
}

// overfull allocation
REQUIRE (allocator.allocate<double> (100) == nullptr);

// clear allocator
allocator.clear();
REQUIRE (allocator.get_bytes_used() == 0);
}
}

0 comments on commit 19fd177

Please sign in to comment.