static Scheme_Object *apply_impersonator_of(int for_chaperone, Scheme_Object *procs, Scheme_Object *obj) { Scheme_Object *a[1], *v, *oprocs; a[0] = obj; v = _scheme_apply(SCHEME_CDR(procs), 1, a); if (SCHEME_FALSEP(v)) return NULL; oprocs = scheme_struct_type_property_ref(scheme_impersonator_of_property, v); if (!oprocs || !SAME_OBJ(SCHEME_CAR(oprocs), SCHEME_CAR(procs))) scheme_contract_error((for_chaperone ? "impersonator-of?" : "equal?"), "impersonator-of property procedure returned a value with a different prop:impersonator-of source", "original value", 1, obj, "returned value", 1, v, NULL); procs = scheme_struct_type_property_ref(scheme_equal_property, obj); oprocs = scheme_struct_type_property_ref(scheme_equal_property, v); if (procs || oprocs) if (!procs || !oprocs || !SAME_OBJ(SCHEME_VEC_ELS(oprocs)[0], SCHEME_VEC_ELS(procs)[0])) scheme_contract_error((for_chaperone ? "impersonator-of?" : "equal?"), "impersonator-of property procedure returned a value with a different prop:equal+hash source", "original value", 1, obj, "returned value", 1, v, NULL); return v; }
Scheme_Object *scheme_chaperone_vector_ref2(Scheme_Object *o, int i, Scheme_Object *outermost) { if (!SCHEME_NP_CHAPERONEP(o)) { return SCHEME_VEC_ELS(o)[i]; } else { Scheme_Chaperone *px = (Scheme_Chaperone *)o; Scheme_Object *a[4], *red, *orig; #ifdef DO_STACK_CHECK { # include "mzstkchk.h" return chaperone_vector_ref_overflow(o, i); } #endif if(SCHEME_FALSEP(px->redirects)) { /* unsafe chaperones */ return scheme_chaperone_vector_ref2(px->val, i, outermost); } orig = scheme_chaperone_vector_ref2(px->prev, i, outermost); if (SCHEME_REDIRECTS_PROP_ONLY_VECTORP(px->redirects)) { /* chaperone was on property accessors */ /* or vector chaperone is property only */ return orig; } red = SCHEME_CAR(px->redirects); if (SCHEME_CHAPERONE_FLAGS(px) & SCHEME_VEC_CHAPERONE_STAR) { a[0] = outermost; a[1] = px->prev; a[2] = scheme_make_integer(i); a[3] = orig; o = _scheme_apply(red, 4, a); } else { a[0] = px->prev; a[1] = scheme_make_integer(i); a[2] = orig; o = _scheme_apply(red, 3, a); } if (!(SCHEME_CHAPERONE_FLAGS(px) & SCHEME_CHAPERONE_IS_IMPERSONATOR)) if (!scheme_chaperone_of(o, orig)) scheme_wrong_chaperoned("vector-ref", "result", orig, o); return o; } }
void scheme_chaperone_vector_set(Scheme_Object *o, int i, Scheme_Object *v) { Scheme_Object *outermost = o; while (1) { if (!SCHEME_NP_CHAPERONEP(o)) { SCHEME_VEC_ELS(o)[i] = v; return; } else { Scheme_Chaperone *px = (Scheme_Chaperone *)o; Scheme_Object *a[4], *red; int chap_star = SCHEME_CHAPERONE_FLAGS(px) & SCHEME_VEC_CHAPERONE_STAR ? 1 : 0; red = px->redirects; if (SCHEME_FALSEP(red)) { o = px->val; continue; } o = px->prev; if (!SCHEME_REDIRECTS_PROP_ONLY_VECTORP(red)) { /* not a property only chaperone */ red = SCHEME_CDR(px->redirects); if (chap_star) { a[0] = outermost; a[1] = o; a[2] = scheme_make_integer(i); a[3] = v; v = _scheme_apply(red, 4, a); } else { a[0] = o; a[1] = scheme_make_integer(i); a[2] = v; v = _scheme_apply(red, 3, a); } if (!(SCHEME_CHAPERONE_FLAGS(px) & SCHEME_CHAPERONE_IS_IMPERSONATOR)) if (!scheme_chaperone_of(v, a[2 + chap_star])) scheme_wrong_chaperoned("vector-set!", "value", a[2 + chap_star], v); } } } }
static void sfs_restore_one_branch(SFS_Info *info, int ip, Scheme_Object *vec, int delta) { int t_min_t, t_cnt, i; Scheme_Object *t_vec; t_vec = SCHEME_VEC_ELS(vec)[(delta * SFS_BRANCH_W) + 1]; if (SCHEME_FALSEP(t_vec)) return; t_min_t = SCHEME_INT_VAL(SCHEME_VEC_ELS(vec)[delta * SFS_BRANCH_W]); t_cnt = SCHEME_VEC_SIZE(t_vec); for (i = 0; i < t_cnt; i++) { if (SCHEME_TRUEP(SCHEME_VEC_ELS(t_vec)[i])) info->max_used[i + t_min_t] = ip; } }
Scheme_Object *scheme_rational_round(const Scheme_Object *o) { Scheme_Rational *r = (Scheme_Rational *)o; Scheme_Object *q, *qd, *delta, *half; int more = 0, can_eq_half, negative; negative = !scheme_is_rational_positive(o); q = scheme_bin_quotient(r->num, r->denom); /* Get remainder absolute value: */ qd = scheme_bin_mult(q, r->denom); if (negative) delta = scheme_bin_minus(qd, r->num); else delta = scheme_bin_minus(r->num, qd); half = scheme_bin_quotient(r->denom, scheme_make_integer(2)); can_eq_half = SCHEME_FALSEP(scheme_odd_p(1, &r->denom)); if (SCHEME_INTP(half) && SCHEME_INTP(delta)) { if (can_eq_half && (SCHEME_INT_VAL(delta) == SCHEME_INT_VAL(half))) more = SCHEME_TRUEP(scheme_odd_p(1, &q)); else more = (SCHEME_INT_VAL(delta) > SCHEME_INT_VAL(half)); } else if (SCHEME_BIGNUMP(delta) && SCHEME_BIGNUMP(half)) { if (can_eq_half && (scheme_bignum_eq(delta, half))) more = SCHEME_TRUEP(scheme_odd_p(1, &q)); else more = !scheme_bignum_lt(delta, half); } else more = SCHEME_BIGNUMP(delta); if (more) { if (negative) q = scheme_sub1(1, &q); else q = scheme_add1(1, &q); } return q; }
static Scheme_Object *do_chaperone_vector(const char *name, int is_impersonator, int pass_self, int unsafe, int argc, Scheme_Object **argv) { Scheme_Chaperone *px; Scheme_Object *val = argv[0]; Scheme_Object *redirects; Scheme_Object *props; if (SCHEME_CHAPERONEP(val)) { val = SCHEME_CHAPERONE_VAL(val); } if (!SCHEME_VECTORP(val) || (is_impersonator && !SCHEME_MUTABLEP(val))) scheme_wrong_contract(name, is_impersonator ? "(and/c vector? (not/c immutable?))" : "vector?", 0, argc, argv); if (unsafe) { /* We cannot dispatch the operations on an unsafe vector chaperone to a chaperoned vector because of the invariant that the val field of a vector chaperone must point to a non-chaperoned vector. To ensure this we error if the second argument passed to `unsafe-chaperone-vector` is not a unchaperoned vector */ if (!SCHEME_VECTORP(argv[1])) { scheme_wrong_contract(name, "(and/c vector? (not/c impersonator?))", 1, argc, argv); } val = argv[1]; } else { /* allow false for interposition procedures */ scheme_check_proc_arity2(name, 3 + (pass_self ? 1 : 0), 1, argc, argv, 1); scheme_check_proc_arity2(name, 3 + (pass_self ? 1 : 0), 2, argc, argv, 1); /* but only allow `#f` if both are `#f` */ if (SCHEME_FALSEP(argv[1]) != SCHEME_FALSEP(argv[2])) { scheme_contract_error(name, "accessor and mutator wrapper must be both `#f` or neither `#f`", "accessor wrapper", 1, argv[1], "mutator wrapper", 1, argv[2], NULL); } } props = scheme_parse_chaperone_props(name, unsafe ? 2 : 3, argc, argv); /* Regular vector chaperones store redirect procedures in a pair, (cons getter setter). Property only vector chaperones have no redirection procedures, and redirects is assigned an empty vector. Unsafe vector chaperones dispatch operations to another vector stored in a box in redirects. */ if (SCHEME_FALSEP(argv[1])) { redirects = scheme_make_vector(0, NULL); } else if (unsafe) { redirects = scheme_false; } else { redirects = scheme_make_pair(argv[1], argv[2]); } px = MALLOC_ONE_TAGGED(Scheme_Chaperone); px->iso.so.type = scheme_chaperone_type; px->props = props; px->val = val; px->prev = argv[0]; px->redirects = redirects; if (is_impersonator) SCHEME_CHAPERONE_FLAGS(px) |= SCHEME_CHAPERONE_IS_IMPERSONATOR; /* Use flag to tell if the chaperone is a chaperone* */ if (pass_self) { SCHEME_CHAPERONE_FLAGS(px) |= SCHEME_VEC_CHAPERONE_STAR; } return (Scheme_Object *)px; }
int is_equal (Scheme_Object *obj1, Scheme_Object *obj2, Equal_Info *eql) { Scheme_Type t1, t2; int cmp; Scheme_Object *orig_obj1, *orig_obj2; top: orig_obj1 = obj1; orig_obj2 = obj2; if (eql->next_next) { if (eql->next) { Scheme_Object *a[2]; a[0] = obj1; a[1] = obj2; obj1 = _scheme_apply(eql->next, 2, a); return SCHEME_TRUEP(obj1); } eql->next = eql->next_next; } top_after_next: cmp = is_fast_equal(obj1, obj2, eql->for_chaperone == 1); if (cmp > -1) return cmp; if (eql->for_chaperone && SCHEME_CHAPERONEP(obj2) && scheme_is_noninterposing_chaperone(obj2)) { obj2 = ((Scheme_Chaperone *)obj2)->prev; goto top_after_next; } if (eql->for_chaperone && SCHEME_CHAPERONEP(obj1) && (!(SCHEME_CHAPERONE_FLAGS((Scheme_Chaperone *)obj1) & SCHEME_CHAPERONE_IS_IMPERSONATOR) || (eql->for_chaperone > 1))) { /* `obj1` and `obj2` are not eq, otherwise is_fast_equal() would have returned true */ if (SCHEME_CHAPERONEP(obj2)) { /* for immutable hashes, it's ok for the two objects to not be eq, as long as the interpositions are the same and the underlying values are `{impersonator,chaperone}-of?`: */ if (SCHEME_HASHTRP(((Scheme_Chaperone *)obj1)->val) && SCHEME_HASHTRP(((Scheme_Chaperone *)obj2)->val) /* eq redirects means redirects were propagated: */ && SAME_OBJ(((Scheme_Chaperone *)obj1)->redirects, ((Scheme_Chaperone *)obj2)->redirects)) obj2 = ((Scheme_Chaperone *)obj2)->prev; } obj1 = ((Scheme_Chaperone *)obj1)->prev; goto top_after_next; } t1 = SCHEME_TYPE(obj1); t2 = SCHEME_TYPE(obj2); if (NOT_SAME_TYPE(t1, t2)) { if (!eql->for_chaperone) { if (SCHEME_CHAPERONEP(obj1)) { obj1 = ((Scheme_Chaperone *)obj1)->val; goto top_after_next; } else if (t1 == scheme_hash_tree_indirection_type) { obj1 = (Scheme_Object *)scheme_hash_tree_resolve_placeholder((Scheme_Hash_Tree *)obj1); goto top_after_next; } if (SCHEME_CHAPERONEP(obj2)) { obj2 = ((Scheme_Chaperone *)obj2)->val; goto top_after_next; } else if (t2 == scheme_hash_tree_indirection_type) { obj2 = (Scheme_Object *)scheme_hash_tree_resolve_placeholder((Scheme_Hash_Tree *)obj2); goto top_after_next; } } return 0; } else { switch (t1) { case scheme_pair_type: { # include "mzeqchk.inc" if ((eql->car_depth > 2) || !scheme_is_list(obj1)) { if (union_check(obj1, obj2, eql)) return 1; } eql->car_depth += 2; if (is_equal(SCHEME_CAR(obj1), SCHEME_CAR(obj2), eql)) { eql->car_depth -= 2; obj1 = SCHEME_CDR(obj1); obj2 = SCHEME_CDR(obj2); goto top; } else return 0; } case scheme_mutable_pair_type: { # include "mzeqchk.inc" if (eql->for_chaperone == 1) return 0; if (union_check(obj1, obj2, eql)) return 1; if (is_equal(SCHEME_CAR(obj1), SCHEME_CAR(obj2), eql)) { obj1 = SCHEME_CDR(obj1); obj2 = SCHEME_CDR(obj2); goto top; } else return 0; } case scheme_vector_type: case scheme_fxvector_type: { # include "mzeqchk.inc" if ((eql->for_chaperone == 1) && (!SCHEME_IMMUTABLEP(obj1) || !SCHEME_IMMUTABLEP(obj2))) return 0; if (union_check(obj1, obj2, eql)) return 1; return vector_equal(obj1, orig_obj1, obj2, orig_obj2, eql); } case scheme_byte_string_type: case scheme_unix_path_type: case scheme_windows_path_type: { intptr_t l1, l2; if ((eql->for_chaperone == 1) && (!SCHEME_IMMUTABLEP(obj1) || !SCHEME_IMMUTABLEP(obj2))) return 0; l1 = SCHEME_BYTE_STRTAG_VAL(obj1); l2 = SCHEME_BYTE_STRTAG_VAL(obj2); return ((l1 == l2) && !memcmp(SCHEME_BYTE_STR_VAL(obj1), SCHEME_BYTE_STR_VAL(obj2), l1)); } case scheme_char_string_type: { intptr_t l1, l2; if ((eql->for_chaperone == 1) && (!SCHEME_IMMUTABLEP(obj1) || !SCHEME_IMMUTABLEP(obj2))) return 0; l1 = SCHEME_CHAR_STRTAG_VAL(obj1); l2 = SCHEME_CHAR_STRTAG_VAL(obj2); return ((l1 == l2) && !memcmp(SCHEME_CHAR_STR_VAL(obj1), SCHEME_CHAR_STR_VAL(obj2), l1 * sizeof(mzchar))); } case scheme_regexp_type: { if (scheme_regexp_is_byte(obj1) != scheme_regexp_is_byte(obj2)) return 0; if (scheme_regexp_is_pregexp(obj1) != scheme_regexp_is_pregexp(obj2)) return 0; obj1 = scheme_regexp_source(obj1); obj2 = scheme_regexp_source(obj2); goto top; } case scheme_structure_type: case scheme_proc_struct_type: { Scheme_Struct_Type *st1, *st2; Scheme_Object *procs1, *procs2; st1 = SCHEME_STRUCT_TYPE(obj1); st2 = SCHEME_STRUCT_TYPE(obj2); if (eql->for_chaperone == 1) procs1 = NULL; else procs1 = scheme_struct_type_property_ref(scheme_impersonator_of_property, (Scheme_Object *)st1); if (procs1) procs1 = scheme_apply_impersonator_of(eql->for_chaperone, procs1, obj1); if (eql->for_chaperone) procs2 = NULL; else { procs2 = scheme_struct_type_property_ref(scheme_impersonator_of_property, (Scheme_Object *)st2); if (procs2) procs2 = scheme_apply_impersonator_of(eql->for_chaperone, procs2, obj2); } if (procs1 || procs2) { /* impersonator-of property trumps other forms of checking */ if (procs1) { obj1 = procs1; orig_obj1 = obj1; } if (procs2) { obj2 = procs2; orig_obj2 = obj2; } goto top_after_next; } else { procs1 = scheme_struct_type_property_ref(scheme_equal_property, (Scheme_Object *)st1); if (procs1 && (st1 != st2)) { procs2 = scheme_struct_type_property_ref(scheme_equal_property, (Scheme_Object *)st2); if (!procs2 || !SAME_OBJ(SCHEME_VEC_ELS(procs1)[0], SCHEME_VEC_ELS(procs2)[0])) procs1 = NULL; } if (procs1) { /* Has an equality property: */ Scheme_Object *a[3], *recur; Equal_Info *eql2; # include "mzeqchk.inc" if (union_check(obj1, obj2, eql)) return 1; /* Create/cache closure to use for recursive equality checks: */ if (eql->recur) { recur = eql->recur; eql2 = (Equal_Info *)SCHEME_PRIM_CLOSURE_ELS(recur)[0]; } else { eql2 = (Equal_Info *)scheme_malloc(sizeof(Equal_Info)); a[0] = (Scheme_Object *)eql2; recur = scheme_make_prim_closure_w_arity(equal_recur, 1, a, "equal?/recur", 2, 2); eql->recur = recur; } memcpy(eql2, eql, sizeof(Equal_Info)); a[0] = orig_obj1; a[1] = orig_obj2; a[2] = recur; procs1 = SCHEME_VEC_ELS(procs1)[1]; recur = _scheme_apply(procs1, 3, a); memcpy(eql, eql2, sizeof(Equal_Info)); return SCHEME_TRUEP(recur); } else if (st1 != st2) { return 0; } else if ((eql->for_chaperone == 1) && !(MZ_OPT_HASH_KEY(&st1->iso) & STRUCT_TYPE_ALL_IMMUTABLE)) { return 0; } else { /* Same types, but doesn't have an equality property (or checking for chaperone), so check transparency: */ Scheme_Object *insp; if (scheme_struct_is_transparent(obj1)) insp = NULL; else { insp = scheme_get_param(scheme_current_config(), MZCONFIG_INSPECTOR); } if (!insp || scheme_inspector_sees_part(obj1, insp, -2)) { # include "mzeqchk.inc" if (union_check(obj1, obj2, eql)) return 1; return struct_equal(obj1, orig_obj1, obj2, orig_obj2, eql); } else return 0; } } } case scheme_box_type: { SCHEME_USE_FUEL(1); if ((eql->for_chaperone == 1) && (!SCHEME_IMMUTABLEP(obj1) || !SCHEME_IMMUTABLEP(obj2))) return 0; if (union_check(obj1, obj2, eql)) return 1; if (SAME_OBJ(obj1, orig_obj1)) obj1 = SCHEME_BOX_VAL(obj1); else obj1 = scheme_unbox(orig_obj1); if (SAME_OBJ(obj2, orig_obj2)) obj2 = SCHEME_BOX_VAL(obj2); else obj2 = scheme_unbox(orig_obj2); goto top; } case scheme_hash_table_type: { # include "mzeqchk.inc" if (eql->for_chaperone == 1) return 0; if (union_check(obj1, obj2, eql)) return 1; return scheme_hash_table_equal_rec((Scheme_Hash_Table *)obj1, orig_obj1, (Scheme_Hash_Table *)obj2, orig_obj2, eql); } case scheme_hash_tree_type: case scheme_eq_hash_tree_type: case scheme_eqv_hash_tree_type: case scheme_hash_tree_indirection_type: { # include "mzeqchk.inc" if (union_check(obj1, obj2, eql)) return 1; return scheme_hash_tree_equal_rec((Scheme_Hash_Tree *)obj1, orig_obj1, (Scheme_Hash_Tree *)obj2, orig_obj2, eql); } case scheme_bucket_table_type: { # include "mzeqchk.inc" if (eql->for_chaperone == 1) return 0; if (union_check(obj1, obj2, eql)) return 1; return scheme_bucket_table_equal_rec((Scheme_Bucket_Table *)obj1, orig_obj1, (Scheme_Bucket_Table *)obj2, orig_obj2, eql); } case scheme_wrap_chunk_type: { return vector_equal(obj1, obj1, obj2, obj2, eql); } case scheme_resolved_module_path_type: { obj1 = SCHEME_PTR_VAL(obj1); obj2 = SCHEME_PTR_VAL(obj2); goto top; } case scheme_module_index_type: { Scheme_Modidx *midx1, *midx2; # include "mzeqchk.inc" midx1 = (Scheme_Modidx *)obj1; midx2 = (Scheme_Modidx *)obj2; if (eql->eq_for_modidx && (SCHEME_FALSEP(midx1->path) || SCHEME_FALSEP(midx2->path))) return 0; else if (is_equal(midx1->path, midx2->path, eql)) { obj1 = midx1->base; obj2 = midx2->base; goto top; } } case scheme_scope_table_type: { Scheme_Scope_Table *mt1 = (Scheme_Scope_Table *)obj1; Scheme_Scope_Table *mt2 = (Scheme_Scope_Table *)obj2; if (!is_equal((Scheme_Object *)mt1->simple_scopes, (Scheme_Object *)mt2->simple_scopes, eql)) return 0; obj1 = mt1->multi_scopes; obj2 = mt2->multi_scopes; goto top; } default: if (!eql->for_chaperone && ((t1 == scheme_chaperone_type) || (t1 == scheme_proc_chaperone_type))) { /* both chaperones */ obj1 = ((Scheme_Chaperone *)obj1)->val; obj2 = ((Scheme_Chaperone *)obj2)->val; goto top_after_next; } else { Scheme_Equal_Proc eqlp = scheme_type_equals[t1]; if (eqlp) { if (union_check(obj1, obj2, eql)) return 1; return eqlp(obj1, obj2, eql); } else return 0; } } } }