~apparmor-dev/apparmor/master

« back to all changes in this revision

Viewing changes to parser/libapparmor_re/expr-tree.h

  • Committer: Steve Beattie
  • Date: 2019-02-19 09:38:13 UTC
  • Revision ID: sbeattie@ubuntu.com-20190219093813-ud526ee6hwn8nljz
The AppArmor project has been converted to git and is now hosted on
gitlab.

To get the converted repository, please do
  git clone https://gitlab.com/apparmor/apparmor

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
3
 
 * Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
4
 
 * Copyright 2009-2013 Canonical Ltd.
5
 
 *
6
 
 * The libapparmor library is licensed under the terms of the GNU
7
 
 * Lesser General Public License, version 2.1. Please see the file
8
 
 * COPYING.LGPL.
9
 
 *
10
 
 * This library is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU Lesser General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU Lesser General Public License
16
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 
 *
18
 
 *
19
 
 * Functions to create/manipulate an expression tree for regular expressions
20
 
 * that have been parsed.
21
 
 *
22
 
 * The expression tree can be used directly after the parse creates it, or
23
 
 * it can be factored so that the set of important nodes is smaller.
24
 
 * Having a reduced set of important nodes generally results in a dfa that
25
 
 * is closer to minimum (fewer redundant states are created).  It also
26
 
 * results in fewer important nodes in a the state set during subset
27
 
 * construction resulting in less memory used to create a dfa.
28
 
 *
29
 
 * Generally it is worth doing expression tree simplification before dfa
30
 
 * construction, if the regular expression tree contains any alternations.
31
 
 * Even if the regular expression doesn't simplification should be fast
32
 
 * enough that it can be used with minimal overhead.
33
 
 */
34
 
#ifndef __LIBAA_RE_EXPR_H
35
 
#define __LIBAA_RE_EXPR_H
36
 
 
37
 
#include <map>
38
 
#include <set>
39
 
#include <stack>
40
 
#include <ostream>
41
 
 
42
 
#include <stdint.h>
43
 
 
44
 
#include "apparmor_re.h"
45
 
 
46
 
using namespace std;
47
 
 
48
 
typedef unsigned char uchar;
49
 
typedef set<uchar> Chars;
50
 
 
51
 
ostream &operator<<(ostream &os, uchar c);
52
 
 
53
 
/* Compute the union of two sets. */
54
 
template<class T> set<T> operator+(const set<T> &a, const set<T> &b)
55
 
{
56
 
        set<T> c(a);
57
 
        c.insert(b.begin(), b.end());
58
 
        return c;
59
 
}
60
 
 
61
 
/**
62
 
 * When creating DFAs from regex trees, a DFA state is constructed from
63
 
 * a set of important nodes in the syntax tree. This includes AcceptNodes,
64
 
 * which indicate that when a match ends in a particular state, the
65
 
 * regular expressions that the AcceptNode belongs to match.
66
 
 */
67
 
class Node;
68
 
class ImportantNode;
69
 
typedef set<ImportantNode *> NodeSet;
70
 
 
71
 
/**
72
 
 * Text-dump a state (for debugging).
73
 
 */
74
 
ostream &operator<<(ostream &os, const NodeSet &state);
75
 
 
76
 
/**
77
 
 * Out-edges from a state to another: we store the follow-set of Nodes
78
 
 * for each input character that is not a default match in
79
 
 * cases (i.e., following a CharNode or CharSetNode), and default
80
 
 * matches in otherwise as well as in all matching explicit cases
81
 
 * (i.e., following an AnyCharNode or NotCharSetNode). This avoids
82
 
 * enumerating all the explicit tranitions for default matches.
83
 
 */
84
 
typedef struct Cases {
85
 
        typedef map<uchar, NodeSet *>::iterator iterator;
86
 
        iterator begin() { return cases.begin(); }
87
 
        iterator end() { return cases.end(); }
88
 
 
89
 
        Cases(): otherwise(0) { }
90
 
        map<uchar, NodeSet *> cases;
91
 
        NodeSet *otherwise;
92
 
} Cases;
93
 
 
94
 
ostream &operator<<(ostream &os, Node &node);
95
 
 
96
 
/* An abstract node in the syntax tree. */
97
 
class Node {
98
 
public:
99
 
        Node(): nullable(false), label(0) { child[0] = child[1] = 0; }
100
 
        Node(Node *left): nullable(false), label(0)
101
 
        {
102
 
                child[0] = left;
103
 
                child[1] = 0;
104
 
        }
105
 
        Node(Node *left, Node *right): nullable(false), label(0)
106
 
        {
107
 
                child[0] = left;
108
 
                child[1] = right;
109
 
        }
110
 
        virtual ~Node()
111
 
        {
112
 
                if (child[0])
113
 
                        child[0]->release();
114
 
                if (child[1])
115
 
                        child[1]->release();
116
 
        }
117
 
 
118
 
        /**
119
 
         * See the "Dragon Book" for an explanation of nullable, firstpos,
120
 
         * lastpos, and followpos.
121
 
         */
122
 
        virtual void compute_nullable() { }
123
 
        virtual void compute_firstpos() = 0;
124
 
        virtual void compute_lastpos() = 0;
125
 
        virtual void compute_followpos() { }
126
 
        virtual int eq(Node *other) = 0;
127
 
        virtual ostream &dump(ostream &os) = 0;
128
 
        void dump_syntax_tree(ostream &os);
129
 
        virtual void normalize(int dir)
130
 
        {
131
 
                if (child[dir])
132
 
                        child[dir]->normalize(dir);
133
 
                if (child[!dir])
134
 
                        child[!dir]->normalize(dir);
135
 
        }
136
 
        /* return false if no work done */
137
 
        virtual int normalize_eps(int dir __attribute__((unused))) { return 0; }
138
 
 
139
 
        bool nullable;
140
 
        NodeSet firstpos, lastpos, followpos;
141
 
        /* child 0 is left, child 1 is right */
142
 
        Node *child[2];
143
 
 
144
 
        unsigned int label;     /* unique number for debug etc */
145
 
        /**
146
 
         * We indirectly release Nodes through a virtual function because
147
 
         * accept and Eps Nodes are shared, and must be treated specially.
148
 
         * We could use full reference counting here but the indirect release
149
 
         * is sufficient and has less overhead
150
 
         */
151
 
        virtual void release(void) { delete this; }
152
 
};
153
 
 
154
 
class InnerNode: public Node {
155
 
public:
156
 
        InnerNode(): Node() { };
157
 
        InnerNode(Node *left): Node(left) { };
158
 
        InnerNode(Node *left, Node *right): Node(left, right) { };
159
 
};
160
 
 
161
 
class OneChildNode: public InnerNode {
162
 
public:
163
 
        OneChildNode(Node *left): InnerNode(left) { };
164
 
};
165
 
 
166
 
class TwoChildNode: public InnerNode {
167
 
public:
168
 
        TwoChildNode(Node *left, Node *right): InnerNode(left, right) { };
169
 
        virtual int normalize_eps(int dir);
170
 
};
171
 
 
172
 
class LeafNode: public Node {
173
 
public:
174
 
        LeafNode(): Node() { };
175
 
        virtual void normalize(int dir __attribute__((unused))) { return; }
176
 
};
177
 
 
178
 
/* Match nothing (//). */
179
 
class EpsNode: public LeafNode {
180
 
public:
181
 
        EpsNode(): LeafNode()
182
 
        {
183
 
                nullable = true;
184
 
                label = 0;
185
 
        }
186
 
        void release(void)
187
 
        {
188
 
                /* don't delete Eps nodes because there is a single static
189
 
                 * instance shared by all trees.  Look for epsnode in the code
190
 
                 */
191
 
        }
192
 
 
193
 
        void compute_firstpos() { }
194
 
        void compute_lastpos() { }
195
 
        int eq(Node *other)
196
 
        {
197
 
                if (dynamic_cast<EpsNode *>(other))
198
 
                        return 1;
199
 
                return 0;
200
 
        }
201
 
        ostream &dump(ostream &os)
202
 
        {
203
 
                return os << "[]";
204
 
        }
205
 
};
206
 
 
207
 
/**
208
 
 * Leaf nodes in the syntax tree are important to us: they describe the
209
 
 * characters that the regular expression matches. We also consider
210
 
 * AcceptNodes import: they indicate when a regular expression matches.
211
 
 */
212
 
class ImportantNode: public LeafNode {
213
 
public:
214
 
        ImportantNode(): LeafNode() { }
215
 
        void compute_firstpos() { firstpos.insert(this); }
216
 
        void compute_lastpos() { lastpos.insert(this); }
217
 
        virtual void follow(Cases &cases) = 0;
218
 
        virtual int is_accept(void) = 0;
219
 
        virtual int is_postprocess(void) = 0;
220
 
};
221
 
 
222
 
/* common base class for all the different classes that contain
223
 
 * character information.
224
 
 */
225
 
class CNode: public ImportantNode {
226
 
public:
227
 
        CNode(): ImportantNode() { }
228
 
        int is_accept(void) { return false; }
229
 
        int is_postprocess(void) { return false; }
230
 
};
231
 
 
232
 
/* Match one specific character (/c/). */
233
 
class CharNode: public CNode {
234
 
public:
235
 
        CharNode(uchar c): c(c) { }
236
 
        void follow(Cases &cases)
237
 
        {
238
 
                NodeSet **x = &cases.cases[c];
239
 
                if (!*x) {
240
 
                        if (cases.otherwise)
241
 
                                *x = new NodeSet(*cases.otherwise);
242
 
                        else
243
 
                                *x = new NodeSet;
244
 
                }
245
 
                (*x)->insert(followpos.begin(), followpos.end());
246
 
        }
247
 
        int eq(Node *other)
248
 
        {
249
 
                CharNode *o = dynamic_cast<CharNode *>(other);
250
 
                if (o) {
251
 
                        return c == o->c;
252
 
                }
253
 
                return 0;
254
 
        }
255
 
        ostream &dump(ostream &os)
256
 
        {
257
 
                return os << c;
258
 
        }
259
 
 
260
 
        uchar c;
261
 
};
262
 
 
263
 
/* Match a set of characters (/[abc]/). */
264
 
class CharSetNode: public CNode {
265
 
public:
266
 
        CharSetNode(Chars &chars): chars(chars) { }
267
 
        void follow(Cases &cases)
268
 
        {
269
 
                for (Chars::iterator i = chars.begin(); i != chars.end(); i++) {
270
 
                        NodeSet **x = &cases.cases[*i];
271
 
                        if (!*x) {
272
 
                                if (cases.otherwise)
273
 
                                        *x = new NodeSet(*cases.otherwise);
274
 
                                else
275
 
                                        *x = new NodeSet;
276
 
                        }
277
 
                        (*x)->insert(followpos.begin(), followpos.end());
278
 
                }
279
 
        }
280
 
        int eq(Node *other)
281
 
        {
282
 
                CharSetNode *o = dynamic_cast<CharSetNode *>(other);
283
 
                if (!o || chars.size() != o->chars.size())
284
 
                        return 0;
285
 
 
286
 
                for (Chars::iterator i = chars.begin(), j = o->chars.begin();
287
 
                     i != chars.end() && j != o->chars.end(); i++, j++) {
288
 
                        if (*i != *j)
289
 
                                return 0;
290
 
                }
291
 
                return 1;
292
 
        }
293
 
        ostream &dump(ostream &os)
294
 
        {
295
 
                os << '[';
296
 
                for (Chars::iterator i = chars.begin(); i != chars.end(); i++)
297
 
                        os << *i;
298
 
                return os << ']';
299
 
        }
300
 
 
301
 
        Chars chars;
302
 
};
303
 
 
304
 
/* Match all except one character (/[^abc]/). */
305
 
class NotCharSetNode: public CNode {
306
 
public:
307
 
        NotCharSetNode(Chars &chars): chars(chars) { }
308
 
        void follow(Cases &cases)
309
 
        {
310
 
                if (!cases.otherwise)
311
 
                        cases.otherwise = new NodeSet;
312
 
                for (Chars::iterator j = chars.begin(); j != chars.end(); j++) {
313
 
                        NodeSet **x = &cases.cases[*j];
314
 
                        if (!*x)
315
 
                                *x = new NodeSet(*cases.otherwise);
316
 
                }
317
 
                /* Note: Add to the nonmatching characters after copying away
318
 
                 * the old otherwise state for the matching characters.
319
 
                 */
320
 
                cases.otherwise->insert(followpos.begin(), followpos.end());
321
 
                for (Cases::iterator i = cases.begin(); i != cases.end();
322
 
                     i++) {
323
 
                        if (chars.find(i->first) == chars.end())
324
 
                                i->second->insert(followpos.begin(),
325
 
                                                  followpos.end());
326
 
                }
327
 
        }
328
 
        int eq(Node *other)
329
 
        {
330
 
                NotCharSetNode *o = dynamic_cast<NotCharSetNode *>(other);
331
 
                if (!o || chars.size() != o->chars.size())
332
 
                        return 0;
333
 
 
334
 
                for (Chars::iterator i = chars.begin(), j = o->chars.begin();
335
 
                     i != chars.end() && j != o->chars.end(); i++, j++) {
336
 
                        if (*i != *j)
337
 
                                return 0;
338
 
                }
339
 
                return 1;
340
 
        }
341
 
        ostream &dump(ostream &os)
342
 
        {
343
 
                os << "[^";
344
 
                for (Chars::iterator i = chars.begin(); i != chars.end(); i++)
345
 
                        os << *i;
346
 
                return os << ']';
347
 
        }
348
 
 
349
 
        Chars chars;
350
 
};
351
 
 
352
 
/* Match any character (/./). */
353
 
class AnyCharNode: public CNode {
354
 
public:
355
 
        AnyCharNode() { }
356
 
        void follow(Cases &cases)
357
 
        {
358
 
                if (!cases.otherwise)
359
 
                        cases.otherwise = new NodeSet;
360
 
                cases.otherwise->insert(followpos.begin(), followpos.end());
361
 
                for (Cases::iterator i = cases.begin(); i != cases.end();
362
 
                     i++)
363
 
                        i->second->insert(followpos.begin(), followpos.end());
364
 
        }
365
 
        int eq(Node *other)
366
 
        {
367
 
                if (dynamic_cast<AnyCharNode *>(other))
368
 
                        return 1;
369
 
                return 0;
370
 
        }
371
 
        ostream &dump(ostream &os) { return os << "."; }
372
 
};
373
 
 
374
 
/* Match a node zero or more times. (This is a unary operator.) */
375
 
class StarNode: public OneChildNode {
376
 
public:
377
 
        StarNode(Node *left): OneChildNode(left) { nullable = true; }
378
 
        void compute_firstpos() { firstpos = child[0]->firstpos; }
379
 
        void compute_lastpos() { lastpos = child[0]->lastpos; }
380
 
        void compute_followpos()
381
 
        {
382
 
                NodeSet from = child[0]->lastpos, to = child[0]->firstpos;
383
 
                for (NodeSet::iterator i = from.begin(); i != from.end(); i++) {
384
 
                        (*i)->followpos.insert(to.begin(), to.end());
385
 
                }
386
 
        }
387
 
        int eq(Node *other)
388
 
        {
389
 
                if (dynamic_cast<StarNode *>(other))
390
 
                        return child[0]->eq(other->child[0]);
391
 
                return 0;
392
 
        }
393
 
        ostream &dump(ostream &os)
394
 
        {
395
 
                os << '(';
396
 
                child[0]->dump(os);
397
 
                return os << ")*";
398
 
        }
399
 
};
400
 
 
401
 
/* Match a node one or more times. (This is a unary operator.) */
402
 
class PlusNode: public OneChildNode {
403
 
public:
404
 
        PlusNode(Node *left): OneChildNode(left) {
405
 
        }
406
 
        void compute_nullable() { nullable = child[0]->nullable; }
407
 
        void compute_firstpos() { firstpos = child[0]->firstpos; }
408
 
        void compute_lastpos() { lastpos = child[0]->lastpos; }
409
 
        void compute_followpos()
410
 
        {
411
 
                NodeSet from = child[0]->lastpos, to = child[0]->firstpos;
412
 
                for (NodeSet::iterator i = from.begin(); i != from.end(); i++) {
413
 
                        (*i)->followpos.insert(to.begin(), to.end());
414
 
                }
415
 
        }
416
 
        int eq(Node *other) {
417
 
                if (dynamic_cast<PlusNode *>(other))
418
 
                        return child[0]->eq(other->child[0]);
419
 
                return 0;
420
 
        }
421
 
        ostream &dump(ostream &os) {
422
 
                os << '(';
423
 
                child[0]->dump(os);
424
 
                return os << ")+";
425
 
        }
426
 
};
427
 
 
428
 
/* Match a pair of consecutive nodes. */
429
 
class CatNode: public TwoChildNode {
430
 
public:
431
 
        CatNode(Node *left, Node *right): TwoChildNode(left, right) { }
432
 
        void compute_nullable()
433
 
        {
434
 
                nullable = child[0]->nullable && child[1]->nullable;
435
 
        }
436
 
        void compute_firstpos()
437
 
        {
438
 
                if (child[0]->nullable)
439
 
                        firstpos = child[0]->firstpos + child[1]->firstpos;
440
 
                else
441
 
                        firstpos = child[0]->firstpos;
442
 
        }
443
 
        void compute_lastpos()
444
 
        {
445
 
                if (child[1]->nullable)
446
 
                        lastpos = child[0]->lastpos + child[1]->lastpos;
447
 
                else
448
 
                        lastpos = child[1]->lastpos;
449
 
        }
450
 
        void compute_followpos()
451
 
        {
452
 
                NodeSet from = child[0]->lastpos, to = child[1]->firstpos;
453
 
                for (NodeSet::iterator i = from.begin(); i != from.end(); i++) {
454
 
                        (*i)->followpos.insert(to.begin(), to.end());
455
 
                }
456
 
        }
457
 
        int eq(Node *other)
458
 
        {
459
 
                if (dynamic_cast<CatNode *>(other)) {
460
 
                        if (!child[0]->eq(other->child[0]))
461
 
                                return 0;
462
 
                        return child[1]->eq(other->child[1]);
463
 
                }
464
 
                return 0;
465
 
        }
466
 
        ostream &dump(ostream &os)
467
 
        {
468
 
                child[0]->dump(os);
469
 
                child[1]->dump(os);
470
 
                return os;
471
 
        }
472
 
        void normalize(int dir);
473
 
};
474
 
 
475
 
/* Match one of two alternative nodes. */
476
 
class AltNode: public TwoChildNode {
477
 
public:
478
 
        AltNode(Node *left, Node *right): TwoChildNode(left, right) { }
479
 
        void compute_nullable()
480
 
        {
481
 
                nullable = child[0]->nullable || child[1]->nullable;
482
 
        }
483
 
        void compute_lastpos()
484
 
        {
485
 
                lastpos = child[0]->lastpos + child[1]->lastpos;
486
 
        }
487
 
        void compute_firstpos()
488
 
        {
489
 
                firstpos = child[0]->firstpos + child[1]->firstpos;
490
 
        }
491
 
        int eq(Node *other)
492
 
        {
493
 
                if (dynamic_cast<AltNode *>(other)) {
494
 
                        if (!child[0]->eq(other->child[0]))
495
 
                                return 0;
496
 
                        return child[1]->eq(other->child[1]);
497
 
                }
498
 
                return 0;
499
 
        }
500
 
        ostream &dump(ostream &os)
501
 
        {
502
 
                os << '(';
503
 
                child[0]->dump(os);
504
 
                os << '|';
505
 
                child[1]->dump(os);
506
 
                os << ')';
507
 
                return os;
508
 
        }
509
 
        void normalize(int dir);
510
 
};
511
 
 
512
 
class SharedNode: public ImportantNode {
513
 
public:
514
 
        SharedNode() { }
515
 
        void release(void)
516
 
        {
517
 
                /* don't delete SharedNodes via release as they are shared, and
518
 
                 * will be deleted when the table they are stored in is deleted
519
 
                 */
520
 
        }
521
 
 
522
 
        void follow(Cases &cases __attribute__ ((unused)))
523
 
        {
524
 
                /* Nothing to follow. */
525
 
        }
526
 
 
527
 
        /* requires shared nodes to be common by pointer */
528
 
        int eq(Node *other) { return (this == other); }
529
 
};
530
 
 
531
 
/**
532
 
 * Indicate that a regular expression matches. An AcceptNode itself
533
 
 * doesn't match anything, so it will never generate any transitions.
534
 
 */
535
 
class AcceptNode: public SharedNode {
536
 
public:
537
 
        AcceptNode() { }
538
 
        int is_accept(void) { return true; }
539
 
        int is_postprocess(void) { return false; }
540
 
};
541
 
 
542
 
class MatchFlag: public AcceptNode {
543
 
public:
544
 
        MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit) { }
545
 
        ostream &dump(ostream &os) { return os << "< 0x" << hex << flag << '>'; }
546
 
 
547
 
        uint32_t flag;
548
 
        uint32_t audit;
549
 
};
550
 
 
551
 
class ExactMatchFlag: public MatchFlag {
552
 
public:
553
 
        ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit) {}
554
 
};
555
 
 
556
 
class DenyMatchFlag: public MatchFlag {
557
 
public:
558
 
        DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet) {}
559
 
};
560
 
 
561
 
/* Traverse the syntax tree depth-first in an iterator-like manner. */
562
 
class depth_first_traversal {
563
 
        stack<Node *>pos;
564
 
        void push_left(Node *node) {
565
 
                pos.push(node);
566
 
 
567
 
                while (dynamic_cast<InnerNode *>(node)) {
568
 
                        pos.push(node->child[0]);
569
 
                        node = node->child[0];
570
 
                }
571
 
        }
572
 
public:
573
 
        depth_first_traversal(Node *node) { push_left(node); }
574
 
        Node *operator*() { return pos.top(); }
575
 
        Node *operator->() { return pos.top(); }
576
 
        operator  bool() { return !pos.empty(); }
577
 
        void operator++(int)
578
 
        {
579
 
                Node *last = pos.top();
580
 
                pos.pop();
581
 
 
582
 
                if (!pos.empty()) {
583
 
                        /* no need to dynamic cast, as we just popped a node so
584
 
                         * the top node must be an inner node */
585
 
                        InnerNode *node = (InnerNode *) (pos.top());
586
 
                        if (node->child[1] && node->child[1] != last) {
587
 
                                push_left(node->child[1]);
588
 
                        }
589
 
                }
590
 
        }
591
 
};
592
 
 
593
 
struct node_counts {
594
 
        int charnode;
595
 
        int charset;
596
 
        int notcharset;
597
 
        int alt;
598
 
        int plus;
599
 
        int star;
600
 
        int any;
601
 
        int cat;
602
 
};
603
 
 
604
 
extern EpsNode epsnode;
605
 
 
606
 
int debug_tree(Node *t);
607
 
Node *simplify_tree(Node *t, dfaflags_t flags);
608
 
void label_nodes(Node *root);
609
 
unsigned long hash_NodeSet(NodeSet *ns);
610
 
void flip_tree(Node *node);
611
 
 
612
 
 
613
 
 
614
 
/*
615
 
 * hashedNodes - for efficient set comparison
616
 
 */
617
 
class hashedNodeSet {
618
 
public:
619
 
        unsigned long hash;
620
 
        NodeSet *nodes;
621
 
 
622
 
        hashedNodeSet(NodeSet *n): nodes(n)
623
 
        {
624
 
                hash = hash_NodeSet(n);
625
 
        }
626
 
 
627
 
        bool operator<(hashedNodeSet const &rhs)const
628
 
        {
629
 
                if (hash == rhs.hash) {
630
 
                        if (nodes->size() == rhs.nodes->size())
631
 
                                return *nodes < *(rhs.nodes);
632
 
                        else
633
 
                                return nodes->size() < rhs.nodes->size();
634
 
                } else {
635
 
                        return hash < rhs.hash;
636
 
                }
637
 
        }
638
 
};
639
 
 
640
 
 
641
 
class hashedNodeVec {
642
 
public:
643
 
        typedef ImportantNode ** iterator;
644
 
        iterator begin() { return nodes; }
645
 
        iterator end() { iterator t = nodes ? &nodes[len] : NULL; return t; }
646
 
 
647
 
        unsigned long hash;
648
 
        unsigned long len;
649
 
        ImportantNode **nodes;
650
 
 
651
 
        hashedNodeVec(NodeSet *n)
652
 
        {
653
 
                hash = hash_NodeSet(n);
654
 
                len = n->size();
655
 
                nodes = new ImportantNode *[n->size()];
656
 
 
657
 
                unsigned int j = 0;
658
 
                for (NodeSet::iterator i = n->begin(); i != n->end(); i++, j++) {
659
 
                        nodes[j] = *i;
660
 
                }
661
 
        }
662
 
 
663
 
        hashedNodeVec(NodeSet *n, unsigned long h): hash(h)
664
 
        {
665
 
                len = n->size();
666
 
                nodes = new ImportantNode *[n->size()];
667
 
                ImportantNode **j = nodes;
668
 
                for (NodeSet::iterator i = n->begin(); i != n->end(); i++) {
669
 
                        *(j++) = *i;
670
 
                }
671
 
        }
672
 
 
673
 
        ~hashedNodeVec()
674
 
        {
675
 
                delete [] nodes;
676
 
        }
677
 
 
678
 
        unsigned long size()const { return len; }
679
 
 
680
 
        bool operator<(hashedNodeVec const &rhs)const
681
 
        {
682
 
                if (hash == rhs.hash) {
683
 
                        if (len == rhs.size()) {
684
 
                                for (unsigned int i = 0; i < len; i++) {
685
 
                                        if (nodes[i] != rhs.nodes[i])
686
 
                                                return nodes[i] < rhs.nodes[i];
687
 
                                }
688
 
                                return false;
689
 
                        }
690
 
                        return len < rhs.size();
691
 
                }
692
 
                return hash < rhs.hash;
693
 
        }
694
 
};
695
 
 
696
 
class CacheStats {
697
 
public:
698
 
        unsigned long dup, sum, max;
699
 
 
700
 
        CacheStats(void): dup(0), sum(0), max(0) { };
701
 
 
702
 
        void clear(void) { dup = sum = max = 0; }
703
 
        virtual unsigned long size(void) const = 0;
704
 
};
705
 
 
706
 
class NodeCache: public CacheStats {
707
 
public:
708
 
        set<hashedNodeSet> cache;
709
 
 
710
 
        NodeCache(void): cache() { };
711
 
        ~NodeCache() { clear(); };
712
 
 
713
 
        virtual unsigned long size(void) const { return cache.size(); }
714
 
 
715
 
        void clear()
716
 
        {
717
 
                for (set<hashedNodeSet>::iterator i = cache.begin();
718
 
                     i != cache.end(); i++) {
719
 
                        delete i->nodes;
720
 
                }
721
 
                cache.clear();
722
 
                CacheStats::clear();
723
 
        }
724
 
 
725
 
        NodeSet *insert(NodeSet *nodes)
726
 
        {
727
 
                if (!nodes)
728
 
                        return NULL;
729
 
                pair<set<hashedNodeSet>::iterator,bool> uniq;
730
 
                uniq = cache.insert(hashedNodeSet(nodes));
731
 
                if (uniq.second == false) {
732
 
                        delete(nodes);
733
 
                        dup++;
734
 
                } else {
735
 
                        sum += nodes->size();
736
 
                        if (nodes->size() > max)
737
 
                                max = nodes->size();
738
 
                }
739
 
                return uniq.first->nodes;
740
 
        }
741
 
};
742
 
 
743
 
struct deref_less_than {
744
 
       bool operator()(hashedNodeVec * const &lhs, hashedNodeVec * const &rhs)const
745
 
                {
746
 
                        return *lhs < *rhs;
747
 
                }
748
 
};
749
 
 
750
 
class NodeVecCache: public CacheStats {
751
 
public:
752
 
        set<hashedNodeVec *, deref_less_than> cache;
753
 
 
754
 
        NodeVecCache(void): cache() { };
755
 
        ~NodeVecCache() { clear(); };
756
 
 
757
 
        virtual unsigned long size(void) const { return cache.size(); }
758
 
 
759
 
        void clear()
760
 
        {
761
 
                for (set<hashedNodeVec *>::iterator i = cache.begin();
762
 
                     i != cache.end(); i++) {
763
 
                        delete *i;
764
 
                }
765
 
                cache.clear();
766
 
                CacheStats::clear();
767
 
        }
768
 
 
769
 
        hashedNodeVec *insert(NodeSet *nodes)
770
 
        {
771
 
                if (!nodes)
772
 
                        return NULL;
773
 
                pair<set<hashedNodeVec *>::iterator,bool> uniq;
774
 
                hashedNodeVec *nv = new hashedNodeVec(nodes);
775
 
                uniq = cache.insert(nv);
776
 
                if (uniq.second == false) {
777
 
                        delete nv;
778
 
                        dup++;
779
 
                } else {
780
 
                        sum += nodes->size();
781
 
                        if (nodes->size() > max)
782
 
                                max = nodes->size();
783
 
                }
784
 
                delete(nodes);
785
 
                return (*uniq.first);
786
 
        }
787
 
};
788
 
 
789
 
#endif /* __LIBAA_RE_EXPR */