diff options
author | pechatnov <pechatnov@yandex-team.ru> | 2022-02-10 16:48:57 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:48:57 +0300 |
commit | 132a3640fac343164b858d0a914e020a848a2848 (patch) | |
tree | 5d5cb817648f650d76cf1076100726fd9b8448e8 | |
parent | 8e9b2f8bbf4a2320f539eef5b85555f42c065425 (diff) | |
download | ydb-132a3640fac343164b858d0a914e020a848a2848.tar.gz |
Restoring authorship annotation for <pechatnov@yandex-team.ru>. Commit 2 of 2.
39 files changed, 1905 insertions, 1905 deletions
diff --git a/contrib/python/ya.make b/contrib/python/ya.make index 96a26549ba..d01ced9f3a 100644 --- a/contrib/python/ya.make +++ b/contrib/python/ya.make @@ -1078,7 +1078,7 @@ RECURSE( tornado tornado-opentracing toro - tqdm + tqdm trace_event traceback2 traitlets diff --git a/library/cpp/iterator/README.md b/library/cpp/iterator/README.md index 77f0c29b92..cd92a284c9 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 40c5391134..c3ebfdcc33 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 afeced9995..3ef70339a2 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 1657b4246c..4ca8e2e82d 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 fe7e802aa0..64d2cd451a 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 4118a67e85..b195f0b31d 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 21eae25f39..2c83fb41bf 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 c27612502c..8e1542f61b 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 69099c2b70..c28e3bc6c4 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 e63845acb6..da2d0757ce 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 3a2548292c..57a0d66373 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 201f95f10e..047f38c58f 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 486efd0899..6c5e763184 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 cd39158bd2..2dee9a55c8 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 76db8d8a99..601e5663b9 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 dfc4b43a89..1ba1ffb411 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 0b6121fbdc..36338ea527 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 6ec0993240..ac12ed35fe 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 d9bd32a21e..5fd4296a93 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 b42a83a4ca..2e82bb953e 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 99c9e33eca..05950a568d 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 7248148d0c..b39e070718 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 c735fcd5e6..5f90f95df0 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 a046334457..448e99f575 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()); diff --git a/library/python/ya.make b/library/python/ya.make index 58e8bff985..2e1eb6e0e1 100644 --- a/library/python/ya.make +++ b/library/python/ya.make @@ -163,7 +163,7 @@ RECURSE( runtime_py3/main runtime_py3/test runtime_test - sanitizers + sanitizers sdms_api sfx selenium_ui_test diff --git a/util/datetime/base.h b/util/datetime/base.h index a9c890ff3f..5e902b8f63 100644 --- a/util/datetime/base.h +++ b/util/datetime/base.h @@ -12,15 +12,15 @@ #include <util/generic/typetraits.h> #include <util/generic/yexception.h> -#include <chrono> - -#if defined(__cpp_lib_three_way_comparison) - #include <compare> -#endif - +#include <chrono> + +#if defined(__cpp_lib_three_way_comparison) + #include <compare> +#endif + #include <ctime> #include <cstdio> -#include <ratio> +#include <ratio> #include <time.h> @@ -213,49 +213,49 @@ public: { } - /** - * TDuration is compatible with std::chrono::duration: - * it can be constructed and compared with std::chrono::duration. - * But there is two significant and dangerous differencies between them: - * 1) TDuration is never negative and use saturation between 0 and maximum value. - * std::chrono::duration can be negative and can overflow. - * 2) TDuration uses integer number of microseconds. - * std::chrono::duration is flexible, can be integer of floating point, - * can have different precisions. - * So when casted from std::chrono::duration to TDuration value is clamped and rounded. - * In arithmethic operations std::chrono::duration argument is only rounded, - * result is TDuration and it clamped and rounded. - * In comparisons std::chrono::duration argument is rounded. - */ - template <typename T, typename TRatio> - constexpr TDuration(std::chrono::duration<T, TRatio> duration) noexcept { - static_assert( - std::ratio_greater_equal<TRatio, std::micro>::value && - (!std::is_floating_point<T>::value || std::ratio_greater<TRatio, std::micro>::value), - "Extremely likely it is loss of precision, because TDuration stores microseconds. " - "Cast you duration explicitly to microseconds if you really need it."); - - if (duration.count() < 0) { - *this = TDuration::Zero(); // clamp from the bottom - } else { - if -#if !defined(__NVCC__) - constexpr -#endif - /* if [constexpr] */ (std::ratio_greater<TRatio, std::micro>::value || std::is_floating_point<T>::value) { - // clamp from the top - using TCommonDuration = std::chrono::duration<typename std::common_type<T, TValue>::type, TRatio>; - constexpr auto maxDuration = std::chrono::duration<TValue, std::micro>(::Max<TValue>()); - if (std::chrono::duration_cast<TCommonDuration>(duration) >= std::chrono::duration_cast<TCommonDuration>(maxDuration)) { - *this = TDuration::Max(); - return; - } - } - const TValue us = std::chrono::duration_cast<std::chrono::duration<TValue, std::micro>>(duration).count(); - *this = TDuration::MicroSeconds(us); - } - } - + /** + * TDuration is compatible with std::chrono::duration: + * it can be constructed and compared with std::chrono::duration. + * But there is two significant and dangerous differencies between them: + * 1) TDuration is never negative and use saturation between 0 and maximum value. + * std::chrono::duration can be negative and can overflow. + * 2) TDuration uses integer number of microseconds. + * std::chrono::duration is flexible, can be integer of floating point, + * can have different precisions. + * So when casted from std::chrono::duration to TDuration value is clamped and rounded. + * In arithmethic operations std::chrono::duration argument is only rounded, + * result is TDuration and it clamped and rounded. + * In comparisons std::chrono::duration argument is rounded. + */ + template <typename T, typename TRatio> + constexpr TDuration(std::chrono::duration<T, TRatio> duration) noexcept { + static_assert( + std::ratio_greater_equal<TRatio, std::micro>::value && + (!std::is_floating_point<T>::value || std::ratio_greater<TRatio, std::micro>::value), + "Extremely likely it is loss of precision, because TDuration stores microseconds. " + "Cast you duration explicitly to microseconds if you really need it."); + + if (duration.count() < 0) { + *this = TDuration::Zero(); // clamp from the bottom + } else { + if +#if !defined(__NVCC__) + constexpr +#endif + /* if [constexpr] */ (std::ratio_greater<TRatio, std::micro>::value || std::is_floating_point<T>::value) { + // clamp from the top + using TCommonDuration = std::chrono::duration<typename std::common_type<T, TValue>::type, TRatio>; + constexpr auto maxDuration = std::chrono::duration<TValue, std::micro>(::Max<TValue>()); + if (std::chrono::duration_cast<TCommonDuration>(duration) >= std::chrono::duration_cast<TCommonDuration>(maxDuration)) { + *this = TDuration::Max(); + return; + } + } + const TValue us = std::chrono::duration_cast<std::chrono::duration<TValue, std::micro>>(duration).count(); + *this = TDuration::MicroSeconds(us); + } + } + static constexpr TDuration FromValue(TValue value) noexcept { return TDuration(value); } @@ -667,110 +667,110 @@ constexpr TDuration operator+(const TDuration& l, const TDuration& r) noexcept { return TDuration::FromValue(::NDateTimeHelpers::SumWithSaturation(l.GetValue(), r.GetValue())); } -template <typename T, typename TRatio> -constexpr bool operator==(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { - return r.count() >= 0 && l == TDuration(r); -} - -#if defined(__cpp_lib_three_way_comparison) - -template <typename T, typename TRatio> -constexpr std::strong_ordering operator<=>(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { - if (r.count() < 0) { - return std::strong_ordering::greater; - } - return l.GetValue() <=> TDuration(r).GetValue(); -} - -#else - -template <typename T, typename TRatio> -constexpr bool operator<(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { - return r.count() >= 0 && l < TDuration(r); -} - -template <typename T, typename TRatio> -constexpr bool operator<=(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { - return r.count() >= 0 && l <= TDuration(r); -} - -template <typename T, typename TRatio> -constexpr bool operator!=(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { - return !(l == r); -} - -template <typename T, typename TRatio> -constexpr bool operator>(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { - return r.count() < 0 || l > TDuration(r); -} - -template <typename T, typename TRatio> -constexpr bool operator>=(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { - return r.count() < 0 || l >= TDuration(r); -} - -template <typename T, typename TRatio> -constexpr bool operator<(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { - return r > l; -} - -template <typename T, typename TRatio> -constexpr bool operator<=(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { - return r >= l; -} - -template <typename T, typename TRatio> -constexpr bool operator==(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { - return r == l; -} - -template <typename T, typename TRatio> -constexpr bool operator!=(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { - return r != l; -} - -template <typename T, typename TRatio> -constexpr bool operator>(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { - return r < l; -} - -template <typename T, typename TRatio> -constexpr bool operator>=(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { - return r >= l; -} - -#endif - -template <typename T, typename TRatio> -constexpr TDuration operator+(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { - return r < r.zero() ? l - TDuration(-r) : l + TDuration(r); -} - -template <typename T, typename TRatio> -constexpr TDuration operator+(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { - return r + l; -} - -template <typename T, typename TRatio> -constexpr TDuration operator-(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { - return l + (-r); -} - -template <typename T, typename TRatio> -constexpr TDuration operator-(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { - return TDuration(l) - r; -} - -template <typename T, typename TRatio> -constexpr TInstant operator+(const TInstant& l, const std::chrono::duration<T, TRatio>& r) noexcept { - return r < r.zero() ? l - TDuration(-r) : l + TDuration(r); -} - -template <typename T, typename TRatio> -constexpr TInstant operator-(const TInstant& l, const std::chrono::duration<T, TRatio>& r) noexcept { - return l + (-r); -} - +template <typename T, typename TRatio> +constexpr bool operator==(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { + return r.count() >= 0 && l == TDuration(r); +} + +#if defined(__cpp_lib_three_way_comparison) + +template <typename T, typename TRatio> +constexpr std::strong_ordering operator<=>(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { + if (r.count() < 0) { + return std::strong_ordering::greater; + } + return l.GetValue() <=> TDuration(r).GetValue(); +} + +#else + +template <typename T, typename TRatio> +constexpr bool operator<(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { + return r.count() >= 0 && l < TDuration(r); +} + +template <typename T, typename TRatio> +constexpr bool operator<=(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { + return r.count() >= 0 && l <= TDuration(r); +} + +template <typename T, typename TRatio> +constexpr bool operator!=(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { + return !(l == r); +} + +template <typename T, typename TRatio> +constexpr bool operator>(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { + return r.count() < 0 || l > TDuration(r); +} + +template <typename T, typename TRatio> +constexpr bool operator>=(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { + return r.count() < 0 || l >= TDuration(r); +} + +template <typename T, typename TRatio> +constexpr bool operator<(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { + return r > l; +} + +template <typename T, typename TRatio> +constexpr bool operator<=(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { + return r >= l; +} + +template <typename T, typename TRatio> +constexpr bool operator==(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { + return r == l; +} + +template <typename T, typename TRatio> +constexpr bool operator!=(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { + return r != l; +} + +template <typename T, typename TRatio> +constexpr bool operator>(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { + return r < l; +} + +template <typename T, typename TRatio> +constexpr bool operator>=(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { + return r >= l; +} + +#endif + +template <typename T, typename TRatio> +constexpr TDuration operator+(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { + return r < r.zero() ? l - TDuration(-r) : l + TDuration(r); +} + +template <typename T, typename TRatio> +constexpr TDuration operator+(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { + return r + l; +} + +template <typename T, typename TRatio> +constexpr TDuration operator-(const TDuration& l, const std::chrono::duration<T, TRatio>& r) noexcept { + return l + (-r); +} + +template <typename T, typename TRatio> +constexpr TDuration operator-(const std::chrono::duration<T, TRatio>& l, const TDuration& r) noexcept { + return TDuration(l) - r; +} + +template <typename T, typename TRatio> +constexpr TInstant operator+(const TInstant& l, const std::chrono::duration<T, TRatio>& r) noexcept { + return r < r.zero() ? l - TDuration(-r) : l + TDuration(r); +} + +template <typename T, typename TRatio> +constexpr TInstant operator-(const TInstant& l, const std::chrono::duration<T, TRatio>& r) noexcept { + return l + (-r); +} + template <class T> inline TDuration operator*(TDuration d, T t) noexcept { Y_ASSERT(t >= T()); diff --git a/util/datetime/base_ut.cpp b/util/datetime/base_ut.cpp index 8a7e6976b6..afc3f802eb 100644 --- a/util/datetime/base_ut.cpp +++ b/util/datetime/base_ut.cpp @@ -12,8 +12,8 @@ #include <limits.h> -using namespace std::chrono_literals; - +using namespace std::chrono_literals; + struct TTestTime { const time_t T_ = 987654321; const char* Date_ = "Thu Apr 19 04:25:21 2001\n"; @@ -530,125 +530,125 @@ Y_UNIT_TEST_SUITE(DateTimeTest) { "incorrect date " << (1900 + time.tm_year) << "-" << (time.tm_mon + 1) << "-" << time.tm_mday); } } - - Y_UNIT_TEST(TestTDurationConstructorFromStdChronoDuration) { - - UNIT_ASSERT_VALUES_EQUAL(TDuration::Zero(), TDuration(0ms)); - UNIT_ASSERT_VALUES_EQUAL(TDuration::MicroSeconds(42), TDuration(42us)); - UNIT_ASSERT_VALUES_EQUAL(TDuration::MicroSeconds(42000000000000L), TDuration(42000000000000us)); - UNIT_ASSERT_VALUES_EQUAL(TDuration::MilliSeconds(42), TDuration(42ms)); - UNIT_ASSERT_VALUES_EQUAL(TDuration::MilliSeconds(42.75), TDuration(42.75ms)); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(42), TDuration(42s)); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(42.25), TDuration(42.25s)); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Minutes(42), TDuration(42min)); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Hours(42), TDuration(42h)); - - // TDuration doesn't support negative durations - UNIT_ASSERT_VALUES_EQUAL(TDuration::Zero(), TDuration(-5min)); - - UNIT_ASSERT_VALUES_EQUAL(TDuration::MilliSeconds(5), TDuration(std::chrono::duration<i8, std::milli>{5ms})); - + + Y_UNIT_TEST(TestTDurationConstructorFromStdChronoDuration) { + + UNIT_ASSERT_VALUES_EQUAL(TDuration::Zero(), TDuration(0ms)); + UNIT_ASSERT_VALUES_EQUAL(TDuration::MicroSeconds(42), TDuration(42us)); + UNIT_ASSERT_VALUES_EQUAL(TDuration::MicroSeconds(42000000000000L), TDuration(42000000000000us)); + UNIT_ASSERT_VALUES_EQUAL(TDuration::MilliSeconds(42), TDuration(42ms)); + UNIT_ASSERT_VALUES_EQUAL(TDuration::MilliSeconds(42.75), TDuration(42.75ms)); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(42), TDuration(42s)); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(42.25), TDuration(42.25s)); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Minutes(42), TDuration(42min)); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Hours(42), TDuration(42h)); + + // TDuration doesn't support negative durations + UNIT_ASSERT_VALUES_EQUAL(TDuration::Zero(), TDuration(-5min)); + + UNIT_ASSERT_VALUES_EQUAL(TDuration::MilliSeconds(5), TDuration(std::chrono::duration<i8, std::milli>{5ms})); + #if defined(_LIBCPP_STD_VER) && _LIBCPP_STD_VER > 17 // libstdc++ does not provide std::chrono::days at the time // Consider removing this code upon OS_SDK update - UNIT_ASSERT_VALUES_EQUAL(TDuration::Days(1), TDuration(std::chrono::days{1})); -#endif - - // clump - UNIT_ASSERT_VALUES_EQUAL(TDuration::Zero(), TDuration(std::chrono::duration<i64>{-1})); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Zero(), TDuration(std::chrono::duration<double>{-1})); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), - TDuration(std::chrono::duration<ui64, std::ratio<3600>>{static_cast<ui64>(1e18)})); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), - TDuration(std::chrono::duration<i64, std::milli>{static_cast<i64>(::Max<ui64>() / 1000)})); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), - TDuration(std::chrono::duration<double, std::ratio<3600>>{1e18})); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), - TDuration(std::chrono::duration<double, std::milli>{::Max<ui64>() / 1000})); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), TDuration(std::chrono::duration<double, std::milli>{ - static_cast<double>(::Max<ui64>()) / 1000 + 0.1})); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), TDuration(std::chrono::duration<float, std::milli>{ - static_cast<float>(::Max<ui64>()) / 1000 + 0.1})); - } - - Y_UNIT_TEST(TestTDurationCompareWithStdChronoDuration) { - UNIT_ASSERT(TDuration::Zero() == 0ms); - UNIT_ASSERT(TDuration::Seconds(42) == 42s); - - UNIT_ASSERT(0ms == TDuration::Zero()); - - UNIT_ASSERT(TDuration::Zero() != 1ms); - UNIT_ASSERT(TDuration::Zero() != -1ms); - UNIT_ASSERT(TDuration::MilliSeconds(1) != -1ms); - UNIT_ASSERT(TDuration::MilliSeconds(1) != -1ms); - - UNIT_ASSERT(1ms != TDuration::Zero()); - - UNIT_ASSERT(TDuration::Seconds(2) < 3s); - UNIT_ASSERT(3s > TDuration::Seconds(2)); - UNIT_ASSERT(!(TDuration::Seconds(2) < 1s)); - UNIT_ASSERT(!(TDuration::Seconds(2) < -3s)); - UNIT_ASSERT(!(TDuration::Seconds(2) < 2s)); - - UNIT_ASSERT(2s < TDuration::Seconds(3)); - - UNIT_ASSERT(TDuration::Seconds(2) <= 3s); - UNIT_ASSERT(!(TDuration::Seconds(2) <= 1s)); - UNIT_ASSERT(!(TDuration::Seconds(2) <= -3s)); - UNIT_ASSERT(TDuration::Seconds(2) <= 2s); - - UNIT_ASSERT(2s <= TDuration::Seconds(2)); - - UNIT_ASSERT(TDuration::Seconds(2) > -2s); - UNIT_ASSERT(TDuration::Seconds(2) > 1s); - UNIT_ASSERT(TDuration::Seconds(2) > 0s); - UNIT_ASSERT(!(TDuration::Seconds(2) > 3s)); - UNIT_ASSERT(!(TDuration::Seconds(2) > 2s)); - - UNIT_ASSERT(2s > TDuration::Seconds(1)); - - UNIT_ASSERT(TDuration::Seconds(2) >= -2s); - UNIT_ASSERT(TDuration::Seconds(2) >= 1s); - UNIT_ASSERT(TDuration::Seconds(2) >= 0s); - UNIT_ASSERT(!(TDuration::Seconds(2) >= 3s)); - UNIT_ASSERT(TDuration::Seconds(2) >= 2s); - - UNIT_ASSERT(2s >= TDuration::Seconds(2)); - - static_assert(TDuration::Zero() == 0ms); - static_assert(TDuration::Zero() < 1ms); - } - - Y_UNIT_TEST(TestAdditionOfStdChronoDuration) { - UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(1) + 2s, TDuration::Seconds(3)); - UNIT_ASSERT_VALUES_EQUAL(2s + TDuration::Seconds(1), TDuration::Seconds(3)); - UNIT_ASSERT_VALUES_EQUAL(-2s + TDuration::Seconds(3), TDuration::Seconds(1)); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(3) + (-2s), TDuration::Seconds(1)); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(3) - 2s, TDuration::Seconds(1)); - UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(1) - (-2s), TDuration::Seconds(3)); - UNIT_ASSERT_VALUES_EQUAL(3s - TDuration::Seconds(2), TDuration::Seconds(1)); - UNIT_ASSERT_VALUES_EQUAL(3s - TDuration::Seconds(4), TDuration::Zero()); - - UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(1) + 2s, TInstant::Seconds(3)); - UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(3) + (-2s), TInstant::Seconds(1)); - UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(3) - 2s, TInstant::Seconds(1)); - UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(1) - (-2s), TInstant::Seconds(3)); - - // Operations between TDuration/TInstant and std::chrono::duration are performed - // with saturation according to the rules of TDuration/TInstant - UNIT_ASSERT_VALUES_EQUAL(TDuration::Max() + 1h, TDuration::Max()); - UNIT_ASSERT_VALUES_EQUAL(TInstant::Max() + 1h, TInstant::Max()); - UNIT_ASSERT_VALUES_EQUAL(1h + TDuration::Max(), TDuration::Max()); - UNIT_ASSERT_VALUES_EQUAL(TInstant::Max() + 1h, TInstant::Max()); - - UNIT_ASSERT_VALUES_EQUAL(TDuration::Max() - (-1h), TDuration::Max()); - UNIT_ASSERT_VALUES_EQUAL(TInstant::Max() - (-1h), TInstant::Max()); - UNIT_ASSERT_VALUES_EQUAL(TInstant::Max() - (-1h), TInstant::Max()); - - UNIT_ASSERT_VALUES_EQUAL(-1h - TDuration::Max(), TDuration::Zero()); - UNIT_ASSERT_VALUES_EQUAL(1h - TDuration::Max(), TDuration::Zero()); - - static_assert(TDuration::Zero() + 1s == 1s); - static_assert(TInstant::Seconds(1) + 1s == TInstant::Seconds(2)); - } + UNIT_ASSERT_VALUES_EQUAL(TDuration::Days(1), TDuration(std::chrono::days{1})); +#endif + + // clump + UNIT_ASSERT_VALUES_EQUAL(TDuration::Zero(), TDuration(std::chrono::duration<i64>{-1})); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Zero(), TDuration(std::chrono::duration<double>{-1})); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), + TDuration(std::chrono::duration<ui64, std::ratio<3600>>{static_cast<ui64>(1e18)})); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), + TDuration(std::chrono::duration<i64, std::milli>{static_cast<i64>(::Max<ui64>() / 1000)})); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), + TDuration(std::chrono::duration<double, std::ratio<3600>>{1e18})); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), + TDuration(std::chrono::duration<double, std::milli>{::Max<ui64>() / 1000})); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), TDuration(std::chrono::duration<double, std::milli>{ + static_cast<double>(::Max<ui64>()) / 1000 + 0.1})); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Max(), TDuration(std::chrono::duration<float, std::milli>{ + static_cast<float>(::Max<ui64>()) / 1000 + 0.1})); + } + + Y_UNIT_TEST(TestTDurationCompareWithStdChronoDuration) { + UNIT_ASSERT(TDuration::Zero() == 0ms); + UNIT_ASSERT(TDuration::Seconds(42) == 42s); + + UNIT_ASSERT(0ms == TDuration::Zero()); + + UNIT_ASSERT(TDuration::Zero() != 1ms); + UNIT_ASSERT(TDuration::Zero() != -1ms); + UNIT_ASSERT(TDuration::MilliSeconds(1) != -1ms); + UNIT_ASSERT(TDuration::MilliSeconds(1) != -1ms); + + UNIT_ASSERT(1ms != TDuration::Zero()); + + UNIT_ASSERT(TDuration::Seconds(2) < 3s); + UNIT_ASSERT(3s > TDuration::Seconds(2)); + UNIT_ASSERT(!(TDuration::Seconds(2) < 1s)); + UNIT_ASSERT(!(TDuration::Seconds(2) < -3s)); + UNIT_ASSERT(!(TDuration::Seconds(2) < 2s)); + + UNIT_ASSERT(2s < TDuration::Seconds(3)); + + UNIT_ASSERT(TDuration::Seconds(2) <= 3s); + UNIT_ASSERT(!(TDuration::Seconds(2) <= 1s)); + UNIT_ASSERT(!(TDuration::Seconds(2) <= -3s)); + UNIT_ASSERT(TDuration::Seconds(2) <= 2s); + + UNIT_ASSERT(2s <= TDuration::Seconds(2)); + + UNIT_ASSERT(TDuration::Seconds(2) > -2s); + UNIT_ASSERT(TDuration::Seconds(2) > 1s); + UNIT_ASSERT(TDuration::Seconds(2) > 0s); + UNIT_ASSERT(!(TDuration::Seconds(2) > 3s)); + UNIT_ASSERT(!(TDuration::Seconds(2) > 2s)); + + UNIT_ASSERT(2s > TDuration::Seconds(1)); + + UNIT_ASSERT(TDuration::Seconds(2) >= -2s); + UNIT_ASSERT(TDuration::Seconds(2) >= 1s); + UNIT_ASSERT(TDuration::Seconds(2) >= 0s); + UNIT_ASSERT(!(TDuration::Seconds(2) >= 3s)); + UNIT_ASSERT(TDuration::Seconds(2) >= 2s); + + UNIT_ASSERT(2s >= TDuration::Seconds(2)); + + static_assert(TDuration::Zero() == 0ms); + static_assert(TDuration::Zero() < 1ms); + } + + Y_UNIT_TEST(TestAdditionOfStdChronoDuration) { + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(1) + 2s, TDuration::Seconds(3)); + UNIT_ASSERT_VALUES_EQUAL(2s + TDuration::Seconds(1), TDuration::Seconds(3)); + UNIT_ASSERT_VALUES_EQUAL(-2s + TDuration::Seconds(3), TDuration::Seconds(1)); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(3) + (-2s), TDuration::Seconds(1)); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(3) - 2s, TDuration::Seconds(1)); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(1) - (-2s), TDuration::Seconds(3)); + UNIT_ASSERT_VALUES_EQUAL(3s - TDuration::Seconds(2), TDuration::Seconds(1)); + UNIT_ASSERT_VALUES_EQUAL(3s - TDuration::Seconds(4), TDuration::Zero()); + + UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(1) + 2s, TInstant::Seconds(3)); + UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(3) + (-2s), TInstant::Seconds(1)); + UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(3) - 2s, TInstant::Seconds(1)); + UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(1) - (-2s), TInstant::Seconds(3)); + + // Operations between TDuration/TInstant and std::chrono::duration are performed + // with saturation according to the rules of TDuration/TInstant + UNIT_ASSERT_VALUES_EQUAL(TDuration::Max() + 1h, TDuration::Max()); + UNIT_ASSERT_VALUES_EQUAL(TInstant::Max() + 1h, TInstant::Max()); + UNIT_ASSERT_VALUES_EQUAL(1h + TDuration::Max(), TDuration::Max()); + UNIT_ASSERT_VALUES_EQUAL(TInstant::Max() + 1h, TInstant::Max()); + + UNIT_ASSERT_VALUES_EQUAL(TDuration::Max() - (-1h), TDuration::Max()); + UNIT_ASSERT_VALUES_EQUAL(TInstant::Max() - (-1h), TInstant::Max()); + UNIT_ASSERT_VALUES_EQUAL(TInstant::Max() - (-1h), TInstant::Max()); + + UNIT_ASSERT_VALUES_EQUAL(-1h - TDuration::Max(), TDuration::Zero()); + UNIT_ASSERT_VALUES_EQUAL(1h - TDuration::Max(), TDuration::Zero()); + + static_assert(TDuration::Zero() + 1s == 1s); + static_assert(TInstant::Seconds(1) + 1s == TInstant::Seconds(2)); + } } diff --git a/util/generic/adaptor.h b/util/generic/adaptor.h index b89c1f81e5..b88a65fc81 100644 --- a/util/generic/adaptor.h +++ b/util/generic/adaptor.h @@ -1,6 +1,6 @@ #pragma once -#include "store_policy.h" +#include "store_policy.h" #include "typetraits.h" namespace NPrivate { @@ -42,23 +42,23 @@ namespace NPrivate { using TBase::Base; using TBase::TBase; - auto begin() const { + auto begin() const { return Base().rbegin(); } - auto end() const { + auto end() const { return Base().rend(); - } - - auto begin() { + } + + auto begin() { return Base().rbegin(); - } - - auto end() { + } + + auto end() { return Base().rend(); - } - }; - + } + }; + template <class Range> class TReverseRangeBase<Range, false>: public TReverseRangeStorage<Range> { using TBase = TReverseRangeStorage<Range>; @@ -68,26 +68,26 @@ namespace NPrivate { using TBase::TBase; auto begin() const { - using std::end; + using std::end; return std::make_reverse_iterator(end(Base())); } auto end() const { - using std::begin; + using std::begin; return std::make_reverse_iterator(begin(Base())); } auto begin() { - using std::end; + using std::end; return std::make_reverse_iterator(end(Base())); } auto end() { - using std::begin; + using std::begin; return std::make_reverse_iterator(begin(Base())); } }; - + template <class Range> class TReverseRange: public TReverseRangeBase<Range> { using TBase = TReverseRangeBase<Range>; @@ -95,30 +95,30 @@ namespace NPrivate { public: using TBase::Base; using TBase::TBase; - + TReverseRange(TReverseRange&&) = default; TReverseRange(const TReverseRange&) = default; - - auto rbegin() const { - using std::begin; + + auto rbegin() const { + using std::begin; return begin(Base()); - } - - auto rend() const { - using std::end; + } + + auto rend() const { + using std::end; return end(Base()); - } - - auto rbegin() { - using std::begin; + } + + auto rbegin() { + using std::begin; return begin(Base()); - } - - auto rend() { - using std::end; + } + + auto rend() { + using std::end; return end(Base()); - } - }; + } + }; } /** diff --git a/util/generic/adaptor_ut.cpp b/util/generic/adaptor_ut.cpp index ff980632b4..721f849f93 100644 --- a/util/generic/adaptor_ut.cpp +++ b/util/generic/adaptor_ut.cpp @@ -40,10 +40,10 @@ Y_UNIT_TEST_SUITE(TReverseAdaptor) { for (const auto& x : Reversed(cont)) { UNIT_ASSERT_VALUES_EQUAL(etalon[idx++], x); } - idx = 0; - for (const auto& x : Reversed(std::move(cont))) { - UNIT_ASSERT_VALUES_EQUAL(etalon[idx++], x); - } + idx = 0; + for (const auto& x : Reversed(std::move(cont))) { + UNIT_ASSERT_VALUES_EQUAL(etalon[idx++], x); + } } Y_UNIT_TEST(WriteTest) { @@ -75,50 +75,50 @@ Y_UNIT_TEST_SUITE(TReverseAdaptor) { UNIT_ASSERT_NO_EXCEPTION(Reversed(lvalue)); UNIT_ASSERT_NO_EXCEPTION(Reversed(clvalue)); } - - Y_UNIT_TEST(ReverseX2Test) { - TVector<int> cont = {1, 2, 3}; - size_t idx = 0; - for (const auto& x : Reversed(Reversed(cont))) { - UNIT_ASSERT_VALUES_EQUAL(cont[idx++], x); - } - } - - Y_UNIT_TEST(ReverseX3Test) { - TVector<int> cont = {1, 2, 3}; - TVector<int> etalon = {3, 2, 1}; - size_t idx = 0; - for (const auto& x : Reversed(Reversed(Reversed(cont)))) { - UNIT_ASSERT_VALUES_EQUAL(etalon[idx++], x); - } - } - - Y_UNIT_TEST(ReverseTemporaryTest) { - TVector<int> etalon = {3, 2, 1}; - TVector<int> etalon2 = {1, 2, 3}; - size_t idx = 0; - for (const auto& x : Reversed(TVector<int>{1, 2, 3})) { - UNIT_ASSERT_VALUES_EQUAL(etalon[idx++], x); - } - idx = 0; - for (const auto& x : Reversed(Reversed(TVector<int>{1, 2, 3}))) { - UNIT_ASSERT_VALUES_EQUAL(etalon2[idx++], x); - } - } - - Y_UNIT_TEST(ReverseInitializerListTest) { - // initializer_list has no rbegin and rend - auto cont = {1, 2, 3}; - TVector<int> etalon = {3, 2, 1}; - TVector<int> etalon2 = {1, 2, 3}; - - size_t idx = 0; - for (const auto& x : Reversed(cont)) { - UNIT_ASSERT_VALUES_EQUAL(etalon[idx++], x); - } - idx = 0; - for (const auto& x : Reversed(Reversed(cont))) { - UNIT_ASSERT_VALUES_EQUAL(etalon2[idx++], x); - } - } + + Y_UNIT_TEST(ReverseX2Test) { + TVector<int> cont = {1, 2, 3}; + size_t idx = 0; + for (const auto& x : Reversed(Reversed(cont))) { + UNIT_ASSERT_VALUES_EQUAL(cont[idx++], x); + } + } + + Y_UNIT_TEST(ReverseX3Test) { + TVector<int> cont = {1, 2, 3}; + TVector<int> etalon = {3, 2, 1}; + size_t idx = 0; + for (const auto& x : Reversed(Reversed(Reversed(cont)))) { + UNIT_ASSERT_VALUES_EQUAL(etalon[idx++], x); + } + } + + Y_UNIT_TEST(ReverseTemporaryTest) { + TVector<int> etalon = {3, 2, 1}; + TVector<int> etalon2 = {1, 2, 3}; + size_t idx = 0; + for (const auto& x : Reversed(TVector<int>{1, 2, 3})) { + UNIT_ASSERT_VALUES_EQUAL(etalon[idx++], x); + } + idx = 0; + for (const auto& x : Reversed(Reversed(TVector<int>{1, 2, 3}))) { + UNIT_ASSERT_VALUES_EQUAL(etalon2[idx++], x); + } + } + + Y_UNIT_TEST(ReverseInitializerListTest) { + // initializer_list has no rbegin and rend + auto cont = {1, 2, 3}; + TVector<int> etalon = {3, 2, 1}; + TVector<int> etalon2 = {1, 2, 3}; + + size_t idx = 0; + for (const auto& x : Reversed(cont)) { + UNIT_ASSERT_VALUES_EQUAL(etalon[idx++], x); + } + idx = 0; + for (const auto& x : Reversed(Reversed(cont))) { + UNIT_ASSERT_VALUES_EQUAL(etalon2[idx++], x); + } + } } diff --git a/util/generic/algorithm.h b/util/generic/algorithm.h index d183d4ab00..badfb88993 100644 --- a/util/generic/algorithm.h +++ b/util/generic/algorithm.h @@ -638,11 +638,11 @@ inline typename std::iterator_traits<T>::difference_type Count(T first, T last, return std::count(first, last, value); } -template <class TContainer, class TValue> -static inline auto Count(const TContainer& container, const TValue& value) { - return Count(std::cbegin(container), std::cend(container), value); -} - +template <class TContainer, class TValue> +static inline auto Count(const TContainer& container, const TValue& value) { + return Count(std::cbegin(container), std::cend(container), value); +} + template <class It, class P> static inline auto CountIf(It first, It last, P p) { return std::count_if(first, last, p); @@ -753,13 +753,13 @@ template <class It> std::pair<It, It> MinMaxElement(It first, It last) { return std::minmax_element(first, last); } - -template <class TIterator, class TGenerator> -void Generate(TIterator first, TIterator last, TGenerator generator) { - std::generate(first, last, generator); -} - -template <class TIterator, class TSize, class TGenerator> -void GenerateN(TIterator first, TSize count, TGenerator generator) { - std::generate_n(first, count, generator); -} + +template <class TIterator, class TGenerator> +void Generate(TIterator first, TIterator last, TGenerator generator) { + std::generate(first, last, generator); +} + +template <class TIterator, class TSize, class TGenerator> +void GenerateN(TIterator first, TSize count, TGenerator generator) { + std::generate_n(first, count, generator); +} diff --git a/util/generic/algorithm_ut.cpp b/util/generic/algorithm_ut.cpp index 2473adb021..8d732fcc0c 100644 --- a/util/generic/algorithm_ut.cpp +++ b/util/generic/algorithm_ut.cpp @@ -44,18 +44,18 @@ Y_UNIT_TEST_SUITE(TAlgorithm) { UNIT_ASSERT(3 == CountIf(array, isOne)); } - Y_UNIT_TEST(CountTest) { - UNIT_ASSERT(3 == Count("____1________1____1_______", '1')); + Y_UNIT_TEST(CountTest) { + UNIT_ASSERT(3 == Count("____1________1____1_______", '1')); UNIT_ASSERT(3 == Count(TStringBuf("____1________1____1_______"), '1')); UNIT_ASSERT(5 == Count(TStringBuf("1____1________1____1_______1"), '1')); UNIT_ASSERT(0 == Count(TStringBuf("___________"), '1')); - UNIT_ASSERT(0 == Count(TStringBuf(), '1')); + UNIT_ASSERT(0 == Count(TStringBuf(), '1')); UNIT_ASSERT(1 == Count(TStringBuf("1"), '1')); const char array[] = "____1________1____1_______"; UNIT_ASSERT(3 == Count(array, '1')); - } - + } + struct TStrokaNoCopy: TString { public: TStrokaNoCopy(const char* p) diff --git a/util/generic/iterator_range.h b/util/generic/iterator_range.h index c03ec723a2..9f4d02da29 100644 --- a/util/generic/iterator_range.h +++ b/util/generic/iterator_range.h @@ -5,44 +5,44 @@ #include <iterator> #include <utility> -template <typename TBegin, typename TEnd = TBegin> -struct TIteratorRange { - using TElement = std::remove_reference_t<decltype(*std::declval<TBegin>())>; - - TIteratorRange(TBegin begin, TEnd end) - : Begin_(begin) - , End_(end) - { - } - - TIteratorRange() - : TIteratorRange(TBegin{}, TEnd{}) - { - } - - TBegin begin() const { - return Begin_; - } - - TEnd end() const { - return End_; - } - - bool empty() const { - // because range based for requires exactly '!=' - return !(Begin_ != End_); - } - -private: - TBegin Begin_; - TEnd End_; -}; - -template <class TIterator> -class TIteratorRange<TIterator, TIterator> { +template <typename TBegin, typename TEnd = TBegin> +struct TIteratorRange { + using TElement = std::remove_reference_t<decltype(*std::declval<TBegin>())>; + + TIteratorRange(TBegin begin, TEnd end) + : Begin_(begin) + , End_(end) + { + } + + TIteratorRange() + : TIteratorRange(TBegin{}, TEnd{}) + { + } + + TBegin begin() const { + return Begin_; + } + + TEnd end() const { + return End_; + } + + bool empty() const { + // because range based for requires exactly '!=' + return !(Begin_ != End_); + } + +private: + TBegin Begin_; + TEnd End_; +}; + +template <class TIterator> +class TIteratorRange<TIterator, TIterator> { public: - using iterator = TIterator; - using const_iterator = TIterator; + using iterator = TIterator; + using const_iterator = TIterator; using value_type = typename std::iterator_traits<iterator>::value_type; using reference = typename std::iterator_traits<iterator>::reference; using const_reference = typename std::iterator_traits<const_iterator>::reference; @@ -55,17 +55,17 @@ public: { } - TIteratorRange(TIterator begin, TIterator end) + TIteratorRange(TIterator begin, TIterator end) : Begin_(begin) , End_(end) { } - TIterator begin() const { + TIterator begin() const { return Begin_; } - TIterator end() const { + TIterator end() const { return End_; } @@ -84,21 +84,21 @@ public: } private: - TIterator Begin_; - TIterator End_; + TIterator Begin_; + TIterator End_; }; -template <class TIterator> -TIteratorRange<TIterator> MakeIteratorRange(TIterator begin, TIterator end) { - return TIteratorRange<TIterator>(begin, end); +template <class TIterator> +TIteratorRange<TIterator> MakeIteratorRange(TIterator begin, TIterator end) { + return TIteratorRange<TIterator>(begin, end); +} + +template <class TIterator> +TIteratorRange<TIterator> MakeIteratorRange(const std::pair<TIterator, TIterator>& range) { + return TIteratorRange<TIterator>(range.first, range.second); } -template <class TIterator> -TIteratorRange<TIterator> MakeIteratorRange(const std::pair<TIterator, TIterator>& range) { - return TIteratorRange<TIterator>(range.first, range.second); +template <class TBegin, class TEnd> +TIteratorRange<TBegin, TEnd> MakeIteratorRange(TBegin begin, TEnd end) { + return {begin, end}; } - -template <class TBegin, class TEnd> -TIteratorRange<TBegin, TEnd> MakeIteratorRange(TBegin begin, TEnd end) { - return {begin, end}; -} diff --git a/util/generic/iterator_range_ut.cpp b/util/generic/iterator_range_ut.cpp index 60032745f5..a7e3670ae1 100644 --- a/util/generic/iterator_range_ut.cpp +++ b/util/generic/iterator_range_ut.cpp @@ -10,11 +10,11 @@ Y_UNIT_TEST_SUITE(IteratorRange) { UNIT_ASSERT(range.empty()); } - Y_UNIT_TEST(DefaultConstructorSentinel) { - TIteratorRange<int*, void*> range; - UNIT_ASSERT(range.empty()); - } - + Y_UNIT_TEST(DefaultConstructorSentinel) { + TIteratorRange<int*, void*> range; + UNIT_ASSERT(range.empty()); + } + Y_UNIT_TEST(RangeBasedForLoop) { // compileability test for (int i : TIteratorRange<int*>()) { @@ -22,13 +22,13 @@ Y_UNIT_TEST_SUITE(IteratorRange) { } } - Y_UNIT_TEST(RangeBasedForLoopSentinel) { - // compileability test - for (int i : TIteratorRange<int*, void*>()) { - Y_UNUSED(i); - } - } - + Y_UNIT_TEST(RangeBasedForLoopSentinel) { + // compileability test + for (int i : TIteratorRange<int*, void*>()) { + Y_UNUSED(i); + } + } + Y_UNIT_TEST(Works) { const int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; auto range = MakeIteratorRange(values, values + Y_ARRAY_SIZE(values)); @@ -37,37 +37,37 @@ Y_UNIT_TEST_SUITE(IteratorRange) { UNIT_ASSERT(!range.empty()); } - Y_UNIT_TEST(WorksSentinel) { - struct TRangeSentinel { - }; - - struct TEnumerator { - ui32 operator*() const { - return Cur; - } - - void operator++() { - ++Cur; - } - - bool operator!=(const TRangeSentinel&) const { - return Cur < End; - } - - ui32 Cur; - ui32 End; - }; - - auto range = MakeIteratorRange(TEnumerator{0, 10}, TRangeSentinel{}); - UNIT_ASSERT(!range.empty()); - - ui32 i = 0; - for (auto j : range) { - UNIT_ASSERT_VALUES_EQUAL(j, i++); - } - UNIT_ASSERT_VALUES_EQUAL(i, 10); - } - + Y_UNIT_TEST(WorksSentinel) { + struct TRangeSentinel { + }; + + struct TEnumerator { + ui32 operator*() const { + return Cur; + } + + void operator++() { + ++Cur; + } + + bool operator!=(const TRangeSentinel&) const { + return Cur < End; + } + + ui32 Cur; + ui32 End; + }; + + auto range = MakeIteratorRange(TEnumerator{0, 10}, TRangeSentinel{}); + UNIT_ASSERT(!range.empty()); + + ui32 i = 0; + for (auto j : range) { + UNIT_ASSERT_VALUES_EQUAL(j, i++); + } + UNIT_ASSERT_VALUES_EQUAL(i, 10); + } + Y_UNIT_TEST(OperatorsAndReferences) { TVector<size_t> values{1, 2, 3, 4, 5}; auto range = MakeIteratorRange(values.begin(), values.end()); diff --git a/util/generic/store_policy.h b/util/generic/store_policy.h index c3c88c1e14..148821c70c 100644 --- a/util/generic/store_policy.h +++ b/util/generic/store_policy.h @@ -14,20 +14,20 @@ struct TWithRefCount: public TBase, public TRefCounted<TWithRefCount<TBase, TCou template <class T> struct TPtrPolicy { - inline TPtrPolicy(T* t) + inline TPtrPolicy(T* t) : T_(t) { } - inline T* Ptr() noexcept { - return T_; - } - + inline T* Ptr() noexcept { + return T_; + } + inline const T* Ptr() const noexcept { return T_; } - T* T_; + T* T_; }; template <class T> @@ -70,49 +70,49 @@ struct TRefPolicy { TIntrusivePtr<THelper> T_; }; -/** +/** * Storage class that can be handy for implementing proxies / adaptors that can * accept both lvalues and rvalues. In the latter case it's often required to * extend the lifetime of the passed rvalue, and the only option is to store it * in your proxy / adaptor. - * - * Example usage: - * \code - * template<class T> - * struct TProxy { - * TAutoEmbedOrPtrPolicy<T> Value_; - * // Your proxy code... - * }; - * - * template<class T> - * TProxy<T> MakeProxy(T&& value) { - * // Rvalues are automagically moved-from, and stored inside the proxy. + * + * Example usage: + * \code + * template<class T> + * struct TProxy { + * TAutoEmbedOrPtrPolicy<T> Value_; + * // Your proxy code... + * }; + * + * template<class T> + * TProxy<T> MakeProxy(T&& value) { + * // Rvalues are automagically moved-from, and stored inside the proxy. * return {std::forward<T>(value)}; - * } - * \endcode - * - * Look at `Reversed` in `adaptor.h` for real example. - */ + * } + * \endcode + * + * Look at `Reversed` in `adaptor.h` for real example. + */ template <class T, bool IsReference = std::is_reference<T>::value> struct TAutoEmbedOrPtrPolicy: TPtrPolicy<std::remove_reference_t<T>> { using TBase = TPtrPolicy<std::remove_reference_t<T>>; - + TAutoEmbedOrPtrPolicy(T& reference) : TBase(&reference) - { - } -}; - + { + } +}; + template <class T> struct TAutoEmbedOrPtrPolicy<T, false>: TEmbedPolicy<T> { using TBase = TEmbedPolicy<T>; - + TAutoEmbedOrPtrPolicy(T&& object) : TBase(std::move(object)) - { - } -}; - + { + } +}; + template <class T> using TAtomicRefPolicy = TRefPolicy<T, TAtomicCounter>; diff --git a/util/generic/store_policy_ut.cpp b/util/generic/store_policy_ut.cpp index 30710dc913..c9722203aa 100644 --- a/util/generic/store_policy_ut.cpp +++ b/util/generic/store_policy_ut.cpp @@ -1,87 +1,87 @@ -#include "store_policy.h" - +#include "store_policy.h" + #include <library/cpp/testing/unittest/registar.h> -#include <util/generic/algorithm.h> -#include <util/generic/vector.h> - -Y_UNIT_TEST_SUITE(StorePolicy) { - Y_UNIT_TEST(Compileability) { - // construction - TAutoEmbedOrPtrPolicy<THolder<int>>(MakeHolder<int>(1)); - TAutoEmbedOrPtrPolicy<TVector<int>>(TVector<int>{1, 2, 3}); - auto a = MakeHolder<int>(42); - TAutoEmbedOrPtrPolicy<THolder<int>&>{a}; - - // const - (**TAutoEmbedOrPtrPolicy<THolder<int>>(MakeHolder<int>(1)).Ptr())++; // ok +#include <util/generic/algorithm.h> +#include <util/generic/vector.h> + +Y_UNIT_TEST_SUITE(StorePolicy) { + Y_UNIT_TEST(Compileability) { + // construction + TAutoEmbedOrPtrPolicy<THolder<int>>(MakeHolder<int>(1)); + TAutoEmbedOrPtrPolicy<TVector<int>>(TVector<int>{1, 2, 3}); + auto a = MakeHolder<int>(42); + TAutoEmbedOrPtrPolicy<THolder<int>&>{a}; + + // const + (**TAutoEmbedOrPtrPolicy<THolder<int>>(MakeHolder<int>(1)).Ptr())++; // ok (**TAutoEmbedOrPtrPolicy<THolder<int>&>(a).Ptr())++; // ok - - const TVector<int> b = {0}; - auto bValue = (*TAutoEmbedOrPtrPolicy<const TVector<int>&>(b).Ptr())[0]; // ok - // (*TAutoEmbedOrPtrPolicy<const TVector<int>&>(b).Ptr())[0]++; // not ok - Y_UNUSED(bValue); - } - - template <typename T, typename TFunc> + + const TVector<int> b = {0}; + auto bValue = (*TAutoEmbedOrPtrPolicy<const TVector<int>&>(b).Ptr())[0]; // ok + // (*TAutoEmbedOrPtrPolicy<const TVector<int>&>(b).Ptr())[0]++; // not ok + Y_UNUSED(bValue); + } + + template <typename T, typename TFunc> void FunctionTakingRefDefaultIsObject(T&& a, TFunc func) { - TAutoEmbedOrPtrPolicy<T> refHolder(a); - func(refHolder); - } - - Y_UNIT_TEST(Reference) { - { - TVector<ui32> a = {1, 2, 3}; - - FunctionTakingRefDefaultIsObject(a, [](auto& holder) { - holder.Ptr()->push_back(4); - auto secondHolder = holder; - secondHolder.Ptr()->push_back(5); - }); - - UNIT_ASSERT_VALUES_EQUAL(a.size(), 5); - } - { - const TVector<ui32> a = {1, 2, 3}; - - static_assert(std::is_const<decltype(a)>::value); - - FunctionTakingRefDefaultIsObject(a, [](auto& holder) { + TAutoEmbedOrPtrPolicy<T> refHolder(a); + func(refHolder); + } + + Y_UNIT_TEST(Reference) { + { + TVector<ui32> a = {1, 2, 3}; + + FunctionTakingRefDefaultIsObject(a, [](auto& holder) { + holder.Ptr()->push_back(4); + auto secondHolder = holder; + secondHolder.Ptr()->push_back(5); + }); + + UNIT_ASSERT_VALUES_EQUAL(a.size(), 5); + } + { + const TVector<ui32> a = {1, 2, 3}; + + static_assert(std::is_const<decltype(a)>::value); + + FunctionTakingRefDefaultIsObject(a, [](auto& holder) { static_assert(std::is_const<std::remove_reference_t<decltype(*holder.Ptr())>>::value); - UNIT_ASSERT_VALUES_EQUAL(holder.Ptr()->size(), 3); - }); - } - } - - template <typename T, typename TFunc> + UNIT_ASSERT_VALUES_EQUAL(holder.Ptr()->size(), 3); + }); + } + } + + template <typename T, typename TFunc> void FunctionTakingObjectDefaultObject(T&& a, TFunc func) { TAutoEmbedOrPtrPolicy<T> objectHolder(std::forward<T>(a)); - func(objectHolder); - } - - Y_UNIT_TEST(Object) { - TVector<ui32> a = {1, 2, 3}; - - FunctionTakingObjectDefaultObject(std::move(a), [&a](auto& holder) { - static_assert(std::is_copy_assignable<decltype(holder)>::value); - UNIT_ASSERT_VALUES_EQUAL(a.size(), 0); - UNIT_ASSERT_VALUES_EQUAL(holder.Ptr()->size(), 3); - holder.Ptr()->push_back(4); - auto secondHolder = holder; - secondHolder.Ptr()->push_back(5); - - UNIT_ASSERT_VALUES_EQUAL(holder.Ptr()->size(), 4); - UNIT_ASSERT_VALUES_EQUAL(secondHolder.Ptr()->size(), 5); - }); - - UNIT_ASSERT_VALUES_EQUAL(a.size(), 0); - - THolder<int> b = MakeHolder<int>(42); - FunctionTakingObjectDefaultObject(std::move(b), [](auto& holder) { - static_assert(!std::is_copy_assignable<decltype(holder)>::value); - UNIT_ASSERT_VALUES_EQUAL(**holder.Ptr(), 42); - auto secondHolder = std::move(holder); - UNIT_ASSERT(!*holder.Ptr()); - UNIT_ASSERT_VALUES_EQUAL(**secondHolder.Ptr(), 42); - }); - } -} + func(objectHolder); + } + + Y_UNIT_TEST(Object) { + TVector<ui32> a = {1, 2, 3}; + + FunctionTakingObjectDefaultObject(std::move(a), [&a](auto& holder) { + static_assert(std::is_copy_assignable<decltype(holder)>::value); + UNIT_ASSERT_VALUES_EQUAL(a.size(), 0); + UNIT_ASSERT_VALUES_EQUAL(holder.Ptr()->size(), 3); + holder.Ptr()->push_back(4); + auto secondHolder = holder; + secondHolder.Ptr()->push_back(5); + + UNIT_ASSERT_VALUES_EQUAL(holder.Ptr()->size(), 4); + UNIT_ASSERT_VALUES_EQUAL(secondHolder.Ptr()->size(), 5); + }); + + UNIT_ASSERT_VALUES_EQUAL(a.size(), 0); + + THolder<int> b = MakeHolder<int>(42); + FunctionTakingObjectDefaultObject(std::move(b), [](auto& holder) { + static_assert(!std::is_copy_assignable<decltype(holder)>::value); + UNIT_ASSERT_VALUES_EQUAL(**holder.Ptr(), 42); + auto secondHolder = std::move(holder); + UNIT_ASSERT(!*holder.Ptr()); + UNIT_ASSERT_VALUES_EQUAL(**secondHolder.Ptr(), 42); + }); + } +} diff --git a/util/generic/ut/ya.make b/util/generic/ut/ya.make index a9626dc057..6eaf24cc5f 100644 --- a/util/generic/ut/ya.make +++ b/util/generic/ut/ya.make @@ -40,7 +40,7 @@ SRCS( generic/singleton_ut.cpp generic/size_literals_ut.cpp generic/stack_ut.cpp - generic/store_policy_ut.cpp + generic/store_policy_ut.cpp generic/strbuf_ut.cpp generic/string_ut.cpp generic/typelist_ut.cpp diff --git a/util/generic/xrange.h b/util/generic/xrange.h index 48db812b2e..5fc8c82912 100644 --- a/util/generic/xrange.h +++ b/util/generic/xrange.h @@ -148,7 +148,7 @@ namespace NPrivate { constexpr TIterator(T value, const TSteppedXRange& parent) noexcept : Value_(value) - , Parent_(&parent) + , Parent_(&parent) { } @@ -165,7 +165,7 @@ namespace NPrivate { } TIterator& operator++() noexcept { - Value_ += Parent_->Step_; + Value_ += Parent_->Step_; return *this; } @@ -202,7 +202,7 @@ namespace NPrivate { private: T Value_; - const TSteppedXRange* Parent_; + const TSteppedXRange* Parent_; }; using value_type = T; diff --git a/util/str_stl.h b/util/str_stl.h index 2113e2bed2..f1e137181d 100644 --- a/util/str_stl.h +++ b/util/str_stl.h @@ -34,9 +34,9 @@ namespace NHashPrivate { template <class T, bool needNumericHashing> struct THashHelper { inline size_t operator()(const T& t) const noexcept { - return (size_t)t; // If you have a compilation error here, look at explanation below: - // Probably error is caused by undefined template specialization of THash<T> - // You can find examples of specialization in this file + return (size_t)t; // If you have a compilation error here, look at explanation below: + // Probably error is caused by undefined template specialization of THash<T> + // You can find examples of specialization in this file } }; |