#pragma once namespace _cow_util { /// A type that spans a sized region of memory template struct Span { protected: virtual const void* area() const =0; virtual void* area() = 0; public: virtual size_t size() const = 0; inline T* ptr() { return reinterpret_cast(area()); } inline const T* ptr() const { return reinterpret_cast(area()); } inline size_t size_bytes() const { return size() * sizeof(T); } inline unsigned char* as_bytes() { return area_as(); } inline const unsigned char* as_bytes() const { return area_as(); } inline T& operator[](size_t index) { if(index >= size()) throw "index out of range"; return ptr()[index]; } inline const T& operator[](size_t index) const { if(index >= size()) throw "index out of range"; return ptr()[index]; } inline T* operator&() { return &(*this)[0]; } inline const T* operator&() const {return &(*this)[0]; } inline T* operator->() { return &(*this)[0]; } inline const T* operator->() const {return &(*this)[0]; } inline T& operator*() { return (*this)[0]; } inline const T& operator*() const { return (*this)[0]; } inline operator const T*() const { return &(*this)[0]; } inline operator T*() { return &(*this)[0]; } template inline U* area_as() requires(sizeof(T) % sizeof(U) == 0) { return reinterpret_cast(area()); } template inline const U* area_as() const requires(sizeof(T) % sizeof(U) == 0) { return reinterpret_cast(area()); } template size_t size_as() const requires(sizeof(T) % sizeof(U) == 0) { return size_bytes() / sizeof(U); } struct Slice; inline operator Slice() { return Slice(ptr(), size()); } inline operator const Slice() const { return Slice(const_cast(ptr()), size()); } inline bool bounds_ok(size_t start) const { return start < size(); } inline bool bounds_ok(size_t start, size_t len) const { return (start + len) <= size() && bounds_ok(start); } inline ssize_t wrap_len(ssize_t len) const { if(size() ==0 ) return 0; return len < 0 ? wrap_len(size() + len) : ((size_t)len) % size(); } /// Slice (absolute). Specify start and end. inline const Slice slice_abs(size_t start, size_t end) const { auto len = end -start; if(bounds_ok(start,len)) return Slice(const_cast(ptr()+start), len); else throw "Out of bounds slice"; } inline Slice slice_abs(size_t start, size_t end) { auto len = end -start; if(bounds_ok(start,len)) return Slice(ptr()+start, len); else throw "Out of bounds slice"; } /// Slice (relative). Specify start and length. inline const Slice slice(size_t start, size_t len) const { if(bounds_ok(start,len)) return Slice(const_cast(ptr()+start), len); else throw "Out of bounds slice"; } inline Slice slice(size_t start, size_t len) { if(bounds_ok(start,len)) return Slice(ptr()+start, len); else throw "Out of bounds slice"; } /// Slice from 0. Specify length. inline Slice slice(size_t len) { return slice(0, len); } inline const Slice slice(size_t len) const { return slice(0, len); }//slice(start, size()-start); } /// Slice total. inline Slice slice() { return slice(0, size()); } inline const Slice slice() const { return slice(0, size()); } /// Slice wrapping. Specify start and end that may wrap over and/or under the span's size. inline Slice slice_wrap(ssize_t start, ssize_t end) { return slice_abs((size_t)wrap_len(start), (size_t)wrap_len(end)); } inline const Slice slice_wrap(ssize_t start, ssize_t end) const { return slice_abs((size_t)wrap_len(start), (size_t)wrap_len(end)); } inline Slice slice_wrap(ssize_t len) { return slice_abs((size_t)wrap_len(len)); } inline const Slice slice_wrap(ssize_t len) const { return slice_abs((size_t)wrap_len(len)); } template inline Span::Slice reinterpret() { return typename Span::Slice(area_as(), size_bytes() / sizeof(U)); } template inline Span::Slice reinterpret() const { return typename Span::Slice(area_as(), size_bytes() / sizeof(U)); } }; /// A slice of memory with a backing pointer and size. template struct Span::Slice : public Span { inline Slice(T* ptr, size_t sz) : _area(reinterpret_cast(ptr)), _size(sz){} inline Slice(const Span& slice) : _area(const_cast(slice.area())), _size(slice.size()){} inline Slice(const Slice& copy) = default; inline Slice(Slice&& copy) : _area(copy._area), _size(copy._size){ *const_cast(©._size) = 0; } Slice() = delete; inline size_t size() const override { return _size; } protected: inline const void* area() const override { return _area; } inline void* area() override { return _area; } private: void* const _area; const size_t _size; }; template using Slice = Span::Slice; }