Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

Expression.h

Go to the documentation of this file.
00001 #ifndef TAGCOLL_EXPRESSION_H
00002 #define TAGCOLL_EXPRESSION_H
00003 
00004 /*
00005  * Expression that can match tagsets
00006  * 
00007  * Copyright (C) 2003,2004,2005  Enrico Zini <enrico@debian.org>
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00022  */
00023 
00024 #include <tagcoll/Filter.h>
00025 #include <string>
00026 #include <map>
00027 
00028 namespace Tagcoll
00029 {
00030 
00031 class TagexprContext;
00032 
00036 class ExpressionImpl
00037 {
00038 protected:
00039     int _ref;
00040 
00041 public:
00042     ExpressionImpl() : _ref(0) {}
00043     virtual ~ExpressionImpl() {}
00044 
00046     void ref() throw () { ++_ref; }
00047 
00050     bool unref() throw () { return --_ref == 0; }
00051 
00055     virtual std::string format() const = 0;
00056 
00062     virtual bool eval(const TagexprContext& context) const = 0;
00063 
00070     virtual bool eval(const OpSet<std::string>& tags) const = 0;
00071 
00075     //virtual Tagexpr* clone() const = 0;
00076 };
00077 
00078 class Expression
00079 {
00080 protected:
00081     ExpressionImpl* m_impl;
00082 
00083     Expression(ExpressionImpl* impl) : m_impl(impl) { m_impl->ref(); }
00084 
00085     const ExpressionImpl* impl() const { return m_impl; }
00086     ExpressionImpl* impl() { return m_impl; }
00087 
00088 public:
00089     Expression();
00090     Expression(const std::string& expr);
00091 
00092     Expression(const Expression& e)
00093     {
00094         if (e.m_impl)
00095             e.m_impl->ref();
00096         m_impl = e.m_impl;
00097     }
00098     ~Expression() { if (m_impl->unref()) delete m_impl; }
00099 
00100     Expression& operator=(const Expression& e)
00101     {
00102         if (e.m_impl)
00103             e.m_impl->ref();  // Do it early to correctly handle the case of x = x;
00104         if (m_impl && m_impl->unref())
00105             delete m_impl;
00106         m_impl = e.m_impl;
00107         return *this;
00108     }
00109 
00110     Expression operator and (const Expression& e);
00111     Expression operator or (const Expression& e);
00112     Expression operator not ();
00113 
00114     template<typename M>
00115     bool operator()(const OpSet<M>& tags) const { return m_impl->eval(tags); }
00116 
00117     bool operator()(const TagexprContext& context) const { return m_impl->eval(context); }
00118 
00119     std::string format() const { return m_impl->format(); }
00120 
00121     static Expression matchTag(const std::string& pattern);
00122 };
00123 
00136 class TagexprContext
00137 {
00138 protected:
00139     const OpSet<std::string>& tags;
00140     const std::map<std::string, Expression>& derivedTags;
00141     // Tags "visited" during tag evaluation: used to break circular loops
00142     mutable OpSet<std::string> seen;
00143 
00144 public:
00158     TagexprContext(const OpSet<std::string>& tags, const std::map<std::string, Expression>& derivedTags)
00159         : tags(tags), derivedTags(derivedTags) {}
00160 
00166     bool eval(const std::string& tag) const;
00167 };
00168 
00169 
00173 template<class ITEM, class TAG>
00174 class FilterItemsByExpression : public Filter<ITEM, TAG>
00175 {
00176 public:
00177     enum MatchType { PLAIN, INVERTED };
00178 
00179 protected:
00180     Expression expr;
00181     MatchType matchType;
00182     int matched;
00183 
00184     bool match(const OpSet<TAG>& tags) const
00185     {
00186         if (matchType == PLAIN)
00187             return expr(tags);
00188         else
00189             return !expr(tags);
00190 
00191     }
00192 
00193     virtual void consumeItemUntagged(const ITEM& item)
00194     {
00195         if (match(OpSet<TAG>()))
00196         {
00197             matched++;
00198             this->consumer->consume(item);
00199         }
00200     }
00201     virtual void consumeItem(const ITEM& item, const OpSet<TAG>& tags)
00202     {
00203         if (match(tags))
00204         {
00205             matched++;
00206             this->consumer->consume(item, tags);
00207         }
00208     }
00209     virtual void consumeItemsUntagged(const OpSet<ITEM>& items)
00210     {
00211         if (match(OpSet<TAG>()))
00212         {
00213             matched += items.size();
00214             this->consumer->consume(items);
00215         }
00216     }
00217     virtual void consumeItems(const OpSet<ITEM>& items, const OpSet<TAG>& tags)
00218     {
00219         if (match(tags))
00220         {
00221             matched += items.size();
00222             this->consumer->consume(items, tags);
00223         }
00224     }
00225     
00226 public: 
00227     FilterItemsByExpression(const Expression& expression) :
00228         expr(expression), matchType(PLAIN), matched(0) {}
00229     FilterItemsByExpression(const std::string& expression) :
00230         expr(expression), matchType(PLAIN), matched(0) {}
00231     FilterItemsByExpression(Consumer<ITEM, TAG>&cons, const Expression& expression) :
00232         Filter<ITEM, TAG>(cons),
00233         expr(expression), matchType(PLAIN), matched(0) {}
00234     FilterItemsByExpression(Consumer<ITEM, TAG>&cons, const std::string& expression) :
00235         Filter<ITEM, TAG>(cons),
00236         expr(expression), matchType(PLAIN), matched(0) {}
00237     virtual ~FilterItemsByExpression() {}
00238 
00245     void setExpression(const Expression& expression)
00246     {
00247         expr = expression;
00248     }
00249 
00256     void setExpression(const std::string& expression)
00257     {
00258         expr = Expression(expression);
00259     }
00260 
00268     void setMatchType(MatchType type) { matchType = type; }
00269 
00279     int countMatched() const { return matched; }
00280 
00281 };
00282 
00290 template<class ITEM, class TAG>
00291 class FilterTagsByExpression : public Filter<ITEM, TAG>
00292 {
00293 public:
00294     enum MatchType { PLAIN, INVERTED };
00295 
00296 protected:
00297     Expression expr;
00298     MatchType matchType;
00299     int matched;
00300 
00301     bool match(const TAG& tag) const
00302     {
00303         OpSet<TAG> tags;
00304         tags += tag;
00305         if (matchType == PLAIN)
00306             return expr(tags);
00307         else
00308             return !expr(tags);
00309     }
00310 
00311     virtual void consumeItemUntagged(const ITEM& item)
00312     {
00313         this->consumer->consume(item);
00314     }
00315 
00316     virtual void consumeItem(const ITEM& item, const OpSet<TAG>& tags)
00317     {
00318         OpSet<TAG> outTags;
00319         for (typename OpSet<TAG>::const_iterator i = tags.begin(); i != tags.end(); i++)
00320             if (match(*i))
00321             {
00322                 matched++;
00323                 outTags += *i;
00324             }
00325         this->consumer->consume(item, outTags);
00326     }
00327 
00328     virtual void consumeItemsUntagged(const OpSet<ITEM>& items)
00329     {
00330         this->consumer->consume(items);
00331     }
00332 
00333     virtual void consumeItems(const OpSet<ITEM>& items, const OpSet<TAG>& tags)
00334     {
00335         OpSet<TAG> outTags;
00336         for (typename OpSet<TAG>::const_iterator i = tags.begin();
00337                 i != tags.end(); i++)
00338             if (match(*i))
00339             {
00340                 matched += items.size();
00341                 outTags += *i;
00342             }
00343         this->consumer->consume(items, outTags);
00344     }
00345     
00346 public: 
00347     FilterTagsByExpression(const Expression& expression) :
00348         expr(expression), matchType(PLAIN), matched(0) {}
00349     FilterTagsByExpression(const std::string& expression) :
00350         expr(expression), matchType(PLAIN), matched(0) {}
00351     FilterTagsByExpression(Consumer<ITEM, TAG>&cons, const Expression& expression) :
00352         Filter<ITEM, TAG>(cons),
00353         expr(expression), matchType(PLAIN), matched(0) {}
00354     FilterTagsByExpression(Consumer<ITEM, TAG>&cons, const std::string& expression) :
00355         Filter<ITEM, TAG>(cons),
00356         expr(expression), matchType(PLAIN), matched(0) {}
00357     virtual ~FilterTagsByExpression() {}
00358 
00365     void setExpression(const Expression& expression)
00366     {
00367         expr = expression;
00368     }
00369 
00376     void setExpression(const std::string& expression)
00377     {
00378         expr = Expression(expression);
00379     }
00380 
00388     void setMatchType(MatchType type) { matchType = type; }
00389 
00399     int countMatched() const { return matched; }
00400 };
00401 
00402 };
00403 
00404 // vim:set ts=4 sw=4:
00405 #endif

Generated on Fri Sep 9 22:18:04 2005 for libtagcoll by  doxygen 1.4.4