State

It’s rough, not finished, but it’s very promising! I’ll probably finish it very soon. Oh yes, I almost forgot, it’s a state machine compile time with a transition table that’s not 100% complete.

// Copyright (c) January 2026 Félix-Olivier Dumas. All rights reserved.
// Licensed under the terms described in the LICENSE file

#include <iostream>
#include <type_traits>
#include <variant>

inline constexpr char IdleStateName[] = "Idle";
inline constexpr char PausedStateName[] = "Paused";
inline constexpr char RunningStateName[] = "Running";

inline constexpr char StopEventName[] = "Stop";
inline constexpr char PauseEventName[] = "Pause";
inline constexpr char StartEventName[] = "Start";


template<const char* Name>
struct Label {
    inline static constexpr const char* toString() { return Name; }
};


struct IState {};
struct IEvent {};

struct InvalidState : IState {};
struct InvalidEvent : IEvent {};

struct Idle    : IState, Label<IdleStateName>    {};
struct Paused  : IState, Label<PausedStateName>  {};
struct Running : IState, Label<RunningStateName> {};

struct Stop  : IEvent, Label<StopEventName>  {};
struct Pause : IEvent, Label<PauseEventName> {};
struct Start : IEvent, Label<StartEventName> {};

using State = std::variant<Idle, Running, Paused>;

/*************************************************/

template<typename... Field>
struct EntryKey {};

template<typename... Field>
struct EntryValue {};

/*************************************************/

template<typename, typename>
struct TableEntry;

template<typename... KFields, typename... VFields>
struct TableEntry<EntryKey<KFields...>, EntryValue<VFields...>> {
    using key = EntryKey<KFields...>;
    using value = EntryValue<VFields...>;
};

/*************************************************/

template<typename>
struct entry_key_size_impl;

template<typename... Fields>
struct entry_key_size_impl<EntryKey<Fields...>> {
    inline static constexpr std::size_t value = sizeof...(Fields);
};

template<typename Key>
struct entry_key_size {
    inline static constexpr std::size_t value = entry_key_size_impl<Key>::value;
};

template<typename Key>
inline static constexpr std::size_t entry_key_size_v = entry_key_size<Key>::value;

/*************************************************/

template<typename>
struct entry_value_size_impl;

template<typename... Fields>
struct entry_value_size_impl<EntryValue<Fields...>> {
    inline static constexpr std::size_t value = sizeof...(Fields);
};

template<typename Value>
struct entry_value_size {
    inline static constexpr std::size_t value = entry_value_size_impl<Value>::value;
};

template<typename Value>
inline static constexpr std::size_t entry_value_size_v = entry_value_size<Value>::value;

/*************************************************/

template<typename...>
struct Table {}; //ULTRA TEMPORAIRE ULTRA TEMPORAIRE ULTRA TEMPORAIRE ULTRA TEMPORAIRE

template<
    template<template<typename...> class, template<typename...> class> class... Entries,
    template<typename...> class Key, template<typename...> class Value
>
struct Table<Entries<Key, Value>...> {};
//ici j'ai un prob, il faut que ce soit LE NOMBRE qui soit le meme, 
//faut pas que ce soit les types de Key qui soit identiques

/*************************************************/

template<typename>
struct table_count_impl;

template<typename... Entries>
struct table_count_impl<Table<Entries...>> {
    inline static constexpr std::size_t value = sizeof...(Entries);
};

template<typename Entry>
struct table_count {
    inline static constexpr std::size_t value = table_count_impl<Entry>::value;
};

template<typename Entry>
inline static constexpr std::size_t table_count_v = table_count<Entry>::value;

/*************************************************/

template<typename>
struct table_entry_size_impl;

template<typename Entry>
struct table_entry_size_impl {
    inline static constexpr std::size_t value =
        entry_key_size<typename Entry::key>::value
        + entry_value_size<typename Entry::value>::value;
};

template<typename Entry>
struct table_entry_size {
    inline static constexpr std::size_t value = table_entry_size_impl<Entry>::value;
};

template<typename Entry>
inline static constexpr std::size_t table_entry_size_v = 
    table_entry_size_impl<Entry>::value;

/*************************************************/

template<
    std::size_t N, typename Table,
    typename Enable = std::enable_if_t<(N < table_count_v<Table>)> //fragile
>
struct at_impl;

template<template<typename...> class L, typename T, typename... Ts>
struct at_impl<0, L<T, Ts...>> {
    using type = T;
};

template<std::size_t N, template<typename...> class L, typename T, typename... Ts>
struct at_impl<N, L<T, Ts...>> {
    using type = typename at_impl<N - 1, L<Ts...>>::type;
};

//possiblement inclure ma lib et utiliser celle a disposition
//meme chose pour les méthodes utilitaires extra

/*************************************************/

template<typename... Ts>
struct min { // a mettre dans ma lib
    inline static constexpr std::size_t value = //fragile et brisé je penses
        ((std::min({ table_entry_size<Ts>::value })), ...);
};//probablement preferer max pour verifier

/*************************************************/

template<typename... Ts>
struct max {
    inline static constexpr std::size_t value =
        ((std::max({ table_entry_size<Ts>::value })), ...);
};

/*************************************************/

//un peu sale mais ca fonctionne ;)

template<typename Table, typename F, std::size_t... Is>
constexpr auto
for_each_in_table_impl2(std::index_sequence<Is...>, F&& func) {
    (func(typename at_impl<Is, std::remove_cvref_t<Table>>::type{}), ...);
}

template<typename Table, typename F, std::size_t... Is>
constexpr auto
get_for_each_in_table_impl2(std::index_sequence<Is...>, F&& func) {
    return std::tuple{
        func(typename at_impl<Is, std::remove_cvref_t<Table>>::type{})...
    };
}


template<typename F, typename Table>
constexpr decltype(auto)
for_each_in_table(F&& func, Table&& table) {
    for_each_in_table_impl2<Table>(
        std::make_index_sequence<
            table_count_v<std::remove_cvref_t<decltype(table)>>
        >{},
        func
    );
}

template<typename F, typename Table>
constexpr decltype(auto)
get_for_each_in_table(F&& func, Table&& table) {
    return get_for_each_in_table_impl2<Table>(
        std::make_index_sequence<
            table_count_v<std::remove_cvref_t<decltype(table)>>
        >{},
        func
    );
}



/*************************************************/

template<typename Table>
struct TableLookup {
    inline static constexpr std::size_t size = table_count<Table>::value;

    //template<typename... Keys>
    //auto find_by_key(Keys&&...) const
    //    -> std::enable_if_t<
    //        (sizeof...(Keys) == std::)
    //    >



        //utiliser index sequence + at

        //size
        //find (key -> value)
        //contains (value -> exists)
        //potentiellement un at (index -> value)
};

/*************************************************/

//template<typename...>
//struct Entry;
//
//template<typename Current, typename Event, typename Result>
//struct Entry<Current, Event, Result> {
//    using current = Current;
//    using event = Event;
//    using result = Result;
//};

/*************************************************/

//template<typename>
//struct Table;
//
//template<template<typename...> class... Entries, typename... Fields>
//struct Table<Entries<Fields...>...> {};

/*************************************************/

//template<typename>
//struct entry_count_impl;
//
//template<typename... Fields>
//struct entry_count_impl<Entry<Fields...>> {
//    inline static constexpr std::size_t value = sizeof...(Fields);
//};
//
//template<typename Entry>
//struct entry_count {
//    inline static constexpr std::size_t value = entry_count_impl<Entry>::value;
//};
//
//template<typename Entry>
//inline static constexpr std::size_t entry_count_v = entry_count<Entry>::value;

/*************************************************/


/*************************************************/




/*************************************************/



/*************************************************/

//a la longue, faire un system de dictionnaire compile-time avec clé valeur

template<typename Current, typename Event, typename Result>
struct Transition {
    using current = Current;
    using event = Event;
    using result = Result;
};

template<typename... Transitions>
struct TransitionTable {};


template<typename Table>
struct TransitionTableDispatcher {};

template<typename... Entries>
struct TransitionTableDispatcher<TransitionTable<Entries...>> {
    constexpr void test() { //peut etre faire un truc avec lambda
        ((std::cout
            << typename Entries::current::toString() << " + "
            << typename Entries::event::toString()   << " -> "
            << typename Entries::result::toString()  << "\n"
        ), ...);

        //faire une fonction genre check_table ou something like that.
        //fait juste iterer et si A et B == true alors on return C
    }
};

//faire facade au pire pour garder le format (prefere lui)
//ou bien faire un type entry spécial pour transition
using MyFsm = TransitionTable<
    Transition<Idle, Start, Running>,
    Transition<Running, Pause, Paused>,
    Transition<Running, Stop, Idle>,
    Transition<Paused, Start, Running>,
    Transition<Paused, Stop, Idle>
>;




/*************************************************/


template<typename State, typename Event>
struct transition_impl {
    using to = State; // ou invalid state et check après
};

template<>
struct transition_impl<Idle, Start> {
    using to = Running;
};

template<>
struct transition_impl<Running, Pause> {
    using to = Paused;
};

template<>
struct transition_impl<Running, Stop> {
    using to = Idle;
};

template<>
struct transition_impl<Paused, Start> {
    using to = Running;
};

template<>
struct transition_impl<Paused, Stop> {
    using to = Idle;
};

template<typename E>
State transition(const State& state, E) {
    return std::visit([&]<typename Cur>(Cur&&) -> State {
        return typename transition_impl<
            std::remove_cvref_t<Cur>,
            std::remove_cvref_t<E>
        >::to{};
    }, state);
}

struct Engine final {
public:
    explicit Engine(State init_state = Idle{})
        : state_(std::move(init_state)) {}

public:
    template<typename Event>
    void process_event() {
        state_ = transition(state_, Event{});

        printState(state_);
    }

    void printState(const State& s) {
        std::visit([](auto&& val) {
            std::cout << "State: " << val.toString() << "\n";
        }, s);
    }


private:
    State state_;
    

};

struct Derived {
public:


private:


};

int main() {
    //using n = transition<State::Idle, Event::Start>::to;

    //std::cout << typeid(n).name() << "\n";

    using f = transition_impl<Idle, Start>::to;
    using f2 = transition_impl<f, Stop>::to;


    f result;
    f2 result2;

    //std::cout << result.toString() << "\n";
    //std::cout << result2.toString() << "\n";

    Engine e{};

    e.process_event<Start>();
    e.process_event<Pause>();
    e.process_event<Pause>();
    e.process_event<Stop>();
    e.process_event<Pause>();


    auto d = TransitionTableDispatcher<MyFsm>{};

    d.test();
    /*
        Engine e;
        e.process_event<Start>();   // Idle → Running
        e.process_event<Pause>();   // Running → Paused
        e.process_event<Start>();   // Paused → Running
        e.process_event<Stop>();    // Running → Idle
    */   //Transition<Idle, Start, Running>,  Transition<Running, Pause, Paused>,

    using Table0 = Table<
        TableEntry<EntryKey<Idle, Start>, EntryValue<Running>>,
        TableEntry<EntryKey<Running, Pause>, EntryValue<Paused>>
    >;

    using res0 = at_impl<0, Table0>::type;
    using res1 = at_impl<1, Table0>::type;

    std::cout << "Key: " << typeid(typename res0::key).name() << "\n";
    std::cout << "Value: " << typeid(typename res0::value).name() << "\n";

    constexpr std::size_t size = min<res0, res1>::value;

    std::cout << size << "\n";


    auto table = Table0{};

    auto t2 = get_for_each_in_table([](auto&&... entry) {
        return ((table_entry_size_v<std::remove_cvref_t<decltype(entry)>>), ...);
    }, table);

    std::apply([](auto&&... sz) {
        std::cout << "MIN SIZE: " << std::min({ sz... }) << "\n";
        std::cout << "MAX SIZE: " << std::max({ sz... }) << "\n";
    }, t2);

    for_each_in_table([](auto&&... entry) {
        ((std::cout << "for_each_in_table() -> " << typeid(decltype(entry)).name() << "\n"), ...);
    }, table);
}