/
ESHAPE.C
229 lines (195 loc) · 6.15 KB
/
ESHAPE.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/* Copyright (c) 1992 by AT&T Bell Laboratories. */
/* Advanced C++ Programming Styles and Idioms */
/* James O. Coplien */
/* All rights reserved. */
//************************************************************//
// //
// F I L E : E S H A P E . C //
// //
// Code for class Shape //
// //
//************************************************************//
#include "eshape.h"
#ifndef _SHAPEREP_H
#include "eshaprp.h"
#endif
#ifndef _TRIANGLE_H
#include "etringl.h"
#endif
#ifndef _RECTANGLE_H
#include "erect.h"
#endif
#include "List.h"
// Class Shape does much of the memory management work for
// all Shapes.
// Handles to all extant Shape instances everywhere
List<Topp> *Shape::allShapes = 0;
// List of all Exemplars that are made for subclasses
// of class ShapeRep
List<Thingp> *Shape::allShapeExemplars = 0;
// Shape exemplar
extern Shape *shape = 0;
void
Shape::init() {
// initializes all global data structures for
// Shapes, so main can orchestrate order of
// initialization
allShapes = new List<Topp>;
allShapeExemplars = new List<Thingp>;
shape = new Shape;
// orchestrate initialization of ShapeRep types
ShapeRep::init();
Triangle::init();
Rectangle::init();
}
Top *
Shape::doit() {
// handy function that can be reloaded by users
// and used as a utility
return 0;
}
Shape::Shape() {
// default shape constructor
Topp tp = this;
// log self in allShapes list
allShapes->put(tp);
// we don't know what kind of Shape:
// just make it a dummy for now
rep = new ShapeRep;
}
Shape::~Shape() {
Listiter<Topp> tp = *allShapes;
Topp t;
for ( tp.reset(); tp.next(t); ) {
if (t == (Thingp)this) {
tp.remove_prev(t);
break;
}
}
if (allShapes->length() == 0) {
// last gasp garbage collection
gc();
}
}
Shape::Shape(Shape &x) {
// copy constructor
Thingp tp = (Thingp) this;
// log self with allShapes list
allShapes->put(tp);
// just point to parameter's rep
rep = x.rep;
}
Shape::Shape(ShapeRep &x) {
// build a Shape from a ShapeRep: used
// mainly to convert the ShapeReps built
// by Triangle, Rectangle, etc., into
// Shapes that are returned to the users
// (users never see the inner classes)
Topp tp = this;
// log self with allShapes
allShapes->put(tp);
// note: no ->ref(); caller must yield copy!
rep = &x;
}
Shape&
Shape::operator=(Shape &x) {
// assignment of shapes. Don't worry about what
// rep used to point to: garbage collection
// will get it.
rep = x.rep;
return *this;
}
Top *
Shape::type() {
// A Shape's type is its own exemplar
return shape;
}
void
Shape::dataUpdate(Thingp &oldExemplar,
const Thingp newExemplar) {
// This function allows class replacement of a subclass
// of ShapeRep. It assumes that all virtual functions
// have been recompiled and incrementally loaded
// against the new class definition. It also assumes
// the programmer has provided a cutover function
// which, when invoked on an old instance of the
// shape, will return a pointer to a semantically
// equivalent copy.
ShapeRep* savedExemplar = (ShapeRep*) oldExemplar;
Topp tp = 0;
// get a static copy to iterate over; we don't
// want to catch new things as they are added!
// The copy will be reclaimed on return from this
// member function
List<Topp> staticCopy = *allShapes;
// change exemplars
oldExemplar = newExemplar;
// cut over all subobjects for this exemplar
Listiter<Topp> shapeIter = staticCopy;
for ( shapeIter.reset(); shapeIter.next(tp); ) {
Shapepointer sp = (Shapepointer)tp;
if (sp->rep->type() == (Thingp)savedExemplar) {
if (sp->rep->docutover()) {
ShapeRep *oldrep = sp->rep;
printf("\tchanging shape 0x%x to new format\n",
oldrep);
sp->rep = (ShapeRep*)sp->rep->cutover();
// must manually clean up old rep here:
// garbage collector won't get it, as it's
// about to go out of the arena
oldrep->ShapeRep::~ShapeRep();
}
}
}
// Remove this exemplar from Shape's list of all exemplars
// in the world--it is no longer participating as part
// of this abstract base exemplar
UnRegister(savedExemplar);
}
void
Shape::gc() {
// Shape garbage collector: orchestrates collection
// of unreachable objects for all subclasses of
// ShapeRep. Uses Baker's algorithm
// First half of Baker: mark all reachable shapes
Listiter<Topp> shapeIter = *allShapes;
shapeIter.reset();
for ( Topp tp = 0; shapeIter.next(tp); ) {
Shapepointer sp = (Shapepointer)tp;
if (sp->rep) {
sp->rep->mark();
}
}
// Second half of Baker: sweep. Let individual
// subtypes each do their own sweep of their own
// pools, using their own gc member function.
Listiter<Thingp> shapeExemplarIter = *allShapeExemplars;
shapeExemplarIter.reset();
for ( Thingp anExemplar = 0;
shapeExemplarIter.next(anExemplar); ) {
ShapeRep *thisExemplar = (ShapeRep*)anExemplar;
thisExemplar->gc(0);
}
// Baker swap of To and From spaces
ShapeRep::FromSpace ^= 1;
ShapeRep::ToSpace ^= 1;
}
void
Shape::Register(ShapeRep *s) {
// routine by which ShapeRep exemplars
// register themselves with Shape
Thingp tp = s;
allShapeExemplars->put(tp);
}
void
Shape::UnRegister(ShapeRep *s) {
// Allows an exemplar to unregister itself
// (as when it is replaced by a new version)
Thingp tp = 0;
Listiter<Thingp> shapeIter = *allShapeExemplars;
for ( shapeIter.reset(); shapeIter.next(tp); ) {
if (tp == (Thingp)s) {
shapeIter.remove_prev(tp);
}
}
}