[Debtags-commits] [svn] r1683 - in tagcoll/2.0: . tagcoll tests tools

Enrico Zini enrico at costa.debian.org
Tue May 2 00:54:41 UTC 2006


Author: enrico
Date: Tue May  2 00:54:37 2006
New Revision: 1683

Added:
   tagcoll/2.0/tagcoll/Sink.h
   tagcoll/2.0/tagcoll/TextFormat.tcc
Modified:
   tagcoll/2.0/   (props changed)
   tagcoll/2.0/Makefile.am
   tagcoll/2.0/tagcoll/Consumer.h
   tagcoll/2.0/tagcoll/Expression.cc
   tagcoll/2.0/tagcoll/Expression.h
   tagcoll/2.0/tagcoll/Filters.cc
   tagcoll/2.0/tagcoll/Filters.h
   tagcoll/2.0/tagcoll/Makefile.am
   tagcoll/2.0/tagcoll/TextFormat.cc
   tagcoll/2.0/tagcoll/TextFormat.h
   tagcoll/2.0/tagcoll/test-utils.cc
   tagcoll/2.0/tests/normalize.cc
   tagcoll/2.0/tests/test-utils.h
   tagcoll/2.0/tools/tagcoll.cc
Log:
 r2538 at viaza:  enrico | 2006-05-02 00:08:40 +0200
 Started getting rid of Consumer


Modified: tagcoll/2.0/Makefile.am
==============================================================================
--- tagcoll/2.0/Makefile.am	(original)
+++ tagcoll/2.0/Makefile.am	Tue May  2 00:54:37 2006
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS = tagcoll tools tests bench doc .
+SUBDIRS = tagcoll tests tools bench doc .
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA=libtagcoll.pc

Modified: tagcoll/2.0/tagcoll/Consumer.h
==============================================================================
--- tagcoll/2.0/tagcoll/Consumer.h	(original)
+++ tagcoll/2.0/tagcoll/Consumer.h	Tue May  2 00:54:37 2006
@@ -24,6 +24,7 @@
  */
 
 #include <tagcoll/OpSet.h>
+#include <wibble/empty.h>
 
 namespace tagcoll
 {
@@ -84,21 +85,37 @@
 	void consume(const OpSet<ITEM>& items, const OpSet<TAG>& tags) { consumeItems(items, tags); }
 };
 
-
-/**
- * Consumer that discards its input
- */
 template<class ITEM, class TAG>
-class Sink : public Consumer<ITEM, TAG>
+class ConsumerAdaptor
 {
-protected:
-	virtual void consumeItemUntagged(const ITEM& item) {}
-	virtual void consumeItem(const ITEM& item, const OpSet<TAG>& tags) {}
-	virtual void consumeItemsUntagged(const OpSet<ITEM>& items) {}
-	virtual void consumeItems(const OpSet<ITEM>& items, const OpSet<TAG>& tags) {}
+	Consumer<ITEM, TAG>& target;
+
 public:
+	ConsumerAdaptor(Consumer<ITEM, TAG>& target) : target(target) {}
+
+	ConsumerAdaptor<ITEM, TAG>& operator++() { return *this; }
+
+	template<typename Items, typename Tags>
+	ConsumerAdaptor<ITEM, TAG>& operator=(const std::pair<Items, Tags>& data)
+	{
+		target.consume(data.first, data.second);
+		return *this;
+	}
+
+	template<typename Items, typename Tag>
+	ConsumerAdaptor<ITEM, TAG>& operator=(const std::pair<Items, wibble::Empty<Tag> >& data)
+	{
+		target.consume(data.first);
+		return *this;
+	}
 };
 
+template<typename ITEM, typename TAG>
+ConsumerAdaptor<ITEM, TAG> consumer(Consumer<ITEM, TAG>& target)
+{
+	return ConsumerAdaptor<ITEM, TAG>(target);
+}
+
 };
 
 // vim:set ts=4 sw=4:

Modified: tagcoll/2.0/tagcoll/Expression.cc
==============================================================================
--- tagcoll/2.0/tagcoll/Expression.cc	(original)
+++ tagcoll/2.0/tagcoll/Expression.cc	Tue May  2 00:54:37 2006
@@ -36,7 +36,7 @@
 	virtual std::string format() const { return "*"; }
 
 	virtual bool eval(const TagexprContext& context) const { return true; }
-	virtual bool eval(const OpSet<std::string>& tags) const { return true; }
+	virtual bool eval(const std::set<std::string>& tags) const { return true; }
 };
 
 class TagexprTag : public ExpressionImpl
@@ -54,12 +54,12 @@
 	{
 		return context.eval(_tag);
 	}
-	virtual bool eval(const OpSet<std::string>& tags) const
+	virtual bool eval(const std::set<std::string>& tags) const
 	{
 		if (_tag[0] == '*')
 		{
 			string match = _tag.substr(1);
-			for (OpSet<string>::const_iterator i = tags.begin();
+			for (std::set<string>::const_iterator i = tags.begin();
 					i != tags.end(); i++)
 				if (i->size() >= match.size() &&
 						i->substr(i->size() - match.size()) == match)
@@ -69,7 +69,7 @@
 		else if (_tag[_tag.size() - 1] == '*')
 		{
 			string match = _tag.substr(0, _tag.size() - 1);
-			for (OpSet<string>::const_iterator i = tags.begin();
+			for (std::set<string>::const_iterator i = tags.begin();
 					i != tags.end(); i++)
 				if (i->size() >= match.size() &&
 						i->substr(0, match.size()) == match)
@@ -95,7 +95,7 @@
 	{
 		return ! _op(context);
 	}
-	virtual bool eval(const OpSet<std::string>& tags) const
+	virtual bool eval(const std::set<std::string>& tags) const
 	{
 		return ! _op(tags);
 	}
@@ -120,7 +120,7 @@
 	{
 		return _op1(context) && _op2(context);
 	}
-	virtual bool eval(const OpSet<std::string>& tags) const
+	virtual bool eval(const std::set<std::string>& tags) const
 	{
 		return _op1(tags) && _op2(tags);
 	}
@@ -145,7 +145,7 @@
 	{
 		return _op1(context) || _op2(context);
 	}
-	virtual bool eval(const OpSet<std::string>& tags) const
+	virtual bool eval(const std::set<std::string>& tags) const
 	{
 		return _op1(tags) || _op2(tags);
 	}
@@ -187,12 +187,12 @@
 {
 	std::map<std::string, Expression>::const_iterator i = derivedTags.find(tag);
 	if (i == derivedTags.end())
-		return tags.contains(tag);
-	else if (!seen.contains(tag))
+		return tags.find(tag) != tags.end();
+	else if (seen.find(tag) == seen.end())
 	{
-		seen += tag;
+		seen.insert(tag);
 		bool res = i->second(*this);
-		seen -= tag;
+		seen.erase(tag);
 		return res;
 	}
 	else
@@ -203,16 +203,6 @@
 
 }
 
-#ifndef INSTANTIATING_TEMPLATES
-#include <string>
-
-namespace tagcoll {
-	template class FilterItemsByExpression<std::string, std::string>;
-	template class FilterTagsByExpression<std::string, std::string>;
-}
-#endif
-
-
 #ifdef COMPILE_TESTSUITE
 
 #include <tests/test-utils.h>
@@ -229,10 +219,10 @@
 template<> template<>
 void to::test<1>()
 {
-	OpSet<string> test;
-	test += "coffee";
-	test += "tea";
-	test += "sugar";
+	std::set<string> test;
+	test.insert("coffee");
+	test.insert("tea");
+	test.insert("sugar");
 	
 	Expression e1("coffee");
 	gen_ensure(e1(test));
@@ -258,9 +248,9 @@
 	e1 = Expression("!(coffee && milk) && (tea && sugar)");
 	gen_ensure(e1(test));
 
-	OpSet<string> test1;
-	test1 += "coffee";
-	test1 += "milk";
+	std::set<string> test1;
+	test1.insert("coffee");
+	test1.insert("milk");
 	Expression e3("coffee && milk && !sugar");
 	gen_ensure(e3(test1));
 }
@@ -279,8 +269,8 @@
 			"d:  c::D, e::F,    f::g\n"
 			);
 	InputMerger<string, string> result;
-	FilterItemsByExpression<string, string> filter(result, "(*::D && e::F) || c");
-	outputCollection(input_coll, filter); 
+	parseCollection(input_coll, filterItemsByExpression(
+				"(*::D && e::F) || c", consumer(result)));
 
 	InputMerger<string, string> reference;
 	outputCollection(output_coll, reference); 
@@ -303,8 +293,8 @@
 			"d: c::D, e::F\n"
 			);
 	InputMerger<string, string> result;
-	FilterTagsByExpression<string, string> filter(result, "*::D || e::F || c");
-	outputCollection(input_coll, filter); 
+	parseCollection(input_coll, filterItemsByExpression(
+				"*::D || e::F || c", consumer(result))); 
 
 	InputMerger<string, string> reference;
 	outputCollection(output_coll, reference); 

Modified: tagcoll/2.0/tagcoll/Expression.h
==============================================================================
--- tagcoll/2.0/tagcoll/Expression.h	(original)
+++ tagcoll/2.0/tagcoll/Expression.h	Tue May  2 00:54:37 2006
@@ -4,7 +4,7 @@
 /*
  * Expression that can match tagsets
  * 
- * Copyright (C) 2003,2004,2005  Enrico Zini <enrico at debian.org>
+ * Copyright (C) 2003,2004,2005,2006  Enrico Zini <enrico at debian.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -21,9 +21,10 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
  */
 
-#include <tagcoll/Filter.h>
 #include <string>
+#include <set>
 #include <map>
+#include <vector>
 
 namespace tagcoll
 {
@@ -67,7 +68,7 @@
 	 * \return
 	 *   true if the expression matches the tags, false otherwise
 	 */
-	virtual bool eval(const OpSet<std::string>& tags) const = 0;
+	virtual bool eval(const std::set<std::string>& tags) const = 0;
 
 	/**
 	 * Return a clone of this tag expression
@@ -111,8 +112,8 @@
 	Expression operator or (const Expression& e);
 	Expression operator not ();
 
-	template<typename M>
-	bool operator()(const OpSet<M>& tags) const { return m_impl->eval(tags); }
+	template<typename Tags>
+	bool operator()(const Tags& tags) const { return m_impl->eval(tags); }
 
 	bool operator()(const TagexprContext& context) const { return m_impl->eval(context); }
 
@@ -136,10 +137,10 @@
 class TagexprContext
 {
 protected:
-	const OpSet<std::string>& tags;
+	const std::set<std::string>& tags;
 	const std::map<std::string, Expression>& derivedTags;
 	// Tags "visited" during tag evaluation: used to break circular loops
-	mutable OpSet<std::string> seen;
+	mutable std::set<std::string> seen;
 
 public:
 	/**
@@ -155,7 +156,7 @@
 	 * \param derivedTags
 	 *   The table of derived tags to use in the evaluation
 	 */
-	TagexprContext(const OpSet<std::string>& tags, const std::map<std::string, Expression>& derivedTags)
+	TagexprContext(const std::set<std::string>& tags, const std::map<std::string, Expression>& derivedTags)
 		: tags(tags), derivedTags(derivedTags) {}
 
 	/**
@@ -166,12 +167,7 @@
 	bool eval(const std::string& tag) const;
 };
 
-
-/**
- * Remove the items that do not match a tag expression.
- */
-template<class ITEM, class TAG>
-class FilterItemsByExpression : public Filter<ITEM, TAG>
+class ExpressionFilter
 {
 public:
 	enum MatchType { PLAIN, INVERTED };
@@ -179,62 +175,21 @@
 protected:
 	Expression expr;
 	MatchType matchType;
-	int matched;
 
-	bool match(const OpSet<TAG>& tags) const
+	template<typename Tags>
+	bool match(const Tags& tags)
 	{
 		if (matchType == PLAIN)
 			return expr(tags);
 		else
 			return !expr(tags);
-
 	}
 
-	virtual void consumeItemUntagged(const ITEM& item)
-	{
-		if (match(OpSet<TAG>()))
-		{
-			matched++;
-			this->consumer->consume(item);
-		}
-	}
-	virtual void consumeItem(const ITEM& item, const OpSet<TAG>& tags)
-	{
-		if (match(tags))
-		{
-			matched++;
-			this->consumer->consume(item, tags);
-		}
-	}
-	virtual void consumeItemsUntagged(const OpSet<ITEM>& items)
-	{
-		if (match(OpSet<TAG>()))
-		{
-			matched += items.size();
-			this->consumer->consume(items);
-		}
-	}
-	virtual void consumeItems(const OpSet<ITEM>& items, const OpSet<TAG>& tags)
-	{
-		if (match(tags))
-		{
-			matched += items.size();
-			this->consumer->consume(items, tags);
-		}
-	}
-	
-public:	
-	FilterItemsByExpression(const Expression& expression) :
-		expr(expression), matchType(PLAIN), matched(0) {}
-	FilterItemsByExpression(const std::string& expression) :
-		expr(expression), matchType(PLAIN), matched(0) {}
-	FilterItemsByExpression(Consumer<ITEM, TAG>&cons, const Expression& expression) :
-		Filter<ITEM, TAG>(cons),
-		expr(expression), matchType(PLAIN), matched(0) {}
-	FilterItemsByExpression(Consumer<ITEM, TAG>&cons, const std::string& expression) :
-		Filter<ITEM, TAG>(cons),
-		expr(expression), matchType(PLAIN), matched(0) {}
-	virtual ~FilterItemsByExpression() {}
+public:
+	ExpressionFilter(const std::string& expr)
+		: expr(expr), matchType(PLAIN) {}
+	ExpressionFilter(const Expression& expr)
+		: expr(expr), matchType(PLAIN) {}
 
 	/**
 	 * Set the expression to use for this filter
@@ -266,20 +221,45 @@
 	 *   INVERTED: only keep the items that do not match the expression
 	 */
 	void setMatchType(MatchType type) { matchType = type; }
+};
 
-	/**
-	 * Return the number of items that matched the expression.
-	 *
-	 * It returns the number of items that did not match if INVERTED match is
-	 * used.
-	 *
-	 * @returns
-	 *   The match count
-	 */
-	int countMatched() const { return matched; }
+/**
+ * Remove the items that do not match a tag expression.
+ */
+template<class OUT>
+class FilterItemsByExpression : public ExpressionFilter
+{
+protected:
+	OUT out;
 
+public:
+	FilterItemsByExpression(const std::string& expr, const OUT& out)
+		: ExpressionFilter(expr), out(out) {}
+	FilterItemsByExpression(const Expression& expr, const OUT& out)
+		: ExpressionFilter(expr), out(out) {}
+	
+	// output iterator interface
+
+	FilterItemsByExpression& operator++() const { return *this; }
+
+	template<typename Items, typename Tags>
+	FilterItemsByExpression& operator=(const std::pair<Items, Tags>& data)
+	{
+		if (match(data.second))
+		{
+			out = data;
+			++out;
+		}
+		return *this;
+	}
 };
 
+template<typename EXPR, typename OUT>
+inline FilterItemsByExpression<OUT> filterItemsByExpression(const EXPR& expr, const OUT& out)
+{
+	return FilterItemsByExpression<OUT>(expr, out);
+}
+
 /**
  * Remove the tags that do not singularly match a tag expression.
  *
@@ -287,118 +267,53 @@
  * tags matching, for example, "special::not-yet-tagged*" or
  * "!(use::gaming || game::*)".
  */
-template<class ITEM, class TAG>
-class FilterTagsByExpression : public Filter<ITEM, TAG>
+template<class OUT>
+class FilterTagsByExpression : public ExpressionFilter
 {
-public:
-	enum MatchType { PLAIN, INVERTED };
-
 protected:
-	Expression expr;
-	MatchType matchType;
-	int matched;
+	OUT out;
 
-	bool match(const TAG& tag) const
-	{
-		OpSet<TAG> tags;
-		tags += tag;
-		if (matchType == PLAIN)
-			return expr(tags);
-		else
-			return !expr(tags);
-	}
+public:
+	FilterTagsByExpression(const std::string& expression, const OUT& out) :
+		ExpressionFilter(expression), out(out) {}
+	FilterTagsByExpression(const Expression& expression, const OUT& out) :
+		ExpressionFilter(expression), out(out) {}
 
-	virtual void consumeItemUntagged(const ITEM& item)
-	{
-		this->consumer->consume(item);
-	}
+	// output iterator interface
 
-	virtual void consumeItem(const ITEM& item, const OpSet<TAG>& tags)
-	{
-		OpSet<TAG> outTags;
-		for (typename OpSet<TAG>::const_iterator i = tags.begin(); i != tags.end(); i++)
-			if (match(*i))
-			{
-				matched++;
-				outTags += *i;
-			}
-		this->consumer->consume(item, outTags);
-	}
+	FilterTagsByExpression& operator++() const { return *this; }
 
-	virtual void consumeItemsUntagged(const OpSet<ITEM>& items)
+	template<typename Items, typename Tags>
+	FilterTagsByExpression& operator=(const std::pair<Items, Tags>& data)
 	{
-		this->consumer->consume(items);
-	}
+		// We can use a vector since we know the input is sorted, and we
+		// remove elements without altering the order of the remaining ones
+		std::vector<typename Tags::value_type> filtered;
+		bool changed = false;
 
-	virtual void consumeItems(const OpSet<ITEM>& items, const OpSet<TAG>& tags)
-	{
-		OpSet<TAG> outTags;
-		for (typename OpSet<TAG>::const_iterator i = tags.begin();
-				i != tags.end(); i++)
+		for (typename Tags::iterator i = data.second.begin();
+				i != data.second.end(); ++i)
+		{
 			if (match(*i))
-			{
-				matched += items.size();
-				outTags += *i;
-			}
-		this->consumer->consume(items, outTags);
-	}
-	
-public:	
-	FilterTagsByExpression(const Expression& expression) :
-		expr(expression), matchType(PLAIN), matched(0) {}
-	FilterTagsByExpression(const std::string& expression) :
-		expr(expression), matchType(PLAIN), matched(0) {}
-	FilterTagsByExpression(Consumer<ITEM, TAG>&cons, const Expression& expression) :
-		Filter<ITEM, TAG>(cons),
-		expr(expression), matchType(PLAIN), matched(0) {}
-	FilterTagsByExpression(Consumer<ITEM, TAG>&cons, const std::string& expression) :
-		Filter<ITEM, TAG>(cons),
-		expr(expression), matchType(PLAIN), matched(0) {}
-	virtual ~FilterTagsByExpression() {}
-
-	/**
-	 * Set the expression to use for this filter
-	 *
-	 * @param expression
-	 *   The expression to use for matching
-	 */
-	void setExpression(const Expression& expression)
-	{
-		expr = expression;
-	}
-
-	/**
-	 * Set the expression to use for this filter
-	 *
-	 * @param expression
-	 *   The expression to use for matching
-	 */
-	void setExpression(const std::string& expression)
-	{
-		expr = Expression(expression);
+				filtered.push_back(*i);
+			else
+				changed = true;
+		}
+		if (!changed)
+			out = data;
+		else
+			out = std::make_pair(data.first, filtered);
+		++out;
+		return *this;
 	}
-
-	/**
-	 * Set the type of match
-	 *
-	 * @param type
-	 *   PLAIN: only keep the tags that match the expression
-	 *   INVERTED: only keep the tags that do not match the expression
-	 */
-	void setMatchType(MatchType type) { matchType = type; }
-
-	/**
-	 * Return the number of tags that matched the expression.
-	 *
-	 * It returns the number oftags that did not match if INVERTED match is
-	 * used.
-	 *
-	 * @returns
-	 *   The match count
-	 */
-	int countMatched() const { return matched; }
 };
 
+template<typename EXPR, typename OUT>
+inline FilterTagsByExpression<OUT> filterTagsByExpression(const EXPR& expr, const OUT& out)
+{
+	return FilterTagsByExpression<OUT>(expr, out);
+}
+
 };
 
 // vim:set ts=4 sw=4:

Modified: tagcoll/2.0/tagcoll/Filters.cc
==============================================================================
--- tagcoll/2.0/tagcoll/Filters.cc	(original)
+++ tagcoll/2.0/tagcoll/Filters.cc	Tue May  2 00:54:37 2006
@@ -68,17 +68,6 @@
 
 }
 
-#ifndef INSTANTIATING_TEMPLATES
-#include <string>
-
-namespace tagcoll {
-template class Substitutions<std::string>;
-template class Substitute<std::string, std::string>;
-template class UnfacetedRemover<std::string>;
-}
-#endif
-
-
 #ifdef COMPILE_TESTSUITE
 
 #include <tests/test-utils.h>
@@ -112,10 +101,10 @@
 			"d:  c::D,    f::g\n"
 			);
 	InputMerger<string, string> result;
-	Substitute<string, string> filter(result);
+	Substitutions<string> changes;
 
-	outputCollection(input_subst, filter.substitutions());
-	outputCollection(input_coll, filter); 
+	parseCollection(input_subst, changes.inserter());
+	parseCollection(input_coll, substitute(changes, consumer(result))); 
 
 	InputMerger<string, string> reference;
 	outputCollection(output_coll, reference); 

Modified: tagcoll/2.0/tagcoll/Filters.h
==============================================================================
--- tagcoll/2.0/tagcoll/Filters.h	(original)
+++ tagcoll/2.0/tagcoll/Filters.h	Tue May  2 00:54:37 2006
@@ -39,23 +39,44 @@
  * collections such as TextFormat.
  */
 template<typename T>
-class Substitutions : public Consumer<T, T>
+class Substitutions
 {
 protected:
 	typedef std::map<T, T> changes_t;
 	changes_t changes;
 
-	virtual void consumeItemUntagged(const T& item) {}
-	virtual void consumeItem(const T& item, const OpSet<T>& tags)
+public:
+	template<typename IT>
+	class SubstitutionsInserter
 	{
-		for (typename OpSet<T>::const_iterator i = tags.begin();
-				i != tags.end(); i++)
-			changes.insert(make_pair(*i, item));
-	}
-	virtual void consumeItemsUntagged(const OpSet<T>& items) {}
+		Substitutions<IT>& out;
 
-public:
-	virtual ~Substitutions() {}
+	public:
+		SubstitutionsInserter(Substitutions<IT>& out)
+			: out(out) {}
+		SubstitutionsInserter& operator++() const { return *this; }
+
+		template<typename NewItems, typename OldItems>
+		SubstitutionsInserter& operator=(const std::pair<NewItems, OldItems>& data)
+		{
+			for (typename NewItems::const_iterator i = data.first.begin();
+					i != data.first.end(); ++i)
+				for (typename OldItems::const_iterator j = data.second.begin();
+						j != data.second.end(); ++j)
+					out.add(*j, *i);
+		}
+	};
+
+	/// Change all the items in a set
+	template<typename Items>
+	std::set<T> change(const Items& values) const
+	{
+		std::set<T> res;
+		for (typename Items::const_iterator t = values.begin();
+				t != values.end(); ++t)
+			res.insert(change(*t));
+		return res;
+	}
 
 	/// Change a single value
 	T change(const T& v) const
@@ -65,14 +86,16 @@
 		return (i == changes.end()) ? v : i->second;
 	}
 
-	/// Change all the items in a set
-	OpSet<T> change(const OpSet<T>& values) const
+	/// Add one substitution to the list
+	void add(const T& oldItem, const T& newItem)
 	{
-		OpSet<T> res;
-		for (typename OpSet<T>::const_iterator t = values.begin();
-				t != values.end(); t++)
-			res += change(*t);
-		return res;
+		changes.insert(make_pair(oldItem, newItem));
+	}
+
+	/// Create an inserter for this class
+	SubstitutionsInserter<T> inserter()
+	{
+		return SubstitutionsInserter<T>(*this);
 	}
 };
 
@@ -91,47 +114,43 @@
  *   coll.output(filter);
  * \endcode
  */
-template<typename ITEM, typename TAG>
-class Substitute : public Filter<ITEM, TAG>
+template<typename T, typename OUT>
+class Substitute
 {
 protected:
-	Substitutions<TAG> changes;
+	Substitutions<T> changes;
+	OUT out;
 	
-	virtual void consumeItemUntagged(const ITEM& item)
-	{
-		this->consumer->consume(item);
-	}
-	virtual void consumeItem(const ITEM& item, const OpSet<TAG>& tags)
-	{
-		this->consumer->consume(item, changes.change(tags));
-	}
-	virtual void consumeItemsUntagged(const OpSet<ITEM>& items)
-	{
-		this->consumer->consume(items);
-	}
-	virtual void consumeItem(const OpSet<ITEM>& items, const OpSet<TAG>& tags)
-	{
-		this->consumer->consume(items, changes.change(tags));
-	}
-
 public:
-	Substitute() {}
-	Substitute(Consumer<ITEM, TAG>& cons) : Filter<ITEM, TAG>(cons) {}
-	Substitute(const Substitutions<TAG>& changes) : changes(changes) {}
-	Substitute(Consumer<ITEM, TAG>& cons, const Substitutions<TAG>& changes) :
-		Filter<ITEM, TAG>(cons), changes(changes) {}
+	Substitute(const OUT& out) : out(out) {}
+	Substitute(const Substitutions<T>& changes, const OUT& out) : changes(changes), out(out) {}
 
 	/**
 	 * Access the internal Substitution list
 	 */
-	Substitutions<TAG>& substitutions() { return changes; }
+	Substitutions<T>& substitutions() { return changes; }
 
 	/**
 	 * Access the internal Substitution list (const version)
 	 */
-	const Substitutions<TAG>& substitutions() const { return changes; }
+	const Substitutions<T>& substitutions() const { return changes; }
+
+	Substitute<T, OUT>& operator++() const { return *this; }
+
+	template<typename Items, typename Tags>
+	Substitute<T, OUT>& operator=(const std::pair<Items, Tags>& data)
+	{
+		out = make_pair(data.first, changes.change(data.second));
+		++out;
+	}
 };
 
+template<typename T, typename OUT>
+Substitute<T, OUT> substitute(const Substitutions<T>& changes, const OUT& out)
+{
+	return Substitute<T, OUT>(changes, out);
+}
+
 /**
  * Remove packages with no tags.
  *

Modified: tagcoll/2.0/tagcoll/Makefile.am
==============================================================================
--- tagcoll/2.0/tagcoll/Makefile.am	(original)
+++ tagcoll/2.0/tagcoll/Makefile.am	Tue May  2 00:54:37 2006
@@ -15,6 +15,7 @@
 		StdioParserInput.h \
 		\
 		Consumer.h \
+		Sink.h \
 		Filter.h \
 		ReadonlyCollection.h \
 		Collection.h \
@@ -28,7 +29,7 @@
 		Serializer.h \
 		Serializer.cc \
 		TextFormat.h \
-		TextFormat.cc \
+		TextFormat.tcc \
 		\
 		TDBIndexer.h \
 		TDBIndexer.cc \
@@ -64,6 +65,7 @@
 		\
 		Consumer.cc \
 		Filter.cc \
+		Filters.cc \
 		Patches.cc \
 		InputMerger.cc \
 		PatchCollection.cc \
@@ -79,7 +81,6 @@
 		IntDiskIndex.cc \
 		BasicStringDiskIndex.cc \
 		\
-		Filters.cc \
 		Implications.cc \
 		\
 		Expression.cc \

Modified: tagcoll/2.0/tagcoll/TextFormat.cc
==============================================================================
--- tagcoll/2.0/tagcoll/TextFormat.cc	(original)
+++ tagcoll/2.0/tagcoll/TextFormat.cc	Tue May  2 00:54:37 2006
@@ -30,372 +30,6 @@
 using namespace stringf;
 using namespace tagcoll;
 
-static void printTagset(const OpSet<string>& ts, FILE* out)
-{
-	for (OpSet<string>::const_iterator i = ts.begin();
-			i != ts.end(); i++)
-		if (i == ts.begin())
-		{
-			if (fprintf(out, "%.*s", PFSTR(*i)) < 0)
-				throw wibble::exception::System("writing tagset");
-		}
-		else
-		{
-			if (fprintf(out, ", %.*s", PFSTR(*i)) < 0)
-				throw wibble::exception::System("writing tagset");
-		}
-}
-
-template<class ITEM, class TAG>
-void TextFormat<ITEM, TAG>::consumeItemUntagged(const ITEM& item)
-{
-	string sitem = itemconv(item);
-	if (fprintf(out, "%.*s\n", PFSTR(sitem)) < 0)
-		throw wibble::exception::System("writing item");
-}
-
-template<class ITEM, class TAG>
-void TextFormat<ITEM, TAG>::consumeItem(const ITEM& item, const OpSet<TAG>& tags)
-{
-	string sitem = itemconv(item);
-	if (fprintf(out, "%.*s: ", PFSTR(sitem)) < 0)
-		throw wibble::exception::System("writing item");
-	printTagset(tagconv(tags), out);
-	if (fprintf(out, "\n") < 0)
-		throw wibble::exception::System("writing newline after tagset");
-}
-
-template<class ITEM, class TAG>
-void TextFormat<ITEM, TAG>::consumeItemsUntagged(const OpSet<ITEM>& items)
-{
-	printTagset(itemconv(items), out);
-	if (fprintf(out, "\n") < 0)
-		throw wibble::exception::System("writing newline after items");
-}
-
-template<class ITEM, class TAG>
-void TextFormat<ITEM, TAG>::consumeItems(const OpSet<ITEM>& items, const OpSet<TAG>& tags)
-{
-	printTagset(itemconv(items), out);
-	if (fprintf(out, ": ") < 0)
-		throw wibble::exception::System("writing colon after items");
-	printTagset(tagconv(tags), out);
-	if (fprintf(out, "\n") < 0)
-		throw wibble::exception::System("writing newline after tagset");
-}
-
-
-template<class ITEM, class TAG>
-void TextFormat<ITEM, TAG>::outputPatch(
-		Converter<ITEM, std::string>& itemconv,
-		Converter<TAG, std::string>& tagconv,
-		const PatchList<ITEM, TAG>& patch,
-		FILE* out)
-{
-	for (typename PatchList<ITEM, TAG>::const_iterator i = patch.begin();
-			i != patch.end(); i++)
-	{
-		string sitem = itemconv(i->first);
-		if (fprintf(out, "%.*s: ", PFSTR(sitem)) < 0)
-			throw wibble::exception::System("writing item");
-
-		OpSet<string> stags;
-		for (typename OpSet<TAG>::const_iterator j = i->second.getAdded().begin();
-				j != i->second.getAdded().end(); j++)
-			stags += "+"+tagconv(*j);
-		for (typename OpSet<TAG>::const_iterator j = i->second.getRemoved().begin();
-				j != i->second.getRemoved().end(); j++)
-			stags += "-"+tagconv(*j);
-
-		printTagset(stags, out);
-		if (fprintf(out, "\n") < 0)
-			throw wibble::exception::System("writing newline after tagset");
-	}
-}
-
-
-// Parse an element
-// Return the trailing separating char, that can be:
-//  ParserInput::Eof
-//  '\n'
-//  ':'
-//  ','
-// Return the item in `item'
-
-// element: \s*[^ \t,:]\s*([.:])\s*
-// or
-// element: \s*[^ \t,:].*?[^ \t,:]\s*([.:])\s+
-static int parseElement(ParserInput& in, string& item) throw (tagcoll::exception::Parser)
-{
-	item = string();
-	string sep;
-	int c;
-	char sepchar = 0;
-	enum {LSPACE, ITEM, ISPACE, ISEP, TSPACE} state = LSPACE;
-	while ((c = in.nextChar()) != ParserInput::Eof)
-	{
-		if (c == '\n')
-		{
-			if (sepchar && sepchar != ':')
-				throw tagcoll::exception::Parser("separator character ends the line");
-			else
-				return '\n';
-		}
-		switch (state)
-		{
-			// Optional leading space
-			case LSPACE:
-				switch (c)
-				{
-					case ' ':
-					case '\t':
-						break;
-					case ':':
-					case ',':
-						throw tagcoll::exception::Parser("element cannot start with a separation character");
-						break;
-					default:
-						item += c;
-						state = ITEM;
-						break;
-				}
-				break;
-			// Non-separating characters
-			case ITEM:
-				switch (c)
-				{
-					case ' ':
-					case '\t':
-						sep += c;
-						state = ISPACE;
-						break;
-					case ':':
-					case ',':
-						sepchar = c;
-						sep += c;
-						state = ISEP;
-						break;
-					default:
-						item += c;
-						break;
-				}
-				break;
-			// Space inside item or at the end of item
-			case ISPACE:
-				switch (c)
-				{
-					case ' ':
-					case '\t':
-						sep += c;
-						break;
-					case ':':
-					case ',':
-						sepchar = c;
-						state = TSPACE;
-						break;
-					default:
-						item += sep;
-						item += c;
-						sep = string();
-						state = ITEM;
-						break;
-				}
-				break;
-			// Separator inside item or at the end of item
-			case ISEP:
-				switch (c)
-				{
-					case ' ':
-					case '\t':
-						if (sep.size() > 1)
-							throw tagcoll::exception::Parser("item is followed by more than one separator characters");
-						state = TSPACE;
-						break;
-					case ':':
-					case ',':
-						sep += c;
-						break;
-					default:
-						item += sep;
-						item += c;
-						sepchar = 0;
-						sep = string();
-						state = ITEM;
-						break;
-				}
-				break;
-			case TSPACE:
-				switch (c)
-				{
-					case ' ':
-					case '\t':
-						break;
-					default:
-						in.pushChar(c);
-						return sepchar;
-				}
-				break;
-		}
-	}
-	return ParserInput::Eof;
-}
-
-// item1, item2, item3: tag1, tag2, tag3
-
-//#define TRACE_PARSE
-static void parseTextFormat(
-		ParserInput& in,
-		Consumer<string, string>& consumer)
-{
-	string item;
-
-	OpSet<string> itemset;
-	OpSet<string> tagset;
-	int sep;
-	enum {ITEMS, TAGS} state = ITEMS;
-	int line = 1;
-	do
-	{
-		try {
-			sep = parseElement(in, item);
-		} catch (tagcoll::exception::Parser& e) {
-			// Add the line number and propagate
-			e.line(line);
-			throw e;
-		}
-		
-		if (item.size() != 0)
-			if (state == ITEMS)
-				itemset += item;
-			else
-				tagset += item;
-		
-		switch (sep)
-		{
-			case '\n':
-				line++;
-			case ParserInput::Eof:
-				if (!(itemset.empty() && tagset.empty()))
-				{
-					if (itemset.empty())
-						throw tagcoll::exception::Parser(line, "no elements before `:' separator");
-					if (tagset.empty())
-						consumer.consume(itemset);
-					else
-						consumer.consume(itemset, tagset);
-				}
-				itemset.clear();
-				tagset.clear();
-				state = ITEMS;
-				break;
-			case ':':
-				if (state == TAGS)
-					throw tagcoll::exception::Parser(line, "separator `:' appears twice");
-				state = TAGS;
-				break;
-			default:
-				break;
-		}
-	} while (sep != ParserInput::Eof);
-}
-
-
-template<class ITEM, class TAG>
-void TextFormat<ITEM, TAG>::parse(
-		Converter<std::string, ITEM>& itemconv,
-		Converter<std::string, TAG>& tagconv,
-		ParserInput& in,
-		Consumer<ITEM, TAG>& consumer)
-{
-	ConversionFilter<string, string, ITEM, TAG> conv(itemconv, tagconv, consumer);
-	parseTextFormat(in, conv);
-}
-
-template<class ITEM, class TAG>
-class PatchBuilder : public Consumer<string, string>
-{
-protected:
-	PatchList<ITEM, TAG> patch;
-	const Converter<std::string, ITEM>& itemconv;
-	const Converter<std::string, TAG>& tagconv;
-
-	virtual void consumeItemUntagged(const string&) {}
-
-	virtual void consumeItem(const string& item, const OpSet<string>& tags)
-	{
-		ITEM it = itemconv(item);
-		if (it == ITEM())
-			return;
-
-		Patch<ITEM, TAG> p(it);
-		for (OpSet<string>::const_iterator i = tags.begin(); i != tags.end(); i++)
-		{
-			TAG tag = tagconv(i->substr(1));
-			if (tag != TAG())
-				if ((*i)[0] == '-')
-					p.remove(tag);
-				else if ((*i)[0] == '+')
-					p.add(tag);
-		}
-		patch.addPatch(p);
-	}
-
-	virtual void consumeItemsUntagged(const OpSet<string>&) {}
-
-	virtual void consumeItems(const OpSet<string>& items, const OpSet<string>& tags)
-	{
-		OpSet<TAG> added;
-		OpSet<TAG> removed;
-
-		for (OpSet<string>::const_iterator i = tags.begin(); i != tags.end(); i++)
-		{
-			TAG tag = tagconv(i->substr(1));
-			if (tag != TAG())
-				if ((*i)[0] == '-')
-					removed += tag;
-				else if ((*i)[0] == '+')
-					added += tag;
-		}
-
-		for (OpSet<string>::const_iterator i = items.begin(); i != items.end(); i++)
-		{
-			ITEM it = itemconv(*i);
-			if (it != ITEM())
-				patch.addPatch(Patch<ITEM, TAG>(it, added, removed));
-		}
-	}
-
-
-public:
-	PatchBuilder(
-			const Converter<std::string, ITEM>& itemconv,
-			const Converter<std::string, TAG>& tagconv)
-		: itemconv(itemconv), tagconv(tagconv) {}
-	virtual ~PatchBuilder() {}
-	
-	const PatchList<ITEM, TAG>& getPatch() const throw () { return patch; }
-};
-
-template<class ITEM, class TAG>
-PatchList<ITEM, TAG> TextFormat<ITEM, TAG>::parsePatch(
-		Converter<std::string, ITEM>& itemconv,
-		Converter<std::string, TAG>& tagconv,
-		ParserInput& in)
-{
-	PatchBuilder<ITEM, TAG> builder(itemconv, tagconv);
-	parseTextFormat(in, builder);
-	return builder.getPatch();
-}
-
-#ifndef INSTANTIATING_TEMPLATES
-#include <string>
-
-namespace tagcoll {
-	template class TextFormat<std::string, std::string>;
-}
-#endif
-
-
 #ifdef COMPILE_TESTSUITE
 
 #include <tests/test-utils.h>
@@ -419,9 +53,7 @@
 	);
 	
 	TestConsumer<string, string> cons;
-
-	TrivialConverter<string, string> a;
-	TextFormat<string, string>::parse(a, a, coll, cons);
+	TextFormat<string, string>::parse(coll, consumer(cons));
 
 	gen_ensure_equals(cons.items, 4);
 	gen_ensure_equals(cons.tags, 5);

Modified: tagcoll/2.0/tagcoll/TextFormat.h
==============================================================================
--- tagcoll/2.0/tagcoll/TextFormat.h	(original)
+++ tagcoll/2.0/tagcoll/TextFormat.h	Tue May  2 00:54:37 2006
@@ -57,6 +57,8 @@
 	const Converter<TAG, std::string>& tagconv;
 	FILE* out;
 
+	static int parseElement(ParserInput& in, std::string& item) throw (tagcoll::exception::Parser);
+
 	virtual void consumeItemUntagged(const ITEM& item);
 	virtual void consumeItem(const ITEM& item, const OpSet<TAG>& tags);
 	virtual void consumeItemsUntagged(const OpSet<ITEM>& items);
@@ -80,6 +82,16 @@
 			FILE* out);
 
 	/**
+	 * Parse a tagged collection, sending the results to out.
+	 *
+	 * @param out
+	 *   An output iterator accepting a std::pair<string, string>
+	 */
+	template<typename OUT>
+	static void parse(ParserInput& in, OUT out);
+
+#if 0
+	/**
 	 * Parse a tagged collection, sending the data to `consumer'
 	 */
 	static void parse(
@@ -87,6 +99,7 @@
 			Converter<std::string, TAG>& tagconv,
 			ParserInput& in,
 			Consumer<ITEM, TAG>& consumer);
+#endif
 
 	/**
 	 * Parse a tagcoll patch

Modified: tagcoll/2.0/tagcoll/test-utils.cc
==============================================================================
--- tagcoll/2.0/tagcoll/test-utils.cc	(original)
+++ tagcoll/2.0/tagcoll/test-utils.cc	Tue May  2 00:54:37 2006
@@ -50,8 +50,7 @@
 void outputCollection(const std::string& str, tagcoll::Consumer<string, string>& cons)
 {
 	StringParserInput input(str);
-	TrivialConverter<string, string> a;
-	TextFormat<string, string>::parse(a, a, input, cons);
+	TextFormat<string, string>::parse(input, consumer(cons));
 }
 
 void __tc_ensure_coll_equals(const Location& loc,

Modified: tagcoll/2.0/tests/normalize.cc
==============================================================================
--- tagcoll/2.0/tests/normalize.cc	(original)
+++ tagcoll/2.0/tests/normalize.cc	Tue May  2 00:54:37 2006
@@ -22,7 +22,7 @@
 		scores.add("implemented-in::*", 0.3);
 		scores.add("*::TODO", 0.1);
 
-		TextFormat<string, string>::parse(conv, conv, in, norm);
+		TextFormat<string, string>::parse(in, consumer(norm));
 
 		norm.buildGraph(scores);
 		norm.normalize();
@@ -37,4 +37,6 @@
 	}
 }
 
+#include <tagcoll/TextFormat.tcc>
+
 // vim:set ts=4 sw=4:

Modified: tagcoll/2.0/tests/test-utils.h
==============================================================================
--- tagcoll/2.0/tests/test-utils.h	(original)
+++ tagcoll/2.0/tests/test-utils.h	Tue May  2 00:54:37 2006
@@ -12,6 +12,8 @@
 
 #ifdef TEST_TAGCOLL
 #include <tagcoll/Collection.h>
+#include <tagcoll/StringParserInput.h>
+#include <tagcoll/TextFormat.h>
 #endif
 /*
 #include <apt-front/cache.h>
@@ -85,6 +87,13 @@
 
 void outputCollection(const std::string& str, tagcoll::Consumer<string, string>& cons);
 
+template<typename OUT>
+void parseCollection(const std::string& str, const OUT& out)
+{
+	StringParserInput input(str);
+	TextFormat<string, string>::parse(input, out);
+}
+
 #define gen_ensure(x) _gen_ensure(Location(__FILE__, __LINE__, #x), (x))
 #define inner_ensure(x) _gen_ensure(Location(loc, __FILE__, __LINE__, #x), (x))
 void _gen_ensure(const Location& loc, bool res);

Modified: tagcoll/2.0/tools/tagcoll.cc
==============================================================================
--- tagcoll/2.0/tools/tagcoll.cc	(original)
+++ tagcoll/2.0/tools/tagcoll.cc	Tue May  2 00:54:37 2006
@@ -49,7 +49,6 @@
 #include <tagcoll/Filters.h>
 #include <tagcoll/Patches.h>
 #include <tagcoll/DerivedTags.h>
-#include <tagcoll/ItemGrouper.h>
 
 #include <tagcoll/StdioParserInput.h>
 #include <tagcoll/TextFormat.h>
@@ -115,17 +114,15 @@
 
 void readCollection(const string& file, Consumer<string, string>& builder)
 {
-	TrivialConverter<string, string> conv;
-
 	if (file == "-")
 	{
 		StdioParserInput input(stdin, "<stdin>");
-		TextFormat<string, string>::parse(conv, conv, input, builder);
+		TextFormat<string, string>::parse(input, consumer(builder));
 	}
 	else
 	{
 		StdioParserInput input(file);
-		TextFormat<string, string>::parse(conv, conv, input, builder);
+		TextFormat<string, string>::parse(input, consumer(builder));
 	}
 }
 



More information about the Debtags-commits mailing list