/*-------------------------------------------------------------------------*/ static vector_t * intersect_ordered_arr (vector_t *a1, vector_t *a2) /* Compute the intersection of the two ordered arrays <a1> and <a2>. * * The result is a new sorted(!) vector with all elements, which are present * in both input vectors. * This function is called by f_intersect_alists(). */ { vector_t *a3; mp_int d, l, i1, i2, a1s, a2s; a1s = (mp_int)VEC_SIZE(a1); a2s = (mp_int)VEC_SIZE(a2); a3 = allocate_array( a1s < a2s ? a1s : a2s); for (i1=i2=l=0; i1 < a1s && i2 < a2s; ) { d = svalue_cmp(&a1->item[i1], &a2->item[i2]); if (d<0) i1++; else if (d>0) i2++; else { assign_svalue_no_free(&a3->item[l++], &a2->item[(i1++,i2++)] ); } } return shrink_array(a3, l); } /* intersect_ordered_arr() */
int mgt_commit(islpci_private *priv) { int rvalue; enum oid_num_t u; if (islpci_get_state(priv) < PRV_STATE_INIT) return 0; rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1)); if (priv->iw_mode != IW_MODE_MONITOR) rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2)); u = OID_INL_MODE; rvalue |= mgt_commit_list(priv, &u, 1); rvalue |= mgt_update_addr(priv); if (rvalue) { /* some request have failed. The device might be in an incoherent state. We should reset it ! */ printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name); } return rvalue; }
void count_simul_efun_extra_refs (struct pointer_table *ptable) /* DEBUG support: count the extra refs for structures of this module. */ { if (simul_efun_vector) { simul_efun_vector->extra_ref++; if (NULL != register_pointer(ptable, simul_efun_vector) ) count_extra_ref_in_vector( simul_efun_vector->item, VEC_SIZE(simul_efun_vector) ); } if (simul_efun_program) { simul_efun_program->extra_ref++; if (NULL == register_pointer(ptable, simul_efun_program)) return; simul_efun_program->extra_ref = 1; count_inherits(simul_efun_program); } } /* count_simul_efun_extra_refs() */
int main(int argc, char** argv) { int64 nside=4096; double rad_radians=-1; int rad_in_file=0; process_args(argc, argv, &nside, &rad_radians, &rad_in_file); struct healpix* hpix = hpix_new(nside); VEC(int64) pixlist = VEC_NEW(int64); double ra=0, dec=0; while (2 == fscanf(stdin,"%lf %lf", &ra, &dec)) { if (rad_in_file) { if (1 != fscanf(stdin,"%lf", &rad_radians)) { fprintf(stderr,"failed to read radius\n"); exit(EXIT_FAILURE); } rad_radians *= D2R/3600.; } hpix_disc_intersect_radec(hpix, ra, dec, rad_radians, pixlist); printf("%.16g %.16g %lu", ra, dec, VEC_SIZE(pixlist); VEC_FOREACH(pix_ptr, pixlist) { printf(" %ld", *pix_ptr); } printf("\n"); }
/*-------------------------------------------------------------------------*/ void count_simul_efun_refs (void) /* GC support: count the references of all memory held by the module. */ { if (simul_efun_file_name) count_ref_from_string(simul_efun_file_name); if (simul_efunp) { int i; note_malloced_block_ref((char *)simul_efunp); for (i = num_simul_efun; --i >= 0; ) count_ref_from_string(simul_efunp[i].name); } if (simul_efun_vector && !simul_efun_vector->ref++) { note_malloced_block_ref((char *)simul_efun_vector); count_ref_in_vector( simul_efun_vector->item, VEC_SIZE(simul_efun_vector) ); } if (simul_efun_program) mark_program_ref(simul_efun_program); } /* count_simul_efun_refs() */
int main(void) { char *strings[] = { "take", "a", "walk", "on", "the", "wild", "side", "song", "composed", "by", "Lou", "Reed", "and", "Velvet", "undeground"}; for (int i=0; i<VEC_SIZE(strings); i++) printf("hash of \'%11s\' is: %u\n", strings[i], hash(strings[i])); return(EXIT_SUCCESS); }
/*-------------------------------------------------------------------------*/ 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 err_cb (const riff_chunkv_t * chunk_path_ptr, FILE * f, uint64_t position, riff_result_t err, void * cookie) { riff_chunk_t cur; char buf[5]; int i; for(i=0;i<VEC_SIZE(*chunk_path_ptr);i++) { cur = VEC_GET(*chunk_path_ptr, i); fourcc_to_string(cur.fourcc, buf); printf("%s:", buf); } cur = VEC_TOP(*chunk_path_ptr); printf(" %" PRIu64 " - %" PRIu64 "\n", cur.pos_head, cur.pos_end); }
riff_cbresult_t chunk_cb (const riff_chunkv_t * chunk_path_ptr, FILE * f, uint64_t position, void * cookie) { riff_chunk_t cur; char buf[5]; int i; cur = VEC_TOP(*chunk_path_ptr); fourcc_to_string(cur.fourcc, buf); assert(cur.pos_content == position); for(i=0; i<VEC_SIZE(skipv); i++) { if(VEC_GET(skipv, i) == VEC_TOP(*chunk_path_ptr).fourcc) { printf("Skipping: %s\n", buf); return RIFF_SKIP_CHUNK; } } for(i=0; i<VEC_SIZE(stopv); i++) { if(VEC_GET(stopv, i) == VEC_TOP(*chunk_path_ptr).fourcc) { printf("Stoping: %s\n", buf); return RIFF_STOP; } } for(i=0; i<VEC_SIZE(readv); i++) { if(VEC_GET(readv, i) == VEC_TOP(*chunk_path_ptr).fourcc) { printf("Reading: %s\n", buf); for(; position < cur.pos_end; position++) { fgetc(f); } return RIFF_CHUNK_READ; } } for(i=0;i<VEC_SIZE(*chunk_path_ptr);i++) { cur = VEC_GET(*chunk_path_ptr, i); fourcc_to_string(cur.fourcc, buf); printf("%s:", buf); } cur = VEC_TOP(*chunk_path_ptr); printf(" %" PRIu64 " - %" PRIu64 "\n", cur.pos_head, cur.pos_end); return RIFF_CONTINUE; /* go print subchunks */ }
int mgt_commit(islpci_private *priv) { int rvalue; enum oid_num_t u; if (islpci_get_state(priv) < PRV_STATE_INIT) return 0; rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1)); if (priv->iw_mode != IW_MODE_MONITOR) rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2)); u = OID_INL_MODE; rvalue |= mgt_commit_list(priv, &u, 1); rvalue |= mgt_update_addr(priv); if (rvalue) { printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name); } return rvalue; }
int main(void) { int arr[] = {10, 12, 24, 21, 34, 37, 41, 48, 54, 59, 61, 68, 72, 77, 80, 85, 88, 91, 92, 94, 98, 100, 101, 102, 120, 130, 130, 178}; int value = 72; int result = binary_search(value, arr, VEC_SIZE(arr)); if (result == -1) printf("Element %d is not present\n", value); else printf("Element '%d' has index: '%d'\n", value, result); return(EXIT_SUCCESS); }
void clear_simul_efun_refs (void) /* GC support: clear the references of all memory held by the module. */ { if (simul_efun_vector && simul_efun_vector->ref) { simul_efun_vector->ref = 0; clear_ref_in_vector( simul_efun_vector->item, VEC_SIZE(simul_efun_vector) ); } if (simul_efun_program) simul_efun_program->ref = 0; } /* clear_simul_efun_refs() */
/*-------------------------------------------------------------------------*/ Bool assert_simul_efun_object (void) /* (Re)load the simul_efun object and extract all information we need. * Result is TRUE if either the simul_efun object could be loaded, or if * master::get_simul_efun() did not return a string/string vector to * name the simul efun object. The result is FALSE if master::get_simul_efun() * specified a simul efun object, which couldn't be found. * * In other words: after calling assert_simul_efun_object(), the caller * still has to check if simul_efun_object is NULL. * * At the time of call, simul_efun_object must be NULL. */ { svalue_t *svp; object_t *ob; program_t *progp; CBool *visible; /* Flag for every function: visible or not */ string_t *name; int i, j, num_fun; invalidate_simul_efuns(); /* Invalidate the simul_efun information */ free_defines(); /* to prevent #defines hideing places for globals */ /* Get the name(s) of the simul_efun object. */ svp = apply_master(STR_GET_SEFUN, 0); /* If a simul_efun_object appears during the GET_SEFUN call, it * might have been due to a recursive get_simul_efun() call which may * have gotten an old backup copy. This can lead to hard-to-debug * variable and function definition inconsistencies. */ if (simul_efun_object) { printf("%s simul_efun object appeared while asking for it.\n", time_stamp()); return MY_TRUE; } if (svp == NULL) { printf("%s No simul_efun\n", time_stamp()); return MY_TRUE; } if (svp->type == T_POINTER) { simul_efun_vector = svp->u.vec; svp->type = T_NUMBER; if (VEC_SIZE(svp->u.vec)) svp = svp->u.vec->item; } if (svp->type != T_STRING) { printf("%s No simul_efun\n", time_stamp()); return MY_TRUE; } /* Make the (primary) simul_efun name */ name = del_slash(svp->u.str); if (simul_efun_file_name) free_mstring(simul_efun_file_name); simul_efun_file_name = make_tabled(name); /* Get the object and load the program */ ob = find_object(simul_efun_file_name); if (ob == NULL) { fprintf(stderr, "%s The simul_efun file %s was not loaded.\n" , time_stamp(), get_txt(simul_efun_file_name)); fprintf(stderr, "%s The function get_simul_efun() in the master must load it.\n" , time_stamp()); return MY_FALSE; } if (O_PROG_SWAPPED(ob) && load_ob_from_swap(ob) < 0) { fprintf(stderr, "%s Out of memory (unswap object '%s') ==> " "No simul_efun\n", time_stamp(), get_txt(ob->name)); return MY_TRUE; } reference_prog( (simul_efun_program = ob->prog), "get_simul_efun"); num_fun = ob->prog->num_function_names; if (num_fun == 0) return MY_TRUE; if (!simul_efunp) { simul_efunp = xalloc(sizeof (function_t) * num_fun); } else num_fun = total_simul_efun; free_defines(); /* to prevent #defines hideing places for globals */ /* locals and defines are freed now. There are still reserved words, * but it is impossible to define a function with the name being * a reserved word, thus, there will be no clashes with higher-priority * shared identifiers. */ progp = ob->prog; visible = alloca((i = ob->prog->num_functions) * sizeof(*visible)); memset(visible, 0, i); i = ob->prog->num_function_names; while (--i >= 0) visible[progp->function_names[i]] = MY_TRUE; /* The functions .num_function_names+1 .. .num_functions are not * visible by definition. */ /* Loop over the functions in the simul_efun object and * copy the salient information. */ for (i = 0; i < ob->prog->num_functions; i++) { int ix; funflag_t flags, flags2; bytecode_p funstart; mp_int fun_ix_offs, var_ix_offs; program_t *inherit_progp; function_t*funheader; if (!visible[i]) continue; ix = i; flags2 = flags = progp->functions[ix]; flags &= ~FUNSTART_MASK; /* Pinpoint the function, resolving inheritance where * necessary. */ fun_ix_offs = ix; var_ix_offs = 0; inherit_progp = progp; while (flags2 & NAME_INHERITED) { inherit_t *inheritp; inheritp = &inherit_progp->inherit[flags2 & INHERIT_MASK]; ix -= inheritp->function_index_offset; var_ix_offs += inheritp->variable_index_offset; inherit_progp = inheritp->prog; flags2 = inherit_progp->functions[ix]; } fun_ix_offs -= ix; funstart = inherit_progp->program + (flags2 & FUNSTART_MASK); funheader = inherit_progp->function_headers + FUNCTION_HEADER_INDEX(funstart); /* Don't stumble over undefined functions */ if (is_undef_function(funstart)) { flags |= NAME_UNDEFINED; } /* If the function is __INIT, pretend it's a private function */ if ( !(flags & (TYPE_MOD_STATIC|TYPE_MOD_PRIVATE|NAME_UNDEFINED)) ) { if (mstreq(funheader->name, STR_VARINIT)) flags |= TYPE_MOD_PRIVATE; } /* If the function is indeed visible, get its information */ if ( !(flags & (TYPE_MOD_STATIC|TYPE_MOD_PROTECTED|TYPE_MOD_PRIVATE|NAME_UNDEFINED)) ) { string_t *function_name; ident_t *p; unsigned char num_arg; function_name = funheader->name; num_arg = funheader->num_arg; /* Find or make the identifier for the function */ p = make_shared_identifier_mstr(function_name, I_TYPE_GLOBAL, 0); if (p->type == I_TYPE_UNKNOWN) { init_global_identifier(p, /* bVariable: */ MY_FALSE); p->next_all = all_simul_efuns; all_simul_efuns = p; } if (flags & TYPE_MOD_VARARGS) num_arg = SIMUL_EFUN_VARARGS; /* Find the proper index in simul_efunp[] */ switch(0) { default: /* TRY... */ /* Try to find a discarded sefun entry with matching * name, number of arguments and XVARARGS flag to reuse. */ if (all_discarded_simul_efun >= 0) { int last; j = all_discarded_simul_efun; while ( (j = simul_efunp[last = j].offset.next_sefun) >= 0) { if (num_arg != simul_efunp[j].num_arg || 0 != ((simul_efunp[j].flags ^ flags) & TYPE_MOD_XVARARGS) ) continue; if (!mstreq(function_name, simul_efunp[j].name)) continue; /* Found one: remove it from the 'discarded' list */ simul_efunp[last].offset.next_sefun = simul_efunp[j].offset.next_sefun; break; } if (j >= 0) break; /* switch */ } /* New simul_efun: make a new entry */ (void)ref_mstring(function_name); j = num_simul_efun++; if (num_simul_efun > num_fun) { num_fun = num_simul_efun + 12; simul_efunp = rexalloc(simul_efunp , sizeof (function_t) * num_fun ); } simul_efunp[j].name = function_name; simul_efunp[j].num_arg = num_arg; } /* switch() */ /* j now indexes the simul_efunp[] entry to use */ p->u.global.sim_efun = j; simul_efunp[j].flags = funheader->flags; simul_efunp[j].type = funheader->type; simul_efunp[j].num_locals = funheader->num_locals; /* If possible, make an entry in the simul_efun table */ if ((size_t)j < SEFUN_TABLE_SIZE) { simul_efun_table[j].funstart = funstart; simul_efun_table[j].program = inherit_progp; simul_efun_table[j].function_index_offset = fun_ix_offs; simul_efun_table[j].variable_index_offset = var_ix_offs; } } /* if (function visible) */ } /* for ( all functions) */ total_simul_efun = num_fun; simul_efun_object = ob; return MY_TRUE; } /* get_simul_efun_object() */
svalue_t * f_psyc_parse (svalue_t *sp) { char *buffer = NULL; svalue_t *sv; vector_t *v, *list; mapping_t *map; char oper = 0; psycString name = {0,0}, value = {0,0}, elems[MAX_LIST_SIZE], elem; psycParseListState listState; int ret, retl, type = -1, error = 0; size_t size, i; ssize_t n; time_t timmy; if (!psyc_dispatch_callback) psyc_dispatch_callback = new_tabled("psyc_dispatch"); if (!psyc_error_callback) psyc_error_callback = new_tabled("psyc_error"); assert_shadow_sent(current_object); psyc_state_t *state = O_GET_PSYC_STATE(current_object); if (!state) { state = pxalloc(sizeof(psyc_state_t)); if (!state) { errorf("Out of memory for psyc state struct.\n"); return sp; // not reached } O_GET_PSYC_STATE(current_object) = state; memset(state, 0, sizeof(psyc_state_t)); state->parser = pxalloc(sizeof(psycParseState)); if (!state->parser) { errorf("Out of memory for psyc parse state struct.\n"); return sp; // not reached } psyc_initParseState(state->parser); } v = state->packet; if (sp->type == T_POINTER) { errorf("\npsyc_parse got %ld int* bytes... not supported yet\n", VEC_SIZE(sp->u.vec)); return sp; // not reached } else if (sp->type == T_STRING) { #ifdef DEBUG printf("\npsyc_parse got a %ld bytes long string...\n", mstrsize(sp->u.str)); #endif if (state->remaining) { // there are remaining bytes from the previous call to psyc_parse, // copy them together with the newly arrived data buffer = pxalloc(state->remaining_len + mstrsize(sp->u.str)); if (!buffer) { errorf("Out of memory for psyc_parse buffer.\n"); return sp; // not reached } memcpy(buffer, state->remaining, state->remaining_len); memcpy(buffer + state->remaining_len, get_txt(sp->u.str), mstrsize(sp->u.str)); psyc_setParseBuffer2(state->parser, buffer, state->remaining_len + mstrsize(sp->u.str)); pfree(state->remaining); state->remaining = NULL; state->remaining_len = 0; } else { psyc_setParseBuffer2(state->parser, get_txt(sp->u.str), mstrsize(sp->u.str)); } } else { errorf("\npsyc_parse got type %d, not supported\n", sp->type); return sp; // not reached } do { ret = psyc_parse(state->parser, &oper, &name, &value); #ifdef DEBUG printf("#%2d %c%.*s = %.*s\n", ret, oper ? oper : ' ', (int)name.length, name.ptr, (int)value.length, value.ptr); #endif if (!state->packet) { state->packet = allocate_array(4); if (!state->packet) { errorf("Out of memory for psyc_parse array.\n"); return sp; // not reached } v = state->packet; map = allocate_mapping(0, 2); // empty mapping if (!map) { errorf("Out of memory for psyc_parse routing header.\n"); return sp; // not reached } put_mapping(&v->item[PACKET_ROUTING], map); map = allocate_mapping(0, 2); // empty mapping if (!map) { errorf("Out of memory for psyc_parse entity header.\n"); return sp; // not reached } put_mapping(&v->item[PACKET_ENTITY], map); } switch (ret) { case PSYC_PARSE_ENTITY_START: case PSYC_PARSE_BODY_START: // save oper, name & value in state at the start of // incomplete entity or body state->oper = oper; state->name = mstring_alloc_string(name.length); memcpy(get_txt(state->name), name.ptr, name.length); if (!state->name) { errorf("Out of memory for name.\n"); return sp; // not reached } // allocate memory for the total length of the value state->value_len = 0; state->value = mstring_alloc_string(psyc_getParseValueLength(state->parser)); if (!state->value) { errorf("Out of memory for value.\n"); return sp; // not reached } // fall thru case PSYC_PARSE_ENTITY_CONT: case PSYC_PARSE_BODY_CONT: case PSYC_PARSE_ENTITY_END: case PSYC_PARSE_BODY_END: // append value to tmp buffer in state memcpy(get_txt(state->value) + state->value_len, value.ptr, value.length); state->value_len += value.length; } if (ret == PSYC_PARSE_ENTITY_END || ret == PSYC_PARSE_BODY_END) { // incomplete entity or body parsing done, // set oper/name/value to the ones saved in state oper = state->oper; name.ptr = get_txt(state->name); name.length = mstrsize(state->name); value.ptr = get_txt(state->value); value.length = mstrsize(state->value); } switch (ret) { case PSYC_PARSE_ROUTING: sv = pxalloc(sizeof(svalue_t)); // new_n_tabled fetches a reference of a probably existing // shared string put_string(sv, new_n_tabled(name.ptr, name.length)); sv = get_map_lvalue(v->item[PACKET_ROUTING].u.map, sv); put_number(&sv[1], oper); // strings are capable of containing 0 so we can do this // for binary data too. let's use a tabled string even // for values of routing variables as they repeat a lot put_string(sv, new_n_tabled(value.ptr, value.length)); break; case PSYC_PARSE_ENTITY_START: case PSYC_PARSE_ENTITY_CONT: break; case PSYC_PARSE_ENTITY_END: case PSYC_PARSE_ENTITY: sv = pxalloc(sizeof(svalue_t)); if (ret == PSYC_PARSE_ENTITY) put_string(sv, new_n_tabled(name.ptr, name.length)); else // PSYC_PARSE_ENTITY_END put_string(sv, make_tabled(state->name)); sv = get_map_lvalue(v->item[PACKET_ENTITY].u.map, sv); put_number(&sv[1], oper); type = psyc_getVarType(&name); switch (type) { case PSYC_TYPE_DATE: // number + PSYC_EPOCH if (psyc_parseDate(&value, &timmy)) put_number(sv, timmy); else error = PSYC_PARSE_ERROR_DATE; break; case PSYC_TYPE_TIME: // number if (psyc_parseTime(&value, &timmy)) put_number(sv, timmy); else error = PSYC_PARSE_ERROR_TIME; break; case PSYC_TYPE_AMOUNT: // number if (psyc_parseNumber(&value, &n)) put_number(sv, n); else error = PSYC_PARSE_ERROR_AMOUNT; break; case PSYC_TYPE_DEGREE: // first digit if (value.length && value.ptr[0] >= '0' && value.ptr[0] <= '9') put_number(sv, value.ptr[0] - '0'); else error = PSYC_PARSE_ERROR_DEGREE; break; case PSYC_TYPE_FLAG: // 0 or 1 if (value.length && value.ptr[0] >= '0' && value.ptr[0] <= '1') put_number(sv, value.ptr[0] - '0'); else error = PSYC_PARSE_ERROR_FLAG; break; case PSYC_TYPE_LIST: // array size = 0; if (value.length) { psyc_initParseListState(&listState); psyc_setParseListBuffer(&listState, value); elem = (psycString){0, 0}; do { retl = psyc_parseList(&listState, &elem); switch (retl) { case PSYC_PARSE_LIST_END: retl = 0; case PSYC_PARSE_LIST_ELEM: if (size >= MAX_LIST_SIZE) { error = PSYC_PARSE_ERROR_LIST_TOO_LARGE; break; } elems[size++] = elem; break; default: error = PSYC_PARSE_ERROR_LIST; } } while (retl > 0 && !error); } if (error) break; list = allocate_array(size); for (i = 0; i < size; i++) put_string(&list->item[i], new_n_tabled(elems[i].ptr, elems[i].length)); put_array(sv, list); break; default: // string if (ret == PSYC_PARSE_ENTITY) // is it good to put entity variable values into the // shared string table? probably yes.. but it's a guess //t_string(sv, new_n_mstring(value.ptr, value.length)); put_string(sv, new_n_tabled(value.ptr, value.length)); else // PSYC_PARSE_ENTITY_END put_string(sv, state->value); } break; case PSYC_PARSE_BODY_START: case PSYC_PARSE_BODY_CONT: break; case PSYC_PARSE_BODY_END: put_string(&v->item[PACKET_METHOD], make_tabled(state->name)); put_string(&v->item[PACKET_BODY], state->value); break; case PSYC_PARSE_BODY: // new_n_tabled gets the shared string for the method put_string(&v->item[PACKET_METHOD], new_n_tabled(name.ptr, name.length)); // allocate an untabled string for the packet body put_string(&v->item[PACKET_BODY], new_n_mstring(value.ptr, value.length)); break; case PSYC_PARSE_COMPLETE: put_array(inter_sp, v); sapply(psyc_dispatch_callback, current_object, 1); state->packet = NULL; break; case PSYC_PARSE_INSUFFICIENT: // insufficient data, save remaining bytes state->remaining_len = psyc_getParseRemainingLength(state->parser); if (state->remaining_len) { state->remaining = pxalloc(state->remaining_len); memcpy(state->remaining, psyc_getParseRemainingBuffer(state->parser), state->remaining_len); } else state->remaining = NULL; ret = 0; break; default: error = ret; } switch (ret) { case PSYC_PARSE_BODY_END: case PSYC_PARSE_ENTITY_END: // reset tmp buffers in state when incomplete // entity or body parsing is finished state->oper = 0; state->name = NULL; state->value = NULL; } } while (ret && !error); if (buffer) pfree(buffer); free_svalue(sp); put_number(sp, error); return sp; } /* f_psyc_parse */
/*-------------------------------------------------------------------------*/ static svalue_t * insert_alist (svalue_t *key, svalue_t * /* TODO: bool */ key_data, vector_t *list) /* Implementation of efun insert_alist() * * The function can be used in two ways: * * 1. Insert/replace a (new) <key>:<keydata> tuple into the alist <list>. * <key> and <key_data> have to point to an array of svalues. The first * element is the key value, the following values the associated * data values. The function will read as many elements from the * array as necessary to fill the alist <list>. * Result is a fresh copy of the modified alist. * * 2. Lookup a <key> in the alist <list> and return its index. If the key * is not found, return the position at which it would be inserted. * <key_data> must be NULL, <key> points to the svalue to be looked * up, and <list> points to an alist with at least the key vector. * * If <list> is no alist, the result can be wrong (case 2.) or not * an alist either (case 1.). * * If the <key> is a string, it is made shared. * * TODO: Make the hidden flag 'key_data' a real flag. */ { static svalue_t stmp; /* Result value */ mp_int i,j,ix; mp_int keynum, list_size; /* Number of keys, number of alist vectors */ int new_member; /* Flag if a new tuple is given */ /* If key is a string, make it shared */ if (key->type == T_STRING && !mstr_tabled(key->u.str)) { key->u.str = make_tabled(key->u.str); } keynum = (mp_int)VEC_SIZE(list->item[0].u.vec); /* Locate the key */ ix = lookup_key(key, list->item[0].u.vec); /* If its just a lookup: return the result. */ if (key_data == NULL) { put_number(&stmp, ix < 0 ? -ix-1 : ix); return &stmp; } /* Prepare the result alist vector */ put_array(&stmp, allocate_array(list_size = (mp_int)VEC_SIZE(list))); new_member = ix < 0; if (new_member) ix = -ix-1; /* Loop over all key/data vectors in <list>, insert/replace the * new value and put the new vector into <stmp>. */ for (i = 0; i < list_size; i++) { vector_t *vtmp; if (new_member) { svalue_t *pstmp = list->item[i].u.vec->item; vtmp = allocate_array(keynum+1); for (j=0; j < ix; j++) { assign_svalue_no_free(&vtmp->item[j], pstmp++); } assign_svalue_no_free(&vtmp->item[ix], i ? &key_data[i] : key ); for (j = ix+1; j <= keynum; j++) { assign_svalue_no_free(&vtmp->item[j], pstmp++); } } else { vtmp = slice_array(list->item[i].u.vec, 0, keynum-1); if (i) assign_svalue(&vtmp->item[ix], &key_data[i]); /* No need to assign the key value: it's already there. */ } stmp.u.vec->item[i].type=T_POINTER; stmp.u.vec->item[i].u.vec=vtmp; } /* Done */ return &stmp; } /* insert_alist() */
svalue_t * f_psyc_render(svalue_t *sp) { uint8_t i; vector_t *v; string_t *out; char *meth, *body; size_t mlen, blen; mapping_t *map; psycPacket packet; psycHeader headers[2]; // unless (sp->type == T_POINTER) return sp; v = sp->u.vec; if (VEC_SIZE(v) == PACKET_BODY + 1) { for (i = PACKET_ROUTING; i <= PACKET_ENTITY; i++) { headers[i].lines = 0; if (v->item[i].type == T_MAPPING) { map = v->item[i].u.map; if (!MAP_SIZE(map)) continue; headers[i].modifiers = malloc(sizeof(psycModifier) * MAP_SIZE(v->item[i].u.map)); if (!headers[i].modifiers) { errorf("Out of memory in psyc_render for modifier table.\n"); return sp; // not reached } walk_mapping(map, &fill_header_from_mapping, &(psyc_modifier_t) { &headers[i], map->num_values, i == PACKET_ROUTING ? PSYC_MODIFIER_ROUTING : PSYC_MODIFIER_CHECK_LENGTH }); } // else ... ignoring possibly invalid args } } else { errorf("Wrong number of elements (%" PRIdMPINT ") " "in array argument to psyc_render()\n", VEC_SIZE(v)); return sp; // not reached } if (v->item[PACKET_METHOD].type == T_STRING) { meth = get_txt(v->item[PACKET_METHOD].u.str); mlen = mstrsize(v->item[PACKET_METHOD].u.str); } else { meth = NULL; mlen = 0; } if (v->item[PACKET_BODY].type == T_STRING) { body = get_txt(v->item[PACKET_BODY].u.str); blen = mstrsize(v->item[PACKET_BODY].u.str); } else { body = NULL; blen = 0; } packet = psyc_newPacket2(headers[PACKET_ROUTING].modifiers, headers[PACKET_ROUTING].lines, headers[PACKET_ENTITY].modifiers, headers[PACKET_ENTITY].lines, meth, mlen, body, blen, PSYC_PACKET_CHECK_LENGTH); #ifdef DEBUG printf("rendering... packet.length = %ld\n", packet.length); #endif // alloc_mstring creates an *untabled* string suitable for tmp data memsafe(out = alloc_mstring(packet.length), packet.length, "f_psyc_render"); psyc_render(&packet, get_txt(out), packet.length); free_svalue(sp); put_string(sp, out); // stack should take care of freeing the string after use return sp; } /* f_psyc_render */
/*-------------------------------------------------------------------------*/ svalue_t * v_insert_alist (svalue_t *sp, int num_arg) /* EFUN insert_alist() * * mixed* insert_alist (mixed key, mixed data..., mixed * alist) * int insert_alist (mixed key, mixed * keys) * * 1. Form: Alist Insertion * * The <key> and all following <data> values are inserted * into the <alist>. If an entry for <key> already exists * in the list, just the data values are replaced. The number * of <data> values must match the number of data arrays * in the alist, naturally. * * Result is the updated <alist>. * * 2. Form: Key Insertion * * Insert the <key> into the (ordered) array of <keys>, so that * subsequent assoc()s can perform quick lookups. Result is the * index at which <key> was inserted (or already found). * * CAVEAT: when working with string keys, the index might no longer * be valid after the next call to insert_alist(). */ /* 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. */ { int i; vector_t *list; long listsize; size_t keynum; svalue_t *key,*key_data,*ret; static LOCAL_VEC1(insert_alist_vec, T_NUMBER); /* Mock-alist for the insert_alist() key-insertion form. */ if (sp->type != T_POINTER) vefun_arg_error(num_arg, T_POINTER, sp->type, sp); /* Make up an alist if only a key-insertion is required */ if ( !(listsize = (long)VEC_SIZE(sp->u.vec)) || sp->u.vec->item[0].type != T_POINTER ) { list = &insert_alist_vec.v; *list->item = *sp; listsize = 1; } else list = sp->u.vec; /* Check the validity of the alist */ keynum = VEC_SIZE(list->item[0].u.vec); for (i = 1; i < listsize; i++) { if (list->item[i].type != T_POINTER || (size_t)VEC_SIZE(list->item[i].u.vec) != keynum) { errorf("Type or size mismatch of the data arrays.\n"); /* NOTREACHED */ return sp; } } /* Get and test the data to insert */ if (num_arg == 2) { if (sp[-1].type != T_POINTER) { key_data = NULL; key = sp-1; } else { if (VEC_SIZE(sp[-1].u.vec) != listsize) { errorf("Size mismatch of the data arrays: " "vec size %ld, list size %ld.\n" , (long)VEC_SIZE(sp[-1].u.vec), (long)listsize ); /* NOTREACHED */ return sp; } key_data = key = sp[-1].u.vec->item; } } else { if (num_arg - 1 != listsize) { errorf("Not enough data given: %ld arguments, %ld listsize.\n" , (long)num_arg - 1, (long)listsize); /* NOTREACHED */ return sp; } key_data = key = sp-num_arg+1; } /* Do the insertion */ ret = insert_alist(key,key_data,list); sp = pop_n_elems(num_arg, sp); sp++; *sp = *ret; return sp; } /* v_insert_alist() */
/* * os_badblocks_get -- returns 0 and bad blocks in the 'bbs' array * (that has to be pre-allocated) * or -1 in case of an error */ int os_badblocks_get(const char *file, struct badblocks *bbs) { LOG(3, "file %s badblocks %p", file, bbs); ASSERTne(bbs, NULL); VEC(bbsvec, struct bad_block) bbv = VEC_INITIALIZER; struct extents *exts = NULL; long extents = 0; unsigned long long bb_beg; unsigned long long bb_end; unsigned long long bb_len; unsigned long long bb_off; unsigned long long ext_beg; unsigned long long ext_end; unsigned long long not_block_aligned; int bb_found = -1; /* -1 means an error */ memset(bbs, 0, sizeof(*bbs)); if (os_dimm_files_namespace_badblocks(file, bbs)) { LOG(1, "checking the file for bad blocks failed -- '%s'", file); goto error_free_all; } if (bbs->bb_cnt == 0) { bb_found = 0; goto exit_free_all; } exts = Zalloc(sizeof(struct extents)); if (exts == NULL) { ERR("!Zalloc"); goto error_free_all; } extents = os_extents_count(file, exts); if (extents < 0) { LOG(1, "counting file's extents failed -- '%s'", file); goto error_free_all; } if (extents == 0) { /* dax device has no extents */ bb_found = (int)bbs->bb_cnt; for (unsigned b = 0; b < bbs->bb_cnt; b++) { LOG(4, "bad block found: offset: %llu, length: %u", bbs->bbv[b].offset, bbs->bbv[b].length); } goto exit_free_all; } exts->extents = Zalloc(exts->extents_count * sizeof(struct extent)); if (exts->extents == NULL) { ERR("!Zalloc"); goto error_free_all; } if (os_extents_get(file, exts)) { LOG(1, "getting file's extents failed -- '%s'", file); goto error_free_all; } bb_found = 0; for (unsigned b = 0; b < bbs->bb_cnt; b++) { bb_beg = bbs->bbv[b].offset; bb_end = bb_beg + bbs->bbv[b].length - 1; for (unsigned e = 0; e < exts->extents_count; e++) { ext_beg = exts->extents[e].offset_physical; ext_end = ext_beg + exts->extents[e].length - 1; /* check if the bad block overlaps with file's extent */ if (bb_beg > ext_end || ext_beg > bb_end) continue; bb_found++; bb_beg = (bb_beg > ext_beg) ? bb_beg : ext_beg; bb_end = (bb_end < ext_end) ? bb_end : ext_end; bb_len = bb_end - bb_beg + 1; bb_off = bb_beg + exts->extents[e].offset_logical - exts->extents[e].offset_physical; LOG(10, "bad block found: physical offset: %llu, length: %llu", bb_beg, bb_len); /* check if offset is block-aligned */ not_block_aligned = bb_off & (exts->blksize - 1); if (not_block_aligned) { bb_off -= not_block_aligned; bb_len += not_block_aligned; } /* check if length is block-aligned */ bb_len = ALIGN_UP(bb_len, exts->blksize); LOG(4, "bad block found: logical offset: %llu, length: %llu", bb_off, bb_len); /* * Form a new bad block structure with offset and length * expressed in bytes and offset relative * to the beginning of the file. */ struct bad_block bb; bb.offset = bb_off; bb.length = (unsigned)(bb_len); /* unknown healthy replica */ bb.nhealthy = NO_HEALTHY_REPLICA; /* add the new bad block to the vector */ if (VEC_PUSH_BACK(&bbv, bb)) { VEC_DELETE(&bbv); bb_found = -1; goto error_free_all; } } } error_free_all: Free(bbs->bbv); bbs->bbv = NULL; bbs->bb_cnt = 0; exit_free_all: if (exts) { Free(exts->extents); Free(exts); } if (extents > 0 && bb_found > 0) { bbs->bbv = VEC_ARR(&bbv); bbs->bb_cnt = (unsigned)VEC_SIZE(&bbv); LOG(10, "number of bad blocks detected: %u", bbs->bb_cnt); /* sanity check */ ASSERTeq((unsigned)bb_found, bbs->bb_cnt); } return (bb_found >= 0) ? 0 : -1; }
/*-------------------------------------------------------------------------*/ 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() */
void fill_header_from_mapping (svalue_t *key, svalue_t *val, void *extra) { psyc_modifier_t *m = extra; char oper = 0; char *name, *value; size_t namelen, valuelen, i; uint8_t type; svalue_t vsp, *lval; psycList list; psycString *elems = NULL; if (key->type != T_STRING) { errorf("fill_header_from_mapping: key type %d not supported\n", key->type); return; // not reached } name = get_txt(key->u.str); namelen = mstrsize(key->u.str); type = psyc_getVarType2(name, namelen); if (m->num_values > 1) oper = val[1].u.number; if (!oper) oper = C_GLYPH_OPERATOR_SET; switch (val->type) { case T_STRING: value = get_txt(val->u.str); valuelen = mstrsize(val->u.str); break; case T_NUMBER: case T_OBJECT: vsp.type = val->type; switch (val->type) { case T_NUMBER: if (type == PSYC_TYPE_DATE) vsp.u.number = val->u.number - PSYC_EPOCH; else vsp.u.number = val->u.number; break; case T_OBJECT: vsp.u.ob = val->u.ob; break; } f_to_string(&vsp); // generates an mstring value = get_txt(vsp.u.str); valuelen = mstrsize(vsp.u.str); break; case T_POINTER: if (VEC_SIZE(val->u.vec)) { elems = pxalloc(sizeof(psycString) * VEC_SIZE(val->u.vec)); if (!elems) { errorf("Out of memory in fill_header_from_mapping for elems\n"); return; // not reached } for (i = 0; i < VEC_SIZE(val->u.vec); i++) { lval = &(val->u.vec->item[i]); switch (lval->type) { case T_STRING: elems[i] = (psycString){mstrsize(lval->u.str), get_txt(lval->u.str)}; break; case T_NUMBER: case T_OBJECT: vsp.type = lval->type; switch (lval->type) { case T_NUMBER: vsp.u.number = lval->u.number; break; case T_OBJECT: vsp.u.ob = lval->u.ob; break; } f_to_string(&vsp); elems[i] = (psycString){mstrsize(vsp.u.str), get_txt(vsp.u.str)}; break; default: errorf("fill_header_from_mapping: list value type %d not supported\n", lval->type); return; // not reached } } } list = psyc_newList(elems, VEC_SIZE(val->u.vec), PSYC_LIST_CHECK_LENGTH); valuelen = list.length; value = pxalloc(valuelen); if (!value) { errorf("Out of memory in fill_header_from_mapping for list value\n"); return; // not reached } psyc_renderList(&list, value, valuelen); break; default: errorf("fill_header_from_mapping: value type %d not supported\n", val->type); return; // not reached } m->header->modifiers[m->header->lines++] = psyc_newModifier2(oper, name, namelen, value, valuelen, m->flag); }
/*-------------------------------------------------------------------------*/ svalue_t * v_order_alist (svalue_t *sp, int num_arg) /* EFUN order_alist() * * mixed *order_alist(mixed *keys, mixed *|void data, ...) * * Creates an alist. * * Either takes an array containing keys, and others containing * the associated data, where all arrays are to be of the same * length, or takes a single array that contains as first member * the array of keys and has an arbitrary number of other members * containing data, each of wich has to be of the same length as * the key array. Returns an array holding the sorted key array * and the data arrays; the same permutation that is applied to * the key array is applied to all data arrays. */ { int i; svalue_t *args; vector_t *list; long listsize; Bool reuse; size_t keynum; args = sp-num_arg+1; /* Get the key array to order */ if (num_arg == 1 && ((list = args->u.vec), (listsize = (long)VEC_SIZE(list))) && list->item[0].type == T_POINTER) { args = list->item; reuse = (list->ref == 1); } else { listsize = num_arg; reuse = MY_TRUE; } keynum = VEC_SIZE(args[0].u.vec); /* Get the data arrays to order */ for (i = 0; i < listsize; i++) { if (args[i].type != T_POINTER || (size_t)VEC_SIZE(args[i].u.vec) != keynum) { errorf("bad data array %d in call to order_alist\n",i); } } /* Create the alist */ list = order_alist(args, listsize, reuse); sp = pop_n_elems(num_arg, sp); sp++; put_array(sp, list); return sp; } /* v_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 * f_wizlist_info (svalue_t *sp) /* EFUN wizlist_info() * * mixed *wizlist_info() * * Returns an array with the interesting entries of the wizlist. * Raises a privilege_violation (wizlist_info, this_object(), 0). * * The result is an array with one entry for every wizard (uid). * Every entry is an array itself: * * string w[WL_NAME] = Name of the wizard. * int w[WL_COMMANDS] = Weighted number of commands execute by objects * of this wizard. * int w[WL_COST] and w[WL_GIGACOST] = Weighted sum of eval_costs. * int w[WL_TOTAL_COST] and w[WL_TOTAL_GIGACOST] = Total sum of * eval_costs. * int w[WL_HEART_BEATS] = Weighted count of heart_beats. * int w[WL_CALL_OUT] = Reserved for call_out() (unused yet). * int w[WL_ARRAY_TOTAL] = Total size of arrays in elements. * int w[WL_MAPPING_TOTAL] = Total size of mappings in elements. #ifdef USE_STRUCTS * int w[WL_STRUCT_TOTAL] = Total size of mappings in elements. #endif * mixed w[WL_EXTRA] = Extra wizlist-info if set. */ { vector_t *all, *entry; svalue_t *wsvp, *svp; wiz_list_t *w; if (!privilege_violation(STR_WIZLIST_INFO, &const0, sp)) { all = allocate_array(0); } else { all = allocate_array(number_of_wiz); wsvp = all->item; for (w = all_wiz; w; w = w->next) { entry = allocate_array(WL_SIZE); put_array(wsvp, entry); wsvp++; svp = entry->item; put_ref_string(&(svp[WL_NAME]), w->name); put_number(&(svp[WL_COMMANDS]), w->score); put_number(&(svp[WL_COST]), w->cost); put_number(&(svp[WL_GIGACOST]), w->gigacost); put_number(&(svp[WL_TOTAL_COST]), w->total_cost); put_number(&(svp[WL_TOTAL_GIGACOST]), w->total_gigacost); put_number(&(svp[WL_HEART_BEATS]), w->heart_beats); put_number(&(svp[WL_CALL_OUT]), 0); /* TODO: Implement me */ put_number(&(svp[WL_ARRAY_TOTAL]), w->size_array); put_number(&(svp[WL_MAPPING_TOTAL]), w->mapping_total); #ifdef USE_STRUCTS put_number(&(svp[WL_STRUCT_TOTAL]), w->struct_total); #else put_number(&(svp[WL_STRUCT_TOTAL]), 0); #endif /* USE_STRUCTS */ if (w->extra.type == T_POINTER) { vector_t *v = w->extra.u.vec; put_array(&(svp[WL_EXTRA]), slice_array(v, 0, VEC_SIZE(v) - 1)); } else assign_svalue_no_free(&(svp[WL_EXTRA]), &w->extra); } /* end for */ } /* end if */ push_array(sp, all); return sp; } /* f_wizlist_info() */
/*-------------------------------------------------------------------------*/ static size_t svalue_size (svalue_t *v, mp_int * pTotal) /* Compute the memory usage of *<v> (modified to reflect data sharing), * calling svalue_size() recursively if necessary, and return it. * The size of *v itself is not included. * *<pUnshared> and *<pShared> are set to the total unshared and shared * datasize. */ { mp_int i, composite, total, overhead; assert_stack_gap(); *pTotal = 0; total = overhead = composite = 0; switch(v->type) { case T_OBJECT: case T_NUMBER: case T_FLOAT: return 0; case T_STRING: case T_SYMBOL: // If ref==0 the string is probably shared a lot, but we can't estimate // the correct number, so we return 0 as memory consumption for the // string. if (v->u.str->info.ref) { *pTotal = mstr_mem_size(v->u.str); return *pTotal / v->u.str->info.ref; } else return 0; case T_MAPPING: { struct svalue_size_locals locals; if (NULL == register_pointer(ptable, v->u.map) ) return 0; if (v->u.map->ref) { overhead = (mp_uint)mapping_overhead(v->u.map); locals.total = 0; locals.composite = 0; locals.num_values = v->u.map->num_values; walk_mapping(v->u.map, svalue_size_map_filter, &locals); *pTotal = locals.total + overhead; return (overhead + locals.composite) / v->u.map->ref; } else return 0; } case T_POINTER: case T_QUOTED_ARRAY: { if (v->u.vec == &null_vector) return 0; if (NULL == register_pointer(ptable, v->u.vec) ) return 0; if (v->u.vec->ref) { overhead = sizeof *v->u.vec - sizeof v->u.vec->item + sizeof(svalue_t) * v->u.vec->size + sizeof(char *); for (i=0; i < (mp_int)VEC_SIZE(v->u.vec); i++) { composite += svalue_size(&v->u.vec->item[i], &total); *pTotal += total; } *pTotal += overhead; return (overhead + composite) / v->u.vec->ref; } else return 0; } case T_STRUCT: { struct_t *st = v->u.strct; if (NULL == register_pointer(ptable, st) ) return 0; if (st->ref) { overhead = sizeof *st - sizeof st->member + sizeof(svalue_t) * struct_size(st); for (i=0; i < (mp_int)struct_size(st); i++) { composite += svalue_size(&st->member[i], &total); *pTotal += total; } *pTotal += overhead; return (overhead + composite) / st->ref; } else return 0; } case T_CLOSURE: { int num_values; svalue_t *svp; lambda_t *l; if (!CLOSURE_MALLOCED(v->x.closure_type)) return 0; if (!CLOSURE_REFERENCES_CODE(v->x.closure_type)) { if (v->x.closure_type == CLOSURE_LFUN) composite = SIZEOF_LAMBDA(v->u.lambda->function.lfun.context_size); else /* CLOSURE_IDENTIFIER || CLOSURE_PRELIMINARY */ composite = sizeof *v->u.lambda; composite += sizeof(char *); *pTotal = composite; return composite / v->u.lambda->ref; } /* CLOSURE_LAMBDA */ composite = overhead = 0; l = v->u.lambda; if (v->x.closure_type == CLOSURE_BOUND_LAMBDA) { total = sizeof *l - sizeof l->function + sizeof l->function.lambda; *pTotal += total; composite += total / l->ref; l = l->function.lambda; } num_values = l->function.code.num_values; svp = (svalue_t *)l - num_values; if (NULL == register_pointer(ptable, svp)) return 0; overhead = sizeof(svalue_t) * num_values + sizeof (char *); { bytecode_p p = l->function.code.program; do { switch(GET_CODE(p++)) { case F_RETURN: case F_RETURN0: break; default: continue; } break; } while (1); overhead += (p - (bytecode_p)l + (sizeof(bytecode_p) - 1)) & ~(sizeof(bytecode_p) - 1); } while (--num_values >= 0) { composite += svalue_size(svp++, &total); *pTotal += total; } *pTotal += overhead; if (l->ref) return (overhead + composite) / l->ref; else return 0; } default: fatal("Illegal type: %d\n", v->type); } /*NOTREACHED*/ return 0; }