Skip to content

Commit

Permalink
buffer: Add realign() member function
Browse files Browse the repository at this point in the history
This function is used to realign the buffer so that the data starts at
a given offest from the beginning of the buffer. This is useful when
a struct is streamed into the buffer but it is not aligned to the
proper memory boundary.

Might also be useful for other use cases.

ConstBufferType::realign() is a const member function that does a
similar thing but since ConstBufferType doesn't own its buffer
it can't grow if this is required. This overload of realign() will
grow the buffer if that is needed, and if not it calls the const
version of realign().

Unit tests included.

Signed-off-by: Charlie Vigue <[email protected]>
  • Loading branch information
cvigue committed Nov 22, 2024
1 parent d21bc91 commit d29b5f0
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 6 deletions.
35 changes: 29 additions & 6 deletions openvpn/buffer/buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,7 @@ class BufferType : public ConstBufferType<T>
/**
* @brief Default constructor for BufferType.
*/
BufferType(){};
BufferType() = default;

/**
* @brief Constructor for BufferType that takes a void pointer, size, and a flag indicating if the buffer is filled.
Expand Down Expand Up @@ -953,6 +953,15 @@ class BufferAllocatedType : public BufferType<T>
*/
void realloc(const size_t newcap);

/**
@brief Realign the buffer with the specified headroom.
@param headroom The amount of headroom to reserve in the buffer.
@return BufferAllocatedType& A reference to the realigned buffer.
@note May reallocate or throw an exception if the reallocation fails.
@throws if the buffer is full and the reallocation fails.
*/
BufferAllocatedType &realign(const size_t headroom);

/**
* @brief Resets the buffer with the specified minimum capacity and flags.
* @param min_capacity The minimum capacity for the buffer.
Expand Down Expand Up @@ -1052,8 +1061,9 @@ class BufferAllocatedType : public BufferType<T>
/**
* @brief Reallocates the buffer to the specified new capacity.
* @param newcap The new capacity for the buffer.
* @param new_offset The new offset for the buffer.
*/
void realloc_(const size_t newcap);
void realloc_(const size_t newcap, size_t new_offset);

/**
* @brief Frees the data associated with the buffer.
Expand Down Expand Up @@ -1709,7 +1719,20 @@ template <typename T>
void BufferAllocatedType<T>::realloc(const size_t newcap)
{
if (newcap > capacity())
realloc_(newcap);
realloc_(newcap, offset());
}

template <typename T>
BufferAllocatedType<T> &BufferAllocatedType<T>::realign(const size_t headroom)
{
if (headroom != offset())
{
if (headroom + size() > capacity())
realloc_(headroom + size(), headroom);
else
BufferType<T>::realign(headroom);
}
return *this;
}

template <typename T>
Expand Down Expand Up @@ -1800,16 +1823,16 @@ void BufferAllocatedType<T>::resize(const size_t new_capacity)
if (newcap > capacity())
{
if (flags_ & BufAllocFlags::GROW)
realloc_(newcap);
realloc_(newcap, offset());
else
buffer_full_error(newcap, true);
}
}

template <typename T>
void BufferAllocatedType<T>::realloc_(const size_t newcap)
void BufferAllocatedType<T>::realloc_(const size_t newcap, size_t new_offset)
{
auto tempBuffer = BufferAllocatedType(offset(), size(), newcap, flags_);
auto tempBuffer = BufferAllocatedType(new_offset, size(), newcap, flags_);
if (size())
std::memcpy(tempBuffer.data(), c_data(), size() * sizeof(T));
swap(tempBuffer);
Expand Down
59 changes: 59 additions & 0 deletions test/unittests/test_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,62 @@ TEST(buffer, alloc_buffer_read1)

EXPECT_EQ(memcmp(raw, data, sizeof(raw)), 0);
}

TEST(buffer, realign)
{
BufferAllocated buf(64, 0);
buf_append_string(buf, "hello world");

buf.advance(5);
EXPECT_EQ(buf.c_data_raw()[0], 'h');

buf.realign(0);

EXPECT_EQ(buf[0], ' ');
EXPECT_EQ(buf[5], 'd');
EXPECT_THROW(buf[6], BufferException);
EXPECT_EQ(buf.size(), 6u);
EXPECT_EQ(buf.c_data_raw()[0], ' ');
}

TEST(buffer, realign2)
{
BufferAllocated buf(64, 0);
buf_append_string(buf, "hello world");

EXPECT_EQ(buf.c_data_raw()[0], 'h');

buf.realign(5);

EXPECT_EQ(buf.c_data_raw()[5], 'h');
EXPECT_EQ(buf[0], 'h');
EXPECT_EQ(buf.size(), 11u);
}

TEST(buffer, realign3)
{
BufferAllocated buf(11, 0);
buf_append_string(buf, "hello world");

EXPECT_EQ(buf.c_data_raw()[0], 'h');

buf.realign(5);

EXPECT_EQ(buf.c_data_raw()[5], 'h');
EXPECT_EQ(buf[0], 'h');
EXPECT_EQ(buf.size(), 11u);
EXPECT_EQ(buf.offset(), 5u);
}

TEST(buffer, realign4)
{
BufferAllocated buf(32, 0);
buf.realign(7u);
buf_append_string(buf, "hello world");
EXPECT_EQ(buf.offset(), 7u);
buf.realign(0);

EXPECT_EQ(buf.c_data_raw()[0], 'h');
EXPECT_EQ(buf[0], 'h');
EXPECT_EQ(buf.offset(), 0);
}

0 comments on commit d29b5f0

Please sign in to comment.