Commit 2aa61bb9 authored by Carlos Alves's avatar Carlos Alves Committed by Kurt Hindenburg
Browse files

Change CompactHistory data storage

It is removing the vector of lines storage. Now it is using a similar
idea used in history file.

All chars are stored in a linear way, only the line indexes are
changed when reflowing.

No speed problem found when removing lines.
parent 92798b03
......@@ -159,9 +159,6 @@ set(konsoleprivate_SRCS ${windowadaptors_SRCS}
history/HistoryType.cpp
history/HistoryTypeFile.cpp
history/HistoryTypeNone.cpp
history/compact/CompactHistoryBlock.cpp
history/compact/CompactHistoryBlockList.cpp
history/compact/CompactHistoryLine.cpp
history/compact/CompactHistoryScroll.cpp
history/compact/CompactHistoryType.cpp
widgets/DetachableTabBar.cpp
......
......@@ -516,7 +516,7 @@ void Screen::resizeImage(int new_lines, int new_columns)
_history->getCells(histPos, 0, histLineLen, histLine.data());
_screenLines.insert(0, histLine);
_lineProperties.insert(0, lineProperty);
_history->removeCells(histPos);
_history->removeCells();
cursorLine++;
}
}
......
......@@ -53,12 +53,7 @@ public:
virtual void addLine(LineProperty lineProperty = 0) = 0;
// modify history
virtual void insertCellsVector(int position, const QVector<Character> &cells) = 0;
virtual void insertCells(int position, const Character a[], int count) = 0;
virtual void removeCells(int position) = 0;
virtual void setCellsAt(int position, const Character a[], int count) = 0;
virtual void setCellsVectorAt(int position, const QVector<Character> &cells) = 0;
virtual void setLineAt(int position, LineProperty lineProperty) = 0;
virtual void removeCells() = 0;
virtual int reflowLines(int columns) = 0;
//
......
......@@ -95,11 +95,7 @@ void HistoryScrollFile::addLine(LineProperty lineProperty)
_lineflags.add(reinterpret_cast<char *>(&lineProperty), sizeof(char));
}
void HistoryScrollFile::insertCells(int, const Character[], int)
{
}
void HistoryScrollFile::removeCells(int)
void HistoryScrollFile::removeCells()
{
qint64 res = (getLines() - 2) * sizeof(qint64);
if (getLines() < 2) {
......@@ -113,26 +109,6 @@ void HistoryScrollFile::removeCells(int)
_lineflags.removeLast(res * sizeof(unsigned char));
}
void HistoryScrollFile::insertCellsVector(int, const QVector<Character> &)
{
}
void HistoryScrollFile::setCellsAt(int, const Character text[], int count)
{
qint64 res = (getLines() - 2) * sizeof(qint64);
if (getLines() < 2) {
_cells.removeLast(0);
} else {
_index.get(reinterpret_cast<char *>(&res), sizeof(qint64), res);
_cells.removeLast(res);
}
_cells.add(reinterpret_cast<const char *>(text), count * sizeof(Character));
}
void HistoryScrollFile::setCellsVectorAt(int, const QVector<Character> &)
{
}
int HistoryScrollFile::reflowLines(int columns)
{
auto reflowFile = std::make_unique<HistoryFile>();
......@@ -196,15 +172,3 @@ int HistoryScrollFile::reflowLines(int columns)
return 0;
}
void HistoryScrollFile::setLineAt(int, LineProperty lineProperty)
{
qint64 locn = qMax(0, getLines() - 1);
_index.removeLast(locn * sizeof(qint64));
_lineflags.removeLast(locn * sizeof(unsigned char));
locn = _cells.len();
_index.add(reinterpret_cast<char *>(&locn), sizeof(qint64));
_lineflags.add(reinterpret_cast<char *>(&lineProperty), sizeof(char));
}
......@@ -37,12 +37,7 @@ public:
void addLine(LineProperty lineProperty = 0) override;
// Modify history
void insertCellsVector(int position, const QVector<Character> &cells) override;
void insertCells(int position, const Character a[], int count) override;
void removeCells(int position) override;
void setCellsAt(int position, const Character a[], int count) override;
void setCellsVectorAt(int position, const QVector<Character> &cells) override;
void setLineAt(int position, LineProperty lineProperty) override;
void removeCells() override;
int reflowLines(int columns) override;
private:
......
......@@ -62,23 +62,7 @@ void HistoryScrollNone::addLine(LineProperty)
{
}
void HistoryScrollNone::insertCells(int , const Character [], int)
{
}
void HistoryScrollNone::removeCells(int )
{
}
void HistoryScrollNone::insertCellsVector(int , const QVector<Character> &)
{
}
void HistoryScrollNone::setCellsAt(int , const Character [], int)
{
}
void HistoryScrollNone::setCellsVectorAt(int , const QVector<Character> &)
void HistoryScrollNone::removeCells()
{
}
......@@ -86,7 +70,3 @@ int HistoryScrollNone::reflowLines(int)
{
return 0;
}
void HistoryScrollNone::setLineAt(int , LineProperty)
{
}
......@@ -36,12 +36,7 @@ public:
void addLine(LineProperty lineProperty = 0) override;
// Modify history (do nothing here)
void insertCellsVector(int position, const QVector<Character> &cells) override;
void insertCells(int position, const Character a[], int count) override;
void removeCells(int position) override;
void setCellsAt(int position, const Character a[], int count) override;
void setCellsVectorAt(int position, const QVector<Character> &cells) override;
void setLineAt(int position, LineProperty lineProperty) override;
void removeCells() override;
int reflowLines(int) override;
};
......
/*
SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
// Own
#include "CompactHistoryBlock.h"
using namespace Konsole;
constexpr size_t BLOCK_LENGTH = 4096 * 64 ; // 256kb
CompactHistoryBlock::CompactHistoryBlock(size_t blockLength) :
_blockLength(BLOCK_LENGTH),
_tail(nullptr),
_blockStart(nullptr),
_allocCount(0)
{
if (blockLength > _blockLength) {
_blockLength = blockLength;
}
_head = static_cast<quint8 *>(mmap(nullptr, _blockLength, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0));
Q_ASSERT(_head != MAP_FAILED);
_tail = _blockStart = _head;
}
CompactHistoryBlock::~CompactHistoryBlock()
{
//free(_blockStart);
munmap(_blockStart, _blockLength);
}
unsigned int CompactHistoryBlock::remaining()
{
return _blockStart + _blockLength - _tail;
}
unsigned CompactHistoryBlock::length()
{
return _blockLength;
}
bool CompactHistoryBlock::contains(void *addr)
{
return addr >= _blockStart && addr < (_blockStart + _blockLength);
}
bool CompactHistoryBlock::isInUse()
{
return _allocCount != 0;
}
void *CompactHistoryBlock::allocate(size_t size)
{
Q_ASSERT(size > 0);
if (_tail - _blockStart + size > _blockLength) {
return nullptr;
}
void *block = _tail;
_tail += size;
////qDebug() << "allocated " << length << " bytes at address " << block;
_allocCount++;
return block;
}
void CompactHistoryBlock::deallocate()
{
_allocCount--;
Q_ASSERT(_allocCount >= 0);
}
/*
SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef COMPACTHISTORYBLOCK_H
#define COMPACTHISTORYBLOCK_H
// Konsole
#include "../characters/Character.h"
// System
#include <sys/mman.h>
namespace Konsole
{
class CompactHistoryBlock
{
public:
CompactHistoryBlock(size_t blockLength = 0);
virtual ~CompactHistoryBlock();
virtual unsigned int remaining();
virtual unsigned length();
virtual void *allocate(size_t size);
virtual bool contains(void *addr);
virtual void deallocate();
virtual bool isInUse();
private:
size_t _blockLength;
quint8 *_head;
quint8 *_tail;
quint8 *_blockStart;
int _allocCount;
};
}
#endif
/*
SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
// Own
#include "CompactHistoryBlockList.h"
// Qt
using namespace Konsole;
CompactHistoryBlockList::CompactHistoryBlockList()
: _blocks()
{
}
void *CompactHistoryBlockList::allocate(size_t size)
{
if (_blocks.empty() || _blocks.back()->remaining() < size) {
_blocks.push_back(std::make_unique<CompactHistoryBlock>(size));
////qDebug() << "new block created, remaining " << block->remaining() << "number of blocks=" << _blocks.size();
}
return _blocks.back()->allocate(size);
}
void CompactHistoryBlockList::deallocate(void *ptr)
{
Q_ASSERT(!_blocks.empty());
auto block = _blocks.begin();
while (block != _blocks.end() && !(*block)->contains(ptr)) {
block++;
}
Q_ASSERT(block != _blocks.end());
(*block)->deallocate();
if (!(*block)->isInUse()) {
_blocks.erase(block);
////qDebug() << "block deleted, new size = " << list.size();
}
}
int CompactHistoryBlockList::length()
{
return _blocks.size();
}
CompactHistoryBlockList::~CompactHistoryBlockList()
{
_blocks.clear();
}
/*
SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef COMPACTHISTORYBLOCKLIST_H
#define COMPACTHISTORYBLOCKLIST_H
#include <memory>
#include <vector>
#include "CompactHistoryBlock.h"
namespace Konsole
{
class CompactHistoryBlockList
{
public:
CompactHistoryBlockList();
~CompactHistoryBlockList();
void *allocate(size_t size);
void deallocate(void *);
int length();
private:
std::vector<std::unique_ptr<CompactHistoryBlock>> _blocks;
};
}
#endif
/*
SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "CompactHistoryLine.h"
using namespace Konsole;
void *CompactHistoryLine::operator new(size_t size, CompactHistoryBlockList &blockList)
{
return blockList.allocate(size);
}
void CompactHistoryLine::operator delete(void *)
{
/* do nothing, deallocation from pool is done in destructor*/
}
CompactHistoryLine::CompactHistoryLine(const TextLine &line, CompactHistoryBlockList &bList) :
_blockListRef(bList),
_formatArray(nullptr),
_text(nullptr),
_formatLength(0),
_lineProperty(0)
{
if (!line.isEmpty()) {
_length = line.size();
// count number of different formats in this text line
Character c = line[0];
_formatLength = 1;
for (auto &k : line) {
if (!(k.equalsFormat(c))) {
_formatLength++; // format change detected
c = k;
}
}
_formatArray = static_cast<CharacterFormat *>(_blockListRef.allocate(sizeof(CharacterFormat) * _formatLength));
Q_ASSERT(_formatArray != nullptr);
_text = static_cast<uint *>(_blockListRef.allocate(sizeof(uint) * line.size()));
Q_ASSERT(_text != nullptr);
c = line[0];
_formatArray[0].setFormat(c);
_formatArray[0].startPos = 0;
for (int i = 0, k = 1; i < _length; i++) {
if (!line[i].equalsFormat(c)) {
c = line[i];
_formatArray[k].setFormat(c);
_formatArray[k].startPos = i;
k++;
}
_text[i] = line[i].character;
}
_lineProperty = 0;
}
}
CompactHistoryLine::~CompactHistoryLine()
{
if (_length > 0) {
_blockListRef.deallocate(_text);
_blockListRef.deallocate(_formatArray);
}
_blockListRef.deallocate(this);
}
void CompactHistoryLine::getCharacters(Character *array, int size, int startColumn)
{
Q_ASSERT(startColumn >= 0 && size >= 0);
Q_ASSERT(startColumn + size <= static_cast<int>(getLength()));
int formatPos = 0;
while ((formatPos + 1) < _formatLength && startColumn >= _formatArray[formatPos + 1].startPos) {
formatPos++;
}
for (int i = startColumn; i < size + startColumn; i++) {
if ((formatPos + 1) < _formatLength && i == _formatArray[formatPos + 1].startPos) {
formatPos++;
}
array[i - startColumn] = Character(_text[i],
_formatArray[formatPos].fgColor,
_formatArray[formatPos].bgColor,
_formatArray[formatPos].rendition,
_formatArray[formatPos].isRealCharacter);
}
}
void CompactHistoryLine::setCharacters(const TextLine &line)
{
if (line.isEmpty()) {
if (_formatArray) {
_blockListRef.deallocate(_formatArray);
}
if (_text) {
_blockListRef.deallocate(_text);
}
_formatArray = nullptr;
_text = nullptr;
_formatLength = 0;
_length = 0;
return;
}
int new_length = line.size();
// count number of different formats in this text line
Character c = line[0];
int new_formatLength = 1;
for (auto &k : line) {
if (!(k.equalsFormat(c))) {
new_formatLength++; // format change detected
c = k;
}
}
if (_formatLength < new_formatLength) {
_blockListRef.deallocate(_formatArray);
_formatArray = static_cast<CharacterFormat *>(_blockListRef.allocate(sizeof(CharacterFormat) * new_formatLength));
Q_ASSERT(_formatArray != nullptr);
}
if (_length < new_length) {
_blockListRef.deallocate(_text);
_text = static_cast<uint *>(_blockListRef.allocate(sizeof(uint) * new_length));
Q_ASSERT(_text != nullptr);
}
_length = new_length;
_formatLength = new_formatLength;
c = line[0];
_formatArray[0].setFormat(c);
_formatArray[0].startPos = 0;
for (int i = 0, k = 1; i < _length; i++) {
if (!line[i].equalsFormat(c)) {
c = line[i];
_formatArray[k].setFormat(c);
_formatArray[k].startPos = i;
k++;
}
_text[i] = line[i].character;
}
}
bool CompactHistoryLine::isWrapped() const
{
return _lineProperty & LINE_WRAPPED;
}
void CompactHistoryLine::setWrapped(bool value)
{
if (value) {
_lineProperty |= LINE_WRAPPED;
} else {
_lineProperty &= ~LINE_WRAPPED;
}
}
LineProperty CompactHistoryLine::getLineProperty() const
{
return _lineProperty;
}
void CompactHistoryLine::setLineProperty(LineProperty value)
{
_lineProperty = value;
}
unsigned int CompactHistoryLine::getLength() const
{
return _length;
}
/*
SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef COMPACTHISTORYLINE_H
#define COMPACTHISTORYLINE_H
#include <QVector>
#include "../characters/CharacterFormat.h"
#include "CompactHistoryBlockList.h"
namespace Konsole
{
typedef QVector<Character> TextLine;
class CompactHistoryLine
{
public:
CompactHistoryLine(const TextLine &, CompactHistoryBlockList &blockList);
virtual ~CompactHistoryLine();
// custom new operator to allocate memory from custom pool instead of heap
static void *operator new(size_t size, CompactHistoryBlockList &blockList);
static void operator delete(void *);
virtual void setCharacters(const TextLine &);
virtual void getCharacters(Character *array, int size, int startColumn);
virtual bool isWrapped() const;
virtual void setWrapped(bool value);
virtual LineProperty getLineProperty() const;
virtual void setLineProperty(LineProperty value);
virtual unsigned int getLength() const;
protected:
CompactHistoryBlockList &_blockListRef;
CharacterFormat *_formatArray;
int _length;
uint *_text;
int _formatLength;
LineProperty _lineProperty;
};
}
#endif
......@@ -11,66 +11,79 @@
using namespace Konsole;
struct reflowData { // data to reflow lines
QList<int> index;
QList<LineProperty> flags;
};