#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 #include #include namespace blt { 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); } }; 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} // NOLINT {} template()))>(*)[], T(*)[]>), bool> = true> constexpr span(std::array& arr) noexcept: size_(N), data_{arr.data()} // NOLINT {} template()))>(*)[], T(*)[]>), bool> = true> constexpr span(const std::array& arr) noexcept: size_(N), data_{arr.data()} // NOLINT {} 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)) // NOLINT {} template, bool> = true> explicit constexpr span(std::initializer_list il) noexcept: size_(il.size()), data_(&il.begin()) // NOLINT {} template, bool> = true> explicit span(std::initializer_list il) noexcept: size_(il.size()), data_(&il.begin()) // NOLINT {} 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()} // NOLINT {} constexpr span& operator=(const span& copy) { size_ = copy.size(); data_ = copy.data(); return *this; } 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