2021-03-23 00:25:47 +00:00
|
|
|
#include <cubescript/cubescript.hh>
|
|
|
|
|
|
|
|
#include "cs_strman.hh"
|
2021-03-25 00:37:13 +00:00
|
|
|
#include "cs_thread.hh"
|
2021-03-23 00:25:47 +00:00
|
|
|
|
2021-03-23 22:32:25 +00:00
|
|
|
namespace cubescript {
|
2021-03-23 00:25:47 +00:00
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
struct string_ref_state {
|
2021-03-23 00:25:47 +00:00
|
|
|
std::size_t length;
|
|
|
|
std::size_t refcount;
|
|
|
|
};
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
inline string_ref_state *get_ref_state(char const *ptr) {
|
|
|
|
return const_cast<string_ref_state *>(
|
|
|
|
reinterpret_cast<string_ref_state const *>(ptr)
|
2021-03-23 00:25:47 +00:00
|
|
|
) - 1;
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
char const *string_pool::add(std::string_view str) {
|
2021-03-23 00:25:47 +00:00
|
|
|
auto it = counts.find(str);
|
|
|
|
/* already present: just increment ref */
|
|
|
|
if (it != counts.end()) {
|
|
|
|
auto *st = it->second;
|
|
|
|
/* having a null pointer is the same as non-existence */
|
|
|
|
if (st) {
|
|
|
|
++st->refcount;
|
|
|
|
return reinterpret_cast<char const *>(st + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* not present: allocate brand new data */
|
|
|
|
auto ss = str.size();
|
|
|
|
auto strp = alloc_buf(ss);
|
|
|
|
/* write string data, it's already pre-terminated */
|
|
|
|
memcpy(strp, str.data(), ss);
|
|
|
|
/* store it */
|
|
|
|
counts.emplace(std::string_view{strp, ss}, get_ref_state(strp));
|
|
|
|
return strp;
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
char const *string_pool::ref(char const *ptr) {
|
2021-03-23 00:25:47 +00:00
|
|
|
auto *ss = get_ref_state(ptr);
|
|
|
|
++ss->refcount;
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
string_ref string_pool::steal(char *ptr) {
|
2021-03-23 00:25:47 +00:00
|
|
|
auto *ss = get_ref_state(ptr);
|
|
|
|
auto sr = std::string_view{ptr, ss->length};
|
|
|
|
/* much like add(), but we already have memory */
|
|
|
|
auto it = counts.find(sr);
|
|
|
|
if (it != counts.end()) {
|
|
|
|
auto *st = it->second;
|
|
|
|
if (st) {
|
|
|
|
/* the buffer is superfluous now */
|
2021-03-23 22:29:32 +00:00
|
|
|
cstate->alloc(ss, ss->length + sizeof(string_ref_state) + 1, 0);
|
|
|
|
return string_ref{reinterpret_cast<char const *>(st + 1), cstate};
|
2021-03-23 00:25:47 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-23 22:29:32 +00:00
|
|
|
ss->refcount = 0; /* string_ref will increment it */
|
2021-03-23 00:25:47 +00:00
|
|
|
counts.emplace(sr, ss);
|
2021-03-23 22:29:32 +00:00
|
|
|
return string_ref{ptr, cstate};
|
2021-03-23 00:25:47 +00:00
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
void string_pool::unref(char const *ptr) {
|
2021-03-23 00:25:47 +00:00
|
|
|
auto *ss = get_ref_state(ptr);
|
|
|
|
if (!--ss->refcount) {
|
|
|
|
/* refcount zero, so ditch it
|
|
|
|
* this path is a little slow...
|
|
|
|
*/
|
|
|
|
auto sr = std::string_view{ptr, ss->length};
|
|
|
|
auto it = counts.find(sr);
|
|
|
|
if (it == counts.end()) {
|
|
|
|
/* internal error: this should *never* happen */
|
2021-03-23 22:29:32 +00:00
|
|
|
throw internal_error{"no refcount"};
|
2021-03-23 00:25:47 +00:00
|
|
|
}
|
|
|
|
/* we're freeing the key */
|
|
|
|
counts.erase(it);
|
|
|
|
/* dealloc */
|
2021-03-23 22:29:32 +00:00
|
|
|
cstate->alloc(ss, ss->length + sizeof(string_ref_state) + 1, 0);
|
2021-03-23 00:25:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
char const *string_pool::find(std::string_view str) const {
|
2021-03-23 00:25:47 +00:00
|
|
|
auto it = counts.find(str);
|
|
|
|
if (it == counts.end()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return reinterpret_cast<char const *>(it->second + 1);
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
std::string_view string_pool::get(char const *ptr) const {
|
2021-03-23 00:25:47 +00:00
|
|
|
auto *ss = get_ref_state(ptr);
|
|
|
|
return std::string_view{ptr, ss->length};
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
char *string_pool::alloc_buf(std::size_t len) const {
|
|
|
|
auto mem = cstate->alloc(nullptr, 0, len + sizeof(string_ref_state) + 1);
|
2021-03-23 00:25:47 +00:00
|
|
|
if (!mem) {
|
2021-03-23 22:29:32 +00:00
|
|
|
throw internal_error{"allocation failed"};
|
2021-03-23 00:25:47 +00:00
|
|
|
}
|
|
|
|
/* write length and initial refcount */
|
2021-03-23 22:29:32 +00:00
|
|
|
auto *sst = static_cast<string_ref_state *>(mem);
|
2021-03-23 00:25:47 +00:00
|
|
|
sst->length = len;
|
|
|
|
sst->refcount = 1;
|
|
|
|
/* pre-terminate */
|
|
|
|
auto *strp = reinterpret_cast<char *>(sst + 1);
|
|
|
|
strp[len] = '\0';
|
|
|
|
/* now the user can fill it */
|
|
|
|
return strp;
|
|
|
|
};
|
|
|
|
|
2021-03-23 00:49:29 +00:00
|
|
|
/* strref implementation */
|
|
|
|
|
|
|
|
/* strref */
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
LIBCUBESCRIPT_EXPORT string_ref::string_ref(
|
|
|
|
internal_state *cs, std::string_view str
|
2021-03-23 00:49:29 +00:00
|
|
|
): p_state{cs}
|
|
|
|
{
|
|
|
|
p_str = cs->strman->add(str);
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
LIBCUBESCRIPT_EXPORT string_ref::string_ref(state &cs, std::string_view str):
|
2021-03-25 00:37:13 +00:00
|
|
|
p_state{cs.p_tstate->istate}
|
2021-03-23 00:49:29 +00:00
|
|
|
{
|
|
|
|
p_str = p_state->strman->add(str);
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
LIBCUBESCRIPT_EXPORT string_ref::string_ref(string_ref const &ref):
|
2021-03-23 00:49:29 +00:00
|
|
|
p_state{ref.p_state}, p_str{ref.p_str}
|
|
|
|
{
|
|
|
|
p_state->strman->ref(p_str);
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
/* this can be used by friends to do quick string_ref creation */
|
|
|
|
LIBCUBESCRIPT_EXPORT string_ref::string_ref(char const *p, internal_state *cs):
|
2021-03-23 00:49:29 +00:00
|
|
|
p_state{cs}
|
|
|
|
{
|
|
|
|
p_str = p_state->strman->ref(p);
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
LIBCUBESCRIPT_EXPORT string_ref::~string_ref() {
|
2021-03-23 00:49:29 +00:00
|
|
|
p_state->strman->unref(p_str);
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
LIBCUBESCRIPT_EXPORT string_ref &string_ref::operator=(string_ref const &ref) {
|
2021-03-23 00:49:29 +00:00
|
|
|
p_str = ref.p_str;
|
|
|
|
p_state = ref.p_state;
|
|
|
|
p_state->strman->ref(p_str);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
LIBCUBESCRIPT_EXPORT string_ref::operator std::string_view() const {
|
2021-03-23 00:49:29 +00:00
|
|
|
return p_state->strman->get(p_str);
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:29:32 +00:00
|
|
|
LIBCUBESCRIPT_EXPORT bool string_ref::operator==(string_ref const &s) const {
|
2021-03-23 00:49:29 +00:00
|
|
|
return p_str == s.p_str;
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:32:25 +00:00
|
|
|
} /* namespace cubescript */
|