예제 #1
0
int
dict_find(const ref * pdref, const ref * pkey, ref ** ppvalue)
{
    dict *pdict = pdref->value.pdict;
    int code = real_dict_find(pdref, pkey, ppvalue);

    stats_dict.lookups++;
    if (r_has_type(pkey, t_name) && dict_is_packed(pdict)) {
        uint nidx = name_index(dict_mem(pdict), pkey);
        uint hash =
        dict_hash_mod(dict_name_index_hash(nidx), npairs(pdict)) + 1;

        if (pdict->keys.value.packed[hash] ==
            pt_tag(pt_literal_name) + nidx
            )
            stats_dict.probe1++;
        else if (pdict->keys.value.packed[hash - 1] ==
                 pt_tag(pt_literal_name) + nidx
            )
            stats_dict.probe2++;
    }
    /* Do the cheap flag test before the expensive remainder test. */
    if (gs_debug_c('d') && !(stats_dict.lookups % 1000))
        dlprintf3("[d]lookups=%ld probe1=%ld probe2=%ld\n",
                  stats_dict.lookups, stats_dict.probe1, stats_dict.probe2);
    return code;
}
예제 #2
0
/* Enumerate the next element of a dictionary. */
int
dict_next(const ref * pdref, int index, ref * eltp /* ref eltp[2] */ )
{
    dict *pdict = pdref->value.pdict;
    ref *vp = pdict->values.value.refs + index;

    while (vp--, --index >= 0) {
        array_get(dict_mem(pdict), &pdict->keys, (long)index, eltp);
        /* Make sure this is a valid entry. */
        if (r_has_type(eltp, t_name) ||
            (!dict_is_packed(pdict) && !r_has_type(eltp, t_null))
            ) {
            eltp[1] = *vp;
            if_debug6m('d', dict_mem(pdict), "[d]0x%lx: index %d: %lx %lx, %lx %lx\n",
                       (ulong) pdict, index,
                       ((ulong *) eltp)[0], ((ulong *) eltp)[1],
                       ((ulong *) vp)[0], ((ulong *) vp)[1]);
            return index;
        }
    }
    return -1;			/* no more elements */
}
예제 #3
0
/*
 * Enter a key-value pair where the key is a (constant) C string.
 */
int
dict_put_string(ref * pdref, const char *kstr, const ref * pvalue,
                dict_stack_t *pds)
{
    int code;
    ref kname;
    dict *pdict = pdref->value.pdict;

    if ((code = name_ref(dict_mem(pdict),
                         (const byte *)kstr, strlen(kstr), &kname, 0)) < 0)
        return code;
    return dict_put(pdref, &kname, pvalue, pds);
}
예제 #4
0
/* If the index designates an unoccupied entry, return gs_error_undefined. */
int
dict_index_entry(const ref * pdref, int index, ref * eltp /* ref eltp[2] */ )
{
    const dict *pdict = pdref->value.pdict;

    array_get(dict_mem(pdict), &pdict->keys, (long)(index + 1), eltp);
    if (r_has_type(eltp, t_name) ||
        (!dict_is_packed(pdict) && !r_has_type(eltp, t_null))
        ) {
        eltp[1] = pdict->values.value.refs[index + 1];
        return 0;
    }
    return gs_error_undefined;
}
예제 #5
0
/*
 * Look up a (constant) C string in a dictionary.
 * Return 1 if found, <= 0 if not.
 */
int
dict_find_string(const ref * pdref, const char *kstr, ref ** ppvalue)
{
    int code;
    ref kname;
    if ( pdref != 0 ) {
        dict *pdict = pdref->value.pdict;

        if ((code = name_ref(dict_mem(pdict),
                             (const byte *)kstr, strlen(kstr), &kname, -1)) < 0)
            return code;
        code = dict_find(pdref, &kname, ppvalue);
        if (code == gs_error_dictfull)
            return_error(gs_error_undefined);
        return code;
    }
    return 0;
}
예제 #6
0
/*
 * Enter a key-value pair in a dictionary.
 * See idict.h for the possible return values.
 */
int
dict_put(ref * pdref /* t_dictionary */ , const ref * pkey, const ref * pvalue,
         dict_stack_t *pds)
{
    dict *pdict = pdref->value.pdict;
    gs_ref_memory_t *mem = dict_memory(pdict);
    gs_memory_t *pmem = dict_mem(pdict);
    int rcode = 0;
    int code;
    ref *pvslot, kname;

    /* Check the value. */
    store_check_dest(pdref, pvalue);
  top:if ((code = dict_find(pdref, pkey, &pvslot)) <= 0) {	/* not found *//* Check for overflow */
        uint index;

        switch (code) {
            case 0:
                break;
            case gs_error_dictfull:
                if (!pmem->gs_lib_ctx->dict_auto_expand)
                    return_error(gs_error_dictfull);
                code = dict_grow(pdref, pds);
                if (code < 0)
                    return code;
                goto top;	/* keep things simple */
            default:		/* gs_error_typecheck */
                return code;
        }
        index = pvslot - pdict->values.value.refs;
        /* If the key is a string, convert it to a name. */
        if (r_has_type(pkey, t_string)) {
            int code;

            if (!r_has_attr(pkey, a_read))
                return_error(gs_error_invalidaccess);
            code = name_from_string(pmem, pkey, &kname);
            if (code < 0)
                return code;
            pkey = &kname;
        }
        if (dict_is_packed(pdict)) {
            ref_packed *kp;

            if (!r_has_type(pkey, t_name) ||
                name_index(pmem, pkey) > packed_name_max_index
                ) {		/* Change to unpacked representation. */
                int code = dict_unpack(pdref, pds);

                if (code < 0)
                    return code;
                goto top;
            }
            kp = pdict->keys.value.writable_packed + index;
            if (ref_must_save_in(mem, &pdict->keys)) {	/* See initial comment for why it is safe */
                /* not to save the change if the keys */
                /* array itself is new. */
                ref_do_save_in(mem, &pdict->keys, kp, "dict_put(key)");
            }
            *kp = pt_tag(pt_literal_name) + name_index(pmem, pkey);
        } else {
            ref *kp = pdict->keys.value.refs + index;

            if_debug2m('d', (const gs_memory_t *)mem, "[d]0x%lx: fill key at 0x%lx\n",
                       (ulong) pdict, (ulong) kp);
            store_check_dest(pdref, pkey);
            ref_assign_old_in(mem, &pdict->keys, kp, pkey,
                              "dict_put(key)");	/* set key of pair */
        }
        ref_save_in(mem, pdref, &pdict->count, "dict_put(count)");
        pdict->count.value.intval++;
        /* If the key is a name, update its 1-element cache. */
        if (r_has_type(pkey, t_name)) {
            name *pname = pkey->value.pname;

            if (pname->pvalue == pv_no_defn &&
                CAN_SET_PVALUE_CACHE(pds, pdref, mem)
                ) {		/* Set the cache. */
                if_debug0m('d', (const gs_memory_t *)mem, "[d]set cache\n");
                pname->pvalue = pvslot;
            } else {		/* The cache can't be used. */
                if_debug0m('d', (const gs_memory_t *)mem, "[d]no cache\n");
                pname->pvalue = pv_other;
            }
        }
        rcode = 1;
    }
    if_debug8m('d', (const gs_memory_t *)mem,
               "[d]0x%lx: put key 0x%lx 0x%lx\n  value at 0x%lx: old 0x%lx 0x%lx, new 0x%lx 0x%lx\n",
               (ulong) pdref->value.pdict,
               ((const ulong *)pkey)[0], ((const ulong *)pkey)[1],
               (ulong) pvslot,
               ((const ulong *)pvslot)[0], ((const ulong *)pvslot)[1],
               ((const ulong *)pvalue)[0], ((const ulong *)pvalue)[1]);
    ref_assign_old_in(mem, &pdref->value.pdict->values, pvslot, pvalue,
                      "dict_put(value)");
    return rcode;
}
예제 #7
0
/*
 * Look up a key in a dictionary.  Store a pointer to the value slot
 * where found, or to the (value) slot for inserting.
 * See idict.h for the possible return values.
 */
int
dict_find(const ref * pdref, const ref * pkey,
          ref ** ppvalue /* result is stored here */ )
{
    dict *pdict = pdref->value.pdict;
    uint size = npairs(pdict);
    register int etype;
    uint nidx;
    ref_packed kpack;
    uint hash;
    int ktype;
    const gs_memory_t *mem = dict_mem(pdict);

    /* Compute hash.  The only types we bother with are strings, */
    /* names, and (unlikely, but worth checking for) integers. */
    switch (r_type(pkey)) {
    case t_name:
        nidx = name_index(mem, pkey);
    nh:
        hash = dict_name_index_hash(nidx);
        kpack = packed_name_key(nidx);
        ktype = t_name;
        break;
    case t_string:		/* convert to a name first */
        {
            ref nref;
            int code;

            if (!r_has_attr(pkey, a_read))
                return_error(gs_error_invalidaccess);
            code = name_ref(mem, pkey->value.bytes, r_size(pkey), &nref, 1);
            if (code < 0)
                return code;
            nidx = name_index(mem, &nref);
        }
        goto nh;
    case t_real:
        /*
         * Make sure that equal reals and integers hash the same.
         */
        {
            int expt, i;
            double mant = frexp(pkey->value.realval, &expt);
            /*
             * The value is mant * 2^expt, where 0.5 <= mant < 1,
             * or else expt == mant == 0.
             */

            if (expt < sizeof(long) * 8 || pkey->value.realval == min_long)
                i = (int)pkey->value.realval;
            else
                i = (int)(mant * min_long); /* MSVC 6.00.8168.0 cannot compile this */
            hash = (uint)i * 30503;         /*   with -O2 as a single expression    */
        }
        goto ih;
    case t_integer:
        hash = (uint)pkey->value.intval * 30503;
    ih:
        kpack = packed_key_impossible;
        ktype = -1;
        nidx = 0;		/* only to pacify gcc */
        break;
    case t_null:		/* not allowed as a key */
        return_error(gs_error_typecheck);
    default:
        hash = r_btype(pkey) * 99;	/* yech */
        kpack = packed_key_impossible;
        ktype = -1;
        nidx = 0;		/* only to pacify gcc */
    }
    /* Search the dictionary */
    if (dict_is_packed(pdict)) {
        const ref_packed *pslot = 0;

#	define found *ppvalue = packed_search_value_pointer; return 1
#	define deleted if (pslot == 0) pslot = kp
#	define missing goto miss
#	include "idicttpl.h"
#	undef missing
#	undef deleted
#	undef found
        /*
         * Double wraparound, dict is full.
         * Note that even if there was an empty slot (pslot != 0),
         * we must return dictfull if length = maxlength.
         */
        if (pslot == 0 || d_length(pdict) == d_maxlength(pdict))
            return_error(gs_error_dictfull);
        *ppvalue = pdict->values.value.refs + (pslot - kbot);
        return 0;
      miss:			/* Key is missing, not double wrap.  See above re dictfull. */
        if (d_length(pdict) == d_maxlength(pdict))
            return_error(gs_error_dictfull);
        if (pslot == 0)
            pslot = kp;
        *ppvalue = pdict->values.value.refs + (pslot - kbot);
        return 0;
    } else {
        ref *kbot = pdict->keys.value.refs;
        register ref *kp;
        ref *pslot = 0;
        int wrap = 0;

        for (kp = kbot + dict_hash_mod(hash, size) + 2;;) {
            --kp;
            if ((etype = r_type(kp)) == ktype) {	/* Fast comparison if both keys are names */
                if (name_index(mem, kp) == nidx) {
                    *ppvalue = pdict->values.value.refs + (kp - kbot);
                    return 1;
                }
            } else if (etype == t_null) {	/* Empty, deleted, or wraparound. */
                /* Figure out which. */
                if (kp == kbot) {	/* wrap */
                    if (wrap++) {	/* wrapped twice */
                        if (pslot == 0)
                            return_error(gs_error_dictfull);
                        break;
                    }
                    kp += size + 1;
                } else if (r_has_attr(kp, a_executable)) {	/* Deleted entry, save the slot. */
                    if (pslot == 0)
                        pslot = kp;
                } else		/* key not found */
                    break;
            } else {
                if (obj_eq(mem, kp, pkey)) {
                    *ppvalue = pdict->values.value.refs + (kp - kbot);
                    return 1;
                }
            }
        }
        if (d_length(pdict) == d_maxlength(pdict))
            return_error(gs_error_dictfull);
        *ppvalue = pdict->values.value.refs +
            ((pslot != 0 ? pslot : kp) - kbot);
        return 0;
    }
}
예제 #8
0
파일: idstack.c 프로젝트: 99years/plan9
/*
 * Look up a name on the dictionary stack.
 * Return the pointer to the value if found, 0 if not.
 */
ref *
dstack_find_name_by_index(dict_stack_t * pds, uint nidx)
{
    ds_ptr pdref = pds->stack.p;

/* Since we know the hash function is the identity function, */
/* there's no point in allocating a separate variable for it. */
#define hash dict_name_index_hash(nidx)
    ref_packed kpack = packed_name_key(nidx);

    do {
	dict *pdict = pdref->value.pdict;
	uint size = npairs(pdict);
	const gs_memory_t *mem = dict_mem(pdict);
#ifdef DEBUG
	if (gs_debug_c('D')) {
	    ref dnref;

	    name_index_ref(mem, nidx, &dnref);
	    dlputs("[D]lookup ");
	    debug_print_name(mem, &dnref);
	    dprintf3(" in 0x%lx(%u/%u)\n",
		     (ulong) pdict, dict_length(pdref),
		     dict_maxlength(pdref));
	}
#endif
#define INCR_DEPTH(pdref)\
  INCR(depth[min(MAX_STATS_DEPTH, pds->stack.p - pdref)])
	if (dict_is_packed(pdict)) {
	    packed_search_1(INCR_DEPTH(pdref),
			    return packed_search_value_pointer,
			    DO_NOTHING, goto miss);
	    packed_search_2(INCR_DEPTH(pdref),
			    return packed_search_value_pointer,
			    DO_NOTHING, break);
	  miss:;
	} else {
	    ref *kbot = pdict->keys.value.refs;
	    register ref *kp;
	    int wrap = 0;

	    /* Search the dictionary */
	    for (kp = kbot + dict_hash_mod(hash, size) + 2;;) {
		--kp;
		if (r_has_type(kp, t_name)) {
		    if (name_index(mem, kp) == nidx) {
			INCR_DEPTH(pdref);
			return pdict->values.value.refs + (kp - kbot);
		    }
		} else if (r_has_type(kp, t_null)) {	/* Empty, deleted, or wraparound. */
		    /* Figure out which. */
		    if (!r_has_attr(kp, a_executable))
			break;
		    if (kp == kbot) {	/* wrap */
			if (wrap++)
			    break;	/* 2 wraps */
			kp += size + 1;
		    }
		}
	    }
	}
#undef INCR_DEPTH
    }