#pragma once
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <gp/optional.hpp>
|
|
#include <gp/iterator.hpp>
|
|
#include <gp/function.hpp>
|
|
#include <gp/exception.hpp>
|
|
#include <gp/algorithm/move.hpp>
|
|
|
|
namespace gp{
|
|
|
|
template<typename T>
|
|
class buffer final{
|
|
public:
|
|
struct buffer_iterator final
|
|
{
|
|
T* data;
|
|
typedef T value_type;
|
|
typedef std::size_t difference_type;
|
|
static constexpr iterator_type_t iterator_type = iterator_type_t::contiguous_iterator;
|
|
|
|
constexpr buffer_iterator(const buffer_iterator& oth)
|
|
: data{oth.data}
|
|
{}
|
|
|
|
constexpr buffer_iterator(T* ptr)
|
|
: data{ptr}
|
|
{}
|
|
|
|
constexpr operator T&()
|
|
{
|
|
return *data;
|
|
}
|
|
|
|
constexpr T& operator*(){
|
|
return *data;
|
|
}
|
|
|
|
constexpr buffer_iterator operator++()
|
|
{
|
|
return buffer_iterator{++data};
|
|
}
|
|
|
|
constexpr buffer_iterator operator++(int)
|
|
{
|
|
return buffer_iterator{data++};
|
|
}
|
|
|
|
constexpr buffer_iterator operator--()
|
|
{
|
|
return buffer_iterator{--data};
|
|
}
|
|
|
|
constexpr buffer_iterator operator--(int)
|
|
{
|
|
return buffer_iterator{data--};
|
|
}
|
|
|
|
constexpr buffer_iterator operator+(const std::size_t offset)
|
|
{
|
|
return buffer_iterator{data+offset};
|
|
}
|
|
|
|
constexpr buffer_iterator operator+(const int offset)
|
|
{
|
|
return buffer_iterator{data+offset};
|
|
}
|
|
|
|
constexpr buffer_iterator operator-(const std::size_t offset)
|
|
{
|
|
return buffer_iterator{data-offset};
|
|
}
|
|
|
|
constexpr buffer_iterator operator-(const int offset)
|
|
{
|
|
return buffer_iterator{data-offset};
|
|
}
|
|
|
|
constexpr difference_type operator-(const buffer_iterator& oth) const
|
|
{
|
|
return (T*)data-(T*)oth.data;
|
|
}
|
|
|
|
constexpr bool operator==(const buffer_iterator& oth)
|
|
{
|
|
return data==oth.data;
|
|
}
|
|
|
|
constexpr bool operator!=(buffer_iterator& oth)
|
|
{
|
|
return data!=oth.data;
|
|
}
|
|
|
|
constexpr bool before_or_equal(const buffer_iterator& oth)
|
|
{
|
|
return reinterpret_cast<std::intptr_t>(data) <= reinterpret_cast<std::intptr_t>(oth.data);
|
|
}
|
|
|
|
constexpr bool operator<=(const buffer_iterator& oth)
|
|
{
|
|
return before_or_equal(oth);
|
|
}
|
|
};
|
|
private:
|
|
buffer_iterator begin_elem;
|
|
buffer_iterator end_elem;
|
|
public:
|
|
using associated_iterator = buffer_iterator;
|
|
|
|
constexpr buffer(T* beg_ptr, T* end_ptr)
|
|
: begin_elem{beg_ptr}
|
|
, end_elem{end_ptr}
|
|
{}
|
|
|
|
constexpr buffer(T* beg_ptr, std::size_t sz)
|
|
: begin_elem{beg_ptr}
|
|
, end_elem{beg_ptr+sz}
|
|
{}
|
|
|
|
constexpr typename buffer_iterator::difference_type size() const
|
|
{
|
|
return end_elem - begin_elem;
|
|
}
|
|
|
|
constexpr associated_iterator begin() const
|
|
{
|
|
return begin_elem;
|
|
}
|
|
|
|
constexpr associated_iterator end() const
|
|
{
|
|
return end_elem;
|
|
}
|
|
|
|
constexpr T& operator[](std::size_t offset)
|
|
{
|
|
return *(begin_elem+offset);
|
|
}
|
|
|
|
optional<buffer_iterator> at(std::size_t offset)
|
|
{
|
|
auto elem = begin()+offset;
|
|
if(!contains(elem))
|
|
{
|
|
return nullopt;
|
|
}
|
|
return elem;
|
|
}
|
|
|
|
constexpr bool contains(buffer_iterator ptr)
|
|
{
|
|
return
|
|
ptr.data < end_elem.data
|
|
&& ptr.data >= begin_elem.data;
|
|
}
|
|
|
|
template<typename U>
|
|
buffer<U> cast()
|
|
{
|
|
if constexpr(sizeof(T)%sizeof(U) == 0)
|
|
{
|
|
return buffer<U>(reinterpret_cast<U*>(&*begin_elem), size()*(sizeof(T)/sizeof(U)));
|
|
}
|
|
else
|
|
{
|
|
if(size()*sizeof(T)/sizeof(U))
|
|
{
|
|
return buffer<U>(reinterpret_cast<U*>(&*begin_elem), size()*sizeof(T)/sizeof(U));
|
|
}
|
|
else if constexpr (gp_config::has_exceptions)
|
|
{
|
|
throw bad_buffer_cast<T, U>{};
|
|
}
|
|
else
|
|
{
|
|
return buffer<U>(reinterpret_cast<U*>(nullptr), 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
buffer slice_start(size_t new_sz)
|
|
{
|
|
if(new_sz<=size())
|
|
{
|
|
return buffer{&*begin(), &*(begin()+new_sz)};
|
|
}
|
|
else
|
|
{
|
|
return buffer{(T*)nullptr,(size_t)0};
|
|
}
|
|
}
|
|
|
|
buffer slice_end(size_t new_sz)
|
|
{
|
|
if(new_sz<=size())
|
|
{
|
|
return buffer{&*(end()-(1+new_sz)), &*end()};
|
|
}
|
|
else
|
|
{
|
|
return buffer{(T*)nullptr,(size_t)0};
|
|
}
|
|
}
|
|
};
|
|
}
|