diff --git a/libraries/libvapours/include/vapours.hpp b/libraries/libvapours/include/vapours.hpp index 4db67f4e8..d51797e3a 100644 --- a/libraries/libvapours/include/vapours.hpp +++ b/libraries/libvapours/include/vapours.hpp @@ -20,6 +20,7 @@ #include #include +#include #include #include diff --git a/libraries/libvapours/include/vapours/span.hpp b/libraries/libvapours/include/vapours/span.hpp new file mode 100644 index 000000000..ee0a07a2d --- /dev/null +++ b/libraries/libvapours/include/vapours/span.hpp @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +namespace ams { + + /* TODO C++20 switch to template using Span = std::span */ + + namespace impl { + + template + class SpanConstIterator; + + template + class SpanIteratorImpl { + public: + friend class SpanConstIterator; + + using index_type = typename Span::index_type; + using difference_type = typename Span::difference_type; + using value_type = typename std::remove_cv::type; + using pointer = typename std::add_pointer::type; + using reference = Reference; + using iterator_category = std::random_access_iterator_tag; + private: + const Span *span = nullptr; + index_type index = 0; + public: + constexpr ALWAYS_INLINE SpanIteratorImpl() = default; + constexpr ALWAYS_INLINE SpanIteratorImpl(const Span *s, index_type idx) : span(s), index(idx) { /* ... */ } + + constexpr ALWAYS_INLINE pointer operator->() const { + return this->span->data() + this->index; + } + + constexpr ALWAYS_INLINE reference operator*() const { + return *this->operator->(); + } + + constexpr ALWAYS_INLINE Derived operator++(int) { + auto prev = static_cast(*this); + ++(*this); + return prev; + } + + constexpr ALWAYS_INLINE Derived operator--(int) { + auto prev = static_cast(*this); + --(*this); + return prev; + } + + constexpr ALWAYS_INLINE Derived &operator++() { ++this->index; return static_cast(*this); } + constexpr ALWAYS_INLINE Derived &operator--() { --this->index; return static_cast(*this); } + + constexpr ALWAYS_INLINE Derived &operator+=(difference_type n) { this->index += n; return static_cast(*this); } + constexpr ALWAYS_INLINE Derived &operator-=(difference_type n) { this->index -= n; return static_cast(*this); } + + constexpr ALWAYS_INLINE Derived operator+(difference_type n) const { auto r = static_cast(*this); return r += n; } + constexpr ALWAYS_INLINE Derived operator-(difference_type n) const { auto r = static_cast(*this); return r -= n; } + + constexpr ALWAYS_INLINE friend Derived operator+(difference_type n, Derived it) { return it + n; } + constexpr ALWAYS_INLINE difference_type operator-(Derived rhs) const { AMS_ASSERT(this->span == rhs.span); return this->index - rhs.index; } + + constexpr ALWAYS_INLINE reference operator[](difference_type n) const { return *(*this + n); } + + constexpr ALWAYS_INLINE friend bool operator==(Derived lhs, Derived rhs) { + return lhs.span == rhs.span && lhs.index == rhs.index; + } + + constexpr ALWAYS_INLINE friend bool operator<(Derived lhs, Derived rhs) { + AMS_ASSERT(lhs.span == rhs.span); + return lhs.index < rhs.index; + } + + constexpr ALWAYS_INLINE friend bool operator!=(Derived lhs, Derived rhs) { return !(lhs == rhs); } + + constexpr ALWAYS_INLINE friend bool operator>(Derived lhs, Derived rhs) { return rhs < lhs; } + + constexpr ALWAYS_INLINE friend bool operator<=(Derived lhs, Derived rhs) { return !(lhs > rhs); } + constexpr ALWAYS_INLINE friend bool operator>=(Derived lhs, Derived rhs) { return !(lhs < rhs); } + }; + + template + class SpanIterator : public SpanIteratorImpl, typename Span::element_type&> { + public: + using SpanIteratorImpl, typename Span::element_type&>::SpanIteratorImpl; + }; + + template + class SpanConstIterator : public SpanIteratorImpl, const typename Span::element_type&> { + public: + using SpanIteratorImpl, const typename Span::element_type&>::SpanIteratorImpl; + + constexpr ALWAYS_INLINE SpanConstIterator() = default; + constexpr ALWAYS_INLINE SpanConstIterator(const SpanIterator &rhs) : SpanConstIterator(rhs.span, rhs.index) { /* ... */ } + }; + + } + + template + class Span { + public: + using element_type = T; + using value_type = typename std::remove_cv::type; + using index_type = std::ptrdiff_t; + using difference_type = std::ptrdiff_t; + using pointer = element_type *; + using reference = element_type &; + using iterator = ::ams::impl::SpanIterator; + using const_iterator = ::ams::impl::SpanConstIterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + private: + T *ptr; + index_type num_elements; + public: + constexpr ALWAYS_INLINE Span() : ptr(), num_elements() { /* ... */ } + + constexpr ALWAYS_INLINE Span(T *p, index_type size) : ptr(p), num_elements(size) { + AMS_ASSERT(this->num_elements > 0 || this->ptr == nullptr); + } + + constexpr ALWAYS_INLINE Span(T *start, T *end) : Span(start, end - start) { /* ... */ } + + template + constexpr ALWAYS_INLINE Span(T (&arr)[Size]) : Span(static_cast(arr), static_cast(Size)) { /* ... */ } + + template + constexpr ALWAYS_INLINE Span(std::array &arr) : Span(arr.data(), static_cast(Size)) { /* ... */ } + + template + constexpr ALWAYS_INLINE Span(const std::array &arr) : Span(arr.data(), static_cast(Size)) { /* ... */ } + + template::value>::type> + constexpr ALWAYS_INLINE Span(const Span &rhs) : Span(rhs.data(), rhs.size()) { /* ... */ } + public: + constexpr ALWAYS_INLINE iterator begin() const { return { this, 0 }; } + constexpr ALWAYS_INLINE iterator end() const { return { this, this->num_elements }; } + + constexpr ALWAYS_INLINE const_iterator cbegin() const { return { this, 0 }; } + constexpr ALWAYS_INLINE const_iterator cend() const { return { this, this->num_elements }; } + + constexpr ALWAYS_INLINE reverse_iterator rbegin() const { return reverse_iterator(this->end()); } + constexpr ALWAYS_INLINE reverse_iterator rend() const { return reverse_iterator(this->begin()); } + + constexpr ALWAYS_INLINE const_reverse_iterator crbegin() const { return reverse_iterator(this->cend()); } + constexpr ALWAYS_INLINE const_reverse_iterator crend() const { return reverse_iterator(this->cbegin()); } + + constexpr ALWAYS_INLINE pointer data() const { return this->ptr; } + + constexpr ALWAYS_INLINE index_type size() const { return this->num_elements; } + constexpr ALWAYS_INLINE index_type size_bytes() const { return this->size() * sizeof(T); } + + constexpr ALWAYS_INLINE bool empty() const { return this->size() == 0; } + + constexpr ALWAYS_INLINE T &operator[](index_type idx) const { + AMS_ASSERT(idx < this->size()); + return this->ptr[idx]; + } + + constexpr ALWAYS_INLINE T &operator()(index_type idx) const { return (*this)[idx]; } + + constexpr ALWAYS_INLINE Span first(index_type size) const { + AMS_ASSERT(size <= this->size()); + return { this->ptr, size }; + } + + constexpr ALWAYS_INLINE Span last(index_type size) const { + AMS_ASSERT(size <= this->size()); + return { this->ptr + (this->size() - size), size }; + } + + constexpr ALWAYS_INLINE Span subspan(index_type idx, index_type size) const { + AMS_ASSERT(size <= this->size()); + AMS_ASSERT(this->size() - size >= idx); + return { this->ptr + idx, size }; + } + + constexpr ALWAYS_INLINE Span subspan(index_type idx) const { + AMS_ASSERT(idx <= this->size()); + return { this->ptr + idx, this->size() - idx }; + } + }; + + template + constexpr ALWAYS_INLINE Span MakeSpan(T *start, T *end) { + return { start, end }; + } + + template + constexpr ALWAYS_INLINE Span MakeSpan(T *p, typename Span::index_type size) { + return { p, size }; + } + + template + constexpr ALWAYS_INLINE Span MakeSpan(T (&arr)[Size]) { + return Span(arr); + } + + template + constexpr ALWAYS_INLINE Span MakeSpan(std::array &arr) { + return Span(arr); + } + + template + constexpr ALWAYS_INLINE Span MakeSpan(const std::array &arr) { + return Span(arr); + } + +}