#pragma once #include <util/generic/iterator_range.h> #include <util/generic/store_policy.h> #include <iterator> namespace NIteratorPrivate { template <class TIterator> constexpr bool HasRandomAccess() { return std::is_same_v<typename std::iterator_traits<TIterator>::iterator_category, std::random_access_iterator_tag>; } }; template <class TIterator, class TMapper> class TMappedIterator { protected: using TSelf = TMappedIterator<TIterator, TMapper>; using TSrcPointerType = typename std::iterator_traits<TIterator>::reference; using TValue = typename std::invoke_result_t<TMapper, TSrcPointerType>; public: using difference_type = std::ptrdiff_t; using value_type = TValue; using reference = TValue&; using pointer = std::remove_reference_t<TValue>*; using iterator_category = std::conditional_t<NIteratorPrivate::HasRandomAccess<TIterator>(), std::random_access_iterator_tag, std::input_iterator_tag>; TMappedIterator(TIterator it, TMapper mapper) : Iter(it) , Mapper(std::move(mapper)) { } TSelf& operator++() { ++Iter; return *this; } TSelf& operator--() { --Iter; return *this; } TValue operator*() { return Mapper((*Iter)); } TValue operator*() const { return Mapper((*Iter)); } pointer operator->() const { return &(Mapper((*Iter))); } TValue operator[](difference_type n) const { return Mapper(*(Iter + n)); } TSelf& operator+=(difference_type n) { Iter += n; return *this; } TSelf& operator-=(difference_type n) { Iter -= n; return *this; } TSelf operator+(difference_type n) const { return TSelf(Iter + n, Mapper); } TSelf operator-(difference_type n) const { return TSelf(Iter - n, Mapper); } difference_type operator-(const TSelf& other) const { return Iter - other.Iter; } bool operator==(const TSelf& other) const { return Iter == other.Iter; } bool operator!=(const TSelf& other) const { return Iter != other.Iter; } bool operator>(const TSelf& other) const { return Iter > other.Iter; } bool operator<(const TSelf& other) const { return Iter < other.Iter; } private: TIterator Iter; TMapper Mapper; }; template <class TContainer, class TMapper> class TInputMappedRange { protected: using TContainerStorage = TAutoEmbedOrPtrPolicy<TContainer>; using TMapperStorage = TAutoEmbedOrPtrPolicy<TMapper>; using TMapperWrapper = std::reference_wrapper<std::remove_reference_t<TMapper>>; using TInternalIterator = decltype(std::begin(std::declval<TContainer&>())); using TIterator = TMappedIterator<TInternalIterator, TMapperWrapper>; public: using iterator = TIterator; using const_iterator = TIterator; using value_type = typename TIterator::value_type; using reference = typename TIterator::reference; using const_reference = typename TIterator::reference; TInputMappedRange(TContainer&& container, TMapper&& mapper) : Container(std::forward<TContainer>(container)) , Mapper(std::forward<TMapper>(mapper)) { } TIterator begin() const { return {std::begin(*Container.Ptr()), {*Mapper.Ptr()}}; } TIterator end() const { return {std::end(*Container.Ptr()), {*Mapper.Ptr()}}; } bool empty() const { return std::begin(*Container.Ptr()) == std::end(*Container.Ptr()); } protected: mutable TContainerStorage Container; mutable TMapperStorage Mapper; }; template <class TContainer, class TMapper> class TRandomAccessMappedRange : public TInputMappedRange<TContainer, TMapper> { using TBase = TInputMappedRange<TContainer, TMapper>; using TInternalIterator = typename TBase::TInternalIterator; using TIterator = typename TBase::TIterator; public: using iterator = typename TBase::iterator; using const_iterator = typename TBase::const_iterator; using value_type = typename TBase::value_type; using reference = typename TBase::reference; using const_reference = typename TBase::const_reference; using difference_type = typename std::iterator_traits<iterator>::difference_type; using size_type = std::size_t; TRandomAccessMappedRange(TContainer&& container, TMapper&& mapper) : TBase(std::forward<TContainer>(container), std::forward<TMapper>(mapper)) { } using TBase::begin; using TBase::end; using TBase::empty; size_type size() const { return std::end(*this->Container.Ptr()) - std::begin(*this->Container.Ptr()); } const_reference operator[](size_t at) const { Y_ASSERT(at < this->size()); return *(this->begin() + at); } reference operator[](size_t at) { Y_ASSERT(at < this->size()); return *(this->begin() + at); } }; template <class TIterator, class TMapper> TMappedIterator<TIterator, TMapper> MakeMappedIterator(TIterator iter, TMapper mapper) { return {iter, mapper}; } template <class TIterator, class TMapper> auto MakeMappedRange(TIterator begin, TIterator end, TMapper mapper) { return MakeIteratorRange(MakeMappedIterator(begin, mapper), MakeMappedIterator(end, mapper)); } template <class TContainer, class TMapper> auto MakeMappedRange(TContainer&& container, TMapper&& mapper) { if constexpr (NIteratorPrivate::HasRandomAccess<decltype(std::begin(container))>()) { return TRandomAccessMappedRange<TContainer, TMapper>(std::forward<TContainer>(container), std::forward<TMapper>(mapper)); } else { return TInputMappedRange<TContainer, TMapper>(std::forward<TContainer>(container), std::forward<TMapper>(mapper)); } }