cfad47cfa3/tads3/vmlookup.h

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
/* $Header$ */
2
3
/* 
4
 *   Copyright (c) 2001, 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
  vmlookup.h - LookupTable metaclass
12
Function
13
  
14
Notes
15
  
16
Modified
17
  02/06/01 MJRoberts  - Creation
18
*/
19
20
#ifndef VMLOOKUP_H
21
#define VMLOOKUP_H
22
23
#include "t3std.h"
24
#include "vmtype.h"
25
#include "vmglob.h"
26
#include "vmobj.h"
27
#include "vmundo.h"
28
#include "vmcoll.h"
29
#include "vmiter.h"
30
31
32
/* ------------------------------------------------------------------------ */
33
/*
34
 *   The image file data block is arranged as follows:
35
 *   
36
 *.  UINT2 bucket_count
37
 *.  UINT2 value_count
38
 *.  UINT2 first_free_index
39
 *.  UINT2 bucket_index[1]
40
 *.  UINT2 bucket_index[2]
41
 *.  ...
42
 *.  UINT2 bucket_index[N]
43
 *.  value[1]
44
 *.  value[2]
45
 *.  value[3]
46
 *.  etc
47
 *   
48
 *   value_count gives the number of value slots allocated.  Free value
49
 *   slots are kept in a linked list, the head of which is at the 1-based
50
 *   index given by first_free_index.  If first_free_index is zero, there
51
 *   are no free value slots.
52
 *   
53
 *   Each bucket_index[i] is the 1-based index of the first value in the
54
 *   chain for that hash bucket.  If the value in a bucket_index[i] is zero,
55
 *   there are values for that bucket.
56
 *   
57
 *   Each free entry has a VM_EMPTY value stored in its key to indicate that
58
 *   it's empty.
59
 *   
60
 *   Each value[i] looks like this:
61
 *   
62
 *.  DATAHOLDER key
63
 *.  DATAHOLDER value
64
 *.  UINT2 next_index
65
 *   
66
 *   next_index gives the 1-based index of the next value in the chain for
67
 *   that bucket; a value of zero indicates that this is the last value in
68
 *   the chain.  
69
 */
70
71
/* value entry size */
72
#define VMLOOKUP_VALUE_SIZE  (VMB_DATAHOLDER + VMB_DATAHOLDER + VMB_UINT2)
73
74
/* ------------------------------------------------------------------------ */
75
/*
76
 *   in-memory value entry structure 
77
 */
78
struct vm_lookup_val
79
{
80
    /* the key */
81
    vm_val_t key;
82
83
    /* the value */
84
    vm_val_t val;
85
86
    /* next entry in same hash bucket */
87
    vm_lookup_val *nxt;
88
};
89
90
/*
91
 *   Our in-memory extension data structure, which mimics the image file
92
 *   structure but uses native types.  
93
 */
94
struct vm_lookup_ext
95
{
96
    /* allocate the structure, given the number of buckets and values */
97
    static vm_lookup_ext *alloc_ext(VMG_ class CVmObjLookupTable *self,
98
                                    uint bucket_cnt, uint value_cnt);
99
100
    /* 
101
     *   Initialize the extension - puts all values into the free list and
102
     *   clears all buckets.  We don't do this automatically as part of
103
     *   allocation, because some types of allocation set up the buckets and
104
     *   free list from a known data set and thus are more efficient if they
105
     *   skip the initialization step. 
106
     */
107
    void init_ext();
108
109
    /* 
110
     *   Reallocate the structure with a larger number of values.  Copies
111
     *   all of the data from the original hash table into the new hash
112
     *   table, and deletes the old structure.  
113
     */
114
    static vm_lookup_ext *expand_ext(VMG_ class CVmObjLookupTable *self,
115
                                     vm_lookup_ext *old_ext,
116
                                     uint new_value_cnt);
117
118
    /* 
119
     *   Copy the given extension's data into myself.  This can only be used
120
     *   when we have the same bucket count as the original (the entry count
121
     *   need not be the same, but it must be large enough to hold all of
122
     *   the data from the original).
123
     *   
124
     *   This loses any data previously in the table.  
125
     */
126
    void copy_ext_from(vm_lookup_ext *old_ext);
127
128
    /* allocate a value entry out of my free list */
129
    vm_lookup_val *alloc_val_entry()
130
    {
131
        vm_lookup_val *entry;
132
        
133
        /* if the free list is empty, return failure */
134
        if (first_free == 0)
135
            return 0;
136
137
        /* take the first item off the free list */
138
        entry = first_free;
139
140
        /* unlink it from the free list */
141
        first_free = first_free->nxt;
142
143
        /* return the allocated item */
144
        return entry;
145
    }
146
147
    /* 
148
     *   Add a value into the given hash bucket.  The caller is responsible
149
     *   for ensuring there's enough room. 
150
     */
151
    void add_val(uint hash, const vm_val_t *key, const vm_val_t *val)
152
    {
153
        vm_lookup_val *entry;
154
        
155
        /* allocate a new entry */
156
        entry = alloc_val_entry();
157
158
        /* set it up with the new data */
159
        entry->key = *key;
160
        entry->val = *val;
161
162
        /* link it into the given bucket */
163
        entry->nxt = buckets[hash];
164
        buckets[hash] = entry;
165
    }
166
167
    /* 
168
     *   Given a pool index, retrieve a value entry from our pool of value
169
     *   entries.  This has nothing to do with the hash bucket lists or the
170
     *   free list - this is simply the nth entry in the master pool of all
171
     *   values.  
172
     */
173
    vm_lookup_val *idx_to_val(uint idx) const
174
    {
175
        vm_lookup_val *pool;
176
177
        /* the pool of values starts immediately after the buckets */
178
        pool = (vm_lookup_val *)(void *)&buckets[bucket_cnt];
179
180
        /* return the nth element of the pool */
181
        return &pool[idx];
182
    }
183
184
    /* given a value entry, get the pool index */
185
    uint val_to_idx(vm_lookup_val *val) const
186
    {
187
        return (val - idx_to_val(0));
188
    }
189
190
    /* 
191
     *   Convert an image-file or save-file index to a value pointer.  These
192
     *   are given as 1-based pointers, with the special value zero used to
193
     *   indicate a null pointer. 
194
     */
195
    vm_lookup_val *img_idx_to_val(uint idx) const
196
    {
197
        if (idx == 0)
198
            return 0;
199
        else
200
            return idx_to_val(idx - 1);
201
    }
202
203
    /* convert a value pointer to an image file index */
204
    uint val_to_img_idx(vm_lookup_val *val)
205
    {
206
        /* 
207
         *   use zero for a null pointer; otherwise, use a 1-based index in
208
         *   our master value pool 
209
         */
210
        if (val == 0)
211
            return 0;
212
        else
213
            return (val - idx_to_val(0)) + 1;
214
    }
215
216
    /* number of buckets and number of allocated value entries */
217
    uint bucket_cnt;
218
    uint value_cnt;
219
220
    /* pointer to the first free value */
221
    vm_lookup_val *first_free;
222
223
    /* 
224
     *   buckets (we overallocate the structure to make room): each bucket
225
     *   points to the first entry in the list of entries at this hash value 
226
     */
227
    vm_lookup_val *buckets[1];
228
};
229
230
231
/* ------------------------------------------------------------------------ */
232
/* 
233
 *   undo action codes 
234
 */
235
enum lookuptab_undo_action
236
{
237
    /* 
238
     *   null record - we use this to mark a record that has become
239
     *   irrelevant because of a stale weak reference 
240
     */
241
    LOOKUPTAB_UNDO_NULL,
242
243
    /* we added this word to the dictionary (undo by deleting it) */
244
    LOOKUPTAB_UNDO_ADD,
245
246
    /* we deleted this word from the dictionary (undo by adding it back) */
247
    LOOKUPTAB_UNDO_DEL,
248
249
    /* we modified the value for a given key */
250
    LOOKUPTAB_UNDO_MOD
251
};
252
253
254
/* ------------------------------------------------------------------------ */
255
/*
256
 *   LookupTable metaclass 
257
 */
258
259
class CVmObjLookupTable: public CVmObjCollection
260
{
261
    friend class CVmObjIterLookupTable;
262
    friend class CVmMetaclassLookupTable;
263
    
264
public:
265
    /* metaclass registration object */
266
    static class CVmMetaclass *metaclass_reg_;
267
    class CVmMetaclass *get_metaclass_reg() const { return metaclass_reg_; }
268
269
    /* am I of the given metaclass? */
270
    virtual int is_of_metaclass(class CVmMetaclass *meta) const
271
    {
272
        /* try my own metaclass and my base class */
273
        return (meta == metaclass_reg_
274
                || CVmObjCollection::is_of_metaclass(meta));
275
    }
276
277
    /* create */
278
    static vm_obj_id_t create(VMG_ int in_root_set,
279
                              uint bucket_count, uint init_capacity);
280
281
    /* create dynamically using stack arguments */
282
    static vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr,
283
                                         uint argc);
284
285
    /* 
286
     *   call a static property - we don't have any of our own, so simply
287
     *   "inherit" the base class handling 
288
     */
289
    static int call_stat_prop(VMG_ vm_val_t *result,
290
                              const uchar **pc_ptr, uint *argc,
291
                              vm_prop_id_t prop)
292
    {
293
        return CVmObjCollection::
294
            call_stat_prop(vmg_ result, pc_ptr, argc, prop);
295
    }
296
297
    /* reserve constant data */
298
    virtual void reserve_const_data(VMG_ class CVmConstMapper *mapper,
299
                                    vm_obj_id_t self)
300
    {
301
        /* we cannot be converted to constant data */
302
    }
303
304
    /* convert to constant data */
305
    virtual void convert_to_const_data(VMG_ class CVmConstMapper *mapper,
306
                                       vm_obj_id_t self);
307
308
    /* notify of deletion */
309
    void notify_delete(VMG_ int in_root_set);
310
311
    /* set a property */
312
    void set_prop(VMG_ class CVmUndo *undo,
313
                  vm_obj_id_t self, vm_prop_id_t prop, const vm_val_t *val);
314
315
    /* get a property */
316
    int get_prop(VMG_ vm_prop_id_t prop, vm_val_t *val,
317
                 vm_obj_id_t self, vm_obj_id_t *source_obj, uint *argc);
318
319
    /* 
320
     *   receive savepoint notification - we don't keep any
321
     *   savepoint-relative records, so we don't need to do anything here 
322
     */
323
    void notify_new_savept() { }
324
325
    /* apply an undo record */
326
    void apply_undo(VMG_ struct CVmUndoRecord *rec);
327
328
    /* discard an undo record */
329
    void discard_undo(VMG_ struct CVmUndoRecord *);
330
331
    /* mark undo references */
332
    void mark_undo_ref(VMG_ struct CVmUndoRecord *rec);
333
334
    /* mark references */
335
    void mark_refs(VMG_ uint);
336
337
    /* we keep only strong references */
338
    void remove_stale_weak_refs(VMG0_) { }
339
    void remove_stale_undo_weak_ref(VMG_ struct CVmUndoRecord *) { }
340
341
    /* load from an image file */
342
    void load_from_image(VMG_ vm_obj_id_t self, const char *ptr, size_t siz);
343
344
    /* reload from an image file */
345
    void reload_from_image(VMG_ vm_obj_id_t self,
346
                           const char *ptr, size_t siz);
347
348
    /* rebuild for image file */
349
    virtual ulong rebuild_image(VMG_ char *buf, ulong buflen);
350
351
    /* save to a file */
352
    void save_to_file(VMG_ class CVmFile *fp);
353
354
    /* restore from a file */
355
    void restore_from_file(VMG_ vm_obj_id_t self,
356
                           class CVmFile *fp, class CVmObjFixup *fixups);
357
358
    /* 
359
     *   determine if we've been changed since loading - assume we have (if
360
     *   we haven't, the only harm is the cost of unnecessarily reloading or
361
     *   saving) 
362
     */
363
    int is_changed_since_load() const { return TRUE; }
364
365
    /* get a value by index */
366
    void index_val(VMG_ vm_val_t *result,
367
                   vm_obj_id_t self,
368
                   const vm_val_t *index_val);
369
370
    /* set a value by index */
371
    void set_index_val(VMG_ vm_val_t *new_container,
372
                       vm_obj_id_t self,
373
                       const vm_val_t *index_val,
374
                       const vm_val_t *new_val);
375
    
376
    /* add an entry - does not generate undo */
377
    void add_entry(VMG_ const vm_val_t *key, const vm_val_t *val);
378
379
protected:
380
    /* get and range-check the constructor arguments */
381
    static void get_constructor_args(VMG_ uint argc, size_t *bucket_count,
382
                                     size_t *init_capacity);
383
384
    /* load or reload image data */
385
    void load_image_data(VMG_ const char *ptr, size_t siz);
386
387
    /* create a new object as a copy of this object */
388
    vm_obj_id_t create_copy(VMG0_);
389
    
390
    /* add an entry, generating undo */
391
    void add_entry_undo(VMG_ vm_obj_id_t self,
392
                        const vm_val_t *key, const vm_val_t *val);
393
394
    /* delete an entry - does not generate undo */
395
    void del_entry(VMG_ const vm_val_t *key);
396
397
    /* 
398
     *   Unlink an entry - does not generate undo.  'prv_entry' is the
399
     *   previous entry in the hash chain containing this entry, and
400
     *   'hashval' is the bucket containing the entry.  Pass null for
401
     *   'prv_entry' when the entry to unlink is the first entry in its hash
402
     *   chain.  
403
     */
404
    void unlink_entry(VMG_ vm_lookup_val *entry, uint hashval,
405
                      vm_lookup_val *prv_entry);
406
    
407
    /* 
408
     *   modify an entry - changes the value associated with the given key;
409
     *   does not generate undo 
410
     */
411
    void mod_entry(VMG_ const vm_val_t *key, const vm_val_t *val);
412
413
    /* find an entry */
414
    vm_lookup_val *find_entry(VMG_ const vm_val_t *key,
415
                              uint *hashval_p, vm_lookup_val **prv_entry_p);
416
    
417
    /*
418
     *   Check the table to make sure there's enough free space to add one
419
     *   new item, and expand the table if necessary.  
420
     */
421
    void expand_if_needed(VMG0_);
422
423
    /* allocate a new entry, expanding the table if necessary */
424
    vm_lookup_val *alloc_new_entry(VMG0_);
425
426
    /* calculate a value's hash code */
427
    uint calc_key_hash(VMG_ const vm_val_t *key);
428
429
    /* get my extension data */
430
    vm_lookup_ext *get_ext() const { return (vm_lookup_ext *)ext_; }
431
432
    /* get the hash bucket count */
433
    uint get_bucket_count() const { return get_ext()->bucket_cnt; }
434
435
    /* get the value entry count */
436
    uint get_entry_count() const { return get_ext()->value_cnt; }
437
438
    /* get/set the first-free item */
439
    vm_lookup_val *get_first_free() const { return get_ext()->first_free; }
440
    void set_first_free(vm_lookup_val *p) { get_ext()->first_free = p; }
441
442
    /* get a bucket's first entry given a hash code */
443
    vm_lookup_val **get_bucket(uint hash) const
444
        { return &get_ext()->buckets[hash]; }
445
446
    /* set a bucket's contents given a hash code */
447
    void set_bucket(uint hash, vm_lookup_val *p)
448
        { get_ext()->buckets[hash] = p; }
449
450
    /* set an entry, keeping undo for the change */
451
    void set_entry_val_undo(VMG_ vm_obj_id_t self,
452
                            vm_lookup_val *entry, const vm_val_t *val);
453
454
    /* create an iterator */
455
    virtual void new_iterator(VMG_ vm_val_t *retval,
456
                              const vm_val_t *self_val);
457
458
    /* create a live iterator */
459
    virtual void new_live_iterator(VMG_ vm_val_t *retval,
460
                                   const vm_val_t *self_val);
461
462
    /* create a lookup table with no initial contents */
463
    CVmObjLookupTable() { ext_ = 0; }
464
465
    /* 
466
     *   Create a lookup table with a given number of hash table buckets,
467
     *   and the given number of entry slots.  The hash table bucket count
468
     *   is fixed for the life of the object.  The entry slot count is
469
     *   merely advisory: the table size will be increased as necessary to
470
     *   accommodate new elements.  
471
     */
472
    CVmObjLookupTable(VMG_ size_t hash_count, size_t entry_count);
473
474
    /* property evaluator - undefined function */
475
    int getp_undef(VMG_ vm_obj_id_t, vm_val_t *, uint *) { return FALSE; }
476
477
    /* property evaluator - remove an entry given the key */
478
    int getp_remove_entry(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
479
480
    /* property evaluator - determine if a given key is in the table */
481
    int getp_key_present(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
482
483
    /* property evaluator - apply a callback to each element */
484
    int getp_apply_all(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
485
486
    /* property evaluator - call a callback on each element */
487
    int getp_for_each(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
488
489
    /* property evaluator - call a callback on each element */
490
    int getp_for_each_assoc(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
491
492
    /* general forEach/forEachAssoc processor */
493
    int for_each_gen(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc,
494
                     int pass_key_to_cb);
495
496
    /* get the number of buckets in the table */
497
    int getp_count_buckets(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
498
499
    /* get the number of entries in the table */
500
    int getp_count_entries(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
501
502
    /* make a list of all of the keys in the table */
503
    int getp_keys_to_list(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
504
505
    /* make a list of all of the values in the table */
506
    int getp_vals_to_list(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
507
508
    /* general handler for making a list of keys or values */
509
    int make_list(VMG_ vm_obj_id_t self,
510
                  vm_val_t *retval, uint *argc, int store_keys);
511
512
    /* add a record to the global undo stream */
513
    void add_undo_rec(VMG_ vm_obj_id_t self,
514
                      enum lookuptab_undo_action action,
515
                      const vm_val_t *key,
516
                      const vm_val_t *old_entry_val);
517
518
    /* property evaluation function table */
519
    static int (CVmObjLookupTable::*func_table_[])(VMG_ vm_obj_id_t self,
520
        vm_val_t *retval, uint *argc);
521
};
522
523
/* ------------------------------------------------------------------------ */
524
/*
525
 *   WeakRefLookupTable - a subclass of LookupTable that places weak
526
 *   references on its values.  The keys are still strong references. 
527
 */
528
class CVmObjWeakRefLookupTable: public CVmObjLookupTable
529
{
530
    friend class CVmMetaclassWeakRefLookupTable;
531
532
public:
533
    /* metaclass registration object */
534
    static class CVmMetaclass *metaclass_reg_;
535
    class CVmMetaclass *get_metaclass_reg() const { return metaclass_reg_; }
536
537
    /* am I of the given metaclass? */
538
    virtual int is_of_metaclass(class CVmMetaclass *meta) const
539
    {
540
        /* try my own metaclass and my base class */
541
        return (meta == metaclass_reg_
542
                || CVmObjLookupTable::is_of_metaclass(meta));
543
    }
544
545
    /* create */
546
    static vm_obj_id_t create(VMG_ int in_root_set,
547
                              uint bucket_count, uint init_capacity);
548
549
    /* create dynamically using stack arguments */
550
    static vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr,
551
                                         uint argc);
552
553
    /* 
554
     *   call a static property - we don't have any of our own, so simply
555
     *   "inherit" the base class handling 
556
     */
557
    static int call_stat_prop(VMG_ vm_val_t *result,
558
                              const uchar **pc_ptr, uint *argc,
559
                              vm_prop_id_t prop)
560
    {
561
        return CVmObjLookupTable::
562
            call_stat_prop(vmg_ result, pc_ptr, argc, prop);
563
    }
564
565
    /* mark references */
566
    void mark_refs(VMG_ uint);
567
568
    /* mark undo references */
569
    void mark_undo_ref(VMG_ struct CVmUndoRecord *rec);
570
571
    /* remove stale weak references */
572
    void remove_stale_undo_weak_ref(VMG_ struct CVmUndoRecord *rec);
573
574
    /* remove stale weak references */
575
    void remove_stale_weak_refs(VMG0_);
576
577
protected:
578
    /* create a lookup table with no initial contents */
579
    CVmObjWeakRefLookupTable() { ext_ = 0; }
580
581
    /* construct */
582
    CVmObjWeakRefLookupTable(VMG_ size_t hash_count, size_t entry_count)
583
        : CVmObjLookupTable(vmg_ hash_count, entry_count) { }
584
};
585
586
/* ------------------------------------------------------------------------ */
587
/*
588
 *   LookupTable Registration table object 
589
 */
590
class CVmMetaclassLookupTable: public CVmMetaclass
591
{
592
public:
593
    /* get the global name */
594
    const char *get_meta_name() const { return "lookuptable/030002"; }
595
596
    /* create from image file */
597
    void create_for_image_load(VMG_ vm_obj_id_t id)
598
    {
599
        new (vmg_ id) CVmObjLookupTable();
600
        G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE);
601
    }
602
603
    /* create from restoring from saved state */
604
    void create_for_restore(VMG_ vm_obj_id_t id)
605
    {
606
        new (vmg_ id) CVmObjLookupTable();
607
        G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE);
608
    }
609
610
    /* create dynamically using stack arguments */
611
    vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, uint argc)
612
        { return CVmObjLookupTable::create_from_stack(vmg_ pc_ptr, argc); }
613
614
    /* call a static property */
615
    int call_stat_prop(VMG_ vm_val_t *result,
616
                       const uchar **pc_ptr, uint *argc,
617
                       vm_prop_id_t prop)
618
    {
619
        return CVmObjLookupTable::
620
            call_stat_prop(vmg_ result, pc_ptr, argc, prop);
621
    }
622
623
    /* I'm a Collection object */
624
    CVmMetaclass *get_supermeta_reg() const
625
        { return CVmObjCollection::metaclass_reg_; }
626
};
627
628
/*
629
 *   WeakRefLookupTable registration object
630
 */
631
class CVmMetaclassWeakRefLookupTable: public CVmMetaclass
632
{
633
public:
634
    /* get the global name */
635
    const char *get_meta_name() const { return "weakreflookuptable/030000"; }
636
637
    /* create from image file */
638
    void create_for_image_load(VMG_ vm_obj_id_t id)
639
        { new (vmg_ id) CVmObjWeakRefLookupTable(); }
640
641
    /* create from restoring from saved state */
642
    void create_for_restore(VMG_ vm_obj_id_t id)
643
        { new (vmg_ id) CVmObjWeakRefLookupTable(); }
644
645
    /* create dynamically using stack arguments */
646
    vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, uint argc)
647
        { return CVmObjWeakRefLookupTable::
648
        create_from_stack(vmg_ pc_ptr, argc); }
649
650
    /* call a static property */
651
    int call_stat_prop(VMG_ vm_val_t *result,
652
                       const uchar **pc_ptr, uint *argc,
653
                       vm_prop_id_t prop)
654
    {
655
        return CVmObjWeakRefLookupTable::
656
            call_stat_prop(vmg_ result, pc_ptr, argc, prop);
657
    }
658
659
    /* I'm a LookupTable object */
660
    CVmMetaclass *get_supermeta_reg() const
661
        { return CVmObjLookupTable::metaclass_reg_; }
662
};
663
664
/* ------------------------------------------------------------------------ */
665
/*
666
 *   LookupTable Iterator subclass.  This iterator is tightly coupled with
667
 *   the LookupTable class, since we must look into the internal
668
 *   implementation of the LookupTable to implement an iterator on it.  
669
 */
670
671
/*
672
 *   The extension data for an lookup table iterator consists of a reference
673
 *   to the associated LookupTable object, the current bucket index, and the
674
 *   index of the current entry.
675
 *   
676
 *   DATAHOLDER lookuptable_value
677
 *.  UINT2 cur_entry_index (1-based; zero is invalid)
678
 *.  UINT2 flags
679
 *   
680
 *   The flag values are:
681
 *   
682
 *   VMOBJITERLOOKUPTABLE_UNDO - we've saved undo for this savepoint.  If
683
 *   this is set, we won't save additional undo for the same savepoint.  
684
 */
685
686
/* total extension size */
687
#define VMOBJITERLOOKUPTABLE_EXT_SIZE  (VMB_DATAHOLDER + 2 + 2)
688
689
/* 
690
 *   flag bits 
691
 */
692
693
/* we've saved undo for the current savepoint */
694
#define VMOBJITERLOOKUPTABLE_UNDO   0x0001
695
696
/*
697
 *   LookupTable iterator class 
698
 */
699
class CVmObjIterLookupTable: public CVmObjIter
700
{
701
    friend class CVmMetaclassIterLookupTable;
702
703
public:
704
    /* metaclass registration object */
705
    static class CVmMetaclass *metaclass_reg_;
706
    class CVmMetaclass *get_metaclass_reg() const { return metaclass_reg_; }
707
708
    /* am I of the given metaclass? */
709
    virtual int is_of_metaclass(class CVmMetaclass *meta) const
710
    {
711
        /* try my own metaclass and my base class */
712
        return (meta == metaclass_reg_
713
                || CVmObjIter::is_of_metaclass(meta));
714
    }
715
716
    /* 
717
     *   call a static property - we don't have any of our own, so simply
718
     *   "inherit" the base class handling 
719
     */
720
    static int call_stat_prop(VMG_ vm_val_t *result,
721
                              const uchar **pc_ptr, uint *argc,
722
                              vm_prop_id_t prop)
723
    {
724
        return CVmObjIter::call_stat_prop(vmg_ result, pc_ptr, argc, prop);
725
    }
726
727
    /*
728
     *   Create a lookup table iterator.  This method is to be called by the
729
     *   lookup table to create an iterator for its value.  
730
     */
731
    static vm_obj_id_t create_for_coll(VMG_ const vm_val_t *coll);
732
733
    /* notify of deletion */
734
    void notify_delete(VMG_ int in_root_set);
735
736
    /* 
737
     *   notify of a new savepoint - clear the 'undo' flag, since we cannot
738
     *   have created any undo information yet for the new savepoint 
739
     */
740
    void notify_new_savept()
741
        { set_flags(get_flags() & ~VMOBJITERLOOKUPTABLE_UNDO); }
742
743
    /* apply undo */
744
    void apply_undo(VMG_ struct CVmUndoRecord *rec);
745
746
    /* mark references */
747
    void mark_refs(VMG_ uint state);
748
749
    /* there are no references in our undo stream */
750
    void mark_undo_ref(VMG_ struct CVmUndoRecord *) { }
751
752
    /* we keep only strong references */
753
    void remove_stale_weak_refs(VMG0_) { }
754
    void remove_stale_undo_weak_ref(VMG_ struct CVmUndoRecord *) { }
755
756
    /* load from an image file */
757
    void load_from_image(VMG_ vm_obj_id_t self, const char *ptr, size_t siz);
758
759
    /* reload from an image file */
760
    void reload_from_image(VMG_ vm_obj_id_t self,
761
                           const char *ptr, size_t siz);
762
763
    /* 
764
     *   determine if the object has been changed since it was loaded -
765
     *   assume we have 
766
     */
767
    int is_changed_since_load() const { return TRUE; }
768
769
    /* save to a file */
770
    void save_to_file(VMG_ class CVmFile *fp);
771
772
    /* restore from a file */
773
    void restore_from_file(VMG_ vm_obj_id_t self,
774
                           class CVmFile *fp, class CVmObjFixup *fixups);
775
776
    /* rebuild for image file */
777
    virtual ulong rebuild_image(VMG_ char *buf, ulong buflen);
778
779
    /* convert to constant data */
780
    virtual void convert_to_const_data(VMG_ class CVmConstMapper *mapper,
781
                                       vm_obj_id_t self);
782
783
protected:
784
    /* create */
785
    CVmObjIterLookupTable() { ext_ = 0; }
786
787
    /* create */
788
    CVmObjIterLookupTable(VMG_ const vm_val_t *coll);
789
790
    /* find the first valid entry, starting at the given index */
791
    uint find_first_valid_entry(VMG_ uint entry) const;
792
793
    /* property evaluator - get next value */
794
    virtual int getp_get_next(VMG_ vm_obj_id_t self, vm_val_t *retval,
795
                              uint *argc);
796
797
    /* property evaluator - is next value available? */
798
    virtual int getp_is_next_avail(VMG_ vm_obj_id_t self, vm_val_t *retval,
799
                                   uint *argc);
800
801
    /* property evaluator - reset to first item */
802
    virtual int getp_reset_iter(VMG_ vm_obj_id_t self, vm_val_t *retval,
803
                                uint *argc);
804
805
    /* property evaluator - get current key */
806
    virtual int getp_get_cur_key(VMG_ vm_obj_id_t self, vm_val_t *retval,
807
                                 uint *argc);
808
809
    /* property evaluator - get current value */
810
    virtual int getp_get_cur_val(VMG_ vm_obj_id_t self, vm_val_t *retval,
811
                                 uint *argc);
812
813
    /* get information on the current entry */
814
    void get_cur_entry(VMG_ vm_val_t *valp, vm_val_t *keyp) const;
815
816
    /* get my collection value */
817
    void get_coll_val(vm_val_t *val) const { vmb_get_dh(ext_, val); }
818
819
    /* get/set the current entry index (without saving undo) */
820
    long get_entry_index() const
821
        { return osrp2(ext_ + VMB_DATAHOLDER); }
822
    void set_entry_index(uint idx)
823
        { oswp2(ext_ + VMB_DATAHOLDER, idx); }
824
825
    /* update the entry index value, saving undo if necessary */
826
    void set_entry_index_undo(VMG_ vm_obj_id_t self, uint entry);
827
828
    /* get/set the flags */
829
    uint get_flags() const
830
        { return osrp2(ext_ + VMB_DATAHOLDER + 2); }
831
    void set_flags(uint flags) const
832
        { oswp2(ext_ + VMB_DATAHOLDER + 2, flags); }
833
};
834
835
/*
836
 *   Registration table object for lookup table iterators
837
 */
838
class CVmMetaclassIterLookupTable: public CVmMetaclass
839
{
840
public:
841
    /* get the global name */
842
    const char *get_meta_name() const
843
        { return "lookuptable-iterator/030000"; }
844
845
    /* create from image file */
846
    void create_for_image_load(VMG_ vm_obj_id_t id)
847
    {
848
        new (vmg_ id) CVmObjIterLookupTable();
849
        G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE);
850
    }
851
852
    /* create from restoring from saved state */
853
    void create_for_restore(VMG_ vm_obj_id_t id)
854
    {
855
        new (vmg_ id) CVmObjIterLookupTable();
856
        G_obj_table->set_obj_gc_characteristics(id, TRUE, FALSE);
857
    }
858
859
    /* create dynamically using stack arguments */
860
    vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, uint argc)
861
    {
862
        err_throw(VMERR_BAD_DYNAMIC_NEW);
863
        AFTER_ERR_THROW(return VM_INVALID_OBJ;)
864
    }
865
866
    /* call a static property */
867
    int call_stat_prop(VMG_ vm_val_t *result,
868
                       const uchar **pc_ptr, uint *argc,
869
                       vm_prop_id_t prop)
870
    {
871
        return CVmObjIterLookupTable::
872
            call_stat_prop(vmg_ result, pc_ptr, argc, prop);
873
    }
874
};
875
876
877
#endif /* VMLOOKUP_H */
878
879
/*
880
 *   Register the classes
881
 */
882
VM_REGISTER_METACLASS(CVmObjLookupTable)
883
VM_REGISTER_METACLASS(CVmObjWeakRefLookupTable)
884
VM_REGISTER_METACLASS(CVmObjIterLookupTable)
885