woboq/verdigris

Idea: Better Compiletime Counting

Closed this issue · 5 comments

The compile time counter is used to differentiate and collect the bits of information provided by the macros.

Idea: https://godbolt.org/z/S5WAMH

  • forward counting
  • only one layer of inheritance.
  • allows to easily collect everything without recursion.

What do you think?

Interesting idea.

COUNTER is a compiler extension, i've tried to stay away from non standard things, but I guess if every compiler support that it could be fine. Maybe COUNTER can be replaced by some unique type or something. COUNTER might not work with templates as the same COUNTER will be re-used for different instantiation. (I guess that's fine if count() and example() are also part of the template.)

if constexpr is c++17, and i'd like to keep supporting C++14 for now, but i guess it can be replaced by good old SFINAE

It's also possible to do log2 search:

template<size_t L, size_t N = 0, size_t M = 1024, size_t X = (N+M)/2>
constexpr auto count() {
    if constexpr (N==X) {
        return std::is_same_v<void, decltype(example(index<X>))> ? N : M;
    }
    else if constexpr (std::is_same_v<void, decltype(example(index<X>))>) {
        return count<L, N, X>();
    } 
    else {
        return count<L, X, M>();
    }
}

(Godbolt short links seems down)

A C++14 variant that reduces the MSVC output in Godbolt.

template<size_t L, size_t N, size_t M, size_t X = (N+M)/2
    , bool noX = std::is_same<void, decltype(example(index<X>))>::value
    , bool up = N==X>
struct Count;

template<size_t L, size_t N, size_t M, size_t X>
struct Count<L, N, M, X, true, true> {
    static constexpr auto value = N;
};
template<size_t L, size_t N, size_t M, size_t X>
struct Count<L, N, M, X, false, true> {
    static constexpr auto value = M;
};
template<size_t L, size_t N, size_t M, size_t X>
struct Count<L, N, M, X, true, false> {
    static constexpr auto value = Count<L, N, X>::value;
};
template<size_t L, size_t N, size_t M, size_t X>
struct Count<L, N, M, X, false, false> {
    static constexpr auto value = Count<L, X, M>::value;
};

template<size_t L>
constexpr auto count = Count<L, 0, 1024>::value;

Just to keep track of it 😎

I did a full implementation for Verdigris. See: https://github.com/arBmind/verdigris/tree/feature/cpp17_forwardCounter

It works at least on GCC 7.3. Visual Studio runs into complexity barriers with my string implementations (same as before).

This is merged… 👍