Oups I just notice a Cut&Paste problem. The prototype I am proposing is as follow, sorry about that. Optionnally, insert could return a reference or a pointer to the newly inserted paragraph but I think that the get(size_t) function is cleaner.

class ParagraphList
{
public:
        ///     
        typedef std::list<Paragraph>::iterator Pli;       
        typedef std::list<Paragraph>::const_iterator Iter;        

protected:
        typedef std::vector<Pli>::iterator Iter;
        list<Paragraph> ParList_;
        vector<Pli> PliVector_;

public:
        ///
        ParagraphList()
        {
                // Reserve Memory for 100000 iterators
                // which would represent 1000000 paragraph
                // I guess this is enough?
                PliVector_.reserve(100000);
        }

        Paragrah& get(size_t pos)
        {
                BOOST_ASSERT(pos < PliVector_.size())
                return *PliVector_[pos];
        }

        /// Erases the paragraph at position pos.
        bool erase(size_t pos)
        {
                if (pos >= PliVector_.size())
                {
                        // What happened here?
                        return false
                }

                size_t new_size=PliVector_.size()-1;
                PliVector.resize(new_size);

                if (pos == PliVector_.size())
                {
                        PliVector[pos] = ParList_.pop_back(Par);
                }
                else
                {
                        ParList_.erase(PliVector_[pos]);
                }

                // Warning: I think Vector resize does not keep data
                // in this case. So it is safer to update the vector
                // entirely
                Pli pli = ParList_.begin();
                for (size_t i=0; i<new_size; ++i)
                {
                        PliVector[i]=pli
                        ++pli;
                }
                return true;
        }

        /// Inserts the paragraph par at position pos.
        /// The subsequent paragraph are shifted toward the end.
        bool insert(size_t pos, const Paragraph& par)
        {               
                if (pos > PliVector_.size())
                {
                        // What happened here?
                        return false;
                }

                size_t new_size=PliVector_.size()+1;
                PliVector.resize(new_size);
                if (pos == PliVector_.size())
                {
                        PliVector[pos] = ParList_.push_back(Par);
                }
                else
                {
                        Pli pli = ParList_.insert(PliVector_[pos], Par);
                        for (size_t i=pos; i<new_sizepli; ++i)
                        {
                                PliVector[i]=pli
                                        ++pli;
                        }
                }
                return true;
        }
};

Abdel a écrit :
Martin Vermeer a écrit :
On Tue, Jan 03, 2006 at 07:52:13PM +0100, Abdel wrote:
Hello,

On windows with 1.4.0cvs on for big documents (ex: Extended.lyx), there is a big delay (~1s) before a "Carriage Return" is shown on screen after typing the "enter" key in the middle of a paragraph. The same will happen when you type "Backspace" at the beginning of a paragraph. On the contrary, if you type Ctrl-Z immediately after, the screen update is instantaneous.

For both keys, 1.3.7pre is very quick.

I am trying to investigate if I could speed-up this a bit because this is very, very irritating. I found that the big delay is in "LyXText::breakParagraph" and more precisely in "::breakParagraph", paragraph_funcs.C:97. The time consuming operation is the insertion of a new paragraph inside the ParagraphList which is in fact a std::vector :

    ParagraphList::iterator tmp =
        pars.insert(pars.begin() + par_offset + 1, Paragraph());

I have compiled this file with -O3 but the slowness is still there. Indeed insertion inside a vector is known to be inefficient. I have read the history about ParagraphList_fwd.h (http://www.lyx.org/cgi-bin/viewcvs.cgi/lyx-devel/src/ParagraphList_fwd.h) and I guess there might be some valid reason to choose a vector instead of a list but performance wise, it shows, definitely. I have tried to replace with a list but this won't compile because some source needs the [] operator. I have also tried a deque and the results are a bit better. The weird thing is that the slowness is not at the same place. Indeed, within a "Standard" environment, the paragraph insertion at the beginning seems to be very fast but the following operation is slowing things down:

        for (pos_type i = pos_end; i >= pos; --i)
            par.eraseIntern(i);

Within a "List" environment, the behavior is the same as with a vector based class: the slowness is in the paragraph insertion at the beginning.

But I don't know if this is safe, so my question is: is there any assumption in the code that the ParagraphList use a contiguous memory? Deque does not... But "Extended.lyx" loads fine and all seems correct (math, table, etc...).

There is a pending patch which could use the <vector> property... or
not (bug 2015) ;-)

From what I see it uses size() and operator[] so deque would be fine here also. But maybe rewriting this patch to use ParagraphList::iterator and algorithm::find would be better, wouldn't it? This way we won't rely on vector property.


I think a better solution would be to use a map or maybe a vector of pointer. Like it is now, IMHO, lyx-1.4 is close to unusable under window. Is there some unofficial patch that would speed up things a bit?

Andre had something that IIRC would replace the official insert() by a
homegrown one, presumably faster. (What's the status of that?)

I think it is possible to rewrite the ParagraphList class that would not need the removal of the official insert(), only a cosmetic change. IMHO, a good solution would be to use a list<Paragraph> member to store the paragraphs and a vector<list<Paragraph>::iterator> for the interface. This way ParagraphList::insert would call list::insert and then update the vector or list iterator. I believe this would imply minimal change to the code using ParagraphList; we would just need to replace "insert(XXX.begin()+pos, Par)" with "insert(pos, Par)". Here is a class prototype (not tested):

class ParagraphList
{
public:
    ///
    typedef std::vector <Paragraph*> BaseType;
    typedef std::vector <Paragraph*>::iterator Iter;
    typedef std::vector <Paragraph*>::const_iterator ConstIter;
typedef std::list<Paragraph>::iterator Pli; typedef std::list<Paragraph>::const_iterator Iter;
protected:
    typedef std::vector<Pli>::iterator Iter;
    list<Paragraph> ParList_;
    vector<Pli> PliVector_;

public:
    ///
    ParagraphList()
    {
        // Reserve Memory for 100000 iterators
        // which would represent 1000000 paragraph
        // I guess this is enough?
        PliVector_.reserve(100000);
    }

    Paragrah& get(size_t pos)
    {
        BOOST_ASSERT(pos < PliVector_.size())
        return *PliVector_[pos];
    }

    /// Erases the paragraph at position pos.
    bool erase(size_t pos)
    {
        if (pos >= PliVector_.size())
        {
            // What happened here?
            return false
        }

        size_t new_size=PliVector_.size()-1;
        PliVector.resize(new_size);

        if (pos == PliVector_.size())
        {
            PliVector[pos] = ParList_.pop_back(Par);
        }
        else
        {
            ParList_.erase(PliVector_[pos]);
        }

        // Warning: I think Vector resize does not keep data
        // in this case. So it is safer to update the vector
        // entirely
        Pli pli = ParList_.begin();
        for (size_t i=0; i<new_size; ++i)
        {
            PliVector[i]=pli
            ++pli;
        }
        return true;
    }
};

What do think?
Abdel.


Thanks,
Abdel.

- Martin



Reply via email to