Added StrideSpan type (a span with a stride). Added makeSpan() function to TypelessBuffer.
This commit is contained in:
parent
617e051943
commit
938135768b
232
source/mijin/container/stride_span.hpp
Normal file
232
source/mijin/container/stride_span.hpp
Normal file
@ -0,0 +1,232 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(MIJIN_CONTAINER_STRIDE_SPAN_HPP_INCLUDED)
|
||||
#define MIJIN_CONTAINER_STRIDE_SPAN_HPP_INCLUDED 1
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include "../debug/assert.hpp"
|
||||
|
||||
namespace mijin
|
||||
{
|
||||
|
||||
//
|
||||
// public defines
|
||||
//
|
||||
|
||||
//
|
||||
// public constants
|
||||
//
|
||||
|
||||
//
|
||||
// public types
|
||||
//
|
||||
|
||||
template<typename T, typename U>
|
||||
[[nodiscard]] std::ptrdiff_t bytediff(T* first, U* second) noexcept
|
||||
{
|
||||
return std::bit_cast<std::byte*>(second) - std::bit_cast<std::byte*>(first);
|
||||
}
|
||||
template<typename T>
|
||||
[[nodiscard]] T* byteoffset(T* old, std::ptrdiff_t offset) noexcept
|
||||
{
|
||||
return std::bit_cast<T*>(std::bit_cast<std::byte*>(old) + offset);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class StrideSpanIterator
|
||||
{
|
||||
public:
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = T;
|
||||
private:
|
||||
T* ele_ = nullptr;
|
||||
std::size_t strideBytes_ = 0;
|
||||
#if MIJIN_CHECKED_ITERATORS
|
||||
T* start_ = nullptr;
|
||||
T* end_ = nullptr;
|
||||
#endif
|
||||
public:
|
||||
StrideSpanIterator() = default;
|
||||
constexpr StrideSpanIterator(T* ele, std::size_t strideBytes, [[maybe_unused]] T* start, [[maybe_unused]] T* end)
|
||||
: ele_(ele), strideBytes_(strideBytes)
|
||||
#if MIJIN_CHECKED_ITERATORS
|
||||
, start_(start), end_(end)
|
||||
#endif
|
||||
{
|
||||
MIJIN_ASSERT(strideBytes_!= 0 && bytediff(start_, end_) % strideBytes_ == 0, "StrideSpan: stride elements don't match supplied pointers.");
|
||||
}
|
||||
StrideSpanIterator(const StrideSpanIterator&) = default;
|
||||
|
||||
StrideSpanIterator& operator=(const StrideSpanIterator&) = default;
|
||||
StrideSpanIterator& operator+=(difference_type diff);
|
||||
StrideSpanIterator& operator-=(difference_type diff) {
|
||||
return *this += -diff;
|
||||
}
|
||||
|
||||
constexpr auto operator<=>(const StrideSpanIterator&) const noexcept = default;
|
||||
|
||||
[[nodiscard]] T& operator*() const;
|
||||
[[nodiscard]] T* operator->() const;
|
||||
StrideSpanIterator& operator++();
|
||||
StrideSpanIterator operator++(int);
|
||||
StrideSpanIterator& operator--();
|
||||
StrideSpanIterator operator--(int);
|
||||
|
||||
[[nodiscard]] difference_type operator-(const StrideSpanIterator& other) const { return bytediff(other.ele_, ele_) / strideBytes_; }
|
||||
[[nodiscard]] StrideSpanIterator operator+(difference_type diff) const;
|
||||
[[nodiscard]] StrideSpanIterator operator-(difference_type diff) const { return (*this + -diff); }
|
||||
|
||||
[[nodiscard]] T& operator[](difference_type diff) const { return *(*this + diff); }
|
||||
};
|
||||
template<typename T>
|
||||
inline StrideSpanIterator<T> operator+(std::iter_difference_t<T> diff, const StrideSpanIterator<T>& iter) {
|
||||
return iter + diff;
|
||||
}
|
||||
static_assert(std::random_access_iterator<StrideSpanIterator<int>>);
|
||||
|
||||
template<typename T>
|
||||
class StrideSpan
|
||||
{
|
||||
public:
|
||||
using element_type = T;
|
||||
using value_type = std::remove_cv_t<T>;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using iterator = StrideSpanIterator<T>;
|
||||
using const_iterator = StrideSpanIterator<const T>;
|
||||
private:
|
||||
T* begin_ = nullptr;
|
||||
T* end_ = nullptr;
|
||||
std::size_t strideBytes_ = 0;
|
||||
public:
|
||||
StrideSpan() = default;
|
||||
StrideSpan(const StrideSpan&) = default;
|
||||
StrideSpan(T* begin, T* end, std::size_t strideBytes) noexcept : begin_(begin), end_(end), strideBytes_(strideBytes) {
|
||||
MIJIN_ASSERT(strideBytes_ > 0, "Stride elements must be >0.");
|
||||
MIJIN_ASSERT(strideBytes_ % alignof(T) == 0, "Stride must be a multiple of element align.");
|
||||
MIJIN_ASSERT(bytediff(begin_, end_) % strideBytes_ == 0, "Difference of begin and end must be a multiple of stride bytes.");
|
||||
}
|
||||
|
||||
StrideSpan& operator=(const StrideSpan&) = default;
|
||||
auto operator<=>(const StrideSpan&) const noexcept = default;
|
||||
|
||||
reference operator[](size_type index);
|
||||
const_reference operator[](size_type index) const;
|
||||
|
||||
[[nodiscard]] constexpr size_type size() const noexcept { return bytediff(begin_, end_) / strideBytes_; }
|
||||
|
||||
[[nodiscard]] iterator begin() { return StrideSpanIterator<T>(begin_, strideBytes_, begin_, end_); }
|
||||
[[nodiscard]] const_iterator begin() const { return StrideSpanIterator<const T>(begin_, strideBytes_, begin_, end_); }
|
||||
[[nodiscard]] const_iterator cbegin() const { return StrideSpanIterator<const T>(begin_, strideBytes_, begin_, end_); }
|
||||
[[nodiscard]] iterator end() { return StrideSpanIterator<T>(end_, strideBytes_, begin_, end_); }
|
||||
[[nodiscard]] const_iterator end() const { return StrideSpanIterator<const T>(end_, strideBytes_, begin_, end_); }
|
||||
[[nodiscard]] const_iterator cend() const { return StrideSpanIterator<const T>(end_, strideBytes_, begin_, end_); }
|
||||
};
|
||||
|
||||
//
|
||||
// public functions
|
||||
//
|
||||
|
||||
template<typename T>
|
||||
StrideSpanIterator<T>& StrideSpanIterator<T>::operator+=(difference_type diff)
|
||||
{
|
||||
#if MIJIN_CHECKED_ITERATORS
|
||||
MIJIN_ASSERT(byteoffset(ele_, diff * strideBytes_) <= end_ && byteoffset(ele_, diff * strideBytes_) >= start_,
|
||||
"Moving iterator out-of-bounds.");
|
||||
#endif
|
||||
ele_ = byteoffset(ele_, diff * strideBytes_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& StrideSpanIterator<T>::operator*() const
|
||||
{
|
||||
#if MIJIN_CHECKED_ITERATORS
|
||||
MIJIN_ASSERT(ele_ >= start_ && ele_ < end_, "Attempting to dereference invalid iterator.");
|
||||
#endif
|
||||
return *ele_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* StrideSpanIterator<T>::operator->() const
|
||||
{
|
||||
#if MIJIN_CHECKED_ITERATORS
|
||||
MIJIN_ASSERT(ele_ >= start_ && ele_ < end_, "Attempting to dereference invalid iterator.");
|
||||
#endif
|
||||
return ele_;
|
||||
}
|
||||
template<typename T>
|
||||
StrideSpanIterator<T>& StrideSpanIterator<T>::operator++()
|
||||
{
|
||||
#if MIJIN_CHECKED_ITERATORS
|
||||
MIJIN_ASSERT(ele_ < end_, "Attempting to move iterator past end.");
|
||||
#endif
|
||||
ele_ = byteoffset(ele_, strideBytes_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrideSpanIterator<T> StrideSpanIterator<T>::operator++(int)
|
||||
{
|
||||
StrideSpanIterator copy(*this);
|
||||
++(*this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrideSpanIterator<T>& StrideSpanIterator<T>::operator--()
|
||||
{
|
||||
#if MIJIN_CHECKED_ITERATORS
|
||||
MIJIN_ASSERT(ele_ > start_, "Attempting to move iterator before start.");
|
||||
#endif
|
||||
ele_ = byteoffset(ele_, -strideBytes_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrideSpanIterator<T> StrideSpanIterator<T>::operator--(int)
|
||||
{
|
||||
StrideSpanIterator copy(*this);
|
||||
--(*this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
StrideSpanIterator<T> StrideSpanIterator<T>::operator+(difference_type diff) const
|
||||
{
|
||||
#if MIJIN_CHECKED_ITERATORS
|
||||
MIJIN_ASSERT((byteoffset(ele_ + strideBytes_ * diff) <= end_) && (byteoffset(ele_, strideBytes_ * diff) >= start_),
|
||||
"Creating out-of-bounds iterator.");
|
||||
#endif
|
||||
return StrideSpanIterator(byteoffset(ele_, diff * strideBytes_), strideBytes_,
|
||||
#if MIJIN_CHECKED_ITERATORS
|
||||
start_, end_
|
||||
#else
|
||||
nullptr, nullptr
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto StrideSpan<T>::operator[](size_type index) -> reference
|
||||
{
|
||||
MIJIN_ASSERT(index < size(), "Attempting to access StrideSpan out of bounds.");
|
||||
return *byteoffset(begin_, index * strideBytes_);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto StrideSpan<T>::operator[](size_type index) const -> const_reference
|
||||
{
|
||||
MIJIN_ASSERT(index < size(), "Attempting to access StrideSpan out of bounds.");
|
||||
return byteoffset(begin_, index * strideBytes_);
|
||||
}
|
||||
} // namespace mijin
|
||||
|
||||
#endif // !defined(MIJIN_CONTAINER_STRIDE_SPAN_HPP_INCLUDED)
|
@ -5,6 +5,7 @@
|
||||
#define MIJIN_CONTAINER_TYPELESS_BUFFER_HPP_INCLUDED 1
|
||||
|
||||
#include <cstddef>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include "../debug/assert.hpp"
|
||||
|
||||
@ -41,6 +42,12 @@ public:
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] BufferView<T> makeBufferView() { return BufferView<T>(this); }
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] std::span<T> makeSpan();
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] std::span<const T> makeSpan() const;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@ -99,6 +106,25 @@ public:
|
||||
// public functions
|
||||
//
|
||||
|
||||
template<typename T>
|
||||
std::span<T> TypelessBuffer::makeSpan()
|
||||
{
|
||||
MIJIN_ASSERT(bytes_.size() % sizeof(T) == 0, "Buffer cannot be divided into elements of this type.");
|
||||
return {
|
||||
std::bit_cast<T*>(bytes_.data()),
|
||||
std::bit_cast<T*>(bytes_.data() + bytes_.size())
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::span<const T> TypelessBuffer::makeSpan() const
|
||||
{
|
||||
MIJIN_ASSERT(bytes_.size() % sizeof(T) == 0, "Buffer cannot be divided into elements of this type.");
|
||||
return {
|
||||
std::bit_cast<const T*>(bytes_.data()),
|
||||
std::bit_cast<const T*>(bytes_.data() + bytes_.size())
|
||||
};
|
||||
}
|
||||
} // namespace mijin
|
||||
|
||||
#endif // !defined(MIJIN_CONTAINER_TYPELESS_BUFFER_HPP_INCLUDED)
|
||||
|
Loading…
x
Reference in New Issue
Block a user