Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

unrays/State

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
5 Commits
 
 
 
 
 
 
 
 

Repository files navigation

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);
}

Releases

No releases published

Packages

 
 
 

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.