cfad47cfa3/tads3/vmundo.h

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
/* $Header: d:/cvsroot/tads/tads3/VMUNDO.H,v 1.2 1999/05/17 02:52:29 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
  vmundo.h - VM undo manager
12
Function
13
  
14
Notes
15
  
16
Modified
17
  10/29/98 MJRoberts  - Creation
18
*/
19
20
#ifndef VMUNDO_H
21
#define VMUNDO_H
22
23
#include "t3std.h"
24
#include "vmtype.h"
25
26
27
/* ------------------------------------------------------------------------ */
28
/*
29
 *   Undo record.  The VM undo manager maintains a list of these records;
30
 *   each record contains the information necessary to undo one particular
31
 *   data change in an object.  Each object class (TADS object, array,
32
 *   etc) keeps a linked list of undo records for its own actions.  
33
 */
34
struct CVmUndoRecord
35
{
36
    /*
37
     *   Object ID.  All undoable state is stored in objects, hence each
38
     *   undo record is associated with an object.
39
     */
40
    vm_obj_id_t obj;
41
42
    /* 
43
     *   Identifier - the meaning of this member is defined by the object
44
     *   that created the record.  For TADS objects, this is a property ID
45
     *   specifying the property that was changed; for arrays, it's the
46
     *   index of the array element that changed.  Other object
47
     *   metaclasses may assign different meanings.  
48
     */
49
    union
50
    {
51
        /* property value key */
52
        vm_prop_id_t prop;
53
54
        /* integer value key */
55
        uint32 intval;
56
57
        /* pointer value key */
58
        void *ptrval;
59
    } id;
60
61
    /*
62
     *   Data value.  This is the data value prior to the change.  In some
63
     *   cases, the type may be 'empty' to indicate that the original
64
     *   value did not exist; for example, when a property is added to a
65
     *   TADS object and the property was not present previously, we
66
     *   create an undo record with type 'empty' to indicate that the
67
     *   property must be deleted on undo.  
68
     */
69
    vm_val_t oldval;
70
};
71
72
73
/*
74
 *   Undo meta-record.  Each slot in the undo array is one of these
75
 *   meta-records, which is a union of the normal undo record and an undo
76
 *   link pointer.  The first undo record in any savepoint is always a
77
 *   link pointer; all of the other records are normal undo records. 
78
 */
79
union CVmUndoMeta
80
{
81
    /* the first entry in each savepoint is a link entry */
82
    struct
83
    {
84
        /* pointer to the first record in the previous savepoint */
85
        CVmUndoMeta *prev_first;
86
87
        /* pointer to the first record in the next savepoint */
88
        CVmUndoMeta *next_first;
89
    } link;
90
    
91
    /* every entry but the first in a savepoint is an ordinary undo record */
92
    CVmUndoRecord rec;
93
};
94
95
96
/* ------------------------------------------------------------------------ */
97
/*
98
 *   Undo manager 
99
 */
100
class CVmUndo
101
{
102
public:
103
    /* 
104
     *   create the undo manager, specifying the upper limit for memory
105
     *   usage and retained savepoints 
106
     */
107
    CVmUndo(size_t undo_record_cnt, uint max_savepts);
108
109
    /* delete the undo manager */
110
    ~CVmUndo();
111
112
    /* 
113
     *   Create a savepoint.  If doing so would exceed the maximum number
114
     *   of savepoints, we'll discard the oldest savepoint. 
115
     */
116
    void create_savept(VMG0_);
117
118
    /* get the current savepoint ID */
119
    vm_savept_t get_cur_savept() const { return cur_savept_; }
120
121
    /* determine how many savepoints exist */
122
    uint get_savept_cnt() const { return savept_cnt_; }
123
124
    /* drop all undo information */
125
    void drop_undo(VMG0_);
126
127
    /*
128
     *   Allocate and initialize an undo record with a property key or
129
     *   with an integer key.
130
     *   
131
     *   We check that the undo manager has an active savepoint.  It may
132
     *   not have an active savepoint if no savepoint has been created,
133
     *   all undo records have been applied, or we've run out of space in
134
     *   the current savepoint; in any of these cases, since there's no
135
     *   savepoint, we don't need to keep any undo records.  
136
     */
137
    void add_new_record_prop_key(VMG_ vm_obj_id_t obj, vm_prop_id_t key,
138
                                 const vm_val_t *val);
139
    void add_new_record_int_key(VMG_ vm_obj_id_t obj, uint32 key,
140
                                const vm_val_t *val);
141
142
    /* 
143
     *   Add a new undo record with a pointer key; returns true if the
144
     *   record was created, false if not.  (This version of
145
     *   add_new_record_xxx_key returns an indication of success because
146
     *   the pointer value might have been allocated, in which case the
147
     *   caller must deallocate the value if we didn't add an undo
148
     *   record.) 
149
     */
150
    int add_new_record_ptr_key(VMG_ vm_obj_id_t obj, void *key,
151
                               const vm_val_t *val);
152
153
    /*
154
     *   Apply undo to the latest savepoint.  After applying the undo
155
     *   records, we delete all undo records to the savepoint; this leaves
156
     *   the previous savepoint as the new most recent savepoint, so
157
     *   repeating this will undo to the previous savepoint.  
158
     */
159
    void undo_to_savept(VMG0_);
160
161
    /*
162
     *   Garbage collection: mark referenced objects.  This goes through
163
     *   all of the undo records; for each undo record, we have the object
164
     *   that owns the undo record mark as referenced any object to which
165
     *   the record refers. 
166
     */
167
    void gc_mark_refs(VMG0_);
168
169
    /*
170
     *   Garbage collection: delete obsolete weak references.  This goes
171
     *   through all of the undo records; for each undo record, if the
172
     *   object that owns the record is unreachable, we'll delete the undo
173
     *   record; otherwise, we'll tell the object that owns the record to
174
     *   clean up the record if it contains an unreachable weak reference. 
175
     */
176
    void gc_remove_stale_weak_refs(VMG0_);
177
178
private:
179
    /*
180
     *   Allocate an undo record.  Returns null if no records are
181
     *   available, in which case the caller should simply skip saving
182
     *   undo.  
183
     */
184
    CVmUndoMeta *alloc_rec(VMG0_);
185
186
    /* 
187
     *   increment a record pointer, wrapping back at the end of the array
188
     *   to the first record 
189
     */
190
    void inc_rec_ptr(CVmUndoMeta **rec)
191
    {
192
        /* increment the record pointer */
193
        ++(*rec);
194
195
        /* if it's at the end of the array, wrap back to the start */
196
        if (*rec == rec_arr_ + rec_arr_size_)
197
            *rec = rec_arr_;
198
    }
199
200
    /*
201
     *   Add a new record and return the new record.  If we don't have an
202
     *   active savepoint, this will return null, since there's no need to
203
     *   keep undo.  
204
     */
205
    CVmUndoRecord *add_new_record(VMG_ vm_obj_id_t controlling_obj);
206
207
    /* discard the oldest savepoint */
208
    void drop_oldest_savept(VMG0_);
209
    
210
    /* current savepoint ID */
211
    vm_savept_t cur_savept_;
212
213
    /* 
214
     *   Number of active savepoint ID's.  If this is zero, it means that
215
     *   we have no undo information and we're not keeping any undo
216
     *   information.  If this is one, it means that we only have the
217
     *   current savepoint stored.  
218
     */
219
    uint savept_cnt_;
220
221
    /*
222
     *   The nominal maximum number of savepoints to keep.  Any time that
223
     *   we attempt to create a new savepoint, and doing so would exceed
224
     *   this number of stored savepoints, we will discard the oldest
225
     *   savepoint.  Note that we may not always store this many
226
     *   savepoints, since we will also discard old savepoints when we run
227
     *   out of available undo records attempting to create a new
228
     *   savepoint.  
229
     */
230
    vm_savept_t max_savepts_;
231
    
232
    /* 
233
     *   Pointer to the first record in the current savepoint.  This isn't
234
     *   a real undo record -- it's a link record.  
235
     */
236
    CVmUndoMeta *cur_first_;
237
238
    /*
239
     *   Pointer to the first undo record in the oldest savepoint.  This
240
     *   is a link record. 
241
     */
242
    CVmUndoMeta *oldest_first_;
243
244
    /* pointer to the next free undo record */
245
    CVmUndoMeta *next_free_;
246
247
    /*
248
     *   Master array of undo records, and the number of records in this
249
     *   list.  We pre-allocate a fixed array of these records.  If we run
250
     *   out, we start discarding old undo.  
251
     */
252
    CVmUndoMeta *rec_arr_;
253
    size_t rec_arr_size_;
254
};
255
256
257
#endif /* VMUNDO_H */
258