diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp index e987cb60e3..6ae5e52858 100644 --- a/Telegram/SourceFiles/layout.cpp +++ b/Telegram/SourceFiles/layout.cpp @@ -293,9 +293,9 @@ void LayoutAbstractFileItem::setStatusSize(int32 newSize, int32 fullSize, int32 } } -LayoutOverviewDate::LayoutOverviewDate(const QDate &date, bool month) - : _date(date) - , _text(month ? langMonthFull(date) : langDayOfMonthFull(date)) { +LayoutOverviewDate::LayoutOverviewDate(const QDate &date, bool month) : LayoutItem(OverviewItemInfo::Bit()) +, _date(date) +, _text(month ? langMonthFull(date) : langDayOfMonthFull(date)) { } void LayoutOverviewDate::initDimensions() { @@ -311,7 +311,7 @@ void LayoutOverviewDate::paint(Painter &p, const QRect &clip, uint32 selection, } } -LayoutOverviewPhoto::LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent) : LayoutMediaItem(parent) +LayoutOverviewPhoto::LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent) : LayoutMediaItem(0, parent) , _data(photo) , _link(new PhotoLink(photo)) , _goodLoaded(false) { @@ -385,7 +385,7 @@ void LayoutOverviewPhoto::getState(TextLinkPtr &link, HistoryCursorState &cursor } } -LayoutOverviewVideo::LayoutOverviewVideo(VideoData *video, HistoryItem *parent) : LayoutAbstractFileItem(parent) +LayoutOverviewVideo::LayoutOverviewVideo(VideoData *video, HistoryItem *parent) : LayoutAbstractFileItem(0, parent) , _data(video) , _duration(formatDurationText(_data->duration)) , _thumbLoaded(false) { @@ -550,7 +550,7 @@ void LayoutOverviewVideo::updateStatusText() const { } } -LayoutOverviewAudio::LayoutOverviewAudio(AudioData *audio, HistoryItem *parent) : LayoutAbstractFileItem(parent) +LayoutOverviewAudio::LayoutOverviewAudio(AudioData *audio, HistoryItem *parent) : LayoutAbstractFileItem(OverviewItemInfo::Bit(), parent) , _data(audio) , _namel(new AudioOpenLink(_data)) { setLinks(new AudioOpenLink(_data), new AudioOpenLink(_data), new AudioCancelLink(_data)); @@ -738,7 +738,7 @@ bool LayoutOverviewAudio::updateStatusText() const { return showPause; } -LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryItem *parent) : LayoutAbstractFileItem(parent) +LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryItem *parent) : LayoutAbstractFileItem(OverviewItemInfo::Bit(), parent) , _data(document) , _msgl(new MessageLink(parent)) , _namel(new DocumentOpenLink(_data)) @@ -1061,7 +1061,7 @@ namespace { } } -LayoutOverviewLink::LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent) : LayoutMediaItem(parent) +LayoutOverviewLink::LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent) : LayoutMediaItem(OverviewItemInfo::Bit(), parent) , _titlew(0) , _page(0) , _pixw(0) @@ -1319,8 +1319,8 @@ LayoutOverviewLink::Link::Link(const QString &url, const QString &text) , lnk(linkFromUrl(url)) { } -LayoutInlineItem::LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo) -: _result(result) +LayoutInlineItem::LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo) : LayoutItem(0) +, _result(result) , _doc(doc) , _photo(photo) , _position(0) { diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h index 0b346456c6..c7303adc95 100644 --- a/Telegram/SourceFiles/layout.h +++ b/Telegram/SourceFiles/layout.h @@ -101,11 +101,9 @@ public: }; class LayoutMediaItem; -class OverviewItemInfo; - -class LayoutItem { +class LayoutItem : public Interfaces { public: - LayoutItem() : _maxw(0), _minh(0) { + LayoutItem(uint64 i_mask) : Interfaces(i_mask), _maxw(0), _minh(0) { } int32 maxWidth() const { @@ -163,12 +161,6 @@ public: virtual DocumentData *getDocument() const { return 0; } - virtual OverviewItemInfo *getOverviewItemInfo() { - return 0; - } - virtual const OverviewItemInfo *getOverviewItemInfo() const { - return 0; - } MsgId msgId() const { const HistoryItem *item = getItem(); return item ? item->id : 0; @@ -182,7 +174,7 @@ protected: class LayoutMediaItem : public LayoutItem { public: - LayoutMediaItem(HistoryItem *parent) : _parent(parent) { + LayoutMediaItem(uint64 i_mask, HistoryItem *parent) : LayoutItem(i_mask), _parent(parent) { } virtual LayoutMediaItem *toLayoutMediaItem() { @@ -202,7 +194,7 @@ protected: class LayoutRadialProgressItem : public LayoutMediaItem { public: - LayoutRadialProgressItem(HistoryItem *parent) : LayoutMediaItem(parent) + LayoutRadialProgressItem(uint64 i_mask, HistoryItem *parent) : LayoutMediaItem(i_mask, parent) , _radial(0) , a_iconOver(0, 0) , _a_iconOver(animation(this, &LayoutRadialProgressItem::step_iconOver)) { @@ -248,7 +240,7 @@ private: class LayoutAbstractFileItem : public LayoutRadialProgressItem { public: - LayoutAbstractFileItem(HistoryItem *parent) : LayoutRadialProgressItem(parent) { + LayoutAbstractFileItem(uint64 i_mask, HistoryItem *parent) : LayoutRadialProgressItem(i_mask, parent) { } protected: @@ -276,7 +268,7 @@ public: }; -class OverviewItemInfo { +class OverviewItemInfo : public BasicInterface { public: OverviewItemInfo() : _top(0) { } @@ -299,16 +291,7 @@ public: virtual void initDimensions(); virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const; - virtual OverviewItemInfo *getOverviewItemInfo() { - return &_info; - } - virtual const OverviewItemInfo *getOverviewItemInfo() const { - return &_info; - } - private: - OverviewItemInfo _info; - QDate _date; QString _text; @@ -374,13 +357,6 @@ public: virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const; virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const; - virtual OverviewItemInfo *getOverviewItemInfo() { - return &_info; - } - virtual const OverviewItemInfo *getOverviewItemInfo() const { - return &_info; - } - protected: virtual float64 dataProgress() const { return _data->progress(); @@ -396,7 +372,6 @@ protected: } private: - OverviewItemInfo _info; AudioData *_data; TextLinkPtr _namel; @@ -419,12 +394,6 @@ public: virtual DocumentData *getDocument() const { return _data; } - virtual OverviewItemInfo *getOverviewItemInfo() { - return &_info; - } - virtual const OverviewItemInfo *getOverviewItemInfo() const { - return &_info; - } protected: virtual float64 dataProgress() const { @@ -441,7 +410,6 @@ protected: } private: - OverviewItemInfo _info; DocumentData *_data; TextLinkPtr _msgl, _namel; @@ -468,15 +436,7 @@ public: virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const; virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const; - virtual OverviewItemInfo *getOverviewItemInfo() { - return &_info; - } - virtual const OverviewItemInfo *getOverviewItemInfo() const { - return &_info; - } - private: - OverviewItemInfo _info; TextLinkPtr _photol; QString _title, _letter; diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 4f8f6dd03c..4c13164d4a 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -355,7 +355,7 @@ void OverviewInner::repaintItem(MsgId itemId, int32 itemIndex) { int32 row = (_photosToAdd + shownAtIndex) / _photosInRow, col = (_photosToAdd + shownAtIndex) % _photosInRow; update(int32(col * w), _marginTop + int32(row * vsize), qCeil(w), vsize); } else { - int32 top = _items.at(itemIndex)->getOverviewItemInfo()->top(); + int32 top = _items.at(itemIndex)->Get()->top(); if (_reversed) top = _height - top; update(_rowsLeft, _marginTop + top, _rowWidth, _items.at(itemIndex)->height()); } @@ -729,7 +729,7 @@ QPoint OverviewInner::mapMouseToItem(QPoint p, MsgId itemId, int32 itemIndex) { p.setX(p.x() - int32(col * w) - st::overviewPhotoSkip); p.setY(p.y() - _marginTop - row * (_rowWidth + st::overviewPhotoSkip) - st::overviewPhotoSkip); } else { - int32 top = _items.at(itemIndex)->getOverviewItemInfo()->top(); + int32 top = _items.at(itemIndex)->Get()->top(); if (_reversed) top = _height - top; p.setY(p.y() - _marginTop - top); } @@ -765,7 +765,7 @@ int32 OverviewInner::itemTop(const FullMsgId &msgId) const { int32 itemIndex = -1; fixItemIndex(itemIndex, (msgId.channel == _channel) ? msgId.msg : ((_migrated && msgId.channel == _migrated->channelId()) ? -msgId.msg : 0)); if (itemIndex >= 0) { - int32 top = _items.at(itemIndex)->getOverviewItemInfo()->top(); + int32 top = _items.at(itemIndex)->Get()->top(); if (_reversed) top = _height - top; return _marginTop + top; } @@ -879,10 +879,10 @@ void OverviewInner::paintEvent(QPaintEvent *e) { int32 y = 0, w = _rowWidth; for (int32 j = 0, l = _items.size(); j < l; ++j) { int32 i = _reversed ? (l - j - 1) : j, nexti = _reversed ? (i - 1) : (i + 1); - int32 nextItemTop = (j + 1 == l) ? (_reversed ? 0 : _height) : _items.at(nexti)->getOverviewItemInfo()->top(); + int32 nextItemTop = (j + 1 == l) ? (_reversed ? 0 : _height) : _items.at(nexti)->Get()->top(); if (_reversed) nextItemTop = _height - nextItemTop; if (_marginTop + nextItemTop > r.top()) { - OverviewItemInfo *info = _items.at(i)->getOverviewItemInfo(); + OverviewItemInfo *info = _items.at(i)->Get(); int32 curY = info->top(); if (_reversed) curY = _height - curY; if (_marginTop + curY >= r.y() + r.height()) break; @@ -944,10 +944,10 @@ void OverviewInner::onUpdateSelected() { for (int32 j = 0, l = _items.size(); j < l; ++j) { bool lastItem = (j + 1 == l); int32 i = _reversed ? (l - j - 1) : j, nexti = _reversed ? (i - 1) : (i + 1); - int32 nextItemTop = lastItem ? (_reversed ? 0 : _height) : _items.at(nexti)->getOverviewItemInfo()->top(); + int32 nextItemTop = lastItem ? (_reversed ? 0 : _height) : _items.at(nexti)->Get()->top(); if (_reversed) nextItemTop = _height - nextItemTop; if (_marginTop + nextItemTop > m.y() || lastItem) { - int32 top = _items.at(i)->getOverviewItemInfo()->top(); + int32 top = _items.at(i)->Get()->top(); if (_reversed) top = _height - top; if (!_items.at(i)->toLayoutMediaItem()) { // day item int32 h = _items.at(i)->height(); @@ -956,11 +956,11 @@ void OverviewInner::onUpdateSelected() { if (i > 0 && (beforeItem || i == _items.size() - 1)) { --i; if (!_items.at(i)->toLayoutMediaItem()) break; // wtf - top = _items.at(i)->getOverviewItemInfo()->top(); + top = _items.at(i)->Get()->top(); } else if (i < _items.size() - 1 && (!beforeItem || !i)) { ++i; if (!_items.at(i)->toLayoutMediaItem()) break; // wtf - top = _items.at(i)->getOverviewItemInfo()->top(); + top = _items.at(i)->Get()->top(); } else { break; // wtf } @@ -1385,7 +1385,7 @@ int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeigh for (int32 i = 0, l = _items.size(); i < l; ++i) { int32 h = _items.at(i)->resizeGetHeight(_rowWidth); if (resize) { - _items.at(i)->getOverviewItemInfo()->setTop(_height + (_reversed ? h : 0)); + _items.at(i)->Get()->setTop(_height + (_reversed ? h : 0)); _height += h; } } @@ -1746,7 +1746,7 @@ void OverviewInner::mediaOverviewUpdated() { if (allGood) { if (_items.size() > index && complexMsgId(_items.at(index)->getItem()) == msgid) { if (withDates) prevDate = _items.at(index)->getItem()->date.date(); - top = _items.at(index)->getOverviewItemInfo()->top(); + top = _items.at(index)->Get()->top(); if (!_reversed) { top += _items.at(index)->height(); } @@ -1756,7 +1756,7 @@ void OverviewInner::mediaOverviewUpdated() { if (_items.size() > index + 1 && !_items.at(index)->toLayoutMediaItem() && complexMsgId(_items.at(index + 1)->getItem()) == msgid) { // day item ++index; if (withDates) prevDate = _items.at(index)->getItem()->date.date(); - top = _items.at(index)->getOverviewItemInfo()->top(); + top = _items.at(index)->Get()->top(); if (!_reversed) { top += _items.at(index)->height(); } @@ -1877,7 +1877,7 @@ void OverviewInner::repaintItem(const HistoryItem *msg) { if (history == _migrated) msgid = -msgid; for (int32 i = 0, l = _items.size(); i != l; ++i) { if (complexMsgId(_items.at(i)->getItem()) == msgid) { - int32 top = _items.at(i)->getOverviewItemInfo()->top(); + int32 top = _items.at(i)->Get()->top(); if (_reversed) top = _height - top; update(_rowsLeft, _marginTop + top, _rowWidth, _items.at(i)->height()); break; @@ -1982,7 +1982,7 @@ int32 OverviewInner::setLayoutItem(int32 index, LayoutItem *item, int32 top) { _items.push_back(item); } int32 h = item->resizeGetHeight(_rowWidth); - if (OverviewItemInfo *info = item->getOverviewItemInfo()) { + if (OverviewItemInfo *info = item->Get()) { info->setTop(top + (_reversed ? h : 0)); } return h; diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 34bd47fba4..1660203d18 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -34,6 +34,39 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "audio.h" #include "localstorage.h" +class InterfacesMetadatasMap : public QMap { +public: + ~InterfacesMetadatasMap() { + for (const_iterator i = cbegin(), e = cend(); i != e; ++i) { + delete i.value(); + } + } +}; + +const InterfacesMetadata *GetInterfacesMetadata(uint64 mask) { + typedef QMap InterfacesMetadatasMap; + static InterfacesMetadatasMap InterfacesMetadatas; + static QMutex InterfacesMetadatasMutex; + + QMutexLocker lock(&InterfacesMetadatasMutex); + InterfacesMetadatasMap::const_iterator i = InterfacesMetadatas.constFind(mask); + if (i == InterfacesMetadatas.cend()) { + InterfacesMetadata *meta = new InterfacesMetadata(mask); + if (!meta) { // terminate if we can't allocate memory + throw "Can't allocate memory!"; + } + + i = InterfacesMetadatas.insert(mask, meta); + } + return i.value(); +} + +InterfaceWrapStruct InterfaceWraps[64] = { + { 0, 0, 0 } +}; + +QAtomicInt InterfaceIndexLast(0); + namespace { int32 peerColorIndex(const PeerId &peer) { int32 myId(MTP::authedId()), peerId(peerToBareInt(peer)); diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 8de9bf0c5d..cdb0fe83b3 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -20,6 +20,159 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org */ #pragma once +class Interfaces; +typedef void(*InterfaceConstruct)(void *location, Interfaces *interfaces); +typedef void(*InterfaceDestruct)(void *location); + +struct InterfaceWrapStruct { + int Size; + InterfaceConstruct Construct; + InterfaceDestruct Destruct; +}; + +template +struct CeilDivideMinimumOne { + static const int Result = ((Value / Denominator) + ((!Value || (Value % Denominator)) ? 1 : 0)); +}; + +template +struct InterfaceWrapTemplate { + static const int Size = CeilDivideMinimumOne::Result * sizeof(uint64); + static void Construct(void *location, Interfaces *interfaces) { + (new (location) Type())->interfaces = interfaces; + } + static void Destruct(void *location) { + ((Type*)location)->~Type(); + } +}; + +extern InterfaceWrapStruct InterfaceWraps[64]; +extern QAtomicInt InterfaceIndexLast; + +template +class BasicInterface { +public: + static int Index() { + static QAtomicInt _index(0); + if (int index = _index.loadAcquire()) { + return index - 1; + } + while (true) { + int last = InterfaceIndexLast.loadAcquire(); + if (InterfaceIndexLast.testAndSetOrdered(last, last + 1)) { + t_assert(last < 64); + if (_index.testAndSetOrdered(0, last + 1)) { + InterfaceWraps[last] = { InterfaceWrapTemplate::Size, InterfaceWrapTemplate::Construct, InterfaceWrapTemplate::Destruct }; + } + break; + } + } + return _index.loadAcquire() - 1; + } + static const uint64 Bit() { + return (1 << Index()); + } + Interfaces *interfaces = 0; +}; + +class InterfacesMetadata { +public: + + InterfacesMetadata(uint64 mask) : _mask(mask), size(0), last(64) { + for (int i = 0; i < 64; ++i) { + uint64 m = (1 << i); + if (_mask & m) { + int s = InterfaceWraps[i].Size; + if (s) { + offsets[i] = size; + size += s; + } else { + offsets[i] = -1; + } + } else if (_mask < m) { + last = i; + for (; i < 64; ++i) { + offsets[i] = -1; + } + } else { + offsets[i] = -1; + } + } + } + + int size, last; + int offsets[64]; + +private: + uint64 _mask; + +}; + +const InterfacesMetadata *GetInterfacesMetadata(uint64 mask); + +class Interfaces { +public: + + Interfaces(uint64 mask = 0) : _meta(GetInterfacesMetadata(mask)), _data(0) { + if (_meta->size) { + _data = malloc(_meta->size); + if (!_data) { // terminate if we can't allocate memory + throw "Can't allocate memory!"; + } + + for (int i = 0; i < _meta->last; ++i) { + int offset = _meta->offsets[i]; + if (offset >= 0) { + try { + InterfaceWraps[i].Construct(_dataptrunsafe(offset), this); + } catch (...) { + while (i > 0) { + --i; + offset = _meta->offsets[--i]; + if (offset >= 0) { + InterfaceWraps[i].Destruct(_dataptrunsafe(offset)); + } + } + throw; + } + } + } + } + } + ~Interfaces() { + if (_data) { + for (int i = 0; i < _meta->last; ++i) { + int offset = _meta->offsets[i]; + if (offset >= 0) { + InterfaceWraps[i].Destruct(_dataptrunsafe(offset)); + } + } + free(_data); + } + } + + template + Type *Get() { + return (Type*)_dataptr(_meta->offsets[Type::Index()]); + } + template + const Type *Get() const { + return (const Type*)_dataptr(_meta->offsets[Type::Index()]); + } + +private: + + void *_dataptrunsafe(int skip) const { + return (char*)_data + skip; + } + void *_dataptr(int skip) const { + return (skip >= 0) ? _dataptrunsafe(skip) : 0; + } + const InterfacesMetadata *_meta; + void *_data; + +}; + typedef int32 ChannelId; static const ChannelId NoChannel = 0;