From 2bab6235dba53a656bced53ba128b91ba2c7b34c Mon Sep 17 00:00:00 2001 From: Avril Date: Thu, 18 Mar 2021 18:31:18 +0000 Subject: [PATCH] Generator method nesting worksgit add . --- include/frame.h | 8 +++---- include/gen.h | 16 ++++++++++++++ include/state.h | 10 ++++++--- src/gen.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 29 ++++++++++++++++++++----- src/state.cpp | 11 ++++++++-- 6 files changed, 117 insertions(+), 14 deletions(-) create mode 100644 include/gen.h create mode 100644 src/gen.cpp diff --git a/include/frame.h b/include/frame.h index f7124a4..387c027 100644 --- a/include/frame.h +++ b/include/frame.h @@ -8,10 +8,10 @@ #define _SM_KEY_SIZE (UINT64_MAX >> 2) struct _sm_user { - uint64_t set : 1; - uint64_t free : 1; + uint64_t set : 1; // bool + uint64_t free : 1; // bool - uint64_t key : 62; + uint64_t key : 62; // Use the rest of the 7 byte hole here for the key. union { uint8_t _8; @@ -33,9 +33,9 @@ struct _sm_user_page { }; struct _sm_frame { + uint64_t pc; _sm_user_page user; - uint64_t pc; _sm_frame* prev; }; diff --git a/include/gen.h b/include/gen.h new file mode 100644 index 0000000..febba5e --- /dev/null +++ b/include/gen.h @@ -0,0 +1,16 @@ +#pragma once + +#include "state.h" + +typedef sm_yield (*sm_gen_fun)(sm_state* state); //NOTE: Same as sm_yield + +// A generator method +struct sm_generator; + +/// Create a generator method with this function. +sm_generator* sm_generate(sm_gen_fun function); +/// Free a generator method +void sm_free_generator(sm_generator* generator); +/// Run this generator until the next yield. +/// Returns false if the generator ends. +bool sm_next(sm_generator** gen, sm_state* state); diff --git a/include/state.h b/include/state.h index c398c1a..bd18b71 100644 --- a/include/state.h +++ b/include/state.h @@ -1,6 +1,7 @@ #pragma once #include "frame.h" +#include typedef void* (*sm_yield)(sm_state* state); //NOTE: This `void*` is a stand-in for this function returning itself. @@ -43,6 +44,8 @@ inline T* _sm_var(_sm_user_page* user, U name, T init) template inline T* _sm_var(sm_state* state, U name, T init) { + assert(state->current != nullptr); + return _sm_var(&state->current->user, name, init); } template @@ -54,6 +57,7 @@ inline T* _sm_var(sm_state* state, T init) // Pop the current stack frame, and re-set the pointer to the previous one. void _sm_pop_stack(sm_state* state); +void _sm_push_stack(sm_state* state); sm_yield _sm_noop(sm_state*); @@ -69,9 +73,9 @@ inline sm_yield sm_continue() { return (sm_yield)_sm_noop; } /// --- #define SM_BEGIN switch(state->current->pc) { case 0: -#define SM_END } _sm_pop_stack(state); return sm_end() +#define SM_END } return sm_end() #define SM_YIELD(v) do { state->current->pc = __LINE__; return (sm_yield)(v); case __LINE__:; } while(0) -sm_state* sm_new(); -void sm_free(sm_state* state); +sm_state* sm_new_state(); +void sm_free_state(sm_state* state); diff --git a/src/gen.cpp b/src/gen.cpp new file mode 100644 index 0000000..f06c4cd --- /dev/null +++ b/src/gen.cpp @@ -0,0 +1,57 @@ +#include + +struct sm_generator +{ + sm_generator* prev; + sm_gen_fun current; +}; + +sm_generator* sm_generate(sm_gen_fun function) +{ + auto gen = box(); + gen->prev = nullptr; + gen->current = function; + return gen; +} + +void sm_free_generator(sm_generator* gen) +{ + auto g = unbox(gen); + if(g.prev) + sm_free_generator(g.prev); +} + +// Returns false if the generator ends. +bool sm_next(sm_generator** gen, sm_state* state) +{ + if( !(*gen)->current) return false; + + sm_yield next = (*gen)->current(state); + switch((uintptr_t)next) + { + case 0: + // Pop the current + (*gen)->current = nullptr; + + if ((*gen)->prev) { + + // Pop back to previous stack + _sm_pop_stack(state); + + *gen = unbox(*gen).prev; + return true; + } else return false; + default: + if (next == (sm_yield)_sm_noop) return true; + + auto prev = *gen; + *gen = sm_generate((sm_gen_fun) next); + (*gen)->prev = prev; + + // Set up new stack frame + _sm_push_stack(state); + + break; + } + return true; +} diff --git a/src/main.cpp b/src/main.cpp index 8510ffa..7a243a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,26 @@ #include +#include + #include struct _test { int a, b; }; +sm_yield sm_test_2(sm_state* state) +{ + int* a = SM_VAR(-10); + + SM_BEGIN; + while( (*a) < 0 ) { + printf("(2) a = %d\n", *a); + SM_YIELD(sm_continue()); + (*a)+=1; + } + printf("Done!\n"); + SM_END; +} + sm_yield sm_test(sm_state* state) { int* a = SM_VAR(10); @@ -22,19 +38,22 @@ sm_yield sm_test(sm_state* state) *a = 0; SM_YIELD(sm_continue()); printf("a = %d\n", *a); + printf("Starting function 2\n"); + SM_YIELD(sm_test_2); + printf("2 done\n"); SM_END; } int main() { - auto state = sm_new(); + auto state = sm_new_state(); + auto gen = sm_generate(&sm_test); - sm_test(state); - sm_test(state); - sm_test(state); + while(sm_next(&gen, state)) (void)0; - sm_free(state); + sm_free_generator(gen); + sm_free_state(state); /* //TODO: `sm_state` creation/initialisation & freeing functions diff --git a/src/state.cpp b/src/state.cpp index c316c59..ce84d56 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -9,7 +9,7 @@ sm_yield _sm_noop(sm_state*) return (sm_yield)nullptr; } -sm_state* sm_new() +sm_state* sm_new_state() { auto state = box(); state->current = box<_sm_frame, true>(); @@ -39,7 +39,7 @@ inline static void _sm_free_all_pages(_sm_user_page* page) } } -void sm_free(sm_state* state) +void sm_free_state(sm_state* state) { _sm_frame* frame = unbox(state).current; @@ -62,3 +62,10 @@ void _sm_pop_stack(sm_state* state) _sm_free_all_pages(last.user.next); _sm_free_page(&last.user); } + +void _sm_push_stack(sm_state* state) +{ + auto next = box<_sm_frame, true>(); + next->prev = state->current; + state->current = next; +}