Skip to content

Commit

Permalink
Expose macros/functionality for defining interfaces (#604)
Browse files Browse the repository at this point in the history
* Added Result definitions to the slang.h

* Removed slang-result.h and added slang-com-helper.h

* Move slang-com-ptr.h to be publically available.

* Add SLANG_IUNKNOWN macros to simplify implementing interfaces.
Use the SLANG_IUNKNOWN macros to in slang.c

* Removed slang-defines.h added outstanding defines to slang.h
  • Loading branch information
jsmall-zzz authored Jun 22, 2018
1 parent e66d66b commit d0c9571
Show file tree
Hide file tree
Showing 25 changed files with 510 additions and 732 deletions.
107 changes: 107 additions & 0 deletions slang-com-helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#ifndef SLANG_COM_HELPER_H
#define SLANG_COM_HELPER_H

/** \file slang-com-helper.h
*/

#include "slang.h"

/* !!!!!!!!!!!!!!!!!!!!! Macros to help checking SlangResult !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

/*! Set SLANG_HANDLE_RESULT_FAIL(x) to code to be executed whenever an error occurs, and is detected by one of the macros */
#ifndef SLANG_HANDLE_RESULT_FAIL
# define SLANG_HANDLE_RESULT_FAIL(x)
#endif

//! Helper macro, that makes it easy to add result checking to calls in functions/methods that themselves return Result.
#define SLANG_RETURN_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { SLANG_HANDLE_RESULT_FAIL(_res); return _res; } }
//! Helper macro that can be used to test the return value from a call, and will return in a void method/function
#define SLANG_RETURN_VOID_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { SLANG_HANDLE_RESULT_FAIL(_res); return; } }
//! Helper macro that will return false on failure.
#define SLANG_RETURN_FALSE_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { SLANG_HANDLE_RESULT_FAIL(_res); return false; } }
//! Helper macro that will return nullptr on failure.
#define SLANG_RETURN_NULL_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { SLANG_HANDLE_RESULT_FAIL(_res); return nullptr; } }

//! Helper macro that will assert if the return code from a call is failure, also returns the failure.
#define SLANG_ASSERT_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { assert(false); return _res; } }
//! Helper macro that will assert if the result from a call is a failure, also returns.
#define SLANG_ASSERT_VOID_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { assert(false); return; } }

/* !!!!!!!!!!!!!!!!!!!!!!! C++ helpers !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

#if defined(__cplusplus)
namespace Slang {

// Alias SlangResult to Slang::Result
typedef SlangResult Result;
// Alias SlangUUID to Slang::Guid
typedef SlangUUID Guid;

SLANG_FORCE_INLINE bool operator==(const Guid& aIn, const Guid& bIn)
{
// Use the largest type the honors the alignment of Guid
typedef uint32_t CmpType;
union GuidCompare
{
Guid guid;
CmpType data[sizeof(Guid) / sizeof(CmpType)];
};
// Type pun - so compiler can 'see' the pun and not break aliasing rules
const CmpType* a = reinterpret_cast<const GuidCompare&>(aIn).data;
const CmpType* b = reinterpret_cast<const GuidCompare&>(bIn).data;
// Make the guid comparison a single branch, by not using short circuit
return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]) | (a[3] ^ b[3])) == 0;
}

SLANG_FORCE_INLINE bool operator!=(const Guid& a, const Guid& b)
{
return !(a == b);
}


/* !!!!!!!! Macros to simplify implementing COM interfaces !!!!!!!!!!!!!!!!!!!!!!!!!!!! */

/* Assumes underlying implementation has a member m_refCount that is initialized to 0 and can have ++ and -- operate on it.
For SLANG_IUNKNOWN_QUERY_INTERFACE to work - must have a method 'getInterface' that returns valid pointers for the Guid, or nullptr
if not found. */

#define SLANG_IUNKNOWN_QUERY_INTERFACE \
SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) \
{ \
ISlangUnknown* intf = getInterface(uuid); \
if (intf) \
{ \
addRef(); \
*outObject = intf; \
return SLANG_OK;\
} \
return SLANG_E_NO_INTERFACE;\
}

#define SLANG_IUNKNOWN_ADD_REF \
SLANG_NO_THROW uint32_t SLANG_MCALL addRef() \
{ \
return ++m_refCount; \
}

#define SLANG_IUNKNOWN_RELEASE \
SLANG_NO_THROW uint32_t SLANG_MCALL release() \
{ \
--m_refCount; \
if (m_refCount == 0) \
{ \
delete this; \
return 0; \
} \
return m_refCount; \
} \

#define SLANG_IUNKNOWN_ALL \
SLANG_IUNKNOWN_QUERY_INTERFACE \
SLANG_IUNKNOWN_ADD_REF \
SLANG_IUNKNOWN_RELEASE

} // namespace Slang
#endif // defined(__cplusplus)

#endif
60 changes: 5 additions & 55 deletions source/core/slang-com-ptr.h → slang-com-ptr.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
#ifndef SLANG_COM_PTR_H
#ifndef SLANG_COM_PTR_H
#define SLANG_COM_PTR_H

#include "slang-defines.h"
#include "slang-result.h"
#include "slang-com-helper.h"

#include <assert.h>

namespace Slang {

/*! \brief ComPtr is a simple smart pointer that manages types which implement COM based interfaces.
\details A class that implements a COM, must derive from the IUnknown interface or a type that matches
it's layout exactly (such as IForwardUnknown). Trying to use this template with a class that doesn't follow
it's layout exactly (such as ISlangUnknown). Trying to use this template with a class that doesn't follow
these rules, will lead to undefined behavior.
This is a 'strong' pointer type, and will AddRef when a non null pointer is set and Release when the pointer
leaves scope.
Expand All @@ -22,12 +21,9 @@ is to write into the smart pointer, other times to pass as an array. To handle t
there are the methods readRef and writeRef, which are used instead of the & (ref) operator. For example
\code
Void doSomething(ID3D12Resource** resources, IndexT numResources);
// ...
ComPtr<ID3D12Resource> resources[3];
doSomething(resources[0].readRef(), SLANG_COUNT_OF(resource));
\endcode
Expand All @@ -41,45 +37,6 @@ Result res = unk->QueryInterface(resource.writeRef());
\endcode
*/

typedef SlangUUID Guid;

SLANG_FORCE_INLINE bool operator==(const Guid& aIn, const Guid& bIn)
{
// Use the largest type the honors the alignment of Guid
typedef uint32_t CmpType;
union GuidCompare
{
Guid guid;
CmpType data[sizeof(Guid) / sizeof(CmpType)];
};
// Type pun - so compiler can 'see' the pun and not break aliasing rules
const CmpType* a = reinterpret_cast<const GuidCompare&>(aIn).data;
const CmpType* b = reinterpret_cast<const GuidCompare&>(bIn).data;
// Make the guid comparison a single branch, by not using short circuit
return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]) | (a[3] ^ b[3])) == 0;
}

SLANG_FORCE_INLINE bool operator!=(const Guid& a, const Guid& b)
{
return !(a == b);
}

// Allows for defining of a GUID that works in C++ and C which defines in a format similar to microsofts INTERFACE style
// MIDL_INTERFACE("00000000-0000-0000-C000-00 00 00 00 00 46")

#define SLANG_GUID_BYTE(x, index) ((uint8_t)(SLANG_UINT64(0x##x) >> (8 * index)))

#define SLANG_MAKE_GUID(data0, data1, data2, shortTail, tail) \
{ (uint32_t)(0x##data0), (uint16_t)(0x##data1), (uint16_t)(0x##data2), \
{ (uint8_t)(0x##shortTail >> 8), (uint8_t)(0x##shortTail & 0xff), \
SLANG_GUID_BYTE(tail,5), SLANG_GUID_BYTE(tail,4), SLANG_GUID_BYTE(tail,3), SLANG_GUID_BYTE(tail,2), SLANG_GUID_BYTE(tail,1), SLANG_GUID_BYTE(tail,0) \
}}

// Compatible with Microsoft IUnknown
static const Guid IID_IComUnknown = SLANG_MAKE_GUID(00000000, 0000, 0000, C000, 000000000046);

typedef ISlangUnknown IComUnknown;

// Enum to force initializing as an attach (without adding a reference)
enum InitAttach
{
Expand All @@ -92,7 +49,7 @@ class ComPtr
public:
typedef T Type;
typedef ComPtr ThisType;
typedef IComUnknown* Ptr;
typedef ISlangUnknown* Ptr;

/// Constructors
/// Default Ctor. Sets to nullptr
Expand Down Expand Up @@ -152,7 +109,7 @@ class ComPtr
protected:
/// Gets the address of the dumb pointer.
// Disabled: use writeRef and readRef to get a reference based on usage.
SLANG_FORCE_INLINE T** operator&();
SLANG_FORCE_INLINE T** operator&() = delete;

T* m_ptr;
};
Expand All @@ -168,13 +125,6 @@ void ComPtr<T>::setNull()
}
}
//----------------------------------------------------------------------------
/* template <typename T>
T** ComPtr<T>::operator&()
{
assert(m_ptr == nullptr);
return &m_ptr;
} */
//----------------------------------------------------------------------------
template <typename T>
const ComPtr<T>& ComPtr<T>::operator=(const ThisType& rhs)
{
Expand Down
Loading

0 comments on commit d0c9571

Please sign in to comment.