diff options
| author | pechatnov <[email protected]> | 2022-02-10 16:48:57 +0300 | 
|---|---|---|
| committer | Daniil Cherednik <[email protected]> | 2022-02-10 16:48:57 +0300 | 
| commit | 132a3640fac343164b858d0a914e020a848a2848 (patch) | |
| tree | 5d5cb817648f650d76cf1076100726fd9b8448e8 /library/cpp | |
| parent | 8e9b2f8bbf4a2320f539eef5b85555f42c065425 (diff) | |
Restoring authorship annotation for <[email protected]>. Commit 2 of 2.
Diffstat (limited to 'library/cpp')
24 files changed, 1306 insertions, 1306 deletions
diff --git a/library/cpp/iterator/README.md b/library/cpp/iterator/README.md index 77f0c29b925..cd92a284c9a 100644 --- a/library/cpp/iterator/README.md +++ b/library/cpp/iterator/README.md @@ -1,100 +1,100 @@ -# Functools library  -  -Эта библиотека предоставляет функции `Enumerate`, `Zip`, `Map`, `Filter`, `Concatenate` и `CartesianProduct`.  -  -`Enumerate`, `Zip`, `Map`, `Filter` повторяют логику одноименных функций из python.  -  -Важный момент:  - * Итераторы данных view почти во всех случаях (кроме Map, там зависит от маппера) возвращают `std::tuple` **по значению** (при этом шаблонные параметры всегда, когда это уместно, ссылки).   -   <br> Так что нет никакого смысла делать `for (const auto& [i, x] : Enumerate(c))`.   -   <br> Лучше всегда `for (auto [i, x] : Enumerate(c))` (`x` в этом случае будет ссылкой и работать с ним можно как со ссылкой) или `for (const auto [i, x] : Enumerate(c))`.  -  -Предоставляемые гарантии:  - * Работа для всех контейнеров, для которых работает range-based for (для `Enumerate`, `Zip`, `Concatenate`, `CartesianProduct`).  -   Для `Map` и `Filter` есть требование на то, что первый и последний итераторы контейнера имеют один тип  - * В том числе работает для обычных массивов (`int a[] = {1, 2, 3}; Enumerate(a)`).  - * Поддержка rvalue для контейнеров, предикатов и функций-мапперов (`Filter([](auto x){...}, TVector{1, 2, 3})`).  -   В этом случае объекты сохраняются внутри view.  - * Проброс элементов контейнеров по неконстантной ссылке  - * `TView::iterator` - можно полагаться, что этот тип есть и корректен  - * `TIterator::iterator_category` - можно полагаться, что этот тип есть и определен.  -  -  -На что гарантий нет:  - * Любые изменения контейнеров, меняющие размер или инвалидирующие их итераторы, инвалидируют созданные view  - * Не принимает списки инициализации (`Enumerate({1, 2, 3})`), так как неизвестен желаемый тип контейнера.  - * В классах реализации оставлены публичные члены вида `.Field_`, чтобы не загромождать реализацию  -   Тем не менее эти поля не гарантированы, могут стать приватными или исчезнуть  - * Для всех итераторов определены вложенные типы: `value_type`, `pointer`, `reference`.  -   Тем не менее не рекомендуется их использовать в связи с их неоднозначностью.  -   `value_type` может быть как обычным типом, так и ссылкой. Может быть `std::tuple<T1, T2>`,  -   а может `std::tuple<T1&, const T2&>`.  -   Если возникает необходимость в этих типах, то возможно, стоит упростить код и вообще не использовать эти view.  -   Если очень хочется можно использовать `delctype(*container.begin())`.  -  -  -Производительность:  - * Бенчмарки времени компиляции и скорости выполнения, а так же сравнение с range-v3 и другими существующими реализациями  -   доступны в [репозитории где ведется разработка](https://github.com/yuri-pechatnov/cpp_functools/tree/master "functools").  -  -  -  -Q: Оверхед?  -A: По выполнению: на Enumerate, Zip, Map - нулевой. Где-то x1.5 на Filter, и x3 на Concatenate и CartesianProduct. Но если в теле цикла происходит хоть что-то существенное, то это пренебрежимо мало.  -   По компиляции: сложно рассчитать как оно скажется в реальном большом проекте, но приблизительно не более x1.5 на один цикл.  -  -Q: А зачем свой велосипед?  -A: ((https://pechatnov.at.yandex-team.ru/67 Ответ в этом посте)).  -  -Q: А почему вот здесь плохо написано, надо же по-другому?  -A: Код несколько раз переписывался и согласовывался ((https://st.yandex-team.ru/IGNIETFERRO-973 более полугода)). А допиливать его внутреннюю реализацию после коммита никто не мешает и дальше.  -  -  -Сигнатуры и эквиваленты:  -  -  -```cpp  -//! In all comments variables ending with '_'  -//! are considered as invisible for {...} block.  -  -//! Usage: for (auto [i, x] : Enumerate(container)) {...}  -//! Equivalent: { std::size_t i_ = 0; for (auto& x : container) { const std::size_t i = i_; {...}; ++i_; }}  -template <typename TContainerOrRef>  -auto Enumerate(TContainerOrRef&& container);  -  -//! Usage: for (auto x : Map(mapperFunc, container)) {...}  -//! Equivalent: for (auto iter_ = std::begin(container); iter_ != std::end(container); ++iter_) {  -//!                 auto x = mapperFunc(*iter_); {...}; }  -template <typename TMapper, typename TContainerOrRef>  -auto Map(TMapper&& mapper, TContainerOrRef&& container);  -  -//! Usage: for (auto x : Filter(predicate, container)) {...}  -//! Equivalent: for (auto x : container) { if (predicate(x)) {...}}  -template <typename TPredicate, typename TContainerOrRef>  -auto Filter(TPredicate&& predicate, TContainerOrRef&& container);  -  -//! Usage: for (auto [ai, bi] : Zip(a, b)) {...}  -//! Equivalent: { auto ia_ = std::begin(a); auto ib_ = std::begin(b);  -//!               for (; ia_ != std::end(a) && ib_ != std::end(b); ++ia_, ++ib_) {  -//!                   auto&& ai = *ia_; auto&& bi = *ib_; {...}  -//!               }}  -template <typename... TContainers>  -auto Zip(TContainers&&... containers);  -  -//! Usage: for (auto x : Reversed(container)) {...}  -//! Equivalent: for (auto iter_ = std::rbegin(container); iter_ != std::rend(container); ++iter_) {  -//!                 auto x = *iter_; {...}}  -template <typename TContainerOrRef>  -auto Reversed(TContainerOrRef&& container);  -  -//! Usage: for (auto x : Concatenate(a, b)) {...}  -//! Equivalent: { for (auto x : a) {...} for (auto x : b) {...} }  -//! (if there is no static variables in {...})  -template <typename TFirstContainer, typename... TContainers>  -auto Concatenate(TFirstContainer&& container, TContainers&&... containers);  -  -//! Usage: for (auto [ai, bi] : CartesianProduct(a, b)) {...}  -//! Equivalent: for (auto& ai : a) { for (auto& bi : b) {...} }  -template <typename... TContainers>  -auto CartesianProduct(TContainers&&... containers);  -```  +# Functools library + +Эта библиотека предоставляет функции `Enumerate`, `Zip`, `Map`, `Filter`, `Concatenate` и `CartesianProduct`. + +`Enumerate`, `Zip`, `Map`, `Filter` повторяют логику одноименных функций из python. + +Важный момент: + * Итераторы данных view почти во всех случаях (кроме Map, там зависит от маппера) возвращают `std::tuple` **по значению** (при этом шаблонные параметры всегда, когда это уместно, ссылки).  +   <br> Так что нет никакого смысла делать `for (const auto& [i, x] : Enumerate(c))`.  +   <br> Лучше всегда `for (auto [i, x] : Enumerate(c))` (`x` в этом случае будет ссылкой и работать с ним можно как со ссылкой) или `for (const auto [i, x] : Enumerate(c))`. + +Предоставляемые гарантии: + * Работа для всех контейнеров, для которых работает range-based for (для `Enumerate`, `Zip`, `Concatenate`, `CartesianProduct`). +   Для `Map` и `Filter` есть требование на то, что первый и последний итераторы контейнера имеют один тип + * В том числе работает для обычных массивов (`int a[] = {1, 2, 3}; Enumerate(a)`). + * Поддержка rvalue для контейнеров, предикатов и функций-мапперов (`Filter([](auto x){...}, TVector{1, 2, 3})`). +   В этом случае объекты сохраняются внутри view. + * Проброс элементов контейнеров по неконстантной ссылке + * `TView::iterator` - можно полагаться, что этот тип есть и корректен + * `TIterator::iterator_category` - можно полагаться, что этот тип есть и определен. + + +На что гарантий нет: + * Любые изменения контейнеров, меняющие размер или инвалидирующие их итераторы, инвалидируют созданные view + * Не принимает списки инициализации (`Enumerate({1, 2, 3})`), так как неизвестен желаемый тип контейнера. + * В классах реализации оставлены публичные члены вида `.Field_`, чтобы не загромождать реализацию +   Тем не менее эти поля не гарантированы, могут стать приватными или исчезнуть + * Для всех итераторов определены вложенные типы: `value_type`, `pointer`, `reference`. +   Тем не менее не рекомендуется их использовать в связи с их неоднозначностью. +   `value_type` может быть как обычным типом, так и ссылкой. Может быть `std::tuple<T1, T2>`, +   а может `std::tuple<T1&, const T2&>`. +   Если возникает необходимость в этих типах, то возможно, стоит упростить код и вообще не использовать эти view. +   Если очень хочется можно использовать `delctype(*container.begin())`. + + +Производительность: + * Бенчмарки времени компиляции и скорости выполнения, а так же сравнение с range-v3 и другими существующими реализациями +   доступны в [репозитории где ведется разработка](https://github.com/yuri-pechatnov/cpp_functools/tree/master "functools"). + + + +Q: Оверхед? +A: По выполнению: на Enumerate, Zip, Map - нулевой. Где-то x1.5 на Filter, и x3 на Concatenate и CartesianProduct. Но если в теле цикла происходит хоть что-то существенное, то это пренебрежимо мало. +   По компиляции: сложно рассчитать как оно скажется в реальном большом проекте, но приблизительно не более x1.5 на один цикл. + +Q: А зачем свой велосипед? +A: ((https://pechatnov.at.yandex-team.ru/67 Ответ в этом посте)). + +Q: А почему вот здесь плохо написано, надо же по-другому? +A: Код несколько раз переписывался и согласовывался ((https://st.yandex-team.ru/IGNIETFERRO-973 более полугода)). А допиливать его внутреннюю реализацию после коммита никто не мешает и дальше. + + +Сигнатуры и эквиваленты: + + +```cpp +//! In all comments variables ending with '_' +//! are considered as invisible for {...} block. + +//! Usage: for (auto [i, x] : Enumerate(container)) {...} +//! Equivalent: { std::size_t i_ = 0; for (auto& x : container) { const std::size_t i = i_; {...}; ++i_; }} +template <typename TContainerOrRef> +auto Enumerate(TContainerOrRef&& container); + +//! Usage: for (auto x : Map(mapperFunc, container)) {...} +//! Equivalent: for (auto iter_ = std::begin(container); iter_ != std::end(container); ++iter_) { +//!                 auto x = mapperFunc(*iter_); {...}; } +template <typename TMapper, typename TContainerOrRef> +auto Map(TMapper&& mapper, TContainerOrRef&& container); + +//! Usage: for (auto x : Filter(predicate, container)) {...} +//! Equivalent: for (auto x : container) { if (predicate(x)) {...}} +template <typename TPredicate, typename TContainerOrRef> +auto Filter(TPredicate&& predicate, TContainerOrRef&& container); + +//! Usage: for (auto [ai, bi] : Zip(a, b)) {...} +//! Equivalent: { auto ia_ = std::begin(a); auto ib_ = std::begin(b); +//!               for (; ia_ != std::end(a) && ib_ != std::end(b); ++ia_, ++ib_) { +//!                   auto&& ai = *ia_; auto&& bi = *ib_; {...} +//!               }} +template <typename... TContainers> +auto Zip(TContainers&&... containers); + +//! Usage: for (auto x : Reversed(container)) {...} +//! Equivalent: for (auto iter_ = std::rbegin(container); iter_ != std::rend(container); ++iter_) { +//!                 auto x = *iter_; {...}} +template <typename TContainerOrRef> +auto Reversed(TContainerOrRef&& container); + +//! Usage: for (auto x : Concatenate(a, b)) {...} +//! Equivalent: { for (auto x : a) {...} for (auto x : b) {...} } +//! (if there is no static variables in {...}) +template <typename TFirstContainer, typename... TContainers> +auto Concatenate(TFirstContainer&& container, TContainers&&... containers); + +//! Usage: for (auto [ai, bi] : CartesianProduct(a, b)) {...} +//! Equivalent: for (auto& ai : a) { for (auto& bi : b) {...} } +template <typename... TContainers> +auto CartesianProduct(TContainers&&... containers); +``` diff --git a/library/cpp/iterator/cartesian_product.cpp b/library/cpp/iterator/cartesian_product.cpp index 40c5391134e..c3ebfdcc33e 100644 --- a/library/cpp/iterator/cartesian_product.cpp +++ b/library/cpp/iterator/cartesian_product.cpp @@ -1 +1 @@ -#include "cartesian_product.h"  +#include "cartesian_product.h" diff --git a/library/cpp/iterator/cartesian_product.h b/library/cpp/iterator/cartesian_product.h index afeced99959..3ef70339a2c 100644 --- a/library/cpp/iterator/cartesian_product.h +++ b/library/cpp/iterator/cartesian_product.h @@ -1,115 +1,115 @@ -#pragma once  -  -#include <util/generic/store_policy.h>  -  -#include <tuple>  -  -  -namespace NPrivate {  -  -    template <typename... TContainers>  -    struct TCartesianMultiplier {  -        template <std::size_t... I>  -        struct TCartesianMultiplierWithIndex {  -        private:  -            using THolders = std::tuple<TAutoEmbedOrPtrPolicy<TContainers>...>;  -            using TValue = std::tuple<decltype(*std::begin(std::declval<TContainers&>()))...>;  -            using TIteratorState = std::tuple<int, decltype(std::begin(std::declval<TContainers&>()))...>;  -            using TSentinelState = std::tuple<int, decltype(std::end(std::declval<TContainers&>()))...>;  -  -            struct TIterator;  -            struct TSentinelCandidate {  -                TSentinelState Iterators_;  -                THolders* HoldersPtr_;  -            };  -            using TSentinel = std::conditional_t<std::is_same_v<TIteratorState, TSentinelState>,  -                                                 TIterator, TSentinelCandidate>;  -  -            struct TIterator {  -            private:  -                //! Return value is true when iteration is not finished  -                template <std::size_t position = sizeof...(TContainers)>  -                void IncrementIteratorsTuple() {  -                    auto& currentIterator = std::get<position>(Iterators_);  -                    ++currentIterator;  -  -                    if (currentIterator != std::end(*std::get<position - 1>(*HoldersPtr_).Ptr())) {  -                        return;  -                    } else {  -                        currentIterator = std::begin(*std::get<position - 1>(*HoldersPtr_).Ptr());  -                        if constexpr (position != 1) {  -                            IncrementIteratorsTuple<position - 1>();  -                        } else {  -                            std::get<0>(Iterators_) = 1;  -                        }  -                    }  -                }  -            public:  -                using difference_type = std::ptrdiff_t;  -                using value_type = TValue;  -                using pointer = TValue*;  -                using reference = TValue&;  -                using iterator_category = std::input_iterator_tag;  -  -                TValue operator*() {  -                    return {*std::get<I + 1>(Iterators_)...};  -                }  -                TValue operator*() const {  -                    return {*std::get<I + 1>(Iterators_)...};  -                }  -                void operator++() {  -                    IncrementIteratorsTuple();  -                }  -                bool operator!=(const TSentinel& other) const {  -                    // not finished iterator VS sentinel (most frequent case)  -                    if (std::get<0>(Iterators_) != std::get<0>(other.Iterators_)) {  -                        return true;  -                    }  -                    // do not compare sentinels and finished iterators  -                    if (std::get<0>(other.Iterators_)) {  -                        return false;  -                    }  -                    // compare not finished iterators  -                    return ((std::get<I + 1>(Iterators_) != std::get<I + 1>(other.Iterators_)) || ...);  -                }  -                bool operator==(const TSentinel& other) const {  -                    return !(*this != other);  -                }  -  -                TIteratorState Iterators_;  -                THolders* HoldersPtr_;  -            };  -        public:  -            using iterator = TIterator;  -            using const_iterator = TIterator;  +#pragma once + +#include <util/generic/store_policy.h> + +#include <tuple> + + +namespace NPrivate { + +    template <typename... TContainers> +    struct TCartesianMultiplier { +        template <std::size_t... I> +        struct TCartesianMultiplierWithIndex { +        private: +            using THolders = std::tuple<TAutoEmbedOrPtrPolicy<TContainers>...>; +            using TValue = std::tuple<decltype(*std::begin(std::declval<TContainers&>()))...>; +            using TIteratorState = std::tuple<int, decltype(std::begin(std::declval<TContainers&>()))...>; +            using TSentinelState = std::tuple<int, decltype(std::end(std::declval<TContainers&>()))...>; + +            struct TIterator; +            struct TSentinelCandidate { +                TSentinelState Iterators_; +                THolders* HoldersPtr_; +            }; +            using TSentinel = std::conditional_t<std::is_same_v<TIteratorState, TSentinelState>, +                                                 TIterator, TSentinelCandidate>; + +            struct TIterator { +            private: +                //! Return value is true when iteration is not finished +                template <std::size_t position = sizeof...(TContainers)> +                void IncrementIteratorsTuple() { +                    auto& currentIterator = std::get<position>(Iterators_); +                    ++currentIterator; + +                    if (currentIterator != std::end(*std::get<position - 1>(*HoldersPtr_).Ptr())) { +                        return; +                    } else { +                        currentIterator = std::begin(*std::get<position - 1>(*HoldersPtr_).Ptr()); +                        if constexpr (position != 1) { +                            IncrementIteratorsTuple<position - 1>(); +                        } else { +                            std::get<0>(Iterators_) = 1; +                        } +                    } +                } +            public: +                using difference_type = std::ptrdiff_t; +                using value_type = TValue; +                using pointer = TValue*; +                using reference = TValue&; +                using iterator_category = std::input_iterator_tag; + +                TValue operator*() { +                    return {*std::get<I + 1>(Iterators_)...}; +                } +                TValue operator*() const { +                    return {*std::get<I + 1>(Iterators_)...}; +                } +                void operator++() { +                    IncrementIteratorsTuple(); +                } +                bool operator!=(const TSentinel& other) const { +                    // not finished iterator VS sentinel (most frequent case) +                    if (std::get<0>(Iterators_) != std::get<0>(other.Iterators_)) { +                        return true; +                    } +                    // do not compare sentinels and finished iterators +                    if (std::get<0>(other.Iterators_)) { +                        return false; +                    } +                    // compare not finished iterators +                    return ((std::get<I + 1>(Iterators_) != std::get<I + 1>(other.Iterators_)) || ...); +                } +                bool operator==(const TSentinel& other) const { +                    return !(*this != other); +                } + +                TIteratorState Iterators_; +                THolders* HoldersPtr_; +            }; +        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; -  -            TIterator begin() const {  -                bool isEmpty = !((std::begin(*std::get<I>(Holders_).Ptr()) != std::end(*std::get<I>(Holders_).Ptr())) && ...);  -                return {TIteratorState{int(isEmpty), std::begin(*std::get<I>(Holders_).Ptr())...}, &Holders_};  -            }  -  -            TSentinel end() const {  -                return {TSentinelState{1, std::end(*std::get<I>(Holders_).Ptr())...}, &Holders_};  -            }  -  -            mutable THolders Holders_;  -        };  -  -        template <std::size_t... I>  -        static auto CartesianMultiply(TContainers&&... containers, std::index_sequence<I...>) {  -            return TCartesianMultiplierWithIndex<I...>{{std::forward<TContainers>(containers)...}};  -        }  -    };  -  -}  -  -//! Usage: for (auto [ai, bi] : CartesianProduct(a, b)) {...}  -//! Equivalent: for (auto& ai : a) { for (auto& bi : b) {...} }  -template <typename... TContainers>  -auto CartesianProduct(TContainers&&... containers) {  -    return NPrivate::TCartesianMultiplier<TContainers...>::CartesianMultiply(  -        std::forward<TContainers>(containers)..., std::make_index_sequence<sizeof...(TContainers)>{});  -}  + +            TIterator begin() const { +                bool isEmpty = !((std::begin(*std::get<I>(Holders_).Ptr()) != std::end(*std::get<I>(Holders_).Ptr())) && ...); +                return {TIteratorState{int(isEmpty), std::begin(*std::get<I>(Holders_).Ptr())...}, &Holders_}; +            } + +            TSentinel end() const { +                return {TSentinelState{1, std::end(*std::get<I>(Holders_).Ptr())...}, &Holders_}; +            } + +            mutable THolders Holders_; +        }; + +        template <std::size_t... I> +        static auto CartesianMultiply(TContainers&&... containers, std::index_sequence<I...>) { +            return TCartesianMultiplierWithIndex<I...>{{std::forward<TContainers>(containers)...}}; +        } +    }; + +} + +//! Usage: for (auto [ai, bi] : CartesianProduct(a, b)) {...} +//! Equivalent: for (auto& ai : a) { for (auto& bi : b) {...} } +template <typename... TContainers> +auto CartesianProduct(TContainers&&... containers) { +    return NPrivate::TCartesianMultiplier<TContainers...>::CartesianMultiply( +        std::forward<TContainers>(containers)..., std::make_index_sequence<sizeof...(TContainers)>{}); +} diff --git a/library/cpp/iterator/concatenate.cpp b/library/cpp/iterator/concatenate.cpp index 1657b4246ca..4ca8e2e82d9 100644 --- a/library/cpp/iterator/concatenate.cpp +++ b/library/cpp/iterator/concatenate.cpp @@ -1 +1 @@ -#include "concatenate.h"  +#include "concatenate.h" diff --git a/library/cpp/iterator/concatenate.h b/library/cpp/iterator/concatenate.h index fe7e802aa02..64d2cd451a3 100644 --- a/library/cpp/iterator/concatenate.h +++ b/library/cpp/iterator/concatenate.h @@ -1,136 +1,136 @@ -#pragma once  -  -#include <util/generic/store_policy.h>  -  -#include <iterator>  -#include <tuple>  -  -  -namespace NPrivate {  -  -    template <typename TValue_, typename... TContainers>  -    struct TConcatenator {  -        template <std::size_t... I>  -        struct TConcatenatorWithIndex {  -        private:  -            using THolders = std::tuple<TAutoEmbedOrPtrPolicy<TContainers>...>;  -            using TValue = TValue_;  -            using TIteratorState = std::tuple<decltype(std::begin(std::declval<TContainers&>()))...>;  -            using TSentinelState = std::tuple<decltype(std::end(std::declval<TContainers&>()))...>;  -  -            struct TIterator;  -            struct TSentinelCandidate {  -                TSentinelState Iterators_;  -                std::size_t Position_;  -                THolders* HoldersPtr_;  -            };  -            using TSentinel = std::conditional_t<std::is_same_v<TIteratorState, TSentinelState>,  -                                                 TIterator, TSentinelCandidate>;  -  -            struct TIterator {  -            private:  -                friend struct TConcatenatorWithIndex<I...>;  -  -                // important, that it is a static function, compiler better optimizes such code  -                template <std::size_t index = 0, typename TMaybeConstIteratorState>  -                static TValue GetCurrentValue(std::size_t position, TMaybeConstIteratorState& iterators) {  -                    if constexpr (index >= sizeof...(TContainers)) {  -                        // never happened when use of iterator is correct  -                        return *std::get<0>(iterators);  -                    } else {  -                        if (position == index) {  -                            return *std::get<index>(iterators);  -                        } else {  -                            return GetCurrentValue<index + 1>(position, iterators);  -                        }  -                    }  -                }  -  -                template <bool needIncrement, std::size_t index = 0>  -                void MaybeIncrementIteratorAndSkipExhaustedContainers() {  -                    if constexpr (index >= sizeof...(TContainers)) {  -                        return;  -                    } else {  -                        if (Position_ == index) {  -                            if constexpr (needIncrement) {  -                                ++std::get<index>(Iterators_);  -                            }  -                            if (!(std::get<index>(Iterators_) != std::end(*std::get<index>(*HoldersPtr_).Ptr()))) {  -                                ++Position_;  -                                MaybeIncrementIteratorAndSkipExhaustedContainers<false, index + 1>();  -                            }  -                        } else {  -                            MaybeIncrementIteratorAndSkipExhaustedContainers<needIncrement, index + 1>();  -                        }  -                    }  -                }  -            public:  -                using difference_type = std::ptrdiff_t;  -                using value_type = TValue;  -                using pointer = std::remove_reference_t<TValue>*;  -                using reference = std::remove_reference_t<TValue>&;  -                using iterator_category = std::input_iterator_tag;  -  -                TValue operator*() {  -                    return GetCurrentValue(Position_, Iterators_);  -                }  -                TValue operator*() const {  -                    return GetCurrentValue(Position_, Iterators_);  -                }  +#pragma once + +#include <util/generic/store_policy.h> + +#include <iterator> +#include <tuple> + + +namespace NPrivate { + +    template <typename TValue_, typename... TContainers> +    struct TConcatenator { +        template <std::size_t... I> +        struct TConcatenatorWithIndex { +        private: +            using THolders = std::tuple<TAutoEmbedOrPtrPolicy<TContainers>...>; +            using TValue = TValue_; +            using TIteratorState = std::tuple<decltype(std::begin(std::declval<TContainers&>()))...>; +            using TSentinelState = std::tuple<decltype(std::end(std::declval<TContainers&>()))...>; + +            struct TIterator; +            struct TSentinelCandidate { +                TSentinelState Iterators_; +                std::size_t Position_; +                THolders* HoldersPtr_; +            }; +            using TSentinel = std::conditional_t<std::is_same_v<TIteratorState, TSentinelState>, +                                                 TIterator, TSentinelCandidate>; + +            struct TIterator { +            private: +                friend struct TConcatenatorWithIndex<I...>; + +                // important, that it is a static function, compiler better optimizes such code +                template <std::size_t index = 0, typename TMaybeConstIteratorState> +                static TValue GetCurrentValue(std::size_t position, TMaybeConstIteratorState& iterators) { +                    if constexpr (index >= sizeof...(TContainers)) { +                        // never happened when use of iterator is correct +                        return *std::get<0>(iterators); +                    } else { +                        if (position == index) { +                            return *std::get<index>(iterators); +                        } else { +                            return GetCurrentValue<index + 1>(position, iterators); +                        } +                    } +                } + +                template <bool needIncrement, std::size_t index = 0> +                void MaybeIncrementIteratorAndSkipExhaustedContainers() { +                    if constexpr (index >= sizeof...(TContainers)) { +                        return; +                    } else { +                        if (Position_ == index) { +                            if constexpr (needIncrement) { +                                ++std::get<index>(Iterators_); +                            } +                            if (!(std::get<index>(Iterators_) != std::end(*std::get<index>(*HoldersPtr_).Ptr()))) { +                                ++Position_; +                                MaybeIncrementIteratorAndSkipExhaustedContainers<false, index + 1>(); +                            } +                        } else { +                            MaybeIncrementIteratorAndSkipExhaustedContainers<needIncrement, index + 1>(); +                        } +                    } +                } +            public: +                using difference_type = std::ptrdiff_t; +                using value_type = TValue; +                using pointer = std::remove_reference_t<TValue>*; +                using reference = std::remove_reference_t<TValue>&; +                using iterator_category = std::input_iterator_tag; + +                TValue operator*() { +                    return GetCurrentValue(Position_, Iterators_); +                } +                TValue operator*() const { +                    return GetCurrentValue(Position_, Iterators_); +                }                  TIterator& operator++() { -                    MaybeIncrementIteratorAndSkipExhaustedContainers<true>();  +                    MaybeIncrementIteratorAndSkipExhaustedContainers<true>();                      return *this; -                }  -                bool operator!=(const TSentinel& other) const {  -                    // give compiler an opportunity to optimize sentinel case (-70% of time)  -                    if (other.Position_ == sizeof...(TContainers)) {  -                        return Position_ < sizeof...(TContainers);  -                    } else {  -                        return (Position_ != other.Position_ ||  -                                ((std::get<I>(Iterators_) != std::get<I>(other.Iterators_)) || ...));  -                    }  -                }  -                bool operator==(const TSentinel& other) const {  -                    return !(*this != other);  -                }  -  -                TIteratorState Iterators_;  -                std::size_t Position_;  -                THolders* HoldersPtr_;  -            };  -        public:  -            using iterator = TIterator;  -            using const_iterator = TIterator;  +                } +                bool operator!=(const TSentinel& other) const { +                    // give compiler an opportunity to optimize sentinel case (-70% of time) +                    if (other.Position_ == sizeof...(TContainers)) { +                        return Position_ < sizeof...(TContainers); +                    } else { +                        return (Position_ != other.Position_ || +                                ((std::get<I>(Iterators_) != std::get<I>(other.Iterators_)) || ...)); +                    } +                } +                bool operator==(const TSentinel& other) const { +                    return !(*this != other); +                } + +                TIteratorState Iterators_; +                std::size_t Position_; +                THolders* HoldersPtr_; +            }; +        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; -  -            TIterator begin() const {  -                TIterator iterator{TIteratorState{std::begin(*std::get<I>(Holders_).Ptr())...}, 0, &Holders_};  -                iterator.template MaybeIncrementIteratorAndSkipExhaustedContainers<false>();  -                return iterator;  -            }  -  -            TSentinel end() const {  -                return {TSentinelState{std::end(*std::get<I>(Holders_).Ptr())...}, sizeof...(TContainers), &Holders_};  -            }  -  -            mutable THolders Holders_;  -        };  -  -        template <std::size_t... I>  -        static auto Concatenate(TContainers&&... containers, std::index_sequence<I...>) {  -            return TConcatenatorWithIndex<I...>{{std::forward<TContainers>(containers)...}};  -        }  -    };  -  -}  -  -  -//! Usage: for (auto x : Concatenate(a, b)) {...}  -template <typename TFirstContainer, typename... TContainers>  -auto Concatenate(TFirstContainer&& container, TContainers&&... containers) {  -    return NPrivate::TConcatenator<decltype(*std::begin(container)), TFirstContainer, TContainers...>::Concatenate(  -        std::forward<TFirstContainer>(container), std::forward<TContainers>(containers)...,  -        std::make_index_sequence<sizeof...(TContainers) + 1>{});  -}  + +            TIterator begin() const { +                TIterator iterator{TIteratorState{std::begin(*std::get<I>(Holders_).Ptr())...}, 0, &Holders_}; +                iterator.template MaybeIncrementIteratorAndSkipExhaustedContainers<false>(); +                return iterator; +            } + +            TSentinel end() const { +                return {TSentinelState{std::end(*std::get<I>(Holders_).Ptr())...}, sizeof...(TContainers), &Holders_}; +            } + +            mutable THolders Holders_; +        }; + +        template <std::size_t... I> +        static auto Concatenate(TContainers&&... containers, std::index_sequence<I...>) { +            return TConcatenatorWithIndex<I...>{{std::forward<TContainers>(containers)...}}; +        } +    }; + +} + + +//! Usage: for (auto x : Concatenate(a, b)) {...} +template <typename TFirstContainer, typename... TContainers> +auto Concatenate(TFirstContainer&& container, TContainers&&... containers) { +    return NPrivate::TConcatenator<decltype(*std::begin(container)), TFirstContainer, TContainers...>::Concatenate( +        std::forward<TFirstContainer>(container), std::forward<TContainers>(containers)..., +        std::make_index_sequence<sizeof...(TContainers) + 1>{}); +} diff --git a/library/cpp/iterator/enumerate.cpp b/library/cpp/iterator/enumerate.cpp index 4118a67e857..b195f0b31df 100644 --- a/library/cpp/iterator/enumerate.cpp +++ b/library/cpp/iterator/enumerate.cpp @@ -1 +1 @@ -#include "enumerate.h"  +#include "enumerate.h" diff --git a/library/cpp/iterator/enumerate.h b/library/cpp/iterator/enumerate.h index 21eae25f39f..2c83fb41bfc 100644 --- a/library/cpp/iterator/enumerate.h +++ b/library/cpp/iterator/enumerate.h @@ -1,82 +1,82 @@ -#pragma once  -  -#include <util/generic/store_policy.h>  -  -#include <limits>  -#include <tuple>  -  -  -namespace NPrivate {  -  -    template <typename TContainer>  -    struct TEnumerator {  -    private:  -        using TStorage = TAutoEmbedOrPtrPolicy<TContainer>;  -        using TValue = std::tuple<const std::size_t, decltype(*std::begin(std::declval<TContainer&>()))>;  -        using TIteratorState = decltype(std::begin(std::declval<TContainer&>()));  -        using TSentinelState = decltype(std::end(std::declval<TContainer&>()));  -  -        static constexpr bool TrivialSentinel = std::is_same_v<TIteratorState, TSentinelState>;  -  -        struct TIterator;  -        struct TSentinelCandidate {  -            TSentinelState Iterator_;  -        };  -        using TSentinel = std::conditional_t<TrivialSentinel, TIterator, TSentinelCandidate>;  -  -        struct TIterator {  -            using difference_type = std::ptrdiff_t;  -            using value_type = TValue;  -            using pointer = TValue*;  -            using reference = TValue&;  -            using iterator_category = std::input_iterator_tag;  -  -            TValue operator*() {  -                return {Index_, *Iterator_};  -            }  -            TValue operator*() const {  -                return {Index_, *Iterator_};  -            }  -            void operator++() {  -                ++Index_;  -                ++Iterator_;  -            }  -            bool operator!=(const TSentinel& other) const {  -                return Iterator_ != other.Iterator_;  -            }  -            bool operator==(const TSentinel& other) const {  -                return Iterator_ == other.Iterator_;  -            }  -  -            std::size_t Index_;  -            TIteratorState Iterator_;  -        };  -    public:  -        using iterator = TIterator;  -        using const_iterator = TIterator;  +#pragma once + +#include <util/generic/store_policy.h> + +#include <limits> +#include <tuple> + + +namespace NPrivate { + +    template <typename TContainer> +    struct TEnumerator { +    private: +        using TStorage = TAutoEmbedOrPtrPolicy<TContainer>; +        using TValue = std::tuple<const std::size_t, decltype(*std::begin(std::declval<TContainer&>()))>; +        using TIteratorState = decltype(std::begin(std::declval<TContainer&>())); +        using TSentinelState = decltype(std::end(std::declval<TContainer&>())); + +        static constexpr bool TrivialSentinel = std::is_same_v<TIteratorState, TSentinelState>; + +        struct TIterator; +        struct TSentinelCandidate { +            TSentinelState Iterator_; +        }; +        using TSentinel = std::conditional_t<TrivialSentinel, TIterator, TSentinelCandidate>; + +        struct TIterator { +            using difference_type = std::ptrdiff_t; +            using value_type = TValue; +            using pointer = TValue*; +            using reference = TValue&; +            using iterator_category = std::input_iterator_tag; + +            TValue operator*() { +                return {Index_, *Iterator_}; +            } +            TValue operator*() const { +                return {Index_, *Iterator_}; +            } +            void operator++() { +                ++Index_; +                ++Iterator_; +            } +            bool operator!=(const TSentinel& other) const { +                return Iterator_ != other.Iterator_; +            } +            bool operator==(const TSentinel& other) const { +                return Iterator_ == other.Iterator_; +            } + +            std::size_t Index_; +            TIteratorState Iterator_; +        }; +    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; -  -        TIterator begin() const {  -            return {0, std::begin(*Storage_.Ptr())};  -        }  -  -        TSentinel end() const {  -            if constexpr (TrivialSentinel) {  -                return TIterator{std::numeric_limits<std::size_t>::max(), std::end(*Storage_.Ptr())};  -            } else {  -                return TSentinel{std::end(*Storage_.Ptr())};  -            }  -        }  -  -        mutable TStorage Storage_;  -    };  -  -}  -  -//! Usage: for (auto [i, x] : Enumerate(container)) {...}  -template <typename TContainerOrRef>  -auto Enumerate(TContainerOrRef&& container) {  -    return NPrivate::TEnumerator<TContainerOrRef>{std::forward<TContainerOrRef>(container)};  -}  + +        TIterator begin() const { +            return {0, std::begin(*Storage_.Ptr())}; +        } + +        TSentinel end() const { +            if constexpr (TrivialSentinel) { +                return TIterator{std::numeric_limits<std::size_t>::max(), std::end(*Storage_.Ptr())}; +            } else { +                return TSentinel{std::end(*Storage_.Ptr())}; +            } +        } + +        mutable TStorage Storage_; +    }; + +} + +//! Usage: for (auto [i, x] : Enumerate(container)) {...} +template <typename TContainerOrRef> +auto Enumerate(TContainerOrRef&& container) { +    return NPrivate::TEnumerator<TContainerOrRef>{std::forward<TContainerOrRef>(container)}; +} diff --git a/library/cpp/iterator/filtering.cpp b/library/cpp/iterator/filtering.cpp index c27612502c8..8e1542f61b6 100644 --- a/library/cpp/iterator/filtering.cpp +++ b/library/cpp/iterator/filtering.cpp @@ -1 +1 @@ -#include "filtering.h"  +#include "filtering.h" diff --git a/library/cpp/iterator/filtering.h b/library/cpp/iterator/filtering.h index 69099c2b702..c28e3bc6c44 100644 --- a/library/cpp/iterator/filtering.h +++ b/library/cpp/iterator/filtering.h @@ -1,10 +1,10 @@  #pragma once -#include <util/generic/iterator_range.h>  -#include <util/generic/store_policy.h>  +#include <util/generic/iterator_range.h> +#include <util/generic/store_policy.h>  #include <iterator> -  +  template <class TIterator, class TCondition>  class TFilteringIterator {  public: @@ -19,7 +19,7 @@ public:      TFilteringIterator(TIterator it, TIterator last, const TCondition& condition)          : Iter(it)          , Last(last) -        , Condition(condition)  +        , Condition(condition)      {          Grep();      } @@ -56,47 +56,47 @@ private:      TCondition Condition;  }; -  -template <class TContainer, class TCondition>  -class TFilteringRange {  -    using TContainerStorage = TAutoEmbedOrPtrPolicy<TContainer>;  -    using TConditionStorage = TAutoEmbedOrPtrPolicy<TCondition>;  -    using TRawIterator = decltype(std::begin(std::declval<TContainer&>()));  -    using TConditionWrapper = std::reference_wrapper<std::remove_reference_t<TCondition>>;  -public:  + +template <class TContainer, class TCondition> +class TFilteringRange { +    using TContainerStorage = TAutoEmbedOrPtrPolicy<TContainer>; +    using TConditionStorage = TAutoEmbedOrPtrPolicy<TCondition>; +    using TRawIterator = decltype(std::begin(std::declval<TContainer&>())); +    using TConditionWrapper = std::reference_wrapper<std::remove_reference_t<TCondition>>; +public:      //TODO: make TIterator typedef private -    using TIterator = TFilteringIterator<TRawIterator, TConditionWrapper>;  +    using TIterator = TFilteringIterator<TRawIterator, TConditionWrapper>; -    using iterator = TIterator;  -    using const_iterator = TIterator;  +    using iterator = TIterator; +    using const_iterator = TIterator;      using value_type = typename TIterator::value_type;      using reference = typename TIterator::reference; -  -    TFilteringRange(TContainer&& container, TCondition&& predicate)  -        : Container(std::forward<TContainer>(container))  -        , Condition(std::forward<TCondition>(predicate))  -    {}  -  -    TIterator begin() const {  -        return {std::begin(*Container.Ptr()), std::end(*Container.Ptr()), {*Condition.Ptr()}};  -    }  -  -    TIterator end() const {  -        return {std::end(*Container.Ptr()), std::end(*Container.Ptr()), {*Condition.Ptr()}};  -    }  -  -private:  -    mutable TContainerStorage Container;  -    mutable TConditionStorage Condition;  -};  -  -  + +    TFilteringRange(TContainer&& container, TCondition&& predicate) +        : Container(std::forward<TContainer>(container)) +        , Condition(std::forward<TCondition>(predicate)) +    {} + +    TIterator begin() const { +        return {std::begin(*Container.Ptr()), std::end(*Container.Ptr()), {*Condition.Ptr()}}; +    } + +    TIterator end() const { +        return {std::end(*Container.Ptr()), std::end(*Container.Ptr()), {*Condition.Ptr()}}; +    } + +private: +    mutable TContainerStorage Container; +    mutable TConditionStorage Condition; +}; + +  template <class TIterator, class TCondition>  auto MakeFilteringRange(TIterator begin, TIterator end, const TCondition& condition) {      return MakeIteratorRange(TFilteringIterator<TIterator, TCondition>(begin, end, condition), TFilteringIterator<TIterator, TCondition>(end, end, condition));  }  template <class TContainer, class TCondition> -auto MakeFilteringRange(TContainer&& container, TCondition&& condition) {  -    return TFilteringRange<TContainer, TCondition>(std::forward<TContainer>(container), std::forward<TCondition>(condition));  +auto MakeFilteringRange(TContainer&& container, TCondition&& condition) { +    return TFilteringRange<TContainer, TCondition>(std::forward<TContainer>(container), std::forward<TCondition>(condition));  } diff --git a/library/cpp/iterator/functools.cpp b/library/cpp/iterator/functools.cpp index e63845acb62..da2d0757ceb 100644 --- a/library/cpp/iterator/functools.cpp +++ b/library/cpp/iterator/functools.cpp @@ -1 +1 @@ -#include "functools.h"  +#include "functools.h" diff --git a/library/cpp/iterator/functools.h b/library/cpp/iterator/functools.h index 3a2548292c9..57a0d663734 100644 --- a/library/cpp/iterator/functools.h +++ b/library/cpp/iterator/functools.h @@ -1,57 +1,57 @@ -#pragma once  -  -#include "cartesian_product.h"  -#include "concatenate.h"  -#include "enumerate.h"  -#include "filtering.h"  -#include "mapped.h"  -#include "zip.h"  -  -#include <util/generic/adaptor.h>  -#include <util/generic/xrange.h>  -  -#include <tuple>  -#include <algorithm>  -  -  -namespace NFuncTools {  -    using ::Enumerate;  -    using ::Reversed;  -    using ::Zip;  -    using ::Concatenate;  -    using ::CartesianProduct;  -  -    template <typename TValue>  -    auto Range(TValue from, TValue to, TValue step) {  -        return xrange(from, to, step);  -    }  -  -    template <typename TValue>  -    auto Range(TValue from, TValue to) {  -        return xrange(from, to);  -    }  -  -    template <typename TValue>  -    auto Range(TValue to) {  -        return xrange(to);  -    }  -  -    //! Usage: for (i32 x : Map([](i32 x) { return x * x; }, a)) {...}  -    template <typename TMapper, typename TContainerOrRef>  -    auto Map(TMapper&& mapper, TContainerOrRef&& container) {  -        return ::MakeMappedRange(std::forward<TContainerOrRef>(container), std::forward<TMapper>(mapper));  -    }  -  -    //! Usage: for (auto i : Map<int>(floats)) {...}  -    template <typename TMapResult, typename TContainerOrRef>  -    auto Map(TContainerOrRef&& container) {  -        return Map([](const auto& x) { return TMapResult(x); }, std::forward<TContainerOrRef>(container));  -    }  -  -    //! Usage: for (i32 x : Filter(predicate, container)) {...}  -    template <typename TPredicate, typename TContainerOrRef>  -    auto Filter(TPredicate&& predicate, TContainerOrRef&& container) {  -        return ::MakeFilteringRange(std::forward<TContainerOrRef>(container), std::forward<TPredicate>(predicate));  -    }  -  -}  +#pragma once + +#include "cartesian_product.h" +#include "concatenate.h" +#include "enumerate.h" +#include "filtering.h" +#include "mapped.h" +#include "zip.h" + +#include <util/generic/adaptor.h> +#include <util/generic/xrange.h> + +#include <tuple> +#include <algorithm> + + +namespace NFuncTools { +    using ::Enumerate; +    using ::Reversed; +    using ::Zip; +    using ::Concatenate; +    using ::CartesianProduct; + +    template <typename TValue> +    auto Range(TValue from, TValue to, TValue step) { +        return xrange(from, to, step); +    } + +    template <typename TValue> +    auto Range(TValue from, TValue to) { +        return xrange(from, to); +    } + +    template <typename TValue> +    auto Range(TValue to) { +        return xrange(to); +    } + +    //! Usage: for (i32 x : Map([](i32 x) { return x * x; }, a)) {...} +    template <typename TMapper, typename TContainerOrRef> +    auto Map(TMapper&& mapper, TContainerOrRef&& container) { +        return ::MakeMappedRange(std::forward<TContainerOrRef>(container), std::forward<TMapper>(mapper)); +    } + +    //! Usage: for (auto i : Map<int>(floats)) {...} +    template <typename TMapResult, typename TContainerOrRef> +    auto Map(TContainerOrRef&& container) { +        return Map([](const auto& x) { return TMapResult(x); }, std::forward<TContainerOrRef>(container)); +    } + +    //! Usage: for (i32 x : Filter(predicate, container)) {...} +    template <typename TPredicate, typename TContainerOrRef> +    auto Filter(TPredicate&& predicate, TContainerOrRef&& container) { +        return ::MakeFilteringRange(std::forward<TContainerOrRef>(container), std::forward<TPredicate>(predicate)); +    } + +} diff --git a/library/cpp/iterator/mapped.cpp b/library/cpp/iterator/mapped.cpp index 201f95f10ef..047f38c58f7 100644 --- a/library/cpp/iterator/mapped.cpp +++ b/library/cpp/iterator/mapped.cpp @@ -1 +1 @@ -#include "mapped.h"  +#include "mapped.h" diff --git a/library/cpp/iterator/mapped.h b/library/cpp/iterator/mapped.h index 486efd0899b..6c5e7631847 100644 --- a/library/cpp/iterator/mapped.h +++ b/library/cpp/iterator/mapped.h @@ -1,33 +1,33 @@  #pragma once  #include <util/generic/iterator_range.h> -#include <util/generic/store_policy.h>  +#include <util/generic/store_policy.h> + +#include <iterator> + -#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> +    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:  +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>;  +        std::random_access_iterator_tag, std::input_iterator_tag>;      TMappedIterator(TIterator it, TMapper mapper)          : Iter(it) @@ -43,9 +43,9 @@ public:          --Iter;          return *this;      } -    TValue operator*() {  -        return Mapper((*Iter));  -    }  +    TValue operator*() { +        return Mapper((*Iter)); +    }      TValue operator*() const {          return Mapper((*Iter));      } @@ -92,13 +92,13 @@ private:      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>>;  +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: @@ -108,68 +108,68 @@ public:      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))  +    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()}};  +        return {std::begin(*Container.Ptr()), {*Mapper.Ptr()}};      }      TIterator end() const { -        return {std::end(*Container.Ptr()), {*Mapper.Ptr()}};  +        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;  -};  +protected: +    mutable TContainerStorage Container; +    mutable TMapperStorage Mapper; +}; + -  -template <class TContainer, class TMapper>  -class TRandomAccessMappedRange : public TInputMappedRange<TContainer, TMapper> {  -    using TBase = TInputMappedRange<TContainer, TMapper>;  +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;  +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());  +        return std::end(*this->Container.Ptr()) - std::begin(*this->Container.Ptr());      }      const_reference operator[](size_t at) const { -        Y_ASSERT(at < this->size());  +        Y_ASSERT(at < this->size()); -        return *(this->begin() + at);  +        return *(this->begin() + at);      }      reference operator[](size_t at) { -        Y_ASSERT(at < this->size());  +        Y_ASSERT(at < this->size()); -        return *(this->begin() + at);  +        return *(this->begin() + at);      }  }; @@ -184,10 +184,10 @@ auto MakeMappedRange(TIterator begin, TIterator end, TMapper mapper) {  }  template <class TContainer, class TMapper> -auto MakeMappedRange(TContainer&& container, TMapper&& mapper) {  +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));  -    }  +        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)); +    }  } diff --git a/library/cpp/iterator/ut/functools_ut.cpp b/library/cpp/iterator/ut/functools_ut.cpp index cd39158bd2c..2dee9a55c85 100644 --- a/library/cpp/iterator/ut/functools_ut.cpp +++ b/library/cpp/iterator/ut/functools_ut.cpp @@ -1,603 +1,603 @@  #include <library/cpp/iterator/functools.h> -  +  #include <library/cpp/testing/gtest/gtest.h> -  -#include <util/generic/vector.h>  -#include <util/generic/xrange.h>  -#include <util/generic/adaptor.h>  -  -#include <set>  -  -// default-win-x86_64-release compiler can't decompose tuple to structure binding (02.03.2019)  -#ifndef _WINDOWS  -#   define FOR_DISPATCH_2(i, j, r) \  -        for (auto [i, j] : r)  -#   define FOR_DISPATCH_3(i, j, k, r) \  -        for (auto [i, j, k] : r)  -#else  -#   define FOR_DISPATCH_2(i, j, r) \  -        for (auto __t_##i##_##j : r) \  -            if (auto& i = std::get<0>(__t_##i##_##j); true) \  -                if (auto& j = std::get<1>(__t_##i##_##j); true)  -#   define FOR_DISPATCH_3(i, j, k, r) \  -        for (auto __t_##i##_##j##_##k : r) \  -            if (auto& i = std::get<0>(__t_##i##_##j##_##k); true) \  -                if (auto& j = std::get<1>(__t_##i##_##j##_##k); true) \  -                    if (auto& k = std::get<2>(__t_##i##_##j##_##k); true)  -#endif  -  -using namespace NFuncTools;  -  -  -    template <typename TContainer>  -    auto ToVector(TContainer&& container) {  -        return std::vector{container.begin(), container.end()};  -    }  -  -    template <typename TContainerObjOrRef>  -    void TestViewCompileability(TContainerObjOrRef&& container) {  -        using TContainer = std::decay_t<TContainerObjOrRef>;  -        using TIterator = typename TContainer::iterator;  -  -        static_assert(std::is_same_v<decltype(container.begin()), TIterator>);  -  -        // iterator_traits must work!  -        using difference_type = typename std::iterator_traits<TIterator>::difference_type;  -        using value_type = typename std::iterator_traits<TIterator>::value_type;  -        using reference = typename std::iterator_traits<TIterator>::reference;  -        using pointer = typename std::iterator_traits<TIterator>::pointer;  -  -        {  -            // operator assignment  -            auto it = container.begin();  -            it = container.end();  -            it = std::move(container.begin());  -            // operator copying  -            auto it2 = it;  -            Y_UNUSED(it2);  -            auto it3 = std::move(it);  -            Y_UNUSED(it3);  -            Y_UNUSED(*it3);  + +#include <util/generic/vector.h> +#include <util/generic/xrange.h> +#include <util/generic/adaptor.h> + +#include <set> + +// default-win-x86_64-release compiler can't decompose tuple to structure binding (02.03.2019) +#ifndef _WINDOWS +#   define FOR_DISPATCH_2(i, j, r) \ +        for (auto [i, j] : r) +#   define FOR_DISPATCH_3(i, j, k, r) \ +        for (auto [i, j, k] : r) +#else +#   define FOR_DISPATCH_2(i, j, r) \ +        for (auto __t_##i##_##j : r) \ +            if (auto& i = std::get<0>(__t_##i##_##j); true) \ +                if (auto& j = std::get<1>(__t_##i##_##j); true) +#   define FOR_DISPATCH_3(i, j, k, r) \ +        for (auto __t_##i##_##j##_##k : r) \ +            if (auto& i = std::get<0>(__t_##i##_##j##_##k); true) \ +                if (auto& j = std::get<1>(__t_##i##_##j##_##k); true) \ +                    if (auto& k = std::get<2>(__t_##i##_##j##_##k); true) +#endif + +using namespace NFuncTools; + + +    template <typename TContainer> +    auto ToVector(TContainer&& container) { +        return std::vector{container.begin(), container.end()}; +    } + +    template <typename TContainerObjOrRef> +    void TestViewCompileability(TContainerObjOrRef&& container) { +        using TContainer = std::decay_t<TContainerObjOrRef>; +        using TIterator = typename TContainer::iterator; + +        static_assert(std::is_same_v<decltype(container.begin()), TIterator>); + +        // iterator_traits must work! +        using difference_type = typename std::iterator_traits<TIterator>::difference_type; +        using value_type = typename std::iterator_traits<TIterator>::value_type; +        using reference = typename std::iterator_traits<TIterator>::reference; +        using pointer = typename std::iterator_traits<TIterator>::pointer; + +        { +            // operator assignment +            auto it = container.begin(); +            it = container.end(); +            it = std::move(container.begin()); +            // operator copying +            auto it2 = it; +            Y_UNUSED(it2); +            auto it3 = std::move(it); +            Y_UNUSED(it3); +            Y_UNUSED(*it3);              EXPECT_TRUE(it3 == it3);              EXPECT_FALSE(it3 != it3); -            // const TIterator  -            const auto it4 = it3;  -            Y_UNUSED(*it4);  +            // const TIterator +            const auto it4 = it3; +            Y_UNUSED(*it4);              EXPECT_TRUE(it4 == it4);              EXPECT_FALSE(it4 != it4);              EXPECT_TRUE(it3 == it4);              EXPECT_TRUE(it4 == it3);              EXPECT_FALSE(it3 != it4);              EXPECT_FALSE(it4 != it3); -        }  -  -        auto it = container.begin();  -  -        // sanity check for types  -        using TConstReference = const std::remove_reference_t<reference>&;  -        TConstReference ref = *it;  -        Y_UNUSED(ref);  -        (void) static_cast<value_type>(*it);  -        (void) static_cast<difference_type>(1);  -        if constexpr (std::is_reference_v<decltype(*it)>) {  -            pointer ptr = &*it;  -            Y_UNUSED(ptr);  -        }  -  -        // std compatibility  -        ToVector(container);  -  -        // const iterators  -        [](const auto& cont) {  -            auto constBeginIterator = cont.begin();  -            auto constEndIterator = cont.end();  -            static_assert(std::is_same_v<decltype(constBeginIterator), typename TContainer::const_iterator>);  -            Y_UNUSED(constBeginIterator);  -            Y_UNUSED(constEndIterator);  -        }(container);  -    }  -  -    struct TTestSentinel {};  -    struct TTestIterator {  -        int operator*() {  -            return X;  -        }  -        void operator++() {  -            ++X;  -        }  -        bool operator!=(const TTestSentinel&) const {  -            return X < 3;  -        }  -  -        int X;  -    };  -  -    // container with minimal interface  -    auto MakeMinimalisticContainer() {  -        return MakeIteratorRange(TTestIterator{}, TTestSentinel{});  -    }  -  -  +        } + +        auto it = container.begin(); + +        // sanity check for types +        using TConstReference = const std::remove_reference_t<reference>&; +        TConstReference ref = *it; +        Y_UNUSED(ref); +        (void) static_cast<value_type>(*it); +        (void) static_cast<difference_type>(1); +        if constexpr (std::is_reference_v<decltype(*it)>) { +            pointer ptr = &*it; +            Y_UNUSED(ptr); +        } + +        // std compatibility +        ToVector(container); + +        // const iterators +        [](const auto& cont) { +            auto constBeginIterator = cont.begin(); +            auto constEndIterator = cont.end(); +            static_assert(std::is_same_v<decltype(constBeginIterator), typename TContainer::const_iterator>); +            Y_UNUSED(constBeginIterator); +            Y_UNUSED(constEndIterator); +        }(container); +    } + +    struct TTestSentinel {}; +    struct TTestIterator { +        int operator*() { +            return X; +        } +        void operator++() { +            ++X; +        } +        bool operator!=(const TTestSentinel&) const { +            return X < 3; +        } + +        int X; +    }; + +    // container with minimal interface +    auto MakeMinimalisticContainer() { +        return MakeIteratorRange(TTestIterator{}, TTestSentinel{}); +    } + +      TEST(FuncTools, CompileRange) { -        TestViewCompileability(Range(19));  -        TestViewCompileability(Range(10, 19));  -        TestViewCompileability(Range(10, 19, 2));  -    }  -  -  +        TestViewCompileability(Range(19)); +        TestViewCompileability(Range(10, 19)); +        TestViewCompileability(Range(10, 19, 2)); +    } + +      TEST(FuncTools, Enumerate) {          TVector<size_t> a = {1, 2, 4};          TVector<size_t> b;          TVector<size_t> c = {1}; -        for (auto& v : {a, b, c}) {  +        for (auto& v : {a, b, c}) {              size_t j = 0; -            FOR_DISPATCH_2(i, x, Enumerate(v)) {  +            FOR_DISPATCH_2(i, x, Enumerate(v)) {                  EXPECT_EQ(v[i], x);                  EXPECT_EQ(i, j++);                  EXPECT_LT(i, v.size()); -            }  +            }              EXPECT_EQ(j, v.size()); -        }  -  +        } +          TVector<size_t> d = {0, 0, 0}; -        FOR_DISPATCH_2(i, x, Enumerate(d)) {  -            x = i;  -        }  +        FOR_DISPATCH_2(i, x, Enumerate(d)) { +            x = i; +        }          EXPECT_THAT(              d,              testing::ElementsAre(0u, 1u, 2u)          ); -    }  -  +    } +      TEST(FuncTools, EnumerateTemporary) {          TVector<size_t> a = {1, 2, 4};          TVector<size_t> b;          TVector<size_t> c = {1}; -        for (auto& v : {a, b, c}) {  +        for (auto& v : {a, b, c}) {              size_t j = 0; -            FOR_DISPATCH_2(i, x, Enumerate(TVector(v))) {  +            FOR_DISPATCH_2(i, x, Enumerate(TVector(v))) {                  EXPECT_EQ(v[i], x);                  EXPECT_EQ(i, j++);                  EXPECT_LT(i, v.size()); -            }  +            }              EXPECT_EQ(j, v.size()); -        }  -  +        } +          FOR_DISPATCH_2(i, x, Enumerate(TVector<size_t>{1, 2, 3})) {              EXPECT_EQ(i + 1, x); -        }  -    }  -  +        } +    } +      TEST(FuncTools, CompileEnumerate) { -        auto container = std::vector{1, 2, 3};  -        TestViewCompileability(Enumerate(container));  -        const auto constContainer = std::vector{1, 2, 3};  -        TestViewCompileability(Enumerate(constContainer));  -        const int arrayContainer[] = {1, 2, 3};  -        TestViewCompileability(Enumerate(arrayContainer));  -  -        std::vector<std::pair<int, int>> res;  -        FOR_DISPATCH_2(i, x, Enumerate(MakeMinimalisticContainer())) {  -            res.push_back({i, x});  -        }  +        auto container = std::vector{1, 2, 3}; +        TestViewCompileability(Enumerate(container)); +        const auto constContainer = std::vector{1, 2, 3}; +        TestViewCompileability(Enumerate(constContainer)); +        const int arrayContainer[] = {1, 2, 3}; +        TestViewCompileability(Enumerate(arrayContainer)); + +        std::vector<std::pair<int, int>> res; +        FOR_DISPATCH_2(i, x, Enumerate(MakeMinimalisticContainer())) { +            res.push_back({i, x}); +        }          EXPECT_EQ(res, (std::vector<std::pair<int, int>>{ -            {0, 0}, {1, 1}, {2, 2},  -        }));  -    }  -  +            {0, 0}, {1, 1}, {2, 2}, +        })); +    } +      TEST(FuncTools, Zip) {          TVector<std::pair<TVector<size_t>, TVector<size_t>>> ts = { -            {{1, 2, 3}, {4, 5, 6}},  -            {{1, 2, 3}, {4, 5, 6, 7}},  -            {{1, 2, 3, 4}, {4, 5, 6}},  -            {{1, 2, 3, 4}, {}},  -        };  -  -        FOR_DISPATCH_2(a, b, ts) {  +            {{1, 2, 3}, {4, 5, 6}}, +            {{1, 2, 3}, {4, 5, 6, 7}}, +            {{1, 2, 3, 4}, {4, 5, 6}}, +            {{1, 2, 3, 4}, {}}, +        }; + +        FOR_DISPATCH_2(a, b, ts) {              size_t k = 0; -            FOR_DISPATCH_2(i, j, Zip(a, b)) {  +            FOR_DISPATCH_2(i, j, Zip(a, b)) {                  EXPECT_EQ(++k, i);                  EXPECT_EQ(i + 3, j); -            }  +            }              EXPECT_EQ(k, Min(a.size(), b.size())); -        }  -    }  -  +        } +    } +      TEST(FuncTools, ZipReference) { -        TVector a = {0, 1, 2};  -        TVector b = {2, 1, 0, -1};  -        FOR_DISPATCH_2(ai, bi, Zip(a, b)) {  -            ai = bi;  -        }  +        TVector a = {0, 1, 2}; +        TVector b = {2, 1, 0, -1}; +        FOR_DISPATCH_2(ai, bi, Zip(a, b)) { +            ai = bi; +        }          EXPECT_THAT(              a,              testing::ElementsAre(2u, 1u, 0u)          ); -    }  -  +    } +      TEST(FuncTools, Zip3) { -        TVector<std::tuple<TVector<i32>, TVector<i32>, TVector<i32>>> ts = {  -            {{1, 2, 3}, {4, 5, 6}, {11, 3}},  -            {{1, 2, 3}, {4, 5, 6, 7}, {9, 0}},  -            {{1, 2, 3, 4}, {9}, {4, 5, 6}},  -            {{1, 2, 3, 4}, {1}, {}},  -            {{}, {1}, {1, 2, 3, 4}},  -        };  -  -        FOR_DISPATCH_3(a, b, c, ts) {  -            TVector<std::tuple<i32, i32, i32>> e;  -            for (size_t j = 0; j < a.size() && j < b.size() && j < c.size(); ++j) {  -                e.push_back({a[j], b[j], c[j]});  -            }  -  -            TVector<std::tuple<i32, i32, i32>> f;  -            FOR_DISPATCH_3(ai, bi, ci, Zip(a, b, c)) {  -                f.push_back({ai, bi, ci});  -            }  -  +        TVector<std::tuple<TVector<i32>, TVector<i32>, TVector<i32>>> ts = { +            {{1, 2, 3}, {4, 5, 6}, {11, 3}}, +            {{1, 2, 3}, {4, 5, 6, 7}, {9, 0}}, +            {{1, 2, 3, 4}, {9}, {4, 5, 6}}, +            {{1, 2, 3, 4}, {1}, {}}, +            {{}, {1}, {1, 2, 3, 4}}, +        }; + +        FOR_DISPATCH_3(a, b, c, ts) { +            TVector<std::tuple<i32, i32, i32>> e; +            for (size_t j = 0; j < a.size() && j < b.size() && j < c.size(); ++j) { +                e.push_back({a[j], b[j], c[j]}); +            } + +            TVector<std::tuple<i32, i32, i32>> f; +            FOR_DISPATCH_3(ai, bi, ci, Zip(a, b, c)) { +                f.push_back({ai, bi, ci}); +            } +              EXPECT_EQ(e, f); -        }  -    }  -  +        } +    } +      TEST(FuncTools, CompileZip) { -        auto container = std::vector{1, 2, 3};  -        TestViewCompileability(Zip(container));  -        TestViewCompileability(Zip(container, container, container));  -        const auto constContainer = std::vector{1, 2, 3};  -        TestViewCompileability(Zip(constContainer, constContainer));  -        const int arrayContainer[] = {1, 2, 3};  -        TestViewCompileability(Zip(arrayContainer, arrayContainer));  -  -        std::vector<std::pair<int, int>> res;  -        FOR_DISPATCH_2(a, b, Zip(MakeMinimalisticContainer(), container)) {  -            res.push_back({a, b});  -        }  +        auto container = std::vector{1, 2, 3}; +        TestViewCompileability(Zip(container)); +        TestViewCompileability(Zip(container, container, container)); +        const auto constContainer = std::vector{1, 2, 3}; +        TestViewCompileability(Zip(constContainer, constContainer)); +        const int arrayContainer[] = {1, 2, 3}; +        TestViewCompileability(Zip(arrayContainer, arrayContainer)); + +        std::vector<std::pair<int, int>> res; +        FOR_DISPATCH_2(a, b, Zip(MakeMinimalisticContainer(), container)) { +            res.push_back({a, b}); +        }          EXPECT_EQ(res, (std::vector<std::pair<int, int>>{ -            {0, 1}, {1, 2}, {2, 3},  -        }));  -    }  -  +            {0, 1}, {1, 2}, {2, 3}, +        })); +    } +      TEST(FuncTools, Filter) { -        TVector<TVector<i32>> ts = {  -            {},  -            {1},  -            {2},  -            {1, 2},  -            {2, 1},  -            {1, 2, 3, 4, 5, 6, 7},  -        };  -  -        auto pred = [](i32 x) -> bool { return x & 1; };  -  -        for (auto& a : ts) {  -            TVector<i32> b;  -            for (i32 x : a) {  -                if (pred(x)) {  -                    b.push_back(x);  -                }  -            }  -  -            TVector<i32> c;  -            for (i32 x : Filter(pred, a)) {  -                c.push_back(x);  -            }  -  +        TVector<TVector<i32>> ts = { +            {}, +            {1}, +            {2}, +            {1, 2}, +            {2, 1}, +            {1, 2, 3, 4, 5, 6, 7}, +        }; + +        auto pred = [](i32 x) -> bool { return x & 1; }; + +        for (auto& a : ts) { +            TVector<i32> b; +            for (i32 x : a) { +                if (pred(x)) { +                    b.push_back(x); +                } +            } + +            TVector<i32> c; +            for (i32 x : Filter(pred, a)) { +                c.push_back(x); +            } +              EXPECT_EQ(b, c); -        }  -    }  -  +        } +    } +      TEST(FuncTools, CompileFilter) { -        auto container = std::vector{1, 2, 3};  -        auto isOdd = [](int x) { return bool(x & 1); };  -        TestViewCompileability(Filter(isOdd, container));  -        const int arrayContainer[] = {1, 2, 3};  -        TestViewCompileability(Filter(isOdd, arrayContainer));  -    }  -  +        auto container = std::vector{1, 2, 3}; +        auto isOdd = [](int x) { return bool(x & 1); }; +        TestViewCompileability(Filter(isOdd, container)); +        const int arrayContainer[] = {1, 2, 3}; +        TestViewCompileability(Filter(isOdd, arrayContainer)); +    } +      TEST(FuncTools, Map) { -        TVector<TVector<i32>> ts = {  -            {},  -            {1},  -            {1, 2},  -            {1, 2, 3, 4, 5, 6, 7},  -        };  -  -        auto f = [](i32 x) { return x * x; };  -  -        for (auto& a : ts) {  -            TVector<i32> b;  -            for (i32 x : a) {  -                b.push_back(f(x));  -            }  -  -            TVector<i32> c;  -            for (i32 x : Map(f, a)) {  -                c.push_back(x);  -            }  -  +        TVector<TVector<i32>> ts = { +            {}, +            {1}, +            {1, 2}, +            {1, 2, 3, 4, 5, 6, 7}, +        }; + +        auto f = [](i32 x) { return x * x; }; + +        for (auto& a : ts) { +            TVector<i32> b; +            for (i32 x : a) { +                b.push_back(f(x)); +            } + +            TVector<i32> c; +            for (i32 x : Map(f, a)) { +                c.push_back(x); +            } +              EXPECT_EQ(b, c); -        }  -  -        TVector floats = {1.4, 4.1, 13.9};  -        TVector ints = {1, 4, 13};  -        TVector<float> roundedFloats = {1, 4, 13};  -        TVector<int> res;  -        TVector<float> resFloat;  -        for (auto i : Map<int>(floats)) {  -            res.push_back(i);  -        }  -        for (auto i : Map<float>(Map<int>(floats))) {  -            resFloat.push_back(i);  -        }  +        } + +        TVector floats = {1.4, 4.1, 13.9}; +        TVector ints = {1, 4, 13}; +        TVector<float> roundedFloats = {1, 4, 13}; +        TVector<int> res; +        TVector<float> resFloat; +        for (auto i : Map<int>(floats)) { +            res.push_back(i); +        } +        for (auto i : Map<float>(Map<int>(floats))) { +            resFloat.push_back(i); +        }          EXPECT_EQ(ints, res);          EXPECT_EQ(roundedFloats, resFloat); -    }  -  +    } +      TEST(FuncTools, CompileMap) { -        auto container = std::vector{1, 2, 3};  -        auto sqr = [](int x) { return x * x; };  -        TestViewCompileability(Map(sqr, container));  -        const int arrayContainer[] = {1, 2, 3};  -        TestViewCompileability(Map(sqr, arrayContainer));  -    }  -  +        auto container = std::vector{1, 2, 3}; +        auto sqr = [](int x) { return x * x; }; +        TestViewCompileability(Map(sqr, container)); +        const int arrayContainer[] = {1, 2, 3}; +        TestViewCompileability(Map(sqr, arrayContainer)); +    } +      TEST(FuncTools, MapRandomAccess) { -        auto sqr = [](int x) { return x * x; };  -        {  -            auto container = std::vector{1, 2, 3};  -            auto mapped = Map(sqr, container);  +        auto sqr = [](int x) { return x * x; }; +        { +            auto container = std::vector{1, 2, 3}; +            auto mapped = Map(sqr, container);              static_assert(                  std::is_same_v<decltype(mapped)::iterator::iterator_category, std::random_access_iterator_tag>              ); -        }  -        {  -            auto container = std::set<int>{1, 2, 3};  -            auto mapped = Map(sqr, container);  +        } +        { +            auto container = std::set<int>{1, 2, 3}; +            auto mapped = Map(sqr, container);              static_assert(                  std::is_same_v<decltype(mapped)::iterator::iterator_category, std::input_iterator_tag>              ); -        }  -    }  -  +        } +    } +      TEST(FuncTools, CartesianProduct) { -        TVector<std::pair<TVector<i32>, TVector<i32>>> ts = {  -            {{1, 2, 3}, {4, 5, 6}},  -            {{1, 2, 3}, {4, 5, 6, 7}},  -            {{1, 2, 3, 4}, {4, 5, 6}},  -            {{1, 2, 3, 4}, {}},  -            {{}, {1, 2, 3, 4}},  -        };  -  -        for (auto [a, b] : ts) {  -            TVector<std::pair<i32, i32>> c;  -            for (auto ai : a) {  -                for (auto bi : b) {  -                    c.push_back({ai, bi});  -                }  -            }  -  -            TVector<std::pair<i32, i32>> d;  -            FOR_DISPATCH_2(ai, bi, CartesianProduct(a, b)) {  -                d.push_back({ai, bi});  -            }  -  +        TVector<std::pair<TVector<i32>, TVector<i32>>> ts = { +            {{1, 2, 3}, {4, 5, 6}}, +            {{1, 2, 3}, {4, 5, 6, 7}}, +            {{1, 2, 3, 4}, {4, 5, 6}}, +            {{1, 2, 3, 4}, {}}, +            {{}, {1, 2, 3, 4}}, +        }; + +        for (auto [a, b] : ts) { +            TVector<std::pair<i32, i32>> c; +            for (auto ai : a) { +                for (auto bi : b) { +                    c.push_back({ai, bi}); +                } +            } + +            TVector<std::pair<i32, i32>> d; +            FOR_DISPATCH_2(ai, bi, CartesianProduct(a, b)) { +                d.push_back({ai, bi}); +            } +              EXPECT_EQ(c, d); -        }  -  -        {  -            TVector<TVector<int>> g = {{}, {}};  -            TVector h = {10, 11, 12};  -            FOR_DISPATCH_2(gi, i, CartesianProduct(g, h)) {  -                gi.push_back(i);  -            }  +        } + +        { +            TVector<TVector<int>> g = {{}, {}}; +            TVector h = {10, 11, 12}; +            FOR_DISPATCH_2(gi, i, CartesianProduct(g, h)) { +                gi.push_back(i); +            }              EXPECT_EQ(g[0], h);              EXPECT_EQ(g[1], h); -        }  -    }  -  +        } +    } +      TEST(FuncTools, CartesianProduct3) { -        TVector<std::tuple<TVector<i32>, TVector<i32>, TVector<i32>>> ts = {  -            {{1, 2, 3}, {4, 5, 6}, {11, 3}},  -            {{1, 2, 3}, {4, 5, 6, 7}, {9}},  -            {{1, 2, 3, 4}, {9}, {4, 5, 6}},  -            {{1, 2, 3, 4}, {1}, {}},  -            {{}, {1}, {1, 2, 3, 4}},  -        };  -  -        FOR_DISPATCH_3(a, b, c, ts) {  -            TVector<std::tuple<i32, i32, i32>> e;  -            for (auto ai : a) {  -                for (auto bi : b) {  -                    for (auto ci : c) {  -                        e.push_back({ai, bi, ci});  -                    }  -                }  -            }  -  -            TVector<std::tuple<i32, i32, i32>> f;  -            FOR_DISPATCH_3(ai, bi, ci, CartesianProduct(a, b, c)) {  -                f.push_back({ai, bi, ci});  -            }  -  +        TVector<std::tuple<TVector<i32>, TVector<i32>, TVector<i32>>> ts = { +            {{1, 2, 3}, {4, 5, 6}, {11, 3}}, +            {{1, 2, 3}, {4, 5, 6, 7}, {9}}, +            {{1, 2, 3, 4}, {9}, {4, 5, 6}}, +            {{1, 2, 3, 4}, {1}, {}}, +            {{}, {1}, {1, 2, 3, 4}}, +        }; + +        FOR_DISPATCH_3(a, b, c, ts) { +            TVector<std::tuple<i32, i32, i32>> e; +            for (auto ai : a) { +                for (auto bi : b) { +                    for (auto ci : c) { +                        e.push_back({ai, bi, ci}); +                    } +                } +            } + +            TVector<std::tuple<i32, i32, i32>> f; +            FOR_DISPATCH_3(ai, bi, ci, CartesianProduct(a, b, c)) { +                f.push_back({ai, bi, ci}); +            } +              EXPECT_EQ(e, f); -        }  -    }  -  +        } +    } +      TEST(FuncTools, CompileCartesianProduct) { -        auto container = std::vector{1, 2, 3};  -        TestViewCompileability(CartesianProduct(container, container));  -        const auto constContainer = std::vector{1, 2, 3};  -        TestViewCompileability(CartesianProduct(constContainer, constContainer));  -        const int arrayContainer[] = {1, 2, 3};  -        TestViewCompileability(CartesianProduct(arrayContainer, arrayContainer));  -  -        std::vector<std::pair<int, int>> res;  -        FOR_DISPATCH_2(a, b, CartesianProduct(MakeMinimalisticContainer(), MakeMinimalisticContainer())) {  -            res.push_back({a, b});  -        }  +        auto container = std::vector{1, 2, 3}; +        TestViewCompileability(CartesianProduct(container, container)); +        const auto constContainer = std::vector{1, 2, 3}; +        TestViewCompileability(CartesianProduct(constContainer, constContainer)); +        const int arrayContainer[] = {1, 2, 3}; +        TestViewCompileability(CartesianProduct(arrayContainer, arrayContainer)); + +        std::vector<std::pair<int, int>> res; +        FOR_DISPATCH_2(a, b, CartesianProduct(MakeMinimalisticContainer(), MakeMinimalisticContainer())) { +            res.push_back({a, b}); +        }          EXPECT_EQ(res, (std::vector<std::pair<int, int>>{ -            {0, 0}, {0, 1}, {0, 2},  -            {1, 0}, {1, 1}, {1, 2},  -            {2, 0}, {2, 1}, {2, 2},  -        }));  -    }  -  +            {0, 0}, {0, 1}, {0, 2}, +            {1, 0}, {1, 1}, {1, 2}, +            {2, 0}, {2, 1}, {2, 2}, +        })); +    } +      TEST(FuncTools, Concatenate2) { -        TVector<std::pair<TVector<i32>, TVector<i32>>> ts = {  -            {{1, 2, 3}, {4, 5, 6}},  -            {{1, 2, 3}, {4, 5, 6, 7}},  -            {{1, 2, 3, 4}, {4, 5, 6}},  -            {{1, 2, 3, 4}, {}},  -            {{}, {1, 2, 3, 4}},  -        };  -  -        for (auto [a, b] : ts) {  -            TVector<i32> c;  -            for (auto ai : a) {  -                c.push_back(ai);  -            }  -            for (auto bi : b) {  -                c.push_back(bi);  -            }  -  -            TVector<i32> d;  -            for (auto x : Concatenate(a, b)) {  -                d.push_back(x);  -            }  -  +        TVector<std::pair<TVector<i32>, TVector<i32>>> ts = { +            {{1, 2, 3}, {4, 5, 6}}, +            {{1, 2, 3}, {4, 5, 6, 7}}, +            {{1, 2, 3, 4}, {4, 5, 6}}, +            {{1, 2, 3, 4}, {}}, +            {{}, {1, 2, 3, 4}}, +        }; + +        for (auto [a, b] : ts) { +            TVector<i32> c; +            for (auto ai : a) { +                c.push_back(ai); +            } +            for (auto bi : b) { +                c.push_back(bi); +            } + +            TVector<i32> d; +            for (auto x : Concatenate(a, b)) { +                d.push_back(x); +            } +              EXPECT_EQ(c, d); -        }  -  -        {  -            TVector<i32> a = {1, 2, 3, 4};  -            TVector<i32> c;  -            for (auto x : Concatenate(a, TVector<i32>{5, 6})) {  -                c.push_back(x);  -            }  +        } + +        { +            TVector<i32> a = {1, 2, 3, 4}; +            TVector<i32> c; +            for (auto x : Concatenate(a, TVector<i32>{5, 6})) { +                c.push_back(x); +            }              EXPECT_EQ(c, (TVector<i32>{1, 2, 3, 4, 5, 6})); -        }  -    }  -  +        } +    } +      TEST(FuncTools, CompileConcatenate) { -        auto container = std::vector{1, 2, 3};  -        TestViewCompileability(Concatenate(container, container));  -        const auto constContainer = std::vector{1, 2, 3};  -        TestViewCompileability(Concatenate(constContainer, constContainer));  -        const int arrayContainer[] = {1, 2, 3};  -        TestViewCompileability(Concatenate(arrayContainer, arrayContainer));  -  -        std::vector<int> res;  -        for (auto a : Concatenate(MakeMinimalisticContainer(), MakeMinimalisticContainer())) {  -            res.push_back(a);  -        }  +        auto container = std::vector{1, 2, 3}; +        TestViewCompileability(Concatenate(container, container)); +        const auto constContainer = std::vector{1, 2, 3}; +        TestViewCompileability(Concatenate(constContainer, constContainer)); +        const int arrayContainer[] = {1, 2, 3}; +        TestViewCompileability(Concatenate(arrayContainer, arrayContainer)); + +        std::vector<int> res; +        for (auto a : Concatenate(MakeMinimalisticContainer(), MakeMinimalisticContainer())) { +            res.push_back(a); +        }          EXPECT_EQ(res, (std::vector{0, 1, 2, 0, 1, 2})); -    }  -  +    } +      TEST(FuncTools, Combo) {          FOR_DISPATCH_2(i, j, Enumerate(xrange(10u))) {              EXPECT_EQ(i, j); -        }  -  +        } +          FOR_DISPATCH_2(i, jk, Enumerate(Enumerate(xrange(10u)))) {              EXPECT_EQ(i, std::get<0>(jk));              EXPECT_EQ(std::get<0>(jk), std::get<1>(jk)); -        }  -  +        } +          TVector<size_t> a = {0, 1, 2}; -        FOR_DISPATCH_2(i, j, Enumerate(Reversed(a))) {  +        FOR_DISPATCH_2(i, j, Enumerate(Reversed(a))) {              EXPECT_EQ(i, 2 - j); -        }  -  -        FOR_DISPATCH_2(i, j, Enumerate(Map<float>(a))) {  +        } + +        FOR_DISPATCH_2(i, j, Enumerate(Map<float>(a))) {              EXPECT_EQ(i, (size_t)j); -        }  -  -        FOR_DISPATCH_2(i, j, Zip(a, Map<float>(a))) {  +        } + +        FOR_DISPATCH_2(i, j, Zip(a, Map<float>(a))) {              EXPECT_EQ(i, (size_t)j); -        }  -  -        auto mapper = [](auto&& x) {  -            return std::get<0>(x) + std::get<1>(x);  -        };  -        FOR_DISPATCH_2(i, j, Zip(a, Map(mapper, Zip(a, a)))) {  +        } + +        auto mapper = [](auto&& x) { +            return std::get<0>(x) + std::get<1>(x); +        }; +        FOR_DISPATCH_2(i, j, Zip(a, Map(mapper, Zip(a, a)))) {              EXPECT_EQ(j, 2 * i); -        }  -    }  -  -  +        } +    } + +      TEST(FuncTools, CopyIterator) { -        TVector a = {1, 2, 3, 4};  -        TVector b = {4, 5, 6, 7};  -  -        // calls f on 2nd, 3d and 4th positions (numeration from 1st)  -        auto testIterator = [](auto it, auto f) {  -            ++it;  -            auto it2 = it;  -            ++it2;  -            ++it2;  -            auto it3 = it;  -            ++it3;  -            f(*it, *it3, *it2);  -        };  -  -        {  -            auto iterable = Enumerate(a);  -            testIterator(std::begin(iterable),  -                [](auto p2, auto p3, auto p4) {  +        TVector a = {1, 2, 3, 4}; +        TVector b = {4, 5, 6, 7}; + +        // calls f on 2nd, 3d and 4th positions (numeration from 1st) +        auto testIterator = [](auto it, auto f) { +            ++it; +            auto it2 = it; +            ++it2; +            ++it2; +            auto it3 = it; +            ++it3; +            f(*it, *it3, *it2); +        }; + +        { +            auto iterable = Enumerate(a); +            testIterator(std::begin(iterable), +                [](auto p2, auto p3, auto p4) {                      EXPECT_EQ(std::get<0>(p2), 1u);                      EXPECT_EQ(std::get<1>(p2), 2);                      EXPECT_EQ(std::get<0>(p3), 2u);                      EXPECT_EQ(std::get<1>(p3), 3);                      EXPECT_EQ(std::get<0>(p4), 3u);                      EXPECT_EQ(std::get<1>(p4), 4); -                });  -        }  -  -        {  -            auto iterable = Map([](i32 x) { return x*x; }, a);  -            testIterator(std::begin(iterable),  -                [](auto p2, auto p3, auto p4) {  +                }); +        } + +        { +            auto iterable = Map([](i32 x) { return x*x; }, a); +            testIterator(std::begin(iterable), +                [](auto p2, auto p3, auto p4) {                      EXPECT_EQ(p2, 4);                      EXPECT_EQ(p3, 9);                      EXPECT_EQ(p4, 16); -                });  -        }  -  -        {  -            auto iterable = Zip(a, b);  -            testIterator(std::begin(iterable),  -                [](auto p2, auto p3, auto p4) {  +                }); +        } + +        { +            auto iterable = Zip(a, b); +            testIterator(std::begin(iterable), +                [](auto p2, auto p3, auto p4) {                      EXPECT_EQ(std::get<0>(p2), 2);                      EXPECT_EQ(std::get<1>(p2), 5);                      EXPECT_EQ(std::get<0>(p3), 3);                      EXPECT_EQ(std::get<1>(p3), 6);                      EXPECT_EQ(std::get<0>(p4), 4);                      EXPECT_EQ(std::get<1>(p4), 7); -                });  -        }  -  -        {  -            auto c = {1, 2, 3, 4, 5, 6, 7, 8};  -            auto iterable = Filter([](i32 x) { return !(x & 1); }, c);  -            testIterator(std::begin(iterable),  -                [](auto p2, auto p3, auto p4) {  +                }); +        } + +        { +            auto c = {1, 2, 3, 4, 5, 6, 7, 8}; +            auto iterable = Filter([](i32 x) { return !(x & 1); }, c); +            testIterator(std::begin(iterable), +                [](auto p2, auto p3, auto p4) {                      EXPECT_EQ(p2, 4);                      EXPECT_EQ(p3, 6);                      EXPECT_EQ(p4, 8); -                });  -        }  -  -        {  -            auto iterable = CartesianProduct(TVector{0, 1}, TVector{2, 3});  -            // (0, 2), (0, 3), (1, 2), (1, 3)  -            testIterator(std::begin(iterable),  -                [](auto p2, auto p3, auto p4) {  +                }); +        } + +        { +            auto iterable = CartesianProduct(TVector{0, 1}, TVector{2, 3}); +            // (0, 2), (0, 3), (1, 2), (1, 3) +            testIterator(std::begin(iterable), +                [](auto p2, auto p3, auto p4) {                      EXPECT_EQ(std::get<0>(p2), 0);                      EXPECT_EQ(std::get<1>(p2), 3);                      EXPECT_EQ(std::get<0>(p3), 1);                      EXPECT_EQ(std::get<1>(p3), 2);                      EXPECT_EQ(std::get<0>(p4), 1);                      EXPECT_EQ(std::get<1>(p4), 3); -                });  -        }  -    }  +                }); +        } +    } diff --git a/library/cpp/iterator/ut/ya.make b/library/cpp/iterator/ut/ya.make index 76db8d8a996..601e5663b9f 100644 --- a/library/cpp/iterator/ut/ya.make +++ b/library/cpp/iterator/ut/ya.make @@ -8,7 +8,7 @@ OWNER(g:util)  SRCS(      filtering_ut.cpp -    functools_ut.cpp  +    functools_ut.cpp      iterate_keys_ut.cpp      iterate_values_ut.cpp      mapped_ut.cpp diff --git a/library/cpp/iterator/ya.make b/library/cpp/iterator/ya.make index dfc4b43a899..1ba1ffb411b 100644 --- a/library/cpp/iterator/ya.make +++ b/library/cpp/iterator/ya.make @@ -2,18 +2,18 @@ OWNER(g:util)  LIBRARY() -SRCS(  -    cartesian_product.cpp  -    concatenate.cpp  -    enumerate.cpp  +SRCS( +    cartesian_product.cpp +    concatenate.cpp +    enumerate.cpp      iterate_keys.cpp      iterate_values.cpp -    filtering.cpp  -    functools.cpp  -    mapped.cpp  -    zip.cpp  -)  -  +    filtering.cpp +    functools.cpp +    mapped.cpp +    zip.cpp +) +  END()  RECURSE_FOR_TESTS(ut) diff --git a/library/cpp/iterator/zip.cpp b/library/cpp/iterator/zip.cpp index 0b6121fbdcf..36338ea5278 100644 --- a/library/cpp/iterator/zip.cpp +++ b/library/cpp/iterator/zip.cpp @@ -1 +1 @@ -#include "zip.h"  +#include "zip.h" diff --git a/library/cpp/iterator/zip.h b/library/cpp/iterator/zip.h index 6ec0993240d..ac12ed35fe8 100644 --- a/library/cpp/iterator/zip.h +++ b/library/cpp/iterator/zip.h @@ -1,128 +1,128 @@ -#pragma once  -  -#include <util/generic/store_policy.h>  -  -#include <algorithm>  -#include <tuple>  -  -  -namespace NPrivate {  -  -    template <typename TContainer, typename TIteratorCategory = typename std::iterator_traits<decltype(std::begin(std::declval<TContainer>()))>::iterator_category>  -    static constexpr bool HasRandomAccessIterator(int32_t) {  -        return std::is_same_v<TIteratorCategory, std::random_access_iterator_tag>;  -    }  -  -    template <typename TContainer>  -    static constexpr bool HasRandomAccessIterator(uint32_t) {  -        return false;  -    }  -  -    template <typename... TContainers>  -    struct TZipper {  -        template <std::size_t... I>  -        struct TZipperWithIndex {  -        private:  -            using THolders = std::tuple<TAutoEmbedOrPtrPolicy<TContainers>...>;  -            using TValue = std::tuple<decltype(*std::begin(std::declval<TContainers&>()))...>;  -            using TIteratorState = std::tuple<decltype(std::begin(std::declval<TContainers&>()))...>;  -            using TSentinelState = std::tuple<decltype(std::end(std::declval<TContainers&>()))...>;  -  -            static constexpr bool TrivialSentinel = std::is_same_v<TIteratorState, TSentinelState>;  -  -            struct TIterator;  -            struct TSentinelCandidate {  -                TSentinelState Iterators_;  -            };  -            using TSentinel = std::conditional_t<TrivialSentinel, TIterator, TSentinelCandidate>;  -  -#ifndef _MSC_VER  -            // windows compiler crashes here  -            static constexpr bool LimitByFirstContainer = TrivialSentinel &&  -                ((HasRandomAccessIterator<TContainers>(0)) && ...);  -#else  -            static constexpr bool LimitByFirstContainer = false;  -#endif  -  -            struct TIterator {  -                using difference_type = std::ptrdiff_t;  -                using value_type = TValue;  -                using pointer = TValue*;  -                using reference = TValue&;  +#pragma once + +#include <util/generic/store_policy.h> + +#include <algorithm> +#include <tuple> + + +namespace NPrivate { + +    template <typename TContainer, typename TIteratorCategory = typename std::iterator_traits<decltype(std::begin(std::declval<TContainer>()))>::iterator_category> +    static constexpr bool HasRandomAccessIterator(int32_t) { +        return std::is_same_v<TIteratorCategory, std::random_access_iterator_tag>; +    } + +    template <typename TContainer> +    static constexpr bool HasRandomAccessIterator(uint32_t) { +        return false; +    } + +    template <typename... TContainers> +    struct TZipper { +        template <std::size_t... I> +        struct TZipperWithIndex { +        private: +            using THolders = std::tuple<TAutoEmbedOrPtrPolicy<TContainers>...>; +            using TValue = std::tuple<decltype(*std::begin(std::declval<TContainers&>()))...>; +            using TIteratorState = std::tuple<decltype(std::begin(std::declval<TContainers&>()))...>; +            using TSentinelState = std::tuple<decltype(std::end(std::declval<TContainers&>()))...>; + +            static constexpr bool TrivialSentinel = std::is_same_v<TIteratorState, TSentinelState>; + +            struct TIterator; +            struct TSentinelCandidate { +                TSentinelState Iterators_; +            }; +            using TSentinel = std::conditional_t<TrivialSentinel, TIterator, TSentinelCandidate>; + +#ifndef _MSC_VER +            // windows compiler crashes here +            static constexpr bool LimitByFirstContainer = TrivialSentinel && +                ((HasRandomAccessIterator<TContainers>(0)) && ...); +#else +            static constexpr bool LimitByFirstContainer = false; +#endif + +            struct TIterator { +                using difference_type = std::ptrdiff_t; +                using value_type = TValue; +                using pointer = TValue*; +                using reference = TValue&;                  using const_reference = const TValue&; -                using iterator_category = std::input_iterator_tag;  -  -                TValue operator*() {  -                    return {*std::get<I>(Iterators_)...};  -                }  -                TValue operator*() const {  -                    return {*std::get<I>(Iterators_)...};  -                }  +                using iterator_category = std::input_iterator_tag; + +                TValue operator*() { +                    return {*std::get<I>(Iterators_)...}; +                } +                TValue operator*() const { +                    return {*std::get<I>(Iterators_)...}; +                }                  TIterator& operator++() { -                    (++std::get<I>(Iterators_), ...);  +                    (++std::get<I>(Iterators_), ...);                      return *this; -                }  +                }                  TIterator operator++(int) {                      return TIterator{TIteratorState{std::get<I>(Iterators_)++...}};                  } -                bool operator!=(const TSentinel& other) const {  -                    if constexpr (LimitByFirstContainer) {  -                        return std::get<0>(Iterators_) != std::get<0>(other.Iterators_);  -                    } else {  -                        // yes, for all correct iterators but end() it is a correct way to compare  -                        return ((std::get<I>(Iterators_) != std::get<I>(other.Iterators_)) && ...);  -                    }  -                }  -                bool operator==(const TSentinel& other) const {  -                    return !(*this != other);  -                }  -  -                TIteratorState Iterators_;  -            };  -        public:  -            using iterator = TIterator;  -            using const_iterator = TIterator;  +                bool operator!=(const TSentinel& other) const { +                    if constexpr (LimitByFirstContainer) { +                        return std::get<0>(Iterators_) != std::get<0>(other.Iterators_); +                    } else { +                        // yes, for all correct iterators but end() it is a correct way to compare +                        return ((std::get<I>(Iterators_) != std::get<I>(other.Iterators_)) && ...); +                    } +                } +                bool operator==(const TSentinel& other) const { +                    return !(*this != other); +                } + +                TIteratorState Iterators_; +            }; +        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::const_reference; -  -            TIterator begin() const {  -                return {TIteratorState{std::begin(*std::get<I>(Holders_).Ptr())...}};  -            }  -  -            TSentinel end() const {  -                if constexpr (LimitByFirstContainer) {  -                    auto endOfFirst = std::begin(*std::get<0>(Holders_).Ptr()) + std::min({  -                        std::end(*std::get<I>(Holders_).Ptr()) - std::begin(*std::get<I>(Holders_).Ptr())...});  -                    TIterator iter{TSentinelState{std::end(*std::get<I>(Holders_).Ptr())...}};  -                    std::get<0>(iter.Iterators_) = endOfFirst;  -                    return iter;  -                } else {  -                    return {TSentinelState{std::end(*std::get<I>(Holders_).Ptr())...}};  -                }  -            }  -  -            mutable THolders Holders_;  -        };  -  -        template <std::size_t... I>  -        static auto Zip(TContainers&&... containers, std::index_sequence<I...>) {  -            return TZipperWithIndex<I...>{{std::forward<TContainers>(containers)...}};  -        }  -    };  -  -}  -  -  -//! Acts as pythonic zip, BUT result length is equal to shortest length of input containers  -//! Usage: for (auto [ai, bi, ci] : Zip(a, b, c)) {...}  -template <typename... TContainers>  -auto Zip(TContainers&&... containers) {  + +            TIterator begin() const { +                return {TIteratorState{std::begin(*std::get<I>(Holders_).Ptr())...}}; +            } + +            TSentinel end() const { +                if constexpr (LimitByFirstContainer) { +                    auto endOfFirst = std::begin(*std::get<0>(Holders_).Ptr()) + std::min({ +                        std::end(*std::get<I>(Holders_).Ptr()) - std::begin(*std::get<I>(Holders_).Ptr())...}); +                    TIterator iter{TSentinelState{std::end(*std::get<I>(Holders_).Ptr())...}}; +                    std::get<0>(iter.Iterators_) = endOfFirst; +                    return iter; +                } else { +                    return {TSentinelState{std::end(*std::get<I>(Holders_).Ptr())...}}; +                } +            } + +            mutable THolders Holders_; +        }; + +        template <std::size_t... I> +        static auto Zip(TContainers&&... containers, std::index_sequence<I...>) { +            return TZipperWithIndex<I...>{{std::forward<TContainers>(containers)...}}; +        } +    }; + +} + + +//! Acts as pythonic zip, BUT result length is equal to shortest length of input containers +//! Usage: for (auto [ai, bi, ci] : Zip(a, b, c)) {...} +template <typename... TContainers> +auto Zip(TContainers&&... containers) {      return ::NPrivate::TZipper<TContainers...>::Zip( -        std::forward<TContainers>(containers)...,  -        std::make_index_sequence<sizeof...(TContainers)>{}  -    );  -}  +        std::forward<TContainers>(containers)..., +        std::make_index_sequence<sizeof...(TContainers)>{} +    ); +} diff --git a/library/cpp/threading/future/core/future-inl.h b/library/cpp/threading/future/core/future-inl.h index d9bd32a21ee..5fd4296a93c 100644 --- a/library/cpp/threading/future/core/future-inl.h +++ b/library/cpp/threading/future/core/future-inl.h @@ -127,21 +127,21 @@ namespace NThreading {              template <typename TT>              void SetValue(TT&& value) { -                bool success = TrySetValue(std::forward<TT>(value));  -                if (Y_UNLIKELY(!success)) {  -                    ythrow TFutureException() << "value already set";  -                }  -            }  -  -            template <typename TT>  -            bool TrySetValue(TT&& value) {  +                bool success = TrySetValue(std::forward<TT>(value)); +                if (Y_UNLIKELY(!success)) { +                    ythrow TFutureException() << "value already set"; +                } +            } + +            template <typename TT> +            bool TrySetValue(TT&& value) {                  TSystemEvent* readyEvent = nullptr;                  TCallbackList<T> callbacks;                  with_lock (StateLock) {                      int state = AtomicGet(State);                      if (Y_UNLIKELY(state != NotReady)) { -                        return false;  +                        return false;                      }                      new (&Value) T(std::forward<TT>(value)); @@ -162,8 +162,8 @@ namespace NThreading {                          callback(temp);                      }                  } -  -                return true;  + +                return true;              }              void SetException(std::exception_ptr e) { @@ -316,20 +316,20 @@ namespace NThreading {              }              void SetValue() { -                bool success = TrySetValue();  -                if (Y_UNLIKELY(!success)) {  -                    ythrow TFutureException() << "value already set";  -                }  -            }  -  -            bool TrySetValue() {  +                bool success = TrySetValue(); +                if (Y_UNLIKELY(!success)) { +                    ythrow TFutureException() << "value already set"; +                } +            } + +            bool TrySetValue() {                  TSystemEvent* readyEvent = nullptr;                  TCallbackList<void> callbacks;                  with_lock (StateLock) {                      int state = AtomicGet(State);                      if (Y_UNLIKELY(state != NotReady)) { -                        return false;  +                        return false;                      }                      readyEvent = ReadyEvent.Get(); @@ -348,8 +348,8 @@ namespace NThreading {                          callback(temp);                      }                  } -  -                return true;  + +                return true;              }              void SetException(std::exception_ptr e) { @@ -798,18 +798,18 @@ namespace NThreading {      }      template <typename T> -    inline bool TPromise<T>::TrySetValue(const T& value) {  -        EnsureInitialized();  -        return State->TrySetValue(value);  -    }  -  -    template <typename T>  -    inline bool TPromise<T>::TrySetValue(T&& value) {  -        EnsureInitialized();  -        return State->TrySetValue(std::move(value));  -    }  -  -    template <typename T>  +    inline bool TPromise<T>::TrySetValue(const T& value) { +        EnsureInitialized(); +        return State->TrySetValue(value); +    } + +    template <typename T> +    inline bool TPromise<T>::TrySetValue(T&& value) { +        EnsureInitialized(); +        return State->TrySetValue(std::move(value)); +    } + +    template <typename T>      inline void TPromise<T>::TryRethrow() const {          if (State) {              State->TryRethrow(); @@ -887,11 +887,11 @@ namespace NThreading {          State->SetValue();      } -    inline bool TPromise<void>::TrySetValue() {  -        EnsureInitialized();  -        return State->TrySetValue();  -    }  -  +    inline bool TPromise<void>::TrySetValue() { +        EnsureInitialized(); +        return State->TrySetValue(); +    } +      inline void TPromise<void>::TryRethrow() const {          if(State) {              State->TryRethrow(); diff --git a/library/cpp/threading/future/core/future.h b/library/cpp/threading/future/core/future.h index b42a83a4ca6..2e82bb953eb 100644 --- a/library/cpp/threading/future/core/future.h +++ b/library/cpp/threading/future/core/future.h @@ -209,9 +209,9 @@ namespace NThreading {          void SetValue(const T& value);          void SetValue(T&& value); -        bool TrySetValue(const T& value);  -        bool TrySetValue(T&& value);  -  +        bool TrySetValue(const T& value); +        bool TrySetValue(T&& value); +          void TryRethrow() const;          bool HasException() const;          void SetException(const TString& e); @@ -250,7 +250,7 @@ namespace NThreading {          void GetValue() const;          void SetValue(); -        bool TrySetValue();  +        bool TrySetValue();          void TryRethrow() const;          bool HasException() const; diff --git a/library/cpp/threading/future/future_ut.cpp b/library/cpp/threading/future/future_ut.cpp index 99c9e33eca5..05950a568d4 100644 --- a/library/cpp/threading/future/future_ut.cpp +++ b/library/cpp/threading/future/future_ut.cpp @@ -479,7 +479,7 @@ namespace {              UNIT_ASSERT_EQUAL(promise.ExtractValue(), 123);              UNIT_CHECK_GENERATED_EXCEPTION(promise.ExtractValue(), TFutureException);          } -  +          Y_UNIT_TEST(ShouldNotExtractFromSharedDefault) {              UNIT_CHECK_GENERATED_EXCEPTION(MakeFuture<int>().ExtractValue(), TFutureException); @@ -495,17 +495,17 @@ namespace {              UNIT_ASSERT_VALUES_EQUAL(MakeFuture<TStorage>().GetValue().String, TString(100, 'a'));          } -        Y_UNIT_TEST(HandlingRepetitiveSet) {  -            TPromise<int> promise = NewPromise<int>();  -            promise.SetValue(42);  -            UNIT_CHECK_GENERATED_EXCEPTION(promise.SetValue(42), TFutureException);  -        }  -  -        Y_UNIT_TEST(HandlingRepetitiveTrySet) {  -            TPromise<int> promise = NewPromise<int>();  -            UNIT_ASSERT(promise.TrySetValue(42));  -            UNIT_ASSERT(!promise.TrySetValue(42));  -        }  +        Y_UNIT_TEST(HandlingRepetitiveSet) { +            TPromise<int> promise = NewPromise<int>(); +            promise.SetValue(42); +            UNIT_CHECK_GENERATED_EXCEPTION(promise.SetValue(42), TFutureException); +        } + +        Y_UNIT_TEST(HandlingRepetitiveTrySet) { +            TPromise<int> promise = NewPromise<int>(); +            UNIT_ASSERT(promise.TrySetValue(42)); +            UNIT_ASSERT(!promise.TrySetValue(42)); +        }          Y_UNIT_TEST(HandlingRepetitiveSetException) {              TPromise<int> promise = NewPromise<int>(); diff --git a/library/cpp/yson/node/node.cpp b/library/cpp/yson/node/node.cpp index 7248148d0c2..b39e0707187 100644 --- a/library/cpp/yson/node/node.cpp +++ b/library/cpp/yson/node/node.cpp @@ -456,71 +456,71 @@ TNode& TNode::At(size_t index) {      return list[index];  } -TNode& TNode::Add() &  +TNode& TNode::Add() &  {      AssureList();      return std::get<TListType>(Value_).emplace_back();  } -TNode TNode::Add() &&  +TNode TNode::Add() && +{ +    return std::move(Add()); +} + +TNode& TNode::Add(const TNode& node) &  { -    return std::move(Add());  -}  -  -TNode& TNode::Add(const TNode& node) &  -{       AssureList();      std::get<TListType>(Value_).emplace_back(node);      return *this;  } -TNode TNode::Add(const TNode& node) &&  +TNode TNode::Add(const TNode& node) && +{ +    return std::move(Add(node)); +} + +TNode& TNode::Add(TNode&& node) &  { -    return std::move(Add(node));  -}  -  -TNode& TNode::Add(TNode&& node) &  -{       AssureList();      std::get<TListType>(Value_).emplace_back(std::move(node));      return *this;  } -TNode TNode::Add(TNode&& node) &&  -{  -    return std::move(Add(std::move(node)));  -}  -  +TNode TNode::Add(TNode&& node) && +{ +    return std::move(Add(std::move(node))); +} +  bool TNode::HasKey(const TStringBuf key) const  {      CheckType(Map);      return std::get<TMapType>(Value_).contains(key);  } -TNode& TNode::operator()(const TString& key, const TNode& value) &  +TNode& TNode::operator()(const TString& key, const TNode& value) &  {      AssureMap();      std::get<TMapType>(Value_)[key] = value;      return *this;  } -TNode TNode::operator()(const TString& key, const TNode& value) &&  +TNode TNode::operator()(const TString& key, const TNode& value) && +{ +    return std::move(operator()(key, value)); +} + +TNode& TNode::operator()(const TString& key, TNode&& value) &  { -    return std::move(operator()(key, value));  -}  -  -TNode& TNode::operator()(const TString& key, TNode&& value) &  -{       AssureMap();      std::get<TMapType>(Value_)[key] = std::move(value);      return *this;  } -TNode TNode::operator()(const TString& key, TNode&& value) &&  -{  -    return std::move(operator()(key, std::move(value)));  -}  -  +TNode TNode::operator()(const TString& key, TNode&& value) && +{ +    return std::move(operator()(key, std::move(value))); +} +  const TNode& TNode::operator[](const TStringBuf key) const  {      CheckType(Map); diff --git a/library/cpp/yson/node/node.h b/library/cpp/yson/node/node.h index c735fcd5e6b..5f90f95df07 100644 --- a/library/cpp/yson/node/node.h +++ b/library/cpp/yson/node/node.h @@ -186,19 +186,19 @@ public:      const TNode& At(size_t index) const;      TNode& At(size_t index); -    TNode& Add() &;  -    TNode Add() &&;  -    TNode& Add(const TNode& node) &;  -    TNode Add(const TNode& node) &&;  -    TNode& Add(TNode&& node) &;  -    TNode Add(TNode&& node) &&;  +    TNode& Add() &; +    TNode Add() &&; +    TNode& Add(const TNode& node) &; +    TNode Add(const TNode& node) &&; +    TNode& Add(TNode&& node) &; +    TNode Add(TNode&& node) &&;      bool HasKey(const TStringBuf key) const; -    TNode& operator()(const TString& key, const TNode& value) &;  -    TNode operator()(const TString& key, const TNode& value) &&;  -    TNode& operator()(const TString& key, TNode&& value) &;  -    TNode operator()(const TString& key, TNode&& value) &&;  +    TNode& operator()(const TString& key, const TNode& value) &; +    TNode operator()(const TString& key, const TNode& value) &&; +    TNode& operator()(const TString& key, TNode&& value) &; +    TNode operator()(const TString& key, TNode&& value) &&;      const TNode& operator[](const TStringBuf key) const;      TNode& operator[](const TStringBuf key); diff --git a/library/cpp/yson/node/node_ut.cpp b/library/cpp/yson/node/node_ut.cpp index a046334457d..448e99f5753 100644 --- a/library/cpp/yson/node/node_ut.cpp +++ b/library/cpp/yson/node/node_ut.cpp @@ -129,19 +129,19 @@ Y_UNIT_TEST_SUITE(YtNodeTest) {      }      Y_UNIT_TEST(TestInsertingMethodsFromTemporaryObjects) { -        // check that .Add(...) doesn't return lvalue reference to temporary object  -        {  -            const TNode& nodeList = TNode().Add(0).Add("pass").Add(0);  -            UNIT_ASSERT_EQUAL(nodeList[1], TNode("pass"));  -        }  -  -        // check that .operator()(...) doesn't return lvalue reference to temporary object  -        {  -            const TNode& nodeMap = TNode()("1", 0)("2", "pass")("3", 0);  -            UNIT_ASSERT_EQUAL(nodeMap["2"], TNode("pass"));  -        }  -    }  -  +        // check that .Add(...) doesn't return lvalue reference to temporary object +        { +            const TNode& nodeList = TNode().Add(0).Add("pass").Add(0); +            UNIT_ASSERT_EQUAL(nodeList[1], TNode("pass")); +        } + +        // check that .operator()(...) doesn't return lvalue reference to temporary object +        { +            const TNode& nodeMap = TNode()("1", 0)("2", "pass")("3", 0); +            UNIT_ASSERT_EQUAL(nodeMap["2"], TNode("pass")); +        } +    } +      Y_UNIT_TEST(TestAttributes) {          TNode node = TNode()("lee", 42)("faa", 54);          UNIT_ASSERT(!node.HasAttributes());  | 
