typval.h (12154B)
1 #pragma once 2 3 #include <assert.h> 4 #include <stdbool.h> 5 #include <stddef.h> 6 #include <stdint.h> 7 #include <string.h> 8 9 #include "nvim/eval/typval_defs.h" // IWYU pragma: keep 10 #include "nvim/gettext_defs.h" 11 #include "nvim/hashtab.h" 12 #include "nvim/lib/queue_defs.h" 13 #include "nvim/macros_defs.h" 14 #include "nvim/mbyte_defs.h" // IWYU pragma: keep 15 #include "nvim/message.h" 16 #include "nvim/types_defs.h" 17 18 #include "eval/typval.h.inline.generated.h" 19 20 // In a hashtab item "hi_key" points to "di_key" in a dictitem. 21 // This avoids adding a pointer to the hashtab item. 22 23 /// Convert a hashitem pointer to a dictitem pointer 24 #define TV_DICT_HI2DI(hi) \ 25 ((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key))) 26 27 /// Increase reference count for a given list 28 /// 29 /// Does nothing for NULL lists. 30 /// 31 /// @param[in,out] l List to modify. 32 static inline void tv_list_ref(list_T *const l) 33 FUNC_ATTR_ALWAYS_INLINE 34 { 35 if (l == NULL) { 36 return; 37 } 38 l->lv_refcount++; 39 } 40 41 /// Set a list as the return value. Increments the reference count. 42 /// 43 /// @param[out] tv Object to receive the list 44 /// @param[in,out] l List to pass to the object 45 static inline void tv_list_set_ret(typval_T *const tv, list_T *const l) 46 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1) 47 { 48 tv->v_type = VAR_LIST; 49 tv->vval.v_list = l; 50 tv_list_ref(l); 51 } 52 53 /// Get list lock status 54 /// 55 /// Returns VAR_FIXED for NULL lists. 56 /// 57 /// @param[in] l List to check. 58 static inline VarLockStatus tv_list_locked(const list_T *const l) 59 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 60 { 61 if (l == NULL) { 62 return VAR_FIXED; 63 } 64 return l->lv_lock; 65 } 66 67 /// Set list lock status 68 /// 69 /// May only “set” VAR_FIXED for NULL lists. 70 /// 71 /// @param[out] l List to modify. 72 /// @param[in] lock New lock status. 73 static inline void tv_list_set_lock(list_T *const l, const VarLockStatus lock) 74 { 75 if (l == NULL) { 76 assert(lock == VAR_FIXED); 77 return; 78 } 79 l->lv_lock = lock; 80 } 81 82 /// Set list copyID 83 /// 84 /// Does not expect NULL list, be careful. 85 /// 86 /// @param[out] l List to modify. 87 /// @param[in] copyid New copyID. 88 static inline void tv_list_set_copyid(list_T *const l, const int copyid) 89 FUNC_ATTR_NONNULL_ALL 90 { 91 l->lv_copyID = copyid; 92 } 93 94 /// Get the number of items in a list 95 /// 96 /// @param[in] l List to check. 97 static inline int tv_list_len(const list_T *const l) 98 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 99 { 100 if (l == NULL) { 101 return 0; 102 } 103 return l->lv_len; 104 } 105 106 /// Get list copyID 107 /// 108 /// Does not expect NULL list, be careful. 109 /// 110 /// @param[in] l List to check. 111 static inline int tv_list_copyid(const list_T *const l) 112 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL 113 { 114 return l->lv_copyID; 115 } 116 117 /// Get latest list copy 118 /// 119 /// Gets lv_copylist field assigned by tv_list_copy() earlier. 120 /// 121 /// Does not expect NULL list, be careful. 122 /// 123 /// @param[in] l List to check. 124 static inline list_T *tv_list_latest_copy(const list_T *const l) 125 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL 126 { 127 return l->lv_copylist; 128 } 129 130 /// Normalize index: that is, return either -1 or non-negative index 131 /// 132 /// @param[in] l List to index. Used to get length. 133 /// @param[in] n List index, possibly negative. 134 /// 135 /// @return -1 or list index in range [0, tv_list_len(l)). 136 static inline int tv_list_uidx(const list_T *const l, int n) 137 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 138 { 139 // Negative index is relative to the end. 140 if (n < 0) { 141 n += tv_list_len(l); 142 } 143 144 // Check for index out of range. 145 if (n < 0 || n >= tv_list_len(l)) { 146 return -1; 147 } 148 return n; 149 } 150 151 /// Check whether list has watchers 152 /// 153 /// E.g. is referenced by a :for loop. 154 /// 155 /// @param[in] l List to check. 156 /// 157 /// @return true if there are watchers, false otherwise. 158 static inline bool tv_list_has_watchers(const list_T *const l) 159 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 160 { 161 return l && l->lv_watch; 162 } 163 164 /// Get first list item 165 /// 166 /// @param[in] l List to get item from. 167 /// 168 /// @return List item or NULL in case of an empty list. 169 static inline listitem_T *tv_list_first(const list_T *const l) 170 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 171 { 172 if (l == NULL) { 173 return NULL; 174 } 175 return l->lv_first; 176 } 177 178 /// Get last list item 179 /// 180 /// @param[in] l List to get item from. 181 /// 182 /// @return List item or NULL in case of an empty list. 183 static inline listitem_T *tv_list_last(const list_T *const l) 184 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 185 { 186 if (l == NULL) { 187 return NULL; 188 } 189 return l->lv_last; 190 } 191 192 /// Set a dictionary as the return value 193 /// 194 /// @param[out] tv Object to receive the dictionary 195 /// @param[in,out] d Dictionary to pass to the object 196 static inline void tv_dict_set_ret(typval_T *const tv, dict_T *const d) 197 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1) 198 { 199 tv->v_type = VAR_DICT; 200 tv->vval.v_dict = d; 201 if (d != NULL) { 202 d->dv_refcount++; 203 } 204 } 205 206 /// Get the number of items in a Dictionary 207 /// 208 /// @param[in] d Dictionary to check. 209 static inline long tv_dict_len(const dict_T *const d) 210 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 211 { 212 if (d == NULL) { 213 return 0; 214 } 215 return (long)d->dv_hashtab.ht_used; 216 } 217 218 /// Check if dictionary is watched 219 /// 220 /// @param[in] d Dictionary to check. 221 /// 222 /// @return true if there is at least one watcher. 223 static inline bool tv_dict_is_watched(const dict_T *const d) 224 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 225 { 226 return d && !QUEUE_EMPTY(&d->watchers); 227 } 228 229 /// Set a blob as the return value. 230 /// 231 /// Increments the reference count. 232 /// 233 /// @param[out] tv Object to receive the blob. 234 /// @param[in,out] b Blob to pass to the object. 235 static inline void tv_blob_set_ret(typval_T *const tv, blob_T *const b) 236 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1) 237 { 238 tv->v_type = VAR_BLOB; 239 tv->vval.v_blob = b; 240 if (b != NULL) { 241 b->bv_refcount++; 242 } 243 } 244 245 /// Get the length of the data in the blob, in bytes. 246 /// 247 /// @param[in] b Blob to check. 248 static inline int tv_blob_len(const blob_T *const b) 249 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 250 { 251 if (b == NULL) { 252 return 0; 253 } 254 return b->bv_ga.ga_len; 255 } 256 257 /// Get the byte at index `idx` in the blob. 258 /// 259 /// @param[in] b Blob to index. Cannot be NULL. 260 /// @param[in] idx Index in a blob. Must be valid. 261 /// 262 /// @return Byte value at the given index. 263 static inline uint8_t tv_blob_get(const blob_T *const b, int idx) 264 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 265 { 266 return ((uint8_t *)b->bv_ga.ga_data)[idx]; 267 } 268 269 /// Store the byte `c` at index `idx` in the blob. 270 /// 271 /// @param[in] b Blob to index. Cannot be NULL. 272 /// @param[in] idx Index in a blob. Must be valid. 273 /// @param[in] c Value to store. 274 static inline void tv_blob_set(blob_T *const blob, int idx, uint8_t c) 275 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL 276 { 277 ((uint8_t *)blob->bv_ga.ga_data)[idx] = c; 278 } 279 280 /// Initialize Vimscript object 281 /// 282 /// Initializes to unlocked VAR_UNKNOWN object. 283 /// 284 /// @param[out] tv Object to initialize. 285 static inline void tv_init(typval_T *const tv) 286 { 287 if (tv != NULL) { 288 memset(tv, 0, sizeof(*tv)); 289 } 290 } 291 292 /// Empty string 293 /// 294 /// Needed for hack which allows not allocating empty string and still not 295 /// crashing when freeing it. 296 extern const char *const tv_empty_string; 297 298 /// Specifies that free_unref_items() function has (not) been entered 299 extern bool tv_in_free_unref_items; 300 301 /// Iterate over a list 302 /// 303 /// @param modifier Modifier: expected to be const or nothing, volatile should 304 /// also work if you have any uses for the volatile list. 305 /// @param[in] l List to iterate over. 306 /// @param li Name of the variable with current listitem_T entry. 307 /// @param code Cycle body. 308 #define TV_LIST_ITER_MOD(modifier, l, li, code) \ 309 do { \ 310 modifier list_T *const l_ = (l); \ 311 if (l_ != NULL) { \ 312 for (modifier listitem_T *li = l_->lv_first; \ 313 li != NULL; li = li->li_next) { \ 314 code \ 315 } \ 316 } \ 317 } while (0) 318 319 /// Iterate over a list 320 /// 321 /// To be used when you need to modify list or values you iterate over, use 322 /// #TV_LIST_ITER_CONST if you don’t. 323 /// 324 /// @param[in] l List to iterate over. 325 /// @param li Name of the variable with current listitem_T entry. 326 /// @param code Cycle body. 327 #define TV_LIST_ITER(l, li, code) \ 328 TV_LIST_ITER_MOD( , l, li, code) 329 330 /// Iterate over a list 331 /// 332 /// To be used when you don’t need to modify list or values you iterate over, 333 /// use #TV_LIST_ITER if you do. 334 /// 335 /// @param[in] l List to iterate over. 336 /// @param li Name of the variable with current listitem_T entry. 337 /// @param code Cycle body. 338 #define TV_LIST_ITER_CONST(l, li, code) \ 339 TV_LIST_ITER_MOD(const, l, li, code) 340 341 // Below macros are macros to avoid duplicating code for functionally identical 342 // const and non-const function variants. 343 344 /// Get typval_T out of list item 345 /// 346 /// @param[in] li List item to get typval_T from, must not be NULL. 347 /// 348 /// @return Pointer to typval_T. 349 #define TV_LIST_ITEM_TV(li) (&(li)->li_tv) 350 351 /// Get next list item given the current one 352 /// 353 /// @param[in] l List to get item from. 354 /// @param[in] li List item to get typval_T from. 355 /// 356 /// @return Pointer to the next item or NULL. 357 #define TV_LIST_ITEM_NEXT(l, li) ((li)->li_next) 358 359 /// Get previous list item given the current one 360 /// 361 /// @param[in] l List to get item from. 362 /// @param[in] li List item to get typval_T from. 363 /// 364 /// @return Pointer to the previous item or NULL. 365 #define TV_LIST_ITEM_PREV(l, li) ((li)->li_prev) 366 // List argument is not used currently, but it is a must for lists implemented 367 // as a pair (size(in list), array) without terminator - basically for lists on 368 // top of kvec. 369 370 /// Iterate over a dictionary 371 /// 372 /// @param[in] d Dictionary to iterate over. 373 /// @param di Name of the variable with current dictitem_T entry. 374 /// @param code Cycle body. 375 #define TV_DICT_ITER(d, di, code) \ 376 HASHTAB_ITER(&(d)->dv_hashtab, di##hi_, { \ 377 { \ 378 dictitem_T *const di = TV_DICT_HI2DI(di##hi_); \ 379 { \ 380 code \ 381 } \ 382 } \ 383 }) 384 385 /// Get the float value 386 /// 387 /// Raises an error if object is not number or floating-point. 388 /// 389 /// @param[in] tv Vimscript object to get value from. 390 /// @param[out] ret_f Location where resulting float is stored. 391 /// 392 /// @return true in case of success, false if tv is not a number or float. 393 static inline bool tv_get_float_chk(const typval_T *const tv, float_T *const ret_f) 394 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 395 { 396 if (tv->v_type == VAR_FLOAT) { 397 *ret_f = tv->vval.v_float; 398 return true; 399 } 400 if (tv->v_type == VAR_NUMBER) { 401 *ret_f = (float_T)tv->vval.v_number; 402 return true; 403 } 404 semsg("%s", _("E808: Number or Float required")); 405 return false; 406 } 407 408 /// Compute the `DictWatcher` address from a QUEUE node. 409 /// 410 /// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer 411 /// arithmetic). 412 static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) 413 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET 414 FUNC_ATTR_NO_SANITIZE_ADDRESS FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 415 { 416 return QUEUE_DATA(q, DictWatcher, node); 417 } 418 419 /// Check whether given typval_T contains a function 420 /// 421 /// That is, whether it contains VAR_FUNC or VAR_PARTIAL. 422 /// 423 /// @param[in] tv Typval to check. 424 /// 425 /// @return True if it is a function or a partial, false otherwise. 426 static inline bool tv_is_func(const typval_T tv) 427 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST 428 { 429 return tv.v_type == VAR_FUNC || tv.v_type == VAR_PARTIAL; 430 } 431 432 /// Specify that argument needs to be translated 433 /// 434 /// Used for size_t length arguments to avoid calling gettext() and strlen() 435 /// unless needed. 436 #define TV_TRANSLATE (SIZE_MAX) 437 438 /// Specify that argument is a NUL-terminated C string 439 /// 440 /// Used for size_t length arguments to avoid calling strlen() unless needed. 441 #define TV_CSTRING (SIZE_MAX - 1) 442 443 #ifdef UNIT_TESTING 444 // Do not use enum constants, see commit message. 445 EXTERN const size_t kTVCstring INIT( = TV_CSTRING); 446 EXTERN const size_t kTVTranslate INIT( = TV_TRANSLATE); 447 #endif 448 449 #include "eval/typval.h.generated.h"