-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6636250
commit 880225c
Showing
5 changed files
with
318 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
/*************************************************************************** | ||
* 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; | ||
|
||
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::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> | ||
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); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/*************************************************************************** | ||
* 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_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); | ||
} | ||
} | ||
} |