[LyX/master] Introduce helper template to simplify breakParagraph code

Jean-Marc Lasgouttes lasgouttes at lyx.org
Tue Dec 7 15:47:01 UTC 2021


commit 49115315ea751332d3f8f8a0770cf8427a2c9640
Author: Jean-Marc Lasgouttes <lasgouttes at lyx.org>
Date:   Sat Jul 17 02:31:49 2021 +0200

    Introduce helper template to simplify breakParagraph code
    
    This is a semi-generic iterator for iterating over a container and
    pretend that we add elements to it along the way.
---
 src/Row.h           |    2 +
 src/TextMetrics.cpp |   79 ++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 67 insertions(+), 14 deletions(-)

diff --git a/src/Row.h b/src/Row.h
index 4fdcee4..72d7a86 100644
--- a/src/Row.h
+++ b/src/Row.h
@@ -150,6 +150,8 @@ public:
 		friend std::ostream & operator<<(std::ostream & os, Element const & row);
 	};
 
+	///
+	typedef Element value_type;
 
 	///
 	Row() {}
diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp
index 00d65da..b5ba974 100644
--- a/src/TextMetrics.cpp
+++ b/src/TextMetrics.cpp
@@ -995,6 +995,62 @@ Row newRow(TextMetrics const & tm, pit_type pit, pos_type pos, bool is_rtl)
 	return nrow;
 }
 
+
+/** Helper template flexible_const_iterator<T>
+ * A way to iterate over a const container, but insert fake elements in it.
+ * In the case of a row, we will have to break some elements, which
+ * create new ones. This class allows to abstract this.
+ * Only the required parts are implemented for now.
+ */
+template<class T>
+class flexible_const_iterator {
+	typedef typename T::value_type value_type;
+public:
+
+	//
+	flexible_const_iterator operator++() {
+		if (pile_.empty())
+			++cit_;
+		else
+			pile_.pop_back();
+		return *this;
+	}
+
+	value_type operator*() const { return pile_.empty() ? *cit_ : pile_.back(); }
+
+	void put(value_type const & e) { pile_.push_back(e); }
+
+// This should be private, but declaring the friend functions is too much work
+//private:
+	typename T::const_iterator cit_;
+	// A vector that is used as like a pile to store the elements to
+	// consider before incrementing the underlying iterator.
+	vector<value_type> pile_;
+};
+
+
+template<class T>
+flexible_const_iterator<T> flexible_begin(T const & t)
+{
+	return { t.begin(), vector<typename T::value_type>() };
+}
+
+
+template<class T>
+flexible_const_iterator<T> flexible_end(T const & t)
+{
+	return { t.end(), vector<typename T::value_type>() };
+}
+
+
+// Equality is only possible if respective piles are empty
+template<class T>
+bool operator==(flexible_const_iterator<T> const & t1,
+                flexible_const_iterator<T> const & t2)
+{
+	return t1.cit_ == t2.cit_ && t1.pile_.empty() && t2.pile_.empty();
+}
+
 }
 
 
@@ -1006,11 +1062,8 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const
 	bool need_new_row = true;
 	pos_type pos = 0;
 	int width = 0;
-	Row::const_iterator cit = bigrow.begin();
-	Row::const_iterator const end = bigrow.end();
-	// This is a vector, but we use it like a pile putting and taking
-	// stuff at the back.
-	Row::Elements pile;
+	flexible_const_iterator<Row> fcit = flexible_begin(bigrow);
+	flexible_const_iterator<Row> const end = flexible_end(bigrow);
 	while (true) {
 		if (need_new_row) {
 			if (!rows.empty()) {
@@ -1029,27 +1082,25 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const
 
 		// The stopping condition is here because we may need a new
 		// empty row at the end.
-		if (cit == end && pile.empty())
+		if (fcit == end)
 			break;
 
 		// Next element to consider is either the top of the temporary
 		// pile, or the place when we were in main row
-		Row::Element elt = pile.empty() ? *cit : pile.back();
-		//LYXERR0("elt=" << elt);
+		Row::Element elt = *fcit;
 		Row::Element next_elt = elt.splitAt(width - rows.back().width(),
 		                                    !elt.font.language()->wordWrap());
-		//LYXERR0("next_elt=" << next_elt);
 		// a new element in the row
 		rows.back().push_back(elt);
 		pos = elt.endpos;
+
 		// Go to next element
-		if (pile.empty())
-			++cit;
-		else
-			pile.pop_back();
+		++fcit;
+
 		// Add a new next element on the pile
 		if (next_elt.isValid()) {
-			pile.push_back(next_elt);
+			// do as if we inserted this element in the original row
+			fcit.put(next_elt);
 			need_new_row = true;
 		}
 	}


More information about the lyx-cvs mailing list