mirror of
https://github.com/neovim/neovim.git
synced 2026-08-29 10:31:48 +00:00
refactor(eval): use arena when converting typvals to Object
Note: this contains two _temporary_ changes which can be reverted once the Arena vs no-Arena distinction in API wrappers has been removed. Both nlua_push_Object and object_to_vim_take_luaref() has been changed to take the object argument as a pointer. This is not going to be necessary once these are only used with arena (or not at all) allocated Objects. The object_to_vim() variant which leaves luaref untouched might need to stay for a little longer.
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
/// Helper structure for vim_to_object
|
||||
typedef struct {
|
||||
kvec_withinit_t(Object, 2) stack; ///< Object stack.
|
||||
Arena *arena; ///< arena where objects will be allocated
|
||||
bool reuse_strdata;
|
||||
} EncodedData;
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
@@ -41,12 +43,21 @@ typedef struct {
|
||||
#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
|
||||
kvi_push(edata->stack, FLOAT_OBJ((Float)(flt)))
|
||||
|
||||
static Object typval_cbuf_to_obj(EncodedData *edata, const char *data, size_t len)
|
||||
{
|
||||
if (edata->reuse_strdata) {
|
||||
return STRING_OBJ(cbuf_as_string((char *)(len ? data : ""), len));
|
||||
} else {
|
||||
return CBUF_TO_ARENA_OBJ(edata->arena, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
#define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \
|
||||
do { \
|
||||
const size_t len_ = (size_t)(len); \
|
||||
const char *const str_ = (str); \
|
||||
assert(len_ == 0 || str_ != NULL); \
|
||||
kvi_push(edata->stack, STRING_OBJ(cbuf_to_string((len_ ? str_ : ""), len_))); \
|
||||
kvi_push(edata->stack, typval_cbuf_to_obj(edata, str_, len_)); \
|
||||
} while (0)
|
||||
|
||||
#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING
|
||||
@@ -58,10 +69,7 @@ typedef struct {
|
||||
do { \
|
||||
const size_t len_ = (size_t)(len); \
|
||||
const blob_T *const blob_ = (blob); \
|
||||
kvi_push(edata->stack, STRING_OBJ(((String) { \
|
||||
.data = len_ != 0 ? xmemdupz(blob_->bv_ga.ga_data, len_) : xstrdup(""), \
|
||||
.size = len_ \
|
||||
}))); \
|
||||
kvi_push(edata->stack, typval_cbuf_to_obj(edata, len_ ? blob_->bv_ga.ga_data : "", len_)); \
|
||||
} while (0)
|
||||
|
||||
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
|
||||
@@ -90,11 +98,7 @@ typedef struct {
|
||||
static inline void typval_encode_list_start(EncodedData *const edata, const size_t len)
|
||||
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
kvi_push(edata->stack, ARRAY_OBJ(((Array) {
|
||||
.capacity = len,
|
||||
.size = 0,
|
||||
.items = xmalloc(len * sizeof(*((Object)OBJECT_INIT).data.array.items)),
|
||||
})));
|
||||
kvi_push(edata->stack, ARRAY_OBJ(arena_array(edata->arena, len)));
|
||||
}
|
||||
|
||||
#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \
|
||||
@@ -109,7 +113,7 @@ static inline void typval_encode_between_list_items(EncodedData *const edata)
|
||||
Object *const list = &kv_last(edata->stack);
|
||||
assert(list->type == kObjectTypeArray);
|
||||
assert(list->data.array.size < list->data.array.capacity);
|
||||
list->data.array.items[list->data.array.size++] = item;
|
||||
ADD_C(list->data.array, item);
|
||||
}
|
||||
|
||||
#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \
|
||||
@@ -131,11 +135,7 @@ static inline void typval_encode_list_end(EncodedData *const edata)
|
||||
static inline void typval_encode_dict_start(EncodedData *const edata, const size_t len)
|
||||
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
kvi_push(edata->stack, DICTIONARY_OBJ(((Dictionary) {
|
||||
.capacity = len,
|
||||
.size = 0,
|
||||
.items = xmalloc(len * sizeof(*((Object)OBJECT_INIT).data.dictionary.items)),
|
||||
})));
|
||||
kvi_push(edata->stack, DICTIONARY_OBJ(arena_dict(edata->arena, len)));
|
||||
}
|
||||
|
||||
#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \
|
||||
@@ -156,9 +156,8 @@ static inline void typval_encode_after_key(EncodedData *const edata)
|
||||
dict->data.dictionary.items[dict->data.dictionary.size].key
|
||||
= key.data.string;
|
||||
} else {
|
||||
api_free_object(key);
|
||||
dict->data.dictionary.items[dict->data.dictionary.size].key
|
||||
= STATIC_CSTR_TO_STRING("__INVALID_KEY__");
|
||||
= STATIC_CSTR_AS_STRING("__INVALID_KEY__");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,17 +232,22 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
|
||||
#undef TYPVAL_ENCODE_CONV_RECURSE
|
||||
#undef TYPVAL_ENCODE_ALLOW_SPECIALS
|
||||
|
||||
/// Convert a vim object to an `Object` instance, recursively expanding
|
||||
/// Convert a vim object to an `Object` instance, recursively converting
|
||||
/// Arrays/Dictionaries.
|
||||
///
|
||||
/// @param obj The source object
|
||||
/// @param arena if NULL, use direct allocation
|
||||
/// @param reuse_strdata when true, don't copy string data to Arena but reference
|
||||
/// typval strings directly. takes no effect when arena is
|
||||
/// NULL
|
||||
/// @return The converted value
|
||||
Object vim_to_object(typval_T *obj)
|
||||
Object vim_to_object(typval_T *obj, Arena *arena, bool reuse_strdata)
|
||||
{
|
||||
EncodedData edata;
|
||||
kvi_init(edata.stack);
|
||||
const int evo_ret = encode_vim_to_object(&edata, obj,
|
||||
"vim_to_object argument");
|
||||
edata.arena = arena;
|
||||
edata.reuse_strdata = reuse_strdata;
|
||||
const int evo_ret = encode_vim_to_object(&edata, obj, "vim_to_object argument");
|
||||
(void)evo_ret;
|
||||
assert(evo_ret == OK);
|
||||
Object ret = kv_A(edata.stack, 0);
|
||||
@@ -259,11 +263,19 @@ Object vim_to_object(typval_T *obj)
|
||||
/// set to VAR_UNKNOWN (no allocation was made for this variable).
|
||||
/// @param err Error object.
|
||||
void object_to_vim(Object obj, typval_T *tv, Error *err)
|
||||
{
|
||||
object_to_vim_take_luaref(&obj, tv, false, err);
|
||||
}
|
||||
|
||||
/// same as object_to_vim but consumes all luarefs (nested) in `obj`
|
||||
///
|
||||
/// useful when `obj` is allocated on an arena
|
||||
void object_to_vim_take_luaref(Object *obj, typval_T *tv, bool take_luaref, Error *err)
|
||||
{
|
||||
tv->v_type = VAR_UNKNOWN;
|
||||
tv->v_lock = VAR_UNLOCKED;
|
||||
|
||||
switch (obj.type) {
|
||||
switch (obj->type) {
|
||||
case kObjectTypeNil:
|
||||
tv->v_type = VAR_SPECIAL;
|
||||
tv->vval.v_special = kSpecialVarNull;
|
||||
@@ -271,41 +283,40 @@ void object_to_vim(Object obj, typval_T *tv, Error *err)
|
||||
|
||||
case kObjectTypeBoolean:
|
||||
tv->v_type = VAR_BOOL;
|
||||
tv->vval.v_bool = obj.data.boolean ? kBoolVarTrue : kBoolVarFalse;
|
||||
tv->vval.v_bool = obj->data.boolean ? kBoolVarTrue : kBoolVarFalse;
|
||||
break;
|
||||
|
||||
case kObjectTypeBuffer:
|
||||
case kObjectTypeWindow:
|
||||
case kObjectTypeTabpage:
|
||||
case kObjectTypeInteger:
|
||||
STATIC_ASSERT(sizeof(obj.data.integer) <= sizeof(varnumber_T),
|
||||
STATIC_ASSERT(sizeof(obj->data.integer) <= sizeof(varnumber_T),
|
||||
"Integer size must be <= Vimscript number size");
|
||||
tv->v_type = VAR_NUMBER;
|
||||
tv->vval.v_number = (varnumber_T)obj.data.integer;
|
||||
tv->vval.v_number = (varnumber_T)obj->data.integer;
|
||||
break;
|
||||
|
||||
case kObjectTypeFloat:
|
||||
tv->v_type = VAR_FLOAT;
|
||||
tv->vval.v_float = obj.data.floating;
|
||||
tv->vval.v_float = obj->data.floating;
|
||||
break;
|
||||
|
||||
case kObjectTypeString:
|
||||
tv->v_type = VAR_STRING;
|
||||
if (obj.data.string.data == NULL) {
|
||||
if (obj->data.string.data == NULL) {
|
||||
tv->vval.v_string = NULL;
|
||||
} else {
|
||||
tv->vval.v_string = xmemdupz(obj.data.string.data,
|
||||
obj.data.string.size);
|
||||
tv->vval.v_string = xmemdupz(obj->data.string.data,
|
||||
obj->data.string.size);
|
||||
}
|
||||
break;
|
||||
|
||||
case kObjectTypeArray: {
|
||||
list_T *const list = tv_list_alloc((ptrdiff_t)obj.data.array.size);
|
||||
list_T *const list = tv_list_alloc((ptrdiff_t)obj->data.array.size);
|
||||
|
||||
for (uint32_t i = 0; i < obj.data.array.size; i++) {
|
||||
Object item = obj.data.array.items[i];
|
||||
for (uint32_t i = 0; i < obj->data.array.size; i++) {
|
||||
typval_T li_tv;
|
||||
object_to_vim(item, &li_tv, err);
|
||||
object_to_vim_take_luaref(&obj->data.array.items[i], &li_tv, take_luaref, err);
|
||||
tv_list_append_owned_tv(list, li_tv);
|
||||
}
|
||||
tv_list_ref(list);
|
||||
@@ -318,11 +329,11 @@ void object_to_vim(Object obj, typval_T *tv, Error *err)
|
||||
case kObjectTypeDictionary: {
|
||||
dict_T *const dict = tv_dict_alloc();
|
||||
|
||||
for (uint32_t i = 0; i < obj.data.dictionary.size; i++) {
|
||||
KeyValuePair item = obj.data.dictionary.items[i];
|
||||
String key = item.key;
|
||||
for (uint32_t i = 0; i < obj->data.dictionary.size; i++) {
|
||||
KeyValuePair *item = &obj->data.dictionary.items[i];
|
||||
String key = item->key;
|
||||
dictitem_T *const di = tv_dict_item_alloc(key.data);
|
||||
object_to_vim(item.value, &di->di_tv, err);
|
||||
object_to_vim_take_luaref(&item->value, &di->di_tv, take_luaref, err);
|
||||
tv_dict_add(dict, di);
|
||||
}
|
||||
dict->dv_refcount++;
|
||||
@@ -333,7 +344,13 @@ void object_to_vim(Object obj, typval_T *tv, Error *err)
|
||||
}
|
||||
|
||||
case kObjectTypeLuaRef: {
|
||||
char *name = register_luafunc(api_new_luaref(obj.data.luaref));
|
||||
LuaRef ref = obj->data.luaref;
|
||||
if (take_luaref) {
|
||||
obj->data.luaref = LUA_NOREF;
|
||||
} else {
|
||||
ref = api_new_luaref(ref);
|
||||
}
|
||||
char *name = register_luafunc(ref);
|
||||
tv->v_type = VAR_FUNC;
|
||||
tv->vval.v_string = xstrdup(name);
|
||||
break;
|
||||
|
||||
@@ -175,7 +175,7 @@ bool try_end(Error *err)
|
||||
/// @param dict The vimscript dict
|
||||
/// @param key The key
|
||||
/// @param[out] err Details of an error that may have occurred
|
||||
Object dict_get_value(dict_T *dict, String key, Error *err)
|
||||
Object dict_get_value(dict_T *dict, String key, Arena *arena, Error *err)
|
||||
{
|
||||
dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
|
||||
|
||||
@@ -184,7 +184,7 @@ Object dict_get_value(dict_T *dict, String key, Error *err)
|
||||
return (Object)OBJECT_INIT;
|
||||
}
|
||||
|
||||
return vim_to_object(&di->di_tv);
|
||||
return vim_to_object(&di->di_tv, arena, true);
|
||||
}
|
||||
|
||||
dictitem_T *dict_check_writable(dict_T *dict, String key, bool del, Error *err)
|
||||
@@ -221,7 +221,8 @@ dictitem_T *dict_check_writable(dict_T *dict, String key, bool del, Error *err)
|
||||
/// @param retval If true the old value will be converted and returned.
|
||||
/// @param[out] err Details of an error that may have occurred
|
||||
/// @return The old value if `retval` is true and the key was present, else NIL
|
||||
Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retval, Error *err)
|
||||
Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retval, Arena *arena,
|
||||
Error *err)
|
||||
{
|
||||
Object rv = OBJECT_INIT;
|
||||
dictitem_T *di = dict_check_writable(dict, key, del, err);
|
||||
@@ -244,7 +245,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva
|
||||
}
|
||||
// Return the old value
|
||||
if (retval) {
|
||||
rv = vim_to_object(&di->di_tv);
|
||||
rv = vim_to_object(&di->di_tv, arena, false);
|
||||
}
|
||||
// Delete the entry
|
||||
tv_dict_item_remove(dict, di);
|
||||
@@ -265,7 +266,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva
|
||||
} else {
|
||||
// Return the old value
|
||||
if (retval) {
|
||||
rv = vim_to_object(&di->di_tv);
|
||||
rv = vim_to_object(&di->di_tv, arena, false);
|
||||
}
|
||||
bool type_error = false;
|
||||
if (dict == &vimvardict
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#define CSTR_TO_ARENA_STR(arena, s) arena_string(arena, cstr_as_string(s))
|
||||
#define CSTR_TO_ARENA_OBJ(arena, s) STRING_OBJ(CSTR_TO_ARENA_STR(arena, s))
|
||||
#define CBUF_TO_ARENA_STR(arena, s, len) arena_string(arena, cbuf_as_string((char *)(s), len))
|
||||
#define CBUF_TO_ARENA_OBJ(arena, s, len) STRING_OBJ(CBUF_TO_ARENA_STR(arena, s, len))
|
||||
|
||||
#define BUFFER_OBJ(s) ((Object) { \
|
||||
.type = kObjectTypeBuffer, \
|
||||
|
||||
Reference in New Issue
Block a user