Speedup the expandLabel by avoiding the recursive part. The labelstrings

are computed recursively to get rid of any \thexxx string by the method
flattenLabelString. The values are cached in Counter objects.

On my mac, the total time (updatelabels+redraw) goes down by 30%. YMMV.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@29342 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Jean-Marc Lasgouttes 2009-04-19 20:05:26 +00:00
parent 1f8e611c03
commit 8d0fcad676
3 changed files with 91 additions and 51 deletions

View File

@ -138,15 +138,23 @@ docstring const & Counter::master() const
}
docstring const & Counter::labelString() const
docstring const & Counter::labelString(bool in_appendix) const
{
return labelstring_;
return in_appendix ? labelstringappendix_ : labelstring_;
}
docstring const & Counter::labelStringAppendix() const
docstring const & Counter::flatLabelString(bool in_appendix) const
{
return labelstringappendix_;
return in_appendix ? flatlabelstringappendix_ : flatlabelstring_;
}
docstring const & Counter::setFlatLabelStrings(docstring const & fls,
docstring const & flsa)
{
flatlabelstring_ = fls;
flatlabelstringappendix_ = flsa;
}
@ -251,8 +259,17 @@ void Counters::reset()
current_float_.erase();
CounterList::iterator it = counterList_.begin();
CounterList::iterator const end = counterList_.end();
std::vector<docstring> callers;
for (; it != end; ++it) {
it->second.reset();
// Compute the explicit counter labels without any
// \thexxx strings, in order to avoid recursion.
// It only needs to be done when the textclass is
// updated, but in practice the extra work is probably
// not noticeable (JMarc)
docstring const fls = flattenLabelString(it->first, false, callers);
docstring const flsa = flattenLabelString(it->first, true, callers);
it->second.setFlatLabelStrings(fls, flsa);
}
}
@ -417,52 +434,68 @@ docstring Counters::labelItem(docstring const & ctr,
docstring Counters::theCounter(docstring const & counter) const
{
std::set<docstring> callers;
return theCounter(counter, callers);
CounterList::const_iterator it = counterList_.find(counter);
if (it == counterList_.end())
return from_ascii("??");
return counterLabel(it->second.flatLabelString(appendix()));
}
docstring Counters::theCounter(docstring const & counter,
std::set<docstring> & callers) const
docstring Counters::flattenLabelString(docstring const & counter, bool in_appendix,
vector<docstring> & callers) const
{
docstring label;
if (callers.find(counter) == callers.end()) {
CounterList::const_iterator it = counterList_.find(counter);
if (it == counterList_.end())
return from_ascii("??");
Counter const & c = it->second;
docstring ls = appendix() ? c.labelStringAppendix() : c.labelString();
if (ls.empty()) {
if (!c.master().empty())
ls = from_ascii("\\the") + c.master() + from_ascii(".");
ls += from_ascii("\\arabic{") + counter + "}";
}
pair<std::set<docstring>::iterator, bool> const result = callers.insert(counter);
label = counterLabel(ls, &callers);
callers.erase(result.first);
} else {
if (find(callers.begin(), callers.end(), counter) != callers.end()) {
// recursion detected
lyxerr << "Warning: Recursion in label for counter `"
<< counter << "' detected"
<< endl;
<< counter << "' detected"
<< endl;
return from_ascii("??");
}
CounterList::const_iterator it = counterList_.find(counter);
if (it == counterList_.end())
return from_ascii("??");
Counter const & c = it->second;
docstring ls = c.labelString(in_appendix);
callers.push_back(counter);
if (ls.empty()) {
if (!c.master().empty())
ls = flattenLabelString(c.master(), in_appendix, callers)
+ from_ascii(".");
callers.pop_back();
return ls + from_ascii("\\arabic{") + counter + "}";
}
return label;
while (true) {
//lyxerr << "ls=" << to_utf8(ls) << endl;
size_t const i = ls.find(from_ascii("\\the"), 0);
if (i == docstring::npos)
break;
size_t const j = i + 4;
size_t k = j;
while (k < ls.size() && lowercase(ls[k]) >= 'a'
&& lowercase(ls[k]) <= 'z')
++k;
docstring const newc = ls.substr(j, k - j);
docstring const repl = flattenLabelString(newc, in_appendix, callers);
ls.replace(i, k - j + 4, repl);
}
callers.pop_back();
return ls;
}
docstring Counters::counterLabel(docstring const & format,
std::set<docstring> * callers) const
docstring Counters::counterLabel(docstring const & format) const
{
docstring label = format;
// FIXME: Using regexps would be better, but we compile boost without
// wide regexps currently.
while (true) {
//lyxerr << "label=" << to_utf8(label) << endl;
size_t const i = label.find(from_ascii("\\the"), 0);
@ -473,12 +506,10 @@ docstring Counters::counterLabel(docstring const & format,
while (k < label.size() && lowercase(label[k]) >= 'a'
&& lowercase(label[k]) <= 'z')
++k;
docstring const counter = label.substr(j, k - j);
docstring const repl = callers? theCounter(counter, *callers):
theCounter(counter);
docstring const newc = label.substr(j, k - j);
docstring const repl = theCounter(newc);
label.replace(i, k - j + 4, repl);
}
while (true) {
//lyxerr << "label=" << to_utf8(label) << endl;

View File

@ -18,7 +18,7 @@
#include "support/docstring.h"
#include <map>
#include <set>
#include <vector>
namespace lyx {
@ -49,14 +49,20 @@ public:
docstring const & master() const;
/// Returns a LaTeX-like string to format the counter.
/** This is similar to what one gets in LaTeX when using
* "\the<counter>".
* "\the<counter>". The \c in_appendix bool tells whether
* we want the version shown in an appendix.
*/
docstring const & labelString() const;
/// Returns a LaTeX-like string to format the counter in appendix.
docstring const & labelString(bool in_appendix) const;
/// Returns a LaTeX-like string to format the counter.
/** This is similar to what one gets in LaTeX when using
* "\the<counter>" in an appendix.
* "\the<counter>". The \c in_appendix bool tells whether
* we want the version shown in an appendix. This version does
* not contain any \\the<counter> expression.
*/
docstring const & labelStringAppendix() const;
docstring const & flatLabelString(bool in_appendix) const;
/// set the \c flatLabelString values.
docstring const & setFlatLabelStrings(docstring const & fls,
docstring const & flsa);
private:
///
int value_;
@ -70,6 +76,10 @@ private:
docstring labelstring_;
/// The same as labelstring_, but in appendices.
docstring labelstringappendix_;
/// A version of the labelstring with \\the<counter> expressions expanded
docstring flatlabelstring_;
/// A version of the appendix labelstring with \\the<counter> expressions expanded
docstring flatlabelstringappendix_;
};
@ -114,9 +124,8 @@ public:
docstring theCounter(docstring const & c) const;
/// Replace in \c format all the LaTeX-like macros that depend on
/// counters.
docstring counterLabel(docstring const & format,
std::set<docstring> * callers = 0) const;
/// Are we in apendix?
docstring counterLabel(docstring const & format) const;
/// Are we in appendix?
bool appendix() const { return appendix_; };
/// Set the state variable indicating whether we are in appendix.
void appendix(bool a) { appendix_ = a; };
@ -129,10 +138,10 @@ public:
/// Set the state variable indicating whether we are in a subfloat.
void isSubfloat(bool s) { subfloat_ = s; };
private:
/// returns the expanded string representation of the counter
/// with recursion protection through callers.
docstring theCounter(docstring const & c,
std::set<docstring> & callers) const;
/// expands recusrsively any \\the<counter> macro in the
/// labelstring of \c counter.
docstring flattenLabelString(docstring const & counter, bool in_appendix,
std::vector<docstring> & callers) const;
/// Returns the value of the counter according to the
/// numbering scheme numbertype.
/** Available numbering schemes are arabic (1, 2,...), roman

View File

@ -1620,7 +1620,7 @@ docstring Paragraph::expandLabel(Layout const & layout,
if (fmt.empty() && layout.labeltype == LABEL_COUNTER
&& !layout.counter.empty())
fmt = "\\the" + layout.counter;
return tclass.counters().theCounter(layout.counter);
// handle 'inherited level parts' in 'fmt',
// i.e. the stuff between '@' in '@Section@.\arabic{subsection}'