7
* Copyright (c) 2000, 2002 Michael J. Roberts. All Rights Reserved.
9
* Please see the accompanying license file, LICENSE.TXT, for information
10
* on using and copying this software.
14
vmiter.cpp - T3 iterator metaclass
20
04/22/00 MJRoberts - Creation
35
/* ------------------------------------------------------------------------ */
37
* Base Iterator metaclass
44
/* metaclass registration object */
45
static CVmMetaclassIter iter_metaclass_reg_obj;
46
CVmMetaclass *CVmObjIter::metaclass_reg_ = &iter_metaclass_reg_obj;
50
*CVmObjIter::func_table_[])(VMG_ vm_obj_id_t self,
51
vm_val_t *retval, uint *argc) =
53
&CVmObjIter::getp_undef,
54
&CVmObjIter::getp_get_next,
55
&CVmObjIter::getp_is_next_avail,
56
&CVmObjIter::getp_reset_iter,
57
&CVmObjIter::getp_get_cur_key,
58
&CVmObjIter::getp_get_cur_val
64
int CVmObjIter::get_prop(VMG_ vm_prop_id_t prop, vm_val_t *retval,
65
vm_obj_id_t self, vm_obj_id_t *source_obj,
70
/* translate the property into a function vector index */
71
func_idx = G_meta_table
72
->prop_to_vector_idx(metaclass_reg_->get_reg_idx(), prop);
74
/* call the appropriate function */
75
if ((this->*func_table_[func_idx])(vmg_ self, retval, argc))
77
*source_obj = metaclass_reg_->get_class_obj(vmg0_);
81
/* inherit default handling from the base object class */
82
return CVmObject::get_prop(vmg_ prop, retval, self, source_obj, argc);
85
/* ------------------------------------------------------------------------ */
87
* Indexed Iterator metaclass
94
/* metaclass registration object */
95
static CVmMetaclassIterIdx idx_metaclass_reg_obj;
96
CVmMetaclass *CVmObjIterIdx::metaclass_reg_ = &idx_metaclass_reg_obj;
98
/* create a list with no initial contents */
99
vm_obj_id_t CVmObjIterIdx::create_for_coll(VMG_ const vm_val_t *coll,
100
long first_valid_index,
101
long last_valid_index)
105
/* push the collection object reference for gc protection */
108
/* create a non-root-set object */
109
id = vm_new_id(vmg_ FALSE, TRUE, FALSE);
111
/* instantiate the iterator */
112
new (vmg_ id) CVmObjIterIdx(vmg_ coll, first_valid_index,
115
/* done with the gc protection */
118
/* return the new object's ID */
125
CVmObjIterIdx::CVmObjIterIdx(VMG_ const vm_val_t *coll,
126
long first_valid_index, long last_valid_index)
128
/* allocate space for our extension data */
129
ext_ = (char *)G_mem->get_var_heap()
130
->alloc_mem(VMOBJITERIDX_EXT_SIZE, this);
132
/* save the collection value */
133
vmb_put_dh(ext_, coll);
136
* set the current index to the first index minus 1, so that we start
137
* with the first element when we make our first call to getNext()
139
set_cur_index_no_undo(first_valid_index - 1);
141
/* remember the first and last valid index values */
142
set_first_valid(first_valid_index);
143
set_last_valid(last_valid_index);
145
/* clear the flags */
152
void CVmObjIterIdx::notify_delete(VMG_ int)
154
/* free our extension */
156
G_mem->get_var_heap()->free_mem(ext_);
160
* property evaluator - get the current item's value
162
int CVmObjIterIdx::getp_get_cur_val(VMG_ vm_obj_id_t self, vm_val_t *retval,
166
static CVmNativeCodeDesc desc(0);
168
/* check arguments */
169
if (get_prop_check_argc(retval, argc, &desc))
172
/* get the current index */
173
idx = get_cur_index();
175
/* if the current value is out of range, throw an error */
176
if (idx < 1 || idx > get_last_valid())
177
err_throw(VMERR_OUT_OF_RANGE);
179
/* retrieve the value for this index */
180
get_indexed_val(vmg_ idx, retval);
187
* property evaluator - get the current item's key
189
int CVmObjIterIdx::getp_get_cur_key(VMG_ vm_obj_id_t self, vm_val_t *retval,
193
static CVmNativeCodeDesc desc(0);
195
/* check arguments */
196
if (get_prop_check_argc(retval, argc, &desc))
199
/* get the current index */
200
idx = get_cur_index();
202
/* if the current value is out of range, throw an error */
203
if (idx < 1 || idx > get_last_valid())
204
err_throw(VMERR_OUT_OF_RANGE);
206
/* return the index */
207
retval->set_int(idx);
214
* property evaluator - get the next item
216
int CVmObjIterIdx::getp_get_next(VMG_ vm_obj_id_t self, vm_val_t *retval,
220
static CVmNativeCodeDesc desc(0);
222
/* check arguments */
223
if (get_prop_check_argc(retval, argc, &desc))
226
/* get the next index, which is one higher than the current index */
227
idx = get_cur_index() + 1;
229
/* if the current value is out of range, throw an error */
230
if (idx > get_last_valid())
231
err_throw(VMERR_OUT_OF_RANGE);
233
/* retrieve the value */
234
get_indexed_val(vmg_ idx, retval);
236
/* save the current index in our internal state */
237
set_cur_index(vmg_ self, idx);
244
* Retrieve an indexed value from my collection
246
void CVmObjIterIdx::get_indexed_val(VMG_ long idx, vm_val_t *retval)
251
/* get my collection value and the next index value */
254
/* check to see if we have an object or a constant list */
258
/* it's a constant list - index the constant value */
259
CVmObjList::index_list(vmg_ retval, coll.get_as_list(vmg0_), idx);
263
/* it's an object - index it */
264
idx_val.set_int(idx);
265
vm_objp(vmg_ coll.val.obj)
266
->index_val(vmg_ retval, coll.val.obj, &idx_val);
271
* Anything else is an error. We really should never be able to
272
* get here, since the only way to instantiate an iterator should
273
* be via the collection object's createIter() method; so if we
274
* get here it must be an internal error, hence we could probably
275
* assert failure here. Nonetheless, just throw an error, since
276
* this will make for a more pleasant indication of the problem.
278
err_throw(VMERR_BAD_TYPE_BIF);
284
* property evaluator - is next value available?
286
int CVmObjIterIdx::getp_is_next_avail(VMG_ vm_obj_id_t self, vm_val_t *retval,
289
static CVmNativeCodeDesc desc(0);
291
/* check arguments */
292
if (get_prop_check_argc(retval, argc, &desc))
296
* if the current index plus one is less than or equal to the last
297
* valid index, another item is available
299
retval->set_logical(get_cur_index() + 1 <= get_last_valid());
306
* property evaluator - reset to first item
308
int CVmObjIterIdx::getp_reset_iter(VMG_ vm_obj_id_t self, vm_val_t *retval,
311
static CVmNativeCodeDesc desc(0);
313
/* check arguments */
314
if (get_prop_check_argc(retval, argc, &desc))
317
/* set the index to the first valid index minus one */
318
set_cur_index(vmg_ self, get_first_valid() - 1);
320
/* no return value */
328
* Set the current index value, saving undo if necessary
330
void CVmObjIterIdx::set_cur_index(VMG_ vm_obj_id_t self, long idx)
332
/* save undo if necessary */
333
if (G_undo != 0 && !(get_flags() & VMOBJITERIDX_UNDO))
338
* Add the undo record. Note that the only information we need
339
* to store is the index value, so we can store this as the key
340
* value - supply a dummy payload, since we have no use for it.
343
G_undo->add_new_record_int_key(vmg_ self, get_cur_index(), &dummy);
346
* set the undo bit so we don't save redundant undo for this
349
set_flags(get_flags() | VMOBJITERIDX_UNDO);
353
set_cur_index_no_undo(idx);
359
void CVmObjIterIdx::apply_undo(VMG_ CVmUndoRecord *rec)
362
* the integer key in the undo record is my saved index value (and
363
* is the only thing in an indexed iterator that can ever change)
365
set_cur_index_no_undo(rec->id.intval);
371
void CVmObjIterIdx::mark_refs(VMG_ uint state)
375
/* if my collection is an object, mark it as referenced */
377
if (coll.typ == VM_OBJ)
378
G_obj_table->mark_all_refs(coll.val.obj, state);
382
* load from an image file
384
void CVmObjIterIdx::load_from_image(VMG_ vm_obj_id_t self,
385
const char *ptr, size_t siz)
387
/* if we already have memory allocated, free it */
390
G_mem->get_var_heap()->free_mem(ext_);
395
* Allocate a new extension. Make sure it's at least as large as
396
* the current standard extension size.
398
ext_ = (char *)G_mem->get_var_heap()
399
->alloc_mem(siz < VMOBJITERIDX_EXT_SIZE
400
? VMOBJITERIDX_EXT_SIZE : siz, this);
402
/* copy the image data to our extension */
403
memcpy(ext_, ptr, siz);
405
/* clear the undo flag */
406
set_flags(get_flags() & ~VMOBJITERIDX_UNDO);
408
/* save our image data pointer, so we can use it for reloading */
409
G_obj_table->save_image_pointer(self, ptr, siz);
413
* reload from an image file
415
void CVmObjIterIdx::reload_from_image(VMG_ vm_obj_id_t,
416
const char *ptr, size_t siz)
418
/* copy the image data over our data */
419
memcpy(ext_, ptr, siz);
421
/* clear the undo flag */
422
set_flags(get_flags() & ~VMOBJITERIDX_UNDO);
429
void CVmObjIterIdx::save_to_file(VMG_ CVmFile *fp)
431
/* write my extension */
432
fp->write_bytes(ext_, VMOBJITERIDX_EXT_SIZE);
438
void CVmObjIterIdx::restore_from_file(VMG_ vm_obj_id_t,
439
CVmFile *fp, CVmObjFixup *fixups)
441
/* free any existing extension */
444
G_mem->get_var_heap()->free_mem(ext_);
448
/* allocate a new extension */
449
ext_ = (char *)G_mem->get_var_heap()
450
->alloc_mem(VMOBJITERIDX_EXT_SIZE, this);
452
/* read my extension */
453
fp->read_bytes(ext_, VMOBJITERIDX_EXT_SIZE);
455
/* fix up my collection object reference */
456
fixups->fix_dh(vmg_ ext_);