Skip to content

Usage Class Members

Andrew Gresyk edited this page Dec 26, 2023 · 4 revisions

FSMs as Class Members

  1. The main goal here is to avoid #include <hfsm2/machine.hpp> in the class header, thus reducing the build times.

actor.hpp

#pragma once

#include <cstddef> // max_align_t

class Actor {
public:
    struct alignas(std::max_align_t) FsmHost {
        char buffer[104]; // the size is hand-adjusted
    };

public:
    Actor();
    ~Actor();

    void turnOn();
    bool isOn() const;

private:
    FsmHost _fsmHost;
};

actor.cpp

#include "actor.hpp"
#include <hfsm2/machine.hpp>

namespace actor_fsm {

using Config = hfsm2::Config
                    ::ContextT<Actor&>;

using M = hfsm2::MachineT<Config>;

#define S(s) struct s
using FSM = M::PeerRoot<
                S(Off),
                S(On)
            >;
#undef S

struct Off : FSM::State {};
struct On  : FSM::State {};

FSM::Instance&
fsm(      Actor::FsmHost& fsmHost) { return *reinterpret_cast<      FSM::Instance*>(&fsmHost); }

const FSM::Instance&
fsm(const Actor::FsmHost& fsmHost) { return *reinterpret_cast<const FSM::Instance*>(&fsmHost); }

}

Actor::Actor() {
    //hfsm2::StaticPrintConstT<alignof(actor_fsm::FSM::Instance)> alignment;
    static_assert(alignof(actor_fsm::FSM::Instance) <= alignof(FsmHost),
                  "Uncomment the line above to find out the alignment of the `FsmHost` needed");

    //hfsm2::StaticPrintConstT<sizeof(actor_fsm::FSM::Instance)> size;
    static_assert(sizeof(actor_fsm::FSM::Instance) <= sizeof(FsmHost),
                  "Uncomment the line above to find out the size of the `FsmHost` needed");

    new (&_fsmHost) actor_fsm::FSM::Instance{*this};
}

Actor::~Actor() {
    hfsm2::destroy(actor_fsm::fsm(_fsmHost));
}

void Actor::turnOn() {
    actor_fsm::fsm(_fsmHost).immediateChangeTo<actor_fsm::On>();
}

bool Actor::isOn() const {
    return actor_fsm::fsm(_fsmHost).isActive<actor_fsm::On>();
}