diff --git a/wpiutil/src/main/native/include/wpi/uv/Buffer.h b/wpiutil/src/main/native/include/wpi/uv/Buffer.h index 9f69f03c13..a0afbe4b44 100644 --- a/wpiutil/src/main/native/include/wpi/uv/Buffer.h +++ b/wpiutil/src/main/native/include/wpi/uv/Buffer.h @@ -15,6 +15,7 @@ #include #include "wpi/ArrayRef.h" +#include "wpi/SmallVector.h" #include "wpi/StringRef.h" namespace wpi { @@ -86,6 +87,65 @@ class Buffer : public uv_buf_t { } }; +/** + * A simple pool allocator for Buffers. + * Buffers are allocated individually but are reused rather than returned + * to the heap. + * @tparam DEPTH depth of pool + */ +template +class SimpleBufferPool { + public: + /** + * Constructor. + * @param size Size of each buffer to allocate. + */ + explicit SimpleBufferPool(size_t size = 4096) : m_size{size} {} + + /** + * Allocate a buffer. + */ + Buffer Allocate() { + if (m_pool.empty()) return Buffer::Allocate(m_size); + auto buf = m_pool.back(); + m_pool.pop_back(); + buf.len = m_size; + return buf; + } + + /** + * Allocate a buffer. + */ + Buffer operator()() { return Allocate(); } + + /** + * Release allocated buffers back into the pool. + * This is NOT safe to use with arbitrary buffers unless they were + * allocated with the same size as the buffer pool allocation size. + */ + void Release(MutableArrayRef bufs) { + for (auto& buf : bufs) m_pool.emplace_back(buf.Move()); + } + + /** + * Clear the pool, releasing all buffers. + */ + void Clear() { + for (auto& buf : m_pool) buf.Deallocate(); + m_pool.clear(); + } + + /** + * Get number of buffers left in the pool before a new buffer will be + * allocated from the heap. + */ + size_t Remaining() const { return m_pool.size(); } + + private: + SmallVector m_pool; + size_t m_size; +}; + } // namespace uv } // namespace wpi diff --git a/wpiutil/src/test/native/cpp/uv/UvBufferTest.cpp b/wpiutil/src/test/native/cpp/uv/UvBufferTest.cpp new file mode 100644 index 0000000000..e837ca9f22 --- /dev/null +++ b/wpiutil/src/test/native/cpp/uv/UvBufferTest.cpp @@ -0,0 +1,50 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2018 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "wpi/uv/Buffer.h" // NOLINT(build/include_order) + +#include "gtest/gtest.h" // NOLINT(build/include_order) + +namespace wpi { +namespace uv { + +TEST(UvSimpleBufferPool, ConstructDefault) { + SimpleBufferPool<> pool; + auto buf1 = pool.Allocate(); + ASSERT_EQ(buf1.len, 4096u); +} + +TEST(UvSimpleBufferPool, ConstructSize) { + SimpleBufferPool<4> pool{8192}; + auto buf1 = pool.Allocate(); + ASSERT_EQ(buf1.len, 8192u); +} + +TEST(UvSimpleBufferPool, ReleaseReuse) { + SimpleBufferPool<4> pool; + auto buf1 = pool.Allocate(); + auto buf1copy = buf1; + auto origSize = buf1.len; + buf1.len = 8; + pool.Release(buf1); + ASSERT_EQ(buf1.base, nullptr); + auto buf2 = pool.Allocate(); + ASSERT_EQ(buf1copy.base, buf2.base); + ASSERT_EQ(buf2.len, origSize); +} + +TEST(UvSimpleBufferPool, ClearRemaining) { + SimpleBufferPool<4> pool; + auto buf1 = pool.Allocate(); + pool.Release(buf1); + ASSERT_EQ(pool.Remaining(), 1u); + pool.Clear(); + ASSERT_EQ(pool.Remaining(), 0u); +} + +} // namespace uv +} // namespace wpi