diff --git a/include/cubescript/cubescript.hh b/include/cubescript/cubescript.hh index 8cab08d..2051f23 100644 --- a/include/cubescript/cubescript.hh +++ b/include/cubescript/cubescript.hh @@ -352,6 +352,32 @@ struct OSTD_EXPORT cs_state { cs_state(cs_alloc_cb func = cs_default_alloc, void *data = nullptr); virtual ~cs_state(); + cs_state(cs_state const &) = delete; + cs_state(cs_state &&s) { + swap(s); + } + + cs_state &operator=(cs_state const &) = delete; + cs_state &operator=(cs_state &&s) { + swap(s); + s.destroy(); + return *this; + } + + void destroy(); + + void swap(cs_state &s) { + std::swap(p_state, s.p_state); + std::swap(p_callstack, s.p_callstack); + std::swap(identflags, s.identflags); + std::swap(p_pstate, s.p_pstate); + std::swap(p_inloop, s.p_inloop); + std::swap(p_owner, s.p_owner); + std::swap(p_callhook, s.p_callhook); + } + + cs_state new_thread(); + cs_hook_cb set_call_hook(cs_hook_cb func); cs_hook_cb const &get_call_hook() const; cs_hook_cb &get_call_hook(); @@ -463,12 +489,15 @@ struct OSTD_EXPORT cs_state { virtual void print_var(cs_var *v); private: + OSTD_LOCAL cs_state(cs_shared_state *s); + cs_ident *add_ident(cs_ident *id); - void *alloc(void *ptr, size_t olds, size_t news); + OSTD_LOCAL void *alloc(void *ptr, size_t olds, size_t news); cs_gen_state *p_pstate = nullptr; int p_inloop = 0; + bool p_owner = false; char p_errbuf[512]; diff --git a/src/cubescript.cc b/src/cubescript.cc index f155b85..6a15198 100644 --- a/src/cubescript.cc +++ b/src/cubescript.cc @@ -311,6 +311,7 @@ cs_state::cs_state(cs_alloc_cb func, void *data): func(data, nullptr, 0, sizeof(cs_shared_state)) ); new (p_state) cs_shared_state(); + p_owner = true; /* set up allocator, from now we can call into alloc() */ p_state->allocf = func; p_state->aptr = data; @@ -414,8 +415,12 @@ cs_state::cs_state(cs_alloc_cb func, void *data): cs_init_lib_base(*this); } -cs_state::~cs_state() { - if (!p_state) { +OSTD_EXPORT cs_state::~cs_state() { + destroy(); +} + +OSTD_EXPORT void cs_state::destroy() { + if (!p_state || !p_owner) { return; } for (auto &p: p_state->idents) { @@ -430,17 +435,25 @@ cs_state::~cs_state() { p_state->destroy(p_state); } -cs_hook_cb cs_state::set_call_hook(cs_hook_cb func) { +cs_state::cs_state(cs_shared_state *s): + p_state(s), p_owner(false) +{} + +OSTD_EXPORT cs_state cs_state::new_thread() { + return cs_state{p_state}; +} + +OSTD_EXPORT cs_hook_cb cs_state::set_call_hook(cs_hook_cb func) { auto hk = std::move(p_callhook); p_callhook = std::move(func); return hk; } -cs_hook_cb const &cs_state::get_call_hook() const { +OSTD_EXPORT cs_hook_cb const &cs_state::get_call_hook() const { return p_callhook; } -cs_hook_cb &cs_state::get_call_hook() { +OSTD_EXPORT cs_hook_cb &cs_state::get_call_hook() { return p_callhook; } @@ -448,7 +461,7 @@ void *cs_state::alloc(void *ptr, size_t os, size_t ns) { return p_state->alloc(ptr, os, ns); } -void cs_state::clear_override(cs_ident &id) { +OSTD_EXPORT void cs_state::clear_override(cs_ident &id) { if (!(id.get_flags() & CS_IDF_OVERRIDDEN)) { return; } @@ -483,13 +496,13 @@ void cs_state::clear_override(cs_ident &id) { id.p_flags &= ~CS_IDF_OVERRIDDEN; } -void cs_state::clear_overrides() { +OSTD_EXPORT void cs_state::clear_overrides() { for (auto &p: p_state->idents) { clear_override(*(p.second)); } } -cs_ident *cs_state::add_ident(cs_ident *id) { +OSTD_EXPORT cs_ident *cs_state::add_ident(cs_ident *id) { if (!id) { return nullptr; } @@ -499,7 +512,7 @@ cs_ident *cs_state::add_ident(cs_ident *id) { return p_state->identmap.back(); } -cs_ident *cs_state::new_ident(ostd::string_range name, int flags) { +OSTD_EXPORT cs_ident *cs_state::new_ident(ostd::string_range name, int flags) { cs_ident *id = get_ident(name); if (!id) { if (cs_check_num(name)) { @@ -512,7 +525,7 @@ cs_ident *cs_state::new_ident(ostd::string_range name, int flags) { return id; } -cs_ident *cs_state::force_ident(cs_value &v) { +OSTD_EXPORT cs_ident *cs_state::force_ident(cs_value &v) { switch (v.get_type()) { case cs_value_type::Ident: return v.get_ident(); @@ -530,7 +543,7 @@ cs_ident *cs_state::force_ident(cs_value &v) { return p_state->identmap[DummyIdx]; } -cs_ident *cs_state::get_ident(ostd::string_range name) { +OSTD_EXPORT cs_ident *cs_state::get_ident(ostd::string_range name) { auto id = p_state->idents.find(name); if (id != p_state->idents.end()) { return id->second; @@ -538,7 +551,7 @@ cs_ident *cs_state::get_ident(ostd::string_range name) { return nullptr; } -cs_alias *cs_state::get_alias(ostd::string_range name) { +OSTD_EXPORT cs_alias *cs_state::get_alias(ostd::string_range name) { auto id = get_ident(name); if (!id || !id->is_alias()) { return nullptr; @@ -546,23 +559,23 @@ cs_alias *cs_state::get_alias(ostd::string_range name) { return static_cast(id); } -bool cs_state::have_ident(ostd::string_range name) { +OSTD_EXPORT bool cs_state::have_ident(ostd::string_range name) { return p_state->idents.find(name) != p_state->idents.end(); } -cs_ident_r cs_state::get_idents() { +OSTD_EXPORT cs_ident_r cs_state::get_idents() { return cs_ident_r( p_state->identmap.data(), p_state->identmap.data() + p_state->identmap.size() ); } -cs_const_ident_r cs_state::get_idents() const { +OSTD_EXPORT cs_const_ident_r cs_state::get_idents() const { auto ptr = const_cast(p_state->identmap.data()); return cs_const_ident_r(ptr, ptr + p_state->identmap.size()); } -cs_ivar *cs_state::new_ivar( +OSTD_EXPORT cs_ivar *cs_state::new_ivar( ostd::string_range n, cs_int m, cs_int x, cs_int v, cs_var_cb f, int flags ) { return add_ident( @@ -570,7 +583,7 @@ cs_ivar *cs_state::new_ivar( )->get_ivar(); } -cs_fvar *cs_state::new_fvar( +OSTD_EXPORT cs_fvar *cs_state::new_fvar( ostd::string_range n, cs_float m, cs_float x, cs_float v, cs_var_cb f, int flags ) { return add_ident( @@ -578,7 +591,7 @@ cs_fvar *cs_state::new_fvar( )->get_fvar(); } -cs_svar *cs_state::new_svar( +OSTD_EXPORT cs_svar *cs_state::new_svar( ostd::string_range n, cs_string v, cs_var_cb f, int flags ) { return add_ident( @@ -586,7 +599,7 @@ cs_svar *cs_state::new_svar( )->get_svar(); } -void cs_state::reset_var(ostd::string_range name) { +OSTD_EXPORT void cs_state::reset_var(ostd::string_range name) { cs_ident *id = get_ident(name); if (!id) { throw cs_error(*this, "variable %s does not exist", name); @@ -597,14 +610,14 @@ void cs_state::reset_var(ostd::string_range name) { clear_override(*id); } -void cs_state::touch_var(ostd::string_range name) { +OSTD_EXPORT void cs_state::touch_var(ostd::string_range name) { cs_ident *id = get_ident(name); if (id && id->is_var()) { static_cast(id)->changed(*this); } } -void cs_state::set_alias(ostd::string_range name, cs_value v) { +OSTD_EXPORT void cs_state::set_alias(ostd::string_range name, cs_value v) { cs_ident *id = get_ident(name); if (id) { switch (id->get_type()) { @@ -639,7 +652,7 @@ void cs_state::set_alias(ostd::string_range name, cs_value v) { } } -void cs_state::print_var(cs_var *v) { +OSTD_EXPORT void cs_state::print_var(cs_var *v) { ostd::writeln(v->to_printable()); } @@ -723,7 +736,7 @@ static inline void cs_override_var(cs_state &cs, cs_var *v, int &vflags, SF sf) } } -void cs_state::set_var_int( +OSTD_EXPORT void cs_state::set_var_int( ostd::string_range name, cs_int v, bool dofunc, bool doclamp ) { cs_ident *id = get_ident(name); @@ -745,7 +758,7 @@ void cs_state::set_var_int( } } -void cs_state::set_var_float( +OSTD_EXPORT void cs_state::set_var_float( ostd::string_range name, cs_float v, bool dofunc, bool doclamp ) { cs_ident *id = get_ident(name); @@ -767,7 +780,7 @@ void cs_state::set_var_float( } } -void cs_state::set_var_str( +OSTD_EXPORT void cs_state::set_var_str( ostd::string_range name, ostd::string_range v, bool dofunc ) { cs_ident *id = get_ident(name); @@ -785,7 +798,8 @@ void cs_state::set_var_str( } } -std::optional cs_state::get_var_int(ostd::string_range name) { +OSTD_EXPORT std::optional +cs_state::get_var_int(ostd::string_range name) { cs_ident *id = get_ident(name); if (!id || id->is_ivar()) { return std::nullopt; @@ -793,7 +807,8 @@ std::optional cs_state::get_var_int(ostd::string_range name) { return static_cast(id)->get_value(); } -std::optional cs_state::get_var_float(ostd::string_range name) { +OSTD_EXPORT std::optional +cs_state::get_var_float(ostd::string_range name) { cs_ident *id = get_ident(name); if (!id || id->is_fvar()) { return std::nullopt; @@ -801,7 +816,8 @@ std::optional cs_state::get_var_float(ostd::string_range name) { return static_cast(id)->get_value(); } -std::optional cs_state::get_var_str(ostd::string_range name) { +OSTD_EXPORT std::optional +cs_state::get_var_str(ostd::string_range name) { cs_ident *id = get_ident(name); if (!id || id->is_svar()) { return std::nullopt; @@ -809,7 +825,8 @@ std::optional cs_state::get_var_str(ostd::string_range name) { return cs_string(static_cast(id)->get_value()); } -std::optional cs_state::get_var_min_int(ostd::string_range name) { +OSTD_EXPORT std::optional +cs_state::get_var_min_int(ostd::string_range name) { cs_ident *id = get_ident(name); if (!id || id->is_ivar()) { return std::nullopt; @@ -817,7 +834,8 @@ std::optional cs_state::get_var_min_int(ostd::string_range name) { return static_cast(id)->get_val_min(); } -std::optional cs_state::get_var_max_int(ostd::string_range name) { +OSTD_EXPORT std::optional +cs_state::get_var_max_int(ostd::string_range name) { cs_ident *id = get_ident(name); if (!id || id->is_ivar()) { return std::nullopt; @@ -825,7 +843,8 @@ std::optional cs_state::get_var_max_int(ostd::string_range name) { return static_cast(id)->get_val_max(); } -std::optional cs_state::get_var_min_float(ostd::string_range name) { +OSTD_EXPORT std::optional +cs_state::get_var_min_float(ostd::string_range name) { cs_ident *id = get_ident(name); if (!id || id->is_fvar()) { return std::nullopt; @@ -833,7 +852,8 @@ std::optional cs_state::get_var_min_float(ostd::string_range name) { return static_cast(id)->get_val_min(); } -std::optional cs_state::get_var_max_float(ostd::string_range name) { +OSTD_EXPORT std::optional +cs_state::get_var_max_float(ostd::string_range name) { cs_ident *id = get_ident(name); if (!id || id->is_fvar()) { return std::nullopt; @@ -841,7 +861,7 @@ std::optional cs_state::get_var_max_float(ostd::string_range name) { return static_cast(id)->get_val_max(); } -std::optional +OSTD_EXPORT std::optional cs_state::get_alias_val(ostd::string_range name) { cs_alias *a = get_alias(name); if (!a) { @@ -874,7 +894,7 @@ cs_int cs_clamp_var(cs_state &cs, cs_ivar *iv, cs_int v) { ); } -void cs_state::set_var_int_checked(cs_ivar *iv, cs_int v) { +OSTD_EXPORT void cs_state::set_var_int_checked(cs_ivar *iv, cs_int v) { if (iv->get_flags() & CS_IDF_READONLY) { throw cs_error( *this, "variable '%s' is read only", iv->get_name() @@ -891,7 +911,7 @@ void cs_state::set_var_int_checked(cs_ivar *iv, cs_int v) { iv->changed(*this); } -void cs_state::set_var_int_checked(cs_ivar *iv, cs_value_r args) { +OSTD_EXPORT void cs_state::set_var_int_checked(cs_ivar *iv, cs_value_r args) { cs_int v = args[0].force_int(); if ((iv->get_flags() & CS_IDF_HEX) && (args.size() > 1)) { v = (v << 16) | (args[1].force_int() << 8); @@ -917,7 +937,7 @@ cs_float cs_clamp_fvar(cs_state &cs, cs_fvar *fv, cs_float v) { return v; } -void cs_state::set_var_float_checked(cs_fvar *fv, cs_float v) { +OSTD_EXPORT void cs_state::set_var_float_checked(cs_fvar *fv, cs_float v) { if (fv->get_flags() & CS_IDF_READONLY) { throw cs_error( *this, "variable '%s' is read only", fv->get_name() @@ -934,7 +954,9 @@ void cs_state::set_var_float_checked(cs_fvar *fv, cs_float v) { fv->changed(*this); } -void cs_state::set_var_str_checked(cs_svar *sv, ostd::string_range v) { +OSTD_EXPORT void cs_state::set_var_str_checked( + cs_svar *sv, ostd::string_range v +) { if (sv->get_flags() & CS_IDF_READONLY) { throw cs_error( *this, "variable '%s' is read only", sv->get_name() @@ -948,7 +970,7 @@ void cs_state::set_var_str_checked(cs_svar *sv, ostd::string_range v) { sv->changed(*this); } -cs_command *cs_state::new_command( +OSTD_EXPORT cs_command *cs_state::new_command( ostd::string_range name, ostd::string_range args, cs_command_cb func ) { int nargs = 0;