Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow arena allocator to be used with alternative memory resource #486

Merged
merged 3 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
}

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSamples, ArenaAllocator& alloc)
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSamples, ArenaAllocator<>& alloc)

Check warning on line 88 in modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.cpp

View check run for this annotation

Codecov / codecov/patch

modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.cpp#L88

Added line #L88 was not covered by tests
{
bufferData = alloc.allocate<FloatType> (numSamples, bufferAlignment);
jassert (bufferData != nullptr); // arena allocator is out of memory!
Expand Down Expand Up @@ -114,7 +114,7 @@
}

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)

Check warning on line 117 in modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.cpp

View check run for this annotation

Codecov / codecov/patch

modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.cpp#L117

Added line #L117 was not covered by tests
{
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);
}
}
Loading