/*-------------------------------------------------------------------------*/ void check_wizlist_for_destr (void) /* Check the 'extra' info in all wizinfo and remove destructed objects * and closures. */ { wiz_list_t *wl; for (wl = &default_wizlist_entry; wl; ) { size_t num; svalue_t *item; if (wl->extra.type == T_POINTER) { num = VEC_SIZE(wl->extra.u.vec); item = &(wl->extra.u.vec->item[0]); } else { num = 1; item = &(wl->extra); } for ( ; num != 0 ; item++, num--) { switch(item->type) { case T_POINTER: check_for_destr(item->u.vec); break; case T_MAPPING: check_map_for_destr(item->u.map); break; case T_OBJECT: case T_CLOSURE: if (destructed_object_ref(item)) assign_svalue(item, &const0); break; default: NOOP; break; } } if (wl == &default_wizlist_entry) wl = all_wiz; else wl = wl->next; } } /* check_wizlist_for_destr() */
/*-------------------------------------------------------------------------*/ void struct_check_for_destr ( struct_t * pStruct ) /* Remove all references to destructed objects from <pStruct>. */ { int member, num_members; svalue_t * svp; num_members = struct_size(pStruct); for (member = 0, svp = pStruct->member ; member < num_members ; member++, svp++ ) { if (destructed_object_ref(svp)) { free_svalue(svp); put_number(svp, 0); } } } /* struct_check_for_destr() */
/*-------------------------------------------------------------------------*/ vector_t * order_alist (svalue_t *inlists, int listnum, Bool reuse) /* Order the alist <inlists> and return a new vector with it. The sorting * order is the internal order defined by alist_cmp(). * * <inlists> is a vector of <listnum> vectors: * <inlists> = ({ ({ keys }), ({ data1 }), ..., ({ data<listnum-1> }) }) * * If <reuse> is true, the vectors of <inlists> are reused for the * vectors of the result when possible, and their entries in <inlists> are * set to T_INVALID. * * As a side effect, strings in the key vector are made shared, and * destructed objects in key and data vectors are replaced by svalue 0s. * * This function is also called by the compiler for constant expressions. */ { vector_t *outlist; /* The result vector of vectors */ vector_t *v; /* Aux vector pointer */ svalue_t *outlists; /* Next element in outlist to fill in */ ptrdiff_t * sorted; /* The vector elements in sorted order */ svalue_t *inpnt; /* Pointer to the value to copy into the result */ mp_int keynum; /* Number of keys */ int i, j; keynum = (mp_int)VEC_SIZE(inlists[0].u.vec); /* Get the sorting order */ sorted = get_array_order(inlists[0].u.vec); /* Generate the result vectors from the sorting order. */ outlist = allocate_array(listnum); outlists = outlist->item; /* Copy the elements from all inlist vectors into the outlist * vectors. * * At the beginning of every loop v points to the vector to * use as the next 'out' vector. It may be a re-used 'in' vector * from the previous run. */ v = allocate_array(keynum); for (i = listnum; --i >= 0; ) { svalue_t *outpnt; /* Next result value element to fill in */ /* Set the new array v as the next 'out' vector, and init outpnt * and offs. */ put_array(outlists + i, v); outpnt = v->item; v = inlists[i].u.vec; /* Next vector to fill if reusable */ /* Copy the elements. * For a reusable 'in' vector, a simple memory copy is sufficient. * For a new vector, a full assignment is due to keep the refcounters * happy. */ if (reuse && inlists[i].u.vec->ref == 1) { if (i) /* not the last iteration */ inlists[i].type = T_INVALID; for (j = keynum; --j >= 0; ) { inpnt = inlists[i].u.vec->item + sorted[j]; if (destructed_object_ref(inpnt)) { free_svalue(inpnt); put_number(outpnt, 0); outpnt++; } else { *outpnt++ = *inpnt; } inpnt->type = T_INVALID; } } else { if (i) /* Not the last iteration: get new out-vector */ v = allocate_array(keynum); for (j = keynum; --j >= 0; ) { inpnt = inlists[i].u.vec->item + sorted[j]; if (destructed_object_ref(inpnt)) { put_number(outpnt, 0); outpnt++; } else { assign_svalue_no_free(outpnt++, inpnt); } } } /* if (reuse) */ } /* for (listnum) */ xfree(sorted); return outlist; } /* order_alist() */
/*-------------------------------------------------------------------------*/ svalue_t * v_assoc (svalue_t *sp, int num_arg) /* EFUN assoc() * * int assoc (mixed key, mixed *keys) * mixed assoc (mixed key, mixed *alist [, mixed fail] ) * mixed assoc (mixed key, mixed *keys, mixed *data [, mixed fail]) * * Search for <key> in the <alist> resp. in the <keys>. * * When the key list of an alist contains destructed objects * it is better not to free them till the next reordering by * order_alist to retain the alist property. */ { svalue_t *args; vector_t *keys,*data; svalue_t *fail_val; int ix; args = sp -num_arg +1; /* Analyse the arguments */ if ( !VEC_SIZE(args[1].u.vec) || args[1].u.vec->item[0].type != T_POINTER ) { keys = args[1].u.vec; if (num_arg == 2) { data = NULL; } else { if (args[2].type != T_POINTER || VEC_SIZE(args[2].u.vec) != VEC_SIZE(keys)) { errorf("Number of values in key and data arrays differ.\n"); /* NOTREACHED */ return sp; } data = args[2].u.vec; } if (num_arg == 4) { fail_val = &args[3]; } else { fail_val = &const0; } } else { keys = args[1].u.vec->item[0].u.vec; if (VEC_SIZE(args[1].u.vec) > 1) { if (args[1].u.vec->item[1].type != T_POINTER || VEC_SIZE(args[1].u.vec->item[1].u.vec) != VEC_SIZE(keys)) { errorf("Number of values in key and data arrays differ.\n"); /* NOTREACHED */ return sp; } data = args[1].u.vec->item[1].u.vec; } else { data = NULL; } if (num_arg == 3) fail_val = &args[2]; else if (num_arg == 2) fail_val = &const0; else { errorf("too many args to efun assoc\n"); /* NOTREACHED */ return sp; } } /* Call lookup_key() and push the result */ ix = lookup_key(&args[0],keys); if (data == NULL) { sp = pop_n_elems(num_arg, sp); push_number(sp, ix < 0 ? -1 : ix); } else { assign_svalue(args , ix < 0 ? fail_val : (destructed_object_ref(&data->item[ix]) ? &const0 : &data->item[ix]) ); sp = pop_n_elems(num_arg-1, sp); } return sp; } /* v_assoc() */
/*-------------------------------------------------------------------------*/ svalue_t * x_map_struct (svalue_t *sp, int num_arg) /* EFUN map() on structs * * mixed * map(struct arg, string func, string|object ob, mixed extra...) * mixed * map(struct arg, closure cl, mixed extra...) * mixed * map(struct arr, mapping map [, int col]) * * Map the elements of <arr> through a filter defined by the other * arguments, and return an array of the elements returned by the filter. * * The filter can be a function call: * * <obj>-><fun>(elem, <extra>...) * * or a mapping query: * * <map>[elem[,idx]] * * In the mapping case, if <map>[elem[,idx]] does not exist, the original * value is returned in the result. * [Note: argument type and range checking for idx is done in v_map()] * * <obj> can both be an object reference or a filename. If <ob> is * omitted, or neither an object nor a string, then this_object() is used. * * As a bonus, all references to destructed objects in <arr> are replaced * by proper 0es. */ { struct_t *st; struct_t *res; svalue_t *arg; svalue_t *v, *w, *x; mp_int cnt; inter_sp = sp; arg = sp - num_arg + 1; st = arg->u.strct; cnt = (mp_int)struct_size(st); if (arg[1].type == T_MAPPING) { /* --- Map through mapping --- */ mapping_t *m; p_int column = 0; /* mapping column to use */ m = arg[1].u.map; if (num_arg > 2) column = arg[2].u.number; res = struct_new(st->type); if (!res) errorf("(map_struct) Out of memory: struct[%"PRIdMPINT"] for result\n", cnt); push_struct(inter_sp, res); /* In case of errors */ for (w = st->member, x = res->member; --cnt >= 0; w++, x++) { if (destructed_object_ref(w)) assign_svalue(w, &const0); v = get_map_value(m, w); if (v == &const0) assign_svalue_no_free(x, w); else assign_svalue_no_free(x, v + column); } if (num_arg > 2) free_svalue(arg+2); free_svalue(arg+1); /* the mapping */ sp = arg; } else { /* --- Map through function call --- */ callback_t cb; int error_index; error_index = setup_efun_callback(&cb, arg+1, num_arg-1); if (error_index >= 0) { vefun_bad_arg(error_index+2, arg); /* NOTREACHED */ return arg; } inter_sp = sp = arg+1; put_callback(sp, &cb); num_arg = 2; res = struct_new(st->type); if (!res) errorf("(map_struct) Out of memory: struct[%"PRIdMPINT"] for result\n", cnt); push_struct(inter_sp, res); /* In case of errors */ /* Loop through arr and res, mapping the values from arr */ for (w = st->member, x = res->member; --cnt >= 0; w++, x++) { if (current_object->flags & O_DESTRUCTED) continue; if (destructed_object_ref(w)) assign_svalue(w, &const0); if (!callback_object(&cb)) errorf("object used by map_array destructed"); push_svalue(w); v = apply_callback(&cb, 1); if (v) { transfer_svalue_no_free(x, v); v->type = T_INVALID; } } free_callback(&cb); } /* The arguments have been removed already, now just replace * the struct on the stack with the result. */ free_struct(st); arg->u.strct = res; /* Keep svalue type T_STRUCT */ return arg; } /* x_map_struct () */