aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/iterator/filtering.h
blob: c28e3bc6c44d9cd1c4193b3f898debb0360dd6e2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#pragma once

#include <util/generic/iterator_range.h>
#include <util/generic/store_policy.h>
#include <iterator>


template <class TIterator, class TCondition>
class TFilteringIterator {
public:
    using TSelf = TFilteringIterator<TIterator, TCondition>;

    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;
    using iterator_category = std::forward_iterator_tag;

    TFilteringIterator(TIterator it, TIterator last, const TCondition& condition)
        : Iter(it)
        , Last(last)
        , Condition(condition)
    {
        Grep();
    }

    TSelf& operator++() {
        ++Iter;
        Grep();
        return *this;
    }

    decltype(auto) operator*() const {
        return *Iter;
    }

    pointer operator->() const {
        return &*Iter;
    }

    bool operator==(const TSelf& other) const {
        return Iter == other.Iter;
    }
    bool operator!=(const TSelf& other) const {
        return Iter != other.Iter;
    }

private:
    void Grep() {
        while (Iter != Last && !Condition(*Iter)) {
            ++Iter;
        }
    }
    TIterator Iter;
    TIterator Last;
    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:
    //TODO: make TIterator typedef private
    using TIterator = TFilteringIterator<TRawIterator, TConditionWrapper>;

    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;
};


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));
}