From e22203f7e2a1fda8fbe287d849b23e3060733112 Mon Sep 17 00:00:00 2001 From: Mchan2003 Date: Mon, 15 Sep 2025 12:29:06 -0700 Subject: [PATCH 1/7] add boiler point for state machine --- include/concrete_state.hpp | 86 ++++++++++++++++++++++++++++++++++++++ include/safe.hpp | 14 +++++++ include/safe_state.hpp | 12 ++++++ src/concrete_state.cpp | 47 +++++++++++++++++++++ src/safe.cpp | 16 +++++++ src/safe_state.cpp | 1 + 6 files changed, 176 insertions(+) create mode 100644 include/concrete_state.hpp create mode 100644 include/safe.hpp create mode 100644 include/safe_state.hpp create mode 100644 src/concrete_state.cpp create mode 100644 src/safe.cpp create mode 100644 src/safe_state.cpp diff --git a/include/concrete_state.hpp b/include/concrete_state.hpp new file mode 100644 index 0000000..4a27ff9 --- /dev/null +++ b/include/concrete_state.hpp @@ -0,0 +1,86 @@ +#pragma once +#include "./safe_state.hpp" + +class UserInputState : public SafeState { + public: + void enter(Safe* safe) {} + void toggle(Safe* safe); + void exit(Safe* safe) {} + static SafeState& get_instance(); + private: + UserInputState() {}; + UserInputState(const UserInputState& other); + UserInputState& operator = (const UserInputState& other); +}; + +class ElfParserState : public SafeState { + public: + void enter(Safe* safe) {} + void toggle(Safe* safe); + void exit(Safe* safe) {} + static SafeState& get_instance(); + private: + ElfParserState() {}; + ElfParserState(const ElfParserState& other); + ElfParserState& operator = (const ElfParserState& other); +}; + +class CallgraphState : public SafeState { + public: + void enter(Safe* safe) {} + void toggle(Safe* safe); + void exit(Safe* safe) {} + static SafeState& get_instance(); + private: + CallgraphState() {}; + CallgraphState(const CallgraphState& other); + CallgraphState& operator = (const CallgraphState& other); +}; + +class AbiParserState : public SafeState { + public: + void enter(Safe* safe) {} + void toggle(Safe* safe); + void exit(Safe* safe) {} + static SafeState& get_instance(); + private: + AbiParserState() {}; + AbiParserState(const AbiParserState& other); + AbiParserState& operator = (const AbiParserState& other); +}; + +class ValidatorState : public SafeState { + public: + void enter(Safe* safe) {} + void toggle(Safe* safe); + void exit(Safe* safe) {} + static SafeState& get_instance(); + private: + ValidatorState() {}; + ValidatorState(const ValidatorState& other); + ValidatorState& operator = (const ValidatorState& other); +}; + +class OutputState : public SafeState { + public: + void enter(Safe* safe) {} + void toggle(Safe* safe); + void exit(Safe* safe) {} + static SafeState& get_instance(); + private: + OutputState() {}; + OutputState(const OutputState& other); + OutputState& operator = (const OutputState& other); +}; + +class ErrorState : public SafeState { + public: + void enter(Safe* safe) {} + void toggle(Safe* safe); + void exit(Safe* safe) {} + static SafeState& get_instance(); + private: + ErrorState() {}; + ErrorState(const ErrorState& other); + ErrorState& operator = (const ErrorState& other); +}; \ No newline at end of file diff --git a/include/safe.hpp b/include/safe.hpp new file mode 100644 index 0000000..ac543d9 --- /dev/null +++ b/include/safe.hpp @@ -0,0 +1,14 @@ +#pragma once +#include "./safe_state.hpp" + +class SafeState; + +class Safe { + public: + Safe(); + inline SafeState* get_current_state() const {return current_state}; + void toggle(); + void set_state(SafeState& new_state); + private: + SafeState* current_state; +}; \ No newline at end of file diff --git a/include/safe_state.hpp b/include/safe_state.hpp new file mode 100644 index 0000000..a11604a --- /dev/null +++ b/include/safe_state.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "./safe_state.hpp" + +class Safe; + +class SafeState { + public: + virtual void enter(Safe* safe) = 0; + virtual void toggle(Safe* safe) = 0; + virtual void exit(Safe* safe) = 0; + virtual ~SafeState() {}; +}; \ No newline at end of file diff --git a/src/concrete_state.cpp b/src/concrete_state.cpp new file mode 100644 index 0000000..e7e7d85 --- /dev/null +++ b/src/concrete_state.cpp @@ -0,0 +1,47 @@ +#include "../include/concrete_state.hpp" +#include "../include/safe.hpp" + +void UserInputState::toggle(Safe* safe) { + safe->set_state(ElfParserState::get_instance()); +} + +SafeState& UserInputState::get_instance() { + static UserInputState instance; + return instance; +} + +void ElfParserState::toggle(Safe* safe) { + safe->set_state(CallgraphState::get_instance()); +} + +SafeState& ElfParserState::get_instance() { + static ElfParserState instance; + return instance; +} + +void CallgraphState::toggle(Safe* safe) { + safe->set_state(AbiParserState::get_instance()); +} + +SafeState& CallgraphState::get_instance() { + static CallgraphState instance; + return instance; +} + +void AbiParserState::toggle(Safe* safe) { + safe->set_state(OutputState::get_instance()); +} + +SafeState& AbiParserState::get_instance() { + static AbiParserState instance; + return instance; +} + +void OutputState::toggle(Safe* safe) { + safe->set_state(UserInputState::get_instance()); +} + +SafeState& OutputState::get_instance() { + static OutputState instance; + return instance; +} diff --git a/src/safe.cpp b/src/safe.cpp new file mode 100644 index 0000000..2072a06 --- /dev/null +++ b/src/safe.cpp @@ -0,0 +1,16 @@ +#include "../include/safe.hpp" +#include "../include/concrete_state.hpp" + +Safe::Safe(){ + current_state = &UserInputState::get_instance(); +} + +void Safe::set_state(SafeState& new_state) { + current_state->exit(this); + current_state = &new_state; + current_state->enter(this); +} + +void Safe::toggle() { + current_state->toggle(this); +} \ No newline at end of file diff --git a/src/safe_state.cpp b/src/safe_state.cpp new file mode 100644 index 0000000..4f2eb6c --- /dev/null +++ b/src/safe_state.cpp @@ -0,0 +1 @@ +#include "../include/state.hpp" From 9dbb263d34ae7551fcf9eb345ca9223280a217be Mon Sep 17 00:00:00 2001 From: Mchan2003 Date: Mon, 22 Sep 2025 13:29:03 -0700 Subject: [PATCH 2/7] updated interface for state machine --- .gitignore | 2 +- include/concrete_state.hpp | 86 ------------------------------- include/concrete_states.hpp | 52 +++++++++++++++++++ include/safe.hpp | 14 ----- include/safe_state.hpp | 12 ----- include/state.hpp | 17 ++++++ include/state_context.hpp | 17 ++++++ src/concrete_state.cpp | 47 ----------------- src/concrete_states.cpp | 100 ++++++++++++++++++++++++++++++++++++ src/main.cpp | 17 ++++++ src/safe.cpp | 16 ------ src/safe_state.cpp | 1 - src/state.cpp | 5 ++ src/state_context.cpp | 26 ++++++++++ 14 files changed, 235 insertions(+), 177 deletions(-) delete mode 100644 include/concrete_state.hpp create mode 100644 include/concrete_states.hpp delete mode 100644 include/safe.hpp delete mode 100644 include/safe_state.hpp create mode 100644 include/state.hpp create mode 100644 include/state_context.hpp delete mode 100644 src/concrete_state.cpp create mode 100644 src/concrete_states.cpp delete mode 100644 src/safe.cpp delete mode 100644 src/safe_state.cpp create mode 100644 src/state.cpp create mode 100644 src/state_context.cpp diff --git a/.gitignore b/.gitignore index 149298d..9b935aa 100644 --- a/.gitignore +++ b/.gitignore @@ -180,4 +180,4 @@ build/ .html/ .latex/ -out/ \ No newline at end of file +out/ diff --git a/include/concrete_state.hpp b/include/concrete_state.hpp deleted file mode 100644 index 4a27ff9..0000000 --- a/include/concrete_state.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once -#include "./safe_state.hpp" - -class UserInputState : public SafeState { - public: - void enter(Safe* safe) {} - void toggle(Safe* safe); - void exit(Safe* safe) {} - static SafeState& get_instance(); - private: - UserInputState() {}; - UserInputState(const UserInputState& other); - UserInputState& operator = (const UserInputState& other); -}; - -class ElfParserState : public SafeState { - public: - void enter(Safe* safe) {} - void toggle(Safe* safe); - void exit(Safe* safe) {} - static SafeState& get_instance(); - private: - ElfParserState() {}; - ElfParserState(const ElfParserState& other); - ElfParserState& operator = (const ElfParserState& other); -}; - -class CallgraphState : public SafeState { - public: - void enter(Safe* safe) {} - void toggle(Safe* safe); - void exit(Safe* safe) {} - static SafeState& get_instance(); - private: - CallgraphState() {}; - CallgraphState(const CallgraphState& other); - CallgraphState& operator = (const CallgraphState& other); -}; - -class AbiParserState : public SafeState { - public: - void enter(Safe* safe) {} - void toggle(Safe* safe); - void exit(Safe* safe) {} - static SafeState& get_instance(); - private: - AbiParserState() {}; - AbiParserState(const AbiParserState& other); - AbiParserState& operator = (const AbiParserState& other); -}; - -class ValidatorState : public SafeState { - public: - void enter(Safe* safe) {} - void toggle(Safe* safe); - void exit(Safe* safe) {} - static SafeState& get_instance(); - private: - ValidatorState() {}; - ValidatorState(const ValidatorState& other); - ValidatorState& operator = (const ValidatorState& other); -}; - -class OutputState : public SafeState { - public: - void enter(Safe* safe) {} - void toggle(Safe* safe); - void exit(Safe* safe) {} - static SafeState& get_instance(); - private: - OutputState() {}; - OutputState(const OutputState& other); - OutputState& operator = (const OutputState& other); -}; - -class ErrorState : public SafeState { - public: - void enter(Safe* safe) {} - void toggle(Safe* safe); - void exit(Safe* safe) {} - static SafeState& get_instance(); - private: - ErrorState() {}; - ErrorState(const ErrorState& other); - ErrorState& operator = (const ErrorState& other); -}; \ No newline at end of file diff --git a/include/concrete_states.hpp b/include/concrete_states.hpp new file mode 100644 index 0000000..d9007ee --- /dev/null +++ b/include/concrete_states.hpp @@ -0,0 +1,52 @@ +#pragma once +#include +#include "./state.hpp" + +class UserInputState : public State { + public: + void enter() override; + void handle() override; + void exit() override; +}; + +class ElfParserState : public State { + public: + void enter() override; + void handle() override; + void exit() override; +}; + +class CallgraphState : public State { + public: + void enter() override; + void handle() override; + void exit() override; +}; + +class AbiParserState : public State { + public: + void enter() override; + void handle() override; + void exit() override; +}; + +class ValidatorState : public State { + public: + void enter() override; + void handle() override; + void exit() override; +}; + +class OutputState : public State { + public: + void enter() override; + void handle() override; + void exit() override; +}; + +class ErrorState : public State { + public: + void enter() override; + void handle() override; + void exit() override; +}; \ No newline at end of file diff --git a/include/safe.hpp b/include/safe.hpp deleted file mode 100644 index ac543d9..0000000 --- a/include/safe.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "./safe_state.hpp" - -class SafeState; - -class Safe { - public: - Safe(); - inline SafeState* get_current_state() const {return current_state}; - void toggle(); - void set_state(SafeState& new_state); - private: - SafeState* current_state; -}; \ No newline at end of file diff --git a/include/safe_state.hpp b/include/safe_state.hpp deleted file mode 100644 index a11604a..0000000 --- a/include/safe_state.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "./safe_state.hpp" - -class Safe; - -class SafeState { - public: - virtual void enter(Safe* safe) = 0; - virtual void toggle(Safe* safe) = 0; - virtual void exit(Safe* safe) = 0; - virtual ~SafeState() {}; -}; \ No newline at end of file diff --git a/include/state.hpp b/include/state.hpp new file mode 100644 index 0000000..33a4d2d --- /dev/null +++ b/include/state.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "./state_context.hpp" + +class StateContext; + +class State { + protected: + StateContext *context; + public: + virtual void enter() = 0; + virtual void handle() = 0; + virtual void exit() = 0; + + void set_context(StateContext *context); + + virtual ~State() = 0; +}; \ No newline at end of file diff --git a/include/state_context.hpp b/include/state_context.hpp new file mode 100644 index 0000000..8dd0488 --- /dev/null +++ b/include/state_context.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "./state.hpp" + +class State; + +class StateContext { + public: + StateContext(State *state); + ~StateContext(); + State* get_current_state(); + void run_state(); + void transition_state(State* new_state); + private: + State* current_state; + int total_state; +}; + diff --git a/src/concrete_state.cpp b/src/concrete_state.cpp deleted file mode 100644 index e7e7d85..0000000 --- a/src/concrete_state.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "../include/concrete_state.hpp" -#include "../include/safe.hpp" - -void UserInputState::toggle(Safe* safe) { - safe->set_state(ElfParserState::get_instance()); -} - -SafeState& UserInputState::get_instance() { - static UserInputState instance; - return instance; -} - -void ElfParserState::toggle(Safe* safe) { - safe->set_state(CallgraphState::get_instance()); -} - -SafeState& ElfParserState::get_instance() { - static ElfParserState instance; - return instance; -} - -void CallgraphState::toggle(Safe* safe) { - safe->set_state(AbiParserState::get_instance()); -} - -SafeState& CallgraphState::get_instance() { - static CallgraphState instance; - return instance; -} - -void AbiParserState::toggle(Safe* safe) { - safe->set_state(OutputState::get_instance()); -} - -SafeState& AbiParserState::get_instance() { - static AbiParserState instance; - return instance; -} - -void OutputState::toggle(Safe* safe) { - safe->set_state(UserInputState::get_instance()); -} - -SafeState& OutputState::get_instance() { - static OutputState instance; - return instance; -} diff --git a/src/concrete_states.cpp b/src/concrete_states.cpp new file mode 100644 index 0000000..06237ce --- /dev/null +++ b/src/concrete_states.cpp @@ -0,0 +1,100 @@ +#include "../include/concrete_state.hpp" +#include "../include/state.hpp" +#include "../include/state_context.hpp" + +//User Input +void UserInputState::enter() { + print("Enter User Input State\n"); +} + +void UserInputState::handle() { + print("Handle User Input State\n"); +} + +void UserInputState::exit() { + print("Exit User Input State\n-------------\n"); + this->contect->transition_state(new ElfParserState); +} + +//Elf Parser +void ElfParserState::enter() { + print("Enter Elf Parser State\n"); +} + +void ElfParserState::handle() { + print("Handle Elf Parser State\n"); +} + +void ElfParserState::exit() { + print("Exit Elf Parser State\n-------------\n"); + this->context->transition_state(new CallgraphState); +} + +//Callgraph +void CallgraphState::enter() { + print("Enter Callgraph State\n"); +} + +void CallgraphState::handle() { + print("Handle Callgraph State\n"); +} + +void CallgraphState::exit() { + print("Exit Callgraph State\n-------------\n"); + this->context->transition_state(new AbiParserState); +} + +//Abi Parser +void AbiParserState::enter() { + print("Enter ABI Parser State\n"); +} + +void AbiParserState::handle() { + print("Handle ABI Parser State\n"); +} + +void AbiParserState::exit() { + print("Exit ABI Parser State\n-------------\n"); + this->context->transition_state(new ValidatorState); +} + +//Validator +void ValidatorState::enter() { + print("Enter Validator State\n") +} + +void ValidatorState::handle() { + print("Handle Validator State\n"); +} + +void ValidatorState::exit() { + print("Exit Validator State\n-------------\n"); + this->context->transition_state(new OutputState); +} + +//Output +void OutputState::enter() { + print("Enter Output State\n"); +} + +void OutputState::handle() { + print("Handle Output State\n"); +} + +void OutputState::exit() { + print("Exit Output State\n-------------\n"); + this->context->transition_state(new OutputState); +} + +//Error +void ErrorState::enter() { + print("Enter Error State\n") +} + +void ErrorState::handle() { + print("Handle Error State\n"); +} + +void ErrorState::exit() { + print("Exit Error State\n-------------\n") +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 803741c..cb4a67e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,5 +16,22 @@ int main(int argc, char** argv) std::ignore = argc; std::ignore = argv; std::println("Hello C++: {}", __cplusplus); +#include "state.hpp" +#include "state_context.hpp" +#include "concrete_states.hpp" + +void state_init() { + UserInputState inital_state; + StateContext *context = new StateContext(&inital_state); + context->run_state(); + delete context; +} + +int main() +{ + std::println("yeet: {}", __cplusplus); + + state_init(); + return 0; } diff --git a/src/safe.cpp b/src/safe.cpp deleted file mode 100644 index 2072a06..0000000 --- a/src/safe.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "../include/safe.hpp" -#include "../include/concrete_state.hpp" - -Safe::Safe(){ - current_state = &UserInputState::get_instance(); -} - -void Safe::set_state(SafeState& new_state) { - current_state->exit(this); - current_state = &new_state; - current_state->enter(this); -} - -void Safe::toggle() { - current_state->toggle(this); -} \ No newline at end of file diff --git a/src/safe_state.cpp b/src/safe_state.cpp deleted file mode 100644 index 4f2eb6c..0000000 --- a/src/safe_state.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "../include/state.hpp" diff --git a/src/state.cpp b/src/state.cpp new file mode 100644 index 0000000..d100a3f --- /dev/null +++ b/src/state.cpp @@ -0,0 +1,5 @@ +#include "../include/state.hpp" + +void State::set_context(StateContext *context) { + this->context = context +} \ No newline at end of file diff --git a/src/state_context.cpp b/src/state_context.cpp new file mode 100644 index 0000000..85ab01f --- /dev/null +++ b/src/state_context.cpp @@ -0,0 +1,26 @@ +#include "../include/state.hpp" +#include "../include/concrete_state.hpp"de +#include "../include/state_context.hpp"; + +StateContext::StateContext(State *state){ + this->transition_state(state); +} + +StateContext::~StateContext() { + delete current_state +} + +void StateContext::transition_state(State* new_state) { + print("Transitioning\n"); + if(this->current_state != nullptr) { + delete this->current_state; + } + this->current_state = new_state; + this->current_state->set_context(this); +} + +void StateContext::run_state() { + self->current_state->enter(); + self->current_state->handle(); + self->current_state->exit(); +} \ No newline at end of file From 536a19429ec5499e827fb2c9698dbc9b66402625 Mon Sep 17 00:00:00 2001 From: Mchan2003 Date: Sat, 11 Oct 2025 12:19:30 -0700 Subject: [PATCH 3/7] complete state machine boiler plate --- CMakeLists.txt | 8 ++- include/concrete_states.hpp | 42 ++++++------- include/state.hpp | 15 ++--- include/state_context.hpp | 21 +++---- include/state_machine.hpp | 18 ++++++ src/concrete_states.cpp | 122 +++++++++++++++++++++--------------- src/main.cpp | 13 ++-- src/state.cpp | 5 -- src/state_context.cpp | 26 -------- src/state_machine.cpp | 27 ++++++++ 10 files changed, 161 insertions(+), 136 deletions(-) create mode 100644 include/state_machine.hpp delete mode 100644 src/state.cpp delete mode 100644 src/state_context.cpp create mode 100644 src/state_machine.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 198c830..b29c88c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,8 +12,12 @@ find_package(libelf REQUIRED) # Find package dependancies list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/build/Debug/generators") -#Linking Libraries -add_executable(${PROJECT_NAME} src/main.cpp src/elf_parser.cpp src/gcc_parse.cpp) +#Creating Executable Target +add_executable(${PROJECT_NAME} src/main.cpp + src/elf_parser.cpp + src/gcc_parse.cpp + src/state_machine.cpp + src/concrete_states.cpp) #Linking Libraries target_link_libraries(${PROJECT_NAME} PUBLIC ctre::ctre libelf::libelf) diff --git a/include/concrete_states.hpp b/include/concrete_states.hpp index d9007ee..52bc02a 100644 --- a/include/concrete_states.hpp +++ b/include/concrete_states.hpp @@ -4,49 +4,49 @@ class UserInputState : public State { public: - void enter() override; - void handle() override; - void exit() override; + void enter(StateContext& context) override; + void handle(StateContext& context) override; + State* exit(StateContext& context) override; }; class ElfParserState : public State { public: - void enter() override; - void handle() override; - void exit() override; + void enter(StateContext& context) override; + void handle(StateContext& context) override; + State* exit(StateContext& context) override; }; class CallgraphState : public State { public: - void enter() override; - void handle() override; - void exit() override; + void enter(StateContext& context) override; + void handle(StateContext& context) override; + State* exit(StateContext& context) override; }; class AbiParserState : public State { public: - void enter() override; - void handle() override; - void exit() override; + void enter(StateContext& context) override; + void handle(StateContext& context) override; + State* exit(StateContext& context) override; }; class ValidatorState : public State { public: - void enter() override; - void handle() override; - void exit() override; + void enter(StateContext& context) override; + void handle(StateContext& context) override; + State* exit(StateContext& context) override; }; class OutputState : public State { public: - void enter() override; - void handle() override; - void exit() override; + void enter(StateContext& context) override; + void handle(StateContext& context) override; + State* exit(StateContext& context) override; }; class ErrorState : public State { public: - void enter() override; - void handle() override; - void exit() override; + void enter(StateContext& context) override; + void handle(StateContext& context) override; + State* exit(StateContext& context) override; }; \ No newline at end of file diff --git a/include/state.hpp b/include/state.hpp index 33a4d2d..cce5b68 100644 --- a/include/state.hpp +++ b/include/state.hpp @@ -1,17 +1,12 @@ #pragma once +#include "./state_machine.hpp" #include "./state_context.hpp" -class StateContext; - class State { - protected: - StateContext *context; public: - virtual void enter() = 0; - virtual void handle() = 0; - virtual void exit() = 0; - - void set_context(StateContext *context); + virtual void enter(StateContext& context) = 0; + virtual void handle(StateContext& context) = 0; + virtual State* exit(StateContext& context) = 0; - virtual ~State() = 0; + virtual ~State() = default; }; \ No newline at end of file diff --git a/include/state_context.hpp b/include/state_context.hpp index 8dd0488..dd3e147 100644 --- a/include/state_context.hpp +++ b/include/state_context.hpp @@ -1,17 +1,10 @@ #pragma once -#include "./state.hpp" - -class State; +// class or struct idk class StateContext { - public: - StateContext(State *state); - ~StateContext(); - State* get_current_state(); - void run_state(); - void transition_state(State* new_state); - private: - State* current_state; - int total_state; -}; - + public: + void inc_data() {data++;} + int get_data() {return data;} + private: + int data = 0; +}; \ No newline at end of file diff --git a/include/state_machine.hpp b/include/state_machine.hpp new file mode 100644 index 0000000..19ffeec --- /dev/null +++ b/include/state_machine.hpp @@ -0,0 +1,18 @@ +#pragma once +#include "./state.hpp" +#include "./state_context.hpp" + +class State; + +class StateMachine { + public: + StateMachine(); + ~StateMachine(); + State* get_current_state(); + void run_state(); + void transition_state(State* new_state); + private: + State *current_state; + StateContext context; +}; + diff --git a/src/concrete_states.cpp b/src/concrete_states.cpp index 06237ce..f48a241 100644 --- a/src/concrete_states.cpp +++ b/src/concrete_states.cpp @@ -1,100 +1,122 @@ -#include "../include/concrete_state.hpp" +#include "../include/concrete_states.hpp" #include "../include/state.hpp" -#include "../include/state_context.hpp" +#include "../include/state_machine.hpp" //User Input -void UserInputState::enter() { - print("Enter User Input State\n"); +void UserInputState::enter(StateContext& context) { + std::print("Enter User Input State\n"); + std::print("Previous Number: {}\n", context.get_data()); } -void UserInputState::handle() { - print("Handle User Input State\n"); +void UserInputState::handle(StateContext& context) { + std::print("Handle User Input State\n"); + context.inc_data(); } -void UserInputState::exit() { - print("Exit User Input State\n-------------\n"); - this->contect->transition_state(new ElfParserState); +State* UserInputState::exit(StateContext& context) { + std::print("Exit User Input State\n-------------\n"); + (void) context; + return new ElfParserState; } //Elf Parser -void ElfParserState::enter() { - print("Enter Elf Parser State\n"); +void ElfParserState::enter(StateContext& context) { + std::print("Enter Elf Parser State\n"); + std::print("Previous Number: {}\n", context.get_data()); } -void ElfParserState::handle() { - print("Handle Elf Parser State\n"); +void ElfParserState::handle(StateContext& context) { + std::print("Handle Elf Parser State\n"); + context.inc_data(); } -void ElfParserState::exit() { - print("Exit Elf Parser State\n-------------\n"); - this->context->transition_state(new CallgraphState); +State* ElfParserState::exit(StateContext& context) { + std::print("Exit Elf Parser State\n-------------\n"); + (void) context; + return new CallgraphState; } //Callgraph -void CallgraphState::enter() { - print("Enter Callgraph State\n"); +void CallgraphState::enter(StateContext& context) { + std::print("Enter Callgraph State\n"); + std::print("Previous Number: {}\n", context.get_data()); } -void CallgraphState::handle() { - print("Handle Callgraph State\n"); +void CallgraphState::handle(StateContext& context) { + context.inc_data(); + std::print("Handle Callgraph State\n"); } -void CallgraphState::exit() { - print("Exit Callgraph State\n-------------\n"); - this->context->transition_state(new AbiParserState); +State* CallgraphState::exit(StateContext& context) { + std::print("Exit Callgraph State\n-------------\n"); + (void) context; + return new AbiParserState; } //Abi Parser -void AbiParserState::enter() { - print("Enter ABI Parser State\n"); +void AbiParserState::enter(StateContext& context) { + std::print("Enter ABI Parser State\n"); + std::print("Previous Number: {}\n", context.get_data()); } -void AbiParserState::handle() { - print("Handle ABI Parser State\n"); +void AbiParserState::handle(StateContext& context) { + std::print("Handle ABI Parser State\n"); + context.inc_data(); } -void AbiParserState::exit() { - print("Exit ABI Parser State\n-------------\n"); - this->context->transition_state(new ValidatorState); +State* AbiParserState::exit(StateContext& context) { + std::print("Exit ABI Parser State\n-------------\n"); + (void) context; + return new ValidatorState; } //Validator -void ValidatorState::enter() { - print("Enter Validator State\n") +void ValidatorState::enter(StateContext& context) { + std::print("Enter Validator State\n"); + std::print("Previous Number: {}\n", context.get_data()); } -void ValidatorState::handle() { - print("Handle Validator State\n"); +void ValidatorState::handle(StateContext& context) { + std::print("Handle Validator State\n"); + context.inc_data(); } -void ValidatorState::exit() { - print("Exit Validator State\n-------------\n"); - this->context->transition_state(new OutputState); +State* ValidatorState::exit(StateContext& context) { + std::print("Exit Validator State\n-------------\n"); + (void) context; + return new OutputState; } //Output -void OutputState::enter() { - print("Enter Output State\n"); +void OutputState::enter(StateContext& context) { + std::print("Enter Output State\n"); + std::print("Previous Number: {}\n", context.get_data()); } -void OutputState::handle() { - print("Handle Output State\n"); +void OutputState::handle(StateContext& context) { + std::print("Handle Output State\n"); + context.inc_data(); } -void OutputState::exit() { - print("Exit Output State\n-------------\n"); - this->context->transition_state(new OutputState); +State* OutputState::exit(StateContext& context) { + std::print("Exit Output State\n-------------\n"); + (void) context; + return nullptr; } //Error -void ErrorState::enter() { - print("Enter Error State\n") +void ErrorState::enter(StateContext& context) { + std::print("Enter Error State\n"); + (void) context; } -void ErrorState::handle() { - print("Handle Error State\n"); +void ErrorState::handle(StateContext& context) { + std::print("Handle Error State\n"); + (void) context; } -void ErrorState::exit() { - print("Exit Error State\n-------------\n") +State* ErrorState::exit(StateContext& context) { + std::print("Exit Error State\n-------------\n"); + (void) context; + return nullptr; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index cb4a67e..d9ebc32 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,18 +20,15 @@ int main(int argc, char** argv) #include "state_context.hpp" #include "concrete_states.hpp" -void state_init() { - UserInputState inital_state; - StateContext *context = new StateContext(&inital_state); - context->run_state(); - delete context; -} - int main() { std::println("yeet: {}", __cplusplus); - state_init(); + StateMachine sm; + + while(sm.get_current_state() != nullptr){ + sm.run_state(); + } return 0; } diff --git a/src/state.cpp b/src/state.cpp deleted file mode 100644 index d100a3f..0000000 --- a/src/state.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "../include/state.hpp" - -void State::set_context(StateContext *context) { - this->context = context -} \ No newline at end of file diff --git a/src/state_context.cpp b/src/state_context.cpp deleted file mode 100644 index 85ab01f..0000000 --- a/src/state_context.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "../include/state.hpp" -#include "../include/concrete_state.hpp"de -#include "../include/state_context.hpp"; - -StateContext::StateContext(State *state){ - this->transition_state(state); -} - -StateContext::~StateContext() { - delete current_state -} - -void StateContext::transition_state(State* new_state) { - print("Transitioning\n"); - if(this->current_state != nullptr) { - delete this->current_state; - } - this->current_state = new_state; - this->current_state->set_context(this); -} - -void StateContext::run_state() { - self->current_state->enter(); - self->current_state->handle(); - self->current_state->exit(); -} \ No newline at end of file diff --git a/src/state_machine.cpp b/src/state_machine.cpp new file mode 100644 index 0000000..bcf79cd --- /dev/null +++ b/src/state_machine.cpp @@ -0,0 +1,27 @@ +#include "../include/state.hpp" +#include "../include/concrete_states.hpp" +#include "../include/state_machine.hpp" + +#include + +StateMachine::StateMachine(){ + current_state = new UserInputState; +} + +StateMachine::~StateMachine() { + delete current_state; +} + +State * StateMachine::get_current_state(){ + return current_state; +} + +void StateMachine::run_state() { + current_state->enter(context); + current_state->handle(context); + transition_state (current_state->exit(context)); +} + +void StateMachine::transition_state(State* new_state) { + this->current_state = new_state; +} \ No newline at end of file From 3c260b6cbdea1c0ebcf816e55f6dc179939b2bf1 Mon Sep 17 00:00:00 2001 From: Mchan2003 Date: Sat, 11 Oct 2025 12:44:48 -0700 Subject: [PATCH 4/7] fixed syntax errors from rebase --- include/state_context.hpp | 7 ++++++- src/concrete_states.cpp | 40 ++++++++++++++++++++++----------------- src/main.cpp | 11 ++++------- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/include/state_context.hpp b/include/state_context.hpp index dd3e147..dd4a806 100644 --- a/include/state_context.hpp +++ b/include/state_context.hpp @@ -1,6 +1,11 @@ #pragma once -// class or struct idk +/** + * @brief Content in this is temporary. Please change + * them according to what the state desires. All data relating to + * SAFE will be stored here and shared between the states. + * + */ class StateContext { public: void inc_data() {data++;} diff --git a/src/concrete_states.cpp b/src/concrete_states.cpp index f48a241..c3eef7a 100644 --- a/src/concrete_states.cpp +++ b/src/concrete_states.cpp @@ -2,7 +2,13 @@ #include "../include/state.hpp" #include "../include/state_machine.hpp" -//User Input +/** + * @brief Content for each of function is temporary. Please change + * them according to what the state desires + * + */ + + void UserInputState::enter(StateContext& context) { std::print("Enter User Input State\n"); std::print("Previous Number: {}\n", context.get_data()); @@ -15,11 +21,11 @@ void UserInputState::handle(StateContext& context) { State* UserInputState::exit(StateContext& context) { std::print("Exit User Input State\n-------------\n"); - (void) context; + std::ignore = context; return new ElfParserState; } -//Elf Parser + void ElfParserState::enter(StateContext& context) { std::print("Enter Elf Parser State\n"); std::print("Previous Number: {}\n", context.get_data()); @@ -32,28 +38,28 @@ void ElfParserState::handle(StateContext& context) { State* ElfParserState::exit(StateContext& context) { std::print("Exit Elf Parser State\n-------------\n"); - (void) context; + std::ignore = context; return new CallgraphState; } -//Callgraph + void CallgraphState::enter(StateContext& context) { std::print("Enter Callgraph State\n"); std::print("Previous Number: {}\n", context.get_data()); } void CallgraphState::handle(StateContext& context) { - context.inc_data(); + std::ignore = context; std::print("Handle Callgraph State\n"); } State* CallgraphState::exit(StateContext& context) { std::print("Exit Callgraph State\n-------------\n"); - (void) context; + std::ignore = context; return new AbiParserState; } -//Abi Parser + void AbiParserState::enter(StateContext& context) { std::print("Enter ABI Parser State\n"); std::print("Previous Number: {}\n", context.get_data()); @@ -66,11 +72,11 @@ void AbiParserState::handle(StateContext& context) { State* AbiParserState::exit(StateContext& context) { std::print("Exit ABI Parser State\n-------------\n"); - (void) context; + std::ignore = context; return new ValidatorState; } -//Validator + void ValidatorState::enter(StateContext& context) { std::print("Enter Validator State\n"); std::print("Previous Number: {}\n", context.get_data()); @@ -83,11 +89,11 @@ void ValidatorState::handle(StateContext& context) { State* ValidatorState::exit(StateContext& context) { std::print("Exit Validator State\n-------------\n"); - (void) context; + std::ignore = context; return new OutputState; } -//Output + void OutputState::enter(StateContext& context) { std::print("Enter Output State\n"); std::print("Previous Number: {}\n", context.get_data()); @@ -100,23 +106,23 @@ void OutputState::handle(StateContext& context) { State* OutputState::exit(StateContext& context) { std::print("Exit Output State\n-------------\n"); - (void) context; + std::ignore = context; return nullptr; } -//Error + void ErrorState::enter(StateContext& context) { std::print("Enter Error State\n"); - (void) context; + std::ignore = context; } void ErrorState::handle(StateContext& context) { std::print("Handle Error State\n"); - (void) context; + std::ignore = context; } State* ErrorState::exit(StateContext& context) { std::print("Exit Error State\n-------------\n"); - (void) context; + std::ignore = context; return nullptr; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index d9ebc32..6a74de6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,10 @@ * @copyright Copyright (c) 2025 * */ +#include "state.hpp" +#include "state_context.hpp" +#include "concrete_states.hpp" + #include #include @@ -16,13 +20,6 @@ int main(int argc, char** argv) std::ignore = argc; std::ignore = argv; std::println("Hello C++: {}", __cplusplus); -#include "state.hpp" -#include "state_context.hpp" -#include "concrete_states.hpp" - -int main() -{ - std::println("yeet: {}", __cplusplus); StateMachine sm; From e9b71c9bdc15ac485b17fa1dc002939f91b62062 Mon Sep 17 00:00:00 2001 From: Mchan2003 Date: Sun, 9 Nov 2025 13:35:43 -0800 Subject: [PATCH 5/7] added std::optional and unique_ptr to remove memory leak and added unit tests --- CMakeLists.txt | 5 +- conanfile.py | 2 +- include/concrete_states.hpp | 16 ++--- include/state.hpp | 4 +- include/state_machine.hpp | 9 ++- src/concrete_states.cpp | 50 +++++----------- src/main.cpp | 5 +- src/state_machine.cpp | 27 +++++---- tests/main.test.cpp | 6 ++ tests/state_machine.test.cpp | 110 +++++++++++++++++++++++++++++++++++ 10 files changed, 172 insertions(+), 62 deletions(-) create mode 100644 tests/state_machine.test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b29c88c..9c65583 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,7 +49,10 @@ target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILER_BUILD_FLAGS}) libhal_unit_test(SOURCES tests/main.test.cpp - tests/testing.test.cpp + # tests/testing.test.cpp + + src/state_machine.cpp + src/concrete_states.cpp PACKAGES tl-function-ref diff --git a/conanfile.py b/conanfile.py index 8f58551..31f8fe5 100644 --- a/conanfile.py +++ b/conanfile.py @@ -49,7 +49,7 @@ def build_requirements(self): """ def layout(self): cmake_layout(self) - + """ Method to build the project """ diff --git a/include/concrete_states.hpp b/include/concrete_states.hpp index 52bc02a..ce5dfaf 100644 --- a/include/concrete_states.hpp +++ b/include/concrete_states.hpp @@ -1,52 +1,54 @@ #pragma once #include +#include +#include #include "./state.hpp" class UserInputState : public State { public: void enter(StateContext& context) override; void handle(StateContext& context) override; - State* exit(StateContext& context) override; + std::optional> exit(StateContext& context) override; }; class ElfParserState : public State { public: void enter(StateContext& context) override; void handle(StateContext& context) override; - State* exit(StateContext& context) override; + std::optional> exit(StateContext& context) override; }; class CallgraphState : public State { public: void enter(StateContext& context) override; void handle(StateContext& context) override; - State* exit(StateContext& context) override; + std::optional> exit(StateContext& context) override; }; class AbiParserState : public State { public: void enter(StateContext& context) override; void handle(StateContext& context) override; - State* exit(StateContext& context) override; + std::optional> exit(StateContext& context) override; }; class ValidatorState : public State { public: void enter(StateContext& context) override; void handle(StateContext& context) override; - State* exit(StateContext& context) override; + std::optional> exit(StateContext& context) override; }; class OutputState : public State { public: void enter(StateContext& context) override; void handle(StateContext& context) override; - State* exit(StateContext& context) override; + std::optional> exit(StateContext& context) override; }; class ErrorState : public State { public: void enter(StateContext& context) override; void handle(StateContext& context) override; - State* exit(StateContext& context) override; + std::optional> exit(StateContext& context) override; }; \ No newline at end of file diff --git a/include/state.hpp b/include/state.hpp index cce5b68..96cd7dc 100644 --- a/include/state.hpp +++ b/include/state.hpp @@ -1,4 +1,6 @@ #pragma once +#include +#include #include "./state_machine.hpp" #include "./state_context.hpp" @@ -6,7 +8,7 @@ class State { public: virtual void enter(StateContext& context) = 0; virtual void handle(StateContext& context) = 0; - virtual State* exit(StateContext& context) = 0; + virtual std::optional> exit(StateContext& context) = 0; virtual ~State() = default; }; \ No newline at end of file diff --git a/include/state_machine.hpp b/include/state_machine.hpp index 19ffeec..1b81359 100644 --- a/include/state_machine.hpp +++ b/include/state_machine.hpp @@ -1,4 +1,6 @@ #pragma once +#include +#include #include "./state.hpp" #include "./state_context.hpp" @@ -8,11 +10,12 @@ class StateMachine { public: StateMachine(); ~StateMachine(); - State* get_current_state(); + std::optional> get_current_state(); + StateContext get_context(); void run_state(); - void transition_state(State* new_state); + void transition_state(std::optional> new_state); private: - State *current_state; + std::optional> current_state; StateContext context; }; diff --git a/src/concrete_states.cpp b/src/concrete_states.cpp index c3eef7a..70a0708 100644 --- a/src/concrete_states.cpp +++ b/src/concrete_states.cpp @@ -10,119 +10,99 @@ void UserInputState::enter(StateContext& context) { - std::print("Enter User Input State\n"); std::print("Previous Number: {}\n", context.get_data()); } void UserInputState::handle(StateContext& context) { - std::print("Handle User Input State\n"); context.inc_data(); } -State* UserInputState::exit(StateContext& context) { - std::print("Exit User Input State\n-------------\n"); +std::optional> UserInputState::exit(StateContext& context) { std::ignore = context; - return new ElfParserState; + return std::make_unique(); } void ElfParserState::enter(StateContext& context) { - std::print("Enter Elf Parser State\n"); std::print("Previous Number: {}\n", context.get_data()); } void ElfParserState::handle(StateContext& context) { - std::print("Handle Elf Parser State\n"); context.inc_data(); } -State* ElfParserState::exit(StateContext& context) { - std::print("Exit Elf Parser State\n-------------\n"); +std::optional> ElfParserState::exit(StateContext& context) { std::ignore = context; - return new CallgraphState; + return std::make_unique(); } void CallgraphState::enter(StateContext& context) { - std::print("Enter Callgraph State\n"); std::print("Previous Number: {}\n", context.get_data()); } void CallgraphState::handle(StateContext& context) { std::ignore = context; - std::print("Handle Callgraph State\n"); + context.inc_data(); } -State* CallgraphState::exit(StateContext& context) { - std::print("Exit Callgraph State\n-------------\n"); +std::optional> CallgraphState::exit(StateContext& context) { std::ignore = context; - return new AbiParserState; + return std::make_unique(); } void AbiParserState::enter(StateContext& context) { - std::print("Enter ABI Parser State\n"); std::print("Previous Number: {}\n", context.get_data()); } void AbiParserState::handle(StateContext& context) { - std::print("Handle ABI Parser State\n"); context.inc_data(); } -State* AbiParserState::exit(StateContext& context) { - std::print("Exit ABI Parser State\n-------------\n"); +std::optional> AbiParserState::exit(StateContext& context) { std::ignore = context; - return new ValidatorState; + return std::make_unique(); } void ValidatorState::enter(StateContext& context) { - std::print("Enter Validator State\n"); std::print("Previous Number: {}\n", context.get_data()); } void ValidatorState::handle(StateContext& context) { - std::print("Handle Validator State\n"); context.inc_data(); } -State* ValidatorState::exit(StateContext& context) { - std::print("Exit Validator State\n-------------\n"); +std::optional> ValidatorState::exit(StateContext& context) { std::ignore = context; - return new OutputState; + return std::make_unique(); } void OutputState::enter(StateContext& context) { - std::print("Enter Output State\n"); std::print("Previous Number: {}\n", context.get_data()); } void OutputState::handle(StateContext& context) { - std::print("Handle Output State\n"); context.inc_data(); } -State* OutputState::exit(StateContext& context) { - std::print("Exit Output State\n-------------\n"); +std::optional> OutputState::exit(StateContext& context) { std::ignore = context; - return nullptr; + return std::nullopt; } void ErrorState::enter(StateContext& context) { - std::print("Enter Error State\n"); std::ignore = context; } void ErrorState::handle(StateContext& context) { - std::print("Handle Error State\n"); std::ignore = context; } -State* ErrorState::exit(StateContext& context) { - std::print("Exit Error State\n-------------\n"); +std::optional> ErrorState::exit(StateContext& context) { std::ignore = context; - return nullptr; + return std::nullopt; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 6a74de6..2dd9d5e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,10 +22,7 @@ int main(int argc, char** argv) std::println("Hello C++: {}", __cplusplus); StateMachine sm; - - while(sm.get_current_state() != nullptr){ - sm.run_state(); - } + sm.run_state(); return 0; } diff --git a/src/state_machine.cpp b/src/state_machine.cpp index bcf79cd..d6ced4d 100644 --- a/src/state_machine.cpp +++ b/src/state_machine.cpp @@ -5,23 +5,30 @@ #include StateMachine::StateMachine(){ - current_state = new UserInputState; + current_state = std::make_unique(); } -StateMachine::~StateMachine() { - delete current_state; +StateMachine::~StateMachine() = default; + +std::optional> StateMachine::get_current_state(){ + if(current_state){ + return std::ref(**current_state); + } + return std::nullopt; } -State * StateMachine::get_current_state(){ - return current_state; +StateContext StateMachine::get_context(){ + return context; } void StateMachine::run_state() { - current_state->enter(context); - current_state->handle(context); - transition_state (current_state->exit(context)); + while(current_state != std::nullopt){ + current_state.value()->enter(context); + current_state.value()->handle(context); + transition_state (current_state.value()->exit(context)); + } } -void StateMachine::transition_state(State* new_state) { - this->current_state = new_state; +void StateMachine::transition_state(std::optional> new_state) { + this->current_state = std::move(new_state); } \ No newline at end of file diff --git a/tests/main.test.cpp b/tests/main.test.cpp index 36712f5..25e6cd9 100644 --- a/tests/main.test.cpp +++ b/tests/main.test.cpp @@ -1,4 +1,10 @@ +#include "state_machine.test.cpp" + +void state_machine_tests(); + int main() { // Position dependent test go below: + state_machine_tests(); + return 0; } \ No newline at end of file diff --git a/tests/state_machine.test.cpp b/tests/state_machine.test.cpp new file mode 100644 index 0000000..692b162 --- /dev/null +++ b/tests/state_machine.test.cpp @@ -0,0 +1,110 @@ +#include "state_machine.hpp" +#include "concrete_states.hpp" +#include "state.hpp" +#include "state_context.hpp" +#include +#include +#include +#include +#include +#include +#include + +// Mock State for testing +class MockState : public State +{ + public: + bool enter_called = false; + bool handle_called = false; + bool exit_called = false; + + void enter(StateContext& context) override + { + std::ignore = context; + enter_called = true; + } + + void handle(StateContext& context) override + { + std::ignore = context; + handle_called = true; + } + + std::optional> exit(StateContext& context) override + { + std::ignore = context; + exit_called = true; + return std::nullopt; + } +}; + +void state_machine_tests() +{ + using namespace boost::ut; + + "StateMachine"_test = [] { + "Initalize inital state"_test = [] { + StateMachine sm; + auto actual_state = sm.get_current_state(); + expect(actual_state.has_value()) << "A State is initialized"; + + State& actual_state_ref = actual_state.value().get(); + expect(typeid(actual_state_ref) == typeid(UserInputState)) << "Initial state should be UserInputState"; + }; + + "Transition State"_test = [] { + StateMachine sm; + std::optional> mock_state = std::make_unique(); + sm.transition_state(std::move(mock_state)); + + auto actual_state = sm.get_current_state(); + expect(actual_state.has_value()) << "A State is initialized"; + + State& actual_state_ref = actual_state.value().get(); + expect(typeid(actual_state_ref) == typeid(MockState)) << "State should transition to MockState"; + }; + + "State calling enter, handle, and exit"_test = [] { + StateMachine sm; + auto mock_state = std::make_unique(); + auto* mock_ptr = mock_state.get(); + + sm.transition_state(std::move(mock_state)); + + auto state = sm.get_current_state(); + if (state.has_value()) { + StateContext context; + state.value().get().enter(context); + state.value().get().handle(context); + state.value().get().exit(context); + } + + expect(mock_ptr->enter_called) << "Should run enter()"; + expect(mock_ptr->handle_called) << "Should run handle()"; + expect(mock_ptr->exit_called) << "Should run exit()"; + }; + + "State Transition Order"_test = [] { + StateMachine sm; + StateContext context = sm.get_context(); + std::optional> actual_state; + std::vector state_order = { + typeid(UserInputState), + typeid(ElfParserState), + typeid(CallgraphState), + typeid(AbiParserState), + typeid(ValidatorState), + typeid(OutputState) + }; + + for (auto& expect_state : state_order){ + actual_state = sm.get_current_state(); + State& actual_state_ref = actual_state.value().get(); + expect(typeid(actual_state_ref) == expect_state) << "State should transition to MockState"; + actual_state_ref.enter(context); + actual_state_ref.handle(context); + sm.transition_state(actual_state_ref.exit(context)); + } + }; + }; +} \ No newline at end of file From c96973b528d8985b2cd365434c639c02dfcb5478 Mon Sep 17 00:00:00 2001 From: Mchan2003 Date: Sun, 9 Nov 2025 17:12:04 -0800 Subject: [PATCH 6/7] reformated files and added doxygen documentation --- include/concrete_states.hpp | 269 ++++++++++++++++++++++++++++++----- include/state.hpp | 82 +++++++++-- include/state_context.hpp | 22 ++- include/state_machine.hpp | 132 +++++++++++++++-- src/concrete_states.cpp | 123 +++++++++------- src/main.cpp | 3 +- src/state_machine.cpp | 43 +++--- tests/state_machine.test.cpp | 48 ++++--- 8 files changed, 555 insertions(+), 167 deletions(-) diff --git a/include/concrete_states.hpp b/include/concrete_states.hpp index ce5dfaf..a1472cf 100644 --- a/include/concrete_states.hpp +++ b/include/concrete_states.hpp @@ -1,54 +1,247 @@ +/** + * @file concrete_states.hpp + * @brief Concrete state implementations for the state machine. + * + * This file defines all concrete states used in the state machine workflow. + * Each state represents a distinct phase in the processing pipeline, from + * user input through validation to output generation. + * + * The states follow a sequential workflow: + * UserInput → ElfParser → Callgraph → AbiParser → Validator → Output + * + * ErrorState can be entered from any state when an error occurs. + */ + #pragma once -#include -#include #include -#include "./state.hpp" +#include +#include -class UserInputState : public State { - public: - void enter(StateContext& context) override; - void handle(StateContext& context) override; - std::optional> exit(StateContext& context) override; +#include "state.hpp" +#include "state_context.hpp" + +/** + * @class UserInputState + * @brief Initial state that handles user input collection and validation. + * + * This is the entry point of the state machine. It processes user input, + * validates parameters, and prepares the context for subsequent states. + * + * @note This is the default initial state of the StateMachine. + */ +class UserInputState : public State +{ + public: + /** + * @brief Initialize user input processing. + * @param p_context Shared state context for storing input data. + */ + void enter(StateContext& p_context) override; + + /** + * @brief Process and validate user input. + * @param p_context Context to store validated input parameters. + */ + void handle(StateContext& p_context) override; + + /** + * @brief Transition to ElfParserState or ErrorState. + * @param p_context Context containing validated input. + * @return Next state (typically ElfParserState) or ErrorState on failure. + */ + std::optional> exit( + StateContext& p_context) override; }; -class ElfParserState : public State { - public: - void enter(StateContext& context) override; - void handle(StateContext& context) override; - std::optional> exit(StateContext& context) override; +/** + * @class ElfParserState + * @brief Parses ELF (Executable and Linkable Format) binary files. + * + * This state reads and analyzes ELF binaries, extracting relevant information + * such as symbols, sections, and metadata needed for further processing. + */ +class ElfParserState : public State +{ + public: + /** + * @brief Initialize ELF parsing resources. + * @param p_context Context containing file paths and configuration. + */ + void enter(StateContext& p_context) override; + + /** + * @brief Parse the ELF binary and extract data. + * @param p_context Context to store parsed ELF information. + */ + void handle(StateContext& p_context) override; + + /** + * @brief Transition to CallgraphState or ErrorState. + * @param p_context Context containing parsed ELF data. + * @return Next state (typically CallgraphState) or ErrorState on parse + * failure. + */ + std::optional> exit( + StateContext& p_context) override; }; -class CallgraphState : public State { - public: - void enter(StateContext& context) override; - void handle(StateContext& context) override; - std::optional> exit(StateContext& context) override; +/** + * @class CallgraphState + * @brief Generates and analyzes the call graph from parsed binary data. + * + * This state parses the GCC call graph representing function relationships + * and dependencies within the analyzed binary. + */ +class CallgraphState : public State +{ + public: + /** + * @brief Initialize call graph generation. + * @param p_context Context containing parsed binary data. + */ + void enter(StateContext& p_context) override; + + /** + * @brief Build the call graph structure. + * @param p_context Context to store the generated call graph. + */ + void handle(StateContext& p_context) override; + + /** + * @brief Transition to AbiParserState or ErrorState. + * @param p_context Context containing the call graph. + * @return Next state (typically AbiParserState) or ErrorState on failure. + */ + std::optional> exit( + StateContext& p_context) override; }; -class AbiParserState : public State { - public: - void enter(StateContext& context) override; - void handle(StateContext& context) override; - std::optional> exit(StateContext& context) override; +/** + * @class AbiParserState + * @brief Parses and analyzes Application Binary Interface (ABI) information. + * + * This state extracts and processes ABI-related data, including function + * signatures, calling conventions, and interface specifications. + */ +class AbiParserState : public State +{ + public: + /** + * @brief Initialize ABI parsing. + * @param p_context Context containing call graph and binary data. + */ + void enter(StateContext& p_context) override; + + /** + * @brief Parse ABI specifications and interface data. + * @param p_context Context to store parsed ABI information. + */ + void handle(StateContext& p_context) override; + + /** + * @brief Transition to ValidatorState or ErrorState. + * @param p_context Context containing ABI data. + * @return Next state (typically ValidatorState) or ErrorState on parse + * failure. + */ + std::optional> exit( + StateContext& p_context) override; }; -class ValidatorState : public State { - public: - void enter(StateContext& context) override; - void handle(StateContext& context) override; - std::optional> exit(StateContext& context) override; +/** + * @class ValidatorState + * @brief Validates the processed data for correctness and consistency. + * + * This state performs validation checks on the parsed and processed data + * to ensure exceptions meets requirements and is internally consistent before + * output. + */ +class ValidatorState : public State +{ + public: + /** + * @brief Initialize validation checks. + * @param p_context Context containing all processed data. + */ + void enter(StateContext& p_context) override; + + /** + * @brief Perform validation on processed data. + * @param p_context Context containing data to validate. + */ + void handle(StateContext& p_context) override; + + /** + * @brief Transition to OutputState or ErrorState. + * @param p_context Context with validation results. + * @return Next state (OutputState if valid) or ErrorState on validation + * failure. + */ + std::optional> exit( + StateContext& p_context) override; }; -class OutputState : public State { - public: - void enter(StateContext& context) override; - void handle(StateContext& context) override; - std::optional> exit(StateContext& context) override; +/** + * @class OutputState + * @brief Generates and writes the final output. + * + * This is the final state in the normal execution flow. It formats and + * outputs the processed results to the specified destination. + */ +class OutputState : public State +{ + public: + /** + * @brief Initialize output generation. + * @param p_context Context containing validated data to output. + */ + void enter(StateContext& p_context) override; + + /** + * @brief Generate and write output. + * @param p_context Context containing all processed data. + */ + void handle(StateContext& p_context) override; + + /** + * @brief Complete execution and terminate state machine. + * @param p_context Context with output results. + * @return std::nullopt to signal state machine completion. + */ + std::optional> exit( + StateContext& p_context) override; }; -class ErrorState : public State { - public: - void enter(StateContext& context) override; - void handle(StateContext& context) override; - std::optional> exit(StateContext& context) override; +/** + * @class ErrorState + * @brief Handles error conditions and cleanup. + * + * This state is entered when an error occurs in any other state. It handles + * error reporting, logging, and cleanup operations before terminating the + * state machine. + * + * @note This state always returns std::nullopt to terminate execution. + */ +class ErrorState : public State +{ + public: + /** + * @brief Initialize error handling. + * @param p_context Context containing error information. + */ + void enter(StateContext& p_context) override; + + /** + * @brief Process and report the error. + * @param p_context Context with error details for reporting. + */ + void handle(StateContext& p_context) override; + + /** + * @brief Terminate state machine after error handling. + * @param p_context Context after error processing. + * @return std::nullopt to signal state machine termination. + */ + std::optional> exit( + StateContext& p_context) override; }; \ No newline at end of file diff --git a/include/state.hpp b/include/state.hpp index 96cd7dc..19060f2 100644 --- a/include/state.hpp +++ b/include/state.hpp @@ -1,14 +1,78 @@ #pragma once -#include #include -#include "./state_machine.hpp" -#include "./state_context.hpp" +#include + +#include "state_context.hpp" + +/** + * @class State + * @brief Abstract base class for all states in the state machine. + * + * The State class defines the interface that all concrete states must + * implement. Each state has three lifecycle phases: enter (initialization), + * handle (main logic), and exit (cleanup and transition). States use the + * StateContext to access shared data and determine transitions. + * + * Concrete states should inherit from this class and implement all three pure + * virtual methods to define their specific behavior. + * + * @note This is an abstract class and cannot be instantiated directly. + * @see StateMachine + * @see StateContext + * @see state_context.hpp + */ +class State +{ + public: + /** + * @brief Called when entering the state. + * + * This method is invoked when the state machine transitions into this + * state. It should perform any initialization or setup required before the + * state's main logic executes. + * + * @param context Reference to the shared state context containing data + * and configuration accessible to all states. + * + * @note This is called before handle() in the state lifecycle. + */ + virtual void enter(StateContext& p_context) = 0; + + /** + * @brief Executes the main logic of the state. + * + * This method contains the primary behavior and operations of the state. + * It is called after enter() and before exit() during state execution. + * + * @param context Reference to the shared state context for accessing + * and modifying shared data. + * + * @note This is where the state performs its core functionality. + */ + virtual void handle(StateContext& p_context) = 0; -class State { - public: - virtual void enter(StateContext& context) = 0; - virtual void handle(StateContext& context) = 0; - virtual std::optional> exit(StateContext& context) = 0; + /** + * @brief Called when exiting the state and determines the next state. + * + * This method is invoked after handle() completes. It should perform any + * cleanup operations and return the next state to transition to. If this + * returns std::nullopt, the state machine will terminate. + * + * @param context Reference to the shared state context for accessing + * data needed to determine the next state. + * + * @return std::optional> The next state to + * transition to, or std::nullopt to terminate the state machine. + * + * @note Returning std::nullopt signals the end of state machine execution. + * @note The returned state's ownership is transferred to the state machine. + */ + virtual std::optional> exit(StateContext& p_context) + = 0; - virtual ~State() = default; + /** + * @brief Virtual destructor for proper cleanup of derived classes. + * + */ + virtual ~State() = default; }; \ No newline at end of file diff --git a/include/state_context.hpp b/include/state_context.hpp index dd4a806..718895e 100644 --- a/include/state_context.hpp +++ b/include/state_context.hpp @@ -2,14 +2,22 @@ /** * @brief Content in this is temporary. Please change - * them according to what the state desires. All data relating to + * them according to what the state desires. All data relating to * SAFE will be stored here and shared between the states. * */ -class StateContext { - public: - void inc_data() {data++;} - int get_data() {return data;} - private: - int data = 0; +class StateContext +{ + public: + void inc_data() + { + data++; + } + int get_data() + { + return data; + } + + private: + int data = 0; }; \ No newline at end of file diff --git a/include/state_machine.hpp b/include/state_machine.hpp index 1b81359..8e2728b 100644 --- a/include/state_machine.hpp +++ b/include/state_machine.hpp @@ -1,21 +1,123 @@ #pragma once -#include #include -#include "./state.hpp" -#include "./state_context.hpp" +#include +#include + +#include "concrete_states.hpp" +#include "state.hpp" +#include "state_context.hpp" class State; -class StateMachine { - public: - StateMachine(); - ~StateMachine(); - std::optional> get_current_state(); - StateContext get_context(); - void run_state(); - void transition_state(std::optional> new_state); - private: - std::optional> current_state; - StateContext context; -}; +/** + * @class StateMachine + * @brief Manages state transitions and execution in a finite state machine. + * + * The StateMachine class implements a complete state machine that automatically + * executes states in sequence. Each state performs its enter, handle, and exit + * operations, with the exit operation determining the next state transition. + * The machine runs until a state returns std::nullopt, indicating completion. + * + * @note The state machine begins with UserInputState as the initial state. + * @note States are owned exclusively by the state machine via unique pointers. + * @see State + * @see StateContext + * @see concrete_states.hpp + */ +class StateMachine +{ + public: + /** + * @brief Constructs a new StateMachine with UserInputState as the initial + * state. + * + * Initializes the state machine with a default context and sets + * UserInputState as the starting state. + */ + StateMachine(); + + /** + * @brief Destroys the StateMachine. + * + * Default destructor that cleans up the current state and context. + */ + ~StateMachine() = default; + + /** + * @brief Gets a reference to the current state. + * + * Retrieves the currently active state without transferring ownership. + * The reference remains valid until the state transitions. + * + * @return std::optional> A reference to + * the current state, or std::nullopt if no state is active. + * + * @note This dereferences the optional and unique_ptr to return a direct + * reference to the State object. + */ + std::optional> get_current_state(); + /** + * @brief Gets the reference of the current state context. + * + * Retrieves the reference of the context containing shared data and + * configuration used by states during execution. + * + * @return StateContext A reference of the current context. + */ + StateContext& get_context(); + + /** + * @brief Executes the state machine until completion. + * + * Runs a continuous loop that executes each state's full lifecycle: + * 1. Calls enter() on the current state + * 2. Calls handle() to perform the state's main logic + * 3. Calls exit() which returns the next state (or nullopt to terminate) + * 4. Transitions to the next state + * + * The loop continues until a state's exit() method returns std::nullopt, + * indicating the state machine has completed its execution. + * + * @note This is a blocking operation that runs until the state machine + * reaches a terminal state. + * @see State::enter() + * @see State::handle() + * @see State::exit() + */ + void run_state(); + + /** + * @brief Transitions to a new state by moving ownership. + * + * Replaces the current state with the new state. If p_new_state is + * std::nullopt, the state machine will have no active state and + * run_state() will terminate. + * + * @param p_new_state The new state to transition to, or std::nullopt to + * terminate the state machine. + * + * @note Ownership of the new state is transferred to the state machine + * using move semantics. + * @note The previous state is automatically destroyed when replaced. + */ + void transition_state(std::optional> p_new_state); + + private: + /** + * @brief The currently active state. + * + * Holds exclusive ownership of the current state. Set to std::nullopt + * when the state machine has completed execution. + */ + std::optional> m_current_state; + + /** + * @brief The context shared across all states. + * + * Contains data and configuration that persists across state transitions. + * This context is passed to each state's enter(), handle(), and exit() + * methods. + */ + StateContext m_context; +}; diff --git a/src/concrete_states.cpp b/src/concrete_states.cpp index 70a0708..93cbf63 100644 --- a/src/concrete_states.cpp +++ b/src/concrete_states.cpp @@ -1,6 +1,4 @@ -#include "../include/concrete_states.hpp" -#include "../include/state.hpp" -#include "../include/state_machine.hpp" +#include "concrete_states.hpp" /** * @brief Content for each of function is temporary. Please change @@ -8,101 +6,120 @@ * */ - -void UserInputState::enter(StateContext& context) { - std::print("Previous Number: {}\n", context.get_data()); +void UserInputState::enter(StateContext& p_context) +{ + std::print("Previous Number: {}\n", p_context.get_data()); } -void UserInputState::handle(StateContext& context) { - context.inc_data(); +void UserInputState::handle(StateContext& p_context) +{ + p_context.inc_data(); } -std::optional> UserInputState::exit(StateContext& context) { - std::ignore = context; +std::optional> UserInputState::exit( + StateContext& p_context) +{ + std::ignore = p_context; return std::make_unique(); } - -void ElfParserState::enter(StateContext& context) { - std::print("Previous Number: {}\n", context.get_data()); +void ElfParserState::enter(StateContext& p_context) +{ + std::print("Previous Number: {}\n", p_context.get_data()); } -void ElfParserState::handle(StateContext& context) { - context.inc_data(); +void ElfParserState::handle(StateContext& p_context) +{ + p_context.inc_data(); } -std::optional> ElfParserState::exit(StateContext& context) { - std::ignore = context; +std::optional> ElfParserState::exit( + StateContext& p_context) +{ + std::ignore = p_context; return std::make_unique(); } - -void CallgraphState::enter(StateContext& context) { - std::print("Previous Number: {}\n", context.get_data()); +void CallgraphState::enter(StateContext& p_context) +{ + std::print("Previous Number: {}\n", p_context.get_data()); } -void CallgraphState::handle(StateContext& context) { - std::ignore = context; - context.inc_data(); +void CallgraphState::handle(StateContext& p_context) +{ + std::ignore = p_context; + p_context.inc_data(); } -std::optional> CallgraphState::exit(StateContext& context) { - std::ignore = context; +std::optional> CallgraphState::exit( + StateContext& p_context) +{ + std::ignore = p_context; return std::make_unique(); } - -void AbiParserState::enter(StateContext& context) { - std::print("Previous Number: {}\n", context.get_data()); +void AbiParserState::enter(StateContext& p_context) +{ + std::print("Previous Number: {}\n", p_context.get_data()); } -void AbiParserState::handle(StateContext& context) { - context.inc_data(); +void AbiParserState::handle(StateContext& p_context) +{ + p_context.inc_data(); } -std::optional> AbiParserState::exit(StateContext& context) { - std::ignore = context; +std::optional> AbiParserState::exit( + StateContext& p_context) +{ + std::ignore = p_context; return std::make_unique(); } - -void ValidatorState::enter(StateContext& context) { - std::print("Previous Number: {}\n", context.get_data()); +void ValidatorState::enter(StateContext& p_context) +{ + std::print("Previous Number: {}\n", p_context.get_data()); } -void ValidatorState::handle(StateContext& context) { - context.inc_data(); +void ValidatorState::handle(StateContext& p_context) +{ + p_context.inc_data(); } -std::optional> ValidatorState::exit(StateContext& context) { - std::ignore = context; +std::optional> ValidatorState::exit( + StateContext& p_context) +{ + std::ignore = p_context; return std::make_unique(); } - -void OutputState::enter(StateContext& context) { - std::print("Previous Number: {}\n", context.get_data()); +void OutputState::enter(StateContext& p_context) +{ + std::print("Previous Number: {}\n", p_context.get_data()); } -void OutputState::handle(StateContext& context) { - context.inc_data(); +void OutputState::handle(StateContext& p_context) +{ + p_context.inc_data(); } -std::optional> OutputState::exit(StateContext& context) { - std::ignore = context; +std::optional> OutputState::exit(StateContext& p_context) +{ + std::ignore = p_context; return std::nullopt; } - -void ErrorState::enter(StateContext& context) { - std::ignore = context; +void ErrorState::enter(StateContext& p_context) +{ + std::ignore = p_context; } -void ErrorState::handle(StateContext& context) { - std::ignore = context; +void ErrorState::handle(StateContext& p_context) +{ + std::ignore = p_context; } -std::optional> ErrorState::exit(StateContext& context) { - std::ignore = context; +std::optional> ErrorState::exit(StateContext& p_context) +{ + std::ignore = p_context; return std::nullopt; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 2dd9d5e..6397515 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,9 +8,10 @@ * @copyright Copyright (c) 2025 * */ +#include "concrete_states.hpp" #include "state.hpp" #include "state_context.hpp" -#include "concrete_states.hpp" +#include "state_machine.hpp" #include #include diff --git a/src/state_machine.cpp b/src/state_machine.cpp index d6ced4d..3b9ce37 100644 --- a/src/state_machine.cpp +++ b/src/state_machine.cpp @@ -1,34 +1,35 @@ -#include "../include/state.hpp" -#include "../include/concrete_states.hpp" -#include "../include/state_machine.hpp" +#include "state_machine.hpp" +#include "concrete_states.hpp" -#include - -StateMachine::StateMachine(){ - current_state = std::make_unique(); +StateMachine::StateMachine() +{ + m_current_state = std::make_unique(); } -StateMachine::~StateMachine() = default; - -std::optional> StateMachine::get_current_state(){ - if(current_state){ - return std::ref(**current_state); +std::optional> StateMachine::get_current_state() +{ + if (m_current_state) { + return std::ref(**m_current_state); } return std::nullopt; } -StateContext StateMachine::get_context(){ - return context; +StateContext& StateMachine::get_context() +{ + return m_context; } -void StateMachine::run_state() { - while(current_state != std::nullopt){ - current_state.value()->enter(context); - current_state.value()->handle(context); - transition_state (current_state.value()->exit(context)); +void StateMachine::run_state() +{ + while (m_current_state != std::nullopt) { + m_current_state.value()->enter(m_context); + m_current_state.value()->handle(m_context); + transition_state(m_current_state.value()->exit(m_context)); } } -void StateMachine::transition_state(std::optional> new_state) { - this->current_state = std::move(new_state); +void StateMachine::transition_state( + std::optional> new_state) +{ + this->m_current_state = std::move(new_state); } \ No newline at end of file diff --git a/tests/state_machine.test.cpp b/tests/state_machine.test.cpp index 692b162..d224e79 100644 --- a/tests/state_machine.test.cpp +++ b/tests/state_machine.test.cpp @@ -1,15 +1,17 @@ -#include "state_machine.hpp" -#include "concrete_states.hpp" -#include "state.hpp" -#include "state_context.hpp" -#include #include +#include #include #include -#include #include #include +#include + +#include "concrete_states.hpp" +#include "state.hpp" +#include "state_context.hpp" +#include "state_machine.hpp" + // Mock State for testing class MockState : public State { @@ -49,28 +51,31 @@ void state_machine_tests() expect(actual_state.has_value()) << "A State is initialized"; State& actual_state_ref = actual_state.value().get(); - expect(typeid(actual_state_ref) == typeid(UserInputState)) << "Initial state should be UserInputState"; + expect(typeid(actual_state_ref) == typeid(UserInputState)) + << "Initial state should be UserInputState"; }; "Transition State"_test = [] { StateMachine sm; - std::optional> mock_state = std::make_unique(); + std::optional> mock_state + = std::make_unique(); sm.transition_state(std::move(mock_state)); auto actual_state = sm.get_current_state(); expect(actual_state.has_value()) << "A State is initialized"; State& actual_state_ref = actual_state.value().get(); - expect(typeid(actual_state_ref) == typeid(MockState)) << "State should transition to MockState"; + expect(typeid(actual_state_ref) == typeid(MockState)) + << "State should transition to MockState"; }; "State calling enter, handle, and exit"_test = [] { StateMachine sm; auto mock_state = std::make_unique(); auto* mock_ptr = mock_state.get(); - + sm.transition_state(std::move(mock_state)); - + auto state = sm.get_current_state(); if (state.has_value()) { StateContext context; @@ -78,7 +83,7 @@ void state_machine_tests() state.value().get().handle(context); state.value().get().exit(context); } - + expect(mock_ptr->enter_called) << "Should run enter()"; expect(mock_ptr->handle_called) << "Should run handle()"; expect(mock_ptr->exit_called) << "Should run exit()"; @@ -88,19 +93,16 @@ void state_machine_tests() StateMachine sm; StateContext context = sm.get_context(); std::optional> actual_state; - std::vector state_order = { - typeid(UserInputState), - typeid(ElfParserState), - typeid(CallgraphState), - typeid(AbiParserState), - typeid(ValidatorState), - typeid(OutputState) - }; - - for (auto& expect_state : state_order){ + std::vector state_order + = { typeid(UserInputState), typeid(ElfParserState), + typeid(CallgraphState), typeid(AbiParserState), + typeid(ValidatorState), typeid(OutputState) }; + + for (auto& expect_state : state_order) { actual_state = sm.get_current_state(); State& actual_state_ref = actual_state.value().get(); - expect(typeid(actual_state_ref) == expect_state) << "State should transition to MockState"; + expect(typeid(actual_state_ref) == expect_state) + << "State should transition to MockState"; actual_state_ref.enter(context); actual_state_ref.handle(context); sm.transition_state(actual_state_ref.exit(context)); From 7341f5f72758d4551d8dc21b20aba232e6346b4d Mon Sep 17 00:00:00 2001 From: Mchan2003 Date: Sun, 9 Nov 2025 18:14:27 -0800 Subject: [PATCH 7/7] fixed error message in State Transition Order test --- tests/state_machine.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/state_machine.test.cpp b/tests/state_machine.test.cpp index d224e79..87377d3 100644 --- a/tests/state_machine.test.cpp +++ b/tests/state_machine.test.cpp @@ -102,7 +102,7 @@ void state_machine_tests() actual_state = sm.get_current_state(); State& actual_state_ref = actual_state.value().get(); expect(typeid(actual_state_ref) == expect_state) - << "State should transition to MockState"; + << "State should transition to " << expect_state.name(); actual_state_ref.enter(context); actual_state_ref.handle(context); sm.transition_state(actual_state_ref.exit(context));