diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 4cb9c62023..00edb26460 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -315,15 +315,16 @@ namespace Sandbox { t_assert_full(SandboxData != 0, "_data is null in Global::" #Name, __FILE__, __LINE__); \ return SandboxData->Name; \ } -#define DefineSandbox(Type, Name) DefineSandboxReadOnly(Type, Name) \ -void Set##Name(const Type &Name) { \ - t_assert_full(SandboxData != 0, "_data is null in Global::Set" #Name, __FILE__, __LINE__); \ - SandboxData->Name = Name; \ -} \ +#define DefineSandboxRef(Type, Name) DefineSandboxReadOnly(Type, Name) \ Type &Ref##Name() { \ t_assert_full(SandboxData != 0, "_data is null in Global::Ref" #Name, __FILE__, __LINE__); \ return SandboxData->Name; \ } +#define DefineSandbox(Type, Name) DefineSandboxRef(Type, Name) \ +void Set##Name(const Type &Name) { \ + t_assert_full(SandboxData != 0, "_data is null in Global::Set" #Name, __FILE__, __LINE__); \ + SandboxData->Name = Name; \ +} DefineSandboxReadOnly(uint64, LaunchId); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 9797a95f3d..5b14292521 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -123,9 +123,10 @@ namespace Sandbox { void finish(); #define DeclareSandboxReadOnly(Type, Name) const Type &Name(); -#define DeclareSandbox(Type, Name) DeclareSandboxReadOnly(Type, Name) \ - void Set##Name(const Type &Name); \ +#define DeclareSandboxRef(Type, Name) DeclareSandboxReadOnly(Type, Name) \ Type &Ref##Name(); +#define DeclareSandbox(Type, Name) DeclareSandboxRef(Type, Name) \ + void Set##Name(const Type &Name); DeclareSandboxReadOnly(uint64, LaunchId); diff --git a/Telegram/SourceFiles/gui/popupmenu.cpp b/Telegram/SourceFiles/gui/popupmenu.cpp index a2adda19af..e64fe2feb0 100644 --- a/Telegram/SourceFiles/gui/popupmenu.cpp +++ b/Telegram/SourceFiles/gui/popupmenu.cpp @@ -523,22 +523,33 @@ PopupMenu::~PopupMenu() { PopupTooltip *PopupTooltipInstance = 0; -PopupTooltip::PopupTooltip(const QPoint &p, const QString &text, const style::Tooltip &st) : TWidget(0) -, _st(0) { - if (PopupTooltip *instance = PopupTooltipInstance) { - hide(); - deleteLater(); - } else { - PopupTooltipInstance = this; - Sandboxer::installEventFilter(this); - _hideByLeaveTimer.setSingleShot(true); - connect(&_hideByLeaveTimer, SIGNAL(timeout()), this, SLOT(onHideByLeave())); +AbstractTooltipShower::~AbstractTooltipShower() { + if (PopupTooltipInstance && PopupTooltipInstance->_shower == this) { + PopupTooltipInstance->_shower = 0; } +} + +PopupTooltip::PopupTooltip() : TWidget(0) +, _shower(0) +, _st(0) { + PopupTooltipInstance = this; setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::ToolTip | Qt::NoDropShadowWindowHint); setAttribute(Qt::WA_NoSystemBackground, true); - PopupTooltipInstance->popup(p, text, &st); + _showTimer.setSingleShot(true); + connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShow())); +} + +void PopupTooltip::onShow() { + if (_shower) { + QString text = _shower->tooltipText(); + if (text.isEmpty()) { + Hide(); + } else { + PopupTooltipInstance->popup(_shower->tooltipPos(), text, _shower->tooltipSt()); + } + } } bool PopupTooltip::eventFilter(QObject *o, QEvent *e) { @@ -565,6 +576,13 @@ PopupTooltip::~PopupTooltip() { } void PopupTooltip::popup(const QPoint &m, const QString &text, const style::Tooltip *st) { + if (!_hideByLeaveTimer.isSingleShot()) { + _hideByLeaveTimer.setSingleShot(true); + connect(&_hideByLeaveTimer, SIGNAL(timeout()), this, SLOT(onHideByLeave())); + + Sandboxer::installEventFilter(this); + } + _point = m; _st = st; _text = Text(_st->textFont, text, _textPlainOptions, _st->widthMax, true); @@ -631,14 +649,27 @@ void PopupTooltip::paintEvent(QPaintEvent *e) { void PopupTooltip::hideEvent(QHideEvent *e) { if (PopupTooltipInstance == this) { - PopupTooltipInstance = 0; - deleteLater(); + Hide(); + } +} + +void PopupTooltip::Show(int32 delay, const AbstractTooltipShower *shower) { + if (!PopupTooltipInstance) { + new PopupTooltip(); + } + PopupTooltipInstance->_shower = shower; + if (delay >= 0) { + PopupTooltipInstance->_showTimer.start(delay); + } else { + PopupTooltipInstance->onShow(); } } void PopupTooltip::Hide() { if (PopupTooltip *instance = PopupTooltipInstance) { PopupTooltipInstance = 0; + instance->_showTimer.stop(); + instance->_hideByLeaveTimer.stop(); instance->hide(); instance->deleteLater(); } diff --git a/Telegram/SourceFiles/gui/popupmenu.h b/Telegram/SourceFiles/gui/popupmenu.h index 354bf445b1..b0ae5b2dde 100644 --- a/Telegram/SourceFiles/gui/popupmenu.h +++ b/Telegram/SourceFiles/gui/popupmenu.h @@ -108,21 +108,31 @@ private: }; +class AbstractTooltipShower { +public: + virtual QString tooltipText() const = 0; + virtual QPoint tooltipPos() const = 0; + virtual const style::Tooltip *tooltipSt() const { + return &st::defaultTooltip; + } + virtual ~AbstractTooltipShower(); +}; + class PopupTooltip : public TWidget { Q_OBJECT public: - PopupTooltip(const QPoint &p, const QString &text, const style::Tooltip &st = st::defaultTooltip); - bool eventFilter(QObject *o, QEvent *e); + static void Show(int32 delay, const AbstractTooltipShower *shower); static void Hide(); ~PopupTooltip(); public slots: + void onShow(); void onHideByLeave(); protected: @@ -132,8 +142,14 @@ protected: private: + PopupTooltip(); + void popup(const QPoint &p, const QString &text, const style::Tooltip *st); + friend class AbstractTooltipShower; + const AbstractTooltipShower *_shower; + QTimer _showTimer; + Text _text; QPoint _point; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 21c119671e..85b7e90420 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -75,8 +75,6 @@ HistoryInner::HistoryInner(HistoryWidget *historyWidget, ScrollArea *scroll, His , _menu(0) { connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); - _tooltipTimer.setSingleShot(true); - connect(&_tooltipTimer, SIGNAL(timeout()), this, SLOT(showLinkTip())); _touchSelectTimer.setSingleShot(true); connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect())); @@ -1628,12 +1626,12 @@ void HistoryInner::onUpdateSelected() { } } } - if (lnk || cursorState == HistoryInDateCursorState) { - _tooltipTimer.start(1000); - } if (_dragCursorState == HistoryInDateCursorState && cursorState != HistoryInDateCursorState) { PopupTooltip::Hide(); } + if (lnk || cursorState == HistoryInDateCursorState) { + PopupTooltip::Show(1000, this); + } if (_dragAction == NoDrag) { _dragCursorState = cursorState; @@ -1869,15 +1867,20 @@ void HistoryInner::applyDragSelection(SelectedItems *toItems) const { } } -void HistoryInner::showLinkTip() { +QString HistoryInner::tooltipText() const { TextLinkPtr lnk = textlnkOver(); if (lnk && !lnk->fullDisplayed()) { - new PopupTooltip(_dragPos, lnk->readable()); + return lnk->readable(); } else if (_dragCursorState == HistoryInDateCursorState && _dragAction == NoDrag) { if (App::hoveredItem()) { - new PopupTooltip(_dragPos, App::hoveredItem()->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat))); + return App::hoveredItem()->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)); } } + return QString(); +} + +QPoint HistoryInner::tooltipPos() const { + return _dragPos; } void HistoryInner::onParentGeometryChanged() { @@ -2017,9 +2020,6 @@ BotKeyboard::BotKeyboard() : TWidget() setGeometry(0, 0, _st->margin, _st->margin); _height = _st->margin; setMouseTracking(true); - - _cmdTipTimer.setSingleShot(true); - connect(&_cmdTipTimer, SIGNAL(timeout()), this, SLOT(showCommandTip())); } void BotKeyboard::paintEvent(QPaintEvent *e) { @@ -2259,17 +2259,22 @@ void BotKeyboard::clearSelection() { } } -void BotKeyboard::showCommandTip() { +QPoint BotKeyboard::tooltipPos() const { + return _lastMousePos; +} + +QString BotKeyboard::tooltipText() const { if (_sel >= 0) { int row = (_sel / MatrixRowShift), col = _sel % MatrixRowShift; if (!_btns.at(row).at(col).full) { - new PopupTooltip(_lastMousePos, _btns.at(row).at(col).cmd); + return _btns.at(row).at(col).cmd; } } + return QString(); } void BotKeyboard::updateSelected() { - _cmdTipTimer.start(1000); + PopupTooltip::Show(1000, this); if (_down >= 0) return; diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 6aae8e548e..94c5ad30da 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -33,7 +33,7 @@ enum DragState { }; class HistoryWidget; -class HistoryInner : public TWidget { +class HistoryInner : public TWidget, public AbstractTooltipShower { Q_OBJECT public: @@ -97,6 +97,10 @@ public: void notifyIsBotChanged(); void notifyMigrateUpdated(); + // AbstractTooltipShower + virtual QString tooltipText() const; + virtual QPoint tooltipPos() const; + ~HistoryInner(); public slots: @@ -104,8 +108,6 @@ public slots: void onUpdateSelected(); void onParentGeometryChanged(); - void showLinkTip(); - void openContextUrl(); void copyContextUrl(); void saveContextImage(); @@ -150,8 +152,6 @@ private: bool _firstLoading; - QTimer _tooltipTimer; - Qt::CursorShape _cursor; typedef QMap SelectedItems; SelectedItems _selected; @@ -249,7 +249,7 @@ private: }; -class BotKeyboard : public TWidget { +class BotKeyboard : public TWidget, public AbstractTooltipShower { Q_OBJECT public: @@ -277,9 +277,12 @@ public: return _wasForMsgId; } + // AbstractTooltipShower + virtual QString tooltipText() const; + virtual QPoint tooltipPos() const; + public slots: - void showCommandTip(); void updateSelected(); private: @@ -290,7 +293,6 @@ private: FullMsgId _wasForMsgId; int32 _height, _maxOuterHeight; bool _maximizeSize, _singleUse, _forceReply; - QTimer _cmdTipTimer; QPoint _lastMousePos; struct Button { diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 8eefed34f1..2ddf41cb03 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -91,8 +91,6 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD App::contextItem(0); - _linkTipTimer.setSingleShot(true); - connect(&_linkTipTimer, SIGNAL(timeout()), this, SLOT(showLinkTip())); _touchSelectTimer.setSingleShot(true); connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect())); @@ -1024,7 +1022,7 @@ void OverviewInner::onUpdateSelected() { _cursorState = cursorState; } if (lnk || cursorState == HistoryInDateCursorState) { - _linkTipTimer.start(1000); + PopupTooltip::Show(1000, this); } fixItemIndex(_dragItemIndex, _dragItem); @@ -1139,16 +1137,20 @@ void OverviewInner::onUpdateSelected() { } } +QPoint OverviewInner::tooltipPos() const { + return _dragPos; +} -void OverviewInner::showLinkTip() { +QString OverviewInner::tooltipText() const { TextLinkPtr lnk = textlnkOver(); if (lnk && !lnk->fullDisplayed()) { - new PopupTooltip(_dragPos, lnk->readable()); + return lnk->readable(); } else if (_cursorState == HistoryInDateCursorState && _dragAction == NoDrag && _mousedItem) { if (HistoryItem *item = App::histItemById(itemChannel(_mousedItem), itemMsgId(_mousedItem))) { - new PopupTooltip(_dragPos, item->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat))); + return item->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)); } } + return QString(); } void OverviewInner::updateDragSelection(MsgId dragSelFrom, int32 dragSelFromIndex, MsgId dragSelTo, int32 dragSelToIndex, bool dragSelecting) { diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index 62ea9d915e..d2740e0441 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -21,7 +21,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #pragma once class OverviewWidget; -class OverviewInner : public QWidget, public RPCSender { +class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender { Q_OBJECT public: @@ -76,12 +76,15 @@ public: void clearSelectedItems(bool onlyTextSelection = false); void fillSelectedItems(SelectedItemSet &sel, bool forDelete = true); + // AbstractTooltipShower + virtual QString tooltipText() const; + virtual QPoint tooltipPos() const; + ~OverviewInner(); public slots: void onUpdateSelected(); - void showLinkTip(); void openContextUrl(); void copyContextUrl(); diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 81c7e8568b..34bd47fba4 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -34,37 +34,6 @@ 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]; - -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 5655fafa54..8de9bf0c5d 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -20,174 +20,6 @@ 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 { - InterfaceWrapStruct() : Size(0), Construct(0), Destruct(0) { - } - InterfaceWrapStruct(int size, InterfaceConstruct construct, InterfaceDestruct destruct) - : Size(size) - , Construct(construct) - , Destruct(destruct) { - } - 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); - } - 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] = InterfaceWrapStruct(InterfaceWrapTemplate::Size, InterfaceWrapTemplate::Construct, InterfaceWrapTemplate::Destruct); - } - break; - } - } - return _index.loadAcquire() - 1; - } - static uint64 Bit() { - return (1 << Index()); - } - -}; - -template -class BasicInterfaceWithPointer : public BasicInterface { -public: - BasicInterfaceWithPointer(Interfaces *interfaces) : interfaces(interfaces) { - } - Interfaces *interfaces = 0; -}; - -class InterfacesMetadata { -public: - - InterfacesMetadata(uint64 mask) : size(0), last(64), _mask(mask) { - 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; diff --git a/Telegram/SourceFiles/types.cpp b/Telegram/SourceFiles/types.cpp index 18ffcc395a..15039a9b3c 100644 --- a/Telegram/SourceFiles/types.cpp +++ b/Telegram/SourceFiles/types.cpp @@ -1016,3 +1016,34 @@ MimeType mimeTypeForData(const QByteArray &data) { } return MimeType(QMimeDatabase().mimeTypeForData(data)); } + +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]; + +QAtomicInt InterfaceIndexLast(0); diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h index d7043d70bb..7c47cca8fd 100644 --- a/Telegram/SourceFiles/types.h +++ b/Telegram/SourceFiles/types.h @@ -529,6 +529,174 @@ inline void destroyImplementation(I *&ptr) { deleteAndMark(ptr); } +class Interfaces; +typedef void(*InterfaceConstruct)(void *location, Interfaces *interfaces); +typedef void(*InterfaceDestruct)(void *location); + +struct InterfaceWrapStruct { + InterfaceWrapStruct() : Size(0), Construct(0), Destruct(0) { + } + InterfaceWrapStruct(int size, InterfaceConstruct construct, InterfaceDestruct destruct) + : Size(size) + , Construct(construct) + , Destruct(destruct) { + } + 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); + } + 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] = InterfaceWrapStruct(InterfaceWrapTemplate::Size, InterfaceWrapTemplate::Construct, InterfaceWrapTemplate::Destruct); + } + break; + } + } + return _index.loadAcquire() - 1; + } + static uint64 Bit() { + return (1 << Index()); + } + +}; + +template +class BasicInterfaceWithPointer : public BasicInterface { +public: + BasicInterfaceWithPointer(Interfaces *interfaces) : interfaces(interfaces) { + } + Interfaces *interfaces = 0; +}; + +class InterfacesMetadata { +public: + + InterfacesMetadata(uint64 mask) : size(0), last(64), _mask(mask) { + 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; + +}; + template class FunctionImplementation { public: