Esempio n. 1
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;
    }
}
Esempio n. 2
0
/*
 * 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
    }