// SPDX-License-Identifier: MPL-2.0 // Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) #pragma once #include #include "utils.h" namespace skyline { /** * @brief A custom wrapper over span that adds several useful methods to it * @note This class is completely transparent, it implicitly converts from and to span */ template class span : public std::span { public: using std::span::span; using std::span::operator=; typedef typename std::span::element_type element_type; typedef typename std::span::size_type size_type; constexpr span(const std::span &spn) : std::span(spn) {} /** * @brief A single-element constructor for a span */ constexpr span(T &spn) : std::span(&spn, 1) {} /** * @brief We want to support implicitly casting from std::string_view -> span as it's just a specialization of a data view which span is a generic form of, the opposite doesn't hold true as not all data held by a span is string data therefore the conversion isn't implicit there */ template constexpr span(const std::basic_string_view &string) : std::span(const_cast(string.data()), string.size()) {} template constexpr Out &as() { if constexpr (Extent != std::dynamic_extent && sizeof(T) * Extent >= sizeof(Out)) return *reinterpret_cast(span::data()); if (span::size_bytes() >= sizeof(Out)) return *reinterpret_cast(span::data()); throw exception("Span size is less than Out type size (0x{:X}/0x{:X})", span::size_bytes(), sizeof(Out)); } /** * @param nullTerminated If true and the string is null-terminated, a view of it will be returned (not including the null terminator itself), otherwise the entire span will be returned as a string view */ constexpr std::string_view as_string(bool nullTerminated = false) { return std::string_view(reinterpret_cast(span::data()), nullTerminated ? static_cast(std::find(span::begin(), span::end(), 0) - span::begin()) : span::size_bytes()); } template constexpr span cast() { if (SkipAlignmentCheck || util::IsAligned(span::size_bytes(), sizeof(Out))) return span(reinterpret_cast(span::data()), span::size_bytes() / sizeof(Out)); throw exception("Span size not aligned with Out type size (0x{:X}/0x{:X})", span::size_bytes(), sizeof(Out)); } /** * @brief Copies data from the supplied span into this one * @param amount The amount of elements that need to be copied (in terms of the supplied span), 0 will try to copy the entirety of the other span */ template constexpr void copy_from(const span spn, size_type amount = 0) { auto size{amount ? amount * sizeof(In) : spn.size_bytes()}; if (span::size_bytes() < size) throw exception("Data being copied is larger than this span"); std::memmove(span::data(), spn.data(), size); } /** * @brief Implicit type conversion for copy_from, this allows passing in std::vector/std::array in directly is automatically passed by reference which is important for any containers */ template constexpr void copy_from(const In &in, size_type amount = 0) { copy_from(span::type>(in), amount); } /** * @return If a supplied span is located entirely inside this span and is effectively a subspan */ constexpr bool contains(const span& other) const { return this->begin() <= other.begin() && this->end() >= other.end(); } /** Comparision operators for equality and binary searches **/ constexpr bool operator==(const span& other) const { return this->data() == other.data() && this->size() == other.size(); } constexpr bool operator<(const span &other) const { return this->data() < other.data(); } constexpr bool operator<(T* pointer) const { return this->data() < pointer; } constexpr bool operator<(typename std::span::iterator it) const { return this->begin() < it; } /** Base Class Functions that return an instance of it, we upcast them **/ template constexpr span first() const noexcept { return std::span::template first(); } template constexpr span last() const noexcept { return std::span::template last(); } constexpr span first(size_type count) const noexcept { return std::span::first(count); } constexpr span last(size_type count) const noexcept { return std::span::last(count); } template constexpr auto subspan() const noexcept -> span { return std::span::template subspan(); } constexpr span subspan(size_type offset, size_type count = std::dynamic_extent) const noexcept { return std::span::subspan(offset, count); } }; /** * @brief Deduction guides required for arguments to span, CTAD will fail for iterators, arrays and containers without this */ template span(It, End) -> span::value_type, Extent>; template span(T (&)[Size]) -> span; template span(std::array &) -> span; template span(const std::array &) -> span; template span(Container &) -> span; template span(const Container &) -> span; }