diff --git a/include/blt/std/ranges.h b/include/blt/std/ranges.h index 80c87c2..b45601f 100644 --- a/include/blt/std/ranges.h +++ b/include/blt/std/ranges.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -205,14 +206,69 @@ namespace blt return end_; } }; - + template itr_offset(C, T) -> itr_offset; - inline constexpr std::size_t dynamic_extent = std::numeric_limits::max(); - template + template + class span; + + // https://codereview.stackexchange.com/questions/217814/c17-span-implementation + namespace span_detail + { + // detect specializations of span + template + struct is_span : std::false_type + { + }; + + template + struct is_span> : std::true_type + { + }; + + template + inline constexpr bool is_span_v = is_span::value; + + // detect specializations of std::array + template + struct is_array : std::false_type + { + }; + + template + struct is_array> : std::true_type + { + }; + + template + inline constexpr bool is_array_v = is_array::value; + + // detect container + template + struct is_cont : std::false_type + { + }; + + template + struct is_cont>, + std::enable_if_t>, + std::enable_if_t>, + decltype(data(std::declval())), + decltype(size(std::declval())) + >> : std::true_type + { + }; + + template + inline constexpr bool is_cont_v = is_cont::value; + } + + template class span { public: @@ -224,11 +280,199 @@ namespace blt using const_pointer = const T*; using reference = T&; using const_reference = const T&; - + using iterator = T*; + using const_iterator = const T*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; private: - + size_type size_; + pointer* data_; public: + constexpr span() noexcept: size_(0), data_(nullptr) + {} + + template = true> + constexpr explicit span(It first, size_type count): size_(count), data_(&*first) + {} + + template = true> + constexpr span(It first, size_type count): size_(count), data_(&*first) + {} + + template = true> + constexpr explicit span(It first, End last): size_(&*last - &*first), data_(&*first) + {} + + template = true> + constexpr span(It first, End last): size_(&*last - &*first), data_(&*first) + {} + + template()))>(*)[], T(*)[]>), bool> = true> + constexpr span(element_type (& arr)[N]) noexcept: size_{N}, data_{arr} + {} + + template()))>(*)[], T(*)[]>), bool> = true> + constexpr span(std::array& arr) noexcept: size_(N), data_{arr.data()} + {} + + template()))>(*)[], T(*)[]>), bool> = true> + constexpr span(const std::array& arr) noexcept: size_(N), data_{arr.data()} + {} + + template>, std::enable_if_t< + extent != dynamic_extent && span_detail::is_cont_v && + std::is_convertible_v()))>(*)[], T(*)[]>, bool> = true> + explicit constexpr span(R&& range): size_(std::size(range)), data_(std::data(range)) + {} + + template>, std::enable_if_t< + extent == dynamic_extent && span_detail::is_cont_v && + std::is_convertible_v()))>(*)[], T(*)[]>, bool> = true> + constexpr span(R&& range): size_(std::size(range)), data_(std::data(range)) + {} + + template, bool> = true> + explicit constexpr span(std::initializer_list il) noexcept: size_(il.size()), data_(&il.begin()) + {} + + template, bool> = true> + explicit span(std::initializer_list il) noexcept: size_(il.size()), data_(&il.begin()) + {} + + template, bool> = true> + explicit constexpr span(const span& source) noexcept: size_{source.size()}, data_{source.data()} + {} + + template, bool> = true> + constexpr span(const span& source) noexcept: size_{source.size()}, data_{source.data()} + {} + + constexpr span(const span& other) noexcept = default; + + constexpr iterator begin() const noexcept + { + return data(); + } + + constexpr iterator end() const noexcept + { + return data() + size(); + } + + constexpr const_iterator cbegin() const noexcept + { + return data(); + } + + constexpr const_iterator cend() const noexcept + { + return data() + size(); + } + + constexpr reverse_iterator rbegin() const noexcept + { + return reverse_iterator{end()}; + } + + constexpr reverse_iterator rend() const noexcept + { + return reverse_iterator{begin()}; + } + + constexpr const_reverse_iterator crbegin() const noexcept + { + return reverse_iterator{cend()}; + } + + constexpr const_reverse_iterator crend() const noexcept + { + return reverse_iterator{cbegin()}; + } + + friend constexpr iterator begin(span s) noexcept + { + return s.begin(); + } + + friend constexpr iterator end(span s) noexcept + { + return s.end(); + } + + [[nodiscard]] constexpr size_type size() const noexcept + { + return size_; + } + + [[nodiscard]] constexpr size_type size_bytes() const noexcept + { + return size() * sizeof(T); + } + + [[nodiscard]] constexpr bool empty() const noexcept + { + return size() == 0; + } + + constexpr reference operator[](size_type idx) const + { + return *(data() + idx); + } + + constexpr reference front() const + { + return *data(); + } + + constexpr reference back() const + { + return *(data() + (size() - 1)); + } + + constexpr pointer data() const noexcept + { + return data_; + } + + constexpr span first(size_type cnt) const + { + return {data(), cnt}; + } + + constexpr span last(size_type cnt) const + { + return {data() + (size() - cnt), cnt}; + } + + constexpr span subspan(size_type off, size_type cnt = dynamic_extent) const + { + return {data() + off, cnt == dynamic_extent ? size() - off : cnt}; + } + }; + + template + span(T (&)[N]) -> span; + + template + span(std::array&) -> span; + + template + span(const std::array&) -> span; + + template + span(Cont&) -> span; + + template + span(const Cont&) -> span; } #endif //BLT_RANGES_H