Совершенный цикл for

: , . , . , .



, , C++. , :



for (int i=0; i<size; i++) {
    [...]
}


, :



find . \( -name \*.h -o -name \*.cpp \) -exec grep -H "for (" {} \; | wc -l
43641


43 . , (, , ), . for ? , , , , (. code review). .



« » (perfection loop).



image



, ?



?



; , , , . , :



for (int iter=0; iter<nb_iter; iter++) {          // some iterative computation
    for (int c=0; c<mesh.cells.nb(); c++)         // loop through all tetrahedra
        for (int lv0=0; lv0<4; lv0++)             // for every pair of
            for (int lv1 = lv0+1; lv1<4; lv1++)   // vertices in the tet
                for (int d=0; d<3; d++) {         // do stuff for each of 3 dimensions
                    nlRowScaling(weight);
                    nlBegin(NL_ROW);
                    nlCoefficient(mesh.cells.vertex(c, lv0)*3 + d,  1);
                    nlCoefficient(mesh.cells.vertex(c, lv1)*3 + d, -1);
                    nlEnd(NL_ROW);
                }
    [...]
}


, , . , , --, .



; . ( ) , for (int i=0; i<size; i++) — : for , .



for(;;), : , . , 0 size-1, . , ? , — .



c++11 , :



#define FOR(I,UPPERBND) for(int I = 0; I<int(UPPERBND); ++I)


:



FOR(iter, nb_iter) {
    FOR(c, mesh.cells.nb())
        FOR(lv0, 4)
            for (int lv1 = lv0+1; lv1<4; lv1++)
                FOR(d, 3) {
                    nlRowScaling(weight);
                    nlBegin(NL_ROW);
                    nlCoefficient(mesh.cells.vertex(c, lv0)*3 + d,  1);
                    nlCoefficient(mesh.cells.vertex(c, lv1)*3 + d, -1);
                    nlEnd(NL_ROW);
                }
    [...]
}


, for (;;), , (, , ). FOR(,) 0 n-1 - . , , , (. ), (, , ).



, , , : " , ?"



11 , range for



? , . , :



for i in range(n):
    print(i)


, range() , . c++11 !



#include <iostream>
int main() {
    int range[] = {0,1,2,3,4,5};
    for (int i : range) {
        std::cerr << i;
    }
}


, , . C++ !



range(int n):



#include <iostream>

constexpr auto range(int n) {
    struct iterator {
        int i;
        void operator++() { ++i; }
        bool operator!=(const iterator& rhs) const { return i != rhs.i; }
        const int &operator*() const { return i; }
    };
    struct wrapper {
        int n;
        auto begin() { return iterator{0}; }
        auto end()   { return iterator{n}; }
    };
    return wrapper{n};
}

int main() {
    for (int i: range(13)) {
        std::cerr << i;
    }
    return 0;
}


, int vs size_t, . gcc 10.2 -std=c++17 -Wall -Wextra -pedantic -O1, ( ):



[...]
.L2:
        mov     esi, ebx
        mov     edi, OFFSET FLAT:_ZSt4cerr
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        add     ebx, 1
        cmp     ebx, 13
        jne     .L2
[...]


, , for (int i=0; i<13; i++).



, for (int i: range(n)) , FOR(,), , .



: enumerate



Range for c++11 . , , , :



#include <vector>
#include <iostream>

struct vec3 {  double x,y,z;  };

int main() {
    std::vector<vec3> points = {{6,5,8},{1,2,3},{7,3,7}};
    for (vec3 &p: points) {
        std::cerr << p.x;
    }
    return 0;
}


for (vec3 &p: points) , , . , ? , . , , , :



    std::vector<vec3> points = {{6,5,8},{1,2,3},{7,3,7}};
    std::vector<double> weights = {4,6,9};
    int i = 0;
    for (vec3 &p: points) {
        std::cerr << p.x << weights[i++];
    }


:



asm
.L2:
        movsd   xmm0, QWORD PTR [r13+0]
        mov     edi, OFFSET FLAT:_ZSt4cerr
        call    std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
        movsd   xmm0, QWORD PTR [rbp+0]
        mov     rdi, rax
        call    std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
        add     rbp, 8
        add     r13, 24
        cmp     r14, rbp
        jne     .L2


, , , , , c++17 structural binding!



, :



#include <vector>
#include <iostream>
#include "range.h"

struct vec3 {
    double x,y,z;
};

int main() {
    std::vector<vec3> points = {{6,5,8},{1,2,3},{7,3,7}};
    std::vector<double> weights = {4,6,9};

    for (auto [i, p]: enumerate(points)) {
        std::cerr << p.x << weights[i];
    }

    return 0;
}


enumerate() :



range.h
#ifndef __RANGE_H__
#define __RANGE_H__

#include <tuple>
#include <utility>
#include <iterator>

constexpr auto range(int n) {
    struct iterator {
        int i;
        void operator++() { ++i; }
        bool operator!=(const iterator& rhs) const { return i != rhs.i; }
        const int &operator*() const { return i; }
    };
    struct wrapper {
        int n;
        auto begin() { return iterator{0}; }
        auto end()   { return iterator{n}; }
    };
    return wrapper{n};
}

template <typename T> constexpr auto enumerate(T && iterable) {
    struct iterator {
        int i;
        typedef decltype(std::begin(std::declval<T>())) iterator_type;
        iterator_type iter;
        bool operator!=(const iterator& rhs) const { return iter != rhs.iter; }
        void operator++() { ++i; ++iter; }
        auto operator*() const { return std::tie(i, *iter); }
    };
    struct wrapper {
        T iterable;
        auto begin() { return iterator{0, std::begin(iterable)}; }
        auto end()   { return iterator{0, std::end  (iterable)}; }
    };
    return wrapper{std::forward<T>(iterable)};
}

#endif // __RANGE_H__


-std=c++17 -Wall -Wextra -pedantic -O2 ( ):



ASM
.L14:
        movsd   xmm0, QWORD PTR [rbx]
        mov     edi, OFFSET FLAT:_ZSt4cerr
        call    std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
        mov     rdi, rax
        mov     rax, QWORD PTR [rsp+32]
        movsd   xmm0, QWORD PTR [rax+rbp]
        call    std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
        add     rbx, 24
        add     rbp, 8
        cmp     r12, rbx
        jne     .L14


(, -O1 -O2).

, c++20 std::ranges, , .





, 2020 ? !



, - range.h .




All Articles