#pragma once #include "box.h" #include #define _SM_STACK_SIZE 15 #define _SM_KEY_SIZE (UINT64_MAX >> 2) struct _sm_user { uint64_t set : 1; // bool uint64_t free : 1; // bool uint64_t key : 62; // Use the rest of the 7 byte hole here for the key. union { uint8_t _8; uint16_t _16; uint32_t _32; uint64_t _64; float _f32; double _f64; void* _ptr; }; }; struct _sm_user_page { _sm_user data[_SM_STACK_SIZE]; _sm_user_page* next; }; struct _sm_frame { uint64_t pc; _sm_user* rval; // Pointer to the return value of this function _sm_user_page user; _sm_frame* prev; }; /// Options for `state`. struct _sm_state_opt { /// Set the return value within a generator at every yield point, instead of just at the end of the function. /// (default: true) bool _opt_INTERMEDIATE_RETURNS; }; extern const _sm_state_opt _sm_state_opt_default; struct sm_state { _sm_state_opt opt; _sm_frame* current; }; #define sm_state_setopt(state, name, value) ((state)->opt._opt_ ## name = (value)) #define sm_state_getopt(state, name) ((state)->opt._opt_ ## name) template inline T* _sm_init(_sm_user* frame, T init) { frame->free = true; T* ptr = box(); *ptr = init; return (T*) (frame->_ptr = (void*)ptr); } template inline T** _sm_init(_sm_user* frame, T* init) { frame->free = false; frame->_ptr = (void*)init; return (T**) &frame->_ptr; } template inline T* _sm_get(_sm_user* frame) { return (T*) frame->_ptr; } inline void _sm_free(_sm_user* frame) { if (frame->free) free(frame->_ptr); frame->free = frame->set = false; } #define _SM_DEF(T) template<> T* _sm_init(_sm_user* frame, T init); \ template<> T* _sm_get(_sm_user* frame) _SM_DEF(char); _SM_DEF(unsigned char); _SM_DEF(short); _SM_DEF(unsigned short); _SM_DEF(int); _SM_DEF(unsigned int); _SM_DEF(long); _SM_DEF(unsigned long); _SM_DEF(float); _SM_DEF(double); #undef _SM_DEF