#ifndef FLOATING_ARRAY_H_INCLUDED_ #define FLOATING_ARRAY_H_INCLUDED_ #include #include #include struct origin_tag { std::ptrdiff_t value = 0; explicit operator ptrdiff_t() const { return value; } }; template using is_input_iterator = std::is_convertible::iterator_category>; template constexpr bool is_input_iterator_v = is_input_iterator::value; inline namespace fl_a { template > class floating_array : private std::deque { private: using BC = std::deque; public: /* Boilerplate stuff */ using value_type = typename BC::value_type; using allocator_type = typename BC::allocator_type; using size_type = typename BC::size_type; using index_type = std::ptrdiff_t; using difference_type = typename BC::difference_type; using reference = typename BC::reference; using const_reference = typename BC::const_reference; using pointer = typename BC::pointer; using const_pointer = typename BC::const_pointer; using iterator = typename BC::iterator; using const_iterator = typename BC::const_iterator; using reverse_iterator = typename BC::reverse_iterator; using const_reverse_iterator = typename BC::const_reverse_iterator; floating_array() = default; explicit floating_array(const Allocator& alloc) : BC(alloc) {} floating_array(size_type count, const T& value = T(), const Allocator& alloc = Allocator()) : BC(count, value, alloc) {} explicit floating_array(size_type count, const Allocator& alloc = Allocator()) : BC(count, alloc) {} template >> floating_array(InputIt first, InputIt last, const Allocator& alloc = Allocator()) : BC(first, last, alloc) {} floating_array(const floating_array& other) = default; floating_array(const floating_array& other, const Allocator& alloc) : BC(static_cast(other), alloc) , offset(other.offset) {} floating_array(floating_array&& other) noexcept = default; floating_array(floating_array&& other, const Allocator& alloc) noexcept( noexcept(BC(static_cast(other), alloc))) : BC(static_cast(other), alloc) , offset(other.offset) {} floating_array(std::initializer_list init, const Allocator& alloc = Allocator()) : BC(init, alloc) {} explicit floating_array(origin_tag o, const Allocator& alloc = Allocator()) : BC(alloc) , offset(o) {} floating_array(origin_tag o, size_type count, const T& value = T(), const Allocator& alloc = Allocator()) : BC(count, value, alloc) , offset(o) {} template >> floating_array(origin_tag o, InputIt first, InputIt last, const Allocator& alloc = Allocator()) : BC(first, last, alloc) , offset(o) {} floating_array(origin_tag o, std::initializer_list init, const Allocator& alloc = Allocator()) : BC(init, alloc) , offset(o) {} auto operator=(const floating_array& other) -> floating_array& = default; auto operator=(floating_array&& other) noexcept( std::allocator_traits::is_always_equal::value) -> floating_array& = default; auto operator=(std::initializer_list ilist) -> floating_array& { BC::operator=(ilist); offset = 0; return *this; } auto assign(size_type count, const T& value) -> void { BC::assign(count, value); offset = 0; } template >> auto assign(InputIt first, InputIt last) -> void { BC::assign(first, last); offset = 0; } auto assign(std::initializer_list ilist) -> void { BC::assign(ilist); offset = 0; return; } auto assign(origin_tag o, size_type count, const T& value) -> void { BC::assign(count, value); offset = o.value; } template >> auto assign(origin_tag o, InputIt first, InputIt last) -> void { BC::assign(first, last); offset = o.value; } auto assign(origin_tag o, std::initializer_list ilist) -> void { BC::assign(ilist); offset = o.value; return; } using BC::get_allocator; [[nodiscard]] auto at(index_type i) -> reference { return BC::at(i - offset); } [[nodiscard]] auto at(index_type i) const -> const_reference { return BC::at(i - offset); } [[nodiscard]] auto operator[](index_type i) noexcept -> reference { return BC::operator[](i - offset); } [[nodiscard]] auto operator[](index_type i) const noexcept -> const_reference { return BC::operator[](i - offset); } using BC::back; using BC::front; using BC::begin; using BC::cbegin; using BC::cend; using BC::crbegin; using BC::crend; using BC::end; using BC::rbegin; using BC::rend; // If the range spans zero, returns an iterator to [0]. // Otherwise, returns end() [[nodiscard]] auto zero() noexcept -> iterator { if (low() < 0 and high() > 0) { return begin() - low(); } return end(); } [[nodiscard]] auto zero() const noexcept -> const_iterator { if (low() < 0 and high() > 0) { return begin() - low(); } return end(); } [[nodiscard]] auto czero() const noexcept -> const_iterator { return zero(); } [[nodiscard]] auto rzero() noexcept -> reverse_iterator { return reverse_iterator(zero()); } [[nodiscard]] auto rzero() const noexcept -> const_reverse_iterator { return const_reverse_iterator(zero()); } [[nodiscard]] auto crzero() const noexcept -> const_reverse_iterator { return rzero(); } using BC::empty; using BC::max_size; using BC::shrink_to_fit; using BC::size; [[nodiscard]] auto high() const noexcept -> index_type { return size() + offset; } [[nodiscard]] auto low() const noexcept -> index_type { return offset; } auto clear() noexcept -> void { BC::clear(); offset = 0; } // no insert, emplace, or erase using BC::emplace_back; using BC::pop_back; using BC::push_back; auto push_front(const T& value) -> void { BC::push_front(value); --offset; } auto push_front(T&& value) -> void { BC::push_front(value); --offset; } template auto emplace_front(Args&&... args) -> reference { BC::emplace_front(std::forward(args)...); --offset; } auto pop_front() -> void { BC::pop_front(); ++offset; } auto swap(floating_array& other) noexcept( std::allocator_traits::is_always_equal::value) -> void { using std::swap; swap(static_cast(*this), static_cast(other)); swap(offset, other.offset); } [[nodiscard]] friend bool operator==(const floating_array& lhs, const floating_array& rhs) { return (lhs.low() == rhs.low()) and (static_cast&>(lhs) == static_cast&>(rhs)); } ~floating_array() = default; private: difference_type offset{0}; }; template [[nodiscard]] bool operator!=(const floating_array& lhs, const floating_array& rhs) { return not (lhs == rhs); } template [[nodiscard]] bool operator<(const floating_array& lhs, const floating_array& rhs) { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } template [[nodiscard]] bool operator<=(const floating_array& lhs, const floating_array& rhs) { return (lhs == rhs) or std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } template [[nodiscard]] bool operator>(const floating_array& lhs, const floating_array& rhs) { return std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end()); } template [[nodiscard]] bool operator>=(const floating_array& lhs, const floating_array& rhs) { return (lhs == rhs) or std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end()); } template auto swap(floating_array& lhs, floating_array& rhs) -> void { lhs.swap(rhs); } } // namespace fl_a #endif // FLOATING_ARRAY_H_INCLUDED_