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,2006 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 <string> 00025 #include <set> 00026 #include <map> 00027 #include <wibble/singleton.h> 00028 #include <wibble/mixin.h> 00029 00030 namespace tagcoll 00031 { 00032 00033 class TagexprContext; 00034 00038 class ExpressionImpl 00039 { 00040 protected: 00041 int _ref; 00042 00043 public: 00044 ExpressionImpl() : _ref(0) {} 00045 virtual ~ExpressionImpl() {} 00046 00048 void ref() throw () { ++_ref; } 00049 00052 bool unref() throw () { return --_ref == 0; } 00053 00057 virtual std::string format() const = 0; 00058 00064 virtual bool eval(const TagexprContext& context) const = 0; 00065 00072 virtual bool eval(const std::set<std::string>& tags) const = 0; 00073 00077 //virtual Tagexpr* clone() const = 0; 00078 }; 00079 00080 class Expression 00081 { 00082 protected: 00083 ExpressionImpl* m_impl; 00084 00085 Expression(ExpressionImpl* impl) : m_impl(impl) { m_impl->ref(); } 00086 00087 const ExpressionImpl* impl() const { return m_impl; } 00088 ExpressionImpl* impl() { return m_impl; } 00089 00090 public: 00091 Expression(); 00092 Expression(const std::string& expr); 00093 00094 Expression(const Expression& e) 00095 { 00096 if (e.m_impl) 00097 e.m_impl->ref(); 00098 m_impl = e.m_impl; 00099 } 00100 ~Expression() { if (m_impl->unref()) delete m_impl; } 00101 00102 Expression& operator=(const Expression& e) 00103 { 00104 if (e.m_impl) 00105 e.m_impl->ref(); // Do it early to correctly handle the case of x = x; 00106 if (m_impl && m_impl->unref()) 00107 delete m_impl; 00108 m_impl = e.m_impl; 00109 return *this; 00110 } 00111 00112 Expression operator and (const Expression& e); 00113 Expression operator or (const Expression& e); 00114 Expression operator not (); 00115 00116 template<typename Tags> 00117 bool operator()(const Tags& tags) const 00118 { 00119 std::set<std::string> stags; 00120 for (typename Tags::const_iterator i = tags.begin(); 00121 i != tags.end(); ++i) 00122 stags.insert(*i); 00123 return m_impl->eval(stags); 00124 } 00125 bool operator()(const std::set<std::string>& tags) const { return m_impl->eval(tags); } 00126 00127 bool operator()(const TagexprContext& context) const { return m_impl->eval(context); } 00128 00129 std::string format() const { return m_impl->format(); } 00130 00131 static Expression matchTag(const std::string& pattern); 00132 }; 00133 00146 class TagexprContext 00147 { 00148 protected: 00149 const std::set<std::string>& tags; 00150 const std::map<std::string, Expression>& derivedTags; 00151 // Tags "visited" during tag evaluation: used to break circular loops 00152 mutable std::set<std::string> seen; 00153 00154 public: 00168 TagexprContext(const std::set<std::string>& tags, const std::map<std::string, Expression>& derivedTags) 00169 : tags(tags), derivedTags(derivedTags) {} 00170 00176 bool eval(const std::string& tag) const; 00177 }; 00178 00179 }; 00180 00181 // vim:set ts=4 sw=4: 00182 #endif