diff options
-rw-r--r-- | src/nvim/eval/typval_encode.h | 34 | ||||
-rw-r--r-- | src/nvim/lib/kvec.h | 94 |
2 files changed, 115 insertions, 13 deletions
diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h index 93342e0764..7659a01194 100644 --- a/src/nvim/eval/typval_encode.h +++ b/src/nvim/eval/typval_encode.h @@ -168,7 +168,15 @@ typedef struct { } MPConvStackVal; /// Stack used to convert VimL values to messagepack. -typedef kvec_t(MPConvStackVal) MPConvStack; +typedef kvec_withinit_t(MPConvStackVal, 8) MPConvStack; + +// Defines for MPConvStack +#define _mp_size kv_size +#define _mp_init kvi_init +#define _mp_destroy kvi_destroy +#define _mp_push kvi_push +#define _mp_pop kv_pop +#define _mp_last kv_last /// Code for checking whether container references itself /// @@ -245,7 +253,7 @@ static int name##_convert_one_value(firstargtype firstargname, \ _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, \ kMPConvList); \ TYPVAL_ENCODE_CONV_LIST_START(tv->vval.v_list->lv_len); \ - kv_push(*mpstack, ((MPConvStackVal) { \ + _mp_push(*mpstack, ((MPConvStackVal) { \ .type = kMPConvList, \ .data = { \ .l = { \ @@ -376,7 +384,7 @@ static int name##_convert_one_value(firstargtype firstargname, \ _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, \ lv_copyID, kMPConvList); \ TYPVAL_ENCODE_CONV_LIST_START(val_di->di_tv.vval.v_list->lv_len); \ - kv_push(*mpstack, ((MPConvStackVal) { \ + _mp_push(*mpstack, ((MPConvStackVal) { \ .type = kMPConvList, \ .data = { \ .l = { \ @@ -406,7 +414,7 @@ static int name##_convert_one_value(firstargtype firstargname, \ _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_list, lv_copyID, \ kMPConvPairs); \ TYPVAL_ENCODE_CONV_DICT_START(val_list->lv_len); \ - kv_push(*mpstack, ((MPConvStackVal) { \ + _mp_push(*mpstack, ((MPConvStackVal) { \ .type = kMPConvPairs, \ .data = { \ .l = { \ @@ -446,7 +454,7 @@ name##_convert_one_value_regular_dict: \ _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, \ kMPConvDict); \ TYPVAL_ENCODE_CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \ - kv_push(*mpstack, ((MPConvStackVal) { \ + _mp_push(*mpstack, ((MPConvStackVal) { \ .type = kMPConvDict, \ .data = { \ .d = { \ @@ -472,18 +480,18 @@ scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \ { \ const int copyID = get_copyID(); \ MPConvStack mpstack; \ - kv_init(mpstack); \ + _mp_init(mpstack); \ if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \ == FAIL) { \ goto encode_vim_to_##name##_error_ret; \ } \ - while (kv_size(mpstack)) { \ - MPConvStackVal *cur_mpsv = &kv_A(mpstack, kv_size(mpstack) - 1); \ + while (_mp_size(mpstack)) { \ + MPConvStackVal *cur_mpsv = &_mp_last(mpstack); \ typval_T *cur_tv = NULL; \ switch (cur_mpsv->type) { \ case kMPConvDict: { \ if (!cur_mpsv->data.d.todo) { \ - (void) kv_pop(mpstack); \ + (void) _mp_pop(mpstack); \ cur_mpsv->data.d.dict->dv_copyID = copyID - 1; \ TYPVAL_ENCODE_CONV_DICT_END(); \ continue; \ @@ -505,7 +513,7 @@ scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \ } \ case kMPConvList: { \ if (cur_mpsv->data.l.li == NULL) { \ - (void) kv_pop(mpstack); \ + (void) _mp_pop(mpstack); \ cur_mpsv->data.l.list->lv_copyID = copyID - 1; \ TYPVAL_ENCODE_CONV_LIST_END(); \ continue; \ @@ -518,7 +526,7 @@ scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \ } \ case kMPConvPairs: { \ if (cur_mpsv->data.l.li == NULL) { \ - (void) kv_pop(mpstack); \ + (void) _mp_pop(mpstack); \ cur_mpsv->data.l.list->lv_copyID = copyID - 1; \ TYPVAL_ENCODE_CONV_DICT_END(); \ continue; \ @@ -545,10 +553,10 @@ scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \ goto encode_vim_to_##name##_error_ret; \ } \ } \ - kv_destroy(mpstack); \ + _mp_destroy(mpstack); \ return OK; \ encode_vim_to_##name##_error_ret: \ - kv_destroy(mpstack); \ + _mp_destroy(mpstack); \ return FAIL; \ } diff --git a/src/nvim/lib/kvec.h b/src/nvim/lib/kvec.h index dcc69f7b26..36c91c86b2 100644 --- a/src/nvim/lib/kvec.h +++ b/src/nvim/lib/kvec.h @@ -38,6 +38,7 @@ #define NVIM_LIB_KVEC_H #include <stdlib.h> +#include <string.h> #include "nvim/memory.h" @@ -96,4 +97,97 @@ : 0)), \ (v).items[(i)]) +/// Type of a vector with a few first members allocated on stack +/// +/// Is compatible with #kv_A, #kv_pop, #kv_size, #kv_max, #kv_last. +/// Is not compatible with #kv_resize, #kv_resize_full, #kv_copy, #kv_push, +/// #kv_pushp, #kv_a, #kv_destroy. +/// +/// @param[in] type Type of vector elements. +/// @param[in] init_size Number of the elements in the initial array. +#define kvec_withinit_t(type, INIT_SIZE) \ + struct { \ + size_t size; \ + size_t capacity; \ + type *items; \ + type init_array[INIT_SIZE]; \ + } + +/// Initialize vector with preallocated array +/// +/// @param[out] v Vector to initialize. +#define kvi_init(v) \ + ((v).capacity = ARRAY_SIZE((v).init_array), \ + (v).size = 0, \ + (v).items = (v).init_array) + +/// Move data to a new destination and free source +static inline void *_memcpy_free(void *const restrict dest, + void *const restrict src, + const size_t size) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_ALWAYS_INLINE +{ + memcpy(dest, src, size); + xfree(src); + return dest; +} + +/// Resize vector with preallocated array +/// +/// @param[out] v Vector to resize. +/// @param[in] s New size. +#define kvi_resize(v, s) \ + ((v).capacity = ((s) > ARRAY_SIZE((v).init_array) \ + ? (s) \ + : ARRAY_SIZE((v).init_array)), \ + (v).items = ((v).capacity == ARRAY_SIZE((v).init_array) \ + ? ((v).items == (v).init_array \ + ? (v).items \ + : _memcpy_free((v).init_array, (v).items, \ + (v).size * sizeof((v).items[0]))) \ + : ((v).items == (v).init_array \ + ? memcpy(xmalloc((v).capacity * sizeof((v).items[0])), \ + (v).items, \ + (v).size * sizeof((v).items[0])) \ + : xrealloc((v).items, \ + (v).capacity * sizeof((v).items[0]))))) + +/// Resize vector with preallocated array when it is full +/// +/// @param[out] v Vector to resize. +#define kvi_resize_full(v) \ + /* ARRAY_SIZE((v).init_array) is the minimal capacity of this vector. */ \ + /* Thus when vector is full capacity may not be zero and it is safe */ \ + /* not to bother with checking whether (v).capacity is 0. But now */ \ + /* capacity is not guaranteed to have size that is a power of 2. */ \ + kvi_resize(v, ((v).capacity == ARRAY_SIZE((v).init_array) \ + ? ((v).capacity++, kv_roundup32((v).capacity)) \ + : (v).capacity << 1)) + +/// Get location where to store new element to a vector with preallocated array +/// +/// @param[in,out] v Vector to push to. +/// +/// @return Pointer to the place where new value should be stored. +#define kvi_pushp(v) \ + ((((v).size == (v).capacity) ? (kvi_resize_full(v), 0) : 0), \ + ((v).items + ((v).size++))) + +/// Push value to a vector with preallocated array +/// +/// @param[out] v Vector to push to. +/// @param[in] x Value to push. +#define kvi_push(v, x) \ + (*kvi_pushp(v) = (x)) + +/// Free array of elements of a vector with preallocated array if needed +/// +/// @param[out] v Vector to free. +#define kvi_destroy(v) \ + do { \ + if ((v).items != (v).init_array) { \ + xfree((v).items); \ + } \ + } while (0) + #endif // NVIM_LIB_KVEC_H |