#pragma once /* * Created by Brett on 06/02/24. * Licensed under GNU General Public License V3.0 * See LICENSE file for license detail */ #ifndef BLT_RANGES_H #define BLT_RANGES_H #include #include #include #include #include #include namespace blt { namespace itr { template class itr_container { public: itr_container(Begin&& begin, End&& end): begin_(std::forward(begin)), end_(std::forward(end)) {} Begin begin() { return begin_; } End end() { return end_; } private: Begin begin_; End end_; }; template> class iterator; template class iterator { public: using iterator_category = std::input_iterator_tag; using value_type = typename TYPE_ITR::value_type; using difference_type = typename TYPE_ITR::difference_type; using pointer = typename TYPE_ITR::pointer; using reference = typename TYPE_ITR::reference; using const_reference = const typename TYPE_ITR::reference; private: blt::size_t index = 0; TYPE_ITR current; public: explicit iterator(TYPE_ITR current): current(std::move(current)) {} iterator& operator++() { ++index; ++current; return *this; } bool operator==(iterator other) const { return current == other.current; } bool operator!=(iterator other) const { return current != other.current; } std::pair operator*() const { return {index, *current}; }; std::pair operator*() { return {index, *current}; }; }; template class iterator { public: using iterator_category = std::input_iterator_tag; using value_type = std::remove_pointer_t; using difference_type = std::ptrdiff_t; using pointer = TYPE_ITR; using reference = std::remove_pointer_t&; using const_reference = const std::remove_pointer_t&; private: blt::size_t index = 0; TYPE_ITR current; public: explicit iterator(TYPE_ITR current): current(std::move(current)) {} iterator& operator++() { ++index; ++current; return *this; } bool operator==(iterator other) const { return current == other.current; } bool operator!=(iterator other) const { return current != other.current; } std::pair operator*() const { return {index, *current}; }; std::pair operator*() { return {index, *current}; }; }; } template class enumerator { public: explicit enumerator(TYPE_ITR begin, TYPE_ITR end): begin_(std::move(begin)), end_(std::move(end)) {} itr::iterator begin() { return begin_; } itr::iterator end() { return end_; } private: itr::iterator begin_; itr::iterator end_; }; template static inline auto enumerate(const T& container) { return enumerator{container.begin(), container.end()}; } template static inline auto enumerate(const T(&container)[size]) { return enumerator{&container[0], &container[size]}; } template static inline auto enumerate(T(&container)[size]) { return enumerator{&container[0], &container[size]}; } template static inline auto enumerate(T& container) { return enumerator{container.begin(), container.end()}; } template static inline auto enumerate(T&& container) { return enumerator{container.begin(), container.end()}; } template static inline auto iterate(Begin&& begin, End&& end) { return itr::itr_container{std::forward(begin), std::forward(end)}; } template struct range { public: struct range_itr { public: using iterator_category = std::bidirectional_iterator_tag; using difference_type = T; using value_type = T; using pointer = T*; using reference = T&; private: T current; bool forward; public: explicit range_itr(T current, bool forward): current(current), forward(forward) {} value_type operator*() const { return current; } value_type operator->() { return current; } range_itr& operator++() { if (forward) current++; else current--; return *this; } range_itr& operator--() { if (forward) current--; else current++; return *this; } friend bool operator==(const range_itr& a, const range_itr& b) { return a.current == b.current; } friend bool operator!=(const range_itr& a, const range_itr& b) { return a.current != b.current; } }; private: T _begin; T _end; T offset = 0; public: range(T begin, T end): _begin(begin), _end(end), offset(end < begin ? 1 : 0) {} range_itr begin() { return range_itr(_begin - offset, offset == 0); } range_itr end() { // not sure if i like this return range_itr(_end - offset, offset == 0); } }; template class itr_offset { private: I begin_; I end_; public: template itr_offset(I begin, I end, T offset): begin_(begin), end_(end) { for (T t = 0; t < offset; t++) ++begin_; } template itr_offset(C& container, T offset): begin_(container.begin()), end_(container.end()) { for (T t = 0; t < offset; t++) ++begin_; } auto begin() { return begin_; } auto end() { return end_; } }; template itr_offset(C, T) -> itr_offset; inline constexpr std::size_t dynamic_extent = std::numeric_limits::max(); 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: using element_type = T; using value_type = std::remove_cv_t; using size_type = blt::size_t; using difference_type = std::ptrdiff_t; using pointer = T*; 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) {} constexpr span(T* data, size_type count): size_(count), data_(data) {} 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>, typename 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>, typename 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