#ifndef HELPERS_H #define HELPERS_H #include #include #include #include #include #include using namespace std; namespace SMX { void Log(string s); void Log(wstring s); // Set a function to receive logs written by SMX::Log. By default, logs are written // to stdout. void SetLogCallback(function callback); void SetThreadName(DWORD iThreadId, const string &name); void StripCrnl(wstring &s); wstring GetErrorString(int err); string vssprintf(const char *szFormat, va_list argList); string ssprintf(const char *fmt, ...); wstring wvssprintf(const wchar_t *szFormat, va_list argList); wstring wssprintf(const wchar_t *fmt, ...); string BinaryToHex(const void *pData_, int iNumBytes); string BinaryToHex(const string &sString); bool GetRandomBytes(void *pData, int iBytes); double GetMonotonicTime(); void GenerateRandom(void *pOut, int iSize); string WideStringToUTF8(wstring s); // Create a char* string that will be valid until the next call to CreateError. // This is used to return error messages to the caller. const char *CreateError(string error); #define arraylen(a) (sizeof(a) / sizeof((a)[0])) // In order to be able to use smart pointers to fully manage an object, we need to get // a shared_ptr to pass around, but also store a weak_ptr in the object itself. This // lets the object create shared_ptrs for itself as needed, without keeping itself from // being deallocated. // // This helper allows this pattern: // // struct Class // { // Class(shared_ptr &pSelf): m_pSelf(GetPointers(pSelf, this)) { } // const weak_ptr m_pSelf; // }; // // shared_ptr obj; // new Class(obj); // // For a more convenient way to invoke this, see CreateObj() below. template weak_ptr GetPointers(shared_ptr &pSharedPtr, T *pObj) { pSharedPtr.reset(pObj); return pSharedPtr; } // Create a class that retains a weak reference to itself, returning a shared_ptr. template shared_ptr CreateObj(Args&&... args) { shared_ptr pResult; new T(pResult, std::forward(args)...); return dynamic_pointer_cast(pResult); } class AutoCloseHandle { public: AutoCloseHandle(HANDLE h); ~AutoCloseHandle(); HANDLE value() const { return handle; } private: AutoCloseHandle(const AutoCloseHandle &rhs); AutoCloseHandle &operator=(const AutoCloseHandle &rhs); HANDLE handle; }; class Mutex { public: Mutex(); ~Mutex(); void Lock(); void Unlock(); void AssertNotLockedByCurrentThread(); void AssertLockedByCurrentThread(); private: HANDLE m_hLock = INVALID_HANDLE_VALUE; DWORD m_iLockedByThread = 0; }; // A local lock helper for Mutex. class LockMutex { public: LockMutex(Mutex &mutex); ~LockMutex(); private: Mutex &m_Mutex; }; class Event { public: Event(Mutex &lock): m_Lock(lock) { m_hEvent = make_shared(CreateEvent(NULL, false, false, NULL)); } void Set() { SetEvent(m_hEvent->value()); } // Unlock m_Lock, wait up to iDelayMilliseconds for the event to be set, // then lock m_Lock. If iDelayMilliseconds is -1, wait forever. void Wait(int iDelayMilliseconds) { if(iDelayMilliseconds == -1) iDelayMilliseconds = INFINITE; m_Lock.AssertLockedByCurrentThread(); m_Lock.Unlock(); vector aHandles = { m_hEvent->value() }; WaitForSingleObjectEx(m_hEvent->value(), iDelayMilliseconds, true); m_Lock.Lock(); } private: shared_ptr m_hEvent; Mutex &m_Lock; }; } #endif