mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 10:11:41 -05:00
950 lines
25 KiB
C++
950 lines
25 KiB
C++
/*
|
|
This file is part of Telegram Desktop,
|
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
|
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
It 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 General Public License for more details.
|
|
|
|
In addition, as a special exception, the copyright holders give permission
|
|
to link the code of portions of this program with the OpenSSL library.
|
|
|
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|
*/
|
|
#pragma once
|
|
|
|
template <typename T>
|
|
void deleteAndMark(T *&link) {
|
|
delete link;
|
|
link = reinterpret_cast<T*>(0x00000BAD);
|
|
}
|
|
|
|
template <typename T>
|
|
T *exchange(T *&ptr) {
|
|
T *result = 0;
|
|
qSwap(result, ptr);
|
|
return result;
|
|
}
|
|
|
|
struct NullType {
|
|
};
|
|
|
|
template <typename T>
|
|
class OrderedSet : public QMap<T, NullType> {
|
|
public:
|
|
|
|
void insert(const T &v) {
|
|
QMap<T, NullType>::insert(v, NullType());
|
|
}
|
|
|
|
};
|
|
|
|
//typedef unsigned char uchar; // Qt has uchar
|
|
typedef qint16 int16;
|
|
typedef quint16 uint16;
|
|
typedef qint32 int32;
|
|
typedef quint32 uint32;
|
|
typedef qint64 int64;
|
|
typedef quint64 uint64;
|
|
|
|
static const int32 ScrollMax = INT_MAX;
|
|
|
|
extern uint64 _SharedMemoryLocation[];
|
|
template <typename T, unsigned int N>
|
|
T *SharedMemoryLocation() {
|
|
static_assert(N < 4, "Only 4 shared memory locations!");
|
|
return reinterpret_cast<T*>(_SharedMemoryLocation + N);
|
|
}
|
|
|
|
#ifdef Q_OS_WIN
|
|
typedef float float32;
|
|
typedef double float64;
|
|
#else
|
|
typedef float float32;
|
|
typedef double float64;
|
|
#endif
|
|
|
|
#include <string>
|
|
#include <exception>
|
|
|
|
#include <QtCore/QReadWriteLock>
|
|
|
|
#include <ctime>
|
|
|
|
using std::string;
|
|
using std::exception;
|
|
using std::swap;
|
|
|
|
#include "logs.h"
|
|
|
|
static volatile int *t_assert_nullptr = 0;
|
|
inline void t_noop() {}
|
|
inline void t_assert_fail(const char *message, const char *file, int32 line) {
|
|
LOG(("Assertion Failed! %1 %2:%3").arg(message).arg(file).arg(line));
|
|
*t_assert_nullptr = 0;
|
|
}
|
|
#define t_assert_full(condition, message, file, line) ((!(condition)) ? t_assert_fail(message, file, line) : t_noop())
|
|
#define t_assert_c(condition, comment) t_assert_full(condition, "\"" #condition "\" (" comment ")", __FILE__, __LINE__)
|
|
#define t_assert(condition) t_assert_full(condition, "\"" #condition "\"", __FILE__, __LINE__)
|
|
|
|
class Exception : public exception {
|
|
public:
|
|
|
|
Exception(const QString &msg, bool isFatal = true) : _fatal(isFatal), _msg(msg.toUtf8()) {
|
|
LOG(("Exception: %1").arg(msg));
|
|
}
|
|
bool fatal() const {
|
|
return _fatal;
|
|
}
|
|
|
|
virtual const char *what() const throw() {
|
|
return _msg.constData();
|
|
}
|
|
virtual ~Exception() throw() {
|
|
}
|
|
|
|
private:
|
|
bool _fatal;
|
|
QByteArray _msg;
|
|
};
|
|
|
|
class MTPint;
|
|
|
|
int32 myunixtime();
|
|
void unixtimeInit();
|
|
void unixtimeSet(int32 servertime, bool force = false);
|
|
int32 unixtime();
|
|
int32 fromServerTime(const MTPint &serverTime);
|
|
uint64 msgid();
|
|
int32 reqid();
|
|
|
|
inline QDateTime date(int32 time = -1) {
|
|
QDateTime result;
|
|
if (time >= 0) result.setTime_t(time);
|
|
return result;
|
|
}
|
|
|
|
inline QDateTime date(const MTPint &time) {
|
|
return date(fromServerTime(time));
|
|
}
|
|
|
|
inline void mylocaltime(struct tm * _Tm, const time_t * _Time) {
|
|
#ifdef Q_OS_WIN
|
|
localtime_s(_Tm, _Time);
|
|
#else
|
|
localtime_r(_Time, _Tm);
|
|
#endif
|
|
}
|
|
|
|
namespace ThirdParty {
|
|
|
|
void start();
|
|
void finish();
|
|
|
|
}
|
|
|
|
bool checkms(); // returns true if time has changed
|
|
uint64 getms(bool checked = false);
|
|
|
|
class SingleTimer : public QTimer { // single shot timer with check
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
SingleTimer();
|
|
|
|
void setSingleShot(bool); // is not available
|
|
void start(); // is not available
|
|
|
|
public slots:
|
|
|
|
void start(int msec);
|
|
void startIfNotActive(int msec);
|
|
void adjust() {
|
|
uint64 n = getms(true);
|
|
if (isActive()) {
|
|
if (n >= _finishing) {
|
|
start(0);
|
|
} else {
|
|
start(_finishing - n);
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
uint64 _finishing;
|
|
bool _inited;
|
|
|
|
};
|
|
|
|
const static uint32 _md5_block_size = 64;
|
|
class HashMd5 {
|
|
public:
|
|
|
|
HashMd5(const void *input = 0, uint32 length = 0);
|
|
void feed(const void *input, uint32 length);
|
|
int32 *result();
|
|
|
|
private:
|
|
|
|
void init();
|
|
void finalize();
|
|
void transform(const uchar *block);
|
|
|
|
bool _finalized;
|
|
uchar _buffer[_md5_block_size];
|
|
uint32 _count[2];
|
|
uint32 _state[4];
|
|
uchar _digest[16];
|
|
|
|
};
|
|
|
|
int32 hashCrc32(const void *data, uint32 len);
|
|
int32 *hashSha1(const void *data, uint32 len, void *dest); // dest - ptr to 20 bytes, returns (int32*)dest
|
|
int32 *hashSha256(const void *data, uint32 len, void *dest); // dest - ptr to 32 bytes, returns (int32*)dest
|
|
int32 *hashMd5(const void *data, uint32 len, void *dest); // dest = ptr to 16 bytes, returns (int32*)dest
|
|
char *hashMd5Hex(const int32 *hashmd5, void *dest); // dest = ptr to 32 bytes, returns (char*)dest
|
|
inline char *hashMd5Hex(const void *data, uint32 len, void *dest) { // dest = ptr to 32 bytes, returns (char*)dest
|
|
return hashMd5Hex(HashMd5(data, len).result(), dest);
|
|
}
|
|
|
|
void memset_rand(void *data, uint32 len);
|
|
|
|
template <typename T>
|
|
inline void memsetrnd(T &value) {
|
|
memset_rand(&value, sizeof(value));
|
|
}
|
|
|
|
class ReadLockerAttempt {
|
|
public:
|
|
|
|
ReadLockerAttempt(QReadWriteLock *_lock) : success(_lock->tryLockForRead()), lock(_lock) {
|
|
}
|
|
~ReadLockerAttempt() {
|
|
if (success) {
|
|
lock->unlock();
|
|
}
|
|
}
|
|
|
|
operator bool() const {
|
|
return success;
|
|
}
|
|
|
|
private:
|
|
|
|
bool success;
|
|
QReadWriteLock *lock;
|
|
|
|
};
|
|
|
|
#define qsl(s) QStringLiteral(s)
|
|
#define qstr(s) QLatin1String(s, sizeof(s) - 1)
|
|
|
|
inline QString fromUtf8Safe(const char *str, int32 size = -1) {
|
|
if (!str || !size) return QString();
|
|
if (size < 0) size = int32(strlen(str));
|
|
QString result(QString::fromUtf8(str, size));
|
|
QByteArray back = result.toUtf8();
|
|
if (back.size() != size || memcmp(back.constData(), str, size)) return QString::fromLocal8Bit(str, size);
|
|
return result;
|
|
}
|
|
|
|
inline QString fromUtf8Safe(const QByteArray &str) {
|
|
return fromUtf8Safe(str.constData(), str.size());
|
|
}
|
|
|
|
static const QRegularExpression::PatternOptions reMultiline(QRegularExpression::DotMatchesEverythingOption | QRegularExpression::MultilineOption);
|
|
|
|
template <typename T>
|
|
inline T snap(const T &v, const T &_min, const T &_max) {
|
|
return (v < _min) ? _min : ((v > _max) ? _max : v);
|
|
}
|
|
|
|
template <typename T>
|
|
class ManagedPtr {
|
|
public:
|
|
ManagedPtr() : ptr(0) {
|
|
}
|
|
ManagedPtr(T *p) : ptr(p) {
|
|
}
|
|
T *operator->() const {
|
|
return ptr;
|
|
}
|
|
T *v() const {
|
|
return ptr;
|
|
}
|
|
|
|
protected:
|
|
|
|
T *ptr;
|
|
typedef ManagedPtr<T> Parent;
|
|
};
|
|
|
|
QString translitRusEng(const QString &rus);
|
|
QString rusKeyboardLayoutSwitch(const QString &from);
|
|
|
|
enum DataBlockId {
|
|
dbiKey = 0x00,
|
|
dbiUser = 0x01,
|
|
dbiDcOptionOld = 0x02,
|
|
dbiMaxGroupCount = 0x03,
|
|
dbiMutePeer = 0x04,
|
|
dbiSendKey = 0x05,
|
|
dbiAutoStart = 0x06,
|
|
dbiStartMinimized = 0x07,
|
|
dbiSoundNotify = 0x08,
|
|
dbiWorkMode = 0x09,
|
|
dbiSeenTrayTooltip = 0x0a,
|
|
dbiDesktopNotify = 0x0b,
|
|
dbiAutoUpdate = 0x0c,
|
|
dbiLastUpdateCheck = 0x0d,
|
|
dbiWindowPosition = 0x0e,
|
|
dbiConnectionType = 0x0f,
|
|
// 0x10 reserved
|
|
dbiDefaultAttach = 0x11,
|
|
dbiCatsAndDogs = 0x12,
|
|
dbiReplaceEmojis = 0x13,
|
|
dbiAskDownloadPath = 0x14,
|
|
dbiDownloadPathOld = 0x15,
|
|
dbiScale = 0x16,
|
|
dbiEmojiTabOld = 0x17,
|
|
dbiRecentEmojisOld = 0x18,
|
|
dbiLoggedPhoneNumber = 0x19,
|
|
dbiMutedPeers = 0x1a,
|
|
// 0x1b reserved
|
|
dbiNotifyView = 0x1c,
|
|
dbiSendToMenu = 0x1d,
|
|
dbiCompressPastedImage = 0x1e,
|
|
dbiLang = 0x1f,
|
|
dbiLangFile = 0x20,
|
|
dbiTileBackground = 0x21,
|
|
dbiAutoLock = 0x22,
|
|
dbiDialogLastPath = 0x23,
|
|
dbiRecentEmojis = 0x24,
|
|
dbiEmojiVariants = 0x25,
|
|
dbiRecentStickers = 0x26,
|
|
dbiDcOption = 0x27,
|
|
dbiTryIPv6 = 0x28,
|
|
dbiSongVolume = 0x29,
|
|
dbiWindowsNotifications = 0x30,
|
|
dbiIncludeMuted = 0x31,
|
|
dbiMaxMegaGroupCount = 0x32,
|
|
dbiDownloadPath = 0x33,
|
|
dbiAutoDownload = 0x34,
|
|
dbiSavedGifsLimit = 0x35,
|
|
dbiShowingSavedGifs = 0x36,
|
|
dbiAutoPlay = 0x37,
|
|
|
|
dbiEncryptedWithSalt = 333,
|
|
dbiEncrypted = 444,
|
|
|
|
// 500-600 reserved
|
|
|
|
dbiVersion = 666,
|
|
};
|
|
|
|
enum DBISendKey {
|
|
dbiskEnter = 0,
|
|
dbiskCtrlEnter = 1,
|
|
};
|
|
|
|
enum DBINotifyView {
|
|
dbinvShowPreview = 0,
|
|
dbinvShowName = 1,
|
|
dbinvShowNothing = 2,
|
|
};
|
|
|
|
enum DBIWorkMode {
|
|
dbiwmWindowAndTray = 0,
|
|
dbiwmTrayOnly = 1,
|
|
dbiwmWindowOnly = 2,
|
|
};
|
|
|
|
enum DBIConnectionType {
|
|
dbictAuto = 0,
|
|
dbictHttpAuto = 1, // not used
|
|
dbictHttpProxy = 2,
|
|
dbictTcpProxy = 3,
|
|
};
|
|
|
|
enum DBIDefaultAttach {
|
|
dbidaDocument = 0,
|
|
dbidaPhoto = 1,
|
|
};
|
|
|
|
struct ConnectionProxy {
|
|
ConnectionProxy() : port(0) {
|
|
}
|
|
QString host;
|
|
uint32 port;
|
|
QString user, password;
|
|
};
|
|
|
|
enum DBIScale {
|
|
dbisAuto = 0,
|
|
dbisOne = 1,
|
|
dbisOneAndQuarter = 2,
|
|
dbisOneAndHalf = 3,
|
|
dbisTwo = 4,
|
|
|
|
dbisScaleCount = 5,
|
|
};
|
|
|
|
static const int MatrixRowShift = 40000;
|
|
|
|
enum DBIEmojiTab {
|
|
dbietRecent = -1,
|
|
dbietPeople = 0,
|
|
dbietNature = 1,
|
|
dbietFood = 2,
|
|
dbietActivity = 3,
|
|
dbietTravel = 4,
|
|
dbietObjects = 5,
|
|
dbietSymbols = 6,
|
|
dbietStickers = 666,
|
|
};
|
|
static const int emojiTabCount = 8;
|
|
inline DBIEmojiTab emojiTabAtIndex(int index) {
|
|
return (index < 0 || index >= emojiTabCount) ? dbietRecent : DBIEmojiTab(index - 1);
|
|
}
|
|
|
|
enum DBIPlatform {
|
|
dbipWindows = 0,
|
|
dbipMac = 1,
|
|
dbipLinux64 = 2,
|
|
dbipLinux32 = 3,
|
|
dbipMacOld = 4,
|
|
};
|
|
|
|
enum DBIPeerReportSpamStatus {
|
|
dbiprsNoButton,
|
|
dbiprsUnknown,
|
|
dbiprsShowButton,
|
|
dbiprsReportSent,
|
|
};
|
|
|
|
typedef enum {
|
|
HitTestNone = 0,
|
|
HitTestClient,
|
|
HitTestSysButton,
|
|
HitTestIcon,
|
|
HitTestCaption,
|
|
HitTestTop,
|
|
HitTestTopRight,
|
|
HitTestRight,
|
|
HitTestBottomRight,
|
|
HitTestBottom,
|
|
HitTestBottomLeft,
|
|
HitTestLeft,
|
|
HitTestTopLeft,
|
|
} HitTestType;
|
|
|
|
inline QString strMakeFromLetters(const uint32 *letters, int32 len) {
|
|
QString result;
|
|
result.reserve(len);
|
|
for (int32 i = 0; i < len; ++i) {
|
|
result.push_back(QChar((((letters[i] << 16) & 0xFF) >> 8) | (letters[i] & 0xFF)));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
class MimeType {
|
|
public:
|
|
|
|
enum TypeEnum {
|
|
Unknown,
|
|
WebP,
|
|
};
|
|
|
|
MimeType(const QMimeType &type) : _typeStruct(type), _type(Unknown) {
|
|
}
|
|
MimeType(TypeEnum type) : _type(type) {
|
|
}
|
|
QStringList globPatterns() const;
|
|
QString filterString() const;
|
|
QString name() const;
|
|
|
|
private:
|
|
|
|
QMimeType _typeStruct;
|
|
TypeEnum _type;
|
|
|
|
};
|
|
|
|
MimeType mimeTypeForName(const QString &mime);
|
|
MimeType mimeTypeForFile(const QFileInfo &file);
|
|
MimeType mimeTypeForData(const QByteArray &data);
|
|
|
|
inline int32 rowscount(int32 count, int32 perrow) {
|
|
return (count + perrow - 1) / perrow;
|
|
}
|
|
inline int32 floorclamp(int32 value, int32 step, int32 lowest, int32 highest) {
|
|
return qMin(qMax(value / step, lowest), highest);
|
|
}
|
|
inline int32 floorclamp(float64 value, int32 step, int32 lowest, int32 highest) {
|
|
return qMin(qMax(qFloor(value / step), lowest), highest);
|
|
}
|
|
inline int32 ceilclamp(int32 value, int32 step, int32 lowest, int32 highest) {
|
|
return qMax(qMin((value / step) + ((value % step) ? 1 : 0), highest), lowest);
|
|
}
|
|
inline int32 ceilclamp(float64 value, int32 step, int32 lowest, int32 highest) {
|
|
return qMax(qMin(qCeil(value / step), highest), lowest);
|
|
}
|
|
|
|
enum ForwardWhatMessages {
|
|
ForwardSelectedMessages,
|
|
ForwardContextMessage,
|
|
ForwardPressedMessage,
|
|
ForwardPressedLinkMessage
|
|
};
|
|
|
|
enum ShowLayerOption {
|
|
CloseOtherLayers = 0x00,
|
|
KeepOtherLayers = 0x01,
|
|
ShowAfterOtherLayers = 0x03,
|
|
|
|
AnimatedShowLayer = 0x00,
|
|
ForceFastShowLayer = 0x04,
|
|
};
|
|
typedef QFlags<ShowLayerOption> ShowLayerOptions;
|
|
|
|
static int32 FullArcLength = 360 * 16;
|
|
static int32 QuarterArcLength = (FullArcLength / 4);
|
|
static int32 MinArcLength = (FullArcLength / 360);
|
|
static int32 AlmostFullArcLength = (FullArcLength - MinArcLength);
|
|
|
|
template <typename I>
|
|
inline void destroyImplementation(I *&ptr) {
|
|
if (ptr) {
|
|
ptr->destroy();
|
|
ptr = 0;
|
|
}
|
|
deleteAndMark(ptr);
|
|
}
|
|
|
|
class Interfaces;
|
|
typedef void(*InterfaceConstruct)(void *location, Interfaces *interfaces);
|
|
typedef void(*InterfaceDestruct)(void *location);
|
|
typedef void(*InterfaceAssign)(void *location, void *waslocation);
|
|
|
|
struct InterfaceWrapStruct {
|
|
InterfaceWrapStruct() : Size(0), Construct(0), Destruct(0) {
|
|
}
|
|
InterfaceWrapStruct(int size, InterfaceConstruct construct, InterfaceDestruct destruct, InterfaceAssign assign)
|
|
: Size(size)
|
|
, Construct(construct)
|
|
, Destruct(destruct)
|
|
, Assign(assign) {
|
|
}
|
|
int Size;
|
|
InterfaceConstruct Construct;
|
|
InterfaceDestruct Destruct;
|
|
InterfaceAssign Assign;
|
|
};
|
|
|
|
template <int Value, int Denominator>
|
|
struct CeilDivideMinimumOne {
|
|
static const int Result = ((Value / Denominator) + ((!Value || (Value % Denominator)) ? 1 : 0));
|
|
};
|
|
|
|
template <typename Type>
|
|
struct InterfaceWrapTemplate {
|
|
static const int Size = CeilDivideMinimumOne<sizeof(Type), sizeof(uint64)>::Result * sizeof(uint64);
|
|
static void Construct(void *location, Interfaces *interfaces) {
|
|
new (location) Type(interfaces);
|
|
}
|
|
static void Destruct(void *location) {
|
|
((Type*)location)->~Type();
|
|
}
|
|
static void Assign(void *location, void *waslocation) {
|
|
*((Type*)location) = *((Type*)waslocation);
|
|
}
|
|
};
|
|
|
|
extern InterfaceWrapStruct InterfaceWraps[64];
|
|
extern QAtomicInt InterfaceIndexLast;
|
|
|
|
template <typename Type>
|
|
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<Type>::Size, InterfaceWrapTemplate<Type>::Construct, InterfaceWrapTemplate<Type>::Destruct, InterfaceWrapTemplate<Type>::Assign);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return _index.loadAcquire() - 1;
|
|
}
|
|
static uint64 Bit() {
|
|
return (1 << Index());
|
|
}
|
|
|
|
};
|
|
|
|
template <typename Type>
|
|
class BasicInterfaceWithPointer : public BasicInterface<Type> {
|
|
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];
|
|
|
|
bool equals(const uint64 &mask) const {
|
|
return _mask == mask;
|
|
}
|
|
|
|
private:
|
|
uint64 _mask;
|
|
|
|
};
|
|
|
|
const InterfacesMetadata *GetInterfacesMetadata(uint64 mask);
|
|
|
|
class Interfaces {
|
|
public:
|
|
|
|
Interfaces(uint64 mask = 0) : _data(zerodata()) {
|
|
if (mask) {
|
|
const InterfacesMetadata *meta = GetInterfacesMetadata(mask);
|
|
int32 size = sizeof(const InterfacesMetadata *) + meta->size;
|
|
void *data = malloc(size);
|
|
if (!data) { // terminate if we can't allocate memory
|
|
throw "Can't allocate memory!";
|
|
}
|
|
|
|
_data = data;
|
|
_meta() = meta;
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void UpdateInterfaces(uint64 mask = 0) {
|
|
if (!_meta()->equals(mask)) {
|
|
Interfaces tmp(mask);
|
|
tmp.swap(*this);
|
|
|
|
if (_data != zerodata() && tmp._data != zerodata()) {
|
|
const InterfacesMetadata *meta = _meta(), *wasmeta = tmp._meta();
|
|
for (int i = 0; i < meta->last; ++i) {
|
|
int offset = meta->offsets[i], wasoffset = wasmeta->offsets[i];
|
|
if (offset >= 0 && wasoffset >= 0) {
|
|
InterfaceWraps[i].Assign(_dataptrunsafe(offset), tmp._dataptrunsafe(wasoffset));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
~Interfaces() {
|
|
if (_data != zerodata()) {
|
|
const InterfacesMetadata *meta = _meta();
|
|
for (int i = 0; i < meta->last; ++i) {
|
|
int offset = meta->offsets[i];
|
|
if (offset >= 0) {
|
|
InterfaceWraps[i].Destruct(_dataptrunsafe(offset));
|
|
}
|
|
}
|
|
free(_data);
|
|
}
|
|
}
|
|
|
|
template <typename Type>
|
|
Type *Get() {
|
|
return static_cast<Type*>(_dataptr(_meta()->offsets[Type::Index()]));
|
|
}
|
|
template <typename Type>
|
|
const Type *Get() const {
|
|
return static_cast<const Type*>(_dataptr(_meta()->offsets[Type::Index()]));
|
|
}
|
|
|
|
private:
|
|
static const InterfacesMetadata *ZeroInterfacesMetadata;
|
|
static void *zerodata() {
|
|
return &ZeroInterfacesMetadata;
|
|
}
|
|
|
|
void *_dataptrunsafe(int skip) const {
|
|
return (char*)_data + sizeof(const InterfacesMetadata*) + skip;
|
|
}
|
|
void *_dataptr(int skip) const {
|
|
return (skip >= 0) ? _dataptrunsafe(skip) : 0;
|
|
}
|
|
const InterfacesMetadata *&_meta() const {
|
|
return *static_cast<const InterfacesMetadata**>(_data);
|
|
}
|
|
void *_data;
|
|
|
|
Interfaces(const Interfaces &other);
|
|
Interfaces &operator=(const Interfaces &other);
|
|
|
|
void swap(Interfaces &other) {
|
|
std::swap(_data, other._data);
|
|
}
|
|
|
|
};
|
|
|
|
template <typename R>
|
|
class FunctionImplementation {
|
|
public:
|
|
virtual R call() = 0;
|
|
virtual void destroy() { delete this; }
|
|
virtual ~FunctionImplementation() {}
|
|
};
|
|
template <typename R>
|
|
class NullFunctionImplementation : public FunctionImplementation<R> {
|
|
public:
|
|
virtual R call() { return R(); }
|
|
virtual void destroy() {}
|
|
static NullFunctionImplementation<R> SharedInstance;
|
|
};
|
|
template <typename R>
|
|
NullFunctionImplementation<R> NullFunctionImplementation<R>::SharedInstance;
|
|
template <typename R>
|
|
class FunctionCreator {
|
|
public:
|
|
FunctionCreator(FunctionImplementation<R> *ptr) : _ptr(ptr) {}
|
|
FunctionCreator(const FunctionCreator<R> &other) : _ptr(other.create()) {}
|
|
FunctionImplementation<R> *create() const { return exchange(_ptr); }
|
|
~FunctionCreator() { destroyImplementation(_ptr); }
|
|
private:
|
|
FunctionCreator<R> &operator=(const FunctionCreator<R> &other);
|
|
mutable FunctionImplementation<R> *_ptr;
|
|
};
|
|
template <typename R>
|
|
class Function {
|
|
public:
|
|
typedef FunctionCreator<R> Creator;
|
|
static Creator Null() { return Creator(&NullFunctionImplementation<R>::SharedInstance); }
|
|
Function(const Creator &creator) : _implementation(creator.create()) {}
|
|
R call() { return _implementation->call(); }
|
|
~Function() { destroyImplementation(_implementation); }
|
|
private:
|
|
Function(const Function<R> &other);
|
|
Function<R> &operator=(const Function<R> &other);
|
|
FunctionImplementation<R> *_implementation;
|
|
};
|
|
|
|
template <typename R>
|
|
class WrappedFunction : public FunctionImplementation<R> {
|
|
public:
|
|
typedef R(*Method)();
|
|
WrappedFunction(Method method) : _method(method) {}
|
|
virtual R call() { return (*_method)(); }
|
|
private:
|
|
Method _method;
|
|
};
|
|
template <typename R>
|
|
inline FunctionCreator<R> func(R(*method)()) {
|
|
return FunctionCreator<R>(new WrappedFunction<R>(method));
|
|
}
|
|
template <typename O, typename I, typename R>
|
|
class ObjectFunction : public FunctionImplementation<R> {
|
|
public:
|
|
typedef R(I::*Method)();
|
|
ObjectFunction(O *obj, Method method) : _obj(obj), _method(method) {}
|
|
virtual R call() { return (_obj->*_method)(); }
|
|
private:
|
|
O *_obj;
|
|
Method _method;
|
|
};
|
|
template <typename O, typename I, typename R>
|
|
inline FunctionCreator<R> func(O *obj, R(I::*method)()) {
|
|
return FunctionCreator<R>(new ObjectFunction<O, I, R>(obj, method));
|
|
}
|
|
|
|
template <typename R, typename A1>
|
|
class Function1Implementation {
|
|
public:
|
|
virtual R call(A1 a1) = 0;
|
|
virtual void destroy() { delete this; }
|
|
virtual ~Function1Implementation() {}
|
|
};
|
|
template <typename R, typename A1>
|
|
class NullFunction1Implementation : public Function1Implementation<R, A1> {
|
|
public:
|
|
virtual R call(A1 a1) { return R(); }
|
|
virtual void destroy() {}
|
|
static NullFunction1Implementation<R, A1> SharedInstance;
|
|
};
|
|
template <typename R, typename A1>
|
|
NullFunction1Implementation<R, A1> NullFunction1Implementation<R, A1>::SharedInstance;
|
|
template <typename R, typename A1>
|
|
class Function1Creator {
|
|
public:
|
|
Function1Creator(Function1Implementation<R, A1> *ptr) : _ptr(ptr) {}
|
|
Function1Creator(const Function1Creator<R, A1> &other) : _ptr(other.create()) {}
|
|
Function1Implementation<R, A1> *create() const { return exchange(_ptr); }
|
|
~Function1Creator() { destroyImplementation(_ptr); }
|
|
private:
|
|
Function1Creator<R, A1> &operator=(const Function1Creator<R, A1> &other);
|
|
mutable Function1Implementation<R, A1> *_ptr;
|
|
};
|
|
template <typename R, typename A1>
|
|
class Function1 {
|
|
public:
|
|
typedef Function1Creator<R, A1> Creator;
|
|
static Creator Null() { return Creator(&NullFunction1Implementation<R, A1>::SharedInstance); }
|
|
Function1(const Creator &creator) : _implementation(creator.create()) {}
|
|
R call(A1 a1) { return _implementation->call(a1); }
|
|
~Function1() { _implementation->destroy(); }
|
|
private:
|
|
Function1(const Function1<R, A1> &other);
|
|
Function1<R, A1> &operator=(const Function1<R, A1> &other);
|
|
Function1Implementation<R, A1> *_implementation;
|
|
};
|
|
|
|
template <typename R, typename A1>
|
|
class WrappedFunction1 : public Function1Implementation<R, A1> {
|
|
public:
|
|
typedef R(*Method)(A1);
|
|
WrappedFunction1(Method method) : _method(method) {}
|
|
virtual R call(A1 a1) { return (*_method)(a1); }
|
|
private:
|
|
Method _method;
|
|
};
|
|
template <typename R, typename A1>
|
|
inline Function1Creator<R, A1> func(R(*method)(A1)) {
|
|
return Function1Creator<R, A1>(new WrappedFunction1<R, A1>(method));
|
|
}
|
|
template <typename O, typename I, typename R, typename A1>
|
|
class ObjectFunction1 : public Function1Implementation<R, A1> {
|
|
public:
|
|
typedef R(I::*Method)(A1);
|
|
ObjectFunction1(O *obj, Method method) : _obj(obj), _method(method) {}
|
|
virtual R call(A1 a1) { return (_obj->*_method)(a1); }
|
|
private:
|
|
O *_obj;
|
|
Method _method;
|
|
};
|
|
template <typename O, typename I, typename R, typename A1>
|
|
Function1Creator<R, A1> func(O *obj, R(I::*method)(A1)) {
|
|
return Function1Creator<R, A1>(new ObjectFunction1<O, I, R, A1>(obj, method));
|
|
}
|
|
|
|
template <typename R, typename A1, typename A2>
|
|
class Function2Implementation {
|
|
public:
|
|
virtual R call(A1 a1, A2 a2) = 0;
|
|
virtual void destroy() { delete this; }
|
|
virtual ~Function2Implementation() {}
|
|
};
|
|
template <typename R, typename A1, typename A2>
|
|
class NullFunction2Implementation : public Function2Implementation<R, A1, A2> {
|
|
public:
|
|
virtual R call(A1 a1, A2 a2) { return R(); }
|
|
virtual void destroy() {}
|
|
static NullFunction2Implementation<R, A1, A2> SharedInstance;
|
|
};
|
|
template <typename R, typename A1, typename A2>
|
|
NullFunction2Implementation<R, A1, A2> NullFunction2Implementation<R, A1, A2>::SharedInstance;
|
|
template <typename R, typename A1, typename A2>
|
|
class Function2Creator {
|
|
public:
|
|
Function2Creator(Function2Implementation<R, A1, A2> *ptr) : _ptr(ptr) {}
|
|
Function2Creator(const Function2Creator<R, A1, A2> &other) : _ptr(other.create()) {}
|
|
Function2Implementation<R, A1, A2> *create() const { return exchange(_ptr); }
|
|
~Function2Creator() { destroyImplementation(_ptr); }
|
|
private:
|
|
Function2Creator<R, A1, A2> &operator=(const Function2Creator<R, A1, A2> &other);
|
|
mutable Function2Implementation<R, A1, A2> *_ptr;
|
|
};
|
|
template <typename R, typename A1, typename A2>
|
|
class Function2 {
|
|
public:
|
|
typedef Function2Creator<R, A1, A2> Creator;
|
|
static Creator Null() { return Creator(&NullFunction2Implementation<R, A1, A2>::SharedInstance); }
|
|
Function2(const Creator &creator) : _implementation(creator.create()) {}
|
|
R call(A1 a1, A2 a2) { return _implementation->call(a1, a2); }
|
|
~Function2() { destroyImplementation(_implementation); }
|
|
private:
|
|
Function2(const Function2<R, A1, A2> &other);
|
|
Function2<R, A1, A2> &operator=(const Function2<R, A1, A2> &other);
|
|
Function2Implementation<R, A1, A2> *_implementation;
|
|
};
|
|
|
|
template <typename R, typename A1, typename A2>
|
|
class WrappedFunction2 : public Function2Implementation<R, A1, A2> {
|
|
public:
|
|
typedef R(*Method)(A1, A2);
|
|
WrappedFunction2(Method method) : _method(method) {}
|
|
virtual R call(A1 a1, A2 a2) { return (*_method)(a1, a2); }
|
|
private:
|
|
Method _method;
|
|
};
|
|
template <typename R, typename A1, typename A2>
|
|
Function2Creator<R, A1, A2> func(R(*method)(A1, A2)) {
|
|
return Function2Creator<R, A1, A2>(new WrappedFunction2<R, A1, A2>(method));
|
|
}
|
|
|
|
template <typename O, typename I, typename R, typename A1, typename A2>
|
|
class ObjectFunction2 : public Function2Implementation<R, A1, A2> {
|
|
public:
|
|
typedef R(I::*Method)(A1, A2);
|
|
ObjectFunction2(O *obj, Method method) : _obj(obj), _method(method) {}
|
|
virtual R call(A1 a1, A2 a2) { return (_obj->*_method)(a1, a2); }
|
|
private:
|
|
O *_obj;
|
|
Method _method;
|
|
};
|
|
template <typename O, typename I, typename R, typename A1, typename A2>
|
|
Function2Creator<R, A1, A2> func(O *obj, R(I::*method)(A1, A2)) {
|
|
return Function2Creator<R, A1, A2>(new ObjectFunction2<O, I, R, A1, A2>(obj, method));
|
|
}
|