~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to tads/tads3/vmiter.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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