aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval')
-rw-r--r--src/nvim/eval/decode.c46
-rw-r--r--src/nvim/eval/encode.c82
-rw-r--r--src/nvim/eval/encode.h13
-rw-r--r--src/nvim/eval/typval.c221
-rw-r--r--src/nvim/eval/typval.h249
-rw-r--r--src/nvim/eval/typval_encode.c.h137
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: {