Beispiel #1
0
/*
 * A new sign in group 'groupname' is added. If the group is not present,
 * create it. Otherwise reference the group.
 */
    static signgroup_T *
sign_group_ref(char_u *groupname)
{
    hash_T		hash;
    hashitem_T		*hi;
    signgroup_T		*group;

    hash = hash_hash(groupname);
    hi = hash_lookup(&sg_table, groupname, hash);
    if (HASHITEM_EMPTY(hi))
    {
	// new group
	group = (signgroup_T *)alloc(
		(unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
	if (group == NULL)
	    return NULL;
	STRCPY(group->sg_name, groupname);
	group->refcount = 1;
	group->next_sign_id = 1;
	hash_add_item(&sg_table, hi, group->sg_name, hash);
    }
    else
    {
	// existing group
	group = HI2SG(hi);
	group->refcount++;
    }

    return group;
}
Beispiel #2
0
Datei: dict.c Projekt: HarmtH/vim
/*
 * Free a Dictionary, including all non-container items it contains.
 * Ignores the reference count.
 */
    static void
dict_free_contents(dict_T *d)
{
    int		todo;
    hashitem_T	*hi;
    dictitem_T	*di;

    /* Lock the hashtab, we don't want it to resize while freeing items. */
    hash_lock(&d->dv_hashtab);
    todo = (int)d->dv_hashtab.ht_used;
    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
    {
	if (!HASHITEM_EMPTY(hi))
	{
	    /* Remove the item before deleting it, just in case there is
	     * something recursive causing trouble. */
	    di = HI2DI(hi);
	    hash_remove(&d->dv_hashtab, hi);
	    clear_tv(&di->di_tv);
	    vim_free(di);
	    --todo;
	}
    }
    hash_clear(&d->dv_hashtab);
}
Beispiel #3
0
Datei: dict.c Projekt: HarmtH/vim
/*
 * Find item "key[len]" in Dictionary "d".
 * If "len" is negative use strlen(key).
 * Returns NULL when not found.
 */
    dictitem_T *
dict_find(dict_T *d, char_u *key, int len)
{
#define AKEYLEN 200
    char_u	buf[AKEYLEN];
    char_u	*akey;
    char_u	*tofree = NULL;
    hashitem_T	*hi;

    if (d == NULL)
	return NULL;
    if (len < 0)
	akey = key;
    else if (len >= AKEYLEN)
    {
	tofree = akey = vim_strnsave(key, len);
	if (akey == NULL)
	    return NULL;
    }
    else
    {
	/* Avoid a malloc/free by using buf[]. */
	vim_strncpy(buf, key, len);
	akey = buf;
    }

    hi = hash_find(&d->dv_hashtab, akey);
    vim_free(tofree);
    if (HASHITEM_EMPTY(hi))
	return NULL;
    return HI2DI(hi);
}
Beispiel #4
0
Datei: dict.c Projekt: HarmtH/vim
/*
 * Return TRUE when two dictionaries have exactly the same key/values.
 */
    int
dict_equal(
    dict_T	*d1,
    dict_T	*d2,
    int		ic,	/* ignore case for strings */
    int		recursive) /* TRUE when used recursively */
{
    hashitem_T	*hi;
    dictitem_T	*item2;
    int		todo;

    if (d1 == NULL && d2 == NULL)
	return TRUE;
    if (d1 == NULL || d2 == NULL)
	return FALSE;
    if (d1 == d2)
	return TRUE;
    if (dict_len(d1) != dict_len(d2))
	return FALSE;

    todo = (int)d1->dv_hashtab.ht_used;
    for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi)
    {
	if (!HASHITEM_EMPTY(hi))
	{
	    item2 = dict_find(d2, hi->hi_key, -1);
	    if (item2 == NULL)
		return FALSE;
	    if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic, recursive))
		return FALSE;
	    --todo;
	}
    }
    return TRUE;
}
Beispiel #5
0
Datei: dict.c Projekt: HarmtH/vim
/*
 * Make a copy of dict "d".  Shallow if "deep" is FALSE.
 * The refcount of the new dict is set to 1.
 * See item_copy() for "copyID".
 * Returns NULL when out of memory.
 */
    dict_T *
dict_copy(dict_T *orig, int deep, int copyID)
{
    dict_T	*copy;
    dictitem_T	*di;
    int		todo;
    hashitem_T	*hi;

    if (orig == NULL)
	return NULL;

    copy = dict_alloc();
    if (copy != NULL)
    {
	if (copyID != 0)
	{
	    orig->dv_copyID = copyID;
	    orig->dv_copydict = copy;
	}
	todo = (int)orig->dv_hashtab.ht_used;
	for (hi = orig->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi)
	{
	    if (!HASHITEM_EMPTY(hi))
	    {
		--todo;

		di = dictitem_alloc(hi->hi_key);
		if (di == NULL)
		    break;
		if (deep)
		{
		    if (item_copy(&HI2DI(hi)->di_tv, &di->di_tv, deep,
							      copyID) == FAIL)
		    {
			vim_free(di);
			break;
		    }
		}
		else
		    copy_tv(&HI2DI(hi)->di_tv, &di->di_tv);
		if (dict_add(copy, di) == FAIL)
		{
		    dictitem_free(di);
		    break;
		}
	    }
	}

	++copy->dv_refcount;
	if (todo > 0)
	{
	    dict_unref(copy);
	    copy = NULL;
	}
    }

    return copy;
}
Beispiel #6
0
Datei: dict.c Projekt: HarmtH/vim
/*
 * Return an allocated string with the string representation of a Dictionary.
 * May return NULL.
 */
    char_u *
dict2string(typval_T *tv, int copyID, int restore_copyID)
{
    garray_T	ga;
    int		first = TRUE;
    char_u	*tofree;
    char_u	numbuf[NUMBUFLEN];
    hashitem_T	*hi;
    char_u	*s;
    dict_T	*d;
    int		todo;

    if ((d = tv->vval.v_dict) == NULL)
	return NULL;
    ga_init2(&ga, (int)sizeof(char), 80);
    ga_append(&ga, '{');

    todo = (int)d->dv_hashtab.ht_used;
    for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi)
    {
	if (!HASHITEM_EMPTY(hi))
	{
	    --todo;

	    if (first)
		first = FALSE;
	    else
		ga_concat(&ga, (char_u *)", ");

	    tofree = string_quote(hi->hi_key, FALSE);
	    if (tofree != NULL)
	    {
		ga_concat(&ga, tofree);
		vim_free(tofree);
	    }
	    ga_concat(&ga, (char_u *)": ");
	    s = echo_string_core(&HI2DI(hi)->di_tv, &tofree, numbuf, copyID,
						 FALSE, restore_copyID, TRUE);
	    if (s != NULL)
		ga_concat(&ga, s);
	    vim_free(tofree);
	    if (s == NULL || did_echo_string_emsg)
		break;
	    line_breakcheck();

	}
    }
    if (todo > 0)
    {
	vim_free(ga.ga_data);
	return NULL;
    }

    ga_append(&ga, '}');
    ga_append(&ga, NUL);
    return (char_u *)ga.ga_data;
}
Beispiel #7
0
/// Add item with key "key" to hashtable "ht".
///
/// @param ht
/// @param key
///
/// @returns FAIL when out of memory or the key is already present.
int hash_add(hashtab_T *ht, char_u *key)
{
  hash_T hash = hash_hash(key);
  hashitem_T *hi = hash_lookup(ht, key, hash);
  if (!HASHITEM_EMPTY(hi)) {
    EMSG2(_(e_intern2), "hash_add()");
    return FAIL;
  }
  return hash_add_item(ht, hi, key, hash);
}
Beispiel #8
0
/// Free the array of a hash table and all contained values.
///
/// @param off the offset from start of value to start of key (@see hashitem_T).
void hash_clear_all(hashtab_T *ht, unsigned int off)
{
  size_t todo = ht->ht_used;
  for (hashitem_T *hi = ht->ht_array; todo > 0; ++hi) {
    if (!HASHITEM_EMPTY(hi)) {
      xfree(hi->hi_key - off);
      todo--;
    }
  }
  hash_clear(ht);
}
Beispiel #9
0
Datei: dict.c Projekt: HarmtH/vim
/*
 * Remove item "item" from Dictionary "dict" and free it.
 */
    void
dictitem_remove(dict_T *dict, dictitem_T *item)
{
    hashitem_T	*hi;

    hi = hash_find(&dict->dv_hashtab, item->di_key);
    if (HASHITEM_EMPTY(hi))
	EMSG2(_(e_intern2), "dictitem_remove()");
    else
	hash_remove(&dict->dv_hashtab, hi);
    dictitem_free(item);
}
Beispiel #10
0
/// Recursively expands a vimscript value in a dict
///
/// @param dict The vimscript dict
/// @param key The key
/// @param[out] err Details of an error that may have occurred
Object dict_get_value(dict_T *dict, String key, Error *err)
{
  hashitem_T *hi = hash_find(&dict->dv_hashtab, (uint8_t *) key.data);

  if (HASHITEM_EMPTY(hi)) {
    set_api_error("Key not found", err);
    return (Object) OBJECT_INIT;
  }

  dictitem_T *di = dict_lookup(hi);
  return vim_to_object(&di->di_tv);
}
Beispiel #11
0
    static void
set_ref_in_dict(dict_T *d, int copyID)
{
    hashtab_T *ht = &d->dv_hashtab;
    int n = ht->ht_used;
    hashitem_T *hi;
    for (hi = ht->ht_array; n > 0; ++hi)
	if (!HASHITEM_EMPTY(hi))
	{
	    dictitem_T *di = dict_lookup(hi);
	    set_ref_in_tv(&di->di_tv, copyID);
	    --n;
	}
}
Beispiel #12
0
/// Free the array of a hash table and all the keys it contains.  The keys must
/// have been allocated.  "off" is the offset from the start of the allocate
/// memory to the location of the key (it's always positive).
///
/// @param ht
/// @param off
void hash_clear_all(hashtab_T *ht, int off)
{
  long todo;
  hashitem_T *hi;

  todo = (long)ht->ht_used;

  for (hi = ht->ht_array; todo > 0; ++hi) {
    if (!HASHITEM_EMPTY(hi)) {
      vim_free(hi->hi_key - off);
      todo--;
    }
  }
  hash_clear(ht);
}
Beispiel #13
0
Datei: dict.c Projekt: HarmtH/vim
/*
 * Go over all entries in "d2" and add them to "d1".
 * When "action" is "error" then a duplicate key is an error.
 * When "action" is "force" then a duplicate key is overwritten.
 * Otherwise duplicate keys are ignored ("action" is "keep").
 */
    void
dict_extend(dict_T *d1, dict_T *d2, char_u *action)
{
    dictitem_T	*di1;
    hashitem_T	*hi2;
    int		todo;
    char_u	*arg_errmsg = (char_u *)N_("extend() argument");

    todo = (int)d2->dv_hashtab.ht_used;
    for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2)
    {
	if (!HASHITEM_EMPTY(hi2))
	{
	    --todo;
	    di1 = dict_find(d1, hi2->hi_key, -1);
	    if (d1->dv_scope != 0)
	    {
		/* Disallow replacing a builtin function in l: and g:.
		 * Check the key to be valid when adding to any scope. */
		if (d1->dv_scope == VAR_DEF_SCOPE
			&& HI2DI(hi2)->di_tv.v_type == VAR_FUNC
			&& var_check_func_name(hi2->hi_key, di1 == NULL))
		    break;
		if (!valid_varname(hi2->hi_key))
		    break;
	    }
	    if (di1 == NULL)
	    {
		di1 = dictitem_copy(HI2DI(hi2));
		if (di1 != NULL && dict_add(d1, di1) == FAIL)
		    dictitem_free(di1);
	    }
	    else if (*action == 'e')
	    {
		EMSG2(_("E737: Key already exists: %s"), hi2->hi_key);
		break;
	    }
	    else if (*action == 'f' && HI2DI(hi2) != di1)
	    {
		if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, TRUE)
		      || var_check_ro(di1->di_flags, arg_errmsg, TRUE))
		    break;
		clear_tv(&di1->di_tv);
		copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv);
	    }
	}
    }
}
Beispiel #14
0
    static int
luaV_dict_iter (lua_State *L)
{
    hashitem_T *hi = (hashitem_T *) lua_touserdata(L, lua_upvalueindex(2));
    int n = lua_tointeger(L, lua_upvalueindex(3));
    dictitem_T *di;
    if (n <= 0) return 0;
    while (HASHITEM_EMPTY(hi)) hi++;
    di = dict_lookup(hi);
    lua_pushstring(L, (char *) hi->hi_key);
    luaV_pushtypval(L, &di->di_tv);
    lua_pushlightuserdata(L, (void *) (hi + 1));
    lua_replace(L, lua_upvalueindex(2));
    lua_pushinteger(L, n - 1);
    lua_replace(L, lua_upvalueindex(3));
    return 2;
}
Beispiel #15
0
Object dict_get_value(dict_T *dict, String key, Error *err)
{
  Object rv;
  hashitem_T *hi;
  dictitem_T *di;
  char *k = xstrndup(key.data, key.size);
  hi = hash_find(&dict->dv_hashtab, (uint8_t *)k);
  free(k);

  if (HASHITEM_EMPTY(hi)) {
    set_api_error("Key not found", err);
    return rv;
  }

  di = dict_lookup(hi);
  rv = vim_to_object(&di->di_tv);

  return rv;
}
Beispiel #16
0
/*
 * A sign in group 'groupname' is removed. If all the signs in this group are
 * removed, then remove the group.
 */
    static void
sign_group_unref(char_u *groupname)
{
    hashitem_T		*hi;
    signgroup_T		*group;

    hi = hash_find(&sg_table, groupname);
    if (!HASHITEM_EMPTY(hi))
    {
	group = HI2SG(hi);
	group->refcount--;
	if (group->refcount == 0)
	{
	    // All the signs in this group are removed
	    hash_remove(&sg_table, hi);
	    vim_free(group);
	}
    }
}
Beispiel #17
0
/*
 * Find a property type by name, return the hashitem.
 * Returns NULL if the item can't be found.
 */
    static hashitem_T *
find_prop_hi(char_u *name, buf_T *buf)
{
    hashtab_T	*ht;
    hashitem_T	*hi;

    if (*name == NUL)
	return NULL;
    if (buf == NULL)
	ht = global_proptypes;
    else
	ht = buf->b_proptypes;

    if (ht == NULL)
	return NULL;
    hi = hash_find(ht, name);
    if (HASHITEM_EMPTY(hi))
	return NULL;
    return hi;
}
Beispiel #18
0
/*
 * Get the next free sign identifier in the specified group
 */
    static int
sign_group_get_next_signid(buf_T *buf, char_u *groupname)
{
    int			id = 1;
    signgroup_T		*group = NULL;
    signlist_T		*sign;
    hashitem_T		*hi;
    int			found = FALSE;

    if (groupname != NULL)
    {
	hi = hash_find(&sg_table, groupname);
	if (HASHITEM_EMPTY(hi))
	    return id;
	group = HI2SG(hi);
    }

    // Search for the next usable sign identifier
    while (!found)
    {
	if (group == NULL)
	    id = next_sign_id++;		// global group
	else
	    id = group->next_sign_id++;

	// Check whether this sign is already placed in the buffer
	found = TRUE;
	FOR_ALL_SIGNS_IN_BUF(buf, sign)
	{
	    if (id == sign->id && sign_in_group(sign, groupname))
	    {
		found = FALSE;		// sign identifier is in use
		break;
	    }
	}
    }

    return id;
}
Beispiel #19
0
/// Resize hastable (new size can be given or automatically computed).
///
/// @param minitems Minimum number of items the new table should hold.
///                 If zero, new size will depend on currently used items:
///                 - Shrink when too much empty space.
///                 - Grow when not enough empty space.
///                 If non-zero, passed minitems will be used.
static void hash_may_resize(hashtab_T *ht, size_t minitems)
{
  // Don't resize a locked table.
  if (ht->ht_locked > 0) {
    return;
  }

#ifdef HT_DEBUG
  if (ht->ht_used > ht->ht_filled) {
    EMSG("hash_may_resize(): more used than filled");
  }

  if (ht->ht_filled >= ht->ht_mask + 1) {
    EMSG("hash_may_resize(): table completely filled");
  }
#endif  // ifdef HT_DEBUG

  size_t minsize;
  if (minitems == 0) {
    // Return quickly for small tables with at least two NULL items.
    // items are required for the lookup to decide a key isn't there.
    if ((ht->ht_filled < HT_INIT_SIZE - 1)
        && (ht->ht_array == ht->ht_smallarray)) {
      return;
    }

    // Grow or refill the array when it's more than 2/3 full (including
    // removed items, so that they get cleaned up).
    // Shrink the array when it's less than 1/5 full. When growing it is
    // at least 1/4 full (avoids repeated grow-shrink operations)
    size_t oldsize = ht->ht_mask + 1;
    if ((ht->ht_filled * 3 < oldsize * 2) && (ht->ht_used > oldsize / 5)) {
      return;
    }

    if (ht->ht_used > 1000) {
      // it's big, don't make too much room
      minsize = ht->ht_used * 2;
    } else {
      // make plenty of room
      minsize = ht->ht_used * 4;
    }
  } else {
    // Use specified size.
    if (minitems < ht->ht_used) {
      // just in case...
      minitems = ht->ht_used;
    }
    // array is up to 2/3 full
    minsize = minitems * 3 / 2;
  }

  size_t newsize = HT_INIT_SIZE;
  while (newsize < minsize) {
    // make sure it's always a power of 2
    newsize <<= 1;
    // assert newsize didn't overflow
    assert(newsize != 0);
  }

  bool newarray_is_small = newsize == HT_INIT_SIZE;
  bool keep_smallarray = newarray_is_small
    && ht->ht_array == ht->ht_smallarray;

  // Make sure that oldarray and newarray do not overlap,
  // so that copying is possible.
  hashitem_T temparray[HT_INIT_SIZE];
  hashitem_T *oldarray = keep_smallarray
    ? memcpy(temparray, ht->ht_smallarray, sizeof(temparray))
    : ht->ht_array;
  hashitem_T *newarray = newarray_is_small
    ? ht->ht_smallarray
    : xmalloc(sizeof(hashitem_T) * newsize);

  memset(newarray, 0, sizeof(hashitem_T) * newsize);

  // Move all the items from the old array to the new one, placing them in
  // the right spot. The new array won't have any removed items, thus this
  // is also a cleanup action.
  hash_T newmask = newsize - 1;
  size_t todo = ht->ht_used;

  for (hashitem_T *olditem = oldarray; todo > 0; ++olditem) {
    if (HASHITEM_EMPTY(olditem)) {
      continue;
    }
    // The algorithm to find the spot to add the item is identical to
    // the algorithm to find an item in hash_lookup(). But we only
    // need to search for a NULL key, thus it's simpler.
    hash_T newi = olditem->hi_hash & newmask;
    hashitem_T *newitem = &newarray[newi];
    if (newitem->hi_key != NULL) {
      for (hash_T perturb = olditem->hi_hash;; perturb >>= PERTURB_SHIFT) {
        newi = 5 * newi + perturb + 1;
        newitem = &newarray[newi & newmask];
        if (newitem->hi_key == NULL) {
          break;
        }
      }
    }
    *newitem = *olditem;
    todo--;
  }

  if (ht->ht_array != ht->ht_smallarray) {
    xfree(ht->ht_array);
  }
  ht->ht_array = newarray;
  ht->ht_mask = newmask;
  ht->ht_filled = ht->ht_used;
}
Beispiel #20
0
Datei: dict.c Projekt: HarmtH/vim
/*
 * Turn a dict into a list:
 * "what" == 0: list of keys
 * "what" == 1: list of values
 * "what" == 2: list of items
 */
    void
dict_list(typval_T *argvars, typval_T *rettv, int what)
{
    list_T	*l2;
    dictitem_T	*di;
    hashitem_T	*hi;
    listitem_T	*li;
    listitem_T	*li2;
    dict_T	*d;
    int		todo;

    if (argvars[0].v_type != VAR_DICT)
    {
	EMSG(_(e_dictreq));
	return;
    }
    if ((d = argvars[0].vval.v_dict) == NULL)
	return;

    if (rettv_list_alloc(rettv) == FAIL)
	return;

    todo = (int)d->dv_hashtab.ht_used;
    for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
    {
	if (!HASHITEM_EMPTY(hi))
	{
	    --todo;
	    di = HI2DI(hi);

	    li = listitem_alloc();
	    if (li == NULL)
		break;
	    list_append(rettv->vval.v_list, li);

	    if (what == 0)
	    {
		/* keys() */
		li->li_tv.v_type = VAR_STRING;
		li->li_tv.v_lock = 0;
		li->li_tv.vval.v_string = vim_strsave(di->di_key);
	    }
	    else if (what == 1)
	    {
		/* values() */
		copy_tv(&di->di_tv, &li->li_tv);
	    }
	    else
	    {
		/* items() */
		l2 = list_alloc();
		li->li_tv.v_type = VAR_LIST;
		li->li_tv.v_lock = 0;
		li->li_tv.vval.v_list = l2;
		if (l2 == NULL)
		    break;
		++l2->lv_refcount;

		li2 = listitem_alloc();
		if (li2 == NULL)
		    break;
		list_append(l2, li2);
		li2->li_tv.v_type = VAR_STRING;
		li2->li_tv.v_lock = 0;
		li2->li_tv.vval.v_string = vim_strsave(di->di_key);

		li2 = listitem_alloc();
		if (li2 == NULL)
		    break;
		list_append(l2, li2);
		copy_tv(&di->di_tv, &li2->li_tv);
	    }
	}
    }
}
Beispiel #21
0
/*
 * Encode "val" into "gap".
 * Return FAIL or OK.
 */
    static int
json_encode_item(garray_T *gap, typval_T *val, int copyID)
{
    char_u	numbuf[NUMBUFLEN];
    char_u	*res;
    list_T	*l;
    dict_T	*d;

    switch (val->v_type)
    {
	case VAR_SPECIAL:
	    switch (val->vval.v_number)
	    {
		case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
		case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
		case VVAL_NONE: break;
		case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
	    }
	    break;

	case VAR_NUMBER:
	    vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
						    (long)val->vval.v_number);
	    ga_concat(gap, numbuf);
	    break;

	case VAR_STRING:
	    res = val->vval.v_string;
	    write_string(gap, res);
	    break;

	case VAR_FUNC:
	    /* no JSON equivalent */
	    EMSG(_(e_invarg));
	    return FAIL;

	case VAR_LIST:
	    l = val->vval.v_list;
	    if (l == NULL)
		ga_concat(gap, (char_u *)"null");
	    else
	    {
		if (l->lv_copyID == copyID)
		    ga_concat(gap, (char_u *)"[]");
		else
		{
		    listitem_T	*li;

		    l->lv_copyID = copyID;
		    ga_append(gap, '[');
		    for (li = l->lv_first; li != NULL && !got_int; )
		    {
			if (json_encode_item(gap, &li->li_tv, copyID) == FAIL)
			    return FAIL;
			li = li->li_next;
			if (li != NULL)
			    ga_append(gap, ',');
		    }
		    ga_append(gap, ']');
		    l->lv_copyID = 0;
		}
	    }
	    break;

	case VAR_DICT:
	    d = val->vval.v_dict;
	    if (d == NULL)
		ga_concat(gap, (char_u *)"null");
	    else
	    {
		if (d->dv_copyID == copyID)
		    ga_concat(gap, (char_u *)"{}");
		else
		{
		    int		first = TRUE;
		    int		todo = (int)d->dv_hashtab.ht_used;
		    hashitem_T	*hi;

		    d->dv_copyID = copyID;
		    ga_append(gap, '{');

		    for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
									 ++hi)
			if (!HASHITEM_EMPTY(hi))
			{
			    --todo;
			    if (first)
				first = FALSE;
			    else
				ga_append(gap, ',');
			    write_string(gap, hi->hi_key);
			    ga_append(gap, ':');
			    if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
							      copyID) == FAIL)
				return FAIL;
			}
		    ga_append(gap, '}');
		    d->dv_copyID = 0;
		}
	    }
	    break;

#ifdef FEAT_FLOAT
	case VAR_FLOAT:
	    vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float);
	    ga_concat(gap, numbuf);
	    break;
#endif
	default: EMSG2(_(e_intern2), "json_encode_item()"); break;
		 return FAIL;
    }
    return OK;
}
Beispiel #22
0
/*
 * Shrink a hashtable when there is too much empty space.
 * Grow a hashtable when there is not enough empty space.
 * Returns OK or FAIL (out of memory).
 */
    static int
hash_may_resize(
    hashtab_T	*ht,
    int		minitems)		/* minimal number of items */
{
    hashitem_T	temparray[HT_INIT_SIZE];
    hashitem_T	*oldarray, *newarray;
    hashitem_T	*olditem, *newitem;
    unsigned	newi;
    int		todo;
    long_u	oldsize, newsize;
    long_u	minsize;
    long_u	newmask;
    hash_T	perturb;

    /* Don't resize a locked table. */
    if (ht->ht_locked > 0)
	return OK;

#ifdef HT_DEBUG
    if (ht->ht_used > ht->ht_filled)
	EMSG("hash_may_resize(): more used than filled");
    if (ht->ht_filled >= ht->ht_mask + 1)
	EMSG("hash_may_resize(): table completely filled");
#endif

    if (minitems == 0)
    {
	/* Return quickly for small tables with at least two NULL items.  NULL
	 * items are required for the lookup to decide a key isn't there. */
	if (ht->ht_filled < HT_INIT_SIZE - 1
					 && ht->ht_array == ht->ht_smallarray)
	    return OK;

	/*
	 * Grow or refill the array when it's more than 2/3 full (including
	 * removed items, so that they get cleaned up).
	 * Shrink the array when it's less than 1/5 full.  When growing it is
	 * at least 1/4 full (avoids repeated grow-shrink operations)
	 */
	oldsize = ht->ht_mask + 1;
	if (ht->ht_filled * 3 < oldsize * 2 && ht->ht_used > oldsize / 5)
	    return OK;

	if (ht->ht_used > 1000)
	    minsize = ht->ht_used * 2;  /* it's big, don't make too much room */
	else
	    minsize = ht->ht_used * 4;  /* make plenty of room */
    }
    else
    {
	/* Use specified size. */
	if ((long_u)minitems < ht->ht_used)	/* just in case... */
	    minitems = (int)ht->ht_used;
	minsize = minitems * 3 / 2;	/* array is up to 2/3 full */
    }

    newsize = HT_INIT_SIZE;
    while (newsize < minsize)
    {
	newsize <<= 1;		/* make sure it's always a power of 2 */
	if (newsize == 0)
	    return FAIL;	/* overflow */
    }

    if (newsize == HT_INIT_SIZE)
    {
	/* Use the small array inside the hashdict structure. */
	newarray = ht->ht_smallarray;
	if (ht->ht_array == newarray)
	{
	    /* Moving from ht_smallarray to ht_smallarray!  Happens when there
	     * are many removed items.  Copy the items to be able to clean up
	     * removed items. */
	    mch_memmove(temparray, newarray, sizeof(temparray));
	    oldarray = temparray;
	}
	else
	    oldarray = ht->ht_array;
    }
    else
    {
	/* Allocate an array. */
	newarray = (hashitem_T *)alloc((unsigned)
					      (sizeof(hashitem_T) * newsize));
	if (newarray == NULL)
	{
	    /* Out of memory.  When there are NULL items still return OK.
	     * Otherwise set ht_error, because lookup may result in a hang if
	     * we add another item. */
	    if (ht->ht_filled < ht->ht_mask)
		return OK;
	    ht->ht_error = TRUE;
	    return FAIL;
	}
	oldarray = ht->ht_array;
    }
    vim_memset(newarray, 0, (size_t)(sizeof(hashitem_T) * newsize));

    /*
     * Move all the items from the old array to the new one, placing them in
     * the right spot.  The new array won't have any removed items, thus this
     * is also a cleanup action.
     */
    newmask = newsize - 1;
    todo = (int)ht->ht_used;
    for (olditem = oldarray; todo > 0; ++olditem)
	if (!HASHITEM_EMPTY(olditem))
	{
	    /*
	     * The algorithm to find the spot to add the item is identical to
	     * the algorithm to find an item in hash_lookup().  But we only
	     * need to search for a NULL key, thus it's simpler.
	     */
	    newi = (unsigned)(olditem->hi_hash & newmask);
	    newitem = &newarray[newi];

	    if (newitem->hi_key != NULL)
		for (perturb = olditem->hi_hash; ; perturb >>= PERTURB_SHIFT)
		{
		    newi = (unsigned)((newi << 2U) + newi + perturb + 1U);
		    newitem = &newarray[newi & newmask];
		    if (newitem->hi_key == NULL)
			break;
		}
	    *newitem = *olditem;
	    --todo;
	}
Beispiel #23
0
/// Shrink a hashtable when there is too much empty space.
/// Grow a hashtable when there is not enough empty space.
///
/// @param ht
/// @param minitems minimal number of items
///
/// @returns OK or FAIL (out of memory).
static int hash_may_resize(hashtab_T *ht, int minitems)
{
  hashitem_T temparray[HT_INIT_SIZE];
  hashitem_T *oldarray, *newarray;
  hashitem_T *olditem, *newitem;
  unsigned newi;
  int todo;
  long_u oldsize, newsize;
  long_u minsize;
  long_u newmask;
  hash_T perturb;

  // Don't resize a locked table.
  if (ht->ht_locked > 0) {
    return OK;
  }

#ifdef HT_DEBUG
  if (ht->ht_used > ht->ht_filled) {
    EMSG("hash_may_resize(): more used than filled");
  }

  if (ht->ht_filled >= ht->ht_mask + 1) {
    EMSG("hash_may_resize(): table completely filled");
  }
#endif  // ifdef HT_DEBUG

  if (minitems == 0) {
    // Return quickly for small tables with at least two NULL items.  NULL
    // items are required for the lookup to decide a key isn't there.
    if ((ht->ht_filled < HT_INIT_SIZE - 1)
        && (ht->ht_array == ht->ht_smallarray)) {
      return OK;
    }

    // Grow or refill the array when it's more than 2/3 full (including
    // removed items, so that they get cleaned up).
    // Shrink the array when it's less than 1/5 full.  When growing it is
    // at least 1/4 full (avoids repeated grow-shrink operations)
    oldsize = ht->ht_mask + 1;
    if ((ht->ht_filled * 3 < oldsize * 2) && (ht->ht_used > oldsize / 5)) {
      return OK;
    }

    if (ht->ht_used > 1000) {
      // it's big, don't make too much room
      minsize = ht->ht_used * 2;
    } else {
      // make plenty of room
      minsize = ht->ht_used * 4;
    }
  } else {
    // Use specified size.
    if ((long_u)minitems < ht->ht_used) {
      // just in case...
      minitems = (int)ht->ht_used;
    }
    // array is up to 2/3 full
    minsize = minitems * 3 / 2;
  }

  newsize = HT_INIT_SIZE;

  while (newsize < minsize) {
    // make sure it's always a power of 2
    newsize <<= 1;
    if (newsize == 0) {
      // overflow
      return FAIL;
    }
  }

  if (newsize == HT_INIT_SIZE) {
    // Use the small array inside the hashdict structure.
    newarray = ht->ht_smallarray;
    if (ht->ht_array == newarray) {
      // Moving from ht_smallarray to ht_smallarray!  Happens when there
      // are many removed items.  Copy the items to be able to clean up
      // removed items.
      mch_memmove(temparray, newarray, sizeof(temparray));
      oldarray = temparray;
    } else {
      oldarray = ht->ht_array;
    }
  } else {
    // Allocate an array.
    newarray = (hashitem_T *)alloc((unsigned)(sizeof(hashitem_T) * newsize));

    if (newarray == NULL) {
      // Out of memory.  When there are NULL items still return OK.
      // Otherwise set ht_error, because lookup may result in a hang if
      // we add another item.
      if (ht->ht_filled < ht->ht_mask) {
        return OK;
      }
      ht->ht_error = TRUE;
      return FAIL;
    }
    oldarray = ht->ht_array;
  }
  memset(newarray, 0, (size_t)(sizeof(hashitem_T) * newsize));

  // Move all the items from the old array to the new one, placing them in
  // the right spot.  The new array won't have any removed items, thus this
  // is also a cleanup action.
  newmask = newsize - 1;
  todo = (int)ht->ht_used;

  for (olditem = oldarray; todo > 0; ++olditem) {
    if (!HASHITEM_EMPTY(olditem)) {
      // The algorithm to find the spot to add the item is identical to
      // the algorithm to find an item in hash_lookup().  But we only
      // need to search for a NULL key, thus it's simpler.
      newi = (unsigned)(olditem->hi_hash & newmask);
      newitem = &newarray[newi];
      if (newitem->hi_key != NULL) {
        for (perturb = olditem->hi_hash;; perturb >>= PERTURB_SHIFT) {
          newi = (unsigned)((newi << 2U) + newi + perturb + 1U);
          newitem = &newarray[newi & newmask];
          if (newitem->hi_key == NULL) {
            break;
          }
        }
      }
      *newitem = *olditem;
      todo--;
    }
  }
Beispiel #24
0
/*
 * Encode "val" into "gap".
 * Return FAIL or OK.
 */
    static int
json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
{
    char_u	numbuf[NUMBUFLEN];
    char_u	*res;
    list_T	*l;
    dict_T	*d;

    switch (val->v_type)
    {
	case VAR_SPECIAL:
	    switch (val->vval.v_number)
	    {
		case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
		case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
		case VVAL_NONE: if ((options & JSON_JS) != 0
					     && (options & JSON_NO_NONE) == 0)
				    /* empty item */
				    break;
				/* FALLTHROUGH */
		case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
	    }
	    break;

	case VAR_NUMBER:
	    vim_snprintf((char *)numbuf, NUMBUFLEN, "%lld",
						(long long)val->vval.v_number);
	    ga_concat(gap, numbuf);
	    break;

	case VAR_STRING:
	    res = val->vval.v_string;
	    write_string(gap, res);
	    break;

	case VAR_FUNC:
	case VAR_PARTIAL:
	case VAR_JOB:
	case VAR_CHANNEL:
	    /* no JSON equivalent TODO: better error */
	    EMSG(_(e_invarg));
	    return FAIL;

	case VAR_LIST:
	    l = val->vval.v_list;
	    if (l == NULL)
		ga_concat(gap, (char_u *)"[]");
	    else
	    {
		if (l->lv_copyID == copyID)
		    ga_concat(gap, (char_u *)"[]");
		else
		{
		    listitem_T	*li;

		    l->lv_copyID = copyID;
		    ga_append(gap, '[');
		    for (li = l->lv_first; li != NULL && !got_int; )
		    {
			if (json_encode_item(gap, &li->li_tv, copyID,
						   options & JSON_JS) == FAIL)
			    return FAIL;
			if ((options & JSON_JS)
				&& li->li_next == NULL
				&& li->li_tv.v_type == VAR_SPECIAL
				&& li->li_tv.vval.v_number == VVAL_NONE)
			    /* add an extra comma if the last item is v:none */
			    ga_append(gap, ',');
			li = li->li_next;
			if (li != NULL)
			    ga_append(gap, ',');
		    }
		    ga_append(gap, ']');
		    l->lv_copyID = 0;
		}
	    }
	    break;

	case VAR_DICT:
	    d = val->vval.v_dict;
	    if (d == NULL)
		ga_concat(gap, (char_u *)"{}");
	    else
	    {
		if (d->dv_copyID == copyID)
		    ga_concat(gap, (char_u *)"{}");
		else
		{
		    int		first = TRUE;
		    int		todo = (int)d->dv_hashtab.ht_used;
		    hashitem_T	*hi;

		    d->dv_copyID = copyID;
		    ga_append(gap, '{');

		    for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
									 ++hi)
			if (!HASHITEM_EMPTY(hi))
			{
			    --todo;
			    if (first)
				first = FALSE;
			    else
				ga_append(gap, ',');
			    if ((options & JSON_JS)
						 && is_simple_key(hi->hi_key))
				ga_concat(gap, hi->hi_key);
			    else
				write_string(gap, hi->hi_key);
			    ga_append(gap, ':');
			    if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
				      copyID, options | JSON_NO_NONE) == FAIL)
				return FAIL;
			}
		    ga_append(gap, '}');
		    d->dv_copyID = 0;
		}
	    }
	    break;

	case VAR_FLOAT:
#ifdef FEAT_FLOAT
# if defined(HAVE_MATH_H)
	    if (isnan(val->vval.v_float))
		ga_concat(gap, (char_u *)"NaN");
	    else if (isinf(val->vval.v_float))
		ga_concat(gap, (char_u *)"Infinity");
	    else
# endif
	    {
		vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
							   val->vval.v_float);
		ga_concat(gap, numbuf);
	    }
	    break;
#endif
	case VAR_UNKNOWN:
	    internal_error("json_encode_item()");
	    return FAIL;
    }
    return OK;
}
Beispiel #25
0
static void
luaV_pushtypval(lua_State *L, typval_T *tv)
{
    if (tv == NULL) luaL_error(L, "null type");
    switch (tv->v_type)
    {
    case VAR_STRING:
        lua_pushstring(L, (char *) tv->vval.v_string);
        break;
    case VAR_NUMBER:
        lua_pushinteger(L, (int) tv->vval.v_number);
        break;
#ifdef FEAT_FLOAT
    case VAR_FLOAT:
        lua_pushnumber(L, (lua_Number) tv->vval.v_float);
        break;
#endif
    case VAR_LIST: {
        list_T *l = tv->vval.v_list;

        if (l != NULL)
        {
            /* check cache */
            lua_pushlightuserdata(L, (void *) l);
            lua_rawget(L, LUA_ENVIRONINDEX);
            if (lua_isnil(L, -1)) /* not interned? */
            {
                listitem_T *li;
                int n = 0;
                lua_pop(L, 1); /* nil */
                lua_newtable(L);
                lua_pushlightuserdata(L, (void *) l);
                lua_pushvalue(L, -2);
                lua_rawset(L, LUA_ENVIRONINDEX);
                for (li = l->lv_first; li != NULL; li = li->li_next)
                {
                    luaV_pushtypval(L, &li->li_tv);
                    lua_rawseti(L, -2, ++n);
                }
            }
        }
        else lua_pushnil(L);
        break;
    }
    case VAR_DICT: {
        dict_T *d = tv->vval.v_dict;

        if (d != NULL)
        {
            /* check cache */
            lua_pushlightuserdata(L, (void *) d);
            lua_rawget(L, LUA_ENVIRONINDEX);
            if (lua_isnil(L, -1)) /* not interned? */
            {
                hashtab_T *ht = &d->dv_hashtab;
                hashitem_T *hi;
                int n = ht->ht_used; /* remaining items */
                lua_pop(L, 1); /* nil */
                lua_newtable(L);
                lua_pushlightuserdata(L, (void *) d);
                lua_pushvalue(L, -2);
                lua_rawset(L, LUA_ENVIRONINDEX);
                for (hi = ht->ht_array; n > 0; hi++)
                {
                    if (!HASHITEM_EMPTY(hi))
                    {
                        dictitem_T *di = dict_lookup(hi);
                        luaV_pushtypval(L, &di->di_tv);
                        lua_setfield(L, -2, (char *) hi->hi_key);
                        n--;
                    }
                }
            }
        }
        else lua_pushnil(L);
        break;
    }
    default:
        luaL_error(L, "invalid type");
    }
}