#ifndef CORE_ITERATOR_HPP #define CORE_ITERATOR_HPP #include #include #include #include #include namespace core { inline namespace v2 { /* capacity */ template constexpr auto size (Container const& container) noexcept -> decltype( container.size() ) { return container.size(); } template constexpr ::std::size_t size (T const (&)[N]) noexcept { return N; } template constexpr bool empty (Container const& container) noexcept { return container.empty(); } template constexpr bool empty (T const (&)[N]) noexcept { return false; } /* element access */ template constexpr auto front (Container const& container) -> decltype( container.front() ) { return container.front(); } template constexpr auto front (Container& container) -> decltype(container.front()) { return container.front(); } template constexpr T const& front (T const (&array)[N]) noexcept { return array[0]; } template constexpr T& front (T (&array)[N]) noexcept { return array[0]; } template constexpr auto back (Container const& container) -> decltype( container.back() ) { return container.back(); } template constexpr auto back (Container& container) -> decltype(container.back()) { return container.back(); } template constexpr T const& back (T const (&array)[N]) noexcept { return array[N - 1]; } template constexpr T& back (T (&array)[N]) noexcept { return array[N - 1]; } /* data access */ template constexpr auto data (Container const& container) noexcept -> decltype( container.data() ) { return container.data(); } template constexpr auto data (Container& container) noexcept -> decltype( container.data() ) { return container.data(); } template constexpr T const* data (T const (&array)[N]) noexcept { return array; } template constexpr T* data (T (&array)[N]) noexcept { return array; } /* iteration */ template auto cbegin (Container const& container) -> decltype(::std::begin(container)) { return ::std::begin(container); } template auto cend (Container const& container) -> decltype(::std::end(container)) { return ::std::end(container); } template auto rbegin (Container const& container) -> decltype(container.rbegin()) { return container.rbegin(); } template auto rbegin (Container& container) -> decltype(container.rbegin()) { return container.rbegin(); } template auto crbegin (Container const& container) -> decltype(rbegin(container)) { return rbegin(container); } template auto rend (Container const& container) -> decltype(container.rend()) { return container.rend(); } template auto rend (Container& container) -> decltype(container.rend()) { return container.rend(); } template auto crend (Container const& container) -> decltype(rend(container)) { return rend(container); } template ::std::reverse_iterator make_reverse_iterator (Iterator iter) { return ::std::reverse_iterator(iter); } template < class DelimT, class CharT=char, class Traits=::std::char_traits > struct ostream_joiner final : ::std::iterator< ::std::output_iterator_tag, void, void, void, void > { using delimiter_type = DelimT; using ostream_type = ::std::basic_ostream; using traits_type = Traits; using char_type = CharT; ostream_joiner (ostream_type& stream, delimiter_type const& delimiter) : stream(stream), delimiter { delimiter } { } ostream_joiner (ostream_type& stream, delimiter_type&& delimiter) : stream(stream), delimiter { ::core::move(delimiter) }, first { true } { } template ostream_joiner& operator = (T const& item) { if (not first and delimiter) { this->stream << delimiter; } this->stream << item; this->first = false; return *this; } ostream_joiner& operator ++ (int) noexcept { return *this; } ostream_joiner& operator ++ () noexcept { return *this; } ostream_joiner& operator * () noexcept { return *this; } private: ostream_type& stream; delimiter_type delimiter; bool first; }; template struct number_iterator { using iterator_category = ::std::bidirectional_iterator_tag; using difference_type = T; using value_type = T; using reference = add_lvalue_reference_t; using pointer = add_pointer_t; static_assert(::std::is_integral::value, ""); explicit number_iterator (value_type value, value_type step=1) noexcept : value { value }, step { step } { } number_iterator (number_iterator const&) noexcept = default; number_iterator () noexcept = default; ~number_iterator () noexcept = default; number_iterator& operator = (number_iterator const&) noexcept = default; void swap (number_iterator& that) noexcept { ::std::swap(this->value, that.value); ::std::swap(this->step, that.step); } reference operator * () noexcept { return this->value; } number_iterator& operator ++ () noexcept { this->value += this->step; return *this; } number_iterator& operator -- () noexcept { this->value -= this->step; return *this; } number_iterator operator ++ (int) const noexcept { return number_iterator { this->value + this->step }; } number_iterator operator -- (int) const noexcept { return number_iterator { this->value - this->step }; } bool operator == (number_iterator const& that) const noexcept { return this->value == that.value and this->step == that.step; } bool operator != (number_iterator const& that) const noexcept { return this->value != that.value and this->step == that.step; } private: value_type value { }; value_type step { static_cast(1) }; }; template void swap (number_iterator& lhs, number_iterator& rhs) noexcept { lhs.swap(rhs); } template ostream_joiner, CharT, Traits> make_ostream_joiner ( ::std::basic_ostream& stream, DelimT&& delimiter ) { return ostream_joiner, CharT, Traits> { stream, ::core::forward(delimiter) }; } template number_iterator make_number_iterator (T value, T step) noexcept { return number_iterator { value, step }; } template number_iterator make_number_iterator (T value) noexcept { return number_iterator { value }; } }} /* namespace core::v2 */ #endif /* CORE_ITERATOR_HPP */