aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/iterator
diff options
context:
space:
mode:
authorpechatnov <pechatnov@yandex-team.ru>2022-02-10 16:48:57 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:48:57 +0300
commit8e9b2f8bbf4a2320f539eef5b85555f42c065425 (patch)
tree189a13fe5128c85492e45518171a532ffa90ba03 /library/cpp/iterator
parent92040fb3ad117c48c87d591bf9fe916ffda61233 (diff)
downloadydb-8e9b2f8bbf4a2320f539eef5b85555f42c065425.tar.gz
Restoring authorship annotation for <pechatnov@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'library/cpp/iterator')
-rw-r--r--library/cpp/iterator/README.md200
-rw-r--r--library/cpp/iterator/cartesian_product.cpp2
-rw-r--r--library/cpp/iterator/cartesian_product.h224
-rw-r--r--library/cpp/iterator/concatenate.cpp2
-rw-r--r--library/cpp/iterator/concatenate.h262
-rw-r--r--library/cpp/iterator/enumerate.cpp2
-rw-r--r--library/cpp/iterator/enumerate.h158
-rw-r--r--library/cpp/iterator/filtering.cpp2
-rw-r--r--library/cpp/iterator/filtering.h74
-rw-r--r--library/cpp/iterator/functools.cpp2
-rw-r--r--library/cpp/iterator/functools.h114
-rw-r--r--library/cpp/iterator/mapped.cpp2
-rw-r--r--library/cpp/iterator/mapped.h128
-rw-r--r--library/cpp/iterator/ut/functools_ut.cpp972
-rw-r--r--library/cpp/iterator/ut/ya.make2
-rw-r--r--library/cpp/iterator/ya.make20
-rw-r--r--library/cpp/iterator/zip.cpp2
-rw-r--r--library/cpp/iterator/zip.h230
18 files changed, 1199 insertions, 1199 deletions
diff --git a/library/cpp/iterator/README.md b/library/cpp/iterator/README.md
index cd92a284c9..77f0c29b92 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 c3ebfdcc33..40c5391134 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 3ef70339a2..afeced9995 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 4ca8e2e82d..1657b4246c 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 64d2cd451a..fe7e802aa0 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 b195f0b31d..4118a67e85 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 2c83fb41bf..21eae25f39 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 8e1542f61b..c27612502c 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 c28e3bc6c4..69099c2b70 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 da2d0757ce..e63845acb6 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 57a0d66373..3a2548292c 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 047f38c58f..201f95f10e 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 6c5e763184..486efd0899 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 <iterator>
-
+#include <util/generic/store_policy.h>
+#include <iterator>
+
+
namespace NIteratorPrivate {
- template <class TIterator>
- constexpr bool HasRandomAccess() {
- return std::is_same_v<typename std::iterator_traits<TIterator>::iterator_category,
- std::random_access_iterator_tag>;
- }
-};
-
-
+ template <class TIterator>
+ 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 2dee9a55c8..cd39158bd2 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 601e5663b9..76db8d8a99 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 1ba1ffb411..dfc4b43a89 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 36338ea527..0b6121fbdc 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 ac12ed35fe..6ec0993240 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)>{}
+ );
+}