From 4588ae23737c4f7e8f5e5ed1264bfbf0762f76f8 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Tue, 23 Mar 2021 01:11:21 +0100 Subject: [PATCH] separate cs_state, cs_std --- src/cs_state.cc | 31 ++++++++ src/cs_state.hh | 116 +++++++++++++++++++++++++++ src/cs_std.hh | 122 +++++++++++++++++++++++++++++ src/cs_util.cc | 10 +-- src/cs_util.hh | 194 +--------------------------------------------- src/cs_val.cc | 14 ++-- src/cs_vm.cc | 6 +- src/cs_vm.hh | 24 +----- src/cubescript.cc | 20 ++--- src/lib_list.cc | 1 + src/lib_str.cc | 5 +- src/meson.build | 1 + 12 files changed, 303 insertions(+), 241 deletions(-) create mode 100644 src/cs_state.cc create mode 100644 src/cs_state.hh create mode 100644 src/cs_std.hh diff --git a/src/cs_state.cc b/src/cs_state.cc new file mode 100644 index 0000000..8a3e061 --- /dev/null +++ b/src/cs_state.cc @@ -0,0 +1,31 @@ +#include + +#include "cs_util.hh" +#include "cs_bcode.hh" +#include "cs_state.hh" + +namespace cscript { + +cs_shared_state::cs_shared_state(cs_alloc_cb af, void *data): + allocf{af}, aptr{data}, + idents{allocator_type{this}}, + identmap{allocator_type{this}}, + varprintf{}, + strman{create(this)}, + empty{bcode_init_empty(this)} +{} + +cs_shared_state::~cs_shared_state() { + bcode_free_empty(this, empty); + destroy(strman); +} + +void *cs_shared_state::alloc(void *ptr, size_t os, size_t ns) { + void *p = allocf(aptr, ptr, os, ns); + if (!p && ns) { + throw std::bad_alloc{}; + } + return p; +} + +} /* namespace cscript */ diff --git a/src/cs_state.hh b/src/cs_state.hh new file mode 100644 index 0000000..0b168a3 --- /dev/null +++ b/src/cs_state.hh @@ -0,0 +1,116 @@ +#ifndef LIBCUBESCRIPT_STATE_HH +#define LIBCUBESCRIPT_STATE_HH + +#include + +#include +#include + +#include "cs_bcode.hh" + +namespace cscript { + +struct cs_state; +struct cs_shared_state; +struct cs_strman; + +template +struct cs_allocator { + using value_type = T; + + inline cs_allocator(cs_shared_state *s); + inline cs_allocator(cs_state &cs); + + template + cs_allocator(cs_allocator const &a): state{a.state} {}; + + inline T *allocate(std::size_t n); + inline void deallocate(T *p, std::size_t n); + + template + bool operator==(cs_allocator const &a) { + return state == a.state; + } + + cs_shared_state *state; +}; + +struct cs_shared_state { + using allocator_type = cs_allocator< + std::pair + >; + cs_alloc_cb allocf; + void *aptr; + + std::unordered_map< + std::string_view, cs_ident *, + std::hash, + std::equal_to, + allocator_type + > idents; + std::vector> identmap; + + cs_vprint_cb varprintf; + cs_strman *strman; + empty_block *empty; + + cs_shared_state() = delete; + + cs_shared_state(cs_alloc_cb af, void *data); + + ~cs_shared_state(); + + void *alloc(void *ptr, size_t os, size_t ns); + + template + T *create(A &&...args) { + T *ret = static_cast(alloc(nullptr, 0, sizeof(T))); + new (ret) T(std::forward(args)...); + return ret; + } + + template + T *create_array(size_t len) { + T *ret = static_cast(alloc(nullptr, 0, len * sizeof(T))); + for (size_t i = 0; i < len; ++i) { + new (&ret[i]) T(); + } + return ret; + } + + template + void destroy(T *v) noexcept { + v->~T(); + alloc(v, sizeof(T), 0); + } + + template + void destroy_array(T *v, size_t len) noexcept { + v->~T(); + alloc(v, len * sizeof(T), 0); + } +}; + +inline cs_shared_state *cs_get_sstate(cs_state &cs) { + return cs.p_state; +} + +template +inline cs_allocator::cs_allocator(cs_shared_state *s): state{s} {} + +template +inline cs_allocator::cs_allocator(cs_state &s): state{cs_get_sstate(s)} {} + +template +inline T *cs_allocator::allocate(std::size_t n) { + return static_cast(state->alloc(nullptr, 0, n * sizeof(T))); +} + +template +inline void cs_allocator::deallocate(T *p, std::size_t n) { + state->alloc(p, n, 0); +} + +} /* namespace cscript */ + +#endif diff --git a/src/cs_std.hh b/src/cs_std.hh new file mode 100644 index 0000000..63a78f5 --- /dev/null +++ b/src/cs_std.hh @@ -0,0 +1,122 @@ +#ifndef LIBCUBESCRIPT_STD_HH +#define LIBCUBESCRIPT_STD_HH + +#include +#include +#include + +#include "cs_state.hh" + +namespace cscript { + +/* run func, call the second one after finishing */ + +template +struct CsScopeExit { + template + CsScopeExit(FF &&f): func(std::forward(f)) {} + ~CsScopeExit() { + func(); + } + std::decay_t func; +}; + +template +inline void call_with_cleanup(F1 &&dof, F2 &&clf) { + CsScopeExit cleanup(std::forward(clf)); + dof(); +} + +/* a simple static array with elements constructed using ctor args */ + +template +struct cs_valarray { + template + cs_valarray(A &&...args) { + for (std::size_t i = 0; i < N; ++i) { + new (&stor[i]) T{std::forward(args)...}; + } + } + + ~cs_valarray() { + for (std::size_t i = 0; i < N; ++i) { + reinterpret_cast(&stor[i])->~T(); + } + } + + T &operator[](std::size_t i) { + return *reinterpret_cast(&stor[i]); + } + + std::aligned_storage_t stor[N]; +}; + +/* a value buffer */ + +template +struct cs_valbuf { + cs_valbuf() = delete; + + cs_valbuf(cs_shared_state *cs): buf{cs_allocator{cs}} {} + cs_valbuf(cs_state &cs): buf{cs_allocator{cs}} {} + + using size_type = std::size_t; + using value_type = T; + using reference = T &; + using const_reference = T const &; + + void reserve(std::size_t s) { buf.reserve(s); } + void resize(std::size_t s) { buf.resize(s); } + + void append(T const *beg, T const *end) { + buf.insert(buf.end(), beg, end); + } + + void push_back(T const &v) { buf.push_back(v); } + void pop_back() { buf.pop_back(); } + + T &back() { return buf.back(); } + T const &back() const { return buf.back(); } + + std::size_t size() const { return buf.size(); } + std::size_t capacity() const { return buf.capacity(); } + + bool empty() const { return buf.empty(); } + + void clear() { buf.clear(); } + + T &operator[](std::size_t i) { return buf[i]; } + T const &operator[](std::size_t i) const { return buf[i]; } + + T *data() { return &buf[0]; } + T const *data() const { return &buf[0]; } + + std::vector> buf; +}; + +/* specialization of value buffer for bytes */ + +struct cs_charbuf: cs_valbuf { + cs_charbuf(cs_shared_state *cs): cs_valbuf{cs} {} + cs_charbuf(cs_state &cs): cs_valbuf{cs} {} + + void append(char const *beg, char const *end) { + cs_valbuf::append(beg, end); + } + + void append(std::string_view v) { + append(&v[0], &v[v.size()]); + } + + std::string_view str() { + return std::string_view{buf.data(), buf.size()}; + } + + std::string_view str_term() { + return std::string_view{buf.data(), buf.size() - 1}; + } +}; + +} /* namespace cscript */ + +#endif diff --git a/src/cs_util.cc b/src/cs_util.cc index eb56207..3d4b2e5 100644 --- a/src/cs_util.cc +++ b/src/cs_util.cc @@ -286,10 +286,10 @@ char *cs_strman::alloc_buf(std::size_t len) const { /* strref */ -cs_strref::cs_strref(cs_shared_state &cs, std::string_view str): - p_state{&cs} +cs_strref::cs_strref(cs_shared_state *cs, std::string_view str): + p_state{cs} { - p_str = cs.strman->add(str); + p_str = cs->strman->add(str); } cs_strref::cs_strref(cs_state &cs, std::string_view str): @@ -304,8 +304,8 @@ cs_strref::cs_strref(cs_strref const &ref): p_state{ref.p_state}, p_str{ref.p_st } /* this can be used by friends to do quick cs_strref creation */ -cs_strref::cs_strref(char const *p, cs_shared_state &cs): - p_state{&cs} +cs_strref::cs_strref(char const *p, cs_shared_state *cs): + p_state{cs} { p_str = p_state->strman->ref(p); } diff --git a/src/cs_util.hh b/src/cs_util.hh index c82e298..f2b86fb 100644 --- a/src/cs_util.hh +++ b/src/cs_util.hh @@ -6,6 +6,7 @@ #include #include "cs_bcode.hh" +#include "cs_state.hh" namespace cscript { @@ -17,201 +18,10 @@ cs_float cs_parse_float( std::string_view input, std::string_view *end = nullptr ); -template -struct CsScopeExit { - template - CsScopeExit(FF &&f): func(std::forward(f)) {} - ~CsScopeExit() { - func(); - } - std::decay_t func; -}; - -template -inline void cs_do_and_cleanup(F1 &&dof, F2 &&clf) { - CsScopeExit cleanup(std::forward(clf)); - dof(); -} - struct cs_strman; struct cs_shared_state; -template -struct cs_allocator { - using value_type = T; - - cs_allocator(cs_shared_state *s): state{s} {} - cs_allocator(cs_state &cs): state{cs_get_sstate(cs)} {} - - template - cs_allocator(cs_allocator const &a): state{a.state} {}; - - inline T *allocate(std::size_t n); - - inline void deallocate(T *p, std::size_t n); - - template - bool operator==(cs_allocator const &a) { - return state == a.state; - } - - cs_shared_state *state; -}; - -template -struct cs_valbuf { - cs_valbuf() = delete; - - cs_valbuf(cs_shared_state &cs): - buf{cs_allocator{&cs}} - {} - - cs_valbuf(cs_state &cs): - buf{cs_allocator{cs_get_sstate(cs)}} - {} - - using size_type = std::size_t; - using value_type = T; - using reference = T &; - using const_reference = T const &; - - void reserve(std::size_t s) { buf.reserve(s); } - void resize(std::size_t s) { buf.resize(s); } - - void append(T const *beg, T const *end) { - buf.insert(buf.end(), beg, end); - } - - void push_back(T const &v) { buf.push_back(v); } - void pop_back() { buf.pop_back(); } - - T &back() { return buf.back(); } - T const &back() const { return buf.back(); } - - std::size_t size() const { return buf.size(); } - std::size_t capacity() const { return buf.capacity(); } - - bool empty() const { return buf.empty(); } - - void clear() { buf.clear(); } - - T &operator[](std::size_t i) { return buf[i]; } - T const &operator[](std::size_t i) const { return buf[i]; } - - T *data() { return &buf[0]; } - T const *data() const { return &buf[0]; } - - std::vector> buf; -}; - -struct cs_charbuf: cs_valbuf { - cs_charbuf(cs_shared_state &cs): cs_valbuf(cs) {} - cs_charbuf(cs_state &cs): cs_valbuf(cs) {} - - void append(char const *beg, char const *end) { - cs_valbuf::append(beg, end); - } - - void append(std::string_view v) { - append(&v[0], &v[v.size()]); - } - - std::string_view str() { - return std::string_view{buf.data(), buf.size()}; - } - - std::string_view str_term() { - return std::string_view{buf.data(), buf.size() - 1}; - } -}; - -struct cs_shared_state { - using allocator_type = cs_allocator< - std::pair - >; - cs_alloc_cb allocf; - void *aptr; - - std::unordered_map< - std::string_view, cs_ident *, - std::hash, - std::equal_to, - allocator_type - > idents; - std::vector> identmap; - - cs_vprint_cb varprintf; - cs_strman *strman; - empty_block *empty; - - cs_shared_state() = delete; - - cs_shared_state(cs_alloc_cb af, void *data): - allocf{af}, aptr{data}, - idents{allocator_type{this}}, - identmap{allocator_type{this}}, - varprintf{}, - strman{create(this)}, - empty{bcode_init_empty(this)} - {} - - ~cs_shared_state() { - bcode_free_empty(this, empty); - destroy(strman); - } - - void *alloc(void *ptr, size_t os, size_t ns) { - void *p = allocf(aptr, ptr, os, ns); - if (!p && ns) { - throw std::bad_alloc{}; - } - return p; - } - - template - T *create(A &&...args) { - T *ret = static_cast(alloc(nullptr, 0, sizeof(T))); - new (ret) T(std::forward(args)...); - return ret; - } - - template - T *create_array(size_t len) { - T *ret = static_cast(alloc(nullptr, 0, len * sizeof(T))); - for (size_t i = 0; i < len; ++i) { - new (&ret[i]) T(); - } - return ret; - } - - template - void destroy(T *v) noexcept { - v->~T(); - alloc(v, sizeof(T), 0); - } - - template - void destroy_array(T *v, size_t len) noexcept { - v->~T(); - alloc(v, len * sizeof(T), 0); - } -}; - -template -inline T *cs_allocator::allocate(std::size_t n) { - return static_cast(state->alloc(nullptr, 0, n * sizeof(T))); -} - -template -inline void cs_allocator::deallocate(T *p, std::size_t n) { - state->alloc(p, n, 0); -} - -inline cs_shared_state *cs_get_sstate(cs_state &cs) { - return cs.p_state; -} - -inline cs_strref cs_make_strref(char const *p, cs_shared_state &cs) { +inline cs_strref cs_make_strref(char const *p, cs_shared_state *cs) { return cs_strref{p, cs}; } diff --git a/src/cs_val.cc b/src/cs_val.cc index 0acd302..7b85e2a 100644 --- a/src/cs_val.cc +++ b/src/cs_val.cc @@ -148,7 +148,7 @@ void cs_value::set_float(cs_float val) { void cs_value::set_str(std::string_view val) { csv_cleanup(p_type, p_stor); - new (&p_stor) cs_strref{*state(), val}; + new (&p_stor) cs_strref{state(), val}; p_type = cs_value_type::STRING; } @@ -224,7 +224,7 @@ cs_int cs_value::force_int() { } std::string_view cs_value::force_str() { - cs_charbuf rs{*state()}; + cs_charbuf rs{state()}; std::string_view str; switch (get_type()) { case cs_value_type::FLOAT: @@ -294,17 +294,17 @@ cs_strref cs_value::get_str() const { case cs_value_type::STRING: return *reinterpret_cast(&p_stor); case cs_value_type::INT: { - cs_charbuf rs{*state()}; - return cs_strref{*state(), intstr(csv_get(p_stor), rs)}; + cs_charbuf rs{state()}; + return cs_strref{state(), intstr(csv_get(p_stor), rs)}; } case cs_value_type::FLOAT: { - cs_charbuf rs{*state()}; - return cs_strref{*state(), floatstr(csv_get(p_stor), rs)}; + cs_charbuf rs{state()}; + return cs_strref{state(), floatstr(csv_get(p_stor), rs)}; } default: break; } - return cs_strref{*state(), ""}; + return cs_strref{state(), ""}; } void cs_value::get_val(cs_value &r) const { diff --git a/src/cs_vm.cc b/src/cs_vm.cc index 7b4a864..6852c55 100644 --- a/src/cs_vm.cc +++ b/src/cs_vm.cc @@ -284,7 +284,7 @@ static inline void cs_call_alias( cs.p_callstack = &aliaslink; uint32_t *codep = static_cast(a)->compile_code(cs)->get_raw(); bcode_incr(codep); - cs_do_and_cleanup([&]() { + call_with_cleanup([&]() { runcode(cs, codep+1, result); }, [&]() { bcode_decr(codep); @@ -479,7 +479,7 @@ static uint32_t *runcode(cs_state &cs, uint32_t *code, cs_value &result) { for (int i = 0; i < numlocals; ++i) { cs_push_alias(cs, args[offset + i].get_ident(), locals[i]); } - cs_do_and_cleanup([&]() { + call_with_cleanup([&]() { code = runcode(cs, code, result); }, [&]() { for (int i = offset; i < numargs; i++) { @@ -1296,7 +1296,7 @@ noid: args[offset + j] ), locals[j]); } - cs_do_and_cleanup([&]() { + call_with_cleanup([&]() { code = runcode(cs, code, result); }, [&]() { for (size_t j = 0; j < size_t(callargs); ++j) { diff --git a/src/cs_vm.hh b/src/cs_vm.hh index e81a11e..f8cf6b3 100644 --- a/src/cs_vm.hh +++ b/src/cs_vm.hh @@ -8,6 +8,7 @@ #include #include +#include "cs_std.hh" #include "cs_util.hh" #include "cs_bcode.hh" #include "cs_ident.hh" @@ -21,27 +22,6 @@ static constexpr int DummyIdx = MaxArguments; static constexpr int NumargsIdx = MaxArguments + 1; static constexpr int DbgaliasIdx = MaxArguments + 2; -template -struct cs_valarray { - cs_valarray(cs_state &cs) { - for (std::size_t i = 0; i < N; ++i) { - new (&stor[i]) T{cs}; - } - } - - ~cs_valarray() { - for (std::size_t i = 0; i < N; ++i) { - reinterpret_cast(&stor[i])->~T(); - } - } - - T &operator[](std::size_t i) { - return *reinterpret_cast(&stor[i]); - } - - std::aligned_storage_t stor[N]; -}; - static const int cs_valtypet[] = { CS_VAL_NULL, CS_VAL_INT, CS_VAL_FLOAT, CS_VAL_STRING, CS_VAL_CODE, CS_VAL_IDENT @@ -235,7 +215,7 @@ static void cs_do_args(cs_state &cs, F body) { prevstack ? prevstack->argstack : nullptr }; cs.p_callstack = &aliaslink; - cs_do_and_cleanup(std::move(body), [&]() { + call_with_cleanup(std::move(body), [&]() { if (prevstack) { prevstack->usedargs = aliaslink.usedargs; } diff --git a/src/cubescript.cc b/src/cubescript.cc index 814c8e5..3487168 100644 --- a/src/cubescript.cc +++ b/src/cubescript.cc @@ -506,7 +506,7 @@ LIBCUBESCRIPT_EXPORT cs_ident *cs_state::new_ident(std::string_view name, int fl ); } auto *inst = p_state->create( - *this, cs_strref{*p_state, name}, flags + *this, cs_strref{p_state, name}, flags ); id = add_ident(inst, inst); } @@ -565,7 +565,7 @@ LIBCUBESCRIPT_EXPORT cs_ivar *cs_state::new_ivar( std::string_view n, cs_int m, cs_int x, cs_int v, cs_var_cb f, int flags ) { auto *iv = p_state->create( - cs_strref{*p_state, n}, m, x, v, std::move(f), flags + cs_strref{p_state, n}, m, x, v, std::move(f), flags ); add_ident(iv, iv); return iv; @@ -575,7 +575,7 @@ LIBCUBESCRIPT_EXPORT cs_fvar *cs_state::new_fvar( std::string_view n, cs_float m, cs_float x, cs_float v, cs_var_cb f, int flags ) { auto *fv = p_state->create( - cs_strref{*p_state, n}, m, x, v, std::move(f), flags + cs_strref{p_state, n}, m, x, v, std::move(f), flags ); add_ident(fv, fv); return fv; @@ -585,8 +585,8 @@ LIBCUBESCRIPT_EXPORT cs_svar *cs_state::new_svar( std::string_view n, std::string_view v, cs_var_cb f, int flags ) { auto *sv = p_state->create( - cs_strref{*p_state, n}, cs_strref{*p_state, v}, - cs_strref{*p_state, ""}, std::move(f), flags + cs_strref{p_state, n}, cs_strref{p_state, v}, + cs_strref{p_state, ""}, std::move(f), flags ); add_ident(sv, sv); return sv; @@ -642,7 +642,7 @@ LIBCUBESCRIPT_EXPORT void cs_state::set_alias(std::string_view name, cs_value v) throw cs_error(*this, "cannot alias number %s", name.data()); } else { auto *a = p_state->create( - *this, cs_strref{*p_state, name}, std::move(v), identflags + *this, cs_strref{p_state, name}, std::move(v), identflags ); add_ident(a, a); } @@ -775,7 +775,7 @@ LIBCUBESCRIPT_EXPORT void cs_state::set_var_str( *this, sv, sv->p_flags, [&sv]() { sv->p_overrideval = sv->get_value(); } ); - sv->set_value(cs_strref{*p_state, v}); + sv->set_value(cs_strref{p_state, v}); if (dofunc) { sv->changed(*this); } @@ -805,7 +805,7 @@ cs_state::get_var_str(std::string_view name) { if (!id || id->is_svar()) { return std::nullopt; } - return cs_strref{*p_state, static_cast(id)->get_value()}; + return cs_strref{p_state, static_cast(id)->get_value()}; } LIBCUBESCRIPT_EXPORT std::optional @@ -957,7 +957,7 @@ LIBCUBESCRIPT_EXPORT void cs_state::set_var_str_checked( *this, sv, svp->p_flags, [&svp]() { svp->p_overrideval = svp->p_storage; } ); - sv->set_value(cs_strref{*p_state, v}); + sv->set_value(cs_strref{p_state, v}); svp->changed(*this); } @@ -1011,7 +1011,7 @@ LIBCUBESCRIPT_EXPORT cs_command *cs_state::new_command( } } auto *cmd = p_state->create( - cs_strref{*p_state, name}, cs_strref{*p_state, args}, nargs, + cs_strref{p_state, name}, cs_strref{p_state, args}, nargs, std::move(func) ); add_ident(cmd, cmd); diff --git a/src/lib_list.cc b/src/lib_list.cc index 8631068..2af6314 100644 --- a/src/lib_list.cc +++ b/src/lib_list.cc @@ -3,6 +3,7 @@ #include #include "cs_util.hh" +#include "cs_std.hh" namespace cscript { diff --git a/src/lib_str.cc b/src/lib_str.cc index 1f6aadb..a1b6a96 100644 --- a/src/lib_str.cc +++ b/src/lib_str.cc @@ -4,6 +4,7 @@ #include #include "cs_util.hh" +#include "cs_std.hh" namespace cscript { @@ -64,7 +65,7 @@ void cs_init_lib_string(cs_state &cs) { buf[i] = tolower(inps[i]); } auto const *cbuf = ics->strman->steal(buf); - auto sr = cs_make_strref(cbuf, *ics); + auto sr = cs_make_strref(cbuf, ics); ics->strman->unref(cbuf); res.set_str(sr); }); @@ -77,7 +78,7 @@ void cs_init_lib_string(cs_state &cs) { buf[i] = toupper(inps[i]); } auto const *cbuf = ics->strman->steal(buf); - auto sr = cs_make_strref(cbuf, *ics); + auto sr = cs_make_strref(cbuf, ics); ics->strman->unref(cbuf); res.set_str(sr); }); diff --git a/src/meson.build b/src/meson.build index 5862927..6702cf0 100644 --- a/src/meson.build +++ b/src/meson.build @@ -8,6 +8,7 @@ libcubescript_src = [ 'cs_error.cc', 'cs_gen.cc', 'cs_ident.cc', + 'cs_state.cc', 'cs_util.cc', 'cs_val.cc', 'cs_vm.cc',