#pragma once
#include "pluginterfaces/base/fplatform.h"
#include "pluginterfaces/base/ftypes.h"
#include "pluginterfaces/base/smartpointer.h"
#include <cstring>
#if SMTG_CPP11_STDLIBSUPPORT
#include <type_traits>
#endif
#if COM_COMPATIBLE
#define INLINE_UID(l1, l2, l3, l4) \
{ \
(::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x000000FF) ), (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x0000FF00) >> 8), \
(::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x00FF0000) >> 16), (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0xFF000000) >> 24), \
(::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x00FF0000) >> 16), (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0xFF000000) >> 24), \
(::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x000000FF) ), (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x0000FF00) >> 8), \
(::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x00FF0000) >> 16), \
(::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x000000FF) ), \
(::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x00FF0000) >> 16), \
(::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x000000FF) ) \
}
#else
#define INLINE_UID(l1, l2, l3, l4) \
{ \
(::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x00FF0000) >> 16), \
(::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x000000FF) ), \
(::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x00FF0000) >> 16), \
(::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x000000FF) ), \
(::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x00FF0000) >> 16), \
(::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x000000FF) ), \
(::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x00FF0000) >> 16), \
(::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x000000FF) ) \
}
#endif
#define DECLARE_UID(name, l1, l2, l3, l4) SMTG_CONSTEXPR14 ::Steinberg::TUID name = INLINE_UID (l1, l2, l3, l4);
#define EXTERN_UID(name) extern const ::Steinberg::TUID name;
#ifdef INIT_CLASS_IID
#define DECLARE_CLASS_IID(ClassName, l1, l2, l3, l4) \
static SMTG_CONSTEXPR14 const ::Steinberg::TUID ClassName##_iid = INLINE_UID (l1, l2, l3, l4); \
const ::Steinberg::FUID ClassName::iid (ClassName##_iid);
#else
#define DECLARE_CLASS_IID(ClassName, l1, l2, l3, l4) \
static SMTG_CONSTEXPR14 const ::Steinberg::TUID ClassName##_iid = INLINE_UID (l1, l2, l3, l4);
#endif
#define DEF_CLASS_IID(ClassName) const ::Steinberg::FUID ClassName::iid (ClassName##_iid);
#define INLINE_UID_OF(ClassName) ClassName##_iid
#define INLINE_UID_FROM_FUID(x) \
INLINE_UID (x.getLong1 (), x.getLong2 (), x.getLong3 (), x.getLong4 ())
#define DECLARE_FUNKNOWN_METHODS \
public: \
virtual ::Steinberg::tresult PLUGIN_API queryInterface (const ::Steinberg::TUID _iid, void** obj) SMTG_OVERRIDE; \
virtual ::Steinberg::uint32 PLUGIN_API addRef () SMTG_OVERRIDE; \
virtual ::Steinberg::uint32 PLUGIN_API release () SMTG_OVERRIDE; \
protected : \
::Steinberg::int32 __funknownRefCount; \
public:
#define DELEGATE_REFCOUNT(ClassName) \
public: \
virtual ::Steinberg::uint32 PLUGIN_API addRef () SMTG_OVERRIDE { return ClassName::addRef (); } \
virtual ::Steinberg::uint32 PLUGIN_API release () SMTG_OVERRIDE { return ClassName::release (); }
#define IMPLEMENT_REFCOUNT(ClassName) \
::Steinberg::uint32 PLUGIN_API ClassName::addRef () \
{ \
return ::Steinberg::FUnknownPrivate::atomicAdd (__funknownRefCount, 1); \
} \
::Steinberg::uint32 PLUGIN_API ClassName::release () \
{ \
if (::Steinberg::FUnknownPrivate::atomicAdd (__funknownRefCount, -1) == 0) \
{ \
delete this; \
return 0; \
} \
return __funknownRefCount; \
}
#define FUNKNOWN_CTOR { __funknownRefCount = 1; }
#if defined(SMTG_FUNKNOWN_DTOR_ASSERT) && SMTG_FUNKNOWN_DTOR_ASSERT
#include <cassert>
#define FUNKNOWN_DTOR { assert (__funknownRefCount == 0); }
#else
#define FUNKNOWN_DTOR
#endif
#define QUERY_INTERFACE(iid, obj, InterfaceIID, InterfaceName) \
if (::Steinberg::FUnknownPrivate::iidEqual (iid, InterfaceIID)) \
{ \
addRef (); \
*obj = static_cast< InterfaceName* >(this); \
return ::Steinberg::kResultOk; \
}
#define IMPLEMENT_QUERYINTERFACE(ClassName, InterfaceName, ClassIID) \
::Steinberg::tresult PLUGIN_API ClassName::queryInterface (const ::Steinberg::TUID _iid, void** obj)\
{ \
QUERY_INTERFACE (_iid, obj, ::Steinberg::FUnknown::iid, InterfaceName) \
QUERY_INTERFACE (_iid, obj, ClassIID, InterfaceName) \
*obj = nullptr; \
return ::Steinberg::kNoInterface; \
}
#define IMPLEMENT_FUNKNOWN_METHODS(ClassName,InterfaceName,ClassIID) \
IMPLEMENT_REFCOUNT (ClassName) \
IMPLEMENT_QUERYINTERFACE (ClassName, InterfaceName, ClassIID)
namespace Steinberg {
#if COM_COMPATIBLE
#if SMTG_OS_WINDOWS
enum
{
kNoInterface = static_cast<tresult>(0x80004002L), kResultOk = static_cast<tresult>(0x00000000L), kResultTrue = kResultOk,
kResultFalse = static_cast<tresult>(0x00000001L), kInvalidArgument = static_cast<tresult>(0x80070057L), kNotImplemented = static_cast<tresult>(0x80004001L), kInternalError = static_cast<tresult>(0x80004005L), kNotInitialized = static_cast<tresult>(0x8000FFFFL), kOutOfMemory = static_cast<tresult>(0x8007000EL) };
#else
enum
{
kNoInterface = static_cast<tresult>(0x80000004L), kResultOk = static_cast<tresult>(0x00000000L), kResultTrue = kResultOk,
kResultFalse = static_cast<tresult>(0x00000001L), kInvalidArgument = static_cast<tresult>(0x80000003L), kNotImplemented = static_cast<tresult>(0x80000001L), kInternalError = static_cast<tresult>(0x80000008L), kNotInitialized = static_cast<tresult>(0x8000FFFFL), kOutOfMemory = static_cast<tresult>(0x80000002L) };
#endif
#else
enum
{
kNoInterface = -1,
kResultOk,
kResultTrue = kResultOk,
kResultFalse,
kInvalidArgument,
kNotImplemented,
kInternalError,
kNotInitialized,
kOutOfMemory
};
#endif
typedef int64 LARGE_INT;
typedef char TUID[16];
#if SMTG_CPP14
inline SMTG_CONSTEXPR14 void copyTUID (char* dst, const char* src)
{
for (auto i = 0; i < 16; ++i)
dst[i] = src[i];
}
#endif
namespace FUnknownPrivate {
SMTG_ALWAYS_INLINE bool iidEqual (const void* iid1, const void* iid2)
{
const uint64* p1 = reinterpret_cast<const uint64*> (iid1);
const uint64* p2 = reinterpret_cast<const uint64*> (iid2);
return p1[0] == p2[0] && p1[1] == p2[1];
}
int32 PLUGIN_API atomicAdd (int32& value, int32 amount);
}
class FUID
{
public:
FUID ();
FUID (uint32 l1, uint32 l2, uint32 l3, uint32 l4);
FUID (const FUID&);
virtual ~FUID () {}
#if SMTG_CPP11_STDLIBSUPPORT
FUID (FUID&& other);
FUID& operator= (FUID&& other);
#endif
bool generate ();
bool isValid () const;
FUID& operator = (const FUID& f);
bool operator == (const FUID& f) const { return ::Steinberg::FUnknownPrivate::iidEqual (data, f.data); }
bool operator < (const FUID& f) const { return memcmp (data, f.data, sizeof (TUID)) < 0; }
bool operator != (const FUID& f) const { return !::Steinberg::FUnknownPrivate::iidEqual (data, f.data); }
uint32 getLong1 () const;
uint32 getLong2 () const;
uint32 getLong3 () const;
uint32 getLong4 () const;
void from4Int (uint32 d1, uint32 d2, uint32 d3, uint32 d4);
void to4Int (uint32& d1, uint32& d2, uint32& d3, uint32& d4) const;
typedef char8 String[33];
void toString (char8* string) const;
bool fromString (const char8* string);
void toRegistryString (char8* string) const;
bool fromRegistryString (const char8* string);
enum UIDPrintStyle
{
kINLINE_UID, kDECLARE_UID, kFUID, kCLASS_UID };
void print (int32 style, char8* string = nullptr, size_t stringBufferSize = 0) const;
template <size_t N>
inline explicit FUID (const char (&uid)[N])
{
#if SMTG_CPP11_STDLIBSUPPORT
static_assert (N == sizeof (TUID), "only TUID allowed");
#endif
memcpy (data, uid, sizeof (TUID));
}
inline void toTUID (TUID result) const { memcpy (result, data, sizeof (TUID)); }
inline operator const TUID& () const { return data; }
inline const TUID& toTUID () const { return data; }
static FUID fromTUID (const TUID uid)
{
FUID res;
if (uid)
memcpy (res.data, uid, sizeof (TUID));
return res;
}
protected:
TUID data;
};
#if SMTG_CPP11_STDLIBSUPPORT
template <typename T>
inline bool operator== (const FUID& f1, T f2)
{
static_assert (
std::is_same<typename std::remove_cv<T>::type, FUID>::value,
"Do not compare a FUID with a TUID directly. Either convert the TUID to a FUID and compare them or use FUnknownPrivate::iidEqual");
return f1.operator== (f2);
}
#endif
class FUnknown
{
public:
virtual tresult PLUGIN_API queryInterface (const TUID _iid, void** obj) = 0;
virtual uint32 PLUGIN_API addRef () = 0;
virtual uint32 PLUGIN_API release () = 0;
static const FUID iid;
};
DECLARE_CLASS_IID (FUnknown, 0x00000000, 0x00000000, 0xC0000000, 0x00000046)
template <class I>
class FUnknownPtr : public IPtr<I>
{
public:
inline FUnknownPtr (FUnknown* unknown); inline FUnknownPtr (const FUnknownPtr& p) : IPtr<I> (p) {}
inline FUnknownPtr () {}
inline FUnknownPtr& operator= (const FUnknownPtr& p)
{
IPtr<I>::operator= (p);
return *this;
}
inline I* operator= (FUnknown* unknown);
inline I* getInterface () { return this->ptr; }
#if SMTG_CPP11_STDLIBSUPPORT
inline FUnknownPtr (FUnknownPtr&& p) SMTG_NOEXCEPT : IPtr<I> (std::move (p)) {}
inline FUnknownPtr& operator= (FUnknownPtr&& p) SMTG_NOEXCEPT
{
IPtr<I>::operator= (std::move (p));
return *this;
}
#endif
};
#if SMTG_CPP11_STDLIBSUPPORT
namespace FUnknownPrivate {
template <typename T>
struct Void : std::false_type
{
using Type = void;
};
template <typename T>
using VoidT = typename Void<T>::Type;
template <typename T, typename U = void>
struct HasIIDType : std::false_type
{
};
template <typename T>
struct HasIIDType<T, FUnknownPrivate::VoidT<typename T::IID>> : std::true_type
{
};
}
template <typename T,
typename std::enable_if<FUnknownPrivate::HasIIDType<T>::value>::type* = nullptr>
const TUID& getTUID ()
{
return T::IID::toTUID ();
}
template <typename T,
typename std::enable_if<!FUnknownPrivate::HasIIDType<T>::value>::type* = nullptr>
const TUID& getTUID ()
{
return T::iid.toTUID ();
}
#else
template<typename T>
const TUID& getTUID ()
{
return T::iid.toTUID ();
}
#endif
template <class I>
inline FUnknownPtr<I>::FUnknownPtr (FUnknown* unknown)
{
if (unknown && unknown->queryInterface (getTUID<I> (), (void**)&this->ptr) != kResultOk)
this->ptr = 0;
}
template <class I>
inline I* FUnknownPtr<I>::operator= (FUnknown* unknown)
{
I* newPtr = 0;
if (unknown && unknown->queryInterface (getTUID<I> (), (void**)&newPtr) == kResultOk)
{
OPtr<I> rel (newPtr);
return IPtr<I>::operator= (newPtr);
}
return IPtr<I>::operator= (0);
}
struct FReleaser
{
FReleaser (FUnknown* u) : u (u) {}
~FReleaser ()
{
if (u)
u->release ();
}
FUnknown* u;
};
}