Beispiel #1
0
//
//  Find_Key: C
// 
// Returns hash index (either the match or the new one).
// A return of zero is valid (as a hash index);
// 
// Wide: width of record (normally 2, a key and a value).
// 
// Modes:
//     0 - search, return hash if found or not
//     1 - search, return hash, else return -1 if not
//     2 - search, return hash, else append value and return -1
//
REBINT Find_Key(REBSER *series, REBSER *hser, const REBVAL *key, REBINT wide, REBCNT cased, REBYTE mode)
{
    REBCNT *hashes;
    REBCNT skip;
    REBCNT hash;
    REBCNT len;
    REBCNT n;
    REBVAL *val;

    // Compute hash for value:
    len = hser->tail;
    hash = Hash_Value(key, len);
    if (!hash) fail (Error_Has_Bad_Type(key));

    // Determine skip and first index:
    skip  = (len == 0) ? 0 : (hash & 0x0000FFFF) % len;
    if (skip == 0) skip = 1;
    hash = (len == 0) ? 0 : (hash & 0x00FFFF00) % len;

    // Scan hash table for match:
    hashes = (REBCNT*)hser->data;
    if (ANY_WORD(key)) {
        while ((n = hashes[hash])) {
            val = BLK_SKIP(series, (n-1) * wide);
            if (
                ANY_WORD(val) &&
                (VAL_WORD_SYM(key) == VAL_WORD_SYM(val) ||
                (!cased && VAL_WORD_CANON(key) == VAL_WORD_CANON(val)))
            ) return hash;
            hash += skip;
            if (hash >= len) hash -= len;
        }
    }
    else if (ANY_BINSTR(key)) {
        while ((n = hashes[hash])) {
            val = BLK_SKIP(series, (n-1) * wide);
            if (
                VAL_TYPE(val) == VAL_TYPE(key)
                && 0 == Compare_String_Vals(key, val, (REBOOL)(!IS_BINARY(key) && !cased))
            ) return hash;
            hash += skip;
            if (hash >= len) hash -= len;
        }
    } else {
        while ((n = hashes[hash])) {
            val = BLK_SKIP(series, (n-1) * wide);
            if (VAL_TYPE(val) == VAL_TYPE(key) && 0 == Cmp_Value(key, val, !cased)) return hash;
            hash += skip;
            if (hash >= len) hash -= len;
        }
    }

    // Append new value the target series:
    if (mode > 1) {
        hashes[hash] = SERIES_TAIL(series) + 1;
        Append_Values_Len(series, key, wide);
    }

    return (mode > 0) ? NOT_FOUND : hash;
}
Beispiel #2
0
//
//  CT_String: C
//
REBINT CT_String(const RELVAL *a, const RELVAL *b, REBINT mode)
{
    REBINT num;

    num = Compare_String_Vals(a, b, NOT(mode == 1));

    if (mode >= 0) return (num == 0) ? 1 : 0;
    if (mode == -1) return (num >= 0) ? 1 : 0;
    return (num > 0) ? 1 : 0;
}
Beispiel #3
0
*/	REBINT CT_String(REBVAL *a, REBVAL *b, REBINT mode)
/*
***********************************************************************/
{
	REBINT num;

	if (mode == 3)
		return VAL_SERIES(a) == VAL_SERIES(b) && VAL_INDEX(a) == VAL_INDEX(b);

	num = Compare_String_Vals(a, b, (REBOOL) !(mode > 1));
	if (mode >= 0) return (num == 0);
	if (mode == -1) return (num >= 0);
	return (num > 0);
}
Beispiel #4
0
//
//  Find_Entry: C
// 
// Try to find the entry in the map. If not found
// and val is SET, create the entry and store the key and
// val.
// 
// RETURNS: the index to the VALUE or zero if there is none.
//
static REBCNT Find_Entry(REBSER *series, REBVAL *key, REBVAL *val)
{
    REBSER *hser = series->extra.series; // can be null
    REBCNT *hashes;
    REBCNT hash;
    REBVAL *v;
    REBCNT n;

    if (IS_NONE(key)) return 0;

    // We may not be large enough yet for the hash table to
    // be worthwhile, so just do a linear search:
    if (!hser) {
        if (series->tail < MIN_DICT*2) {
            v = BLK_HEAD(series);
            if (ANY_WORD(key)) {
                for (n = 0; n < series->tail; n += 2, v += 2) {
                    if (
                        ANY_WORD(v)
                        && SAME_SYM(VAL_WORD_SYM(key), VAL_WORD_SYM(v))
                    ) {
                        if (val) *++v = *val;
                        return n/2+1;
                    }
                }
            }
            else if (ANY_BINSTR(key)) {
                for (n = 0; n < series->tail; n += 2, v += 2) {
                    if (VAL_TYPE(key) == VAL_TYPE(v) && 0 == Compare_String_Vals(key, v, (REBOOL)!IS_BINARY(v))) {
                        if (val)
                            *++v = *val;

                        return n/2+1;
                    }
                }
            }
            else if (IS_INTEGER(key)) {
                for (n = 0; n < series->tail; n += 2, v += 2) {
                    if (IS_INTEGER(v) && VAL_INT64(key) == VAL_INT64(v)) {
                        if (val) *++v = *val;
                        return n/2+1;
                    }
                }
            }
            else if (IS_CHAR(key)) {
                for (n = 0; n < series->tail; n += 2, v += 2) {
                    if (IS_CHAR(v) && VAL_CHAR(key) == VAL_CHAR(v)) {
                        if (val) *++v = *val;
                        return n/2+1;
                    }
                }
            }
            else
                fail (Error_Has_Bad_Type(key));

            if (!val) return 0;
            Append_Value(series, key);
            Append_Value(series, val); // does not copy value, e.g. if string
            return series->tail/2;
        }

        // Add hash table:
        //Print("hash added %d", series->tail);
        series->extra.series = hser = Make_Hash_Sequence(series->tail);
        MANAGE_SERIES(hser);
        Rehash_Hash(series);
    }

    // Get hash table, expand it if needed:
    if (series->tail > hser->tail/2) {
        Expand_Hash(hser); // modifies size value
        Rehash_Hash(series);
    }

    hash = Find_Key(series, hser, key, 2, 0, 0);
    hashes = (REBCNT*)hser->data;
    n = hashes[hash];

    // Just a GET of value:
    if (!val) return n;

    // Must set the value:
    if (n) {  // re-set it:
        *BLK_SKIP(series, ((n-1)*2)+1) = *val; // set it
        return n;
    }

    // Create new entry:
    Append_Value(series, key);
    Append_Value(series, val);  // does not copy value, e.g. if string

    return (hashes[hash] = series->tail/2);
}
Beispiel #5
0
*/	REBINT Cmp_Value(REBVAL *s, REBVAL *t, REBFLG is_case)
/*
**		Compare two values and return the difference.
**
**		is_case TRUE for case sensitive compare
**
***********************************************************************/
{
	REBDEC	d1, d2;

	if (VAL_TYPE(t) != VAL_TYPE(s) && !(IS_NUMBER(s) && IS_NUMBER(t)))
		return VAL_TYPE(s) - VAL_TYPE(t);

	switch(VAL_TYPE(s)) {

	case REB_INTEGER:
		if (IS_DECIMAL(t)) {
			d1 = (REBDEC)VAL_INT64(s);
			d2 = VAL_DECIMAL(t);
			goto chkDecimal;
		}
		return THE_SIGN(VAL_INT64(s) - VAL_INT64(t));

	case REB_LOGIC:
		return VAL_LOGIC(s) - VAL_LOGIC(t);

	case REB_CHAR:
		if (is_case) return THE_SIGN(VAL_CHAR(s) - VAL_CHAR(t));
		return THE_SIGN((REBINT)(UP_CASE(VAL_CHAR(s)) - UP_CASE(VAL_CHAR(t))));

	case REB_DECIMAL:
	case REB_MONEY:
			d1 = VAL_DECIMAL(s);
		if (IS_INTEGER(t))
			d2 = (REBDEC)VAL_INT64(t);
		else
			d2 = VAL_DECIMAL(t);
chkDecimal:
		if (Eq_Decimal(d1, d2))
			return 0;
		if (d1 < d2)
			return -1;
		return 1;

	case REB_PAIR:
		return Cmp_Pair(s, t);

	case REB_EVENT:
		return Cmp_Event(s, t);

	case REB_GOB:
		return Cmp_Gob(s, t);

	case REB_TUPLE:
		return Cmp_Tuple(s, t);

	case REB_TIME:
		return Cmp_Time(s, t);

	case REB_DATE:
		return Cmp_Date(s, t);

	case REB_BLOCK:
	case REB_PAREN:
	case REB_MAP:
	case REB_PATH:
	case REB_SET_PATH:
	case REB_GET_PATH:
	case REB_LIT_PATH:
		return Cmp_Block(s, t, is_case);

	case REB_STRING:
	case REB_FILE:
	case REB_EMAIL:
	case REB_URL:
	case REB_TAG:
		return Compare_String_Vals(s, t, (REBOOL)!is_case);

	case REB_BITSET:
	case REB_BINARY:
	case REB_IMAGE:
		return Compare_Binary_Vals(s, t);

	case REB_VECTOR:
		return Compare_Vector(s, t);

	case REB_DATATYPE:
		return VAL_DATATYPE(s) - VAL_DATATYPE(t);

	case REB_WORD:
	case REB_SET_WORD:
	case REB_GET_WORD:
	case REB_LIT_WORD:
	case REB_REFINEMENT:
	case REB_ISSUE:
		return Compare_Word(s,t,is_case);

	case REB_ERROR:
		return VAL_ERR_NUM(s) - VAL_ERR_NUM(s);

	case REB_OBJECT:
	case REB_MODULE:
	case REB_PORT:
		return VAL_OBJ_FRAME(s) - VAL_OBJ_FRAME(t);

	case REB_NATIVE:
		return &VAL_FUNC_CODE(s) - &VAL_FUNC_CODE(t);

	case REB_ACTION:
	case REB_COMMAND:
	case REB_OP:
	case REB_FUNCTION:
		return VAL_FUNC_BODY(s) - VAL_FUNC_BODY(t);

	case REB_NONE:
	case REB_UNSET:
	case REB_END:
	default:
		break;

	}
	return 0;
}
Beispiel #6
0
*/	REBINT Find_Key(REBSER *series, REBSER *hser, REBVAL *key, REBINT wide, REBCNT cased, REBYTE mode)
/*
**		Returns hash index (either the match or the new one).
**		A return of zero is valid (as a hash index);
**
**		Wide: width of record (normally 2, a key and a value).
**
**		Modes:
**			0 - search, return hash if found or not
**			1 - search, return hash, else return -1 if not
**			2 - search, return hash, else append value and return -1
**
***********************************************************************/
{
	REBCNT *hashes;
	REBCNT skip;
	REBCNT hash;
	REBCNT len;
	REBCNT n;
	REBVAL *val;

	// Compute hash for value:
	len = hser->tail;
	hash = Hash_Value(key, len);
	if (!hash) Trap_Type_DEAD_END(key);

	// Determine skip and first index:
	skip  = (len == 0) ? 0 : (hash & 0x0000FFFF) % len;
	if (skip == 0) skip = 1;
	hash = (len == 0) ? 0 : (hash & 0x00FFFF00) % len;

	// Scan hash table for match:
	hashes = (REBCNT*)hser->data;
	if (ANY_WORD(key)) {
		while ((n = hashes[hash])) {
			val = BLK_SKIP(series, (n-1) * wide);
			if (
				ANY_WORD(val) &&
				(VAL_WORD_SYM(key) == VAL_BIND_SYM(val) ||
				(!cased && VAL_WORD_CANON(key) == VAL_BIND_CANON(val)))
			) return hash;
			hash += skip;
			if (hash >= len) hash -= len;
		}
	}
	else if (ANY_BINSTR(key)) {
		while ((n = hashes[hash])) {
			val = BLK_SKIP(series, (n-1) * wide);
			if (
				VAL_TYPE(val) == VAL_TYPE(key)
				&& 0 == Compare_String_Vals(key, val, (REBOOL)(!IS_BINARY(key) && !cased))
			) return hash;
			hash += skip;
			if (hash >= len) hash -= len;
		}
	} else {
		while ((n = hashes[hash])) {
			val = BLK_SKIP(series, (n-1) * wide);
			if (VAL_TYPE(val) == VAL_TYPE(key) && 0 == Cmp_Value(key, val, !cased)) return hash;
			hash += skip;
			if (hash >= len) hash -= len;
		}
	}

	// Append new value the target series:
	if (mode > 1) {
		hashes[hash] = SERIES_TAIL(series)+1;
		//Debug_Num("hash:", hashes[hash]);
		Append_Series(series, (REBYTE*)key, wide);
		//Dump_Series(series, "hash");
	}

	return (mode > 0) ? NOT_FOUND : hash;
}
Beispiel #7
0
*/	static REBCNT Find_Entry(REBSER *series, REBVAL *key, REBVAL *val)
/*
**		Try to find the entry in the map. If not found
**		and val is SET, create the entry and store the key and
**		val.
**
**		RETURNS: the index to the VALUE or zero if there is none.
**
***********************************************************************/
{
	REBSER *hser = series->extra.series; // can be null
	REBCNT *hashes;
	REBCNT hash;
	REBVAL *v;
	REBCNT n;

	if (IS_NONE(key)) return 0;

	// We may not be large enough yet for the hash table to
	// be worthwhile, so just do a linear search:
	if (!hser) {
		if (series->tail < MIN_DICT*2) {
			v = BLK_HEAD(series);
			if (ANY_WORD(key)) {
				for (n = 0; n < series->tail; n += 2, v += 2) {
					if (ANY_WORD(v) && SAME_SYM(key, v)) {
						if (val) *++v = *val;
						return n/2+1;
					}
				}
			}
			else if (ANY_BINSTR(key)) {
				for (n = 0; n < series->tail; n += 2, v += 2) {
					if (VAL_TYPE(key) == VAL_TYPE(v) && 0 == Compare_String_Vals(key, v, (REBOOL)!IS_BINARY(v))) {
						if (val) {
							*++v = *val;
//							VAL_SERIES(v) = Copy_Series_Value(val);
//							VAL_INDEX(v) = 0;
						}
						return n/2+1;
					}
				}
			}
			else if (IS_INTEGER(key)) {
				for (n = 0; n < series->tail; n += 2, v += 2) {
					if (IS_INTEGER(v) && VAL_INT64(key) == VAL_INT64(v)) {
						if (val) *++v = *val;
						return n/2+1;
					}
				}
			}
			else if (IS_CHAR(key)) {
				for (n = 0; n < series->tail; n += 2, v += 2) {
					if (IS_CHAR(v) && VAL_CHAR(key) == VAL_CHAR(v)) {
						if (val) *++v = *val;
						return n/2+1;
					}
				}
			}
			else Trap_Type_DEAD_END(key);

			if (!val) return 0;
			Append_Value(series, key);
			Append_Value(series, val); // no Copy_Series_Value(val) on strings
			return series->tail/2;
		}

		// Add hash table:
		//Print("hash added %d", series->tail);
		series->extra.series = hser = Make_Hash_Array(series->tail);
		Rehash_Hash(series);
	}

	// Get hash table, expand it if needed:
	if (series->tail > hser->tail/2) {
		Expand_Hash(hser); // modifies size value
		Rehash_Hash(series);
	}

	hash = Find_Key(series, hser, key, 2, 0, 0);
	hashes = (REBCNT*)hser->data;
	n = hashes[hash];

	// Just a GET of value:
	if (!val) return n;

	// Must set the value:
	if (n) {  // re-set it:
		*BLK_SKIP(series, ((n-1)*2)+1) = *val; // set it
		return n;
	}

	// Create new entry:
	Append_Value(series, key);
	Append_Value(series, val);  // no Copy_Series_Value(val) on strings

	return (hashes[hash] = series->tail/2);
}
Beispiel #8
0
//
//  Cmp_Value: C
// 
// Compare two values and return the difference.
// 
// is_case TRUE for case sensitive compare
//
REBINT Cmp_Value(const RELVAL *s, const RELVAL *t, REBOOL is_case)
{
    REBDEC  d1, d2;

    if (VAL_TYPE(t) != VAL_TYPE(s) && !(ANY_NUMBER(s) && ANY_NUMBER(t)))
        return VAL_TYPE(s) - VAL_TYPE(t);

    assert(NOT_END(s) && NOT_END(t));

    switch(VAL_TYPE(s)) {

    case REB_INTEGER:
        if (IS_DECIMAL(t)) {
            d1 = (REBDEC)VAL_INT64(s);
            d2 = VAL_DECIMAL(t);
            goto chkDecimal;
        }
        return THE_SIGN(VAL_INT64(s) - VAL_INT64(t));

    case REB_LOGIC:
        return VAL_LOGIC(s) - VAL_LOGIC(t);

    case REB_CHAR:
        if (is_case) return THE_SIGN(VAL_CHAR(s) - VAL_CHAR(t));
        return THE_SIGN((REBINT)(UP_CASE(VAL_CHAR(s)) - UP_CASE(VAL_CHAR(t))));

    case REB_PERCENT:
    case REB_DECIMAL:
    case REB_MONEY:
        if (IS_MONEY(s))
            d1 = deci_to_decimal(VAL_MONEY_AMOUNT(s));
        else
            d1 = VAL_DECIMAL(s);
        if (IS_INTEGER(t))
            d2 = cast(REBDEC, VAL_INT64(t));
        else if (IS_MONEY(t))
            d2 = deci_to_decimal(VAL_MONEY_AMOUNT(t));
        else
            d2 = VAL_DECIMAL(t);
chkDecimal:
        if (Eq_Decimal(d1, d2))
            return 0;
        if (d1 < d2)
            return -1;
        return 1;

    case REB_PAIR:
        return Cmp_Pair(s, t);

    case REB_EVENT:
        return Cmp_Event(s, t);

    case REB_GOB:
        return Cmp_Gob(s, t);

    case REB_TUPLE:
        return Cmp_Tuple(s, t);

    case REB_TIME:
        return Cmp_Time(s, t);

    case REB_DATE:
        return Cmp_Date(s, t);

    case REB_BLOCK:
    case REB_GROUP:
    case REB_MAP:
    case REB_PATH:
    case REB_SET_PATH:
    case REB_GET_PATH:
    case REB_LIT_PATH:
        return Cmp_Array(s, t, is_case);

    case REB_STRING:
    case REB_FILE:
    case REB_EMAIL:
    case REB_URL:
    case REB_TAG:
        return Compare_String_Vals(s, t, NOT(is_case));

    case REB_BITSET:
    case REB_BINARY:
    case REB_IMAGE:
        return Compare_Binary_Vals(s, t);

    case REB_VECTOR:
        return Compare_Vector(s, t);

    case REB_DATATYPE:
        return VAL_TYPE_KIND(s) - VAL_TYPE_KIND(t);

    case REB_WORD:
    case REB_SET_WORD:
    case REB_GET_WORD:
    case REB_LIT_WORD:
    case REB_REFINEMENT:
    case REB_ISSUE:
        return Compare_Word(s,t,is_case);

    case REB_ERROR:
        return VAL_ERR_NUM(s) - VAL_ERR_NUM(t);

    case REB_OBJECT:
    case REB_MODULE:
    case REB_PORT:
        return VAL_CONTEXT(s) - VAL_CONTEXT(t);

    case REB_FUNCTION:
        return VAL_FUNC_PARAMLIST(s) - VAL_FUNC_PARAMLIST(t);

    case REB_LIBRARY:
        return VAL_LIBRARY(s) - VAL_LIBRARY(t);

    case REB_STRUCT:
        return Cmp_Struct(s, t);

    case REB_BLANK:
    case REB_MAX_VOID:
    default:
        break;

    }
    return 0;
}