| | 1 | /* $Header: d:/cvsroot/tads/tads3/VMLST.H,v 1.2 1999/05/17 02:52:28 MJRoberts Exp $ */ |
| | 2 | |
| | 3 | /* |
| | 4 | * Copyright (c) 1998, 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 | vmlst.h - VM dynamic list implementation |
| | 12 | Function |
| | 13 | |
| | 14 | Notes |
| | 15 | |
| | 16 | Modified |
| | 17 | 10/29/98 MJRoberts - Creation |
| | 18 | */ |
| | 19 | |
| | 20 | #ifndef VMLST_H |
| | 21 | #define VMLST_H |
| | 22 | |
| | 23 | #include <stdlib.h> |
| | 24 | #include "vmtype.h" |
| | 25 | #include "vmobj.h" |
| | 26 | #include "vmcoll.h" |
| | 27 | #include "vmglob.h" |
| | 28 | #include "vmstack.h" |
| | 29 | |
| | 30 | |
| | 31 | class CVmObjList: public CVmObjCollection |
| | 32 | { |
| | 33 | friend class CVmMetaclassList; |
| | 34 | |
| | 35 | public: |
| | 36 | /* metaclass registration object */ |
| | 37 | static class CVmMetaclass *metaclass_reg_; |
| | 38 | class CVmMetaclass *get_metaclass_reg() const { return metaclass_reg_; } |
| | 39 | |
| | 40 | /* am I of the given metaclass? */ |
| | 41 | virtual int is_of_metaclass(class CVmMetaclass *meta) const |
| | 42 | { |
| | 43 | /* try my own metaclass and my base class */ |
| | 44 | return (meta == metaclass_reg_ |
| | 45 | || CVmObjCollection::is_of_metaclass(meta)); |
| | 46 | } |
| | 47 | |
| | 48 | /* create dynamically using stack arguments */ |
| | 49 | static vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, |
| | 50 | uint argc); |
| | 51 | |
| | 52 | /* |
| | 53 | * Create dynamically from parameters in the stack; we do not remove |
| | 54 | * the elements from the stack, but simply create a list from the |
| | 55 | * parameters. 'idx' is the parameter index of the first parameter, |
| | 56 | * and 'cnt' is the number of parameters to use. |
| | 57 | */ |
| | 58 | static vm_obj_id_t create_from_params(VMG_ uint idx, uint cnt); |
| | 59 | |
| | 60 | /* |
| | 61 | * call a static property - we don't have any of our own, so simply |
| | 62 | * "inherit" the base class handling |
| | 63 | */ |
| | 64 | static int call_stat_prop(VMG_ vm_val_t *result, |
| | 65 | const uchar **pc_ptr, uint *argc, |
| | 66 | vm_prop_id_t prop) |
| | 67 | { |
| | 68 | return CVmObjCollection:: |
| | 69 | call_stat_prop(vmg_ result, pc_ptr, argc, prop); |
| | 70 | } |
| | 71 | |
| | 72 | /* reserve constant data */ |
| | 73 | virtual void reserve_const_data(VMG_ class CVmConstMapper *mapper, |
| | 74 | vm_obj_id_t self); |
| | 75 | |
| | 76 | /* convert to constant data */ |
| | 77 | virtual void convert_to_const_data(VMG_ class CVmConstMapper *mapper, |
| | 78 | vm_obj_id_t self); |
| | 79 | |
| | 80 | /* get my datatype when converted to constant data */ |
| | 81 | virtual vm_datatype_t get_convert_to_const_data_type() const |
| | 82 | { return VM_LIST; } |
| | 83 | |
| | 84 | /* create a list with no initial contents */ |
| | 85 | static vm_obj_id_t create(VMG_ int in_root_set); |
| | 86 | |
| | 87 | /* |
| | 88 | * create a list with a given number of elements, for construction |
| | 89 | * of the list element-by-element |
| | 90 | */ |
| | 91 | static vm_obj_id_t create(VMG_ int in_root_set, size_t element_count); |
| | 92 | |
| | 93 | /* |
| | 94 | * create a list from a constant list, for construction of the list |
| | 95 | * as a modified copy of an original list |
| | 96 | */ |
| | 97 | static vm_obj_id_t create(VMG_ int in_root_set, const char *lst); |
| | 98 | |
| | 99 | /* |
| | 100 | * List construction: set an element. List contents are immutable, |
| | 101 | * so they cannot be changed after the list is constructed. |
| | 102 | * However, it is often convenient to construct a list one element |
| | 103 | * at a time, so a caller can create the list with the appropriate |
| | 104 | * number of elements, then use this routine to set each element of |
| | 105 | * the list individually. |
| | 106 | * |
| | 107 | * idx is the index of the element in the list; the first element is |
| | 108 | * at index zero. Note that this routine does *not* allocate |
| | 109 | * memory; the list must be pre-allocated to its full number of |
| | 110 | * elements. |
| | 111 | */ |
| | 112 | void cons_set_element(size_t idx, const vm_val_t *val); |
| | 113 | |
| | 114 | /* update the list in place so that each value is unique */ |
| | 115 | void cons_uniquify(VMG0_); |
| | 116 | |
| | 117 | /* |
| | 118 | * Copy an existing list into our list, starting at a given index. The |
| | 119 | * caller must ensure that our list buffer is large enough to |
| | 120 | * accommodate the new elements. The 'orig_list' value must point to a |
| | 121 | * standard list constant value: a UINT2 element count prefix followed |
| | 122 | * by DATAHOLDER elements. |
| | 123 | */ |
| | 124 | void cons_copy_elements(size_t start_idx, const char *orig_list); |
| | 125 | |
| | 126 | /* |
| | 127 | * Copy existing list elements into our list, starting at the given |
| | 128 | * index. The caller must ensure that our list buffer is large enough |
| | 129 | * to accommodate the new elements. The 'ele_array' is an array of |
| | 130 | * DATAHOLDER values. |
| | 131 | */ |
| | 132 | void cons_copy_data(size_t start_idx, const char *ele_array, |
| | 133 | size_t ele_count); |
| | 134 | |
| | 135 | /* |
| | 136 | * Set the length of the list. This can be used when constructing a |
| | 137 | * list, and the actual number of elements is unknown before |
| | 138 | * construction is complete (however, the maximum number of elements |
| | 139 | * must be known in advance, since this merely sets the length, and |
| | 140 | * does NOT reallocate the list -- hence, this call can only be used |
| | 141 | * to shrink the list below its allocated size, never to expand it). |
| | 142 | */ |
| | 143 | void cons_set_len(size_t len) |
| | 144 | { vmb_put_len(ext_, len); } |
| | 145 | |
| | 146 | /* notify of deletion */ |
| | 147 | void notify_delete(VMG_ int in_root_set); |
| | 148 | |
| | 149 | /* set a property */ |
| | 150 | void set_prop(VMG_ class CVmUndo *undo, |
| | 151 | vm_obj_id_t self, vm_prop_id_t prop, const vm_val_t *val); |
| | 152 | |
| | 153 | /* get a property */ |
| | 154 | int get_prop(VMG_ vm_prop_id_t prop, vm_val_t *val, |
| | 155 | vm_obj_id_t self, vm_obj_id_t *source_obj, uint *argc); |
| | 156 | |
| | 157 | /* undo operations - lists are immutable and hence keep no undo */ |
| | 158 | void notify_new_savept() { } |
| | 159 | void apply_undo(VMG_ struct CVmUndoRecord *) { } |
| | 160 | void mark_undo_ref(VMG_ struct CVmUndoRecord *) { } |
| | 161 | void remove_stale_undo_weak_ref(VMG_ struct CVmUndoRecord *) { } |
| | 162 | |
| | 163 | /* mark references */ |
| | 164 | void mark_refs(VMG_ uint state); |
| | 165 | |
| | 166 | /* |
| | 167 | * remove weak references - we keep only normal (strong) references, |
| | 168 | * so this routine doesn't need to do anything |
| | 169 | */ |
| | 170 | void remove_stale_weak_refs(VMG0_) { } |
| | 171 | |
| | 172 | /* load from an image file */ |
| | 173 | void load_from_image(VMG_ vm_obj_id_t, const char *ptr, size_t) |
| | 174 | { ext_ = (char *)ptr; } |
| | 175 | |
| | 176 | /* rebuild for image file */ |
| | 177 | virtual ulong rebuild_image(VMG_ char *buf, ulong buflen); |
| | 178 | |
| | 179 | /* save to a file */ |
| | 180 | void save_to_file(VMG_ class CVmFile *fp); |
| | 181 | |
| | 182 | /* restore from a file */ |
| | 183 | void restore_from_file(VMG_ vm_obj_id_t self, |
| | 184 | class CVmFile *fp, class CVmObjFixup *fixups); |
| | 185 | |
| | 186 | /* |
| | 187 | * Add a value to the list. If the value to add is a list (constant |
| | 188 | * or object), we'll append each element of the list to this list; |
| | 189 | * otherwise, we'll just append the value itself to the list. In |
| | 190 | * any case, we don't modify this list itself, but create a new list |
| | 191 | * object to hold the result. |
| | 192 | */ |
| | 193 | void add_val(VMG_ vm_val_t *result, |
| | 194 | vm_obj_id_t self, const vm_val_t *val); |
| | 195 | |
| | 196 | /* |
| | 197 | * Index the list |
| | 198 | */ |
| | 199 | void index_val(VMG_ vm_val_t *result, vm_obj_id_t self, |
| | 200 | const vm_val_t *index_val); |
| | 201 | |
| | 202 | /* |
| | 203 | * Set an indexed element of the list. Since the contents of a list |
| | 204 | * object cannot be changed, we'll return in *new_container a new |
| | 205 | * list object that we create with the modified contents. |
| | 206 | */ |
| | 207 | void set_index_val(VMG_ vm_val_t *new_container, vm_obj_id_t self, |
| | 208 | const vm_val_t *index_val, const vm_val_t *new_val); |
| | 209 | |
| | 210 | /* |
| | 211 | * Subtract a value from the list. This creates a new list with the |
| | 212 | * element matching the given value removed from the original list. |
| | 213 | * We do not modify the original list; instead, we create a new list |
| | 214 | * object with the new value. |
| | 215 | */ |
| | 216 | void sub_val(VMG_ vm_val_t *result, |
| | 217 | vm_obj_id_t self, const vm_val_t *val); |
| | 218 | |
| | 219 | /* |
| | 220 | * get as a list - simply return our extension, which is in the |
| | 221 | * required portable list format |
| | 222 | */ |
| | 223 | const char *get_as_list() const { return ext_; } |
| | 224 | |
| | 225 | /* |
| | 226 | * Check a value for equality. We will match any constant list that |
| | 227 | * contains the same data as our list, and any other list object |
| | 228 | * with the same underlying data. |
| | 229 | */ |
| | 230 | int equals(VMG_ vm_obj_id_t self, const vm_val_t *val, int depth) const; |
| | 231 | |
| | 232 | /* |
| | 233 | * Static list adder. This creates a new list object that results |
| | 234 | * from appending the given value to the given list constant. This |
| | 235 | * is defined statically so that this code can be shared for adding |
| | 236 | * to constant pool lists and adding to CVmObjList objects. |
| | 237 | * |
| | 238 | * 'lstval' must point to a constant list. The first two bytes of |
| | 239 | * the list are stored in portable UINT2 format and give the number |
| | 240 | * of elements in the list; this is immediately followed by a packed |
| | 241 | * array of data holders in portable format. |
| | 242 | */ |
| | 243 | static void add_to_list(VMG_ vm_val_t *result, |
| | 244 | vm_obj_id_t self, const char *lstval, |
| | 245 | const vm_val_t *val); |
| | 246 | |
| | 247 | /* |
| | 248 | * Static list subtraction routine. This creates a new list object |
| | 249 | * that results from removing the given value from the list |
| | 250 | * constant. This is defined statically so that this code can be |
| | 251 | * shared for subtracting from constant pool lists and subtracting |
| | 252 | * from CVmObjList objects. |
| | 253 | * |
| | 254 | * 'lstmem' must point to a constant list in the same format as |
| | 255 | * required for add_to_list. If 'lstmem' comes from the constant |
| | 256 | * pool, then 'lstval' must be provided to give us the constant pool |
| | 257 | * address; otherwise, 'lstval' should be null. |
| | 258 | */ |
| | 259 | static void sub_from_list(VMG_ vm_val_t *result, |
| | 260 | const vm_val_t *lstval, const char *lstmem, |
| | 261 | const vm_val_t *val); |
| | 262 | |
| | 263 | /* |
| | 264 | * Constant list comparison routine. Compares the given list |
| | 265 | * constant (in portable format, with leading UINT2 element count |
| | 266 | * prefix followed by the list's elements in portable data holder |
| | 267 | * format) to the other value. Returns true if the other value is a |
| | 268 | * list constant or object whose contents match the list constant, |
| | 269 | * false if not. |
| | 270 | * |
| | 271 | * If 'lstmem' comes from the constant pool, then 'lstval' must be |
| | 272 | * provided to give us the constant pool address; otherwise, |
| | 273 | * 'lstval' should be null. |
| | 274 | */ |
| | 275 | static int const_equals(VMG_ const vm_val_t *lstval, const char *lstmem, |
| | 276 | const vm_val_t *val, int depth); |
| | 277 | |
| | 278 | /* |
| | 279 | * Calculate a hash value for the list |
| | 280 | */ |
| | 281 | uint calc_hash(VMG_ vm_obj_id_t self, int depth) const; |
| | 282 | |
| | 283 | /* |
| | 284 | * Constant list hash value calculation |
| | 285 | */ |
| | 286 | static uint const_calc_hash(VMG_ const vm_val_t *self_val, |
| | 287 | const char *lst, int depth); |
| | 288 | |
| | 289 | /* |
| | 290 | * When we're the right-hand side of a '+' or '-' operation whose |
| | 291 | * left-hand side is another collection type that treats these |
| | 292 | * operators as concatenation/set subtraction, add/subtract our |
| | 293 | * elements individually. |
| | 294 | */ |
| | 295 | size_t get_coll_addsub_rhs_ele_cnt(VMG0_) const |
| | 296 | { return vmb_get_len(ext_); } |
| | 297 | void get_coll_addsub_rhs_ele(VMG_ vm_val_t *result, |
| | 298 | vm_obj_id_t self, size_t idx) |
| | 299 | { index_list(vmg_ result, ext_, idx); } |
| | 300 | |
| | 301 | /* |
| | 302 | * Constant list indexing routine. Indexes the given constant list |
| | 303 | * (which must be in portable format, with leading UINT2 element |
| | 304 | * count followed by the list's elements in portable data holder |
| | 305 | * format), looking up the value at the index number given by the |
| | 306 | * index value, and puts the result in *result. |
| | 307 | */ |
| | 308 | static void index_list(VMG_ vm_val_t *result, |
| | 309 | const char *lst, const vm_val_t *index_val); |
| | 310 | |
| | 311 | /* index a list, using a 1-based index */ |
| | 312 | static void index_list(VMG_ vm_val_t *result, const char *lst, uint idx); |
| | 313 | |
| | 314 | /* push the indexed element, using a 1-based index */ |
| | 315 | static void index_and_push(VMG_ const char *lst, uint idx) |
| | 316 | { |
| | 317 | vm_val_t *p; |
| | 318 | |
| | 319 | /* push a new stack element */ |
| | 320 | p = G_stk->push(); |
| | 321 | |
| | 322 | /* index the list and store the value directly in the stack */ |
| | 323 | index_list(vmg_ p, lst, idx); |
| | 324 | } |
| | 325 | |
| | 326 | /* |
| | 327 | * Constant list set-index routine. Creates a new list object as a |
| | 328 | * copy of this list, with the element at the given index set to the |
| | 329 | * given new value. |
| | 330 | */ |
| | 331 | static void set_index_list(VMG_ vm_val_t *result, |
| | 332 | const char *lst, const vm_val_t *index_val, |
| | 333 | const vm_val_t *new_val); |
| | 334 | |
| | 335 | /* |
| | 336 | * Find a value within a list. If we find the value, we'll set |
| | 337 | * *idxp to the index (starting at zero for the first element) of |
| | 338 | * the item we found, and we'll return true; if we don't find the |
| | 339 | * value, we'll return false. |
| | 340 | */ |
| | 341 | static int find_in_list(VMG_ const vm_val_t *lst, |
| | 342 | const vm_val_t *val, size_t *idxp); |
| | 343 | |
| | 344 | /* find the last match for a value */ |
| | 345 | static int find_last_in_list(VMG_ const vm_val_t *lst, |
| | 346 | const vm_val_t *val, size_t *idxp); |
| | 347 | |
| | 348 | /* |
| | 349 | * Evaluate a property of a constant list value. Returns true if we |
| | 350 | * successfully evaluated the property, false if the property is not |
| | 351 | * one of the properties that the list class defines. |
| | 352 | */ |
| | 353 | static int const_get_prop(VMG_ vm_val_t *retval, const vm_val_t *self_val, |
| | 354 | const char *lst, vm_prop_id_t prop, |
| | 355 | vm_obj_id_t *srcobj, uint *argc); |
| | 356 | |
| | 357 | /* property evaluator - undefined property */ |
| | 358 | static int getp_undef(VMG_ vm_val_t *, const vm_val_t *, |
| | 359 | const char *, uint *) |
| | 360 | { return FALSE; } |
| | 361 | |
| | 362 | /* property evaluator - select a subset through a callback */ |
| | 363 | static int getp_subset(VMG_ vm_val_t *retval, const vm_val_t *self_val, |
| | 364 | const char *lst, uint *argc); |
| | 365 | |
| | 366 | /* property evaluator - apply a callback to each element */ |
| | 367 | static int getp_map(VMG_ vm_val_t *retval, const vm_val_t *self_val, |
| | 368 | const char *lst, uint *argc); |
| | 369 | |
| | 370 | /* get the length */ |
| | 371 | static int getp_len(VMG_ vm_val_t *retval, const vm_val_t *self_val, |
| | 372 | const char *lst, uint *argc); |
| | 373 | |
| | 374 | /* sublist */ |
| | 375 | static int getp_sublist(VMG_ vm_val_t *retval, const vm_val_t *self_val, |
| | 376 | const char *lst, uint *argc); |
| | 377 | |
| | 378 | /* intersect */ |
| | 379 | static int getp_intersect(VMG_ vm_val_t *retval, |
| | 380 | const vm_val_t *self_val, |
| | 381 | const char *lst, uint *argc); |
| | 382 | |
| | 383 | /* indexOf */ |
| | 384 | static int getp_index_of(VMG_ vm_val_t *retval, const vm_val_t *self_val, |
| | 385 | const char *lst, uint *argc); |
| | 386 | |
| | 387 | /* car */ |
| | 388 | static int getp_car(VMG_ vm_val_t *retval, const vm_val_t *self_val, |
| | 389 | const char *lst, uint *argc); |
| | 390 | |
| | 391 | /* cdr */ |
| | 392 | static int getp_cdr(VMG_ vm_val_t *retval, const vm_val_t *self_val, |
| | 393 | const char *lst, uint *argc); |
| | 394 | |
| | 395 | /* indexWhich */ |
| | 396 | static int getp_index_which(VMG_ vm_val_t *retval, |
| | 397 | const vm_val_t *self_val, |
| | 398 | const char *lst, uint *argc); |
| | 399 | |
| | 400 | /* forEach */ |
| | 401 | static int getp_for_each(VMG_ vm_val_t *retval, const vm_val_t *self_val, |
| | 402 | const char *lst, uint *argc); |
| | 403 | |
| | 404 | /* forEachAssoc */ |
| | 405 | static int getp_for_each_assoc(VMG_ vm_val_t *retval, |
| | 406 | const vm_val_t *self_val, |
| | 407 | const char *lst, uint *argc); |
| | 408 | |
| | 409 | /* valWhich */ |
| | 410 | static int getp_val_which(VMG_ vm_val_t *retval, |
| | 411 | const vm_val_t *self_val, |
| | 412 | const char *lst, uint *argc); |
| | 413 | |
| | 414 | /* lastIndexOf */ |
| | 415 | static int getp_last_index_of(VMG_ vm_val_t *retval, |
| | 416 | const vm_val_t *self_val, |
| | 417 | const char *lst, uint *argc); |
| | 418 | |
| | 419 | /* lastIndexWhich */ |
| | 420 | static int getp_last_index_which(VMG_ vm_val_t *retval, |
| | 421 | const vm_val_t *self_val, |
| | 422 | const char *lst, uint *argc); |
| | 423 | |
| | 424 | /* lastValWhich */ |
| | 425 | static int getp_last_val_which(VMG_ vm_val_t *retval, |
| | 426 | const vm_val_t *self_val, |
| | 427 | const char *lst, uint *argc); |
| | 428 | |
| | 429 | /* countOf */ |
| | 430 | static int getp_count_of(VMG_ vm_val_t *retval, |
| | 431 | const vm_val_t *self_val, |
| | 432 | const char *lst, uint *argc); |
| | 433 | |
| | 434 | /* countWhich */ |
| | 435 | static int getp_count_which(VMG_ vm_val_t *retval, |
| | 436 | const vm_val_t *self_val, |
| | 437 | const char *lst, uint *argc); |
| | 438 | |
| | 439 | /* general routine for indexWhich and lastIndexWhich */ |
| | 440 | static int gen_index_which(VMG_ vm_val_t *retval, |
| | 441 | const vm_val_t *self_val, |
| | 442 | const char *lst, uint *argc, |
| | 443 | int forward); |
| | 444 | |
| | 445 | /* getUnique */ |
| | 446 | static int getp_get_unique(VMG_ vm_val_t *retval, |
| | 447 | const vm_val_t *self_val, |
| | 448 | const char *lst, uint *argc); |
| | 449 | |
| | 450 | /* appendUnique */ |
| | 451 | static int getp_append_unique(VMG_ vm_val_t *retval, |
| | 452 | const vm_val_t *self_val, |
| | 453 | const char *lst, uint *argc); |
| | 454 | |
| | 455 | /* append */ |
| | 456 | static int getp_append(VMG_ vm_val_t *retval, |
| | 457 | const vm_val_t *self_val, |
| | 458 | const char *lst, uint *argc); |
| | 459 | |
| | 460 | /* sort */ |
| | 461 | static int getp_sort(VMG_ vm_val_t *retval, |
| | 462 | const vm_val_t *self_val, |
| | 463 | const char *lst, uint *argc); |
| | 464 | |
| | 465 | /* insertAt */ |
| | 466 | static int getp_insert_at(VMG_ vm_val_t *retval, |
| | 467 | const vm_val_t *self_val, |
| | 468 | const char *lst, uint *argc); |
| | 469 | |
| | 470 | /* prepend */ |
| | 471 | static int getp_prepend(VMG_ vm_val_t *retval, |
| | 472 | const vm_val_t *self_val, |
| | 473 | const char *lst, uint *argc); |
| | 474 | |
| | 475 | /* property evaluator - remove a single element at a given index */ |
| | 476 | static int getp_remove_element_at(VMG_ vm_val_t *retval, |
| | 477 | const vm_val_t *self_val, |
| | 478 | const char *lst, uint *argc); |
| | 479 | |
| | 480 | /* property evaluator - removeRange */ |
| | 481 | static int getp_remove_range(VMG_ vm_val_t *retval, |
| | 482 | const vm_val_t *self_val, |
| | 483 | const char *lst, uint *argc); |
| | 484 | |
| | 485 | protected: |
| | 486 | /* general processor for forEach and forEachAssoc */ |
| | 487 | static int for_each_gen(VMG_ vm_val_t *retval, |
| | 488 | const vm_val_t *self_val, |
| | 489 | const char *lst, uint *argc, |
| | 490 | int send_idx_to_cb); |
| | 491 | |
| | 492 | /* |
| | 493 | * Compute the intersection of two lists. Returns a new list with the |
| | 494 | * elements that occur in both lists. |
| | 495 | */ |
| | 496 | static vm_obj_id_t intersect(VMG_ const vm_val_t *lst1, |
| | 497 | const vm_val_t *lst2); |
| | 498 | |
| | 499 | /* insert the arguments into the list at the given index */ |
| | 500 | static void insert_elements(VMG_ vm_val_t *retval, |
| | 501 | const vm_val_t *self_val, |
| | 502 | const char *lst, uint argc, int idx); |
| | 503 | |
| | 504 | /* remove elements */ |
| | 505 | static void remove_range(VMG_ vm_val_t *retval, |
| | 506 | const vm_val_t *self_val, |
| | 507 | const char *lst, int start_idx, int del_cnt); |
| | 508 | |
| | 509 | /* create an iterator */ |
| | 510 | virtual void new_iterator(VMG_ vm_val_t *retval, |
| | 511 | const vm_val_t *self_val); |
| | 512 | |
| | 513 | /* |
| | 514 | * create a live iterator - for a list, there is no difference |
| | 515 | * between snapshot and live iterators, since a list is immutable |
| | 516 | */ |
| | 517 | virtual void new_live_iterator(VMG_ vm_val_t *retval, |
| | 518 | const vm_val_t *self_val) |
| | 519 | { new_iterator(vmg_ retval, self_val); } |
| | 520 | |
| | 521 | /* get the number of elements in the list */ |
| | 522 | size_t get_ele_count() const { return vmb_get_len(ext_); } |
| | 523 | |
| | 524 | /* get an element, given a zero-based index */ |
| | 525 | void get_element(size_t idx, vm_val_t *val) const |
| | 526 | { |
| | 527 | /* get the data from the data holder in our extension */ |
| | 528 | vmb_get_dh(get_element_ptr(idx), val); |
| | 529 | } |
| | 530 | |
| | 531 | /* get the number of elements in a constant list */ |
| | 532 | static size_t get_ele_count_const(const char *lstval) |
| | 533 | { return vmb_get_len(lstval); } |
| | 534 | |
| | 535 | /* get an element from a constant list, given a zero-based index */ |
| | 536 | static void get_element_const(const char *lstval, size_t idx, |
| | 537 | vm_val_t *val) |
| | 538 | { |
| | 539 | /* get the data from the data holder in the constant list */ |
| | 540 | vmb_get_dh(get_element_ptr_const(lstval, idx), val); |
| | 541 | } |
| | 542 | |
| | 543 | /* given an index, get a pointer to the element's data in the list */ |
| | 544 | char *get_element_ptr(size_t idx) const |
| | 545 | { |
| | 546 | /* |
| | 547 | * figure out where this element's data holder is by skipping |
| | 548 | * the count prefix, then skipping past preceding data holders |
| | 549 | */ |
| | 550 | return ext_ + VMB_LEN + (idx * VMB_DATAHOLDER); |
| | 551 | } |
| | 552 | |
| | 553 | /* |
| | 554 | * given an index, and a pointer to a constant list, get a pointer |
| | 555 | * to the element's data in the list constant |
| | 556 | */ |
| | 557 | static const char *get_element_ptr_const(const char *lstval, size_t idx) |
| | 558 | { |
| | 559 | /* |
| | 560 | * figure out where this element's data holder is by skipping |
| | 561 | * the count prefix, then skipping past preceding data holders |
| | 562 | */ |
| | 563 | return lstval + VMB_LEN + (idx * VMB_DATAHOLDER); |
| | 564 | } |
| | 565 | |
| | 566 | /* |
| | 567 | * given a pointer to a list element, increment the pointer so that |
| | 568 | * it points to the next element |
| | 569 | */ |
| | 570 | static void inc_element_ptr(char **p) |
| | 571 | { |
| | 572 | /* add the size of a data holder to the current pointer */ |
| | 573 | *p += VMB_DATAHOLDER; |
| | 574 | } |
| | 575 | |
| | 576 | /* increment a constant element pointer */ |
| | 577 | static void inc_const_element_ptr(const char **p) |
| | 578 | { |
| | 579 | /* add the size of a data holder to the current pointer */ |
| | 580 | *p += VMB_DATAHOLDER; |
| | 581 | } |
| | 582 | |
| | 583 | /* create a list with no initial contents */ |
| | 584 | CVmObjList() { ext_ = 0; } |
| | 585 | |
| | 586 | /* |
| | 587 | * create a list with a given number of elements, for construction |
| | 588 | * of the list element-by-element |
| | 589 | */ |
| | 590 | CVmObjList(VMG_ size_t element_count); |
| | 591 | |
| | 592 | /* create a list from a constant list */ |
| | 593 | CVmObjList(VMG_ const char *lst); |
| | 594 | |
| | 595 | /* |
| | 596 | * Calculate the amount of space we need to store a list of a given |
| | 597 | * length. We require two bytes for the length prefix, plus the |
| | 598 | * space for each element. |
| | 599 | */ |
| | 600 | static size_t calc_alloc(size_t elecnt) |
| | 601 | { return (VMB_LEN + (elecnt * VMB_DATAHOLDER)); } |
| | 602 | |
| | 603 | /* allocate space for the list, given the number of elements */ |
| | 604 | void alloc_list(VMG_ size_t element_count); |
| | 605 | |
| | 606 | /* property evaluation function table */ |
| | 607 | static int (*func_table_[])(VMG_ vm_val_t *retval, |
| | 608 | const vm_val_t *self_val, |
| | 609 | const char *lst, uint *argc); |
| | 610 | }; |
| | 611 | |
| | 612 | |
| | 613 | /* ------------------------------------------------------------------------ */ |
| | 614 | /* |
| | 615 | * A constant list is exactly like an ordinary list, except that our |
| | 616 | * contents come from the constant pool. We store a pointer directly to |
| | 617 | * our constant pool data rather than making a separate copy. The only |
| | 618 | * thing we have to do differently from an ordinary list is that we don't |
| | 619 | * delete our extension when we're deleted, since our extension is really |
| | 620 | * just a pointer into the constant pool. |
| | 621 | */ |
| | 622 | class CVmObjListConst: public CVmObjList |
| | 623 | { |
| | 624 | public: |
| | 625 | /* notify of deletion */ |
| | 626 | void notify_delete(VMG_ int /*in_root_set*/) |
| | 627 | { |
| | 628 | /* |
| | 629 | * do nothing, since our extension is just a pointer into the |
| | 630 | * constant pool |
| | 631 | */ |
| | 632 | } |
| | 633 | |
| | 634 | /* create from constant pool data */ |
| | 635 | static vm_obj_id_t create(VMG_ const char *const_ptr); |
| | 636 | |
| | 637 | protected: |
| | 638 | /* construct from constant pool data */ |
| | 639 | CVmObjListConst(VMG_ const char *const_ptr) |
| | 640 | { |
| | 641 | /* point our extension directly to the constant pool data */ |
| | 642 | ext_ = (char *)const_ptr; |
| | 643 | } |
| | 644 | }; |
| | 645 | |
| | 646 | /* ------------------------------------------------------------------------ */ |
| | 647 | /* |
| | 648 | * Registration table object |
| | 649 | */ |
| | 650 | class CVmMetaclassList: public CVmMetaclass |
| | 651 | { |
| | 652 | public: |
| | 653 | /* get the global name */ |
| | 654 | const char *get_meta_name() const { return "list/030007"; } |
| | 655 | |
| | 656 | /* create from image file */ |
| | 657 | void create_for_image_load(VMG_ vm_obj_id_t id) |
| | 658 | { |
| | 659 | new (vmg_ id) CVmObjList(); |
| | 660 | G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE); |
| | 661 | } |
| | 662 | |
| | 663 | /* create from restoring from saved state */ |
| | 664 | void create_for_restore(VMG_ vm_obj_id_t id) |
| | 665 | { |
| | 666 | new (vmg_ id) CVmObjList(); |
| | 667 | G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE); |
| | 668 | } |
| | 669 | |
| | 670 | /* create dynamically using stack arguments */ |
| | 671 | vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, uint argc) |
| | 672 | { return CVmObjList::create_from_stack(vmg_ pc_ptr, argc); } |
| | 673 | |
| | 674 | /* call a static property */ |
| | 675 | int call_stat_prop(VMG_ vm_val_t *result, |
| | 676 | const uchar **pc_ptr, uint *argc, |
| | 677 | vm_prop_id_t prop) |
| | 678 | { |
| | 679 | return CVmObjList::call_stat_prop(vmg_ result, pc_ptr, argc, prop); |
| | 680 | } |
| | 681 | |
| | 682 | /* I'm a Collection object */ |
| | 683 | CVmMetaclass *get_supermeta_reg() const |
| | 684 | { return CVmObjCollection::metaclass_reg_; } |
| | 685 | }; |
| | 686 | |
| | 687 | #endif /* VMLST_H */ |
| | 688 | |
| | 689 | /* |
| | 690 | * Register the class |
| | 691 | */ |
| | 692 | VM_REGISTER_METACLASS(CVmObjList) |
| | 693 | |