Particles . C++ Snippets
Code that I keep using throughout various projects and improving over time.
Macros
Compile-time array length, inspired by eXile:
namespace helper
{
template <class T, size_t S> char (&arraylen_helper(T (&a)[S]))[S];
}
#define arraylen(a) sizeof(::helper::arraylen_helper(a))
{
template <class T, size_t S> char (&arraylen_helper(T (&a)[S]))[S];
}
#define arraylen(a) sizeof(::helper::arraylen_helper(a))
Emulation of alignas and alignof using the MSVC-specific alignment extensions, inspired by Chris Maiwald:
#define alignas(alignment) __declspec( align(alignment) )
namespace helper
{
// Workaround for Visual Studio Bug: Alignment of some classes
// zero until their size has been evaluated
template <size_t Size, size_t Alignment>
struct alignof_fix
{
static const size_t alignment = Alignment;
};
}
#define alignof(type) ::helper::alignof_fix<sizeof(type), __alignof(type)>::alignment
namespace helper
{
// Workaround for Visual Studio Bug: Alignment of some classes
// zero until their size has been evaluated
template <size_t Size, size_t Alignment>
struct alignof_fix
{
static const size_t alignment = Alignment;
};
}
#define alignof(type) ::helper::alignof_fix<sizeof(type), __alignof(type)>::alignment
com_ptr
Pointer class allowing for COM-style object retrieval, e.g. Create***(..., myPtr.rebind());, and providing automated reference counting:
// Allows for customization of reference counting interface via argument-dependent lookup
template <class COMType>
inline void com_acquire(COMType *p)
{
p->AddRef();
}
template <class COMType>
inline void com_release(COMType *p)
{
p->Release();
}
// Allows for binding of existing references without incrementing the reference count
enum bind_reference_t { bind_reference };
template <class COMType>
class com_ptr
{
public:
typedef COMType com_type;
typedef COMType* value_type;
private:
com_type *m_object;
static com_type* acquire_ref(com_type *object)
{
if (object)
com_acquire(object);
return object;
}
static void release_ref(com_type *object)
{
if (object)
com_release(object);
}
public:
com_ptr(com_type *object = nullptr)
: m_object( acquire_ref(object) ) { }
template <class OtherCOMType>
com_ptr(OtherCOMType *object)
: m_object( acquire_ref(object) ) { }
com_ptr(com_type *object, bind_reference_t)
: m_object(object) { }
com_ptr(const com_ptr &right)
: m_object( acquire_ref(right.m_object) ) { }
template <class OtherCOMType>
com_ptr(const com_ptr<OtherCOMType> &right)
: m_object( acquire_ref(right.get()) ) { }
#ifndef CPP11_NO_RVALUE_REFERENCES
template <class OtherCOMType>
com_ptr(com_ptr<OtherCOMType> &&right)
: m_object(right.unbind()) { }
#endif
~com_ptr() throw()
{
release_ref(m_object);
}
void rebind(com_type *object)
{
com_type *prevObject = m_object;
m_object = object;
release_ref(prevObject);
}
com_type* unbind()
{
com_type *preObject = m_object;
m_object = nullptr;
return preObject;
}
void reset(com_type *object)
{
// Do not check for redundant assignment
// -> The code handles redundant assignment just fine
// -> Checking generates up to twice the code due to unfortunate compiler optimization application order
rebind( acquire_ref(object) );
}
void release()
{
rebind(nullptr);
}
com_ptr& operator =(com_type *object)
{
reset(object);
return *this;
}
com_ptr& operator =(const com_ptr &right)
{
reset(right.m_object);
return *this;
}
template <class OtherCOMType>
com_ptr& operator =(const com_ptr<OtherCOMType> &right)
{
reset(right.get());
return *this;
}
#ifndef CPP11_NO_RVALUE_REFERENCES
template <class OtherCOMType>
com_ptr& operator =(com_ptr<OtherCOMType> &&right)
{
// Self-assignment would be wrong
if ((void*) this != (void*) &right)
rebind(right.unbind());
return *this;
}
#endif
com_type*const& get() const { return m_object; }
com_type& operator *() const { return *m_object; }
com_type* operator ->() const { return m_object; }
/// Gets a double-pointer allowing for COM-style object retrieval. The pointer returned may
/// only ever be used until the next call to one of this COM pointer's methods.
com_type** rebind()
{
release();
return &m_object;
}
};
template <class COMType>
inline void com_acquire(COMType *p)
{
p->AddRef();
}
template <class COMType>
inline void com_release(COMType *p)
{
p->Release();
}
// Allows for binding of existing references without incrementing the reference count
enum bind_reference_t { bind_reference };
template <class COMType>
class com_ptr
{
public:
typedef COMType com_type;
typedef COMType* value_type;
private:
com_type *m_object;
static com_type* acquire_ref(com_type *object)
{
if (object)
com_acquire(object);
return object;
}
static void release_ref(com_type *object)
{
if (object)
com_release(object);
}
public:
com_ptr(com_type *object = nullptr)
: m_object( acquire_ref(object) ) { }
template <class OtherCOMType>
com_ptr(OtherCOMType *object)
: m_object( acquire_ref(object) ) { }
com_ptr(com_type *object, bind_reference_t)
: m_object(object) { }
com_ptr(const com_ptr &right)
: m_object( acquire_ref(right.m_object) ) { }
template <class OtherCOMType>
com_ptr(const com_ptr<OtherCOMType> &right)
: m_object( acquire_ref(right.get()) ) { }
#ifndef CPP11_NO_RVALUE_REFERENCES
template <class OtherCOMType>
com_ptr(com_ptr<OtherCOMType> &&right)
: m_object(right.unbind()) { }
#endif
~com_ptr() throw()
{
release_ref(m_object);
}
void rebind(com_type *object)
{
com_type *prevObject = m_object;
m_object = object;
release_ref(prevObject);
}
com_type* unbind()
{
com_type *preObject = m_object;
m_object = nullptr;
return preObject;
}
void reset(com_type *object)
{
// Do not check for redundant assignment
// -> The code handles redundant assignment just fine
// -> Checking generates up to twice the code due to unfortunate compiler optimization application order
rebind( acquire_ref(object) );
}
void release()
{
rebind(nullptr);
}
com_ptr& operator =(com_type *object)
{
reset(object);
return *this;
}
com_ptr& operator =(const com_ptr &right)
{
reset(right.m_object);
return *this;
}
template <class OtherCOMType>
com_ptr& operator =(const com_ptr<OtherCOMType> &right)
{
reset(right.get());
return *this;
}
#ifndef CPP11_NO_RVALUE_REFERENCES
template <class OtherCOMType>
com_ptr& operator =(com_ptr<OtherCOMType> &&right)
{
// Self-assignment would be wrong
if ((void*) this != (void*) &right)
rebind(right.unbind());
return *this;
}
#endif
com_type*const& get() const { return m_object; }
com_type& operator *() const { return *m_object; }
com_type* operator ->() const { return m_object; }
/// Gets a double-pointer allowing for COM-style object retrieval. The pointer returned may
/// only ever be used until the next call to one of this COM pointer's methods.
com_type** rebind()
{
release();
return &m_object;
}
};