mirror of
https://github.com/neovim/neovim.git
synced 2025-10-02 16:08:36 +00:00
kvec,typval_encode: Add new vector: the one with preallocated array
This commit is contained in:
@@ -168,7 +168,15 @@ typedef struct {
|
|||||||
} MPConvStackVal;
|
} MPConvStackVal;
|
||||||
|
|
||||||
/// Stack used to convert VimL values to messagepack.
|
/// 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
|
/// 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, \
|
_TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, \
|
||||||
kMPConvList); \
|
kMPConvList); \
|
||||||
TYPVAL_ENCODE_CONV_LIST_START(tv->vval.v_list->lv_len); \
|
TYPVAL_ENCODE_CONV_LIST_START(tv->vval.v_list->lv_len); \
|
||||||
kv_push(*mpstack, ((MPConvStackVal) { \
|
_mp_push(*mpstack, ((MPConvStackVal) { \
|
||||||
.type = kMPConvList, \
|
.type = kMPConvList, \
|
||||||
.data = { \
|
.data = { \
|
||||||
.l = { \
|
.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, \
|
_TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, \
|
||||||
lv_copyID, kMPConvList); \
|
lv_copyID, kMPConvList); \
|
||||||
TYPVAL_ENCODE_CONV_LIST_START(val_di->di_tv.vval.v_list->lv_len); \
|
TYPVAL_ENCODE_CONV_LIST_START(val_di->di_tv.vval.v_list->lv_len); \
|
||||||
kv_push(*mpstack, ((MPConvStackVal) { \
|
_mp_push(*mpstack, ((MPConvStackVal) { \
|
||||||
.type = kMPConvList, \
|
.type = kMPConvList, \
|
||||||
.data = { \
|
.data = { \
|
||||||
.l = { \
|
.l = { \
|
||||||
@@ -406,7 +414,7 @@ static int name##_convert_one_value(firstargtype firstargname, \
|
|||||||
_TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_list, lv_copyID, \
|
_TYPVAL_ENCODE_CHECK_SELF_REFERENCE(val_list, lv_copyID, \
|
||||||
kMPConvPairs); \
|
kMPConvPairs); \
|
||||||
TYPVAL_ENCODE_CONV_DICT_START(val_list->lv_len); \
|
TYPVAL_ENCODE_CONV_DICT_START(val_list->lv_len); \
|
||||||
kv_push(*mpstack, ((MPConvStackVal) { \
|
_mp_push(*mpstack, ((MPConvStackVal) { \
|
||||||
.type = kMPConvPairs, \
|
.type = kMPConvPairs, \
|
||||||
.data = { \
|
.data = { \
|
||||||
.l = { \
|
.l = { \
|
||||||
@@ -446,7 +454,7 @@ name##_convert_one_value_regular_dict: \
|
|||||||
_TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, \
|
_TYPVAL_ENCODE_CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, \
|
||||||
kMPConvDict); \
|
kMPConvDict); \
|
||||||
TYPVAL_ENCODE_CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \
|
TYPVAL_ENCODE_CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \
|
||||||
kv_push(*mpstack, ((MPConvStackVal) { \
|
_mp_push(*mpstack, ((MPConvStackVal) { \
|
||||||
.type = kMPConvDict, \
|
.type = kMPConvDict, \
|
||||||
.data = { \
|
.data = { \
|
||||||
.d = { \
|
.d = { \
|
||||||
@@ -472,18 +480,18 @@ scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \
|
|||||||
{ \
|
{ \
|
||||||
const int copyID = get_copyID(); \
|
const int copyID = get_copyID(); \
|
||||||
MPConvStack mpstack; \
|
MPConvStack mpstack; \
|
||||||
kv_init(mpstack); \
|
_mp_init(mpstack); \
|
||||||
if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \
|
if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \
|
||||||
== FAIL) { \
|
== FAIL) { \
|
||||||
goto encode_vim_to_##name##_error_ret; \
|
goto encode_vim_to_##name##_error_ret; \
|
||||||
} \
|
} \
|
||||||
while (kv_size(mpstack)) { \
|
while (_mp_size(mpstack)) { \
|
||||||
MPConvStackVal *cur_mpsv = &kv_A(mpstack, kv_size(mpstack) - 1); \
|
MPConvStackVal *cur_mpsv = &_mp_last(mpstack); \
|
||||||
typval_T *cur_tv = NULL; \
|
typval_T *cur_tv = NULL; \
|
||||||
switch (cur_mpsv->type) { \
|
switch (cur_mpsv->type) { \
|
||||||
case kMPConvDict: { \
|
case kMPConvDict: { \
|
||||||
if (!cur_mpsv->data.d.todo) { \
|
if (!cur_mpsv->data.d.todo) { \
|
||||||
(void) kv_pop(mpstack); \
|
(void) _mp_pop(mpstack); \
|
||||||
cur_mpsv->data.d.dict->dv_copyID = copyID - 1; \
|
cur_mpsv->data.d.dict->dv_copyID = copyID - 1; \
|
||||||
TYPVAL_ENCODE_CONV_DICT_END(); \
|
TYPVAL_ENCODE_CONV_DICT_END(); \
|
||||||
continue; \
|
continue; \
|
||||||
@@ -505,7 +513,7 @@ scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \
|
|||||||
} \
|
} \
|
||||||
case kMPConvList: { \
|
case kMPConvList: { \
|
||||||
if (cur_mpsv->data.l.li == NULL) { \
|
if (cur_mpsv->data.l.li == NULL) { \
|
||||||
(void) kv_pop(mpstack); \
|
(void) _mp_pop(mpstack); \
|
||||||
cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
|
cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
|
||||||
TYPVAL_ENCODE_CONV_LIST_END(); \
|
TYPVAL_ENCODE_CONV_LIST_END(); \
|
||||||
continue; \
|
continue; \
|
||||||
@@ -518,7 +526,7 @@ scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \
|
|||||||
} \
|
} \
|
||||||
case kMPConvPairs: { \
|
case kMPConvPairs: { \
|
||||||
if (cur_mpsv->data.l.li == NULL) { \
|
if (cur_mpsv->data.l.li == NULL) { \
|
||||||
(void) kv_pop(mpstack); \
|
(void) _mp_pop(mpstack); \
|
||||||
cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
|
cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
|
||||||
TYPVAL_ENCODE_CONV_DICT_END(); \
|
TYPVAL_ENCODE_CONV_DICT_END(); \
|
||||||
continue; \
|
continue; \
|
||||||
@@ -545,10 +553,10 @@ scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \
|
|||||||
goto encode_vim_to_##name##_error_ret; \
|
goto encode_vim_to_##name##_error_ret; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
kv_destroy(mpstack); \
|
_mp_destroy(mpstack); \
|
||||||
return OK; \
|
return OK; \
|
||||||
encode_vim_to_##name##_error_ret: \
|
encode_vim_to_##name##_error_ret: \
|
||||||
kv_destroy(mpstack); \
|
_mp_destroy(mpstack); \
|
||||||
return FAIL; \
|
return FAIL; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -38,6 +38,7 @@
|
|||||||
#define NVIM_LIB_KVEC_H
|
#define NVIM_LIB_KVEC_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
|
|
||||||
@@ -96,4 +97,97 @@
|
|||||||
: 0)), \
|
: 0)), \
|
||||||
(v).items[(i)])
|
(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
|
#endif // NVIM_LIB_KVEC_H
|
||||||
|
Reference in New Issue
Block a user