diff --git a/include/libimp/span.h b/include/libimp/span.h new file mode 100644 index 0000000..93d5f3d --- /dev/null +++ b/include/libimp/span.h @@ -0,0 +1,180 @@ +/** + * @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_ diff --git a/test/test_imp_span.cpp b/test/test_imp_span.cpp new file mode 100644 index 0000000..b432e3d --- /dev/null +++ b/test/test_imp_span.cpp @@ -0,0 +1,7 @@ + +#include "gtest/gtest.h" + +#include "libimp/span.h" + +TEST(span, span) { +} \ No newline at end of file