2 comments

[ 2.4 ms ] story [ 12.3 ms ] thread
tl;dr - a lot of mental energy going to avoiding making mistakes with indexed loops when iterators or macro that iterates but gives you an index inside the loop could be used.
There's two basic ways of defining iterators in C to remove some pain points. (There's others, but these two common patterns crop up often enough.)

    void foreach(TYPE* o, void(*f)(TYPE, void*), void* f_state)
Which you would use like:

    static void sum_bytes(wchar_t c, void* state) {
      *((size_t*) state) += c;
    }

    size_t sum = 0;
    foreach(jstr, sum_bytes, (void*)&sum);
An iterator that runs some function repeatedly against each element of the object, with the ability to pass in some kind of state. Tiny bit more advanced than the more common:

    size_t first(TYPE* o) { return 0; }
    size_t end(TYPE* o, size_t position) { return position >= len(o); }
    size_t next(TYPE* o, size_t position) { return position + 1; }
Which you would use like:

    for(size_t i = first(o); !end(o, i); i = next(o, i)) {
    }
Hiding your indexing ideas inside abstractions that you can write once, and use continually, removes some cognitive load, and means that when you find your pesky off-by-one error, it's only in one place, not a half-dozen nearly-matching-but-not-quite patterns.