cfad47cfa3/tads3/vmundo.h
Commiter: Nikos Chantziaras
Author: Nikos Chantziaras
Revision: cfad47cfa3
File Size: 8.1 KB
(June 01, 2009 20:54 UTC) Almost 3 years ago
Initial commit.
/* $Header: d:/cvsroot/tads/tads3/VMUNDO.H,v 1.2 1999/05/17 02:52:29 MJRoberts Exp $ */
/*
* Copyright (c) 1998, 2002 Michael J. Roberts. All Rights Reserved.
*
* Please see the accompanying license file, LICENSE.TXT, for information
* on using and copying this software.
*/
/*
Name
vmundo.h - VM undo manager
Function
Notes
Modified
10/29/98 MJRoberts - Creation
*/
#ifndef VMUNDO_H
#define VMUNDO_H
#include "t3std.h"
#include "vmtype.h"
/* ------------------------------------------------------------------------ */
/*
* Undo record. The VM undo manager maintains a list of these records;
* each record contains the information necessary to undo one particular
* data change in an object. Each object class (TADS object, array,
* etc) keeps a linked list of undo records for its own actions.
*/
struct CVmUndoRecord
{
/*
* Object ID. All undoable state is stored in objects, hence each
* undo record is associated with an object.
*/
vm_obj_id_t obj;
/*
* Identifier - the meaning of this member is defined by the object
* that created the record. For TADS objects, this is a property ID
* specifying the property that was changed; for arrays, it's the
* index of the array element that changed. Other object
* metaclasses may assign different meanings.
*/
union
{
/* property value key */
vm_prop_id_t prop;
/* integer value key */
uint32 intval;
/* pointer value key */
void *ptrval;
} id;
/*
* Data value. This is the data value prior to the change. In some
* cases, the type may be 'empty' to indicate that the original
* value did not exist; for example, when a property is added to a
* TADS object and the property was not present previously, we
* create an undo record with type 'empty' to indicate that the
* property must be deleted on undo.
*/
vm_val_t oldval;
};
/*
* Undo meta-record. Each slot in the undo array is one of these
* meta-records, which is a union of the normal undo record and an undo
* link pointer. The first undo record in any savepoint is always a
* link pointer; all of the other records are normal undo records.
*/
union CVmUndoMeta
{
/* the first entry in each savepoint is a link entry */
struct
{
/* pointer to the first record in the previous savepoint */
CVmUndoMeta *prev_first;
/* pointer to the first record in the next savepoint */
CVmUndoMeta *next_first;
} link;
/* every entry but the first in a savepoint is an ordinary undo record */
CVmUndoRecord rec;
};
/* ------------------------------------------------------------------------ */
/*
* Undo manager
*/
class CVmUndo
{
public:
/*
* create the undo manager, specifying the upper limit for memory
* usage and retained savepoints
*/
CVmUndo(size_t undo_record_cnt, uint max_savepts);
/* delete the undo manager */
~CVmUndo();
/*
* Create a savepoint. If doing so would exceed the maximum number
* of savepoints, we'll discard the oldest savepoint.
*/
void create_savept(VMG0_);
/* get the current savepoint ID */
vm_savept_t get_cur_savept() const { return cur_savept_; }
/* determine how many savepoints exist */
uint get_savept_cnt() const { return savept_cnt_; }
/* drop all undo information */
void drop_undo(VMG0_);
/*
* Allocate and initialize an undo record with a property key or
* with an integer key.
*
* We check that the undo manager has an active savepoint. It may
* not have an active savepoint if no savepoint has been created,
* all undo records have been applied, or we've run out of space in
* the current savepoint; in any of these cases, since there's no
* savepoint, we don't need to keep any undo records.
*/
void add_new_record_prop_key(VMG_ vm_obj_id_t obj, vm_prop_id_t key,
const vm_val_t *val);
void add_new_record_int_key(VMG_ vm_obj_id_t obj, uint32 key,
const vm_val_t *val);
/*
* Add a new undo record with a pointer key; returns true if the
* record was created, false if not. (This version of
* add_new_record_xxx_key returns an indication of success because
* the pointer value might have been allocated, in which case the
* caller must deallocate the value if we didn't add an undo
* record.)
*/
int add_new_record_ptr_key(VMG_ vm_obj_id_t obj, void *key,
const vm_val_t *val);
/*
* Apply undo to the latest savepoint. After applying the undo
* records, we delete all undo records to the savepoint; this leaves
* the previous savepoint as the new most recent savepoint, so
* repeating this will undo to the previous savepoint.
*/
void undo_to_savept(VMG0_);
/*
* Garbage collection: mark referenced objects. This goes through
* all of the undo records; for each undo record, we have the object
* that owns the undo record mark as referenced any object to which
* the record refers.
*/
void gc_mark_refs(VMG0_);
/*
* Garbage collection: delete obsolete weak references. This goes
* through all of the undo records; for each undo record, if the
* object that owns the record is unreachable, we'll delete the undo
* record; otherwise, we'll tell the object that owns the record to
* clean up the record if it contains an unreachable weak reference.
*/
void gc_remove_stale_weak_refs(VMG0_);
private:
/*
* Allocate an undo record. Returns null if no records are
* available, in which case the caller should simply skip saving
* undo.
*/
CVmUndoMeta *alloc_rec(VMG0_);
/*
* increment a record pointer, wrapping back at the end of the array
* to the first record
*/
void inc_rec_ptr(CVmUndoMeta **rec)
{
/* increment the record pointer */
++(*rec);
/* if it's at the end of the array, wrap back to the start */
if (*rec == rec_arr_ + rec_arr_size_)
*rec = rec_arr_;
}
/*
* Add a new record and return the new record. If we don't have an
* active savepoint, this will return null, since there's no need to
* keep undo.
*/
CVmUndoRecord *add_new_record(VMG_ vm_obj_id_t controlling_obj);
/* discard the oldest savepoint */
void drop_oldest_savept(VMG0_);
/* current savepoint ID */
vm_savept_t cur_savept_;
/*
* Number of active savepoint ID's. If this is zero, it means that
* we have no undo information and we're not keeping any undo
* information. If this is one, it means that we only have the
* current savepoint stored.
*/
uint savept_cnt_;
/*
* The nominal maximum number of savepoints to keep. Any time that
* we attempt to create a new savepoint, and doing so would exceed
* this number of stored savepoints, we will discard the oldest
* savepoint. Note that we may not always store this many
* savepoints, since we will also discard old savepoints when we run
* out of available undo records attempting to create a new
* savepoint.
*/
vm_savept_t max_savepts_;
/*
* Pointer to the first record in the current savepoint. This isn't
* a real undo record -- it's a link record.
*/
CVmUndoMeta *cur_first_;
/*
* Pointer to the first undo record in the oldest savepoint. This
* is a link record.
*/
CVmUndoMeta *oldest_first_;
/* pointer to the next free undo record */
CVmUndoMeta *next_free_;
/*
* Master array of undo records, and the number of records in this
* list. We pre-allocate a fixed array of these records. If we run
* out, we start discarding old undo.
*/
CVmUndoMeta *rec_arr_;
size_t rec_arr_size_;
};
#endif /* VMUNDO_H */
|