Branch data Line data Source code
1 : : // $Id: StateAccess.h 6781 2009-06-28 00:50:04Z vern $
2 : : //
3 : : // A class describing a state-modyfing access to a Value or an ID.
4 : :
5 : : #ifndef STATEACESSS_H
6 : : #define STATEACESSS_H
7 : :
8 : : #include <set>
9 : : #include <map>
10 : : #include <string>
11 : :
12 : : #include "SerialObj.h"
13 : :
14 : : class Val;
15 : : class ID;
16 : : class MutableVal;
17 : : class HashKey;
18 : : class ODesc;
19 : : class Serializer;
20 : : class TableVal;
21 : :
22 : : enum Opcode { // Op1 Op2 Op3 (Vals)
23 : : OP_NONE,
24 : : OP_ASSIGN, // new old
25 : : OP_ASSIGN_IDX, // idx new old
26 : : OP_ADD, // idx old
27 : : OP_INCR, // idx new old
28 : : OP_INCR_IDX, // idx new old
29 : : OP_DEL, // idx old
30 : : OP_PRINT, // args
31 : : OP_EXPIRE, // idx
32 : : OP_READ_IDX, // idx
33 : : };
34 : :
35 : : class StateAccess : public SerialObj {
36 : : public:
37 : : StateAccess(Opcode opcode, const ID* target, const Val* op1,
38 : : const Val* op2 = 0, const Val* op3 = 0);
39 : : StateAccess(Opcode opcode, const MutableVal* target, const Val* op1,
40 : : const Val* op2 = 0, const Val* op3 = 0);
41 : :
42 : : // For tables, the idx operand may be given as an index HashKey.
43 : : // This is for efficiency. While we need to reconstruct the index
44 : : // if we are actually going to serialize the access, we can at
45 : : // least skip it if we don't.
46 : : StateAccess(Opcode opcode, const ID* target, const HashKey* op1,
47 : : const Val* op2 = 0, const Val* op3 = 0);
48 : : StateAccess(Opcode opcode, const MutableVal* target, const HashKey* op1,
49 : : const Val* op2 = 0, const Val* op3 = 0);
50 : :
51 : : StateAccess(const StateAccess& sa);
52 : :
53 : : virtual ~StateAccess();
54 : :
55 : : // Replays this access in the our environment.
56 : : void Replay();
57 : :
58 : : // Returns target ID which may be an internal one for unbound vals.
59 : : ID* Target() const;
60 : :
61 : : void Describe(ODesc* d) const;
62 : :
63 : : bool Serialize(SerialInfo* info) const;
64 : : static StateAccess* Unserialize(UnserialInfo* info);
65 : :
66 : : // Main entry point when StateAcesses are performed.
67 : : // For every state-changing operation, this has to be called.
68 : : static void Log(StateAccess* access);
69 : :
70 : : // If we're going to make additional non-replaying accesses during a
71 : : // Replay(), we have to call these.
72 : 0 : static void SuspendReplay() { --replaying; }
73 : 0 : static void ResumeReplay() { ++replaying; }
74 : :
75 : : private:
76 : 0 : StateAccess() { target.id = 0; op1.val = op2 = op3 = 0; }
77 : : void RefThem();
78 : :
79 : : bool CheckOld(const char* op, ID* id, Val* index, Val* should, Val* is);
80 : : bool CheckOldSet(const char* op, ID* id, Val* index, bool should, bool is);
81 : : bool MergeTables(TableVal* dst, Val* src);
82 : :
83 : 0 : DECLARE_SERIAL(StateAccess);
84 : :
85 : : Opcode opcode;
86 : : union {
87 : : ID* id;
88 : : MutableVal* val;
89 : : } target;
90 : :
91 : : union {
92 : : Val* val;
93 : : const HashKey* key;
94 : : } op1;
95 : :
96 : : Val* op2;
97 : : Val* op3;
98 : :
99 : : enum Type { TYPE_ID, TYPE_VAL, TYPE_MVAL, TYPE_KEY };
100 : : Type target_type;
101 : : Type op1_type;
102 : : bool delete_op1_key;
103 : :
104 : : static int replaying;
105 : : };
106 : :
107 : : // We provide a notifier framework to inform interested parties of
108 : : // modifications to selected global IDs/Vals. To get notified about a change,
109 : : // derive a class from Notifier and register the interesting IDs/Vals with
110 : : // the NotifierRegistry.
111 : : //
112 : : // Note: For containers (e.g., tables), notifications are only issued if the
113 : : // container itself is modified, *not* for changes to the values contained
114 : : // therein.
115 : :
116 : : class NotifierRegistry {
117 : : public:
118 : 0 : class Notifier {
119 : : public:
120 [ # # ][ # # ]: 0 : virtual ~Notifier() { }
121 : :
122 : : // Called when a change is being performed. Note that when these
123 : : // methods are called, it is undefined whether the change has
124 : : // already been done or is just going to be performed soon.
125 : : virtual void Access(ID* id, const StateAccess& sa) = 0;
126 : : virtual void Access(Val* val, const StateAccess& sa) = 0;
127 : : virtual const char* Name() const; // for debugging
128 : : };
129 : :
130 : 3 : NotifierRegistry() { }
131 : 3 : ~NotifierRegistry() { }
132 : :
133 : : // Inform the given notifier if ID/Val changes.
134 : : void Register(ID* id, Notifier* notifier);
135 : : void Register(Val* val, Notifier* notifier);
136 : :
137 : : // Cancel notification for this ID/Val.
138 : : void Unregister(ID* id, Notifier* notifier);
139 : : void Unregister(Val* val, Notifier* notifier);
140 : :
141 : : private:
142 : : friend class StateAccess;
143 : : void AccessPerformed(const StateAccess& sa);
144 : :
145 : : typedef std::set<Notifier*> NotifierSet;
146 : : typedef std::map<std::string, NotifierSet*> NotifierMap;
147 : : NotifierMap ids;
148 : : };
149 : :
150 : : extern NotifierRegistry notifiers;
151 : :
152 : : #endif
|