Архитектурная акустика/Реализация/IteratorAdapterConditional

Материал из CAMaaS preliminary wiki
< Архитектурная акустика‎ | Реализация
Версия от 00:37, 9 января 2018; Андрей Чусов (обсуждение | вклад) (Новая страница: «{{class|Архитектурная акустика/Реализация/IteratorAdapterConditional}} {{example_begin}} <source lang="cpp"> #include "collection_…»)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к навигации Перейти к поиску

Реализует прямой итератор, который на каждой итерации проверяет выполнение условия, заданного предикатом, и, если условие не выполняется, осуществляет переход к следующему элементу до тех пор, пока не будет выполнено условие, или итератор не перейдет в состояние, при котором дальнейшие переходы запрещены.

template <class _BaseIterator, class _Predicate, class _IsDeref>
class IteratorAdapterConditional;
_BaseIteratorТип преобразуемого адаптером итератора. Должен удовлетворять требованиям ForwardIterator.
_PredicateТип предиката, при перечислении осуществляющего проверку условия остановки переходов. Предикат должен принимать единственный параметр, который может быть:
  • итератором типа _BaseIterator, непосредственно адаптируемым к типу IteratorAdapterConditional или
  • итератором типа typename adapted_iterator<_BaseIterator>::type, который адаптируется цепочкой адаптеров, в которой последним адаптером является данная специализация IteratorAdapterConditional - например типом some_iterator в цепочке преобразований IteratorAdapterConditional<IteratorAdapterForStep<...<some_iterator>...>>, или
  • значением элемента, связанного с итератором, типа value_type - за исключением случаев, когда тип значения неявно преобразуем к любому из итераторов-адаптеров в цепочке.

Вызов предиката должен быть однозначен и соответствовать только одному из вышеупомянутых случаев, поэтому в качестве предиката не допускается использование шаблонов или обобщенных лямбда-выражений.

Также предикат должен удовлетворять требованиям CopyConstructible и CopyAssignable.
_IsDerefПредикат, проверяющий возможность перехода итератором _BaseIterator к следующему элементу путем инкремента. Тип должен удовлетворять требованиям CopyConstructible и CopyAssignable.
Открытые типы
ТипОписание
iteratorТип _BaseIterator.
iterator_categoryКатегория итератора. Тип эквивалентен std::forward_iterator_tag.
value_typeТип typename std::iterator_traits<iterator>::value_type.
referenceТип typename std::iterator_traits<iterator>::reference.
pointerТип typename std::iterator_traits<iterator>::pointer.
difference_typeТип typename std::iterator_traits<iterator>::difference_type.
predicateТип предиката необходимости перехода. Тип эквивалентен _Predicate.
iterator_predicateТип предиката возможности перехода. Тип эквивалентен _IsDeref.
Открытые методы
МетодОписание
(конструкторы)Конструкторы класса IteratorAdapterConditional.
operator=Операторы присваивания.
operator*Оператор разыменовывания.
operator->Оператор косвенного доступа к элементам.
operator++Переход итератора к следующему элементу, удовлетворяющему предикату IteratorAdapterConditional::predicate.
operator==Проверка на эквивалентность итераторов.
operator!=Проверка на неэквивалентность итераторов.
baseВозвращает адаптируемый итератор в текущей позиции.
adaptation_baseВозвращает текущий корневой адаптированный, возможно цепочкой адаптеров, итератор.
Пример
#include "collection_base.h"
#include <array>
#include <iostream>

using namespace Chusov::Math;

template <class Container>
std::array<int, 20 * 10> extract_even_range_for(const Container& cont)
{
    std::vector<std::thread> vecThreads;
    std::array<int, 20 * 10> EvenValues;
    for (unsigned i = 0; i < std::thread::hardware_concurrency(); ++i)
        vecThreads.emplace_back([&vecThreads, i, &cont, &EvenValues]()
    {
        for (auto&& v :
            adapt_iterator_range<IteratorAdapterConditional>(
                adapt_iterator_range<IteratorAdapterForStep>(
                    Chusov::Memory::make_iterator_range(make_iterator_adapter<IteratorAdapter2D>(cont.crbegin()) + i, cont.crend()),
                    std::thread::hardware_concurrency(),
                    adapt_iterator_range<IteratorAdapter2D>(cont.crbegin(), cont.crend())
                    ),
                [](int x) -> bool {return (x & 1) == 0; },
                //or: [](IteratorAdapterForStep<IteratorAdapter2D<Matrix<int>::const_reverse_iterator>> _it) -> bool {return (*_it & 1) == 0;},
                //or: [](IteratorAdapter2D<Matrix<int>::const_reverse_iterator> _it) -> bool {return (*_it & 1) == 0;},
                [&cont](auto _it) -> bool {return _it.adaptation_base() != cont.crend(); }
                //or: [&cont](IteratorAdapterForStep<IteratorAdapter2D<Matrix<int>::const_reverse_iterator>> it) -> bool {return it != cont.crend();}
                )
            )
            EvenValues[20 * 10 - v / 2] = v;
    });
    for (auto&& thr : vecThreads)
        thr.join();
    return EvenValues;
}

template <class Container>
std::array<int, 20 * 10> extract_even_direct_for(const Container& cont)
{
    std::vector<std::thread> vecThreads;
    std::array<int, 20 * 10> EvenValues;
    for (unsigned i = 0; i < std::thread::hardware_concurrency(); ++i)
        vecThreads.emplace_back([&vecThreads, i, &cont, &EvenValues]()
    {
        for (auto it = make_iterator_adapter<IteratorAdapterConditional>(
            make_iterator_adapter<IteratorAdapterForStep>(
                i,
                std::thread::hardware_concurrency(),
                adapt_iterator_range<IteratorAdapter2D>(cont.crbegin(), cont.crend())
                ),
            //generic lambda causes ambiguity: should it pass an iterator or a value here
            [](IteratorAdapterForStep<IteratorAdapter2D<Matrix<int>::const_reverse_iterator>> _it) -> bool {return (*_it & 1) == 0; }, 
            [&cont](auto _it) -> bool {return _it.adaptation_base() != cont.crend(); }
        ); it.adaptation_base() != make_iterator_adapter<IteratorAdapter2D>(cont.crend()); ++it)
            EvenValues[20 * 10 - *it / 2] = *it;
    });
    for (auto&& thr : vecThreads)
        thr.join();
    return EvenValues;
}

int main(int argc, char** argv)
{
    auto m2 = Matrix<int>(0, 20, 20);
    auto x = 1;
    for (auto&& v : adapt_iterator_range<IteratorAdapter2D>(m2.begin(), m2.end()))
        v = x++;
    auto rng_based = extract_even_range_for(m2);
    std::cout << "\nElements of an array with even elements of a matrix put in parallel in reverse order (range-for based).\n";
    for (auto val:rng_based)
        std::cout << val << "\t";
    std::cout << "\n";
    auto direct_based = extract_even_direct_for(m2);
    for (auto val : direct_based)
        std::cout << val << "\t";
    std::cout << "\n";
    return 0;
}