Wallacoloo / printipi

3d printing directly through the Raspberry Pi's GPIO pins
MIT License
141 stars 43 forks source link

Make an IoDrivers iterator to replace tupleCallOnAll & tupleCallOnIndex calls #75

Closed Wallacoloo closed 9 years ago

Wallacoloo commented 9 years ago

Currently, if you want to iterate over all the ioDrivers, you have to create a class that looks like this:

struct DoForEach {
    template <typename T> operator()(std::size_t index, T &ioDriver) {
        ioDriver.doStuff();
    }
};

and then in the place you want to use it:

void myMethod() {
    tupleCallOnAll(ioDrivers, DoForEach());
}

This is very weird and unintuitive and verbose. A much better interface would be something like:

void myMethod() {
    for (auto &i : ioDrivers) {
        i.doStuff();
    }
}

Unfortunately, this isn't possible because one cannot iterate over a tuple. And note that it isn't always easy to reduce this tuple to a fixed number of arrays at compile time; one can extract the fans and the endstops, but there are different types of Stepper Drivers besides A4988 and different hotend control systems (because of different thermistors).

The solution is to create an iterator type that abstracts much of this. The iterator can still provide interfaces for IoDriver methods like peekNextEvent() and getTargetTemperature() and transparently determine which object to call them on. Thus, you have something like:

void myMethod() {
    for (auto &i : IODriver::iter(ioDrivers)) {
        if (i.isEndstop() && i.isEndstopTriggered()) {
            LOG("Endstop is triggered\n");
        }
    }
}

This is almost as natural as if ioDrivers were an array. In this case the type of i is not IODriver, but an IODriver proxy type, that way it will call the correct isEndstop() function, etc.

Wallacoloo commented 9 years ago

On top of this, IoDrivers really ought to be a specialized container type rather than a std::tuple of IODrivers. This way the for (auto &i : ioDrivers) syntax actually does work, as well as indexing and a proper size() member function (rather than std::tuple_size<TupleT>), etc.