Skip to content

Commit

Permalink
Added implementation of buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
JohanMabille committed Feb 12, 2024
1 parent 6636250 commit cd54a79
Show file tree
Hide file tree
Showing 5 changed files with 328 additions and 6 deletions.
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ OPTION(BUILD_TESTS "xparrow test suite" OFF)
# =====

set(XPARROW_HEADERS
${XPARROW_INCLUDE_DIR}/xparrow/xparrow_version.pp
${XPARROW_INCLUDE_DIR}/xparrow/xbuffer.hpp
${XPARROW_INCLUDE_DIR}/xparrow/xparrow_version.hpp
)

add_library(xparrow INTERFACE)
Expand Down Expand Up @@ -65,7 +66,7 @@ install(TARGETS xparrow
export(EXPORT ${PROJECT_NAME}-targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake")

install(FILES ${Xparrow_HEADERS}
install(FILES ${XPARROW_HEADERS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xparrow)

set(XPARROW_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}" CACHE
Expand Down
239 changes: 239 additions & 0 deletions include/xparrow/xbuffer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
/***************************************************************************
* Copyright (c) QuantStack *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
***************************************************************************/

#pragma once

#include <algorithm>
#include <concepts>
#include <cstdint>

namespace xp
{
namespace impl
{
template <class T>
struct xbuffer_data
{
using value_type = T;
using pointer = T*;
using size_type = std::size_t;

bool empty() const noexcept;
size_type size() const noexcept;

template <class U = T>
U* data() noexcept;

template <class U = T>
const U* data() const noexcept;

void swap(xbuffer_data& rhs) noexcept;
bool equal(const xbuffer_data& rhs) const;

pointer p_data = nullptr;
size_type m_size = 0;
};
}

/**
* @class xbuffer
* @brief Object that owns a piece of contiguous memory
*/
template <class T>
class xbuffer : private impl::xbuffer_data<T>
{
public:

using base_type = impl::xbuffer_data<T>;
using value_type = typename base_type::value_type;
using pointer = typename base_type::pointer;
using size_type = typename base_type::size_type;

xbuffer() = default;
explicit xbuffer(size_type size);
xbuffer(pointer data, size_type size);

~xbuffer();

xbuffer(const xbuffer&);
xbuffer& operator=(const xbuffer&);

xbuffer(xbuffer&&);
xbuffer& operator=(xbuffer&&);

using base_type::empty;
using base_type::size;
using base_type::data;

void resize(size_type new_size);

void swap(xbuffer&) noexcept;
bool equal(const xbuffer& rhs) const;

private:

pointer allocate(size_type size) const;
void deallocate(pointer mem) const;
};

template <class T>
bool operator==(const xbuffer<T>& lhs, const xbuffer<T>& rhs);

/**
* @class xbuffer_reference
* @brief Object that wraps a piece of contiguous memory
* but does not own it.
*/
/*class xbuffer_reference : private xbuffer_data
{
public:
using base_type = xbuffer_data;
xbuffer_reference(uint8_t* data, std::size_t size);
using base_type::size;
using base_type::data;
void swap(xbuffer_reference&) noexcept;
};*/

/******************************
* xbuffer_data implementation *
******************************/

namespace impl
{
template <class T>
bool xbuffer_data<T>::empty() const noexcept
{
return size() == size_type(0);
}

template <class T>
auto xbuffer_data<T>::size() const noexcept -> size_type
{
return m_size;
}

template <class T>
template <class U>
U* xbuffer_data<T>::data() noexcept
{
return reinterpret_cast<U*>(p_data);
}

template <class T>
template <class U>
const U* xbuffer_data<T>::data() const noexcept
{
return reinterpret_cast<const U*>(p_data);
}

template <class T>
void xbuffer_data<T>::swap(xbuffer_data<T>& rhs) noexcept
{
std::swap(p_data, rhs.p_data);
std::swap(m_size, rhs.m_size);
}

template <class T>
bool xbuffer_data<T>::equal(const xbuffer_data<T>& rhs) const
{
return m_size == rhs.m_size && std::equal(p_data, p_data + m_size, rhs.p_data);
}
}

/*************************
* xbuffer implementation *
*************************/

template <class T>
xbuffer<T>::xbuffer(size_type size)
: base_type{allocate(size), size}
{
}

template <class T>
xbuffer<T>::xbuffer(pointer data, size_type size)
: base_type{data, size}
{
}

template <class T>
xbuffer<T>::~xbuffer()
{
deallocate(this->p_data);
this->p_data = nullptr;
this->m_size = 0u;
}

template <class T>
xbuffer<T>::xbuffer(const xbuffer<T>& rhs)
: base_type{allocate(rhs.m_size), rhs.size()}
{
std::copy(rhs.data(), rhs.data() + rhs.size(), data());
}

template <class T>
xbuffer<T>& xbuffer<T>::operator=(const xbuffer<T>& rhs)
{
if (this != &rhs)
{
xbuffer<T> tmp(rhs);
swap(tmp);
}
return *this;
}

template <class T>
xbuffer<T>::xbuffer(xbuffer&& rhs)
: base_type{rhs.data(), rhs.size()}
{
rhs.p_data = nullptr;
rhs.m_size = 0u;
}

template <class T>
xbuffer<T>& xbuffer<T>::operator=(xbuffer<T>&& rhs)
{
swap(rhs);
return *this;
}

template <class T>
void xbuffer<T>::swap(xbuffer<T>& rhs) noexcept
{
base_type::swap(rhs);
}

template <class T>
bool xbuffer<T>::equal(const xbuffer<T>& rhs) const
{
return base_type::equal(rhs);
}

template <class T>
auto xbuffer<T>::allocate(size_type size) const -> pointer
{
return new T[size];
}

template <class T>
void xbuffer<T>::deallocate(pointer mem) const
{
delete[] mem;
}

template <class T>
bool operator==(const xbuffer<T>& lhs, const xbuffer<T>& rhs)
{
return lhs.equal(rhs);
}
}

5 changes: 2 additions & 3 deletions include/xparrow/xparrow_version.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
* *
* The full license is in the file LICENSE, distributed with this software. *
***************************************************************************/
#ifndef XPARROW_VERSION_HPP
#define XPARROW_VERSION_HPP

#pragma once

#define XPARROW_VERSION_MAJOR 0
#define XPARROW_VERSION_MINOR 0
#define XPARROW_VERSION_PATCH 1

#endif
3 changes: 2 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ endif()

set(XPARROW_TESTS
main.cpp
test_xbuffer.cpp
)
set(test_target "test_xparrow_lib")
add_executable(${test_target} ${XPARROW_TESTS})
target_link_libraries(${test_target} PRIVATE doctest::doctest)
target_link_libraries(${test_target} PRIVATE xparrow doctest::doctest)
82 changes: 82 additions & 0 deletions test/test_xbuffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/***************************************************************************
* Copyright (c) QuantStack *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
***************************************************************************/

#include "doctest/doctest.h"

#include <numeric>

#include "xparrow/xbuffer.hpp"

namespace xp
{
using buffer_test_type = xbuffer<uint8_t>;

namespace
{
uint8_t* make_test_buffer(std::size_t size, uint8_t start_value = 0)
{
uint8_t* res = new uint8_t[size];
std::iota(res, res + size, start_value);
return res;
}
}

TEST_SUITE("xbuffer")
{
TEST_CASE("constructors")
{
buffer_test_type b0;
CHECK_EQ(b0.data(), nullptr);
CHECK_EQ(b0.size(), 0u);

std::size_t size = 4u;
buffer_test_type b1(size);
CHECK_NE(b1.data(), nullptr);
CHECK_EQ(b1.size(), size);

uint8_t* mem = make_test_buffer(size);
buffer_test_type b2(mem, size);
CHECK_EQ(b2.data(), mem);
CHECK_EQ(b2.size(), size);
CHECK_EQ(b2.data()[2], uint8_t(2));
}

TEST_CASE("copy semantic")
{
std::size_t size = 4;
buffer_test_type b1(make_test_buffer(size), size);
buffer_test_type b2(b1);
CHECK_EQ(b1, b2);

std::size_t size2 = 8;
buffer_test_type b3(make_test_buffer(size2, 4), size2);
b2 = b3;
CHECK_EQ(b2, b3);
CHECK_NE(b1, b2);
}

TEST_CASE("move semantic")
{
std::size_t size = 4;
buffer_test_type b1(make_test_buffer(size), size);
buffer_test_type control(b1);
buffer_test_type b2(std::move(b1));
CHECK_EQ(b2, control);
CHECK_EQ(b1.size(), 0);
CHECK(b1.empty());
CHECK_EQ(b1.data(), nullptr);

std::size_t size2 = 8;
buffer_test_type b4(make_test_buffer(size2, 4), size2);
buffer_test_type control2(b4);
b2 = std::move(b4);
CHECK_EQ(b2, control2);
CHECK_EQ(b4, control);
}
}
}

0 comments on commit cd54a79

Please sign in to comment.