typename fix
[prop.git] / tests / test_gc12.pcc
blob97e6389443526f688f98da81effcedcf18464fe0
1 //
2 //  Testing finalization with garbage collection.
3 //  We use the class BGC_F (BGC with finalization) for garbage collection.
4 //  In addition of reclaiming garbage, BGC_F will also call the finalization
5 //  method (the destructor) for each object freed.
6 //
7 #include <iostream.h>
8 #include <AD/gc/markswp.h>
10 MarkSweepGC marksweep_gc;
13 //  The following auxiliary class keeps track of allocation and finalization.
15 class LOGGER {
16 public:
17    static int allocation_count;
18    static int deallocation_count;
19    LOGGER() { allocation_count++; }
20   ~LOGGER() { deallocation_count++; }
23 int LOGGER::allocation_count   = 0;
24 int LOGGER::deallocation_count = 0;
27 //  Define an algebraic datatype.  Currently, rewriting can only be 
28 //  performed on datatypes(and not views) in Prop.  
29 //  If replacement is to be performed on a datatype, then it should
30 //  be declared using the ``rewrite'' qualifier.
31 //  In this example, we'll use garbage collection with rewriting.
33 //  We'll inherit from LOGGER so that allocation and finalization
34 //  of each EXP cell is logged.
36 datatype EXP : LOGGER :: collectable rewrite 
37    = om
38    | num (int)
39    | var (char)
40    | add (EXP, EXP)
41    | sub (EXP, EXP)
42    | mul (EXP, EXP)
43    | div (EXP, EXP)
44    ;
47 //  Datatype instantiation generates any additional methods and definitions.
48 //  In this case garbage collection tracing methods are generated.
49 //  As always, this should be placed in an implementation file.
51 instantiate datatype EXP;
54 //  Define a method that prints an expression.  This is a simple
55 //  inductive definition
57 ostream& operator << (ostream& f, EXP e)
58 {  match (e) {
59       om:       { return f << "om"; }
60    |  num i:    { return f << i; }
61    |  var v:    { return f << v; }
62    |  add(a,b): { return f << '(' << a << " + " << b << ')'; }
63    |  sub(a,b): { return f << '(' << a << " - " << b << ')'; }
64    |  mul(a,b): { return f << '(' << a << " * " << b << ')'; }
65    |  div(a,b): { return f << '(' << a << " / " << b << ')'; }
66    }
70 //  Define the interface to a ``rewriting class.''  A rewriting class 
71 //  is simply a C++ class with rewriting rules attached.  In real programs
72 //  this definition should be placed in some definition (i.e. .ph) files.
73 //  
74 //  In parenthesis, we must list all datatypes involved.   Unlike
75 //  simple pattern matching, rewriting can involve a set of mutually
76 //  recursive (or mutually exclusive, if desired) datatype definitions.
77 //  So in general this is a comma delimited list.   
79 //  In this example it involves only the datatype EXP.
81 rewrite class Simplify (EXP)
82 {  // nothing here for now.
83 public:
84    Simplify() {}
88 //  Now we define the rewriting rules in the rewriting class Simplify.  These
89 //  rules should be placed in an implementation file (.pcc, .pC, .pc++ etc).
91 //  In this brief sample class we have some rules that perform 
92 //  simple constant folding and strength reduction.
94 //  Currently, all the rules for a rewrite class must be placed in
95 //  the same rewrite construct.  This will probably change in the future
96 //  once I work out the details on incremental tree automata compilation.
98 rewrite Simplify {
99    add (num 0, x):                    rewrite(x); 
100 |  add (x, num 0):                    rewrite(x);  
101 |  sub (x, num 0):                    rewrite(x);  
102 |  mul (x, num 0):                    rewrite(num(0));  
103 |  mul (num 0, x):                    rewrite(num(0));  
104 |  mul (x, num 1):                    rewrite(x);       
105 |  mul (num 1, x):                    rewrite(x); 
106 |  mul (x, num 2):                    rewrite(add(x,x)); 
107 |  mul (num 2, x):                    rewrite(add(x,x)); 
108 |  div (x, num 1):                    rewrite(x);        
109 |  add (num x, num y):                rewrite(num(x + y)); 
110 |  sub (num x, num y):                rewrite(num(x - y)); 
111 |  mul (num x, num y):                rewrite(num(x * y)); 
112 |  div (num x, num y) where (y != 0): rewrite(num(x / y)); 
113 |  div (_, num 0):                    { /* cout << "Division by zero!\n"; */ }
114 |  div (zero as num 0, x):            rewrite(zero); 
118 //  Now defines the function that uses all this stuff.
120 void do_my_stuff()
122    //
123    // Instantiate a rewriting class 
124    //
125    Simplify sim;
126    EXP t1, term, term2;
128    for (int trials = 1; trials < 10000; trials++) {
129       //
130       // (0 + x * 2) / (1 * 5 + 1 * 3) / (0 / y);
131       //
132       t1 = div(div(add(num(0), mul(var('x'),num(2))), 
133                    add(mul(num(1), num(5)),mul(num(1),num(3)))),
134                div(num(0),var('y')));
135       term = mul(t1,t1);
137       //
138       //  Rewrite the big term above.
139       // 
140       // cout << "Before: " << term << '\n';
141       sim(term);
142       // cout << "After: " << term << '\n';
144       //
145       //  Rewrite it again.  It should have no effect since the term
146       //  is already in normal form.
147       //
148       sim(term);
149       // cout << "Again (should have no effect): " << term << '\n';
151       //
152       //  Rewrite some other term.
153       //
154       term2 = add(sub(num(3),num(3)), var('z'));
155       // cout << "Before: " << term2 << '\n';
156       sim(term2);
157       // cout << "After: " << term2 << '\n';
158    }
161 int main()
163    GC::set_default_gc(marksweep_gc);
164    //
165    // Turn on finalization
166    //
167    GC::get_default_gc().set_finalization(true); 
169    cout << "Now performing some rewrites and generating some garbage.\n"
170            "(See also the test 'test_rc1')\n" << flush;
171    // GC::get_default_gc().set_verbosity(0);
172    do_my_stuff();
173    cout << "Finished.  Now I'll force one more GC to clean up.\n"
174            "There should be at most a few kilobytes of retention at the end.\n"
175            "The GC should be able to recognized a large part of the heap as\n"
176            "garbage.  See below:\n";
177    // GC::get_default_gc().set_verbosity(1);
178    GC::garbage_collect();
179    cout << "The following allocation count should be very close to the\n"
180            "finalization count.  If they are very far apart that means\n"
181            "something is wrong.\n" 
182         << "Allocation count        = " << LOGGER::allocation_count << '\n'
183         << "Number of finalizations = " << LOGGER::deallocation_count << '\n';
184    if (GC::get_default_gc().statistics().bytes_used <= 1024)
185       cout << "Seems like it's working well for your platform.   Lucky dog!\n";
186    return 0;