1 /* $Header$ */ 2 3 /* 4 * Copyright (c) 2000, 2002 Michael J. Roberts. All Rights Reserved. 5 * 6 * Please see the accompanying license file, LICENSE.TXT, for information 7 * on using and copying this software. 8 */ 9 /* 10 Name 11 vmvec.h - T3 VM Vector class 12 Function 13 A Vector is a subclass of Collection. A Vector is a List whose 14 elements can be changed in-place, and whose size can change. 15 Notes 16 17 Modified 18 05/14/00 MJRoberts - Creation 19 */ 20 21 #ifndef VMVEC_H 22 #define VMVEC_H 23 24 #include <stdlib.h> 25 #include "vmtype.h" 26 #include "vmobj.h" 27 #include "vmcoll.h" 28 #include "vmglob.h" 29 #include "vmstack.h" 30 31 /* ------------------------------------------------------------------------ */ 32 /* 33 * Vectors are very similar to lists, but a vector's contents can be 34 * modified during execution. Because vectors are dynamic, a vector's 35 * image file data are copied into the heap. 36 * 37 * A vector's image file data structure looks like this: 38 * 39 * UINT2 elements_allocated 40 *. UINT2 number_of_elements_used 41 *. DATAHOLDER element[1] 42 *. DATAHOLDER element[2] 43 *. etc, up to number_of_elements_used (NOT the number allocated) 44 * 45 * The object extension for a a vector is almost identical, but adds a 46 * prefix giving the "allocated" size of the vector, and a suffix with a 47 * pointer to our original image data (if applicable) plus one bit per 48 * element after the end of the element[] list for undo bits: 49 * 50 * UINT2 allocated_elements 51 *. UINT2 number_of_elements 52 *. DATAHOLDER element[1] 53 *. DATAHOLDER element[2] 54 *. etc 55 *. undo_bits 56 * 57 * The allocated_elements counter gives the total number of elements 58 * allocated in the vector; this can be greater than the number of 59 * elements actually in use, in which case we have free space that we can 60 * use to add elements without reallocating the vector's memory. 61 * 62 * The undo_bits are packed 8 bits per byte. Note that the undo_bits 63 * follow all allocated slots, so these do not change location when we 64 * change the number of elements actually in use. 65 */ 66 67 /* ------------------------------------------------------------------------ */ 68 /* 69 * Vector metaclass 70 */ 71 class CVmObjVector: public CVmObjCollection 72 { 73 friend class CVmMetaclassVector; 74 friend class CVmQSortVector; 75 76 public: 77 /* metaclass registration object */ 78 static class CVmMetaclass *metaclass_reg_; get_metaclass_reg()79 class CVmMetaclass *get_metaclass_reg() const { return metaclass_reg_; } 80 81 /* am I of the given metaclass? */ is_of_metaclass(class CVmMetaclass * meta)82 virtual int is_of_metaclass(class CVmMetaclass *meta) const 83 { 84 /* try my own metaclass and my base class */ 85 return (meta == metaclass_reg_ 86 || CVmObjCollection::is_of_metaclass(meta)); 87 } 88 89 /* create dynamically using stack arguments */ 90 static vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, 91 uint argc); 92 93 /* create with no initial contents */ 94 static vm_obj_id_t create(VMG_ int in_root_set); 95 96 /* create with a given number of elements */ 97 static vm_obj_id_t create(VMG_ int in_root_set, size_t element_count); 98 99 /* 100 * determine if an object is a vector - it is if the object's 101 * virtual metaclass registration index matches the class's static 102 * index 103 */ is_vector_obj(VMG_ vm_obj_id_t obj)104 static int is_vector_obj(VMG_ vm_obj_id_t obj) 105 { return vm_objp(vmg_ obj)->is_of_metaclass(metaclass_reg_); } 106 107 /* set a property */ 108 void set_prop(VMG_ class CVmUndo *undo, 109 vm_obj_id_t self, vm_prop_id_t prop, const vm_val_t *val); 110 111 /* get a property */ 112 int get_prop(VMG_ vm_prop_id_t prop, vm_val_t *val, 113 vm_obj_id_t self, vm_obj_id_t *source_obj, uint *argc); 114 115 /* add a value to the vector, yielding a new vector */ 116 void add_val(VMG_ vm_val_t *result, 117 vm_obj_id_t self, const vm_val_t *val); 118 119 /* subtract a value from the vector, yielding a new vector */ 120 void sub_val(VMG_ vm_val_t *result, 121 vm_obj_id_t self, const vm_val_t *val); 122 123 /* undo operations */ 124 void notify_new_savept(); 125 void apply_undo(VMG_ struct CVmUndoRecord *rec); 126 void mark_undo_ref(VMG_ struct CVmUndoRecord *rec); 127 128 /* we keep only strong references */ remove_stale_undo_weak_ref(VMG_ struct CVmUndoRecord *)129 void remove_stale_undo_weak_ref(VMG_ struct CVmUndoRecord *) { } 130 131 /* mark references */ 132 void mark_refs(VMG_ uint state); 133 134 /* 135 * remove weak references - we keep only normal (strong) references, 136 * so this routine doesn't need to do anything 137 */ remove_stale_weak_refs(VMG0_)138 void remove_stale_weak_refs(VMG0_) { } 139 140 /* rebuild for image file */ 141 virtual ulong rebuild_image(VMG_ char *buf, ulong buflen); 142 143 /* reserve constant data */ 144 virtual void reserve_const_data(VMG_ class CVmConstMapper *mapper, 145 vm_obj_id_t self); 146 147 /* convert to constant data */ 148 virtual void convert_to_const_data(VMG_ class CVmConstMapper *mapper, 149 vm_obj_id_t self); 150 151 /* save to a file */ 152 void save_to_file(VMG_ class CVmFile *fp); 153 154 /* restore from a file */ 155 void restore_from_file(VMG_ vm_obj_id_t self, 156 class CVmFile *fp, class CVmObjFixup *fixups); 157 158 /* load from an image file */ 159 void load_from_image(VMG_ vm_obj_id_t self, const char *ptr, size_t siz); 160 161 /* reload from the image file */ 162 void reload_from_image(VMG_ vm_obj_id_t self, 163 const char *ptr, size_t siz); 164 165 /* 166 * When we're the right-hand side of a '+' or '-' operation whose 167 * left-hand side is another collection type that treats these 168 * operators as concatenation/set subtraction, add/subtract our 169 * elements individually. 170 */ get_coll_addsub_rhs_ele_cnt(VMG0_)171 virtual size_t get_coll_addsub_rhs_ele_cnt(VMG0_) const 172 { return get_element_count(); } get_coll_addsub_rhs_ele(VMG_ vm_val_t * result,vm_obj_id_t self,size_t idx)173 virtual void get_coll_addsub_rhs_ele(VMG_ vm_val_t *result, 174 vm_obj_id_t self, size_t idx) 175 { 176 vm_val_t idx_val; 177 178 /* set up the index value */ 179 idx_val.set_int((int)idx); 180 181 /* index the vector */ 182 index_val(vmg_ result, self, &idx_val); 183 } 184 185 /* index the vector */ 186 void index_val(VMG_ vm_val_t *result, vm_obj_id_t self, 187 const vm_val_t *index_val); 188 189 /* set an indexed element of the vector */ 190 void set_index_val(VMG_ vm_val_t *new_container, vm_obj_id_t self, 191 const vm_val_t *index_val, const vm_val_t *new_val); 192 193 /* 194 * Check a value for equality. We will match any list or vector with 195 * the same number of elements and the same value for each element. 196 */ 197 int equals(VMG_ vm_obj_id_t self, const vm_val_t *val, int depth) const; 198 199 /* calculate a hash value for the vector */ 200 uint calc_hash(VMG_ vm_obj_id_t self, int depth) const; 201 202 /* 203 * assume that we've been changed since loading, if we came from the 204 * image file 205 */ is_changed_since_load()206 int is_changed_since_load() const { return TRUE; } 207 208 /* 209 * get the allocated number of elements of the vector - this will be 210 * greater than or equal to get_element_count(), and reflects the 211 * actual allocated size 212 */ get_allocated_count()213 size_t get_allocated_count() const 214 { return vmb_get_len(get_vector_ext_ptr()); } 215 216 /* get the number of elements in the vector */ get_element_count()217 size_t get_element_count() const 218 { return vmb_get_len(get_vector_ext_ptr() + 2); } 219 220 protected: 221 /* load image data */ 222 void load_image_data(VMG_ const char *ptr, size_t siz); 223 224 /* for construction, remove all redundant elements */ 225 void cons_uniquify(VMG0_); 226 227 /* uniquify the value for an appendUnique operation */ 228 void uniquify_for_append(VMG_ vm_obj_id_t self); 229 230 /* create an iterator */ 231 virtual void new_iterator(VMG_ vm_val_t *retval, 232 const vm_val_t *self_val); 233 234 /* create a live iterator */ 235 virtual void new_live_iterator(VMG_ vm_val_t *retval, 236 const vm_val_t *self_val); 237 238 /* create a copy of the object */ 239 vm_obj_id_t create_copy(VMG_ const vm_val_t *self_val); 240 241 /* create with no initial contents */ CVmObjVector()242 CVmObjVector() { ext_ = 0; } 243 244 /* create with a given number of elements */ 245 CVmObjVector(VMG_ size_t element_count); 246 247 /* get a pointer to my vector data */ get_vector_ext_ptr()248 const char *get_vector_ext_ptr() const { return ext_; } 249 250 /* 251 * get my extension data pointer for construction purposes - this is a 252 * writable pointer, so that a caller can fill our data buffer during 253 * construction 254 */ cons_get_vector_ext_ptr()255 char *cons_get_vector_ext_ptr() const { return ext_; } 256 257 /* 258 * Calculate the amount of space we need to store a list of a given 259 * length. We require two bytes for the length prefix, plus the space 260 * for each element, plus the space for the undo bits (one bit per 261 * element, but we pack eight bits per byte). 262 */ calc_alloc(size_t elecnt)263 static size_t calc_alloc(size_t elecnt) 264 { 265 return (calc_alloc_prefix_and_ele(elecnt) 266 + ((elecnt + 7) & ~7)); 267 } 268 269 /* 270 * calculate the allocation amount, including only the count prefix 271 * and element data 272 */ calc_alloc_prefix_and_ele(size_t elecnt)273 static size_t calc_alloc_prefix_and_ele(size_t elecnt) 274 { 275 return (2*VMB_LEN + calc_alloc_ele(elecnt)); 276 } 277 278 /* calculate the allocation amount, including only the element storage */ calc_alloc_ele(size_t elecnt)279 static size_t calc_alloc_ele(size_t elecnt) 280 { 281 return elecnt * VMB_DATAHOLDER; 282 } 283 284 /* notify of deletion */ 285 void notify_delete(VMG_ int in_root_set); 286 287 /* allocate space for the vector, given the number of elements */ 288 void alloc_vector(VMG_ size_t element_count); 289 290 /* expand to accommodate the given number of new elements */ 291 void expand_by(VMG_ vm_obj_id_t self, size_t added_elements); 292 293 /* get the allocation count increment */ get_alloc_count_increment()294 size_t get_alloc_count_increment() const 295 { 296 /* 297 * we might want to make this parameterizable; for now use a 298 * fixed increment size 299 */ 300 return 16; 301 } 302 303 /* get an element */ get_element(size_t idx,vm_val_t * val)304 void get_element(size_t idx, vm_val_t *val) const 305 { 306 /* get the data from the data holder in our extension */ 307 vmb_get_dh(get_element_ptr(idx), val); 308 } 309 310 /* push an element onto the stack */ push_element(VMG_ size_t idx)311 void push_element(VMG_ size_t idx) const 312 { 313 vm_val_t *p; 314 315 /* push a stack element */ 316 p = G_stk->push(); 317 318 /* 319 * get the data from the data holder in our extension directly into 320 * our new stack element 321 */ 322 vmb_get_dh(get_element_ptr(idx), p); 323 } 324 325 /* set an element, recording undo for the change */ 326 void set_element_undo(VMG_ vm_obj_id_t self, 327 size_t idx, const vm_val_t *val); 328 329 /* set an element */ set_element(size_t idx,const vm_val_t * val)330 void set_element(size_t idx, const vm_val_t *val) 331 { 332 /* set the element's data holder from the value */ 333 vmb_put_dh(get_element_ptr(idx), val); 334 } 335 336 /* set the allocated size */ set_allocated_count(size_t cnt)337 void set_allocated_count(size_t cnt) 338 { vmb_put_len(cons_get_vector_ext_ptr(), cnt); } 339 340 /* set the number of elements in the vector */ set_element_count(size_t cnt)341 void set_element_count(size_t cnt) 342 { vmb_put_len(cons_get_vector_ext_ptr() + 2, cnt); } 343 344 /* given an index, get a pointer to the element's data in the list */ get_element_ptr(size_t idx)345 char *get_element_ptr(size_t idx) const 346 { 347 /* 348 * figure out where this element's data holder is by skipping the 349 * count prefix, then skipping past preceding data holders 350 */ 351 return cons_get_vector_ext_ptr() + 2*VMB_LEN + (idx * VMB_DATAHOLDER); 352 } 353 354 /* get a constant pointer to an element */ get_element_ptr_const(const char * ext,size_t idx)355 static const char *get_element_ptr_const(const char *ext, size_t idx) 356 { 357 return ext + 2*VMB_LEN + (idx * VMB_DATAHOLDER); 358 } 359 360 /* increment an element pointer */ inc_element_ptr(char ** ptr)361 static void inc_element_ptr(char **ptr) { *ptr += VMB_DATAHOLDER; } 362 363 /* get a given undo bit */ get_undo_bit(size_t idx)364 int get_undo_bit(size_t idx) const 365 { 366 char *p; 367 int bitnum; 368 369 /* get the byte containing the bit for this index */ 370 p = get_undo_ptr() + (idx >> 3); 371 372 /* get the bit number within the byte */ 373 bitnum = (idx & 7); 374 375 /* get this bit */ 376 return ((*p & (1 << bitnum)) != 0); 377 } 378 379 /* set a given undo bit */ set_undo_bit(size_t idx,int val)380 void set_undo_bit(size_t idx, int val) 381 { 382 char *p; 383 int bitnum; 384 385 /* get the byte containing the bit for this index */ 386 p = get_undo_ptr() + (idx >> 3); 387 388 /* get the bit number within the byte */ 389 bitnum = (idx & 7); 390 391 /* set or clear the bit */ 392 if (val) 393 *p |= (1 << bitnum); 394 else 395 *p &= ~(1 << bitnum); 396 } 397 398 /* clear all undo bits */ clear_undo_bits()399 void clear_undo_bits() 400 { 401 memset(get_undo_ptr(), 0, ((get_allocated_count() + 7) & ~7)); 402 } 403 404 /* get a pointer to the first byte of the undo bits */ get_undo_ptr()405 char *get_undo_ptr() const 406 { 407 /* the undo bits follow the last element data */ 408 return (cons_get_vector_ext_ptr() 409 + 2*VMB_LEN 410 + get_allocated_count()*VMB_DATAHOLDER); 411 } 412 413 /* set the element count, saving undo for the change */ 414 void set_element_count_undo(VMG_ vm_obj_id_t self, 415 size_t new_element_count); 416 417 /* delete elements from the vector, keeping undo */ 418 void remove_elements_undo(VMG_ vm_obj_id_t self, 419 size_t start_idx, size_t del_cnt); 420 421 /* general handler for indexOf, lastIndexOf, and countOf */ 422 int gen_index_of(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc, 423 int forward, int count_only); 424 425 /* general handler for indexWhich, lastIndexWhich, and countWhich */ 426 int gen_index_which(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc, 427 int forward, int count_only); 428 429 /* property evaluator - undefined function */ getp_undef(VMG_ vm_obj_id_t,vm_val_t *,uint *)430 int getp_undef(VMG_ vm_obj_id_t, vm_val_t *, uint *) { return FALSE; } 431 432 /* property evaluator - convert to a list */ 433 int getp_to_list(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 434 435 /* property evaluator - get the number of elements */ 436 int getp_get_size(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 437 438 /* property evaluator - copy from another vector or list */ 439 int getp_copy_from(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 440 441 /* property evaluator - fill with a value */ 442 int getp_fill_val(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 443 444 /* property evaluator - select a subset */ 445 int getp_subset(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 446 447 /* property evaluator - apply a callback to each element */ 448 int getp_apply_all(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 449 450 /* property evaluator - find the first element satisfying a condition */ 451 int getp_index_which(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 452 453 /* property evaluator - call a callback on each element */ 454 int getp_for_each(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 455 456 /* property evaluator - call a callback(key,val) on each element */ 457 int getp_for_each_assoc(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 458 459 /* general processor for forEach/forEachAssoc */ 460 int for_each_gen(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc, 461 int pass_key_to_cb); 462 463 /* property evaluator - mapAll */ 464 int getp_map_all(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 465 466 /* property evaluator - indexOf */ 467 int getp_index_of(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 468 469 /* property evaluator - valWhich */ 470 int getp_val_which(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 471 472 /* property evaluator - lastIndexOf */ 473 int getp_last_index_of(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 474 475 /* property evaluator - lastIndexWhich */ 476 int getp_last_index_which(VMG_ vm_obj_id_t self, 477 vm_val_t *val, uint *argc); 478 479 /* property evaluator - valWhich */ 480 int getp_last_val_which(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 481 482 /* property evaluator - countOf */ 483 int getp_count_of(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 484 485 /* property evaluator - countWhich */ 486 int getp_count_which(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 487 488 /* property evaluator - getUnique */ 489 int getp_get_unique(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 490 491 /* property evaluator - appendUnique */ 492 int getp_append_unique(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 493 494 /* property evaluator - sort */ 495 int getp_sort(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 496 497 /* property evaluator - set the length */ 498 int getp_set_length(VMG_ vm_obj_id_t self, vm_val_t *retval, uint *argc); 499 500 /* property evaluator - insertAt */ 501 int getp_insert_at(VMG_ vm_obj_id_t self, vm_val_t *retval, uint *argc); 502 503 /* property evaluator - remove a single element at a given index */ 504 int getp_remove_element_at(VMG_ vm_obj_id_t self, vm_val_t *retval, 505 uint *argc); 506 507 /* property evaluator - removeRange */ 508 int getp_remove_range(VMG_ vm_obj_id_t self, vm_val_t *retval, uint *argc); 509 510 /* property evaluator - append a value */ 511 int getp_append(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 512 513 /* property evaluator - prepend a value */ 514 int getp_prepend(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 515 516 /* property evaluator - append everything from a collection */ 517 int getp_append_all(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc); 518 519 /* property evaluator - remove any elements with a given value */ 520 int getp_remove_element(VMG_ vm_obj_id_t self, vm_val_t *retval, 521 uint *argc); 522 523 /* property evaluation function table */ 524 static int (CVmObjVector::*func_table_[])(VMG_ vm_obj_id_t self, 525 vm_val_t *retval, uint *argc); 526 }; 527 528 529 /* ------------------------------------------------------------------------ */ 530 /* 531 * Registration table object 532 */ 533 class CVmMetaclassVector: public CVmMetaclass 534 { 535 public: 536 /* get the global name */ get_meta_name()537 const char *get_meta_name() const { return "vector/030004"; } 538 539 /* create from image file */ create_for_image_load(VMG_ vm_obj_id_t id)540 void create_for_image_load(VMG_ vm_obj_id_t id) 541 { 542 new (vmg_ id) CVmObjVector(); 543 G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE); 544 } 545 546 /* create from restoring from saved state */ create_for_restore(VMG_ vm_obj_id_t id)547 void create_for_restore(VMG_ vm_obj_id_t id) 548 { 549 new (vmg_ id) CVmObjVector(); 550 G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE); 551 } 552 553 /* create dynamically using stack arguments */ create_from_stack(VMG_ const uchar ** pc_ptr,uint argc)554 vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, uint argc) 555 { return CVmObjVector::create_from_stack(vmg_ pc_ptr, argc); } 556 557 /* call a static property */ call_stat_prop(VMG_ vm_val_t * result,const uchar ** pc_ptr,uint * argc,vm_prop_id_t prop)558 int call_stat_prop(VMG_ vm_val_t *result, 559 const uchar **pc_ptr, uint *argc, 560 vm_prop_id_t prop) 561 { 562 return CVmObjVector::call_stat_prop(vmg_ result, pc_ptr, argc, prop); 563 } 564 565 /* I'm a Collection object */ get_supermeta_reg()566 CVmMetaclass *get_supermeta_reg() const 567 { return CVmObjCollection::metaclass_reg_; } 568 }; 569 570 #endif /* VMVEC_H */ 571 572 /* 573 * Register the class 574 */ 575 VM_REGISTER_METACLASS(CVmObjVector) 576