mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Nibbler: Improve getQuoted() performance
Improves "load" time for all performance tests that load data by ~20%. - "next" down 15% total - "list" down 7% total - "all" down 3% total - "add" down 15% total - "export" down 8% total - "import" down 6% total
This commit is contained in:
parent
96ca7eb5f2
commit
77283241a9
1 changed files with 37 additions and 28 deletions
|
@ -180,12 +180,11 @@ bool Nibbler::getN (const int quantity, std::string& result)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Gets quote content: "foobar" -> foobar (for c = '"')
|
||||
// Handles escaped quotes: "foo\"bar" -> foo\"bar (for c = '"')
|
||||
// Returns false if first character is not c, or if there is no closing c
|
||||
bool Nibbler::getQuoted (char c, std::string& result)
|
||||
{
|
||||
bool inquote = false;
|
||||
bool inescape = false;
|
||||
char previous = 0;
|
||||
char current = 0;
|
||||
result = "";
|
||||
|
||||
if (_cursor >= _length ||
|
||||
|
@ -194,42 +193,52 @@ bool Nibbler::getQuoted (char c, std::string& result)
|
|||
return false;
|
||||
}
|
||||
|
||||
for (auto i = _cursor; i < _length; ++i)
|
||||
std::string::size_type start = _cursor + 1; // Skip first quote char
|
||||
std::string::size_type i = start;
|
||||
|
||||
while (i < _length)
|
||||
{
|
||||
current = (*_input)[i];
|
||||
i = (*_input).find (c, i);
|
||||
|
||||
if (current == '\\' && !inescape)
|
||||
if (i == std::string::npos)
|
||||
return false; // Unclosed quote
|
||||
|
||||
if (i == start)
|
||||
{
|
||||
inescape = true;
|
||||
previous = current;
|
||||
continue;
|
||||
// Empty quote
|
||||
_cursor += 2; // Skip both quote chars
|
||||
return true;
|
||||
}
|
||||
|
||||
if (current == c && !inescape)
|
||||
if ((*_input)[i-1] == '\\')
|
||||
{
|
||||
if (!inquote)
|
||||
// Check for escaped backslashes. Backtracking like this is not very
|
||||
// efficient, but is only done in extreme corner cases.
|
||||
|
||||
auto j = i-2; // Start one character further left
|
||||
bool is_escaped_quote = true;
|
||||
while (j >= start && (*_input)[j] == '\\')
|
||||
{
|
||||
inquote = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cursor = i + 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (previous)
|
||||
{
|
||||
result += previous;
|
||||
previous = 0;
|
||||
// Toggle flag for each further backslash encountered.
|
||||
is_escaped_quote = is_escaped_quote ? false : true;
|
||||
--j;
|
||||
}
|
||||
|
||||
result += current;
|
||||
inescape = false;
|
||||
if (is_escaped_quote)
|
||||
{
|
||||
// Keep searching
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// None of the above applied, we must have found the closing quote char.
|
||||
result.assign ((*_input), start, i - start);
|
||||
_cursor = i + 1; // Skip closing quote char
|
||||
return true;
|
||||
}
|
||||
|
||||
// This should never be reached. We could throw here instead.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue