Exemplo n.º 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;
}
Exemplo n.º 2
0
*/	static void Loop_Number(REBVAL *out, REBVAL *var, REBSER* body, REBVAL *start, REBVAL *end, REBVAL *incr)
/*
***********************************************************************/
{
	REBDEC s;
	REBDEC e;
	REBDEC i;

	if (IS_INTEGER(start))
		s = cast(REBDEC, VAL_INT64(start));
	else if (IS_DECIMAL(start) || IS_PERCENT(start))
		s = VAL_DECIMAL(start);
	else
		raise Error_Invalid_Arg(start);

	if (IS_INTEGER(end))
		e = cast(REBDEC, VAL_INT64(end));
	else if (IS_DECIMAL(end) || IS_PERCENT(end))
		e = VAL_DECIMAL(end);
	else
		raise Error_Invalid_Arg(end);

	if (IS_INTEGER(incr))
		i = cast(REBDEC, VAL_INT64(incr));
	else if (IS_DECIMAL(incr) || IS_PERCENT(incr))
		i = VAL_DECIMAL(incr);
	else
		raise Error_Invalid_Arg(incr);

	VAL_SET(var, REB_DECIMAL);

	SET_NONE(out); // Default result to NONE if the loop does not run

	for (; (i > 0.0) ? s <= e : s >= e; s += i) {
		VAL_DECIMAL(var) = s;

		if (Do_Block_Throws(out, body, 0)) {
			if (Loop_Throw_Should_Return(out)) break;
		}

		if (!IS_DECIMAL(var)) raise Error_Has_Bad_Type(var);
		s = VAL_DECIMAL(var);
	}
}
Exemplo n.º 3
0
*/	static void Loop_Integer(REBVAL *out, REBVAL *var, REBSER* body, REBI64 start, REBI64 end, REBI64 incr)
/*
***********************************************************************/
{
	VAL_SET(var, REB_INTEGER);

	SET_NONE(out); // Default result to NONE if the loop does not run

	while ((incr > 0) ? start <= end : start >= end) {
		VAL_INT64(var) = start;

		if (Do_Block_Throws(out, body, 0)) {
			if (Loop_Throw_Should_Return(out)) break;
		}

		if (!IS_INTEGER(var)) raise Error_Has_Bad_Type(var);
		start = VAL_INT64(var);

		if (REB_I64_ADD_OF(start, incr, &start))
			raise Error_0(RE_OVERFLOW);
	}
}
Exemplo n.º 4
0
*/	REBFLG MT_Struct(REBVAL *out, REBVAL *data, enum Reb_Kind type)
/*
 * Format:
 * make struct! [
 *     field1 [type1]
 *     field2: [type2] field2-init-value
 * 	   field3: [struct [field1 [type1]]]
 * 	   field4: [type1[3]]
 * 	   ...
 * ]
***********************************************************************/
{
	//RL_Print("%s\n", __func__);
	REBINT max_fields = 16;

	VAL_STRUCT_FIELDS(out) = Make_Series(
		max_fields, sizeof(struct Struct_Field), MKS_NONE
	);
	MANAGE_SERIES(VAL_STRUCT_FIELDS(out));

	if (IS_BLOCK(data)) {
		//if (Reduce_Block_No_Set_Throws(VAL_SERIES(data), 0, NULL))...
		//data = DS_POP;
		REBVAL *blk = VAL_BLK_DATA(data);
		REBINT field_idx = 0; /* for field index */
		u64 offset = 0; /* offset in data */
		REBCNT eval_idx = 0; /* for spec block evaluation */
		REBVAL *init = NULL; /* for result to save in data */
		REBOOL expect_init = FALSE;
		REBINT raw_size = -1;
		REBUPT raw_addr = 0;
		REBCNT alignment = 0;

		VAL_STRUCT_SPEC(out) = Copy_Array_Shallow(VAL_SERIES(data));
		VAL_STRUCT_DATA(out) = Make_Series(
			1, sizeof(struct Struct_Data), MKS_NONE
		);
		EXPAND_SERIES_TAIL(VAL_STRUCT_DATA(out), 1);

		VAL_STRUCT_DATA_BIN(out) = Make_Series(max_fields << 2, 1, MKS_NONE);
		VAL_STRUCT_OFFSET(out) = 0;

		// We tell the GC to manage this series, but it will not cause a
		// synchronous garbage collect.  Still, when's the right time?
		ENSURE_SERIES_MANAGED(VAL_STRUCT_SPEC(out));
		MANAGE_SERIES(VAL_STRUCT_DATA(out));
		MANAGE_SERIES(VAL_STRUCT_DATA_BIN(out));

		/* set type early such that GC will handle it correctly, i.e, not collect series in the struct */
		SET_TYPE(out, REB_STRUCT);

		if (IS_BLOCK(blk)) {
			parse_attr(blk, &raw_size, &raw_addr);
			++ blk;
		}

		while (NOT_END(blk)) {
			REBVAL *inner;
			struct Struct_Field *field = NULL;
			u64 step = 0;

			EXPAND_SERIES_TAIL(VAL_STRUCT_FIELDS(out), 1);

			DS_PUSH_NONE;
			inner = DS_TOP; /* save in stack so that it won't be GC'ed when MT_Struct is recursively called */

			field = (struct Struct_Field *)SERIES_SKIP(VAL_STRUCT_FIELDS(out), field_idx);
			field->offset = (REBCNT)offset;
			if (IS_SET_WORD(blk)) {
				field->sym = VAL_WORD_SYM(blk);
				expect_init = TRUE;
				if (raw_addr) {
					/* initialization is not allowed for raw memory struct */
					raise Error_Invalid_Arg(blk);
				}
			} else if (IS_WORD(blk)) {
				field->sym = VAL_WORD_SYM(blk);
				expect_init = FALSE;
			}
			else
				raise Error_Has_Bad_Type(blk);

			++ blk;

			if (!IS_BLOCK(blk))
				raise Error_Invalid_Arg(blk);

			if (!parse_field_type(field, blk, inner, &init)) { return FALSE; }
			++ blk;

			STATIC_assert(sizeof(field->size) <= 4);
			STATIC_assert(sizeof(field->dimension) <= 4);

			step = (u64)field->size * (u64)field->dimension;
			if (step > VAL_STRUCT_LIMIT)
				raise Error_1(RE_SIZE_LIMIT, out);

			EXPAND_SERIES_TAIL(VAL_STRUCT_DATA_BIN(out), step);

			if (expect_init) {
				REBVAL safe; // result of reduce or do (GC saved during eval)
				init = &safe;

				if (IS_BLOCK(blk)) {
					if (Reduce_Block_Throws(init, VAL_SERIES(blk), 0, FALSE))
						raise Error_No_Catch_For_Throw(init);

					++ blk;
				} else {
					DO_NEXT_MAY_THROW(
						eval_idx,
						init,
						VAL_SERIES(data),
						blk - VAL_BLK_DATA(data)
					);
					if (eval_idx == THROWN_FLAG)
						raise Error_No_Catch_For_Throw(init);

					blk = VAL_BLK_SKIP(data, eval_idx);
				}

				if (field->array) {
					if (IS_INTEGER(init)) { /* interpreted as a C pointer */
						void *ptr = cast(void *, cast(REBUPT, VAL_INT64(init)));

						/* assuming it's an valid pointer and holding enough space */
						memcpy(SERIES_SKIP(VAL_STRUCT_DATA_BIN(out), (REBCNT)offset), ptr, field->size * field->dimension);
					} else if (IS_BLOCK(init)) {
						REBCNT n = 0;

						if (VAL_LEN(init) != field->dimension)
							raise Error_Invalid_Arg(init);

						/* assign */
						for (n = 0; n < field->dimension; n ++) {
							if (!assign_scalar(&VAL_STRUCT(out), field, n, VAL_BLK_SKIP(init, n))) {
								//RL_Print("Failed to assign element value\n");
								goto failed;
							}
						}
					}
					else
						raise Error_Unexpected_Type(REB_BLOCK, VAL_TYPE(blk));
				} else {
					/* scalar */
					if (!assign_scalar(&VAL_STRUCT(out), field, 0, init)) {
						//RL_Print("Failed to assign scalar value\n");
						goto failed;
					}
				}
			} else if (raw_addr == 0) {
Exemplo n.º 5
0
static REBOOL parse_field_type(struct Struct_Field *field, REBVAL *spec, REBVAL *inner, REBVAL **init)
{
	REBVAL *val = VAL_BLK_DATA(spec);

	if (IS_WORD(val)){
		switch (VAL_WORD_CANON(val)) {
			case SYM_UINT8:
				field->type = STRUCT_TYPE_UINT8;
				field->size = 1;
				break;
			case SYM_INT8:
				field->type = STRUCT_TYPE_INT8;
				field->size = 1;
				break;
			case SYM_UINT16:
				field->type = STRUCT_TYPE_UINT16;
				field->size = 2;
				break;
			case SYM_INT16:
				field->type = STRUCT_TYPE_INT16;
				field->size = 2;
				break;
			case SYM_UINT32:
				field->type = STRUCT_TYPE_UINT32;
				field->size = 4;
				break;
			case SYM_INT32:
				field->type = STRUCT_TYPE_INT32;
				field->size = 4;
				break;
			case SYM_UINT64:
				field->type = STRUCT_TYPE_UINT64;
				field->size = 8;
				break;
			case SYM_INT64:
				field->type = STRUCT_TYPE_INT64;
				field->size = 8;
				break;
			case SYM_FLOAT:
				field->type = STRUCT_TYPE_FLOAT;
				field->size = 4;
				break;
			case SYM_DOUBLE:
				field->type = STRUCT_TYPE_DOUBLE;
				field->size = 8;
				break;
			case SYM_POINTER:
				field->type = STRUCT_TYPE_POINTER;
				field->size = sizeof(void*);
				break;
			case SYM_STRUCT_TYPE:
				++ val;
				if (IS_BLOCK(val)) {
					REBFLG res;

					res = MT_Struct(inner, val, REB_STRUCT);

					if (!res) {
						//RL_Print("Failed to make nested struct!\n");
						return FALSE;
					}

					field->size = SERIES_TAIL(VAL_STRUCT_DATA_BIN(inner));
					field->type = STRUCT_TYPE_STRUCT;
					field->fields = VAL_STRUCT_FIELDS(inner);
					field->spec = VAL_STRUCT_SPEC(inner);
					*init = inner; /* a shortcut for struct intialization */
				}
				else
					raise Error_Unexpected_Type(REB_BLOCK, VAL_TYPE(val));
				break;
			case SYM_REBVAL:
				field->type = STRUCT_TYPE_REBVAL;
				field->size = sizeof(REBVAL);
				break;
			default:
				raise Error_Has_Bad_Type(val);
		}
	} else if (IS_STRUCT(val)) { //[b: [struct-a] val-a]
		field->size = SERIES_TAIL(VAL_STRUCT_DATA_BIN(val));
		field->type = STRUCT_TYPE_STRUCT;
		field->fields = VAL_STRUCT_FIELDS(val);
		field->spec = VAL_STRUCT_SPEC(val);
		*init = val;
	}
	else
		raise Error_Has_Bad_Type(val);

	++ val;

	if (IS_BLOCK(val)) {// make struct! [a: [int32 [2]] [0 0]]
		REBVAL ret;

		if (DO_ARRAY_THROWS(&ret, val)) {
			// !!! Does not check for thrown cases...what should this
			// do in case of THROW, BREAK, QUIT?
			raise Error_No_Catch_For_Throw(&ret);
		}

		if (!IS_INTEGER(&ret))
			raise Error_Unexpected_Type(REB_INTEGER, VAL_TYPE(val));

		field->dimension = cast(REBCNT, VAL_INT64(&ret));
		field->array = TRUE;
		++ val;
	} else {
		field->dimension = 1; /* scalar */
		field->array = FALSE;
	}

	if (NOT_END(val))
		raise Error_Has_Bad_Type(val);

	return TRUE;
}
Exemplo n.º 6
0
static REBOOL assign_scalar(REBSTU *stu,
							struct Struct_Field *field,
							REBCNT n, /* element index, starting from 0 */
							REBVAL *val)
{
	u64 i = 0;
	double d = 0;
	void *data = SERIES_SKIP(STRUCT_DATA_BIN(stu),
							 STRUCT_OFFSET(stu) + field->offset + n * field->size);

	if (field->type == STRUCT_TYPE_REBVAL) {
		memcpy(data, val, sizeof(REBVAL));
		return TRUE;
	}

	switch (VAL_TYPE(val)) {
		case REB_DECIMAL:
			if (!IS_NUMERIC_TYPE(field->type))
				raise Error_Has_Bad_Type(val);

			d = VAL_DECIMAL(val);
			i = (u64) d;
			break;
		case REB_INTEGER:
			if (!IS_NUMERIC_TYPE(field->type))
				if (field->type != STRUCT_TYPE_POINTER)
					raise Error_Has_Bad_Type(val);

			i = (u64) VAL_INT64(val);
			d = (double)i;
			break;
		case REB_STRUCT:
			if (STRUCT_TYPE_STRUCT != field->type)
				raise Error_Has_Bad_Type(val);
			break;
		default:
			raise Error_Has_Bad_Type(val);
	}

	switch (field->type) {
		case STRUCT_TYPE_INT8:
			*(i8*)data = (i8)i;
			break;
		case STRUCT_TYPE_UINT8:
			*(u8*)data = (u8)i;
			break;
		case STRUCT_TYPE_INT16:
			*(i16*)data = (i16)i;
			break;
		case STRUCT_TYPE_UINT16:
			*(u16*)data = (u16)i;
			break;
		case STRUCT_TYPE_INT32:
			*(i32*)data = (i32)i;
			break;
		case STRUCT_TYPE_UINT32:
			*(u32*)data = (u32)i;
			break;
		case STRUCT_TYPE_INT64:
			*(i64*)data = (i64)i;
			break;
		case STRUCT_TYPE_UINT64:
			*(u64*)data = (u64)i;
			break;
		case STRUCT_TYPE_POINTER:
			*cast(void**, data) = cast(void*, cast(REBUPT, i));
			break;
		case STRUCT_TYPE_FLOAT:
			*(float*)data = (float)d;
			break;
		case STRUCT_TYPE_DOUBLE:
			*(double*)data = (double)d;
			break;
		case STRUCT_TYPE_STRUCT:
			if (field->size != VAL_STRUCT_LEN(val))
				raise Error_Invalid_Arg(val);

			if (same_fields(field->fields, VAL_STRUCT_FIELDS(val))) {
				memcpy(data, SERIES_SKIP(VAL_STRUCT_DATA_BIN(val), VAL_STRUCT_OFFSET(val)), field->size);
			} else
				raise Error_Invalid_Arg(val);
			break;
		default:
			/* should never be here */
			return FALSE;
	}
	return TRUE;
}
Exemplo n.º 7
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);
}
Exemplo n.º 8
0
*/	REBINT Find_Key(REBSER *series, REBSER *hser, const 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) raise 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;
}