From 605f8020b7d7e96befd3884c51f842ecf90faffc Mon Sep 17 00:00:00 2001 From: Wilhelm Schuermann Date: Tue, 15 Sep 2015 18:14:18 +0200 Subject: [PATCH] Nibbler: Improve import performance Takes the "import" performance test from 5m5s on a test machine to 13s total. A huge part of the previously morbid performance were memory allocation and release for very little benefit in the JSON parser. With this new approach the copying is kept to a minimum. There is still room for improvements. --- src/Nibbler.cpp | 320 ++++++++++++++++++++++++------------------------ src/Nibbler.h | 3 +- 2 files changed, 162 insertions(+), 161 deletions(-) diff --git a/src/Nibbler.cpp b/src/Nibbler.cpp index d94a83425..b2d020f28 100644 --- a/src/Nibbler.cpp +++ b/src/Nibbler.cpp @@ -39,14 +39,14 @@ #endif #include #include +#include static const char* _uuid_pattern = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; static const unsigned int _uuid_min_length = 8; //////////////////////////////////////////////////////////////////////////////// Nibbler::Nibbler () -: _input ("") -, _length (0) +: _length (0) , _cursor (0) , _saved (0) { @@ -54,7 +54,7 @@ Nibbler::Nibbler () //////////////////////////////////////////////////////////////////////////////// Nibbler::Nibbler (const std::string& input) -: _input (input) +: _input (std::make_shared (input)) , _length (input.length ()) , _cursor (0) { @@ -92,15 +92,15 @@ bool Nibbler::getUntil (char c, std::string& result) { if (_cursor < _length) { - auto i = _input.find (c, _cursor); + auto i = _input->find (c, _cursor); if (i != std::string::npos) { - result = _input.substr (_cursor, i - _cursor); + result = _input->substr (_cursor, i - _cursor); _cursor = i; } else { - result = _input.substr (_cursor); + result = _input->substr (_cursor); _cursor = _length; } @@ -115,15 +115,15 @@ bool Nibbler::getUntil (const std::string& terminator, std::string& result) { if (_cursor < _length) { - auto i = _input.find (terminator, _cursor); + auto i = _input->find (terminator, _cursor); if (i != std::string::npos) { - result = _input.substr (_cursor, i - _cursor); + result = _input->substr (_cursor, i - _cursor); _cursor = i; } else { - result = _input.substr (_cursor); + result = _input->substr (_cursor); _cursor = _length; } @@ -142,14 +142,14 @@ bool Nibbler::getUntilRx (const std::string& regex, std::string& result) RX r (regex, true); std::vector start; std::vector end; - if (r.match (start, end, _input.substr (_cursor))) + if (r.match (start, end, _input->substr (_cursor))) { - result = _input.substr (_cursor, start[0]); + result = _input->substr (_cursor, start[0]); _cursor += start[0]; } else { - result = _input.substr (_cursor); + result = _input->substr (_cursor); _cursor = _length; } @@ -165,15 +165,15 @@ bool Nibbler::getUntilOneOf (const std::string& chars, std::string& result) { if (_cursor < _length) { - auto i = _input.find_first_of (chars, _cursor); + auto i = _input->find_first_of (chars, _cursor); if (i != std::string::npos) { - result = _input.substr (_cursor, i - _cursor); + result = _input->substr (_cursor, i - _cursor); _cursor = i; } else { - result = _input.substr (_cursor); + result = _input->substr (_cursor); _cursor = _length; } @@ -200,7 +200,7 @@ bool Nibbler::getUntilEOS (std::string& result) { if (_cursor < _length) { - result = _input.substr (_cursor); + result = _input->substr (_cursor); _cursor = _length; return true; } @@ -213,7 +213,7 @@ bool Nibbler::getN (const int quantity, std::string& result) { if (_cursor + quantity <= _length) { - result = _input.substr (_cursor, quantity); + result = _input->substr (_cursor, quantity); _cursor += quantity; return true; } @@ -234,14 +234,14 @@ bool Nibbler::getQuoted ( result = ""; if (_cursor >= _length || - _input[_cursor] != c) + (*_input)[_cursor] != c) { return false; } for (auto i = _cursor; i < _length; ++i) { - current = _input[i]; + current = (*_input)[i]; if (current == '\\' && !inescape) { @@ -285,9 +285,9 @@ bool Nibbler::getQuoted ( bool Nibbler::getDigit (int& result) { if (_cursor < _length && - Lexer::isDigit (_input[_cursor])) + Lexer::isDigit ((*_input)[_cursor])) { - result = _input[_cursor++] - '0'; + result = (*_input)[_cursor++] - '0'; return true; } @@ -301,14 +301,14 @@ bool Nibbler::getDigit6 (int& result) if (i < _length && _length - i >= 6) { - if (Lexer::isDigit (_input[i + 0]) && - Lexer::isDigit (_input[i + 1]) && - Lexer::isDigit (_input[i + 2]) && - Lexer::isDigit (_input[i + 3]) && - Lexer::isDigit (_input[i + 4]) && - Lexer::isDigit (_input[i + 5])) + if (Lexer::isDigit ((*_input)[i + 0]) && + Lexer::isDigit ((*_input)[i + 1]) && + Lexer::isDigit ((*_input)[i + 2]) && + Lexer::isDigit ((*_input)[i + 3]) && + Lexer::isDigit ((*_input)[i + 4]) && + Lexer::isDigit ((*_input)[i + 5])) { - result = strtoimax (_input.substr (_cursor, 6).c_str (), NULL, 10); + result = strtoimax (_input->substr (_cursor, 6).c_str (), NULL, 10); _cursor += 6; return true; } @@ -324,12 +324,12 @@ bool Nibbler::getDigit4 (int& result) if (i < _length && _length - i >= 4) { - if (Lexer::isDigit (_input[i + 0]) && - Lexer::isDigit (_input[i + 1]) && - Lexer::isDigit (_input[i + 2]) && - Lexer::isDigit (_input[i + 3])) + if (Lexer::isDigit ((*_input)[i + 0]) && + Lexer::isDigit ((*_input)[i + 1]) && + Lexer::isDigit ((*_input)[i + 2]) && + Lexer::isDigit ((*_input)[i + 3])) { - result = strtoimax (_input.substr (_cursor, 4).c_str (), NULL, 10); + result = strtoimax (_input->substr (_cursor, 4).c_str (), NULL, 10); _cursor += 4; return true; } @@ -345,11 +345,11 @@ bool Nibbler::getDigit3 (int& result) if (i < _length && _length - i >= 3) { - if (Lexer::isDigit (_input[i + 0]) && - Lexer::isDigit (_input[i + 1]) && - Lexer::isDigit (_input[i + 2])) + if (Lexer::isDigit ((*_input)[i + 0]) && + Lexer::isDigit ((*_input)[i + 1]) && + Lexer::isDigit ((*_input)[i + 2])) { - result = strtoimax (_input.substr (_cursor, 3).c_str (), NULL, 10); + result = strtoimax (_input->substr (_cursor, 3).c_str (), NULL, 10); _cursor += 3; return true; } @@ -365,10 +365,10 @@ bool Nibbler::getDigit2 (int& result) if (i < _length && _length - i >= 2) { - if (Lexer::isDigit (_input[i + 0]) && - Lexer::isDigit (_input[i + 1])) + if (Lexer::isDigit ((*_input)[i + 0]) && + Lexer::isDigit ((*_input)[i + 1])) { - result = strtoimax (_input.substr (_cursor, 2).c_str (), NULL, 10); + result = strtoimax (_input->substr (_cursor, 2).c_str (), NULL, 10); _cursor += 2; return true; } @@ -384,19 +384,19 @@ bool Nibbler::getInt (int& result) if (i < _length) { - if (_input[i] == '-') + if ((*_input)[i] == '-') ++i; - else if (_input[i] == '+') + else if ((*_input)[i] == '+') ++i; } // TODO Potential for use of find_first_not_of - while (i < _length && Lexer::isDigit (_input[i])) + while (i < _length && Lexer::isDigit ((*_input)[i])) ++i; if (i > _cursor) { - result = strtoimax (_input.substr (_cursor, i - _cursor).c_str (), NULL, 10); + result = strtoimax (_input->substr (_cursor, i - _cursor).c_str (), NULL, 10); _cursor = i; return true; } @@ -409,12 +409,12 @@ bool Nibbler::getUnsignedInt (int& result) { auto i = _cursor; // TODO Potential for use of find_first_not_of - while (i < _length && Lexer::isDigit (_input[i])) + while (i < _length && Lexer::isDigit ((*_input)[i])) ++i; if (i > _cursor) { - result = strtoimax (_input.substr (_cursor, i - _cursor).c_str (), NULL, 10); + result = strtoimax (_input->substr (_cursor, i - _cursor).c_str (), NULL, 10); _cursor = i; return true; } @@ -443,42 +443,42 @@ bool Nibbler::getNumber (std::string& result) auto i = _cursor; // [+-]? - if (i < _length && (_input[i] == '-' || _input[i] == '+')) + if (i < _length && ((*_input)[i] == '-' || (*_input)[i] == '+')) ++i; // digit+ - if (i < _length && Lexer::isDigit (_input[i])) + if (i < _length && Lexer::isDigit ((*_input)[i])) { ++i; - while (i < _length && Lexer::isDigit (_input[i])) + while (i < _length && Lexer::isDigit ((*_input)[i])) ++i; // ( . digit+ )? - if (i < _length && _input[i] == '.') + if (i < _length && (*_input)[i] == '.') { ++i; - while (i < _length && Lexer::isDigit (_input[i])) + while (i < _length && Lexer::isDigit ((*_input)[i])) ++i; } // ( [eE] [+-]? digit+ )? - if (i < _length && (_input[i] == 'e' || _input[i] == 'E')) + if (i < _length && ((*_input)[i] == 'e' || (*_input)[i] == 'E')) { ++i; - if (i < _length && (_input[i] == '+' || _input[i] == '-')) + if (i < _length && ((*_input)[i] == '+' || (*_input)[i] == '-')) ++i; - if (i < _length && Lexer::isDigit (_input[i])) + if (i < _length && Lexer::isDigit ((*_input)[i])) { ++i; - while (i < _length && Lexer::isDigit (_input[i])) + while (i < _length && Lexer::isDigit ((*_input)[i])) ++i; - result = _input.substr (_cursor, i - _cursor); + result = _input->substr (_cursor, i - _cursor); _cursor = i; return true; } @@ -486,7 +486,7 @@ bool Nibbler::getNumber (std::string& result) return false; } - result = _input.substr (_cursor, i - _cursor); + result = _input->substr (_cursor, i - _cursor); _cursor = i; return true; } @@ -512,7 +512,7 @@ bool Nibbler::getNumber (double &result) bool Nibbler::getLiteral (const std::string& literal) { if (_cursor < _length && - _input.find (literal, _cursor) == _cursor) + _input->find (literal, _cursor) == _cursor) { _cursor += literal.length (); return true; @@ -537,7 +537,7 @@ bool Nibbler::getRx (const std::string& regex, std::string& result) RX r (modified_regex, true); std::vector results; - if (r.match (results, _input.substr (_cursor))) + if (r.match (results, _input->substr (_cursor))) { result = results[0]; _cursor += result.length (); @@ -558,44 +558,44 @@ bool Nibbler::getUUID (std::string& result) _length - i >= 36) { // 88888888-4444-4444-4444-cccccccccccc - if (isxdigit (_input[i + 0]) && - isxdigit (_input[i + 1]) && - isxdigit (_input[i + 2]) && - isxdigit (_input[i + 3]) && - isxdigit (_input[i + 4]) && - isxdigit (_input[i + 5]) && - isxdigit (_input[i + 6]) && - isxdigit (_input[i + 7]) && - _input[i + 8] == '-' && - isxdigit (_input[i + 9]) && - isxdigit (_input[i + 10]) && - isxdigit (_input[i + 11]) && - isxdigit (_input[i + 12]) && - _input[i + 13] == '-' && - isxdigit (_input[i + 14]) && - isxdigit (_input[i + 15]) && - isxdigit (_input[i + 16]) && - isxdigit (_input[i + 17]) && - _input[i + 18] == '-' && - isxdigit (_input[i + 19]) && - isxdigit (_input[i + 20]) && - isxdigit (_input[i + 21]) && - isxdigit (_input[i + 22]) && - _input[i + 23] == '-' && - isxdigit (_input[i + 24]) && - isxdigit (_input[i + 25]) && - isxdigit (_input[i + 26]) && - isxdigit (_input[i + 27]) && - isxdigit (_input[i + 28]) && - isxdigit (_input[i + 29]) && - isxdigit (_input[i + 30]) && - isxdigit (_input[i + 31]) && - isxdigit (_input[i + 32]) && - isxdigit (_input[i + 33]) && - isxdigit (_input[i + 34]) && - isxdigit (_input[i + 35])) + if (isxdigit ((*_input)[i + 0]) && + isxdigit ((*_input)[i + 1]) && + isxdigit ((*_input)[i + 2]) && + isxdigit ((*_input)[i + 3]) && + isxdigit ((*_input)[i + 4]) && + isxdigit ((*_input)[i + 5]) && + isxdigit ((*_input)[i + 6]) && + isxdigit ((*_input)[i + 7]) && + (*_input)[i + 8] == '-' && + isxdigit ((*_input)[i + 9]) && + isxdigit ((*_input)[i + 10]) && + isxdigit ((*_input)[i + 11]) && + isxdigit ((*_input)[i + 12]) && + (*_input)[i + 13] == '-' && + isxdigit ((*_input)[i + 14]) && + isxdigit ((*_input)[i + 15]) && + isxdigit ((*_input)[i + 16]) && + isxdigit ((*_input)[i + 17]) && + (*_input)[i + 18] == '-' && + isxdigit ((*_input)[i + 19]) && + isxdigit ((*_input)[i + 20]) && + isxdigit ((*_input)[i + 21]) && + isxdigit ((*_input)[i + 22]) && + (*_input)[i + 23] == '-' && + isxdigit ((*_input)[i + 24]) && + isxdigit ((*_input)[i + 25]) && + isxdigit ((*_input)[i + 26]) && + isxdigit ((*_input)[i + 27]) && + isxdigit ((*_input)[i + 28]) && + isxdigit ((*_input)[i + 29]) && + isxdigit ((*_input)[i + 30]) && + isxdigit ((*_input)[i + 31]) && + isxdigit ((*_input)[i + 32]) && + isxdigit ((*_input)[i + 33]) && + isxdigit ((*_input)[i + 34]) && + isxdigit ((*_input)[i + 35])) { - result = _input.substr (_cursor, 36); + result = _input->substr (_cursor, 36); _cursor = i + 36; return true; } @@ -610,10 +610,10 @@ bool Nibbler::getPartialUUID (std::string& result) std::string::size_type i; for (i = 0; i < 36 && i < (_length - _cursor); i++) { - if (_uuid_pattern[i] == 'x' && !isxdigit (_input[_cursor + i])) + if (_uuid_pattern[i] == 'x' && !isxdigit ((*_input)[_cursor + i])) break; - else if (_uuid_pattern[i] == '-' && _input[_cursor + i] != '-') + else if (_uuid_pattern[i] == '-' && (*_input)[_cursor + i] != '-') break; } @@ -622,10 +622,10 @@ bool Nibbler::getPartialUUID (std::string& result) { // Fail if there is another hex digit. if (_cursor + i < _length && - isxdigit (_input[_cursor + i])) + isxdigit ((*_input)[_cursor + i])) return false; - result = _input.substr (_cursor, i); + result = _input->substr (_cursor, i); _cursor += i; return true; @@ -643,44 +643,44 @@ bool Nibbler::getDateISO (time_t& t) if (i < _length && _length - i >= 16) { - if (Lexer::isDigit (_input[i + 0]) && - Lexer::isDigit (_input[i + 1]) && - Lexer::isDigit (_input[i + 2]) && - Lexer::isDigit (_input[i + 3]) && - Lexer::isDigit (_input[i + 4]) && - Lexer::isDigit (_input[i + 5]) && - Lexer::isDigit (_input[i + 6]) && - Lexer::isDigit (_input[i + 7]) && - _input[i + 8] == 'T' && - Lexer::isDigit (_input[i + 9]) && - Lexer::isDigit (_input[i + 10]) && - Lexer::isDigit (_input[i + 11]) && - Lexer::isDigit (_input[i + 12]) && - Lexer::isDigit (_input[i + 13]) && - Lexer::isDigit (_input[i + 14]) && - _input[i + 15] == 'Z') + if (Lexer::isDigit ((*_input)[i + 0]) && + Lexer::isDigit ((*_input)[i + 1]) && + Lexer::isDigit ((*_input)[i + 2]) && + Lexer::isDigit ((*_input)[i + 3]) && + Lexer::isDigit ((*_input)[i + 4]) && + Lexer::isDigit ((*_input)[i + 5]) && + Lexer::isDigit ((*_input)[i + 6]) && + Lexer::isDigit ((*_input)[i + 7]) && + (*_input)[i + 8] == 'T' && + Lexer::isDigit ((*_input)[i + 9]) && + Lexer::isDigit ((*_input)[i + 10]) && + Lexer::isDigit ((*_input)[i + 11]) && + Lexer::isDigit ((*_input)[i + 12]) && + Lexer::isDigit ((*_input)[i + 13]) && + Lexer::isDigit ((*_input)[i + 14]) && + (*_input)[i + 15] == 'Z') { _cursor += 16; - int year = (_input[i + 0] - '0') * 1000 - + (_input[i + 1] - '0') * 100 - + (_input[i + 2] - '0') * 10 - + (_input[i + 3] - '0'); + int year = ((*_input)[i + 0] - '0') * 1000 + + ((*_input)[i + 1] - '0') * 100 + + ((*_input)[i + 2] - '0') * 10 + + ((*_input)[i + 3] - '0'); - int month = (_input[i + 4] - '0') * 10 - + (_input[i + 5] - '0'); + int month = ((*_input)[i + 4] - '0') * 10 + + ((*_input)[i + 5] - '0'); - int day = (_input[i + 6] - '0') * 10 - + (_input[i + 7] - '0'); + int day = ((*_input)[i + 6] - '0') * 10 + + ((*_input)[i + 7] - '0'); - int hour = (_input[i + 9] - '0') * 10 - + (_input[i + 10] - '0'); + int hour = ((*_input)[i + 9] - '0') * 10 + + ((*_input)[i + 10] - '0'); - int minute = (_input[i + 11] - '0') * 10 - + (_input[i + 12] - '0'); + int minute = ((*_input)[i + 11] - '0') * 10 + + ((*_input)[i + 12] - '0'); - int second = (_input[i + 13] - '0') * 10 - + (_input[i + 14] - '0'); + int second = ((*_input)[i + 13] - '0') * 10 + + ((*_input)[i + 14] - '0'); // Convert to epoch. struct tm tms = {0}; @@ -723,15 +723,15 @@ bool Nibbler::parseDigits(std::string::size_type& i, // Check that 'f' of them are digits unsigned int g; for (g = 0; g < f; g++) - if (! Lexer::isDigit (_input[i + g])) + if (! Lexer::isDigit ((*_input)[i + g])) break; // Parse the integer when it is the case if (g == f) { if (f == 1) - result = _input[i] - '0'; + result = (*_input)[i] - '0'; else - result = atoi (_input.substr (i, f).c_str ()); + result = atoi (_input->substr (i, f).c_str ()); // Update the global cursor before returning i += f; return true; @@ -814,11 +814,11 @@ bool Nibbler::getDate (const std::string& format, time_t& t) case 'a': case 'A': if (i + 3 <= _length && - ! Lexer::isDigit (_input[i + 0]) && - ! Lexer::isDigit (_input[i + 1]) && - ! Lexer::isDigit (_input[i + 2])) + ! Lexer::isDigit ((*_input)[i + 0]) && + ! Lexer::isDigit ((*_input)[i + 1]) && + ! Lexer::isDigit ((*_input)[i + 2])) { - wday = Date::dayOfWeek (_input.substr (i, 3).c_str ()); + wday = Date::dayOfWeek (_input->substr (i, 3).c_str ()); i += (format[f] == 'a') ? 3 : Date::dayName (wday).size (); } else @@ -828,13 +828,13 @@ bool Nibbler::getDate (const std::string& format, time_t& t) case 'b': case 'B': if (i + 3 <= _length && - ! Lexer::isDigit (_input[i + 0]) && - ! Lexer::isDigit (_input[i + 1]) && - ! Lexer::isDigit (_input[i + 2])) + ! Lexer::isDigit ((*_input)[i + 0]) && + ! Lexer::isDigit ((*_input)[i + 1]) && + ! Lexer::isDigit ((*_input)[i + 2])) { if (month != -1) return false; - month = Date::monthOfYear (_input.substr (i, 3).c_str()); + month = Date::monthOfYear (_input->substr (i, 3).c_str()); i += (format[f] == 'b') ? 3 : Date::monthName (month).size (); } else @@ -843,7 +843,7 @@ bool Nibbler::getDate (const std::string& format, time_t& t) default: if (i + 1 <= _length && - _input[i] == format[f]) + (*_input)[i] == format[f]) ++i; else return false; @@ -935,14 +935,14 @@ bool Nibbler::getName (std::string& result) if (i < _length) { - if (! Lexer::isDigit (_input[i]) && - ! ispunct (_input[i]) && - ! Lexer::isWhitespace (_input[i])) + if (! Lexer::isDigit ((*_input)[i]) && + ! ispunct ((*_input)[i]) && + ! Lexer::isWhitespace ((*_input)[i])) { ++i; while (i < _length && - (_input[i] == '_' || ! ispunct (_input[i])) && - ! Lexer::isWhitespace (_input[i])) + ((*_input)[i] == '_' || ! ispunct ((*_input)[i])) && + ! Lexer::isWhitespace ((*_input)[i])) { ++i; } @@ -950,7 +950,7 @@ bool Nibbler::getName (std::string& result) if (i > _cursor) { - result = _input.substr (_cursor, i - _cursor); + result = _input->substr (_cursor, i - _cursor); _cursor = i; return true; } @@ -967,16 +967,16 @@ bool Nibbler::getWord (std::string& result) if (i < _length) { - while (!Lexer::isDigit (_input[i]) && - !Lexer::isPunctuation (_input[i]) && - !Lexer::isWhitespace (_input[i])) + while (!Lexer::isDigit ((*_input)[i]) && + !Lexer::isPunctuation ((*_input)[i]) && + !Lexer::isWhitespace ((*_input)[i])) { ++i; } if (i > _cursor) { - result = _input.substr (_cursor, i - _cursor); + result = _input->substr (_cursor, i - _cursor); _cursor = i; return true; } @@ -1002,7 +1002,7 @@ bool Nibbler::skipN (const int quantity /* = 1 */) bool Nibbler::skip (char c) { if (_cursor < _length && - _input[_cursor] == c) + (*_input)[_cursor] == c) { ++_cursor; return true; @@ -1016,7 +1016,7 @@ bool Nibbler::skipAll (char c) { if (_cursor < _length) { - auto i = _input.find_first_not_of (c, _cursor); + auto i = _input->find_first_not_of (c, _cursor); if (i == _cursor) return false; @@ -1053,7 +1053,7 @@ bool Nibbler::skipRx (const std::string& regex) RX r (modified_regex, true); std::vector results; - if (r.match (results, _input.substr (_cursor))) + if (r.match (results, _input->substr (_cursor))) { _cursor += results[0].length (); return true; @@ -1081,7 +1081,7 @@ bool Nibbler::skipAllOneOf (const std::string& chars) { if (_cursor < _length) { - auto i = _input.find_first_not_of (chars, _cursor); + auto i = _input->find_first_not_of (chars, _cursor); if (i == _cursor) return false; @@ -1101,7 +1101,7 @@ bool Nibbler::skipAllOneOf (const std::string& chars) char Nibbler::next () { if (_cursor < _length) - return _input[_cursor]; + return (*_input)[_cursor]; return '\0'; } @@ -1119,7 +1119,7 @@ std::string Nibbler::next (const int quantity) if ( _cursor < _length && (unsigned) quantity <= _length && _cursor <= _length - quantity) - return _input.substr (_cursor, quantity); + return _input->substr (_cursor, quantity); return ""; } @@ -1139,7 +1139,7 @@ std::string::size_type Nibbler::restore () //////////////////////////////////////////////////////////////////////////////// const std::string& Nibbler::str () const { - return _input; + return *_input; } //////////////////////////////////////////////////////////////////////////////// @@ -1155,7 +1155,7 @@ bool Nibbler::depleted () std::string Nibbler::dump () { return std::string ("Nibbler ‹") - + _input.substr (_cursor) + + _input->substr (_cursor) + "›"; } diff --git a/src/Nibbler.h b/src/Nibbler.h index f674a5b2d..1fda8ac76 100644 --- a/src/Nibbler.h +++ b/src/Nibbler.h @@ -36,6 +36,7 @@ #include #include #include +#include class Nibbler { @@ -110,7 +111,7 @@ public: std::string dump (); private: - std::string _input; + std::shared_ptr _input; std::string::size_type _length; std::string::size_type _cursor; std::string::size_type _saved;