diff options
Diffstat (limited to 'src/nvim/api/private/converter.c')
-rw-r--r-- | src/nvim/api/private/converter.c | 121 |
1 files changed, 56 insertions, 65 deletions
diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 90023171e5..a70ef1e50b 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -11,7 +11,6 @@ #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" -#include "nvim/func_attr.h" #include "nvim/lua/executor.h" #include "nvim/memory.h" #include "nvim/types_defs.h" @@ -20,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 @@ -42,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 @@ -59,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) \ @@ -91,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) \ @@ -110,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) \ @@ -132,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) \ @@ -157,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__"); } } @@ -234,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,14 +262,20 @@ Object vim_to_object(typval_T *obj) /// @param tv Conversion result is placed here. On failure member v_type is /// 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` /// -/// @returns true if conversion is successful, otherwise false. -bool object_to_vim(Object obj, typval_T *tv, Error *err) +/// 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; @@ -274,46 +283,40 @@ bool 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; - - if (!object_to_vim(item, &li_tv, err)) { - tv_list_free(list); - return false; - } - + 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); @@ -326,27 +329,11 @@ bool 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; - - if (key.size == 0) { - api_set_error(err, kErrorTypeValidation, - "Empty dictionary keys aren't allowed"); - // cleanup - tv_dict_free(dict); - return false; - } - + 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); - - if (!object_to_vim(item.value, &di->di_tv, err)) { - // cleanup - tv_dict_item_free(di); - tv_dict_free(dict); - return false; - } - + object_to_vim_take_luaref(&item->value, &di->di_tv, take_luaref, err); tv_dict_add(dict, di); } dict->dv_refcount++; @@ -357,12 +344,16 @@ bool 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; } } - - return true; } |