cfad47cfa3/tads3/vmiter.cpp

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
#ifdef RCSID
2
static char RCSid[] =
3
"$Header$";
4
#endif
5
6
/* 
7
 *   Copyright (c) 2000, 2002 Michael J. Roberts.  All Rights Reserved.
8
 *   
9
 *   Please see the accompanying license file, LICENSE.TXT, for information
10
 *   on using and copying this software.  
11
 */
12
/*
13
Name
14
  vmiter.cpp - T3 iterator metaclass
15
Function
16
  
17
Notes
18
  
19
Modified
20
  04/22/00 MJRoberts  - Creation
21
*/
22
23
#include <stdlib.h>
24
#include "vmtype.h"
25
#include "vmobj.h"
26
#include "vmiter.h"
27
#include "vmglob.h"
28
#include "vmmeta.h"
29
#include "vmstack.h"
30
#include "vmundo.h"
31
#include "vmlst.h"
32
#include "vmfile.h"
33
34
35
/* ------------------------------------------------------------------------ */
36
/*
37
 *   Base Iterator metaclass 
38
 */
39
40
/*
41
 *   statics 
42
 */
43
44
/* metaclass registration object */
45
static CVmMetaclassIter iter_metaclass_reg_obj;
46
CVmMetaclass *CVmObjIter::metaclass_reg_ = &iter_metaclass_reg_obj;
47
48
/* function table */
49
int (CVmObjIter::
50
     *CVmObjIter::func_table_[])(VMG_ vm_obj_id_t self,
51
                                 vm_val_t *retval, uint *argc) =
52
{
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
59
};
60
61
/* 
62
 *   get a property 
63
 */
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,
66
                         uint *argc)
67
{
68
    uint func_idx;
69
    
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);
73
74
    /* call the appropriate function */
75
    if ((this->*func_table_[func_idx])(vmg_ self, retval, argc))
76
    {
77
        *source_obj = metaclass_reg_->get_class_obj(vmg0_);
78
        return TRUE;
79
    }
80
81
    /* inherit default handling from the base object class */
82
    return CVmObject::get_prop(vmg_ prop, retval, self, source_obj, argc);
83
}
84
85
/* ------------------------------------------------------------------------ */
86
/*
87
 *   Indexed Iterator metaclass 
88
 */
89
90
/*
91
 *   statics 
92
 */
93
94
/* metaclass registration object */
95
static CVmMetaclassIterIdx idx_metaclass_reg_obj;
96
CVmMetaclass *CVmObjIterIdx::metaclass_reg_ = &idx_metaclass_reg_obj;
97
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)
102
{
103
    vm_obj_id_t id;
104
105
    /* push the collection object reference for gc protection */
106
    G_stk->push(coll);
107
108
    /* create a non-root-set object */
109
    id = vm_new_id(vmg_ FALSE, TRUE, FALSE);
110
111
    /* instantiate the iterator */
112
    new (vmg_ id) CVmObjIterIdx(vmg_ coll, first_valid_index,
113
                                last_valid_index);
114
115
    /* done with the gc protection */
116
    G_stk->discard();
117
118
    /* return the new object's ID */
119
    return id;
120
}
121
122
/*
123
 *   constructor 
124
 */
125
CVmObjIterIdx::CVmObjIterIdx(VMG_ const vm_val_t *coll,
126
                             long first_valid_index, long last_valid_index)
127
{
128
    /* allocate space for our extension data */
129
    ext_ = (char *)G_mem->get_var_heap()
130
           ->alloc_mem(VMOBJITERIDX_EXT_SIZE, this);
131
132
    /* save the collection value */
133
    vmb_put_dh(ext_, coll);
134
135
    /* 
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() 
138
     */
139
    set_cur_index_no_undo(first_valid_index - 1);
140
141
    /* remember the first and last valid index values */
142
    set_first_valid(first_valid_index);
143
    set_last_valid(last_valid_index);
144
145
    /* clear the flags */
146
    set_flags(0);
147
}
148
149
/*
150
 *   notify of deletion 
151
 */
152
void CVmObjIterIdx::notify_delete(VMG_ int)
153
{
154
    /* free our extension */
155
    if (ext_ != 0)
156
        G_mem->get_var_heap()->free_mem(ext_);
157
}
158
159
/*
160
 *   property evaluator - get the current item's value
161
 */
162
int CVmObjIterIdx::getp_get_cur_val(VMG_ vm_obj_id_t self, vm_val_t *retval,
163
                                    uint *argc)
164
{
165
    long idx;
166
    static CVmNativeCodeDesc desc(0);
167
    
168
    /* check arguments */
169
    if (get_prop_check_argc(retval, argc, &desc))
170
        return TRUE;
171
172
    /* get the current index */
173
    idx = get_cur_index();
174
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);
178
179
    /* retrieve the value for this index */
180
    get_indexed_val(vmg_ idx, retval);
181
182
    /* handled */
183
    return TRUE;
184
}
185
186
/*
187
 *   property evaluator - get the current item's key
188
 */
189
int CVmObjIterIdx::getp_get_cur_key(VMG_ vm_obj_id_t self, vm_val_t *retval,
190
                                    uint *argc)
191
{
192
    long idx;
193
    static CVmNativeCodeDesc desc(0);
194
195
    /* check arguments */
196
    if (get_prop_check_argc(retval, argc, &desc))
197
        return TRUE;
198
199
    /* get the current index */
200
    idx = get_cur_index();
201
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);
205
206
    /* return the index */
207
    retval->set_int(idx);
208
209
    /* handled */
210
    return TRUE;
211
}
212
213
/*
214
 *   property evaluator - get the next item
215
 */
216
int CVmObjIterIdx::getp_get_next(VMG_ vm_obj_id_t self, vm_val_t *retval,
217
                                 uint *argc)
218
{
219
    long idx;
220
    static CVmNativeCodeDesc desc(0);
221
222
    /* check arguments */
223
    if (get_prop_check_argc(retval, argc, &desc))
224
        return TRUE;
225
226
    /* get the next index, which is one higher than the current index */
227
    idx = get_cur_index() + 1;
228
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);
232
233
    /* retrieve the value */
234
    get_indexed_val(vmg_ idx, retval);
235
236
    /* save the current index in our internal state */
237
    set_cur_index(vmg_ self, idx);
238
239
    /* handled */
240
    return TRUE;
241
}
242
243
/*
244
 *   Retrieve an indexed value from my collection 
245
 */
246
void CVmObjIterIdx::get_indexed_val(VMG_ long idx, vm_val_t *retval)
247
{
248
    vm_val_t coll;
249
    vm_val_t idx_val;
250
251
    /* get my collection value and the next index value */
252
    get_coll_val(&coll);
253
254
    /* check to see if we have an object or a constant list */
255
    switch(coll.typ)
256
    {
257
    case VM_LIST:
258
        /* it's a constant list - index the constant value */
259
        CVmObjList::index_list(vmg_ retval, coll.get_as_list(vmg0_), idx);
260
        break;
261
262
    case VM_OBJ:
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);
267
        break;
268
269
    default:
270
        /* 
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.  
277
         */
278
        err_throw(VMERR_BAD_TYPE_BIF);
279
        break;
280
    }
281
}
282
283
/* 
284
 *   property evaluator - is next value available? 
285
 */
286
int CVmObjIterIdx::getp_is_next_avail(VMG_ vm_obj_id_t self, vm_val_t *retval,
287
                                      uint *argc)
288
{
289
    static CVmNativeCodeDesc desc(0);
290
291
    /* check arguments */
292
    if (get_prop_check_argc(retval, argc, &desc))
293
        return TRUE;
294
295
    /* 
296
     *   if the current index plus one is less than or equal to the last
297
     *   valid index, another item is available 
298
     */
299
    retval->set_logical(get_cur_index() + 1 <= get_last_valid());
300
301
    /* handled */
302
    return TRUE;
303
}
304
305
/* 
306
 *   property evaluator - reset to first item 
307
 */
308
int CVmObjIterIdx::getp_reset_iter(VMG_ vm_obj_id_t self, vm_val_t *retval,
309
                                   uint *argc)
310
{
311
    static CVmNativeCodeDesc desc(0);
312
313
    /* check arguments */
314
    if (get_prop_check_argc(retval, argc, &desc))
315
        return TRUE;
316
317
    /* set the index to the first valid index minus one */
318
    set_cur_index(vmg_ self, get_first_valid() - 1);
319
320
    /* no return value */
321
    retval->set_nil();
322
323
    /* handled */
324
    return TRUE;
325
}
326
327
/*
328
 *   Set the current index value, saving undo if necessary 
329
 */
330
void CVmObjIterIdx::set_cur_index(VMG_ vm_obj_id_t self, long idx)
331
{
332
    /* save undo if necessary */
333
    if (G_undo != 0 && !(get_flags() & VMOBJITERIDX_UNDO))
334
    {
335
        vm_val_t dummy;
336
        
337
        /* 
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. 
341
         */
342
        dummy.set_nil();
343
        G_undo->add_new_record_int_key(vmg_ self, get_cur_index(), &dummy);
344
345
        /* 
346
         *   set the undo bit so we don't save redundant undo for this
347
         *   savepoint 
348
         */
349
        set_flags(get_flags() | VMOBJITERIDX_UNDO);
350
    }
351
352
    /* set the index */
353
    set_cur_index_no_undo(idx);
354
}
355
356
/*
357
 *   apply undo 
358
 */
359
void CVmObjIterIdx::apply_undo(VMG_ CVmUndoRecord *rec)
360
{
361
    /* 
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) 
364
     */
365
    set_cur_index_no_undo(rec->id.intval);
366
}
367
368
/*
369
 *   mark references 
370
 */
371
void CVmObjIterIdx::mark_refs(VMG_ uint state)
372
{
373
    vm_val_t coll;
374
    
375
    /* if my collection is an object, mark it as referenced */
376
    get_coll_val(&coll);
377
    if (coll.typ == VM_OBJ)
378
        G_obj_table->mark_all_refs(coll.val.obj, state);
379
}
380
381
/*
382
 *   load from an image file 
383
 */
384
void CVmObjIterIdx::load_from_image(VMG_ vm_obj_id_t self,
385
                                    const char *ptr, size_t siz)
386
{
387
    /* if we already have memory allocated, free it */
388
    if (ext_ != 0)
389
    {
390
        G_mem->get_var_heap()->free_mem(ext_);
391
        ext_ = 0;
392
    }
393
394
    /* 
395
     *   Allocate a new extension.  Make sure it's at least as large as
396
     *   the current standard extension size.  
397
     */
398
    ext_ = (char *)G_mem->get_var_heap()
399
           ->alloc_mem(siz < VMOBJITERIDX_EXT_SIZE
400
                       ? VMOBJITERIDX_EXT_SIZE : siz, this);
401
402
    /* copy the image data to our extension */
403
    memcpy(ext_, ptr, siz);
404
405
    /* clear the undo flag */
406
    set_flags(get_flags() & ~VMOBJITERIDX_UNDO);
407
408
    /* save our image data pointer, so we can use it for reloading */
409
    G_obj_table->save_image_pointer(self, ptr, siz);
410
}
411
412
/*
413
 *   reload from an image file 
414
 */
415
void CVmObjIterIdx::reload_from_image(VMG_ vm_obj_id_t,
416
                                      const char *ptr, size_t siz)
417
{
418
    /* copy the image data over our data */
419
    memcpy(ext_, ptr, siz);
420
421
    /* clear the undo flag */
422
    set_flags(get_flags() & ~VMOBJITERIDX_UNDO);
423
}
424
425
426
/*
427
 *   save 
428
 */
429
void CVmObjIterIdx::save_to_file(VMG_ CVmFile *fp)
430
{
431
    /* write my extension */
432
    fp->write_bytes(ext_, VMOBJITERIDX_EXT_SIZE);
433
}
434
435
/*
436
 *   restore 
437
 */
438
void CVmObjIterIdx::restore_from_file(VMG_ vm_obj_id_t,
439
                                      CVmFile *fp, CVmObjFixup *fixups)
440
{
441
    /* free any existing extension */
442
    if (ext_ != 0)
443
    {
444
        G_mem->get_var_heap()->free_mem(ext_);
445
        ext_ = 0;
446
    }
447
448
    /* allocate a new extension */
449
    ext_ = (char *)G_mem->get_var_heap()
450
           ->alloc_mem(VMOBJITERIDX_EXT_SIZE, this);
451
452
    /* read my extension */
453
    fp->read_bytes(ext_, VMOBJITERIDX_EXT_SIZE);
454
455
    /* fix up my collection object reference */
456
    fixups->fix_dh(vmg_ ext_);
457
}
458