diff --git a/src/buffer/katetextblock.cpp b/src/buffer/katetextblock.cpp index 3d2465fa..c12410db 100644 --- a/src/buffer/katetextblock.cpp +++ b/src/buffer/katetextblock.cpp @@ -1,746 +1,761 @@ /* This file is part of the Kate project. * * Copyright (C) 2010 Christoph Cullmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "katetextblock.h" #include "katetextbuffer.h" #include namespace Kate { TextBlock::TextBlock(TextBuffer *buffer, int startLine) : m_buffer(buffer) , m_startLine(startLine) { // reserve the block size m_lines.reserve(m_buffer->m_blockSize); } TextBlock::~TextBlock() { // blocks should be empty before they are deleted! Q_ASSERT(m_lines.empty()); Q_ASSERT(m_cursors.empty()); // it only is a hint for ranges for this block, not the storage of them } void TextBlock::setStartLine(int startLine) { // allow only valid lines Q_ASSERT(startLine >= 0); Q_ASSERT(startLine < m_buffer->lines()); m_startLine = startLine; } TextLine TextBlock::line(int line) const { // right input Q_ASSERT(line >= startLine()); - // calc internal line - line = line - startLine(); - - // in range - Q_ASSERT(line < m_lines.size()); - - // get text line - return m_lines.at(line); + // get text line, at will bail out on out-of-range + return m_lines.at(line - startLine()); } void TextBlock::appendLine(const QString &textOfLine) { - m_lines.append(TextLine::create(textOfLine)); + m_lines.push_back(TextLine::create(textOfLine)); } void TextBlock::clearLines() { m_lines.clear(); } void TextBlock::text(QString &text) const { // combine all lines - for (int i = 0; i < m_lines.size(); ++i) { + for (size_t i = 0; i < m_lines.size(); ++i) { // not first line, insert \n if (i > 0 || startLine() > 0) { text.append(QLatin1Char('\n')); } text.append(m_lines.at(i)->text()); } } void TextBlock::wrapLine(const KTextEditor::Cursor &position, int fixStartLinesStartIndex) { // calc internal line int line = position.line() - startLine(); // get text QString &text = m_lines.at(line)->textReadWrite(); // check if valid column Q_ASSERT(position.column() >= 0); Q_ASSERT(position.column() <= text.size()); // create new line and insert it m_lines.insert(m_lines.begin() + line + 1, TextLine(new TextLineData())); // cases for modification: // 1. line is wrapped in the middle // 2. if empty line is wrapped, mark new line as modified // 3. line-to-be-wrapped is already modified if (position.column() > 0 || text.size() == 0 || m_lines.at(line)->markedAsModified()) { m_lines.at(line + 1)->markAsModified(true); } else if (m_lines.at(line)->markedAsSavedOnDisk()) { m_lines.at(line + 1)->markAsSavedOnDisk(true); } // perhaps remove some text from previous line and append it if (position.column() < text.size()) { // text from old line moved first to new one m_lines.at(line + 1)->textReadWrite() = text.right(text.size() - position.column()); // now remove wrapped text from old line text.chop(text.size() - position.column()); // mark line as modified m_lines.at(line)->markAsModified(true); } /** * fix all start lines * we need to do this NOW, else the range update will FAIL! * bug 313759 */ m_buffer->fixStartLines(fixStartLinesStartIndex); /** * notify the text history */ m_buffer->history().wrapLine(position); /** * cursor and range handling below */ // no cursors will leave or join this block // no cursors in this block, no work to do.. if (m_cursors.empty()) { return; } // move all cursors on the line which has the text inserted // remember all ranges modified, optimize for the standard case of a few ranges QVarLengthArray changedRanges; - for (TextCursor *cursor : qAsConst(m_cursors)) { + for (TextCursor *cursor : m_cursors) { // skip cursors on lines in front of the wrapped one! if (cursor->lineInBlock() < line) { continue; } // either this is simple, line behind the wrapped one if (cursor->lineInBlock() > line) { // patch line of cursor cursor->m_line++; } // this is the wrapped line else { // skip cursors with too small column if (cursor->column() <= position.column()) { if (cursor->column() < position.column() || !cursor->m_moveOnInsert) { continue; } } // move cursor // patch line of cursor cursor->m_line++; // patch column cursor->m_column -= position.column(); } // remember range, if any, avoid double insert auto range = cursor->kateRange(); if (range && !range->isValidityCheckRequired()) { range->setValidityCheckRequired(); changedRanges.push_back(range); } } // we might need to invalidate ranges or notify about their changes // checkValidity might trigger delete of the range! for (TextRange *range : qAsConst(changedRanges)) { range->checkValidity(); } } void TextBlock::unwrapLine(int line, TextBlock *previousBlock, int fixStartLinesStartIndex) { // calc internal line line = line - startLine(); // two possiblities: either first line of this block or later line if (line == 0) { // we need previous block with at least one line Q_ASSERT(previousBlock); Q_ASSERT(previousBlock->lines() > 0); // move last line of previous block to this one, might result in empty block TextLine oldFirst = m_lines.at(0); int lastLineOfPreviousBlock = previousBlock->lines() - 1; - TextLine newFirst = previousBlock->m_lines.last(); + TextLine newFirst = previousBlock->m_lines.back(); m_lines[0] = newFirst; previousBlock->m_lines.erase(previousBlock->m_lines.begin() + (previousBlock->lines() - 1)); const int oldSizeOfPreviousLine = newFirst->text().size(); if (oldFirst->length() > 0) { // append text newFirst->textReadWrite().append(oldFirst->text()); // mark line as modified, since text was appended newFirst->markAsModified(true); } // patch startLine of this block --m_startLine; /** * fix all start lines * we need to do this NOW, else the range update will FAIL! * bug 313759 */ m_buffer->fixStartLines(fixStartLinesStartIndex); /** * notify the text history in advance */ m_buffer->history().unwrapLine(startLine() + line, oldSizeOfPreviousLine); /** * cursor and range handling below */ // no cursors in this block and the previous one, no work to do.. if (m_cursors.empty() && previousBlock->m_cursors.empty()) { return; } // move all cursors because of the unwrapped line // remember all ranges modified, optimize for the standard case of a few ranges QVarLengthArray changedRanges; - for (TextCursor *cursor : qAsConst(m_cursors)) { + for (TextCursor *cursor : m_cursors) { // this is the unwrapped line if (cursor->lineInBlock() == 0) { // patch column cursor->m_column += oldSizeOfPreviousLine; // remember range, if any, avoid double insert auto range = cursor->kateRange(); if (range && !range->isValidityCheckRequired()) { range->setValidityCheckRequired(); changedRanges.push_back(range); } } } // move cursors of the moved line from previous block to this block now - QSet newPreviousCursors; - for (TextCursor *cursor : qAsConst(previousBlock->m_cursors)) { + for (auto it = previousBlock->m_cursors.begin(); it != previousBlock->m_cursors.end();) { + auto cursor = *it; if (cursor->lineInBlock() == lastLineOfPreviousBlock) { cursor->m_line = 0; cursor->m_block = this; m_cursors.insert(cursor); // remember range, if any, avoid double insert auto range = cursor->kateRange(); if (range && !range->isValidityCheckRequired()) { range->setValidityCheckRequired(); changedRanges.push_back(range); } + + // remove from previous block + it = previousBlock->m_cursors.erase(it); } else { - newPreviousCursors.insert(cursor); + // keep in previous block + ++it; } } - previousBlock->m_cursors = newPreviousCursors; // fixup the ranges that might be effected, because they moved from last line to this block // we might need to invalidate ranges or notify about their changes // checkValidity might trigger delete of the range! for (TextRange *range : qAsConst(changedRanges)) { // update both blocks updateRange(range); previousBlock->updateRange(range); // afterwards check validity, might delete this range! range->checkValidity(); } // be done return; } // easy: just move text to previous line and remove current one const int oldSizeOfPreviousLine = m_lines.at(line - 1)->length(); const int sizeOfCurrentLine = m_lines.at(line)->length(); if (sizeOfCurrentLine > 0) { m_lines.at(line - 1)->textReadWrite().append(m_lines.at(line)->text()); } const bool lineChanged = (oldSizeOfPreviousLine > 0 && m_lines.at(line - 1)->markedAsModified()) || (sizeOfCurrentLine > 0 && (oldSizeOfPreviousLine > 0 || m_lines.at(line)->markedAsModified())); m_lines.at(line - 1)->markAsModified(lineChanged); if (oldSizeOfPreviousLine == 0 && m_lines.at(line)->markedAsSavedOnDisk()) { m_lines.at(line - 1)->markAsSavedOnDisk(true); } m_lines.erase(m_lines.begin() + line); /** * fix all start lines * we need to do this NOW, else the range update will FAIL! * bug 313759 */ m_buffer->fixStartLines(fixStartLinesStartIndex); /** * notify the text history in advance */ m_buffer->history().unwrapLine(startLine() + line, oldSizeOfPreviousLine); /** * cursor and range handling below */ // no cursors in this block, no work to do.. if (m_cursors.empty()) { return; } // move all cursors because of the unwrapped line // remember all ranges modified, optimize for the standard case of a few ranges QVarLengthArray changedRanges; - for (TextCursor *cursor : qAsConst(m_cursors)) { + for (TextCursor *cursor : m_cursors) { // skip cursors in lines in front of removed one if (cursor->lineInBlock() < line) { continue; } // this is the unwrapped line if (cursor->lineInBlock() == line) { // patch column cursor->m_column += oldSizeOfPreviousLine; } // patch line of cursor cursor->m_line--; // remember range, if any, avoid double insert auto range = cursor->kateRange(); if (range && !range->isValidityCheckRequired()) { range->setValidityCheckRequired(); changedRanges.push_back(range); } } // we might need to invalidate ranges or notify about their changes // checkValidity might trigger delete of the range! for (TextRange *range : qAsConst(changedRanges)) { range->checkValidity(); } } void TextBlock::insertText(const KTextEditor::Cursor &position, const QString &text) { // calc internal line int line = position.line() - startLine(); // get text QString &textOfLine = m_lines.at(line)->textReadWrite(); int oldLength = textOfLine.size(); m_lines.at(line)->markAsModified(true); // check if valid column Q_ASSERT(position.column() >= 0); Q_ASSERT(position.column() <= textOfLine.size()); // insert text textOfLine.insert(position.column(), text); /** * notify the text history */ m_buffer->history().insertText(position, text.size(), oldLength); /** * cursor and range handling below */ // no cursors in this block, no work to do.. if (m_cursors.empty()) { return; } // move all cursors on the line which has the text inserted // remember all ranges modified, optimize for the standard case of a few ranges QVarLengthArray changedRanges; - for (TextCursor *cursor : qAsConst(m_cursors)) { + for (TextCursor *cursor : m_cursors) { // skip cursors not on this line! if (cursor->lineInBlock() != line) { continue; } // skip cursors with too small column if (cursor->column() <= position.column()) { if (cursor->column() < position.column() || !cursor->m_moveOnInsert) { continue; } } // patch column of cursor if (cursor->m_column <= oldLength) { cursor->m_column += text.size(); } // special handling if cursor behind the real line, e.g. non-wrapping cursor in block selection mode else if (cursor->m_column < textOfLine.size()) { cursor->m_column = textOfLine.size(); } // remember range, if any, avoid double insert // we only need to trigger checkValidity later if the range has feedback or might be invalidated auto range = cursor->kateRange(); if (range && !range->isValidityCheckRequired() && (range->feedback() || range->start().line() == range->end().line())) { range->setValidityCheckRequired(); changedRanges.push_back(range); } } // we might need to invalidate ranges or notify about their changes // checkValidity might trigger delete of the range! for (TextRange *range : qAsConst(changedRanges)) { range->checkValidity(); } } void TextBlock::removeText(const KTextEditor::Range &range, QString &removedText) { // calc internal line int line = range.start().line() - startLine(); // get text QString &textOfLine = m_lines.at(line)->textReadWrite(); int oldLength = textOfLine.size(); // check if valid column Q_ASSERT(range.start().column() >= 0); Q_ASSERT(range.start().column() <= textOfLine.size()); Q_ASSERT(range.end().column() >= 0); Q_ASSERT(range.end().column() <= textOfLine.size()); // get text which will be removed removedText = textOfLine.mid(range.start().column(), range.end().column() - range.start().column()); // remove text textOfLine.remove(range.start().column(), range.end().column() - range.start().column()); m_lines.at(line)->markAsModified(true); /** * notify the text history */ m_buffer->history().removeText(range, oldLength); /** * cursor and range handling below */ // no cursors in this block, no work to do.. if (m_cursors.empty()) { return; } // move all cursors on the line which has the text removed // remember all ranges modified, optimize for the standard case of a few ranges QVarLengthArray changedRanges; - for (TextCursor *cursor : qAsConst(m_cursors)) { + for (TextCursor *cursor : m_cursors) { // skip cursors not on this line! if (cursor->lineInBlock() != line) { continue; } // skip cursors with too small column if (cursor->column() <= range.start().column()) { continue; } // patch column of cursor if (cursor->column() <= range.end().column()) { cursor->m_column = range.start().column(); } else { cursor->m_column -= (range.end().column() - range.start().column()); } // remember range, if any, avoid double insert // we only need to trigger checkValidity later if the range has feedback or might be invalidated auto range = cursor->kateRange(); if (range && !range->isValidityCheckRequired() && (range->feedback() || range->start().line() == range->end().line())) { range->setValidityCheckRequired(); changedRanges.push_back(range); } } // we might need to invalidate ranges or notify about their changes // checkValidity might trigger delete of the range! for (TextRange *range : qAsConst(changedRanges)) { range->checkValidity(); } } void TextBlock::debugPrint(int blockIndex) const { // print all blocks - for (int i = 0; i < m_lines.size(); ++i) - printf("%4d - %4d : %4d : '%s'\n", blockIndex, startLine() + i + for (size_t i = 0; i < m_lines.size(); ++i) + printf("%4d - %4lld : %4d : '%s'\n", blockIndex, (unsigned long long)startLine() + i , m_lines.at(i)->text().size(), qPrintable(m_lines.at(i)->text())); } TextBlock *TextBlock::splitBlock(int fromLine) { // half the block int linesOfNewBlock = lines() - fromLine; // create and insert new block TextBlock *newBlock = new TextBlock(m_buffer, startLine() + fromLine); // move lines newBlock->m_lines.reserve(linesOfNewBlock); - for (int i = fromLine; i < m_lines.size(); ++i) { - newBlock->m_lines.append(m_lines.at(i)); + for (size_t i = fromLine; i < m_lines.size(); ++i) { + newBlock->m_lines.push_back(m_lines.at(i)); } m_lines.resize(fromLine); // move cursors - QSet oldBlockSet; - for (TextCursor *cursor : qAsConst(m_cursors)) { + for (auto it = m_cursors.begin(); it != m_cursors.end();) { + auto cursor = *it; if (cursor->lineInBlock() >= fromLine) { cursor->m_line = cursor->lineInBlock() - fromLine; cursor->m_block = newBlock; + + // add to new, remove from current newBlock->m_cursors.insert(cursor); + it = m_cursors.erase(it); } else { - oldBlockSet.insert(cursor); + // keep in current + ++it; } } - m_cursors = oldBlockSet; // fix ALL ranges! const QList allRanges = m_uncachedRanges.toList() + m_cachedLineForRanges.keys(); for (TextRange *range : qAsConst(allRanges)) { // update both blocks updateRange(range); newBlock->updateRange(range); } // return the new generated block return newBlock; } void TextBlock::mergeBlock(TextBlock *targetBlock) { // move cursors, do this first, now still lines() count is correct for target - for (TextCursor *cursor : qAsConst(m_cursors)) { + for (TextCursor *cursor : m_cursors) { cursor->m_line = cursor->lineInBlock() + targetBlock->lines(); cursor->m_block = targetBlock; targetBlock->m_cursors.insert(cursor); } m_cursors.clear(); // move lines targetBlock->m_lines.reserve(targetBlock->lines() + lines()); - for (int i = 0; i < m_lines.size(); ++i) { - targetBlock->m_lines.append(m_lines.at(i)); + for (size_t i = 0; i < m_lines.size(); ++i) { + targetBlock->m_lines.push_back(m_lines.at(i)); } m_lines.clear(); // fix ALL ranges! const QList allRanges = m_uncachedRanges.toList() + m_cachedLineForRanges.keys(); for (TextRange *range : qAsConst(allRanges)) { // update both blocks updateRange(range); targetBlock->updateRange(range); } } void TextBlock::deleteBlockContent() { // kill cursors, if not belonging to a range - QSet copy = m_cursors; - for (TextCursor *cursor : qAsConst(copy)) { + // we can do in-place editing of the current set of cursors as + // we remove them before deleting + for (auto it = m_cursors.begin(); it != m_cursors.end();) { + auto cursor = *it; if (!cursor->kateRange()) { + // remove it and advance to next element + it = m_cursors.erase(it); + + // delete after cursor is gone from the set + // else the destructor will modify it! delete cursor; + } else { + // keep this cursor + ++it; } } // kill lines m_lines.clear(); } void TextBlock::clearBlockContent(TextBlock *targetBlock) { // move cursors, if not belonging to a range - QSet copy = m_cursors; - for (TextCursor *cursor : qAsConst(copy)) { + // we can do in-place editing of the current set of cursors + for (auto it = m_cursors.begin(); it != m_cursors.end();) { + auto cursor = *it; if (!cursor->kateRange()) { cursor->m_column = 0; cursor->m_line = 0; cursor->m_block = targetBlock; targetBlock->m_cursors.insert(cursor); - m_cursors.remove(cursor); + + // remove it and advance to next element + it = m_cursors.erase(it); + } else { + // keep this cursor + ++it; } } // kill lines m_lines.clear(); } void TextBlock::markModifiedLinesAsSaved() { // mark all modified lines as saved - for (int i = 0; i < m_lines.size(); ++i) { - TextLine textLine = m_lines[i]; + for (auto &textLine : m_lines) { if (textLine->markedAsModified()) { textLine->markAsSavedOnDisk(true); } } } void TextBlock::updateRange(TextRange *range) { /** * get some simple facts about our nice range */ const int startLine = range->startInternal().lineInternal(); const int endLine = range->endInternal().lineInternal(); const bool isSingleLine = startLine == endLine; /** * perhaps remove range and be done */ if ((endLine < m_startLine) || (startLine >= (m_startLine + lines()))) { removeRange(range); return; } /** * The range is still a single-line range, and is still cached to the correct line. */ if (isSingleLine && m_cachedLineForRanges.contains(range) && (m_cachedLineForRanges.value(range) == startLine - m_startLine)) { return; } /** * The range is still a multi-line range, and is already in the correct set. */ if (!isSingleLine && m_uncachedRanges.contains(range)) { return; } /** * remove, if already there! */ removeRange(range); /** * simple case: multi-line range */ if (!isSingleLine) { /** * The range cannot be cached per line, as it spans multiple lines */ m_uncachedRanges.insert(range); return; } /** * The range is contained by a single line, put it into the line-cache */ const int lineOffset = startLine - m_startLine; /** * enlarge cache if needed */ if (m_cachedRangesForLine.size() <= lineOffset) { m_cachedRangesForLine.resize(lineOffset + 1); } /** * insert into mapping */ m_cachedRangesForLine[lineOffset].insert(range); m_cachedLineForRanges[range] = lineOffset; } void TextBlock::removeRange(TextRange *range) { /** * uncached range? remove it and be done */ if (m_uncachedRanges.remove(range)) { /** * must be only uncached! */ Q_ASSERT(!m_cachedLineForRanges.contains(range)); return; } /** * cached range? */ QHash::iterator it = m_cachedLineForRanges.find(range); if (it != m_cachedLineForRanges.end()) { /** * must be only cached! */ Q_ASSERT(!m_uncachedRanges.contains(range)); /** * query the range from cache, must be there */ Q_ASSERT(m_cachedRangesForLine.at(*it).contains(range)); /** * remove it and be done */ m_cachedRangesForLine[*it].remove(range); m_cachedLineForRanges.erase(it); return; } /** * else: range was not for this block, just do nothing, removeRange should be "safe" to use */ } } diff --git a/src/buffer/katetextblock.h b/src/buffer/katetextblock.h index 3746d9af..50dfd614 100644 --- a/src/buffer/katetextblock.h +++ b/src/buffer/katetextblock.h @@ -1,281 +1,285 @@ /* This file is part of the Kate project. * * Copyright (C) 2010 Christoph Cullmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KATE_TEXTBLOCK_H #define KATE_TEXTBLOCK_H +#include + #include #include #include #include #include "katetextline.h" namespace Kate { class TextBuffer; class TextCursor; class TextRange; /** * Class representing a text block. * This is used to build up a Kate::TextBuffer. * This class should only be used by TextBuffer/Cursor/Range. */ class KTEXTEDITOR_EXPORT TextBlock { public: /** * Construct an empty text block. * @param buffer parent text buffer * @param startLine start line of this block */ TextBlock(TextBuffer *buffer, int startLine); /** * Destruct the text block */ ~TextBlock(); /** * Start line of this block. * @return start line of this block */ int startLine() const { return m_startLine; } /** * Set start line of this block. * @param startLine new start line of this block */ void setStartLine(int startLine); /** * Retrieve a text line. * @param line wanted line number * @return text line */ TextLine line(int line) const; /** * Append a new line with given text. * @param textOfLine text of the line to append */ void appendLine(const QString &textOfLine); /** * Clear the lines. */ void clearLines(); /** * Number of lines in this block. * @return number of lines */ int lines() const { return m_lines.size(); } /** * Retrieve text of block. * @param text for this block, lines separated by '\n' */ void text(QString &text) const; /** * Wrap line at given cursor position. * @param position line/column as cursor where to wrap * @param fixStartLinesStartIndex start index to fix start lines, normally this is this block */ void wrapLine(const KTextEditor::Cursor &position, int fixStartLinesStartIndex); /** * Unwrap given line. * @param line line to unwrap * @param previousBlock previous block, if any, if we unwrap first line in block, we need to have this * @param fixStartLinesStartIndex start index to fix start lines, normally this is this block or the previous one */ void unwrapLine(int line, TextBlock *previousBlock, int fixStartLinesStartIndex); /** * Insert text at given cursor position. * @param position position where to insert text * @param text text to insert */ void insertText(const KTextEditor::Cursor &position, const QString &text); /** * Remove text at given range. * @param range range of text to remove, must be on one line only. * @param removedText will be filled with removed text */ void removeText(const KTextEditor::Range &range, QString &removedText); /** * Debug output, print whole block content with line numbers and line length * @param blockIndex index of this block in buffer */ void debugPrint(int blockIndex) const; /** * Split given block. A new block will be created and all lines starting from the given index will * be moved to it, together with the cursors belonging to it. * @param fromLine line from which to split * @return new block containing the lines + cursors removed from this one */ TextBlock *splitBlock(int fromLine); /** * Merge this block with given one, the given one must be a direct predecessor. * @param targetBlock block to merge with */ void mergeBlock(TextBlock *targetBlock); /** * Delete the block content, delete all lines and delete all cursors not bound to ranges. * This is used in destructor of TextBuffer, for fast cleanup. Only stuff remaining afterwards are cursors which are * part of a range, TextBuffer will delete them itself... */ void deleteBlockContent(); /** * Clear the block content, delete all lines, move all cursors not bound to range to given block at 0,0. * This is used by clear() of TextBuffer. * @param targetBlock empty target block for cursors */ void clearBlockContent(TextBlock *targetBlock); /** * Return all ranges in this block which might intersect the given line. * @param line line to check intersection * @return list of sets of possible candidate ranges */ QList > rangesForLine(int line) const { return QList >() << m_uncachedRanges << cachedRangesForLine(line); } /** * Is the given range contained in this block? * @param range range to check for * @return contained in this blocks mapping? */ bool containsRange(TextRange *range) const { return m_cachedLineForRanges.contains(range) || m_uncachedRanges.contains(range); } /** * Flag all modified text lines as saved on disk. */ void markModifiedLinesAsSaved(); /** * Insert cursor into this block. * @param cursor cursor to insert */ void insertCursor(Kate::TextCursor *cursor) { m_cursors.insert(cursor); } /** * Remove cursor from this block. * @param cursor cursor to remove */ void removeCursor(Kate::TextCursor *cursor) { - m_cursors.remove(cursor); + m_cursors.erase(cursor); } /** * Update a range from this block. * Will move the range to right set, either cached for one-line ranges or not. * @param range range to update */ void updateRange(TextRange *range); /** * Remove a range from this block. * @param range range to remove */ void removeRange(TextRange *range); /** * Return all ranges in this block which might intersect the given line and only span one line. * For them an internal fast lookup cache is hold. * @param line line to check intersection * @return set of ranges */ QSet cachedRangesForLine(int line) const { line -= m_startLine; if (line >= 0 && line < m_cachedRangesForLine.size()) { return m_cachedRangesForLine[line]; } else { return QSet(); } } private: /** * parent text buffer */ TextBuffer *m_buffer; /** * Lines contained in this buffer. These are shared pointers. + * We need no sharing, use STL. */ - QVector m_lines; + std::vector m_lines; /** * Startline of this block */ int m_startLine; /** * Set of cursors for this block. + * We need no sharing, use STL. */ - QSet m_cursors; + std::unordered_set m_cursors; /** * Contains for each line-offset the ranges that were cached into it. * These ranges are fully contained by the line. */ QVector > m_cachedRangesForLine; /** * Maps for each cached range the line into which the range was cached. */ QHash m_cachedLineForRanges; /** * This contains all the ranges that are not cached. */ QSet m_uncachedRanges; }; } #endif