mirror of
https://github.com/neovim/neovim.git
synced 2025-10-06 09:56:31 +00:00
*: Move some dictionary functions to typval.h and use char*
Also fixes buffer reusage in setmatches() and complete().
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "nvim/hashtab.h"
|
||||
#include "nvim/garray.h"
|
||||
#include "nvim/mbyte.h"
|
||||
#include "nvim/func_attr.h"
|
||||
#include "nvim/lib/queue.h"
|
||||
#include "nvim/profile.h" // for proftime_T
|
||||
#include "nvim/pos.h" // for linenr_T
|
||||
@@ -31,6 +32,31 @@ typedef struct listvar_S list_T;
|
||||
typedef struct dictvar_S dict_T;
|
||||
typedef struct partial_S partial_T;
|
||||
|
||||
typedef struct ufunc ufunc_T;
|
||||
|
||||
typedef enum {
|
||||
kCallbackNone,
|
||||
kCallbackFuncref,
|
||||
kCallbackPartial,
|
||||
} CallbackType;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
char_u *funcref;
|
||||
partial_T *partial;
|
||||
} data;
|
||||
CallbackType type;
|
||||
} Callback;
|
||||
#define CALLBACK_NONE ((Callback){ .type = kCallbackNone })
|
||||
|
||||
/// Structure holding dictionary watcher
|
||||
typedef struct dict_watcher {
|
||||
Callback callback;
|
||||
char *key_pattern;
|
||||
QUEUE node;
|
||||
bool busy; // prevent recursion if the dict is changed in the callback
|
||||
} DictWatcher;
|
||||
|
||||
/// Special variable values
|
||||
typedef enum {
|
||||
kSpecialVarFalse, ///< v:false
|
||||
@@ -134,7 +160,7 @@ struct dictitem_S {
|
||||
struct { \
|
||||
typval_T di_tv; /* Structure that holds scope dictionary itself. */ \
|
||||
uint8_t di_flags; /* Flags. */ \
|
||||
char_u di_key[KEY_LEN]; /* NUL. */ \
|
||||
char_u di_key[KEY_LEN]; /* Key value. */ \
|
||||
}
|
||||
|
||||
/// Structure to hold a scope dictionary
|
||||
@@ -181,9 +207,7 @@ typedef int scid_T;
|
||||
// Structure to hold info for a function that is currently being executed.
|
||||
typedef struct funccall_S funccall_T;
|
||||
|
||||
// Structure to hold info for a user function.
|
||||
typedef struct ufunc ufunc_T;
|
||||
|
||||
/// Structure to hold info for a user function.
|
||||
struct ufunc {
|
||||
int uf_varargs; ///< variable nr of arguments
|
||||
int uf_flags;
|
||||
@@ -207,12 +231,12 @@ struct ufunc {
|
||||
int uf_tml_idx; ///< index of line being timed; -1 if none
|
||||
int uf_tml_execed; ///< line being timed was executed
|
||||
scid_T uf_script_ID; ///< ID of script where function was defined,
|
||||
// used for s: variables
|
||||
///< used for s: variables
|
||||
int uf_refcount; ///< reference count, see func_name_refcount()
|
||||
funccall_T *uf_scoped; ///< l: local variables for closure
|
||||
char_u uf_name[1]; ///< name of function (actually longer); can
|
||||
// start with <SNR>123_ (<SNR> is K_SPECIAL
|
||||
// KS_EXTRA KE_SNR)
|
||||
///< start with <SNR>123_ (<SNR> is K_SPECIAL
|
||||
///< KS_EXTRA KE_SNR)
|
||||
};
|
||||
|
||||
/// Maximum number of function arguments
|
||||
@@ -245,24 +269,17 @@ typedef struct list_stack_S {
|
||||
// In a hashtab item "hi_key" points to "di_key" in a dictitem.
|
||||
// This avoids adding a pointer to the hashtab item.
|
||||
|
||||
/// Convert a dictitem pointer to a hashitem key pointer
|
||||
#define DI2HIKEY(di) ((di)->di_key)
|
||||
|
||||
/// Convert a hashitem key pointer to a dictitem pointer
|
||||
#define HIKEY2DI(p) ((dictitem_T *)(p - offsetof(dictitem_T, di_key)))
|
||||
|
||||
/// Convert a hashitem value pointer to a dictitem pointer
|
||||
#define HIVAL2DI(p) \
|
||||
((dictitem_T *)(((char *)p) - offsetof(dictitem_T, di_tv)))
|
||||
|
||||
/// Convert a hashitem pointer to a dictitem pointer
|
||||
#define HI2DI(hi) HIKEY2DI((hi)->hi_key)
|
||||
#define TV_DICT_HI2DI(hi) \
|
||||
((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key)))
|
||||
|
||||
static inline long tv_list_len(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(list_T *const l)
|
||||
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
if (l == NULL) {
|
||||
return 0;
|
||||
@@ -270,6 +287,64 @@ static inline long tv_list_len(list_T *const l)
|
||||
return l->lv_len;
|
||||
}
|
||||
|
||||
static inline long tv_dict_len(const dict_T *const d)
|
||||
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/// Get the number of items in a Dictionary
|
||||
///
|
||||
/// @param[in] d Dictionary to check.
|
||||
static inline long tv_dict_len(const dict_T *const d)
|
||||
{
|
||||
if (d == NULL) {
|
||||
return 0L;
|
||||
}
|
||||
return (long)d->dv_hashtab.ht_used;
|
||||
}
|
||||
|
||||
static inline bool tv_dict_is_watched(const dict_T *const d)
|
||||
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/// Check if dictionary is watched
|
||||
///
|
||||
/// @param[in] d Dictionary to check.
|
||||
///
|
||||
/// @return true if there is at least one watcher.
|
||||
static inline bool tv_dict_is_watched(const dict_T *const d)
|
||||
{
|
||||
return d && !QUEUE_EMPTY(&d->watchers);
|
||||
}
|
||||
|
||||
static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
|
||||
REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET REAL_FATTR_PURE
|
||||
REAL_FATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/// Compute the `DictWatcher` address from a QUEUE node.
|
||||
///
|
||||
/// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer
|
||||
/// arithmetic).
|
||||
static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
|
||||
{
|
||||
return QUEUE_DATA(q, DictWatcher, node);
|
||||
}
|
||||
|
||||
/// Initialize VimL object
|
||||
///
|
||||
/// Initializes to unlocked VAR_UNKNOWN object.
|
||||
///
|
||||
/// @param[out] tv Object to initialize.
|
||||
static inline void tv_init(typval_T *const tv)
|
||||
{
|
||||
if (tv != NULL) {
|
||||
memset(tv, 0, sizeof(*tv));
|
||||
}
|
||||
}
|
||||
|
||||
#define TV_INITIAL_VALUE \
|
||||
((typval_T) { \
|
||||
.v_type = VAR_UNKNOWN, \
|
||||
.v_lock = VAR_UNLOCKED, \
|
||||
})
|
||||
|
||||
/// Empty string
|
||||
///
|
||||
/// Needed for hack which allows not allocating empty string and still not
|
||||
@@ -279,6 +354,21 @@ 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 dictionary
|
||||
///
|
||||
/// @param[in] d Dictionary to iterate over.
|
||||
/// @param di Name of the variable with current dictitem_T entry.
|
||||
/// @param code Cycle body.
|
||||
#define TV_DICT_ITER(d, di, code) \
|
||||
HASHTAB_ITER(&(d)->dv_hashtab, di##hi_, { \
|
||||
{ \
|
||||
dictitem_T *const di = TV_DICT_HI2DI(di##hi_); \
|
||||
{ \
|
||||
code \
|
||||
} \
|
||||
} \
|
||||
})
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "eval/typval.h.generated.h"
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user