Lars Gullik Bjønnes a écrit :
This is the integrated patch from Abdelrazak, after applying the patch
and a tiny bit of reworking I discovered that scrolling was _really_
slow. After commenting out the debug messages from RandomAccessList.h
I got the speed back.

This is weird, scrolling should not involve any call to ParagraphList insertion or removal. I don't have any slowdown here because of those debug message. Is it because of safe_iterator use?

I have some stuff I want to work on wrtt, but that can come later.

Here is the patch for you to look over.

This is very good Lars and you solved the compilation problem with your forward include. That's cool :-) One thing though, are you sure you don't want a class instead of a typedef? A class would allow us to add paragraph specialised method and/or optimisation in the future.

¹ My Super Scrolling test... amazing how manyproblems it discovers.
Just load the UserGuide and press "Page Down" just watch it and time
it.

Could you explain me what is this Super Scrolling test please?

Thanks,
Abdel.




------------------------------------------------------------------------

Index: src/insets/insettext.h
===================================================================
--- src/insets/insettext.h      (revision 13351)
+++ src/insets/insettext.h      (working copy)
@@ -16,6 +16,7 @@
 #include "RowList_fwd.h"
 #include "lyxfont.h"
 #include "lyxtext.h"
+#include "ParagraphList_fwd.h"
#include "support/types.h" @@ -27,7 +28,6 @@
 class CursorSlice;
 class Dimension;
 class LColor_color;
-class ParagraphList;
/**
Index: src/insets/insetbibitem.C
===================================================================
--- src/insets/insetbibitem.C   (revision 13351)
+++ src/insets/insetbibitem.C   (working copy)
@@ -19,7 +19,7 @@
 #include "lyxfont.h"
 #include "lyxlex.h"
 #include "paragraph.h"
-#include "ParagraphList_fwd.h"
+#include "ParagraphList.h"
#include "frontends/font_metrics.h" Index: src/output_plaintext.C
===================================================================
--- src/output_plaintext.C      (revision 13351)
+++ src/output_plaintext.C      (working copy)
@@ -19,7 +19,7 @@
 #include "output.h"
 #include "outputparams.h"
 #include "paragraph.h"
-#include "ParagraphList_fwd.h"
+#include "ParagraphList.h"
 #include "ParagraphParameters.h"
#include "support/lstrings.h"
Index: src/output_latex.h
===================================================================
--- src/output_latex.h  (revision 13351)
+++ src/output_latex.h  (working copy)
@@ -12,11 +12,12 @@
 #ifndef OUTPUT_LATEX_H
 #define OUTPUT_LATEX_H
+#include "ParagraphList_fwd.h"
+
 #include <string>
class Buffer;
 class OutputParams;
-class ParagraphList;
 class TexRow;
/// Just a wrapper for the method below, first creating the ofstream.
Index: src/bufferlist.C
===================================================================
--- src/bufferlist.C    (revision 13351)
+++ src/bufferlist.C    (working copy)
@@ -22,7 +22,7 @@
 #include "lyx_main.h"
 #include "output_latex.h"
 #include "paragraph.h"
-#include "ParagraphList_fwd.h"
+#include "ParagraphList.h"
#include "frontends/Alert.h" Index: src/ParagraphList_fwd.h
===================================================================
--- src/ParagraphList_fwd.h     (revision 13351)
+++ src/ParagraphList_fwd.h     (working copy)
@@ -12,22 +12,11 @@
 #ifndef PARAGRAPH_LIST_FWD_H
 #define PARAGRAPH_LIST_FWD_H
-#include "paragraph.h"
+template <class T>
+class RandomAccessList;
-#include <vector>
+class Paragraph;
-class ParagraphList : public std::vector<Paragraph>
-{
-public:
-       ///
-       typedef std::vector<Paragraph> BaseType;
-       ///
-       ParagraphList();
-       ///
-       template <class Iter>
-       ParagraphList(Iter beg, Iter end)
-               : BaseType(beg, end)
-       {}
-};
+typedef RandomAccessList<Paragraph> ParagraphList;
#endif
Index: src/lyxtext.h
===================================================================
--- src/lyxtext.h       (revision 13351)
+++ src/lyxtext.h       (working copy)
@@ -21,7 +21,7 @@
 #include "lyxfont.h"
 #include "layout.h"
 #include "lyxlayout_ptr_fwd.h"
-#include "ParagraphList_fwd.h"
+#include "ParagraphList.h"
#include <iosfwd> Index: src/undo.h
===================================================================
--- src/undo.h  (revision 13351)
+++ src/undo.h  (working copy)
@@ -17,7 +17,7 @@
 #define UNDO_H
#include "dociterator.h"
-#include "ParagraphList_fwd.h"
+#include "ParagraphList.h"
 #include "bufferparams.h"
#include "support/types.h"
Index: src/buffer.h
===================================================================
--- src/buffer.h        (revision 13351)
+++ src/buffer.h        (working copy)
@@ -15,6 +15,7 @@
 #include "InsetList.h"
#include "dociterator.h"
+#include "ParagraphList_fwd.h"
#include "support/limited_stack.h"
 #include "support/types.h"
@@ -42,7 +43,6 @@
 class Language;
 class MacroData;
 class OutputParams;
-class ParagraphList;
 class ParConstIterator;
 class ParIterator;
 class TeXErrors;
Index: src/CutAndPaste.h
===================================================================
--- src/CutAndPaste.h   (revision 13351)
+++ src/CutAndPaste.h   (working copy)
@@ -14,6 +14,8 @@
 #ifndef CUTANDPASTE_H
 #define CUTANDPASTE_H
+#include "ParagraphList_fwd.h"
+
 #include "support/types.h"
#include <string>
@@ -23,7 +25,6 @@
 class ErrorList;
 class LyXTextClass;
 class LCursor;
-class ParagraphList;
///
 namespace lyx {
Index: src/support/RandomAccessList.h
===================================================================
--- src/support/RandomAccessList.h      (revision 0)
+++ src/support/RandomAccessList.h      (revision 0)
@@ -0,0 +1,479 @@
+// -*- C++ -*-
+/**
+ * \file RandomAccessList.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Abdelrazak Younes
+ *
+ * Full author contact details are available in file CREDITS.
+ *
+ */
+
+#ifndef RANDOM_ACESS_LIST_H
+#define RANDOM_ACESS_LIST_H
+
+//#include "debug.h"
+
+#include <boost/utility.hpp>
+
+#include <vector>
+#include <list>
+#include <algorithm>
+
+/// Random Access List.
+/**
+This templatized class provide a std::vector like interface to a
+standard std::list underneath. An important property is that it
+keeps the std::list::iterator interface. A typical use would be:
+
+       typedef RandomAccessList<some_class> MyContainer;
+
+Then you can use MyContainer as if it was a standard +std::vector<some_class> for operator[] access and as if it was a
+standard std::list for iterator access. The main difference with
+std::vector is that insertion of elements is much less costly. Compared
+to a standard list alone, there is of course a small overhead because
+the class always keeps its internal vector of iterator (it_vector_) up
+to date.
+*/
+template <class T>
+class RandomAccessList {
+protected:
+       typedef std::list<T> Container;
+       typedef typename Container::const_iterator BaseConstIt;
+       typedef typename Container::iterator BaseIt;
+public:
+       typedef T value_type;
+       typedef typename Container::difference_type difference_type;
+       typedef size_t size_type;
+
+       ///     
+       class iterator: public Container::iterator {
+       public:
+               iterator()
+               {}
+
+               iterator(BaseIt const & it)
+               {
+                       Container::iterator::operator=(it);
+               }
+               iterator & operator+=(difference_type pos)
+               {
+                       std::advance(*this, pos);
+                       return *this;
+               }
+               iterator operator+(difference_type pos) const
+               {
+                       return boost::next(*this,pos);
+               }
+               difference_type operator-(iterator it2) const
+               {
+                       return std::distance(it2, *this);
+               }
+       };
+
+       ///     
+       class const_iterator: public Container::const_iterator {
+       public:
+               const_iterator()
+               {}
+
+               const_iterator(BaseConstIt const & it)
+               {
+                       Container::const_iterator::operator=(it);
+               }
+               const_iterator(iterator const & it)
+               {
+                       
Container::const_iterator::operator=(static_cast<BaseIt>(it));
+               }
+               const_iterator & operator+=(difference_type pos)
+               {
+                       std::advance(*this, pos);
+                       return *this;
+               }
+               const_iterator operator+(difference_type pos) const
+               {
+                       return boost::next(*this, pos);
+               }
+               difference_type operator-(const_iterator it2) const
+               {
+                       return std::distance(it2, *this);
+               }
+       };
+
+private:
+       /// Our container.
+       Container container_;
+       /// Our vector of container iterators.
+       std::vector<iterator> it_vector_;
+public:
+       ///
+       RandomAccessList()
+       {}
+
+       /// Copy constructor.
+       RandomAccessList(RandomAccessList const & ext_list)
+       {
+               it_vector_.reserve(ext_list.size());
+               size_t const end = ext_list.size();
+               for (size_t i = 0; i != end; ++i)
+                       push_back(ext_list[i]);
+       }
+
+       /// Partial copy constructor.
+       /**
+       Copy "length" elements from ext_list beginning at pos.
+       */
+       RandomAccessList(RandomAccessList const & ext_list,
+                        size_t pos, size_t length)
+       {
+               it_vector_.reserve(length);
+               size_t const end = pos + length;
+               //BOOST_ASSERT(end <= ext_list.size());
+               for (size_t i = pos; i != end; ++i)
+                       push_back(ext_list[i]);
+       }
+
+       /// Construct a new RandomAccessList by copying elements
+       /// pointed from it_start to it_end.
+       template<class It>
+       RandomAccessList(It it_start, It it_end)
+       {
+               for (It it = it_start; it != it_end; ++it)
+                       push_back(*it);
+       }
+
+       ///
+       value_type & operator[](size_t pos)
+       {
+               return at(pos);
+       }
+
+       ///
+       value_type const & operator[](size_t pos) const
+       {
+               return at(pos);
+       }
+
+       ///
+       iterator operator()(size_t pos)
+       {
+               return it_vector_[pos];
+       }
+       
+       ///
+       const_iterator operator()(size_t pos) const
+       {
+               return it_vector_[pos];
+       }
+
+       ///
+       RandomAccessList & operator=(RandomAccessList const & ext_list)
+       {
+               assign(ext_list);
+               return *this;
+       }
+
+       /// Copy ext_list.
+       void assign(RandomAccessList const & ext_list)
+       {
+ assign(ext_list, 0, ext_list.size()); + }
+
+       /// Copy ext_list from it_start to it_end.
+       template<class It>
+       void assign(It it_start, It it_end)
+       {
+               clear();
+               for (It it = it_start; it != it_end; ++it)
+                       push_back(*it);
+       }
+
+       /// Copy "length" elements from ext_list beginning at pos.
+       void assign(RandomAccessList const & ext_list,
+                   size_t pos, size_t length)
+       {
+               clear();
+               size_t const end = pos + length;
+               for (size_t i = pos; i != end; ++i)
+                       push_back(ext_list[i]);
+       }
+
+       value_type & at(size_t pos)
+       {
+               // Make sure it_vector_ and container_ are always in sync.
+               //BOOST_ASSERT(it_vector_[pos] == 
boost::next(container_.begin(),pos));
+               return *it_vector_[pos];
+       }
+
+       /// \todo remove first test (pos >= it_vector_.size()) when output_*.C 
has been verified.
+       value_type const & at(size_t pos) const
+       {
+               // Make sure it_vector_ and container_ are always in sync.
+               //BOOST_ASSERT(it_vector_[pos] == 
boost::next(container_.begin(),pos));
+               return *it_vector_[pos];
+       }
+
+       size_t size() const
+       {
+               return it_vector_.size();
+       }
+
+       const_iterator begin() const
+       {
+               return container_.begin();
+       }
+
+       iterator begin()
+       {
+               return container_.begin();
+       }
+
+       const_iterator end() const
+       {
+               return container_.end();
+       }
+
+       iterator end()
+       {
+               return container_.end();
+       }
+
+       value_type & back()
+       {
+               return container_.back();
+       }
+
+       value_type const & back() const
+       {
+               return container_.back();
+       }
+
+       value_type & front()
+       {
+               return container_.front();
+       }
+
+       value_type const & front() const
+       {
+               return container_.front();
+       }
+
+       bool empty() const
+       {
+               return container_.empty();
+       }
+
+       void clear()
+       {
+               container_.clear();
+               it_vector_.clear();
+       }
+
+       /// Erases 'length' elements starting from pos.
+       /**
+       \todo This could be optimized a bit by rebuilding ItVector instead of 
multiple deletion.
+
+       Comments from Angus: use std::remove_if and vector<>::erase, passing the
+       same predicate to remove_if as is used by erase(size_t);
+       Refactor the other erase() member funtions to use this predicate
+       also?
+       std::remove_if doesn't actually remove anything from the vector. It 
simply rearranges the
+       contents so that the stuff to be removed is all at the end, making it 
trivial
+       (and cheap) to then used "itVector_.erase(it, itVector_.end());" to 
resize the
+       vector. (it here is the iterator returned by std::remove_if). You just 
need to
+       write the predicate that would actually flag up elements for removal.
+       */
+       bool erase(size_t pos, size_t length)
+       {
+               bool result = true;
+               size_t const end = pos + length;
+               for (size_t i = pos; i != end; ++i)
+                       result = result && erase(i);
+               
+               return result;
+       }               
+       
+       /// Erases last element.
+       void pop_back()
+       {
+               //lyxerr[Debug::ACTION] << "pop_back from Container"<< 
std::endl;
+               container_.pop_back();
+               it_vector_.pop_back();
+               //lyxerr[Debug::ACTION] << "pop_back done"<< std::endl;
+       }
+
+       /// Erases the element at position pos.
+       bool erase(size_t pos)
+       {
+               if (pos >= it_vector_.size()) {
+                       //lyxerr[Debug::ACTION] << "trying to erase element at "
+                       //                    << pos << " while size is "
+                       //                    << size() << std::endl;
+                       // What happened here?
+                       return false;
+               }
+               
+               if (pos == it_vector_.size() - 1) {
+                       pop_back();
+                       return true;
+               }
+               
+               //lyxerr[Debug::ACTION] << "erasing element from Container at "
+               //                    << pos << std::endl;
+               container_.erase(it_vector_[pos]);
+               it_vector_.erase(it_vector_.begin() + pos);
+               //lyxerr[Debug::ACTION] << "erasing done"<< std::endl;
+               return true;
+       }
+
+       bool erase(iterator it)
+       {
+               size_t const pos = std::distance(container_.begin(),
+                                                static_cast<BaseIt>(it));
+               return erase(pos);
+       }
+
+       bool erase(iterator start, iterator end)
+       {
+               size_t const startpos = std::distance(container_.begin(),
+                                                     
static_cast<BaseIt>(start));
+               size_t const endpos = std::distance(container_.begin(),
+                                                   static_cast<BaseIt>(end));
+               return erase(startpos, endpos - startpos);
+       }
+
+       void push_back(value_type const & new_element)
+       {
+               //lyxerr[Debug::ACTION] << "push_back new_element in Container"
+               //                    << std::endl;
+               iterator it = container_.insert(container_.end(), new_element);
+               it_vector_.push_back(it);
+               //lyxerr[Debug::ACTION] << "push_back done"<< std::endl;
+       }
+
+       /// Inserts the contents of an external container at position pos.
+       /**
+       The subsequent elements are shifted toward the end.
+
+       \todo This could be optimized a bit by rebuilding ItVector instead of 
multiple insertion.
+       */
+       template<class SomeContainer>
+       bool insert(size_t pos, SomeContainer const & some_container)
+       {
+               bool result = true;
+               size_t i = pos;
+               typedef typename SomeContainer::const_iterator Cit;
+               Cit cit = some_container.begin();
+               Cit cend = some_container.end();
+               for (; cit != cend; ++cit, ++i) {
+                       result = result && insert(i, *cit);
+               }
+               return result;
+       }
+
+       /// Inserts an external RandomAccessList at position pos.
+       /**
+       The subsequent elements are shifted toward the end.
+       
+       \todo This could be optimized a bit by rebuilding ItVector instead of 
multiple insertion
+       and maybe using list::splice.
+       */
+       bool insert(size_t pos, RandomAccessList const & ext_list, size_t 
ext_pos, size_t length)
+       {
+               bool result = true;
+               size_t i = pos;
+               size_t const ext_end = ext_pos + length;
+               for (size_t j = ext_pos; j != ext_end; ++j) {
+                       result = result && insert(i, ext_list[j]);
+                       ++i;
+               }
+               return result;
+       }
+
+       /// Inserts external elements pointed by iterator it_start and it_end 
at position pos.
+       /**
+       The subsequent elements are shifted toward the end.
+       \return the position after the last inserted element.
+
+       \todo This could be optimized a bit by rebuilding ItVector instead of 
multiple insertion
+       and maybe using list::splice.
+       */
+       template<class It>
+       size_t insert(size_t pos, It it_start, It it_end)
+       {
+               bool result = true;
+               size_t i = pos;
+               for (It it = it_start; it != it_end; ++it) {
+                       result = result && insert(i, *it);
+                       ++i;
+               }
+               if (result)
+                       return i;
+
+               return size();
+       }
+
+       /// Inserts external elements pointed by iterator it_start and it_end 
before element pointed by it.
+       /**
+       The subsequent elements are shifted toward the end.
+       \return the iterator after the last inserted element.
+
+       \todo This could be optimized a bit by rebuilding ItVector instead of 
multiple insertion
+       and maybe using list::splice.
+       */
+       template<class It>
+       iterator insert(iterator it, It it_start, It it_end)
+       {
+               size_t pos = std::distance(container_.begin(),
+                                          static_cast<BaseIt>(it));
+               pos = insert(pos, it_start, it_end);
+               if (pos < size())
+                       return it_vector_[pos];
+
+               return container_.end();
+       }
+
+       /// Inserts new_element at position pos.
+       /// The subsequent value_types are shifted toward the end.
+       bool insert(size_t pos, value_type const & new_element)
+       {
+               if (pos > it_vector_.size()) {
+                       //lyxerr[Debug::ACTION] << "trying to insert element at " << pos << " 
while size is "<< size() << std::endl;
+                       // What happened here?
+                       return false;
+               }
+               
+               if (pos == it_vector_.size()) {
+                       push_back(new_element);
+                       return true;
+               }
+
+               //lyxerr[Debug::ACTION]
+               //      << "inserting new_element in Container at "
+               //      << pos << std::endl;
+               iterator it = container_.insert(it_vector_[pos], new_element);
+               it_vector_.insert(it_vector_.begin() + pos, it);
+               //lyxerr[Debug::ACTION] << "insertion done"<< std::endl;
+               return true;
+       }
+
+       /// Inserts new_element before element pointed by iterator it.
+       /**
+       \return The iterator pointing to the newly inserted element
+       or container_.end() if the insertion did not succeed.
+       */
+       iterator insert(iterator it, value_type const & new_element)
+       {
+               size_t const pos = std::distance(container_.begin(),
+                                                static_cast<BaseIt>(it));
+               if (insert(pos, new_element))
+                       return it_vector_[pos];
+       
+               return container_.end();
+       }
+
+}; // RandomAccessList
+
+#endif
Index: src/pariterator.h
===================================================================
--- src/pariterator.h   (revision 13351)
+++ src/pariterator.h   (working copy)
@@ -13,6 +13,7 @@
 #define PARITERATOR_H
#include "dociterator.h"
+#include "ParagraphList_fwd.h"
#include "support/types.h" @@ -24,7 +25,6 @@ class InsetBase;
 class LyXText;
-class ParagraphList;
class ParIterator : public std::iterator<std::forward_iterator_tag, Paragraph>,
Index: src/output_linuxdoc.C
===================================================================
--- src/output_linuxdoc.C       (revision 13351)
+++ src/output_linuxdoc.C       (working copy)
@@ -17,7 +17,7 @@
 #include "bufferparams.h"
 #include "paragraph.h"
 #include "paragraph_funcs.h"
-#include "ParagraphList_fwd.h"
+#include "ParagraphList.h"
 #include "ParagraphParameters.h"
 #include "sgml.h"
Index: src/ParagraphList.h
===================================================================
--- src/ParagraphList.h (revision 0)
+++ src/ParagraphList.h (revision 0)
@@ -0,0 +1,22 @@
+// -*- C++ -*-
+/**
+ * \file ParagraphList_fwd.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Angus Leeming
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef PARAGRAPH_LIST_H
+#define PARAGRAPH_LIST_H
+
+#include "paragraph.h"
+
+#include "support/RandomAccessList.h"
+
+/// Container for all kind of Paragraphs used in Lyx.
+typedef RandomAccessList<Paragraph> ParagraphList;
+
+#endif
Index: src/paragraph_funcs.h
===================================================================
--- src/paragraph_funcs.h       (revision 13351)
+++ src/paragraph_funcs.h       (working copy)
@@ -12,6 +12,8 @@
 #ifndef PARAGRAPH_FUNCS_H
 #define PARAGRAPH_FUNCS_H
+#include "ParagraphList_fwd.h"
+
 #include "support/types.h"
class Buffer;
@@ -19,7 +21,6 @@
 class InsetBase;
 class LyXFont;
 class Paragraph;
-class ParagraphList;
/**
  * This breaks a paragraph at the specified position.
Index: src/output_docbook.C
===================================================================
--- src/output_docbook.C        (revision 13351)
+++ src/output_docbook.C        (working copy)
@@ -20,7 +20,7 @@
 #include "debug.h"
 #include "paragraph.h"
 #include "paragraph_funcs.h"
-#include "ParagraphList_fwd.h"
+#include "ParagraphList.h"
 #include "ParagraphParameters.h"
 #include "sgml.h"
Index: src/output_linuxdoc.h
===================================================================
--- src/output_linuxdoc.h       (revision 13351)
+++ src/output_linuxdoc.h       (working copy)
@@ -13,10 +13,11 @@
 #ifndef OUTPUT_LINUXDOC_H
 #define OUTPUT_LINUXDOC_H
+#include "ParagraphList_fwd.h"
+
 #include <iosfwd>
class Buffer;
-class ParagraphList;
 class OutputParams;
///
Index: src/output_docbook.h
===================================================================
--- src/output_docbook.h        (revision 13351)
+++ src/output_docbook.h        (working copy)
@@ -13,11 +13,12 @@
 #ifndef OUTPUT_DOCBOOK_H
 #define OUTPUT_DOCBOOK_H
+#include "ParagraphList_fwd.h"
+
 #include <iosfwd>
class Buffer;
 class OutputParams;
-class ParagraphList;
///
 void docbookParagraphs(ParagraphList const & subset,
Index: src/paragraph.C
===================================================================
--- src/paragraph.C     (revision 13351)
+++ src/paragraph.C     (working copy)
@@ -66,10 +66,6 @@
 using std::ostringstream;
-ParagraphList::ParagraphList()
-{}
-
-
 Paragraph::Paragraph()
        : begin_of_body_(0), pimpl_(new Paragraph::Pimpl(this))
 {
Index: src/buffer_funcs.C
===================================================================
--- src/buffer_funcs.C  (revision 13351)
+++ src/buffer_funcs.C  (working copy)
@@ -27,7 +27,7 @@
 #include "lyxtextclass.h"
 #include "paragraph.h"
 #include "paragraph_funcs.h"
-#include "ParagraphList_fwd.h"
+#include "ParagraphList.h"
 #include "ParagraphParameters.h"
 #include "pariterator.h"
 #include "lyxvc.h"


------------------------------------------------------------------------



Reply via email to