/** * @file libimp/span.h * @author mutouyun (orz@orzz.org) * @brief Describes an object that can refer to a contiguous sequence of objects * @date 2022-10-16 */ #pragma once #include #include #include #include #ifdef LIBIMP_CPP_20 #include #endif // LIBIMP_CPP_20 #include "libimp/def.h" #include "libimp/detect_plat.h" LIBIMP_NAMESPACE_BEG_ namespace detail { /// @brief helper trait for span template using array_convertible = std::is_convertible; template using compatible_ref = array_convertible::type, T>; template using iter_reference_t = decltype(*std::declval()); template using is_array_convertible = typename std::enable_if::value>::type; template using is_compatible_iter = typename std::enable_if>::value>::type; template using is_inconvertible = typename std::enable_if::value>::type; /// @brief Obtain the address represented by p /// without forming a reference to the object pointed to by p. /// @see https://en.cppreference.com/w/cpp/memory/to_address template constexpr T *to_address(T *ptr) noexcept { static_assert(!std::is_function::value, "ptr shouldn't a function pointer"); return ptr; } template constexpr auto to_address(T const &ptr) noexcept(noexcept(ptr.operator->())) -> decltype(ptr.operator->()) { return to_address(ptr.operator->()); } } // namespace detail /** * @brief A simple implementation of span. * @see https://en.cppreference.com/w/cpp/container/span */ template class span { public: using element_type = T; using value_type = typename std::remove_cv::type; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using pointer = element_type *; using const_pointer = typename std::remove_const::type const *; using reference = element_type &; using const_reference = typename std::remove_const::type const &; using iterator = pointer; using reverse_iterator = std::reverse_iterator; private: pointer ptr_ {nullptr}; size_type extent_ {0}; public: constexpr span() noexcept = default; constexpr span(span const &) noexcept = default; constexpr span & operator=(span const &) noexcept = default; template > constexpr span(It first, size_type count) noexcept : ptr_ (detail::to_address(first)) , extent_(count) {} template , typename = detail::is_compatible_iter, typename = detail::is_inconvertible> constexpr span(It first, End last) noexcept(noexcept(last - first)) : ptr_ (detail::to_address(first)) , extent_(static_cast(last - first)) {} template > constexpr span(U (&arr)[E]) noexcept : span(static_cast(arr), E) {} template > constexpr span(std::array &arr) noexcept : span(static_cast(arr.data()), E) {} template ::type, element_type>> constexpr span(std::array const &arr) noexcept : span(static_cast(arr.data()), E) {} template > constexpr span(span const &s) noexcept : ptr_ (s.data()) , extent_(s.size()) {} #ifdef LIBIMP_CPP_20 template > constexpr span(std::span const &s) noexcept : ptr_ (s.data()) , extent_(s.size()) {} #endif // LIBIMP_CPP_20 constexpr size_type size() const noexcept { return extent_; } constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); } constexpr bool empty() const noexcept { return size() == 0; } constexpr pointer data() const noexcept { return this->ptr_; } constexpr reference front() const noexcept { return *data(); } constexpr reference back() const noexcept { return *(data() + (size() - 1)); } constexpr reference operator[](size_type idx) const noexcept { return *(data() + idx); } constexpr iterator begin() const noexcept { return iterator(data()); } constexpr iterator end() const noexcept { return iterator(data() + this->size()); } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(this->end()); } constexpr reverse_iterator rend() const noexcept { return reverse_iterator(this->begin()); } }; LIBIMP_NAMESPACE_END_