1 : #ifndef TAGCOLL_EXPRESSION_H
2 : #define TAGCOLL_EXPRESSION_H
3 :
4 : /*
5 : * Expression that can match tagsets
6 : *
7 : * Copyright (C) 2003,2004,2005,2006 Enrico Zini <enrico@debian.org>
8 : *
9 : * This library is free software; you can redistribute it and/or
10 : * modify it under the terms of the GNU Lesser General Public
11 : * License as published by the Free Software Foundation; either
12 : * version 2.1 of the License, or (at your option) any later version.
13 : *
14 : * This library is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : * Lesser General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU Lesser General Public
20 : * License along with this library; if not, write to the Free Software
21 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 : */
23 :
24 : #include <string>
25 : #include <set>
26 : #include <map>
27 : #include <wibble/singleton.h>
28 : #include <wibble/mixin.h>
29 :
30 : namespace tagcoll
31 : {
32 :
33 : class TagexprContext;
34 :
35 : /**
36 : * Interface for parsed tag expressions
37 : */
38 : class ExpressionImpl
39 : {
40 : protected:
41 : int _ref;
42 :
43 : public:
44 : ExpressionImpl() : _ref(0) {}
45 : virtual ~ExpressionImpl() {}
46 :
47 : /// Increment the reference count for this object
48 10 : void ref() throw () { ++_ref; }
49 :
50 : /// Decrement the reference count for this object, returning true when it
51 : /// reaches 0
52 22 : bool unref() throw () { return --_ref == 0; }
53 :
54 : /**
55 : * Provide a string representation of this expression
56 : */
57 : virtual std::string format() const = 0;
58 :
59 : /**
60 : * Evaluates the expression on a recursive context
61 : *
62 : * \see TagexprContext
63 : */
64 : virtual bool eval(const TagexprContext& context) const = 0;
65 :
66 : /**
67 : * Evaluates the expression on a set of tags
68 : *
69 : * \return
70 : * true if the expression matches the tags, false otherwise
71 : */
72 : virtual bool eval(const std::set<std::string>& tags) const = 0;
73 :
74 : /**
75 : * Return a clone of this tag expression
76 : */
77 : //virtual Tagexpr* clone() const = 0;
78 : };
79 :
80 : class Expression
81 : {
82 : protected:
83 : ExpressionImpl* m_impl;
84 :
85 : Expression(ExpressionImpl* impl) : m_impl(impl) { m_impl->ref(); }
86 :
87 : const ExpressionImpl* impl() const { return m_impl; }
88 : ExpressionImpl* impl() { return m_impl; }
89 :
90 : public:
91 : Expression();
92 : Expression(const std::string& expr);
93 :
94 : Expression(const Expression& e)
95 : {
96 : if (e.m_impl)
97 : e.m_impl->ref();
98 : m_impl = e.m_impl;
99 : }
100 12 : ~Expression() { if (m_impl->unref()) delete m_impl; }
101 :
102 10 : Expression& operator=(const Expression& e)
103 : {
104 10 : if (e.m_impl)
105 10 : e.m_impl->ref(); // Do it early to correctly handle the case of x = x;
106 10 : if (m_impl && m_impl->unref())
107 10 : delete m_impl;
108 10 : m_impl = e.m_impl;
109 10 : return *this;
110 : }
111 :
112 : Expression operator and (const Expression& e);
113 : Expression operator or (const Expression& e);
114 : Expression operator not ();
115 :
116 : template<typename Tags>
117 : bool operator()(const Tags& tags) const
118 : {
119 : std::set<std::string> stags;
120 : for (typename Tags::const_iterator i = tags.begin();
121 : i != tags.end(); ++i)
122 : stags.insert(*i);
123 : return m_impl->eval(stags);
124 : }
125 : bool operator()(const std::set<std::string>& tags) const { return m_impl->eval(tags); }
126 :
127 : bool operator()(const TagexprContext& context) const { return m_impl->eval(context); }
128 :
129 : std::string format() const { return m_impl->format(); }
130 :
131 : static Expression matchTag(const std::string& pattern);
132 : };
133 :
134 : /**
135 : * Context for evaluating expressions of derived tags.
136 : *
137 : * A derived tag is a tag which is automatically inferred when a tag expression
138 : * is matched on a tagset.
139 : *
140 : * TagexprContext allows the inference engine to distinguish between a normal
141 : * tag or a derived tag.
142 : *
143 : * This class is mainly used to support DerivedTags and has probably little
144 : * applications elsewhere.
145 : */
146 : class TagexprContext
147 : {
148 : protected:
149 : const std::set<std::string>& tags;
150 : const std::map<std::string, Expression>& derivedTags;
151 : // Tags "visited" during tag evaluation: used to break circular loops
152 : mutable std::set<std::string> seen;
153 :
154 : public:
155 : /**
156 : * Create a context for recursive tagset evaluation
157 : *
158 : * Evaluation happens using a derivation table, which can list a tag as an
159 : * alias for another tag expression. Whenever a tag is matched for
160 : * equality with a derived tag, the match is performed with the derived tag
161 : * expression instead.
162 : *
163 : * \param tags
164 : * The tags to evaluate
165 : * \param derivedTags
166 : * The table of derived tags to use in the evaluation
167 : */
168 : TagexprContext(const std::set<std::string>& tags, const std::map<std::string, Expression>& derivedTags)
169 : : tags(tags), derivedTags(derivedTags) {}
170 :
171 : /**
172 : * Evaluates the input tags on the contents to see if they contain the
173 : * given tag, or if they match its associated tag expression if tag is a
174 : * derived tag
175 : */
176 : bool eval(const std::string& tag) const;
177 : };
178 :
179 : };
180 :
181 : // vim:set ts=4 sw=4:
182 : #endif
|