From ed9a0a3e6d1af81cc07a54d4feebb8a01c451fb8 Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Tue, 13 Jan 2009 16:34:18 +0100 Subject: [PATCH] Reducing the overhead between ChatlineModelItem and MessageModelItem. This concludes my work on restructuring the MessageModel to not be such a malloc hog. Also it seems that performance can be further increased by reducing virtual calls on the MessageModelItems. --- src/client/messagemodel.cpp | 7 -- src/client/messagemodel.h | 16 +-- src/qtui/chatlinemodelitem.cpp | 178 +++++++++++++-------------------- src/qtui/chatlinemodelitem.h | 24 ++++- src/uisupport/uistyle.cpp | 3 +- src/uisupport/uistyle.h | 9 +- 6 files changed, 104 insertions(+), 133 deletions(-) diff --git a/src/client/messagemodel.cpp b/src/client/messagemodel.cpp index 76943d4c..ca77bfd0 100644 --- a/src/client/messagemodel.cpp +++ b/src/client/messagemodel.cpp @@ -409,13 +409,6 @@ void MessageModel::buffersPermanentlyMerged(BufferId bufferId1, BufferId bufferI // ======================================== // MessageModelItem // ======================================== -MessageModelItem::MessageModelItem(const Message &msg) - : _msg(msg) -{ - if(!_msg.sender().contains('!')) - _msg.setFlags(_msg.flags() |= Message::ServerMsg); -} - QVariant MessageModelItem::data(int column, int role) const { if(column < MessageModel::TimestampColumn || column > MessageModel::ContentsColumn) return QVariant(); diff --git a/src/client/messagemodel.h b/src/client/messagemodel.h index 5da8309d..0d540cd5 100644 --- a/src/client/messagemodel.h +++ b/src/client/messagemodel.h @@ -118,19 +118,19 @@ public: * Subclasses need to provide Qt::DisplayRole at least, which should describe the plaintext * strings without formattings (e.g. for searching purposes). */ - MessageModelItem(const Message &); + MessageModelItem() {} inline virtual ~MessageModelItem() {} virtual QVariant data(int column, int role) const; virtual bool setData(int column, const QVariant &value, int role); - inline const Message &message() const { return _msg; } - inline const QDateTime ×tamp() const { return _msg.timestamp(); } - inline const MsgId &msgId() const { return _msg.msgId(); } - inline const BufferId &bufferId() const { return _msg.bufferId(); } - inline void setBufferId(BufferId bufferId) { _msg.setBufferId(bufferId); } - inline Message::Type msgType() const { return _msg.type(); } - inline Message::Flags msgFlags() const { return _msg.flags(); } + virtual const Message &message() const = 0; + virtual const QDateTime ×tamp() const = 0; + virtual const MsgId &msgId() const = 0; + virtual const BufferId &bufferId() const = 0; + virtual void setBufferId(BufferId bufferId) = 0; + virtual Message::Type msgType() const = 0; + virtual Message::Flags msgFlags() const = 0; // For sorting bool operator<(const MessageModelItem &) const; diff --git a/src/qtui/chatlinemodelitem.cpp b/src/qtui/chatlinemodelitem.cpp index a3de834a..2264fa5a 100644 --- a/src/qtui/chatlinemodelitem.cpp +++ b/src/qtui/chatlinemodelitem.cpp @@ -37,108 +37,93 @@ typedef struct { unsigned unused :2; } HB_CharAttributes_Dummy; -// PRIVATE DATA FOR CHATLINE MODEL ITEM -class ChatLineModelItemPrivate { -public: - inline ChatLineModelItemPrivate(const Message &msg); - ~ChatLineModelItemPrivate(); - - inline bool needsStyling(); - QVariant data(MessageModel::ColumnType column, int role); - -private: - void style(); - void computeWrapList(); - - ChatLineModel::WrapList _wrapList; - Message *_msgBuffer; - UiStyle::StyledMessage *_styledMsg; - - static unsigned char *TextBoundaryFinderBuffer; - static int TextBoundaryFinderBufferSize; -}; - -ChatLineModelItemPrivate::ChatLineModelItemPrivate(const Message &msg) -: _msgBuffer(new Message(msg)), - _styledMsg(0) { +unsigned char *ChatLineModelItem::TextBoundaryFinderBuffer = (unsigned char *)malloc(512 * sizeof(HB_CharAttributes_Dummy)); +int ChatLineModelItem::TextBoundaryFinderBufferSize = 512 * (sizeof(HB_CharAttributes_Dummy) / sizeof(unsigned char)); +// **************************************** +// the actual ChatLineModelItem +// **************************************** +ChatLineModelItem::ChatLineModelItem(const Message &msg) + : MessageModelItem(), + _styledMsg(msg) +{ + if(!msg.sender().contains('!')) + _styledMsg.setFlags(msg.flags() |= Message::ServerMsg); } -ChatLineModelItemPrivate::~ChatLineModelItemPrivate() { - if(_msgBuffer) { - delete _msgBuffer; - } else { - delete _styledMsg; +QVariant ChatLineModelItem::data(int column, int role) const { + MessageModel::ColumnType col = (MessageModel::ColumnType)column; + QVariant variant; + switch(col) { + case ChatLineModel::TimestampColumn: + variant = timestampData(role); + break; + case ChatLineModel::SenderColumn: + variant = senderData(role); + break; + case ChatLineModel::ContentsColumn: + variant = contentsData(role); + break; + default: + break; } + if(!variant.isValid()) + return MessageModelItem::data(column, role); + return variant; } -bool ChatLineModelItemPrivate::needsStyling() { - return (bool)_msgBuffer; +QVariant ChatLineModelItem::timestampData(int role) const { + switch(role) { + case ChatLineModel::DisplayRole: + return _styledMsg.decoratedTimestamp(); + case ChatLineModel::EditRole: + return _styledMsg.timestamp(); + case ChatLineModel::FormatRole: + return QVariant::fromValue(UiStyle::FormatList() << qMakePair((quint16)0, (quint32)_styledMsg.timestampFormat())); + } + return QVariant(); } -QVariant ChatLineModelItemPrivate::data(MessageModel::ColumnType column, int role) { - if(needsStyling()) - style(); - switch(column) { - case ChatLineModel::TimestampColumn: - switch(role) { - case ChatLineModel::DisplayRole: - return _styledMsg->decoratedTimestamp(); - case ChatLineModel::EditRole: - return _styledMsg->timestamp(); - case ChatLineModel::FormatRole: - return QVariant::fromValue(UiStyle::FormatList() - << qMakePair((quint16)0, (quint32)_styledMsg->timestampFormat())); - } - break; - case ChatLineModel::SenderColumn: - switch(role) { - case ChatLineModel::DisplayRole: - return _styledMsg->decoratedSender(); - case ChatLineModel::EditRole: - return _styledMsg->plainSender(); - case ChatLineModel::FormatRole: - return QVariant::fromValue(UiStyle::FormatList() - << qMakePair((quint16)0, (quint32)_styledMsg->senderFormat())); - } - break; - case ChatLineModel::ContentsColumn: - switch(role) { - case ChatLineModel::DisplayRole: - case ChatLineModel::EditRole: - return _styledMsg->plainContents(); - case ChatLineModel::FormatRole: - return QVariant::fromValue(_styledMsg->contentsFormatList()); - case ChatLineModel::WrapListRole: - if(_wrapList.isEmpty()) - computeWrapList(); - return QVariant::fromValue(_wrapList); - } - break; - default: - Q_ASSERT(false); - return 0; +QVariant ChatLineModelItem::senderData(int role) const { + switch(role) { + case ChatLineModel::DisplayRole: + return _styledMsg.decoratedSender(); + case ChatLineModel::EditRole: + return _styledMsg.plainSender(); + case ChatLineModel::FormatRole: + return QVariant::fromValue(UiStyle::FormatList() << qMakePair((quint16)0, (quint32)_styledMsg.senderFormat())); } return QVariant(); } -void ChatLineModelItemPrivate::style() { - _styledMsg = new QtUiStyle::StyledMessage(*_msgBuffer); - _styledMsg->style(QtUi::style()); - delete _msgBuffer; - _msgBuffer = 0; +QVariant ChatLineModelItem::contentsData(int role) const { + if(_styledMsg.needsStyling()) + _styledMsg.style(QtUi::style()); + + switch(role) { + case ChatLineModel::DisplayRole: + case ChatLineModel::EditRole: + return _styledMsg.plainContents(); + case ChatLineModel::FormatRole: + return QVariant::fromValue(_styledMsg.contentsFormatList()); + case ChatLineModel::WrapListRole: + if(_wrapList.isEmpty()) + computeWrapList(); + return QVariant::fromValue(_wrapList); + } + return QVariant(); } -void ChatLineModelItemPrivate::computeWrapList() { - int length = _styledMsg->contents().length(); +void ChatLineModelItem::computeWrapList() const { + int length = _styledMsg.plainContents().length(); if(!length) return; enum Mode { SearchStart, SearchEnd }; QList wplist; // use a temp list which we'll later copy into a QVector for efficiency - QTextBoundaryFinder finder(QTextBoundaryFinder::Word, _styledMsg->contents().unicode(), length, + QTextBoundaryFinder finder(QTextBoundaryFinder::Word, _styledMsg.plainContents().unicode(), length, TextBoundaryFinderBuffer, TextBoundaryFinderBufferSize); int idx; @@ -150,12 +135,12 @@ void ChatLineModelItemPrivate::computeWrapList() { word.start = 0; qreal wordstartx = 0; - QTextLayout layout(_styledMsg->contents()); + QTextLayout layout(_styledMsg.plainContents()); QTextOption option; option.setWrapMode(QTextOption::NoWrap); layout.setTextOption(option); - layout.setAdditionalFormats(QtUi::style()->toTextLayoutList(_styledMsg->contentsFormatList(), length)); + layout.setAdditionalFormats(QtUi::style()->toTextLayoutList(_styledMsg.contentsFormatList(), length)); layout.beginLayout(); QTextLine line = layout.createLine(); line.setNumColumns(length); @@ -204,30 +189,3 @@ void ChatLineModelItemPrivate::computeWrapList() { } } -unsigned char *ChatLineModelItemPrivate::TextBoundaryFinderBuffer = (unsigned char *)malloc(512 * sizeof(HB_CharAttributes_Dummy)); -int ChatLineModelItemPrivate::TextBoundaryFinderBufferSize = 512 * (sizeof(HB_CharAttributes_Dummy) / sizeof(unsigned char)); - -// **************************************** -// the actual ChatLineModelItem -// **************************************** -ChatLineModelItem::ChatLineModelItem(const Message &msg) - : MessageModelItem(msg), - _data(new ChatLineModelItemPrivate(msg)) -{ -} - -ChatLineModelItem::ChatLineModelItem(const ChatLineModelItem &other) - : MessageModelItem(other) -{ - _data = new ChatLineModelItemPrivate(message()); -} - -ChatLineModelItem::~ChatLineModelItem() { - delete _data; -} - -QVariant ChatLineModelItem::data(int column, int role) const { - QVariant d = _data->data((MessageModel::ColumnType)column, role); - if(!d.isValid()) return MessageModelItem::data(column, role); - return d; -} diff --git a/src/qtui/chatlinemodelitem.h b/src/qtui/chatlinemodelitem.h index d4979cdf..5382a7b8 100644 --- a/src/qtui/chatlinemodelitem.h +++ b/src/qtui/chatlinemodelitem.h @@ -23,16 +23,22 @@ #include "messagemodel.h" -class ChatLineModelItemPrivate; +#include "uistyle.h" class ChatLineModelItem : public MessageModelItem { public: ChatLineModelItem(const Message &); - ChatLineModelItem(const ChatLineModelItem &other); - ~ChatLineModelItem(); virtual QVariant data(int column, int role) const; + virtual inline const Message &message() const { return _styledMsg; } + virtual inline const QDateTime ×tamp() const { return _styledMsg.timestamp(); } + virtual inline const MsgId &msgId() const { return _styledMsg.msgId(); } + virtual inline const BufferId &bufferId() const { return _styledMsg.bufferId(); } + virtual inline void setBufferId(BufferId bufferId) { _styledMsg.setBufferId(bufferId); } + virtual inline Message::Type msgType() const { return _styledMsg.type(); } + virtual inline Message::Flags msgFlags() const { return _styledMsg.flags(); } + /// Used to store information about words to be used for wrapping struct Word { quint16 start; @@ -43,7 +49,17 @@ public: typedef QVector WrapList; private: - ChatLineModelItemPrivate *_data; + virtual QVariant timestampData(int role) const; + virtual QVariant senderData(int role) const; + virtual QVariant contentsData(int role) const; + + void computeWrapList() const; + + mutable WrapList _wrapList; + UiStyle::StyledMessage _styledMsg; + + static unsigned char *TextBoundaryFinderBuffer; + static int TextBoundaryFinderBufferSize; }; #endif diff --git a/src/uisupport/uistyle.cpp b/src/uisupport/uistyle.cpp index 141ff335..dafcc5f8 100644 --- a/src/uisupport/uistyle.cpp +++ b/src/uisupport/uistyle.cpp @@ -318,7 +318,7 @@ UiStyle::StyledMessage::StyledMessage(const Message &msg) { } -void UiStyle::StyledMessage::style(UiStyle *style) { +void UiStyle::StyledMessage::style(UiStyle *style) const { QString user = userFromMask(sender()); QString host = hostFromMask(sender()); QString nick = nickFromMask(sender()); @@ -442,6 +442,7 @@ UiStyle::FormatType UiStyle::StyledMessage::senderFormat() const { } } + /***********************************************************************************/ QDataStream &operator<<(QDataStream &out, const UiStyle::FormatList &formatList) { diff --git a/src/uisupport/uistyle.h b/src/uisupport/uistyle.h index 76922279..7f0614b9 100644 --- a/src/uisupport/uistyle.h +++ b/src/uisupport/uistyle.h @@ -156,20 +156,23 @@ class UiStyle::StyledMessage : public Message { public: explicit StyledMessage(const Message &message); + //! Styling is only needed for calls to plainContents() and contentsFormatList() + // StyledMessage can't style lazily by itself, as it doesn't know the used style bool inline needsStyling() const { return _contents.plainText.isNull(); } - void style(UiStyle *style); + void style(UiStyle *style) const; + QString decoratedTimestamp() const; QString plainSender() const; //!< Nickname (no decorations) for Plain and Notice, empty else QString decoratedSender() const; - const QString &plainContents() const { return _contents.plainText; } + inline const QString &plainContents() const { return _contents.plainText; } inline FormatType timestampFormat() const { return UiStyle::Timestamp; } FormatType senderFormat() const; inline const FormatList &contentsFormatList() const { return _contents.formatList; } private: - StyledString _contents; + mutable StyledString _contents; }; QDataStream &operator<<(QDataStream &out, const UiStyle::FormatList &formatList); -- 2.20.1