Generator method nesting worksgit add .

lib
Avril 3 years ago
parent bc2857fc86
commit 2bab6235db
Signed by: flanchan
GPG Key ID: 284488987C31F630

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

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

@ -1,6 +1,7 @@
#pragma once
#include "frame.h"
#include <cassert>
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<typename T, typename U>
inline T* _sm_var(sm_state* state, U name, T init)
{
assert(state->current != nullptr);
return _sm_var<T,U>(&state->current->user, name, init);
}
template<uint64_t name, typename T>
@ -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);

@ -0,0 +1,57 @@
#include <gen.h>
struct sm_generator
{
sm_generator* prev;
sm_gen_fun current;
};
sm_generator* sm_generate(sm_gen_fun function)
{
auto gen = box<sm_generator>();
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;
}

@ -1,10 +1,26 @@
#include <state.h>
#include <gen.h>
#include <cstdio>
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

@ -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<sm_state>();
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;
}

Loading…
Cancel
Save