diff options
Diffstat (limited to 'src/nvim/eval')
-rw-r--r-- | src/nvim/eval/decode.c | 46 | ||||
-rw-r--r-- | src/nvim/eval/encode.c | 82 | ||||
-rw-r--r-- | src/nvim/eval/encode.h | 13 | ||||
-rw-r--r-- | src/nvim/eval/typval.c | 221 | ||||
-rw-r--r-- | src/nvim/eval/typval.h | 249 | ||||
-rw-r--r-- | src/nvim/eval/typval_encode.c.h | 137 |
6 files changed, 555 insertions, 193 deletions
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index 0933b1bf9c..d5c65ebe81 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -60,8 +60,8 @@ static inline void create_special_dict(typval_T *const rettv, dictitem_T *const type_di = tv_dict_item_alloc_len(S_LEN("_TYPE")); type_di->di_tv.v_type = VAR_LIST; type_di->di_tv.v_lock = VAR_UNLOCKED; - type_di->di_tv.vval.v_list = (list_T *) eval_msgpack_type_lists[type]; - type_di->di_tv.vval.v_list->lv_refcount++; + type_di->di_tv.vval.v_list = (list_T *)eval_msgpack_type_lists[type]; + tv_list_ref(type_di->di_tv.vval.v_list); tv_dict_add(dict, type_di); dictitem_T *const val_di = tv_dict_item_alloc_len(S_LEN("_VAL")); val_di->di_tv = val; @@ -120,7 +120,7 @@ static inline int json_decoder_pop(ValuesStackItem obj, last_container = kv_last(*container_stack); } if (last_container.container.v_type == VAR_LIST) { - if (last_container.container.vval.v_list->lv_len != 0 + if (tv_list_len(last_container.container.vval.v_list) != 0 && !obj.didcomma) { EMSG2(_("E474: Expected comma before list item: %s"), val_location); tv_clear(&obj.val); @@ -128,7 +128,7 @@ static inline int json_decoder_pop(ValuesStackItem obj, } assert(last_container.special_val == NULL); listitem_T *obj_li = tv_list_item_alloc(); - obj_li->li_tv = obj.val; + *TV_LIST_ITEM_TV(obj_li) = obj.val; tv_list_append(last_container.container.vval.v_list, obj_li); } else if (last_container.stack_index == kv_size(*stack) - 2) { if (!obj.didcolon) { @@ -155,10 +155,10 @@ static inline int json_decoder_pop(ValuesStackItem obj, list_T *const kv_pair = tv_list_alloc(); tv_list_append_list(last_container.special_val, kv_pair); listitem_T *const key_li = tv_list_item_alloc(); - key_li->li_tv = key.val; + *TV_LIST_ITEM_TV(key_li) = key.val; tv_list_append(kv_pair, key_li); listitem_T *const val_li = tv_list_item_alloc(); - val_li->li_tv = obj.val; + *TV_LIST_ITEM_TV(val_li) = obj.val; tv_list_append(kv_pair, val_li); } } else { @@ -234,7 +234,7 @@ list_T *decode_create_map_special_dict(typval_T *const ret_tv) FUNC_ATTR_NONNULL_ALL { list_T *const list = tv_list_alloc(); - list->lv_refcount++; + tv_list_ref(list); create_special_dict(ret_tv, kMPMap, ((typval_T) { .v_type = VAR_LIST, .v_lock = VAR_UNLOCKED, @@ -270,7 +270,7 @@ typval_T decode_string(const char *const s, const size_t len, : (bool)hasnul); if (really_hasnul) { list_T *const list = tv_list_alloc(); - list->lv_refcount++; + tv_list_ref(list); typval_T tv; create_special_dict(&tv, binary ? kMPBinary : kMPString, ((typval_T) { .v_type = VAR_LIST, @@ -738,8 +738,9 @@ json_decode_string_cycle_start: } else if (last_container.special_val == NULL ? (last_container.container.v_type == VAR_DICT ? (DICT_LEN(last_container.container.vval.v_dict) == 0) - : (last_container.container.vval.v_list->lv_len == 0)) - : (last_container.special_val->lv_len == 0)) { + : (tv_list_len(last_container.container.vval.v_list) + == 0)) + : (tv_list_len(last_container.special_val) == 0)) { emsgf(_("E474: Leading comma: %.*s"), LENP(p, e)); goto json_decode_string_fail; } @@ -849,7 +850,7 @@ json_decode_string_cycle_start: } case '[': { list_T *list = tv_list_alloc(); - list->lv_refcount++; + tv_list_ref(list); typval_T tv = { .v_type = VAR_LIST, .v_lock = VAR_UNLOCKED, @@ -970,7 +971,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) }; } else { list_T *const list = tv_list_alloc(); - list->lv_refcount++; + tv_list_ref(list); create_special_dict(rettv, kMPInteger, ((typval_T) { .v_type = VAR_LIST, .v_lock = VAR_UNLOCKED, @@ -993,7 +994,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) }; } else { list_T *const list = tv_list_alloc(); - list->lv_refcount++; + tv_list_ref(list); create_special_dict(rettv, kMPInteger, ((typval_T) { .v_type = VAR_LIST, .v_lock = VAR_UNLOCKED, @@ -1039,7 +1040,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) } case MSGPACK_OBJECT_ARRAY: { list_T *const list = tv_list_alloc(); - list->lv_refcount++; + tv_list_ref(list); *rettv = (typval_T) { .v_type = VAR_LIST, .v_lock = VAR_UNLOCKED, @@ -1047,9 +1048,10 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) }; for (size_t i = 0; i < mobj.via.array.size; i++) { listitem_T *const li = tv_list_item_alloc(); - li->li_tv.v_type = VAR_UNKNOWN; + TV_LIST_ITEM_TV(li)->v_type = VAR_UNKNOWN; tv_list_append(list, li); - if (msgpack_to_vim(mobj.via.array.ptr[i], &li->li_tv) == FAIL) { + if (msgpack_to_vim(mobj.via.array.ptr[i], TV_LIST_ITEM_TV(li)) + == FAIL) { return FAIL; } } @@ -1094,15 +1096,17 @@ msgpack_to_vim_generic_map: {} list_T *const kv_pair = tv_list_alloc(); tv_list_append_list(list, kv_pair); listitem_T *const key_li = tv_list_item_alloc(); - key_li->li_tv.v_type = VAR_UNKNOWN; + TV_LIST_ITEM_TV(key_li)->v_type = VAR_UNKNOWN; tv_list_append(kv_pair, key_li); listitem_T *const val_li = tv_list_item_alloc(); - val_li->li_tv.v_type = VAR_UNKNOWN; + TV_LIST_ITEM_TV(val_li)->v_type = VAR_UNKNOWN; tv_list_append(kv_pair, val_li); - if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_li->li_tv) == FAIL) { + if (msgpack_to_vim(mobj.via.map.ptr[i].key, TV_LIST_ITEM_TV(key_li)) + == FAIL) { return FAIL; } - if (msgpack_to_vim(mobj.via.map.ptr[i].val, &val_li->li_tv) == FAIL) { + if (msgpack_to_vim(mobj.via.map.ptr[i].val, TV_LIST_ITEM_TV(val_li)) + == FAIL) { return FAIL; } } @@ -1110,7 +1114,7 @@ msgpack_to_vim_generic_map: {} } case MSGPACK_OBJECT_EXT: { list_T *const list = tv_list_alloc(); - list->lv_refcount++; + tv_list_ref(list); tv_list_append_number(list, mobj.via.ext.type); list_T *const ext_val_list = tv_list_alloc(); tv_list_append_list(list, ext_val_list); diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index ef647b3ee4..9f16b78976 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -53,17 +53,18 @@ int encode_list_write(void *const data, const char *const buf, const size_t len) list_T *const list = (list_T *) data; const char *const end = buf + len; const char *line_end = buf; - listitem_T *li = list->lv_last; + listitem_T *li = tv_list_last(list); // Continue the last list element if (li != NULL) { line_end = xmemscan(buf, NL, len); if (line_end != buf) { const size_t line_length = (size_t)(line_end - buf); - char *str = (char *)li->li_tv.vval.v_string; + char *str = (char *)TV_LIST_ITEM_TV(li)->vval.v_string; const size_t li_len = (str == NULL ? 0 : strlen(str)); - li->li_tv.vval.v_string = xrealloc(str, li_len + line_length + 1); - str = (char *)li->li_tv.vval.v_string + li_len; + TV_LIST_ITEM_TV(li)->vval.v_string = xrealloc( + str, li_len + line_length + 1); + str = (char *)TV_LIST_ITEM_TV(li)->vval.v_string + li_len; memcpy(str, buf, line_length); str[line_length] = 0; memchrsub(str, NUL, NL, line_length); @@ -135,21 +136,22 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack, } case kMPConvPairs: case kMPConvList: { - int idx = 0; - const listitem_T *li; - for (li = v.data.l.list->lv_first; - li != NULL && li->li_next != v.data.l.li; - li = li->li_next) { - idx++; - } + const listitem_T *const li = (v.data.l.li == NULL + ? tv_list_last(v.data.l.list) + : TV_LIST_ITEM_PREV(v.data.l.list, + v.data.l.li)); + int idx = (li == NULL + ? 0 + : (int)tv_list_idx_of_item(v.data.l.list, li)); if (v.type == kMPConvList || li == NULL - || (li->li_tv.v_type != VAR_LIST - && li->li_tv.vval.v_list->lv_len <= 0)) { - vim_snprintf((char *) IObuff, IOSIZE, idx_msg, idx); + || (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST + && tv_list_len(TV_LIST_ITEM_TV(li)->vval.v_list) <= 0)) { + vim_snprintf((char *)IObuff, IOSIZE, idx_msg, idx); ga_concat(&msg_ga, IObuff); } else { - typval_T key_tv = li->li_tv.vval.v_list->lv_first->li_tv; + typval_T key_tv = *TV_LIST_ITEM_TV( + tv_list_first(TV_LIST_ITEM_TV(li)->vval.v_list)); char *const key = encode_tv2echo(&key_tv, NULL); vim_snprintf((char *) IObuff, IOSIZE, key_pair_msg, key, idx); xfree(key); @@ -202,21 +204,17 @@ bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len, FUNC_ATTR_NONNULL_ARG(2, 3) FUNC_ATTR_WARN_UNUSED_RESULT { size_t len = 0; - if (list != NULL) { - for (const listitem_T *li = list->lv_first; - li != NULL; - li = li->li_next) { - if (li->li_tv.v_type != VAR_STRING) { - return false; - } - len++; - if (li->li_tv.vval.v_string != 0) { - len += STRLEN(li->li_tv.vval.v_string); - } + TV_LIST_ITER_CONST(list, li, { + if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) { + return false; } - if (len) { - len--; + len++; + if (TV_LIST_ITEM_TV(li)->vval.v_string != 0) { + len += STRLEN(TV_LIST_ITEM_TV(li)->vval.v_string); } + }); + if (len) { + len--; } *ret_len = len; if (len == 0) { @@ -253,31 +251,34 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, char *const buf_end = buf + nbuf; char *p = buf; while (p < buf_end) { - assert(state->li_length == 0 || state->li->li_tv.vval.v_string != NULL); + assert(state->li_length == 0 + || TV_LIST_ITEM_TV(state->li)->vval.v_string != NULL); for (size_t i = state->offset; i < state->li_length && p < buf_end; i++) { - assert(state->li->li_tv.vval.v_string != NULL); - const char ch = (char)state->li->li_tv.vval.v_string[state->offset++]; + assert(TV_LIST_ITEM_TV(state->li)->vval.v_string != NULL); + const char ch = (char)( + TV_LIST_ITEM_TV(state->li)->vval.v_string[state->offset++]); *p++ = (char)((char)ch == (char)NL ? (char)NUL : (char)ch); } if (p < buf_end) { - state->li = state->li->li_next; + state->li = TV_LIST_ITEM_NEXT(state->list, state->li); if (state->li == NULL) { *read_bytes = (size_t) (p - buf); return OK; } *p++ = NL; - if (state->li->li_tv.v_type != VAR_STRING) { - *read_bytes = (size_t) (p - buf); + if (TV_LIST_ITEM_TV(state->li)->v_type != VAR_STRING) { + *read_bytes = (size_t)(p - buf); return FAIL; } state->offset = 0; - state->li_length = (state->li->li_tv.vval.v_string == NULL + state->li_length = (TV_LIST_ITEM_TV(state->li)->vval.v_string == NULL ? 0 - : STRLEN(state->li->li_tv.vval.v_string)); + : STRLEN(TV_LIST_ITEM_TV(state->li)->vval.v_string)); } } *read_bytes = nbuf; - return (state->offset < state->li_length || state->li->li_next != NULL + return ((state->offset < state->li_length + || TV_LIST_ITEM_NEXT(state->list, state->li) != NULL) ? NOTDONE : OK); } @@ -727,12 +728,11 @@ bool encode_check_json_key(const typval_T *const tv) if (val_di->di_tv.vval.v_list == NULL) { return true; } - for (const listitem_T *li = val_di->di_tv.vval.v_list->lv_first; - li != NULL; li = li->li_next) { - if (li->li_tv.v_type != VAR_STRING) { + TV_LIST_ITER_CONST(val_di->di_tv.vval.v_list, li, { + if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) { return false; } - } + }); return true; } diff --git a/src/nvim/eval/encode.h b/src/nvim/eval/encode.h index 9bc665253b..ccea245ab3 100644 --- a/src/nvim/eval/encode.h +++ b/src/nvim/eval/encode.h @@ -33,9 +33,10 @@ int encode_vim_to_echo(garray_T *const packer, /// Structure defining state for read_from_list() typedef struct { + const list_T *const list; ///< List being currently read. const listitem_T *li; ///< Item currently read. - size_t offset; ///< Byte offset inside the read item. - size_t li_length; ///< Length of the string inside the read item. + size_t offset; ///< Byte offset inside the read item. + size_t li_length; ///< Length of the string inside the read item. } ListReaderState; /// Initialize ListReaderState structure @@ -43,11 +44,13 @@ static inline ListReaderState encode_init_lrstate(const list_T *const list) FUNC_ATTR_NONNULL_ALL { return (ListReaderState) { - .li = list->lv_first, + .list = list, + .li = tv_list_first(list), .offset = 0, - .li_length = (list->lv_first->li_tv.vval.v_string == NULL + .li_length = (TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string == NULL ? 0 - : STRLEN(list->lv_first->li_tv.vval.v_string)), + : STRLEN(TV_LIST_ITEM_TV( + tv_list_first(list))->vval.v_string)), }; } diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 4bc3a85efb..0c9c4a0347 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -66,7 +66,7 @@ listitem_T *tv_list_item_alloc(void) void tv_list_item_free(listitem_T *const item) FUNC_ATTR_NONNULL_ALL { - tv_clear(&item->li_tv); + tv_clear(TV_LIST_ITEM_TV(item)); xfree(item); } @@ -153,6 +153,45 @@ list_T *tv_list_alloc(void) return list; } +/// Initialize a static list with 10 items +/// +/// @param[out] sl Static list to initialize. +void tv_list_init_static10(staticList10_T *const sl) + FUNC_ATTR_NONNULL_ALL +{ +#define SL_SIZE ARRAY_SIZE(sl->sl_items) + list_T *const l = &sl->sl_list; + + memset(sl, 0, sizeof(staticList10_T)); + l->lv_first = &sl->sl_items[0]; + l->lv_last = &sl->sl_items[SL_SIZE - 1]; + l->lv_refcount = DO_NOT_FREE_CNT; + tv_list_set_lock(l, VAR_FIXED); + sl->sl_list.lv_len = 10; + + sl->sl_items[0].li_prev = NULL; + sl->sl_items[0].li_next = &sl->sl_items[1]; + sl->sl_items[SL_SIZE - 1].li_prev = &sl->sl_items[SL_SIZE - 2]; + sl->sl_items[SL_SIZE - 1].li_next = NULL; + + for (size_t i = 1; i < SL_SIZE - 1; i++) { + listitem_T *const li = &sl->sl_items[i]; + li->li_prev = li - 1; + li->li_next = li + 1; + } +#undef SL_SIZE +} + +/// Initialize static list with undefined number of elements +/// +/// @param[out] l List to initialize. +void tv_list_init_static(list_T *const l) + FUNC_ATTR_NONNULL_ALL +{ + memset(l, 0, sizeof(*l)); + l->lv_refcount = DO_NOT_FREE_CNT; +} + /// Free items contained in a list /// /// @param[in,out] l List to clear. @@ -221,7 +260,7 @@ void tv_list_unref(list_T *const l) //{{{2 Add/remove -/// Remove items "item" to "item2" from list "l". +/// Remove items "item" to "item2" from list "l" /// /// @warning Does not free the listitem or the value! /// @@ -251,6 +290,30 @@ void tv_list_remove_items(list_T *const l, listitem_T *const item, l->lv_idx_item = NULL; } +/// Move items "item" to "item2" from list "l" to the end of the list "tgt_l" +/// +/// @param[out] l List to move from. +/// @param[in] item First item to move. +/// @param[in] item2 Last item to move. +/// @param[out] tgt_l List to move to. +/// @param[in] cnt Number of items moved. +void tv_list_move_items(list_T *const l, listitem_T *const item, + listitem_T *const item2, list_T *const tgt_l, + const int cnt) + FUNC_ATTR_NONNULL_ALL +{ + tv_list_remove_items(l, item, item2); + item->li_prev = tgt_l->lv_last; + item2->li_next = NULL; + if (tgt_l->lv_last == NULL) { + tgt_l->lv_first = item; + } else { + tgt_l->lv_last->li_next = item; + } + tgt_l->lv_last = item2; + tgt_l->lv_len += cnt; +} + /// Insert list item /// /// @param[out] l List to insert to. @@ -326,7 +389,7 @@ void tv_list_append_tv(list_T *const l, typval_T *const tv) FUNC_ATTR_NONNULL_ALL { listitem_T *const li = tv_list_item_alloc(); - tv_copy(tv, &li->li_tv); + tv_copy(tv, TV_LIST_ITEM_TV(li)); tv_list_append(l, li); } @@ -339,12 +402,12 @@ void tv_list_append_list(list_T *const list, list_T *const itemlist) { listitem_T *const li = tv_list_item_alloc(); - li->li_tv.v_type = VAR_LIST; - li->li_tv.v_lock = VAR_UNLOCKED; - li->li_tv.vval.v_list = itemlist; + TV_LIST_ITEM_TV(li)->v_type = VAR_LIST; + TV_LIST_ITEM_TV(li)->v_lock = VAR_UNLOCKED; + TV_LIST_ITEM_TV(li)->vval.v_list = itemlist; tv_list_append(list, li); if (itemlist != NULL) { - itemlist->lv_refcount++; + tv_list_ref(itemlist); } } @@ -357,9 +420,9 @@ void tv_list_append_dict(list_T *const list, dict_T *const dict) { listitem_T *const li = tv_list_item_alloc(); - li->li_tv.v_type = VAR_DICT; - li->li_tv.v_lock = VAR_UNLOCKED; - li->li_tv.vval.v_dict = dict; + TV_LIST_ITEM_TV(li)->v_type = VAR_DICT; + TV_LIST_ITEM_TV(li)->v_lock = VAR_UNLOCKED; + TV_LIST_ITEM_TV(li)->vval.v_dict = dict; tv_list_append(list, li); if (dict != NULL) { dict->dv_refcount++; @@ -399,9 +462,9 @@ void tv_list_append_allocated_string(list_T *const l, char *const str) listitem_T *const li = tv_list_item_alloc(); tv_list_append(l, li); - li->li_tv.v_type = VAR_STRING; - li->li_tv.v_lock = VAR_UNLOCKED; - li->li_tv.vval.v_string = (char_u *)str; + TV_LIST_ITEM_TV(li)->v_type = VAR_STRING; + TV_LIST_ITEM_TV(li)->v_lock = VAR_UNLOCKED; + TV_LIST_ITEM_TV(li)->vval.v_string = (char_u *)str; } /// Append number to the list @@ -412,9 +475,9 @@ void tv_list_append_allocated_string(list_T *const l, char *const str) void tv_list_append_number(list_T *const l, const varnumber_T n) { listitem_T *const li = tv_list_item_alloc(); - li->li_tv.v_type = VAR_NUMBER; - li->li_tv.v_lock = VAR_UNLOCKED; - li->li_tv.vval.v_number = n; + TV_LIST_ITEM_TV(li)->v_type = VAR_NUMBER; + TV_LIST_ITEM_TV(li)->v_lock = VAR_UNLOCKED; + TV_LIST_ITEM_TV(li)->vval.v_number = n; tv_list_append(l, li); } @@ -439,33 +502,32 @@ list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig, } list_T *copy = tv_list_alloc(); + tv_list_ref(copy); if (copyID != 0) { // Do this before adding the items, because one of the items may // refer back to this list. orig->lv_copyID = copyID; orig->lv_copylist = copy; } - listitem_T *item; - for (item = orig->lv_first; item != NULL && !got_int; - item = item->li_next) { + TV_LIST_ITER(orig, item, { listitem_T *const ni = tv_list_item_alloc(); if (deep) { - if (var_item_copy(conv, &item->li_tv, &ni->li_tv, deep, copyID) == FAIL) { + if (var_item_copy(conv, TV_LIST_ITEM_TV(item), TV_LIST_ITEM_TV(ni), + deep, copyID) == FAIL) { xfree(ni); - break; + goto tv_list_copy_error; } } else { - tv_copy(&item->li_tv, &ni->li_tv); + tv_copy(TV_LIST_ITEM_TV(item), TV_LIST_ITEM_TV(ni)); } tv_list_append(copy, ni); - } - copy->lv_refcount++; - if (item != NULL) { - tv_list_unref(copy); - copy = NULL; - } + }); return copy; + +tv_list_copy_error: + tv_list_unref(copy); + return NULL; } /// Extend first list with the second @@ -475,17 +537,17 @@ list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig, /// @param[in] bef If not NULL, extends before this item. void tv_list_extend(list_T *const l1, list_T *const l2, listitem_T *const bef) - FUNC_ATTR_NONNULL_ARG(1, 2) + FUNC_ATTR_NONNULL_ARG(1) { - int todo = l2->lv_len; + int todo = tv_list_len(l2); listitem_T *const befbef = (bef == NULL ? NULL : bef->li_prev); listitem_T *const saved_next = (befbef == NULL ? NULL : befbef->li_next); // We also quit the loop when we have inserted the original item count of // the list, avoid a hang when we extend a list with itself. - for (listitem_T *item = l2->lv_first - ; item != NULL && --todo >= 0 + for (listitem_T *item = tv_list_first(l2) + ; item != NULL && todo-- ; item = (item == befbef ? saved_next : item->li_next)) { - tv_list_insert_tv(l1, &item->li_tv, bef); + tv_list_insert_tv(l1, TV_LIST_ITEM_TV(item), bef); } } @@ -540,13 +602,12 @@ static int list_join_inner(garray_T *const gap, list_T *const l, { size_t sumlen = 0; bool first = true; - listitem_T *item; // Stringify each item in the list. - for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) { + TV_LIST_ITER(l, item, { char *s; size_t len; - s = encode_tv2echo(&item->li_tv, &len); + s = encode_tv2echo(TV_LIST_ITEM_TV(item), &len); if (s == NULL) { return FAIL; } @@ -557,7 +618,7 @@ static int list_join_inner(garray_T *const gap, list_T *const l, p->tofree = p->s = (char_u *)s; line_breakcheck(); - } + }); // Allocate result buffer with its total size, avoid re-allocation and // multiple copy operations. Add 2 for a tailing ']' and NUL. @@ -591,16 +652,16 @@ static int list_join_inner(garray_T *const gap, list_T *const l, /// /// @return OK in case of success, FAIL otherwise. int tv_list_join(garray_T *const gap, list_T *const l, const char *const sep) - FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_ARG(1) { - if (l->lv_len < 1) { + if (!tv_list_len(l)) { return OK; } garray_T join_ga; int retval; - ga_init(&join_ga, (int)sizeof(Join), l->lv_len); + ga_init(&join_ga, (int)sizeof(Join), tv_list_len(l)); retval = list_join_inner(gap, l, sep, &join_ga); #define FREE_JOIN_TOFREE(join) xfree((join)->tofree) @@ -632,11 +693,13 @@ bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic, return false; } - listitem_T *item1 = l1->lv_first; - listitem_T *item2 = l2->lv_first; + listitem_T *item1 = tv_list_first(l1); + listitem_T *item2 = tv_list_first(l2); for (; item1 != NULL && item2 != NULL - ; item1 = item1->li_next, item2 = item2->li_next) { - if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive)) { + ; (item1 = TV_LIST_ITEM_NEXT(l1, item1), + item2 = TV_LIST_ITEM_NEXT(n2, item2))) { + if (!tv_equal(TV_LIST_ITEM_TV(item1), TV_LIST_ITEM_TV(item2), ic, + recursive)) { return false; } } @@ -644,6 +707,31 @@ bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic, return true; } +/// Reverse list in-place +/// +/// @param[in,out] l List to reverse. +void tv_list_reverse(list_T *const l) +{ + if (tv_list_len(l) <= 1) { + return; + } +#define SWAP(a, b) \ + do { \ + tmp = a; \ + a = b; \ + b = tmp; \ + } while (0) + listitem_T *tmp; + + SWAP(l->lv_first, l->lv_last); + for (listitem_T *li = l->lv_first; li != NULL; li = li->li_next) { + SWAP(li->li_next, li->li_prev); + } +#undef SWAP + + l->lv_idx = l->lv_len - l->lv_idx - 1; +} + //{{{2 Indexing/searching /// Locate item with a given index in a list and return it @@ -662,13 +750,8 @@ listitem_T *tv_list_find(list_T *const l, int n) return NULL; } - // Negative index is relative to the end. - if (n < 0) { - n = l->lv_len + n; - } - - // Check for index out of range. - if (n < 0 || n >= l->lv_len) { + n = tv_list_uidx(l, n); + if (n == -1) { return NULL; } @@ -740,7 +823,7 @@ varnumber_T tv_list_find_nr(list_T *const l, const int n, bool *const ret_error) } return -1; } - return tv_get_number_chk(&li->li_tv, ret_error); + return tv_get_number_chk(TV_LIST_ITEM_TV(li), ret_error); } /// Get list item l[n] as a string @@ -757,7 +840,7 @@ const char *tv_list_find_str(list_T *const l, const int n) emsgf(_(e_listidx), (int64_t)n); return NULL; } - return tv_get_string(&li->li_tv); + return tv_get_string(TV_LIST_ITEM_TV(li)); } /// Locate item in a list and return its index @@ -772,15 +855,14 @@ long tv_list_idx_of_item(const list_T *const l, const listitem_T *const item) if (l == NULL) { return -1; } - long idx = 0; - const listitem_T *li; - for (li = l->lv_first; li != NULL && li != item; li = li->li_next) { + int idx = 0; + TV_LIST_ITER_CONST(l, li, { + if (li == item) { + return idx; + } idx++; - } - if (li == NULL) { - return -1; - } - return idx; + }); + return -1; } //{{{1 Dictionaries @@ -1339,7 +1421,7 @@ int tv_dict_add_list(dict_T *const d, const char *const key, item->di_tv.v_lock = VAR_UNLOCKED; item->di_tv.v_type = VAR_LIST; item->di_tv.vval.v_list = list; - list->lv_refcount++; + tv_list_ref(list); if (tv_dict_add(d, item) == FAIL) { tv_dict_item_free(item); return FAIL; @@ -1677,7 +1759,7 @@ list_T *tv_list_alloc_ret(typval_T *const ret_tv) ret_tv->vval.v_list = l; ret_tv->v_type = VAR_LIST; ret_tv->v_lock = VAR_UNLOCKED; - l->lv_refcount++; + tv_list_ref(l); return l; } @@ -2027,7 +2109,7 @@ void tv_copy(typval_T *const from, typval_T *const to) } case VAR_LIST: { if (from->vval.v_list != NULL) { - to->vval.v_list->lv_refcount++; + tv_list_ref(to->vval.v_list); } break; } @@ -2084,9 +2166,9 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock) CHANGE_LOCK(lock, l->lv_lock); if (deep < 0 || deep > 1) { // Recursive: lock/unlock the items the List contains. - for (listitem_T *li = l->lv_first; li != NULL; li = li->li_next) { - tv_item_lock(&li->li_tv, deep - 1, lock); - } + TV_LIST_ITER(l, li, { + tv_item_lock(TV_LIST_ITEM_TV(li), deep - 1, lock); + }); } } break; @@ -2122,6 +2204,8 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock) /// Check whether VimL value is locked itself or refers to a locked container /// +/// @warning Fixed container is not the same as locked. +/// /// @param[in] tv Value to check. /// /// @return True if value is locked, false otherwise. @@ -2130,8 +2214,7 @@ bool tv_islocked(const typval_T *const tv) { return ((tv->v_lock == VAR_LOCKED) || (tv->v_type == VAR_LIST - && tv->vval.v_list != NULL - && (tv->vval.v_list->lv_lock == VAR_LOCKED)) + && (tv_list_locked(tv->vval.v_list) == VAR_LOCKED)) || (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL && (tv->vval.v_dict->dv_lock == VAR_LOCKED))); diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index c44b85644d..c0d1790c63 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -6,6 +6,8 @@ #include <stdint.h> #include <string.h> #include <stdbool.h> +#include <assert.h> +#include <limits.h> #include "nvim/types.h" #include "nvim/hashtab.h" @@ -26,6 +28,9 @@ typedef uint64_t uvarnumber_T; /// Type used for VimL VAR_FLOAT values typedef double float_T; +/// Refcount for dict or list that should not be freed +enum { DO_NOT_FREE_CNT = (INT_MAX / 2) }; + /// Maximal possible value of varnumber_T variable #define VARNUMBER_MAX INT64_MAX #define UVARNUMBER_MAX UINT64_MAX @@ -150,12 +155,26 @@ struct listvar_S { list_T *lv_used_prev; ///< Previous list in used lists list. }; -// Static list with 10 items. Use init_static_list() to initialize. +// Static list with 10 items. Use tv_list_init_static10() to initialize. typedef struct { list_T sl_list; // must be first listitem_T sl_items[10]; } staticList10_T; +#define TV_LIST_STATIC10_INIT { \ + .sl_list = { \ + .lv_first = NULL, \ + .lv_last = NULL, \ + .lv_refcount = 0, \ + .lv_len = 0, \ + .lv_watch = NULL, \ + .lv_idx_item = NULL, \ + .lv_lock = VAR_FIXED, \ + .lv_used_next = NULL, \ + .lv_used_prev = NULL, \ + }, \ + } + // Structure to hold an item of a Dictionary. // Also used for a variable. // The key is copied into "di_key" to avoid an extra alloc/free for it. @@ -284,13 +303,71 @@ typedef struct list_stack_S { #define TV_DICT_HI2DI(hi) \ ((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key))) -static inline long tv_list_len(const list_T *const l) +/// Increase reference count for a given list +/// +/// Does nothing for NULL lists. +/// +/// @param[in] l List to modify. +static inline void tv_list_ref(list_T *const l) +{ + if (l == NULL) { + return; + } + l->lv_refcount++; +} + +static inline VarLockStatus tv_list_locked(const list_T *const l) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; + +/// Get list lock status +/// +/// Returns VAR_FIXED for NULL lists. +/// +/// @param[in] l List to check. +static inline VarLockStatus tv_list_locked(const list_T *const l) +{ + if (l == NULL) { + return VAR_FIXED; + } + return l->lv_lock; +} + +/// Set list lock status +/// +/// May only “set” VAR_FIXED for NULL lists. +/// +/// @param[out] l List to modify. +/// @param[in] lock New lock status. +static inline void tv_list_set_lock(list_T *const l, + const VarLockStatus lock) +{ + if (l == NULL) { + assert(lock == VAR_FIXED); + return; + } + l->lv_lock = lock; +} + +/// Set list copyID +/// +/// Does not expect NULL list, be careful. +/// +/// @param[out] l List to modify. +/// @param[in] copyid New copyID. +static inline void tv_list_set_copyid(list_T *const l, + const int copyid) + FUNC_ATTR_NONNULL_ALL +{ + l->lv_copyID = copyid; +} + +static inline int tv_list_len(const list_T *const l) REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; /// Get the number of items in a list /// /// @param[in] l List to check. -static inline long tv_list_len(const list_T *const l) +static inline int tv_list_len(const list_T *const l) { if (l == NULL) { return 0; @@ -298,6 +375,103 @@ static inline long tv_list_len(const list_T *const l) return l->lv_len; } +static inline int tv_list_copyid(const list_T *const l) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; + +/// Get list copyID +/// +/// Does not expect NULL list, be careful. +/// +/// @param[in] l List to check. +static inline int tv_list_copyid(const list_T *const l) +{ + return l->lv_copyID; +} + +static inline list_T *tv_list_latest_copy(const list_T *const l) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; + +/// Get latest list copy +/// +/// Gets lv_copylist field assigned by tv_list_copy() earlier. +/// +/// Does not expect NULL list, be careful. +/// +/// @param[in] l List to check. +static inline list_T *tv_list_latest_copy(const list_T *const l) +{ + return l->lv_copylist; +} + +/// Clear the list without freeing anything at all +/// +/// For use in sort() which saves items to a separate array and readds them back +/// after sorting via a number of tv_list_append() calls. +/// +/// @param[out] l List to clear. +static inline void tv_list_clear(list_T *const l) +{ + l->lv_first = NULL; + l->lv_last = NULL; + l->lv_idx_item = NULL; + l->lv_len = 0; +} + +static inline int tv_list_uidx(const list_T *const l, int n) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; + +/// Normalize index: that is, return either -1 or non-negative index +/// +/// @param[in] l List to index. Used to get length. +/// @param[in] n List index, possibly negative. +/// +/// @return -1 or list index in range [0, tv_list_len(l)). +static inline int tv_list_uidx(const list_T *const l, int n) +{ + // Negative index is relative to the end. + if (n < 0) { + n += tv_list_len(l); + } + + // Check for index out of range. + if (n < 0 || n >= tv_list_len(l)) { + return -1; + } + return n; +} + +static inline listitem_T *tv_list_first(const list_T *const l) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; + +/// Get first list item +/// +/// @param[in] l List to get item from. +/// +/// @return List item or NULL in case of an empty list. +static inline listitem_T *tv_list_first(const list_T *const l) +{ + if (l == NULL) { + return NULL; + } + return l->lv_first; +} + +static inline listitem_T *tv_list_last(const list_T *const l) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; + +/// Get last list item +/// +/// @param[in] l List to get item from. +/// +/// @return List item or NULL in case of an empty list. +static inline listitem_T *tv_list_last(const list_T *const l) +{ + if (l == NULL) { + return NULL; + } + return l->lv_last; +} + static inline long tv_dict_len(const dict_T *const d) REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; @@ -352,6 +526,75 @@ extern const char *const tv_empty_string; /// Specifies that free_unref_items() function has (not) been entered extern bool tv_in_free_unref_items; +/// Iterate over a list +/// +/// @param modifier Modifier: expected to be const or nothing, volatile should +/// also work if you have any uses for the volatile list. +/// @param[in] l List to iterate over. +/// @param li Name of the variable with current listitem_T entry. +/// @param code Cycle body. +#define _TV_LIST_ITER_MOD(modifier, l, li, code) \ + do { \ + modifier list_T *const l_ = (l); \ + if (l_ != NULL) { \ + for (modifier listitem_T *li = l_->lv_first; \ + li != NULL; li = li->li_next) { \ + code \ + } \ + } \ + } while (0) + +/// Iterate over a list +/// +/// To be used when you need to modify list or values you iterate over, use +/// #TV_LIST_ITER_CONST if you don’t. +/// +/// @param[in] l List to iterate over. +/// @param li Name of the variable with current listitem_T entry. +/// @param code Cycle body. +#define TV_LIST_ITER(l, li, code) \ + _TV_LIST_ITER_MOD(, l, li, code) + +/// Iterate over a list +/// +/// To be used when you don’t need to modify list or values you iterate over, +/// use #TV_LIST_ITER if you do. +/// +/// @param[in] l List to iterate over. +/// @param li Name of the variable with current listitem_T entry. +/// @param code Cycle body. +#define TV_LIST_ITER_CONST(l, li, code) \ + _TV_LIST_ITER_MOD(const, l, li, code) + +// Below macros are macros to avoid duplicating code for functionally identical +// const and non-const function variants. + +/// Get typval_T out of list item +/// +/// @param[in] li List item to get typval_T from, must not be NULL. +/// +/// @return Pointer to typval_T. +#define TV_LIST_ITEM_TV(li) (&(li)->li_tv) + +/// Get next list item given the current one +/// +/// @param[in] l List to get item from. +/// @param[in] li List item to get typval_T from. +/// +/// @return Pointer to the next item or NULL. +#define TV_LIST_ITEM_NEXT(l, li) ((li)->li_next) + +/// Get previous list item given the current one +/// +/// @param[in] l List to get item from. +/// @param[in] li List item to get typval_T from. +/// +/// @return Pointer to the previous item or NULL. +#define TV_LIST_ITEM_PREV(l, li) ((li)->li_prev) +// List argument is not used currently, but it is a must for lists implemented +// as a pair (size(in list), array) without terminator - basically for lists on +// top of kvec. + /// Iterate over a dictionary /// /// @param[in] d Dictionary to iterate over. diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index a93ad2dbba..e9531178ef 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -355,14 +355,14 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( break; } case VAR_LIST: { - if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) { + if (tv->vval.v_list == NULL || tv_list_len(tv->vval.v_list) == 0) { TYPVAL_ENCODE_CONV_EMPTY_LIST(tv); break; } - const int saved_copyID = tv->vval.v_list->lv_copyID; + const int saved_copyID = tv_list_copyid(tv->vval.v_list); _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, copyID, kMPConvList); - TYPVAL_ENCODE_CONV_LIST_START(tv, tv->vval.v_list->lv_len); + TYPVAL_ENCODE_CONV_LIST_START(tv, tv_list_len(tv->vval.v_list)); assert(saved_copyID != copyID && saved_copyID != copyID - 1); _mp_push(*mpstack, ((MPConvStackVal) { .type = kMPConvList, @@ -371,7 +371,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( .data = { .l = { .list = tv->vval.v_list, - .li = tv->vval.v_list->lv_first, + .li = tv_list_first(tv->vval.v_list), }, }, })); @@ -440,23 +440,43 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( // bits is not checked), other unsigned and have at most 31 // non-zero bits (number of bits is not checked). if (val_di->di_tv.v_type != VAR_LIST - || (val_list = val_di->di_tv.vval.v_list) == NULL - || val_list->lv_len != 4 - || val_list->lv_first->li_tv.v_type != VAR_NUMBER - || (sign = val_list->lv_first->li_tv.vval.v_number) == 0 - || val_list->lv_first->li_next->li_tv.v_type != VAR_NUMBER - || (highest_bits = - val_list->lv_first->li_next->li_tv.vval.v_number) < 0 - || val_list->lv_last->li_prev->li_tv.v_type != VAR_NUMBER - || (high_bits = - val_list->lv_last->li_prev->li_tv.vval.v_number) < 0 - || val_list->lv_last->li_tv.v_type != VAR_NUMBER - || (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) { + || tv_list_len(val_list = val_di->di_tv.vval.v_list) != 4) { goto _convert_one_value_regular_dict; } - uint64_t number = ((uint64_t)(((uint64_t)highest_bits) << 62) - | (uint64_t)(((uint64_t)high_bits) << 31) - | (uint64_t)low_bits); + + const listitem_T *const sign_li = tv_list_first(val_list); + if (TV_LIST_ITEM_TV(sign_li)->v_type != VAR_NUMBER + || (sign = TV_LIST_ITEM_TV(sign_li)->vval.v_number) == 0) { + goto _convert_one_value_regular_dict; + } + + const listitem_T *const highest_bits_li = ( + TV_LIST_ITEM_NEXT(val_list, sign_li)); + if (TV_LIST_ITEM_TV(highest_bits_li)->v_type != VAR_NUMBER + || ((highest_bits + = TV_LIST_ITEM_TV(highest_bits_li)->vval.v_number) + < 0)) { + goto _convert_one_value_regular_dict; + } + + const listitem_T *const high_bits_li = ( + TV_LIST_ITEM_NEXT(val_list, highest_bits_li)); + if (TV_LIST_ITEM_TV(high_bits_li)->v_type != VAR_NUMBER + || ((high_bits = TV_LIST_ITEM_TV(high_bits_li)->vval.v_number) + < 0)) { + goto _convert_one_value_regular_dict; + } + + const listitem_T *const low_bits_li = tv_list_last(val_list); + if (TV_LIST_ITEM_TV(low_bits_li)->v_type != VAR_NUMBER + || ((low_bits = TV_LIST_ITEM_TV(low_bits_li)->vval.v_number) + < 0)) { + goto _convert_one_value_regular_dict; + } + + const uint64_t number = ((uint64_t)(((uint64_t)highest_bits) << 62) + | (uint64_t)(((uint64_t)high_bits) << 31) + | (uint64_t)low_bits); if (sign > 0) { TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, number); } else { @@ -495,12 +515,12 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( if (val_di->di_tv.v_type != VAR_LIST) { goto _convert_one_value_regular_dict; } - const int saved_copyID = val_di->di_tv.vval.v_list->lv_copyID; + const int saved_copyID = tv_list_copyid(val_di->di_tv.vval.v_list); _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, lv_copyID, copyID, kMPConvList); - TYPVAL_ENCODE_CONV_LIST_START(tv, - val_di->di_tv.vval.v_list->lv_len); + TYPVAL_ENCODE_CONV_LIST_START( + tv, tv_list_len(val_di->di_tv.vval.v_list)); assert(saved_copyID != copyID && saved_copyID != copyID - 1); _mp_push(*mpstack, ((MPConvStackVal) { .tv = tv, @@ -509,7 +529,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( .data = { .l = { .list = val_di->di_tv.vval.v_list, - .li = val_di->di_tv.vval.v_list->lv_first, + .li = tv_list_first(val_di->di_tv.vval.v_list), }, }, })); @@ -520,22 +540,21 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( goto _convert_one_value_regular_dict; } list_T *const val_list = val_di->di_tv.vval.v_list; - if (val_list == NULL || val_list->lv_len == 0) { + if (val_list == NULL || tv_list_len(val_list) == 0) { TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, TYPVAL_ENCODE_NODICT_VAR); break; } - for (const listitem_T *li = val_list->lv_first; li != NULL; - li = li->li_next) { - if (li->li_tv.v_type != VAR_LIST - || li->li_tv.vval.v_list->lv_len != 2) { + TV_LIST_ITER_CONST(val_list, li, { + if (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST + || tv_list_len(TV_LIST_ITEM_TV(li)->vval.v_list) != 2) { goto _convert_one_value_regular_dict; } - } - const int saved_copyID = val_di->di_tv.vval.v_list->lv_copyID; + }); + const int saved_copyID = tv_list_copyid(val_di->di_tv.vval.v_list); _TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val_list, lv_copyID, copyID, kMPConvPairs); TYPVAL_ENCODE_CONV_DICT_START(tv, TYPVAL_ENCODE_NODICT_VAR, - val_list->lv_len); + tv_list_len(val_list)); assert(saved_copyID != copyID && saved_copyID != copyID - 1); _mp_push(*mpstack, ((MPConvStackVal) { .tv = tv, @@ -544,7 +563,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( .data = { .l = { .list = val_list, - .li = val_list->lv_first, + .li = tv_list_first(val_list), }, }, })); @@ -554,18 +573,23 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE( const list_T *val_list; varnumber_T type; if (val_di->di_tv.v_type != VAR_LIST - || (val_list = val_di->di_tv.vval.v_list) == NULL - || val_list->lv_len != 2 - || (val_list->lv_first->li_tv.v_type != VAR_NUMBER) - || (type = val_list->lv_first->li_tv.vval.v_number) > INT8_MAX + || tv_list_len((val_list = val_di->di_tv.vval.v_list)) != 2 + || (TV_LIST_ITEM_TV(tv_list_first(val_list))->v_type + != VAR_NUMBER) + || ((type + = TV_LIST_ITEM_TV(tv_list_first(val_list))->vval.v_number) + > INT8_MAX) || type < INT8_MIN - || (val_list->lv_last->li_tv.v_type != VAR_LIST)) { + || (TV_LIST_ITEM_TV(tv_list_last(val_list))->v_type + != VAR_LIST)) { goto _convert_one_value_regular_dict; } size_t len; char *buf; - if (!encode_vim_list_to_buf(val_list->lv_last->li_tv.vval.v_list, - &len, &buf)) { + if (!( + encode_vim_list_to_buf( + TV_LIST_ITEM_TV(tv_list_last(val_list))->vval.v_list, &len, + &buf))) { goto _convert_one_value_regular_dict; } TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type); @@ -671,40 +695,45 @@ typval_encode_stop_converting_one_item: case kMPConvList: { if (cur_mpsv->data.l.li == NULL) { (void)_mp_pop(mpstack); - cur_mpsv->data.l.list->lv_copyID = cur_mpsv->saved_copyID; + tv_list_set_copyid(cur_mpsv->data.l.list, cur_mpsv->saved_copyID); TYPVAL_ENCODE_CONV_LIST_END(cur_mpsv->tv); continue; - } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { + } else if (cur_mpsv->data.l.li + != tv_list_first(cur_mpsv->data.l.list)) { TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(cur_mpsv->tv); } - tv = &cur_mpsv->data.l.li->li_tv; - cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; + tv = TV_LIST_ITEM_TV(cur_mpsv->data.l.li); + cur_mpsv->data.l.li = TV_LIST_ITEM_NEXT(cur_mpsv->data.l.list, + cur_mpsv->data.l.li); break; } case kMPConvPairs: { if (cur_mpsv->data.l.li == NULL) { (void)_mp_pop(mpstack); - cur_mpsv->data.l.list->lv_copyID = cur_mpsv->saved_copyID; + tv_list_set_copyid(cur_mpsv->data.l.list, cur_mpsv->saved_copyID); TYPVAL_ENCODE_CONV_DICT_END(cur_mpsv->tv, TYPVAL_ENCODE_NODICT_VAR); continue; - } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { + } else if (cur_mpsv->data.l.li + != tv_list_first(cur_mpsv->data.l.list)) { TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS( cur_mpsv->tv, TYPVAL_ENCODE_NODICT_VAR); } - const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list; + const list_T *const kv_pair = ( + TV_LIST_ITEM_TV(cur_mpsv->data.l.li)->vval.v_list); TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK( - encode_vim_to__error_ret, kv_pair->lv_first->li_tv); - if (_TYPVAL_ENCODE_CONVERT_ONE_VALUE(TYPVAL_ENCODE_FIRST_ARG_NAME, - &mpstack, cur_mpsv, - &kv_pair->lv_first->li_tv, - copyID, - objname) == FAIL) { + encode_vim_to__error_ret, *TV_LIST_ITEM_TV(tv_list_first(kv_pair))); + if ( + _TYPVAL_ENCODE_CONVERT_ONE_VALUE( + TYPVAL_ENCODE_FIRST_ARG_NAME, &mpstack, cur_mpsv, + TV_LIST_ITEM_TV(tv_list_first(kv_pair)), copyID, objname) + == FAIL) { goto encode_vim_to__error_ret; } TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(cur_mpsv->tv, TYPVAL_ENCODE_NODICT_VAR); - tv = &kv_pair->lv_last->li_tv; - cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; + tv = TV_LIST_ITEM_TV(tv_list_last(kv_pair)); + cur_mpsv->data.l.li = TV_LIST_ITEM_NEXT(cur_mpsv->data.l.list, + cur_mpsv->data.l.li); break; } case kMPConvPartial: { |