Formatted code with ClangFormat (#23)

* Formatted code with ClangFormat

* Change files
This commit is contained in:
Vladimir Morozov 2020-04-01 07:53:30 -07:00 коммит произвёл GitHub
Родитель 68f50343a4
Коммит 67119c9c18
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
115 изменённых файлов: 16219 добавлений и 15930 удалений

111
.clang-format Normal file
Просмотреть файл

@ -0,0 +1,111 @@
#
# Clang formatting rules: https://clang.llvm.org/docs/ClangFormatStyleOptions.html
# The clang-format npm package (https://github.com/angular/clang-format) uses
# a pre-built clang-format.exe from http://llvm.org/builds/
#
---
# We use defaults from the Microsoft style
BasedOnStyle: Microsoft
---
Language: Cpp
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: true
AlignOperands: false
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterExternBlock: true
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
BreakAfterJavaFieldAnnotations: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
BreakStringLiterals: false
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces : true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
FixNamespaceComments: true
ForEachMacros: [ FOR_EACH_RANGE, FOR_EACH, TEST_CLASS, TEST_CLASS_EX ]
IncludeBlocks: Preserve
IncludeCategories:
- Regex: 'pch.h'
Priority: -1
- Regex: '.*\.g\..*'
Priority: 1
- Regex: '^<.*\.h(pp)?>'
Priority: 2
- Regex: '^<.*'
Priority: 3
- Regex: '.*'
Priority: 4
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Latest
TabWidth: 2
UseTab: Never
...

Просмотреть файл

@ -0,0 +1,8 @@
{
"type": "patch",
"comment": "Formatted code with ClangFormat",
"packageName": "@microsoft/mso",
"email": "vmorozov@microsoft.com",
"dependentChangeType": "patch",
"date": "2020-04-01T14:47:10.009Z"
}

Просмотреть файл

@ -14,53 +14,59 @@
#include <comBaseApi.h>
#include <unknwn.h>
namespace Mso {
namespace ComUtil {
namespace Mso { namespace ComUtil {
template<typename T>
HRESULT HrCoCreateInstance(Mso::TCntPtr<T>& target, REFCLSID rclsid, _In_opt_ LPUNKNOWN pUnkOuter = nullptr, DWORD dwClsContext = CLSCTX_ALL) noexcept
template <typename T>
HRESULT HrCoCreateInstance(
Mso::TCntPtr<T>& target,
REFCLSID rclsid,
_In_opt_ LPUNKNOWN pUnkOuter = nullptr,
DWORD dwClsContext = CLSCTX_ALL) noexcept
{
return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), reinterpret_cast<void**>(target.GetAddressOf()));
return ::CoCreateInstance(
rclsid, pUnkOuter, dwClsContext, __uuidof(T), reinterpret_cast<void**>(target.GetAddressOf()));
}
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
template<typename T>
HRESULT HrCoCreateInstance(Mso::TCntPtr<T>& target, _In_z_ LPCOLESTR szProgID, _In_opt_ LPUNKNOWN pUnkOuter = nullptr, DWORD dwClsContext = CLSCTX_ALL) noexcept
template <typename T>
HRESULT HrCoCreateInstance(
Mso::TCntPtr<T>& target,
_In_z_ LPCOLESTR szProgID,
_In_opt_ LPUNKNOWN pUnkOuter = nullptr,
DWORD dwClsContext = CLSCTX_ALL) noexcept
{
CLSID clsid;
HRESULT hr = ::CLSIDFromProgID(szProgID, &clsid);
return SUCCEEDED(hr) ? HrCoCreateInstance(target, clsid, pUnkOuter, dwClsContext) : hr;
CLSID clsid;
HRESULT hr = ::CLSIDFromProgID(szProgID, &clsid);
return SUCCEEDED(hr) ? HrCoCreateInstance(target, clsid, pUnkOuter, dwClsContext) : hr;
}
#endif
} // ComUtil
} // Mso
}} // namespace Mso::ComUtil
namespace Mso {
template <typename T1, typename T2>
__declspec(deprecated("Use Mso::ComUtil::AreEqualObjects")) bool AreEqualObjects(const T1* pLeft, const T2* pRight) noexcept
__declspec(
deprecated("Use Mso::ComUtil::AreEqualObjects")) bool AreEqualObjects(const T1* pLeft, const T2* pRight) noexcept
{
return Mso::ComUtil::AreEqualObjects(pLeft, pRight);
return Mso::ComUtil::AreEqualObjects(pLeft, pRight);
}
} // Mso
} // namespace Mso
#endif // MS_TARGET_WINDOWS
namespace Mso {
namespace Details {
namespace Mso { namespace Details {
// Overloaded global function to provide to IID_PPV_ARGS that support Details::TCntPtrRef
template <typename T>
void** IID_PPV_ARGS_Helper(_Inout_ TCntPtrRef<T> pp) noexcept
{
static_assert(std::is_base_of<IUnknown, T>::value, "T has to derive from IUnknown");
return pp;
static_assert(std::is_base_of<IUnknown, T>::value, "T has to derive from IUnknown");
return pp;
}
} // Details
} // Mso
}} // namespace Mso::Details
#endif // __cplusplus
#endif // LIBLET_COMUTIL_QICAST_H

Просмотреть файл

@ -30,188 +30,199 @@
//============================================================================
/**
qi_cast<Type>(source, optional riid)
qi_cast<Type>(source, optional riid)
Primary version of the template. Generally speaking, it is preferable to
add a MSO_CLASS_GUID(T, "") / MSO_STRUCT_GUID(T, "") declaration to the class/interface, or use
MSO_ASSIGN_CLASS_GUID(T, "") / MSO_ASSIGN_STRUCT_GUID(T, "") if type is already defined. Otherwise it can be
explicitly passed as a 2nd parameter.
Primary version of the template. Generally speaking, it is preferable to
add a MSO_CLASS_GUID(T, "") / MSO_STRUCT_GUID(T, "") declaration to the class/interface, or use
MSO_ASSIGN_CLASS_GUID(T, "") / MSO_ASSIGN_STRUCT_GUID(T, "") if type is already defined. Otherwise it can be
explicitly passed as a 2nd parameter.
*/
template< typename TTarget, typename TSource >
Mso::TCntPtr< TTarget > qi_cast( TSource& piSource, const IID &riid = __uuidof( TTarget ) ) noexcept
template <typename TTarget, typename TSource>
Mso::TCntPtr<TTarget> qi_cast(TSource& piSource, const IID& riid = __uuidof(TTarget)) noexcept
{
Mso::TCntPtr< TTarget > spTarget;
if( piSource != nullptr )
{
if( FAILED ( piSource->QueryInterface( riid, &spTarget ) ) )
spTarget.Empty();
}
return spTarget;
Mso::TCntPtr<TTarget> spTarget;
if (piSource != nullptr)
{
if (FAILED(piSource->QueryInterface(riid, &spTarget)))
spTarget.Empty();
}
return spTarget;
}
/**
qi_cast<Type>(const source, optional riid)
qi_cast<Type>(const source, optional riid)
Shorthand for classes and interfaces with an MSO_CLASS_GUID(T, "") / MSO_STRUCT_GUID(T, "") attribute
or a MSO_ASSIGN_CLASS_GUID(T, "") / MSO_ASSIGN_STRUCT_GUID(T, "") assignment.
TSource does not include the pointer type, which allows the compiler
to disambiguate against the primary function.
Shorthand for classes and interfaces with an MSO_CLASS_GUID(T, "") / MSO_STRUCT_GUID(T, "") attribute
or a MSO_ASSIGN_CLASS_GUID(T, "") / MSO_ASSIGN_STRUCT_GUID(T, "") assignment.
TSource does not include the pointer type, which allows the compiler
to disambiguate against the primary function.
*/
template< typename TTarget, typename TSource >
Mso::TCntPtr< TTarget > qi_cast( const TSource *piSource, const IID &riid = __uuidof( TTarget ) ) noexcept
template <typename TTarget, typename TSource>
Mso::TCntPtr<TTarget> qi_cast(const TSource* piSource, const IID& riid = __uuidof(TTarget)) noexcept
{
TSource *piSourceNonConst = const_cast< TSource* >( piSource );
return qi_cast< TTarget, TSource* >( piSourceNonConst, riid );
TSource* piSourceNonConst = const_cast<TSource*>(piSource);
return qi_cast<TTarget, TSource*>(piSourceNonConst, riid);
}
#pragma warning(push)
#pragma warning(disable:4995) // VerifyElseCrashSz gives "warning C4995: 'IsDebuggerPresent': name was marked as #pragma deprecated"
#pragma warning(disable : 4995) // VerifyElseCrashSz gives "warning C4995: 'IsDebuggerPresent': name was marked as
// #pragma deprecated"
/**
qi_cast_or_crash<Type>(source, optional riid)
qi_cast_or_crash<Type>(source, optional riid)
Calls qi_cast and crashes if it fails.
This is useful when the qi_cast must succeed or otherwise it is a bug.
Calls qi_cast and crashes if it fails.
This is useful when the qi_cast must succeed or otherwise it is a bug.
*/
template< typename TTarget, typename TSource >
Mso::TCntPtr< TTarget > qi_cast_or_crash( TSource& piSource, const IID &riid = __uuidof( TTarget ) ) noexcept
template <typename TTarget, typename TSource>
Mso::TCntPtr<TTarget> qi_cast_or_crash(TSource& piSource, const IID& riid = __uuidof(TTarget)) noexcept
{
Mso::TCntPtr< TTarget > target = qi_cast< TTarget >( piSource, riid );
VerifyElseCrashSzTag( target, "Query interface failed." , 0x022054c3 /* tag_ciftd */);
return target;
Mso::TCntPtr<TTarget> target = qi_cast<TTarget>(piSource, riid);
VerifyElseCrashSzTag(target, "Query interface failed.", 0x022054c3 /* tag_ciftd */);
return target;
}
/**
qi_cast_or_crash<Type>(const source, optional riid)
qi_cast_or_crash<Type>(const source, optional riid)
Calls qi_cast and crashes if it fails.
This is useful when the qi_cast must succeed or otherwise it is a bug.
Calls qi_cast and crashes if it fails.
This is useful when the qi_cast must succeed or otherwise it is a bug.
*/
template< typename TTarget, typename TSource >
Mso::TCntPtr< TTarget > qi_cast_or_crash( const TSource *piSource, const IID &riid = __uuidof( TTarget ) ) noexcept
template <typename TTarget, typename TSource>
Mso::TCntPtr<TTarget> qi_cast_or_crash(const TSource* piSource, const IID& riid = __uuidof(TTarget)) noexcept
{
Mso::TCntPtr< TTarget > target = qi_cast< TTarget >( piSource, riid );
VerifyElseCrashSzTag( target, "Query interface failed." , 0x022054c4 /* tag_cifte */);
return target;
Mso::TCntPtr<TTarget> target = qi_cast<TTarget>(piSource, riid);
VerifyElseCrashSzTag(target, "Query interface failed.", 0x022054c4 /* tag_cifte */);
return target;
}
#pragma warning(pop)
/**
simpleqi_cast<Type>(source, optional riid)
simpleqi_cast<Type>(source, optional riid)
Primary version of the template. Generally speaking, it is preferable to
add a MSO_CLASS_GUID(T, "") / MSO_STRUCT_GUID(T, "") declaration to the class/interface, or use
MSO_ASSIGN_CLASS_GUID(T, "") / MSO_ASSIGN_STRUCT_GUID(T, "") if type is already defined. Otherwise it can be
explicitly passed as a 2nd parameter.
Primary version of the template. Generally speaking, it is preferable to
add a MSO_CLASS_GUID(T, "") / MSO_STRUCT_GUID(T, "") declaration to the class/interface, or use
MSO_ASSIGN_CLASS_GUID(T, "") / MSO_ASSIGN_STRUCT_GUID(T, "") if type is already defined. Otherwise it can be
explicitly passed as a 2nd parameter.
Used for Simple interfaces that do not AddRef
Used for Simple interfaces that do not AddRef
*/
template< typename TTarget, typename TSource >
TTarget* simpleqi_cast( TSource& piSource, const IID &riid = __uuidof( TTarget ) ) noexcept
template <typename TTarget, typename TSource>
TTarget* simpleqi_cast(TSource& piSource, const IID& riid = __uuidof(TTarget)) noexcept
{
TTarget* pTarget = nullptr;
if( piSource != nullptr )
{
if( FAILED( piSource->QueryInterface( riid, reinterpret_cast< void** >( &pTarget ) ) ) )
pTarget = nullptr;
}
return pTarget;
TTarget* pTarget = nullptr;
if (piSource != nullptr)
{
if (FAILED(piSource->QueryInterface(riid, reinterpret_cast<void**>(&pTarget))))
pTarget = nullptr;
}
return pTarget;
}
/**
simpleqi_cast<Type>(const source, optional riid)
simpleqi_cast<Type>(const source, optional riid)
Shorthand for classes and interfaces with an MSO_CLASS_GUID(T, "") / MSO_STRUCT_GUID(T, "") attribute
or a MSO_ASSIGN_CLASS_GUID(T, "") / MSO_ASSIGN_STRUCT_GUID(T, "") assignment.
TSource does not include the pointer type, which allows the compiler
to disambiguate against the primary function.
Shorthand for classes and interfaces with an MSO_CLASS_GUID(T, "") / MSO_STRUCT_GUID(T, "") attribute
or a MSO_ASSIGN_CLASS_GUID(T, "") / MSO_ASSIGN_STRUCT_GUID(T, "") assignment.
TSource does not include the pointer type, which allows the compiler
to disambiguate against the primary function.
*/
template< typename TTarget, typename TSource >
TTarget* simpleqi_cast( const TSource *piSource, const IID &riid = __uuidof( TTarget ) ) noexcept
template <typename TTarget, typename TSource>
TTarget* simpleqi_cast(const TSource* piSource, const IID& riid = __uuidof(TTarget)) noexcept
{
TSource *piSourceNonConst = const_cast< TSource* >( piSource );
return simpleqi_cast< TTarget, TSource *>( piSourceNonConst, riid );
TSource* piSourceNonConst = const_cast<TSource*>(piSource);
return simpleqi_cast<TTarget, TSource*>(piSourceNonConst, riid);
}
namespace Mso {
namespace ComUtil {
namespace Mso { namespace ComUtil {
template <typename T, typename TOther>
HRESULT HrQueryFrom(Mso::TCntPtr<T>& target, const TOther* pOther, const IID &riid = __uuidof(T)) noexcept
HRESULT HrQueryFrom(Mso::TCntPtr<T>& target, const TOther* pOther, const IID& riid = __uuidof(T)) noexcept
{
if (pOther == nullptr)
return E_POINTER;
return const_cast<TOther*>(pOther)->QueryInterface(riid, reinterpret_cast<void**>(target.ClearAndGetAddressOf()));
}
template<typename T, typename TOther>
HRESULT HrQueryFrom(Mso::TCntPtr<T>& target, const TOther& other, const IID &riid = __uuidof(T)) noexcept
{
if (other == nullptr)
return E_POINTER;
return const_cast<TOther&>(other)->QueryInterface(riid, reinterpret_cast<void**>(target.ClearAndGetAddressOf()));
if (pOther == nullptr)
return E_POINTER;
return const_cast<TOther*>(pOther)->QueryInterface(riid, reinterpret_cast<void**>(target.ClearAndGetAddressOf()));
}
template <typename T, typename TOther>
HRESULT HrQueryFrom(Mso::TCntPtr<T>& target, const Mso::TCntPtr<TOther>& other, const IID &riid = __uuidof(T)) noexcept
HRESULT HrQueryFrom(Mso::TCntPtr<T>& target, const TOther& other, const IID& riid = __uuidof(T)) noexcept
{
if (other == nullptr)
return E_POINTER;
return const_cast<Mso::TCntPtr<TOther>&>(other)->QueryInterface(riid, reinterpret_cast<void**>(target.ClearAndGetAddressOf()));
if (other == nullptr)
return E_POINTER;
return const_cast<TOther&>(other)->QueryInterface(riid, reinterpret_cast<void**>(target.ClearAndGetAddressOf()));
}
template <typename T, typename TOther>
bool FQueryFrom(Mso::TCntPtr<T>& target, const TOther* pOther, const IID &riid = __uuidof(T)) noexcept
HRESULT HrQueryFrom(Mso::TCntPtr<T>& target, const Mso::TCntPtr<TOther>& other, const IID& riid = __uuidof(T)) noexcept
{
return SUCCEEDED(HrQueryFrom(target, pOther, riid));
if (other == nullptr)
return E_POINTER;
return const_cast<Mso::TCntPtr<TOther>&>(other)->QueryInterface(
riid, reinterpret_cast<void**>(target.ClearAndGetAddressOf()));
}
template <typename T, typename TOther>
bool FQueryFrom(Mso::TCntPtr<T>& target, const TOther& other, const IID &riid = __uuidof(T)) noexcept
bool FQueryFrom(Mso::TCntPtr<T>& target, const TOther* pOther, const IID& riid = __uuidof(T)) noexcept
{
return SUCCEEDED(HrQueryFrom(target, other, riid));
return SUCCEEDED(HrQueryFrom(target, pOther, riid));
}
template<typename T, typename TOther>
bool FQueryFrom(Mso::TCntPtr<T>& target, const Mso::TCntPtr<TOther>& other, const IID &riid = __uuidof(T)) noexcept
template <typename T, typename TOther>
bool FQueryFrom(Mso::TCntPtr<T>& target, const TOther& other, const IID& riid = __uuidof(T)) noexcept
{
return SUCCEEDED(HrQueryFrom(target, other, riid));
return SUCCEEDED(HrQueryFrom(target, other, riid));
}
template <typename T, typename TOther>
bool FQueryFrom(Mso::TCntPtr<T>& target, const Mso::TCntPtr<TOther>& other, const IID& riid = __uuidof(T)) noexcept
{
return SUCCEEDED(HrQueryFrom(target, other, riid));
}
/// Checks if two IUnknown objects are equal.
template <typename T1, typename T2>
bool AreEqualObjects(const T1* pLeft, const T2* pRight) noexcept
{
if (reinterpret_cast<const void*>(pLeft) == reinterpret_cast<const void*>(pRight))
return true; // Both pointers are the same
if (pLeft == nullptr || pRight == nullptr)
return false; // One is null the other is not
if (reinterpret_cast<const void*>(pLeft) == reinterpret_cast<const void*>(pRight))
return true; // Both pointers are the same
if (pLeft == nullptr || pRight == nullptr)
return false; // One is null the other is not
// Compare IUnknown pointers.
auto punk1 = qi_cast<IUnknown>(pLeft);
if (!punk1)
return false;
// Compare IUnknown pointers.
auto punk1 = qi_cast<IUnknown>(pLeft);
if (!punk1)
return false;
auto punk2 = qi_cast<IUnknown>(pRight);
if (!punk2)
return false;
auto punk2 = qi_cast<IUnknown>(pRight);
if (!punk2)
return false;
IUnknown* pComp1 = Details::TCntPtrAddRefStrategyImpl<Details::AddRefStrategyForType<T1>::TAddRefStrategy::Strategy>::GetIUnknownForObjectCompare(punk1.Get());
IUnknown* pComp2 = Details::TCntPtrAddRefStrategyImpl<Details::AddRefStrategyForType<T2>::TAddRefStrategy::Strategy>::GetIUnknownForObjectCompare(punk2.Get());
return (pComp1 == pComp2);
IUnknown* pComp1 = Details::TCntPtrAddRefStrategyImpl<
Details::AddRefStrategyForType<T1>::TAddRefStrategy::Strategy>::GetIUnknownForObjectCompare(punk1.Get());
IUnknown* pComp2 = Details::TCntPtrAddRefStrategyImpl<
Details::AddRefStrategyForType<T2>::TAddRefStrategy::Strategy>::GetIUnknownForObjectCompare(punk2.Get());
return (pComp1 == pComp2);
}
template <typename T1, typename T2>
bool AreEqualObjects(const T1* pLeft, const Mso::TCntPtr<T2>& right) noexcept { return Mso::ComUtil::AreEqualObjects(pLeft, right.Get()); }
bool AreEqualObjects(const T1* pLeft, const Mso::TCntPtr<T2>& right) noexcept
{
return Mso::ComUtil::AreEqualObjects(pLeft, right.Get());
}
template <typename T1, typename T2>
bool AreEqualObjects(const Mso::TCntPtr<T1>& left, const T2* pRight) noexcept { return Mso::ComUtil::AreEqualObjects(left.Get(), pRight); }
bool AreEqualObjects(const Mso::TCntPtr<T1>& left, const T2* pRight) noexcept
{
return Mso::ComUtil::AreEqualObjects(left.Get(), pRight);
}
template <typename T1, typename T2>
bool AreEqualObjects(const Mso::TCntPtr<T1>& left, const Mso::TCntPtr<T2>& right) noexcept { return Mso::ComUtil::AreEqualObjects(left.Get(), right.Get()); }
bool AreEqualObjects(const Mso::TCntPtr<T1>& left, const Mso::TCntPtr<T2>& right) noexcept
{
return Mso::ComUtil::AreEqualObjects(left.Get(), right.Get());
}
} // ComUtil
} // Mso
}} // namespace Mso::ComUtil
#endif // LIBLET_COMUTIL_QICASTCORE_H

Просмотреть файл

@ -11,23 +11,22 @@
// Check if Microsoft's Structured Exception Handling (SEH) are supported.
#ifndef MSO_HAS_SEH
# if defined(_MSC_VER) || defined(__BORLANDC__)
# define MSO_HAS_SEH 1
# else
# define MSO_HAS_SEH 0
# endif
#if defined(_MSC_VER) || defined(__BORLANDC__)
#define MSO_HAS_SEH 1
#else
#define MSO_HAS_SEH 0
#endif
#endif // MSO_HAS_SEH
// Check if compiler supports UUID
#ifndef COMPILER_SUPPORTS_UUID
# if defined(__clang__) || defined(__GNUC__)
# define COMPILER_SUPPORTS_UUID 0
# elif defined(_MSC_VER)
# define COMPILER_SUPPORTS_UUID 1
# else
# error Unsupported compiler type.
# endif
#if defined(__clang__) || defined(__GNUC__)
#define COMPILER_SUPPORTS_UUID 0
#elif defined(_MSC_VER)
#define COMPILER_SUPPORTS_UUID 1
#else
#error Unsupported compiler type.
#endif
#endif
#endif // COMPILERADAPTERS_COMPILERFEATURES_H

Просмотреть файл

@ -2,15 +2,15 @@
// Licensed under the MIT license.
/**
This header contains cross-plat macros for suppressing compiler warnings
Alphabetically add a [BEGIN|END]_DISABLE_WARNING_* pair of macros for the compiler warning.
clang-only: use BEGIN_DISABLE_COMPILER_WARNING_CLANG with the -W argument
msvc-only: use BEGIN_DISABLE_COMPILER_WARNING_MSVC with the warning number
both: use BEGIN_DISABLE_COMPILER_WARNING with both values
FUTURE: auto-generate this from shared file
This header contains cross-plat macros for suppressing compiler warnings
Alphabetically add a [BEGIN|END]_DISABLE_WARNING_* pair of macros for the compiler warning.
clang-only: use BEGIN_DISABLE_COMPILER_WARNING_CLANG with the -W argument
msvc-only: use BEGIN_DISABLE_COMPILER_WARNING_MSVC with the warning number
both: use BEGIN_DISABLE_COMPILER_WARNING with both values
FUTURE: auto-generate this from shared file
*/
#ifndef LIBLET_COMPILERADAPTERS_COMPILERWARNINGS_H
#define LIBLET_COMPILERADAPTERS_COMPILERWARNINGS_H
@ -25,7 +25,8 @@
#define BEGIN_DISABLE_WARNING_HEADER_HYGIENE_VARIABLE() BEGIN_DISABLE_COMPILER_WARNING_CLANG("-Wheader-hygiene")
#define END_DISABLE_WARNING_HEADER_HYGIENE_VARIABLE() END_DISABLE_COMPILER_WARNING()
#define BEGIN_DISABLE_WARNING_INCONSISTENT_MISSING_OVERRIDE() BEGIN_DISABLE_COMPILER_WARNING_CLANG("-Winconsistent-missing-override")
#define BEGIN_DISABLE_WARNING_INCONSISTENT_MISSING_OVERRIDE() \
BEGIN_DISABLE_COMPILER_WARNING_CLANG("-Winconsistent-missing-override")
#define END_DISABLE_WARNING_INCONSISTENT_MISSING_OVERRIDE() END_DISABLE_COMPILER_WARNING()
#define BEGIN_DISABLE_WARNING_UNUSED_CONST_VARIABLE() BEGIN_DISABLE_COMPILER_WARNING_CLANG("-Wunused-const-variable")

Просмотреть файл

@ -2,8 +2,8 @@
// Licensed under the MIT license.
/**
Implementation details for suppressing compiler warnings in a cross-plat manner.
*/
Implementation details for suppressing compiler warnings in a cross-plat manner.
*/
#ifndef LIBLET_COMPILERADAPTERS_COMPILERWARNINGS_IMPL_H
#define LIBLET_COMPILERADAPTERS_COMPILERWARNINGS_IMPL_H
@ -16,9 +16,9 @@
#define COMPILER_WARNING_POP() __pragma(clang diagnostic pop)
// See https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
#elif defined (__GNUC__)
#elif defined(__GNUC__)
//TODO: Implement GCC-specific warnings.
// TODO: Implement GCC-specific warnings.
#define COMPILER_WARNING_PUSH()
#define COMPILER_WARNING_DISABLE_ALL(msvcNum, gccWarn)
#define COMPILER_WARNING_DISABLE_MSVC(msvcNum)
@ -29,23 +29,23 @@
#define COMPILER_WARNING_PUSH() __pragma(warning(push))
#define COMPILER_WARNING_DISABLE_ALL(msvcNum, clangWarn) COMPILER_WARNING_DISABLE_MSVC(msvcNum)
#define COMPILER_WARNING_DISABLE_MSVC(msvcNum) __pragma(warning(disable:##msvcNum))
#define COMPILER_WARNING_DISABLE_MSVC(msvcNum) __pragma(warning(disable :##msvcNum))
#define COMPILER_WARNING_DISABLE_CLANG(clangWarn)
#define COMPILER_WARNING_POP() __pragma(warning(pop))
#endif
#define BEGIN_DISABLE_COMPILER_WARNING_ALL(msvcNum, clangWarn) \
COMPILER_WARNING_PUSH() \
COMPILER_WARNING_DISABLE_ALL(msvcNum, clangWarn) \
COMPILER_WARNING_PUSH() \
COMPILER_WARNING_DISABLE_ALL(msvcNum, clangWarn)
#define BEGIN_DISABLE_COMPILER_WARNING_MSVC(msvcNum) \
COMPILER_WARNING_PUSH() \
COMPILER_WARNING_DISABLE_MSVC(msvcNum) \
COMPILER_WARNING_PUSH() \
COMPILER_WARNING_DISABLE_MSVC(msvcNum)
#define BEGIN_DISABLE_COMPILER_WARNING_CLANG(clangWarn) \
COMPILER_WARNING_PUSH() \
COMPILER_WARNING_DISABLE_CLANG(clangWarn) \
COMPILER_WARNING_PUSH() \
COMPILER_WARNING_DISABLE_CLANG(clangWarn)
#define END_DISABLE_COMPILER_WARNING() COMPILER_WARNING_POP()

Просмотреть файл

@ -2,21 +2,21 @@
// Licensed under the MIT license.
/**
Various low level macros that are globally useful
Various low level macros that are globally useful
*/
#pragma once
#ifndef COMPILERADAPTERS_CPPMACROS_H
#define COMPILERADAPTERS_CPPMACROS_H
/**
Broadly used macros
Broadly used macros
*/
#ifndef FImplies
#define FImplies(a, b) (!(a) || (b))
#define FImplies(a, b) (!(a) || (b))
#endif
#ifndef FBiImplies
#define FBiImplies(a, b) (!(a) == !(b))
#define FBiImplies(a, b) (!(a) == !(b))
#endif
#ifndef RgC
@ -24,75 +24,94 @@
#endif
/**
Statement - used for control flow macros like Check, IfFailGo
Make the macro act like a statement.
Statement - used for control flow macros like Check, IfFailGo
Make the macro act like a statement.
*/
#ifndef __GNUC__
#define Statement(x) __pragma(warning(push)) __pragma(warning(disable:4127 25037)) do { x; } while(0) __pragma(warning(pop))
#define Statement(x) \
__pragma(warning(push)) __pragma(warning(disable : 4127 25037)) do \
{ \
x; \
} \
while (0) \
__pragma(warning(pop))
#else
#define Statement(x) do { x; } while(0)
// error: there are no arguments to '__noop' that depend on a template parameter, so a declaration of '__noop' must be available [-fpermissive]
#define Statement(x) \
do \
{ \
x; \
} while (0)
// error: there are no arguments to '__noop' that depend on a template parameter, so a declaration of '__noop' must be
// available [-fpermissive]
#define __noop()
#endif
/**
Prevent the compiler from automatically providing implementations of various
class features. Use the macro in your class public: section.
TODO: probably need to update with new Move functions
Prevent the compiler from automatically providing implementations of various
class features. Use the macro in your class public: section.
TODO: probably need to update with new Move functions
*/
#ifndef __GNUC__
#define MSO_NO_COPYCONSTR( C ) __pragma(warning(suppress:4822)) C(const C&) = delete
#define MSO_NO_ASSIGNMENT( C ) __pragma(warning(suppress:4822)) const C& operator=(const C&) = delete
#define MSO_NO_DEFAULTCONSTR( C ) __pragma(warning(suppress:4822)) explicit C() = delete
#define MSO_NO_COPYCONSTR(C) __pragma(warning(suppress : 4822)) C(const C &) = delete
#define MSO_NO_ASSIGNMENT(C) __pragma(warning(suppress : 4822)) const C &operator=(const C &) = delete
#define MSO_NO_DEFAULTCONSTR(C) __pragma(warning(suppress : 4822)) explicit C() = delete
#else
#define MSO_NO_COPYCONSTR( C ) C(const C&) = delete
#define MSO_NO_ASSIGNMENT( C ) const C& operator=(const C&) = delete
#define MSO_NO_DEFAULTCONSTR( C ) explicit C() = delete
#define MSO_NO_COPYCONSTR(C) C(const C &) = delete
#define MSO_NO_ASSIGNMENT(C) const C &operator=(const C &) = delete
#define MSO_NO_DEFAULTCONSTR(C) explicit C() = delete
#endif
#ifndef DECLARE_COPYCONSTR_AND_ASSIGNMENT
#define DECLARE_COPYCONSTR_AND_ASSIGNMENT( C ) MSO_NO_COPYCONSTR( C ); MSO_NO_ASSIGNMENT( C )
#define DECLARE_COPYCONSTR_AND_ASSIGNMENT(C) \
MSO_NO_COPYCONSTR(C); \
MSO_NO_ASSIGNMENT(C)
#endif
#if defined(__cplusplus)
#include <type_traits>
/**
When using an enum class to define a set of bitflags, normal bitflag
enum operations, such as |, ^, and &, don't work without lots of casts.
Use this macro to define |, ^, and & for your enum class, where |, ^ and ~
will return an enum class type, and & will evaluate to true or false.
The implementation causes error C3281 (global operator cannot have
managed type in signature) for managed code.
When using an enum class to define a set of bitflags, normal bitflag
enum operations, such as |, ^, and &, don't work without lots of casts.
Use this macro to define |, ^, and & for your enum class, where |, ^ and ~
will return an enum class type, and & will evaluate to true or false.
The implementation causes error C3281 (global operator cannot have
managed type in signature) for managed code.
*/
#define ENUM_CLASS_FLAGS_OPERATORS(TEnum) \
constexpr TEnum operator~(TEnum a) noexcept \
{ \
return static_cast<TEnum>(~static_cast<std::underlying_type<TEnum>::type>(a)); \
} \
constexpr TEnum operator|(TEnum a, TEnum b) noexcept \
{ \
return static_cast<TEnum>(static_cast<std::underlying_type<TEnum>::type>(a) | static_cast<std::underlying_type<TEnum>::type>(b)); \
} \
constexpr bool operator&(TEnum a, TEnum b) noexcept \
{ \
return !!(static_cast<std::underlying_type<TEnum>::type>(a) & static_cast<std::underlying_type<TEnum>::type>(b)); \
} \
constexpr TEnum operator^(TEnum a, TEnum b) noexcept \
{ \
return static_cast<TEnum>(static_cast<std::underlying_type<TEnum>::type>(a) ^ static_cast<std::underlying_type<TEnum>::type>(b)); \
} \
inline TEnum& operator|=(TEnum& a, TEnum b) noexcept \
{ \
return reinterpret_cast<TEnum&>(reinterpret_cast<std::underlying_type<TEnum>::type&>(a) |= static_cast<std::underlying_type<TEnum>::type>(b)); \
} \
inline TEnum& operator&=(TEnum& a, TEnum b) noexcept \
{ \
return reinterpret_cast<TEnum&>(reinterpret_cast<std::underlying_type<TEnum>::type&>(a) &= static_cast<std::underlying_type<TEnum>::type>(b)); \
} \
inline TEnum& operator^=(TEnum& a, TEnum b) noexcept \
{ \
return reinterpret_cast<TEnum&>(reinterpret_cast<std::underlying_type<TEnum>::type&>(a) ^= static_cast<std::underlying_type<TEnum>::type>(b)); \
}
#define ENUM_CLASS_FLAGS_OPERATORS(TEnum) \
constexpr TEnum operator~(TEnum a) noexcept \
{ \
return static_cast<TEnum>(~static_cast<std::underlying_type<TEnum>::type>(a)); \
} \
constexpr TEnum operator|(TEnum a, TEnum b) noexcept \
{ \
return static_cast<TEnum>(static_cast<std::underlying_type<TEnum>::type>(a) | \
static_cast<std::underlying_type<TEnum>::type>(b)); \
} \
constexpr bool operator&(TEnum a, TEnum b) noexcept \
{ \
return !!(static_cast<std::underlying_type<TEnum>::type>(a) & \
static_cast<std::underlying_type<TEnum>::type>(b)); \
} \
constexpr TEnum operator^(TEnum a, TEnum b) noexcept \
{ \
return static_cast<TEnum>(static_cast<std::underlying_type<TEnum>::type>(a) ^ \
static_cast<std::underlying_type<TEnum>::type>(b)); \
} \
inline TEnum &operator|=(TEnum &a, TEnum b) noexcept \
{ \
return reinterpret_cast<TEnum &>(reinterpret_cast<std::underlying_type<TEnum>::type &>(a) |= \
static_cast<std::underlying_type<TEnum>::type>(b)); \
} \
inline TEnum &operator&=(TEnum &a, TEnum b) noexcept \
{ \
return reinterpret_cast<TEnum &>(reinterpret_cast<std::underlying_type<TEnum>::type &>(a) &= \
static_cast<std::underlying_type<TEnum>::type>(b)); \
} \
inline TEnum &operator^=(TEnum &a, TEnum b) noexcept \
{ \
return reinterpret_cast<TEnum &>(reinterpret_cast<std::underlying_type<TEnum>::type &>(a) ^= \
static_cast<std::underlying_type<TEnum>::type>(b)); \
}
#else // !__cplusplus
@ -101,9 +120,9 @@
#endif // !__cplusplus
/**
Macros to help share enums between C++ and CX.
Enums must derive from int (the default)
Flag enums must derive from unsigned int
Macros to help share enums between C++ and CX.
Enums must derive from int (the default)
Flag enums must derive from unsigned int
*/
#if defined(_WINRT_COMP) && !defined(__clang__)
#define EXPOSE_WINRT_ENUM public
@ -114,9 +133,9 @@
#endif
/**
Macros to force placement of symbols into a particular segment.
For example on iOS ensure large globals aren't placed in the text
segment because there is a size limit enforced by Apple.
Macros to force placement of symbols into a particular segment.
For example on iOS ensure large globals aren't placed in the text
segment because there is a size limit enforced by Apple.
*/
#if MS_TARGET_APPLE
#define DATA_SEGMENT_CONST __attribute__((section("__DATA,__const")))
@ -125,7 +144,7 @@
#endif
#if __GNUC__
#define __forceinline __attribute__ ((always_inline, unused))
#define __forceinline __attribute__((always_inline, unused))
// Stub __declspec in GCC
#define __declspec(s)
#endif

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Some globally useful debug-only macros
Some globally useful debug-only macros
*/
#pragma once
#ifndef COMPILERADAPTERS_CPPMACROSDEBUG_H
@ -16,11 +16,11 @@
#if DEBUG
#define FILELINEPARAMSCOREUNUSED const char*, uint32_t
#define FILELINEPARAMSUNUSED , FILELINEPARAMSCOREUNUSED
#define FILELINEPARAMSOPTCORE const char* szFile = __FILE__, uint32_t iLine = __LINE__
#define FILELINEPARAMSOPTCORE const char *szFile = __FILE__, uint32_t iLine = __LINE__
#define FILELINEPARAMSOPT , FILELINEPARAMSOPTCORE
#define FILELINEPARAMSOPTUNUSEDCORE const char* = __FILE__, uint32_t = __LINE__
#define FILELINEPARAMSOPTUNUSED , FILELINEPARAMSOPTUNUSEDCORE
#define FILELINEPARAMSCORE const char* szFile, uint32_t iLine
#define FILELINEPARAMSCORE const char *szFile, uint32_t iLine
#define FILELINEPARAMS , FILELINEPARAMSCORE
#define FILELINEVARSCORE szFile, iLine
#define FILELINEVARS , FILELINEVARSCORE
@ -51,7 +51,7 @@
#if DEBUG
#define Debug(e) e
#define DebugOnly(e) e
#define DebugElse(s, t) s
#define DebugElse(s, t) s
#define DebugList(e) (e),
#define DebugParam(e) , e
#define DebugFill(pb, cb) (memset((pb), 0xCC, (cb)))
@ -59,21 +59,24 @@
#define Debug(e)
#define DebugOnly(e)
#define DebugElse(s, t) t
#define DebugList(e)
#define DebugList(e)
#define DebugParam(e)
#define DebugFill(pb, cb) (1)
#endif
/**
MsoDebugBreak can be used inside expressions.
Otherwise code should use __debugbreak() directly.
Otherwise code should use __debugbreak() directly.
*/
#ifdef DEBUG
__inline int32_t MsoDebugBreak(void)
__inline int32_t MsoDebugBreak(void)
#ifdef __cplusplus
noexcept
noexcept
#endif // __cplusplus
{ __debugbreak(); return 0; }
{
__debugbreak();
return 0;
}
#else
#define MsoDebugBreak() (0)
#endif

Просмотреть файл

@ -2,8 +2,8 @@
// Licensed under the MIT license.
/**
Cross-compiler support for declspec things
FUTURE: reconcile this with compilerFeatures.h
Cross-compiler support for declspec things
FUTURE: reconcile this with compilerFeatures.h
*/
#pragma once
#ifndef COMPILERADAPTERS_DECLSPECDEFINITIONS_H
@ -31,14 +31,14 @@
// Latest versions of clang supports this natively
#ifndef DECLSPEC_SELECTANY
#define DECLSPEC_SELECTANY __declspec(selectany)
#define DECLSPEC_SELECTANY __declspec(selectany)
#endif
// Mark the variable to be the first to be inited in the global init sequence.
// GCC/Clang does not have init_seg, rather has a priority 101-65535 where 101 is the highest
#ifndef DECLSPEC_INITFIRST
#if defined(__clang__) || defined(__GNUC__)
#define DECLSPEC_INITFIRST __attribute__ ((init_priority (101)))
#define DECLSPEC_INITFIRST __attribute__((init_priority(101)))
#else
#define DECLSPEC_INITFIRST
#endif
@ -57,18 +57,18 @@
#if defined(__clang__) || !defined(__cplusplus) || defined(__GNUC__)
#define DECLSPEC_NOVTABLE
#else
#define DECLSPEC_NOVTABLE __declspec(novtable)
#define DECLSPEC_NOVTABLE __declspec(novtable)
#endif
#endif
#ifndef DECLSPEC_DEPRECATED
# if defined(__clang__) || defined(__GNUC__)
# define DECLSPEC_DEPRECATED __attribute__((deprecated))
# elif !defined(MIDL_PASS)
# define DECLSPEC_DEPRECATED __declspec(deprecated)
# else
# define DECLSPEC_DEPRECATED
# endif
#if defined(__clang__) || defined(__GNUC__)
#define DECLSPEC_DEPRECATED __attribute__((deprecated))
#elif !defined(MIDL_PASS)
#define DECLSPEC_DEPRECATED __declspec(deprecated)
#else
#define DECLSPEC_DEPRECATED
#endif
#endif
#endif // COMPILERADAPTERS_DECLSPECDEFINITIONS_H

Просмотреть файл

@ -2,61 +2,61 @@
// Licensed under the MIT license.
/**
Cross-platform/language macros to decorate APIs
Cross-platform/language macros to decorate APIs
*/
#pragma once
#ifndef COMPILERADAPTERS_FUNCTIONDECORATIONS_H
#define COMPILERADAPTERS_FUNCTIONDECORATIONS_H
/**
The Liblet::PublicApi attribute is used to mark a function, class or
class method as part of your public API. These are automatically
added to your export file and shim DLL.
Note: Your liblet must be configured to process PublicApi.
Note: PublicApi replaces all MSOAPI/MSOCPPAPI-style macros.
Note: See http://aka.ms/cppdef
Platform specific APIs are filtered using standard strings:
win, win32, win32client, win32server, winrt, android
The Liblet::PublicApi attribute is used to mark a function, class or
class method as part of your public API. These are automatically
added to your export file and shim DLL.
Usage: an API is exported for all targets
LIBLET_PUBLICAPI void MyApi() noexcept;
Usage: exporting static methods on a class/interface
struct MyInterface
{
LIBLET_PUBLICAPI static MyInterface* Create();
...
};
Usage: platform-specific APIs
LIBLET_PUBLICAPI_EX("win32") void MyDesktop();
LIBLET_PUBLICAPI_EX("winrt") void MyStore();
LIBLET_PUBLICAPI_EX("win32", "android") void MyApi();
Note: LIBLET_PUBLICAPI_EX(...) is not supported on Apple platforms,
Use LIBLET_PUBLICAPI_APPLE instead.
LIBLET_PUBLICAPI_EX("winrt") LIBLET_PUBLICAPI_APPLE void MyApi();
Note: Your liblet must be configured to process PublicApi.
Note: PublicApi replaces all MSOAPI/MSOCPPAPI-style macros.
Note: See http://aka.ms/cppdef
Usage: export a whole class (heavily discouraged)
struct LIBLET_PUBLICAPI MyExportedClass
{
// override default class export
LIBLET_PUBLICAPI_EX("win32") void MyDesktop();
Platform specific APIs are filtered using standard strings:
win, win32, win32client, win32server, winrt, android
void AlsoExported();
};
Usage: export special data types from a class (android + apple only)
Values: "typeinfo", "typeinfoname", "vtable", "thunks"
struct LIBLET_PUBLICAPI_CLASSDATA("typeinfo") MyClass
{
};
Usage: an API is exported for all targets
LIBLET_PUBLICAPI void MyApi() noexcept;
struct LIBLET_PUBLICAPI_CLASSDATA("typeinfo", "vtable") MyClass
{
};
Usage: exporting static methods on a class/interface
struct MyInterface
{
LIBLET_PUBLICAPI static MyInterface* Create();
...
};
Usage: platform-specific APIs
LIBLET_PUBLICAPI_EX("win32") void MyDesktop();
LIBLET_PUBLICAPI_EX("winrt") void MyStore();
LIBLET_PUBLICAPI_EX("win32", "android") void MyApi();
Note: LIBLET_PUBLICAPI_EX(...) is not supported on Apple platforms,
Use LIBLET_PUBLICAPI_APPLE instead.
LIBLET_PUBLICAPI_EX("winrt") LIBLET_PUBLICAPI_APPLE void MyApi();
Usage: export a whole class (heavily discouraged)
struct LIBLET_PUBLICAPI MyExportedClass
{
// override default class export
LIBLET_PUBLICAPI_EX("win32") void MyDesktop();
void AlsoExported();
};
Usage: export special data types from a class (android + apple only)
Values: "typeinfo", "typeinfoname", "vtable", "thunks"
struct LIBLET_PUBLICAPI_CLASSDATA("typeinfo") MyClass
{
};
struct LIBLET_PUBLICAPI_CLASSDATA("typeinfo", "vtable") MyClass
{
};
*/
#if defined(__clangpluginrunner__)
#define LIBLET_PUBLICAPI [[Liblet::PublicApi]]
@ -85,19 +85,19 @@
#endif
/**
The Liblet::MockName macro enables renaming of the generated mock names.
This is useful when the function / interface method is overloaded.
struct IBank
{
// Generate mock_TryWithdrawlUint32
LIBLET_MOCKNAME("TryWithdrawlUint32")
virtual bool TryWithdrawl(uint32_t amount) = 0;
The Liblet::MockName macro enables renaming of the generated mock names.
This is useful when the function / interface method is overloaded.
// Generate mock_TryWithdrawlFloat
LIBLET_MOCKNAME("TryWithdrawlFloat")
virtual bool TryWithdrawl(float amount) = 0;
};
struct IBank
{
// Generate mock_TryWithdrawlUint32
LIBLET_MOCKNAME("TryWithdrawlUint32")
virtual bool TryWithdrawl(uint32_t amount) = 0;
// Generate mock_TryWithdrawlFloat
LIBLET_MOCKNAME("TryWithdrawlFloat")
virtual bool TryWithdrawl(float amount) = 0;
};
*/
#if defined(__clangpluginrunner__)
#define LIBLET_MOCKNAME(name) [[Liblet::MockName(name)]]
@ -106,21 +106,23 @@
#endif
/**
Macros for extern "C" that support C & C++
Macros for extern "C" that support C & C++
*/
#if defined(__cplusplus)
#define MSOEXTERN_C extern "C"
#define MSOEXTERN_C_BEGIN extern "C" {
#define MSOEXTERN_C_BEGIN \
extern "C" \
{
#define MSOEXTERN_C_END }
#else
#define MSOEXTERN_C
#define MSOEXTERN_C
#define MSOEXTERN_C_BEGIN
#define MSOEXTERN_C_END
#endif
/**
Macro for constexpr
FUTURE: VC14 supports constexpr
Macro for constexpr
FUTURE: VC14 supports constexpr
*/
#if defined(__cplusplus) && defined(__clang__)
#define MSOCONSTEXPR constexpr
@ -129,7 +131,7 @@
#endif
/**
Macros to use nothrow/throw not on clang
Macros to use nothrow/throw not on clang
*/
#if defined(__cplusplus) && !defined(__clang__)
/* SSS_WARNINGS_OFF */
@ -140,7 +142,7 @@
#endif // C++
/**
Macro to enable noexcept only for C++
Macro to enable noexcept only for C++
*/
#if defined(__cplusplus)
#define MSONOEXCEPT noexcept
@ -149,25 +151,25 @@
#endif // C++
/**
Macro to mark a method as const for C & C++
Macro to mark a method as const for C & C++
*/
#if defined(__cplusplus) && !defined(CINTERFACE)
#define CONST_METHOD const
#define CONST_METHOD const
#else
#define CONST_METHOD
#define CONST_METHOD
#endif
/**
Utility macro to make writing NonConst versions of functions easier.
In C, you can't overload functions; thus the two flavors of a function will be
DoSomething
DoSomethingNonConst
In C++, you can overload functions, so the two flavors of a function will have
the same name (but with different arguments).
Utility macro to make writing NonConst versions of functions easier.
In C, you can't overload functions; thus the two flavors of a function will be
DoSomething
DoSomethingNonConst
In C++, you can overload functions, so the two flavors of a function will have
the same name (but with different arguments).
To work around this, declare the second function as NON_CONST_VER(DoSomething)
This also can be used when you explicitly want to call the nonConst version from
an inline function that can be compiled as either C or C++
To work around this, declare the second function as NON_CONST_VER(DoSomething)
This also can be used when you explicitly want to call the nonConst version from
an inline function that can be compiled as either C or C++
*/
#if defined(__cplusplus)
#define NON_CONST_VER(Function) Function
@ -177,7 +179,7 @@
#define NON_CONST_VER_DECL(Function) NON_CONST_VER(Function)
/**
Macro to use __forceinline with cl.exe
Macro to use __forceinline with cl.exe
*/
/* SSS_WARNINGS_OFF */
#if defined(__cplusplus) && !defined(__clang__)
@ -188,14 +190,14 @@
/* SSS_WARNINGS_ON */
#if defined(__clang__)
#define MSO_NO_INLINE __attribute__((noinline))
#define MSO_NO_INLINE __attribute__((noinline))
#else
#define MSO_NO_INLINE __declspec(noinline)
#define MSO_NO_INLINE __declspec(noinline)
#endif
/**
Clang forbids the use of static with friend.
msvc issues warning C4211: nonstandard extension used: redefined extern to static without it
Clang forbids the use of static with friend.
msvc issues warning C4211: nonstandard extension used: redefined extern to static without it
*/
#if defined(__clang__)
#define MSO_STATIC_FRIEND friend
@ -203,26 +205,25 @@
#define MSO_STATIC_FRIEND friend static
#endif
// Don't use any of these macros, they are being eliminated
// The definitions are a mess to prevent removed macros from sneaking back in
#if defined(__cplusplus) && !defined(__clang__)
/* SSS_WARNINGS_OFF */
#define MSOCPPAPI_(t) extern "C++" __declspec(nothrow) t __cdecl
#define MSOCPPAPI_(t) extern "C++" __declspec(nothrow) t __cdecl
#if defined(_M_X64)
#define MSOAPI_(t) MSOEXTERN_C __declspec(nothrow) t __fastcall
#define MSOAPI_(t) MSOEXTERN_C __declspec(nothrow) t __fastcall
#else
#define MSOAPI_(t) MSOEXTERN_C __declspec(nothrow) t __stdcall
#define MSOAPI_(t) MSOEXTERN_C __declspec(nothrow) t __stdcall
#endif
/* SSS_WARNINGS_ON */
#else
#define MSOCPPAPI_(t) extern "C++" t __cdecl
#define MSOCPPAPI_(t) extern "C++" t __cdecl
#if defined(_M_X64)
#define MSOAPI_(t) MSOEXTERN_C t __fastcall
#define MSOAPI_(t) MSOEXTERN_C t __fastcall
#else
#define MSOAPI_(t) MSOEXTERN_C t __stdcall
#define MSOAPI_(t) MSOEXTERN_C t __stdcall
#endif
#endif

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Adapters for various compiler intrinsics
Adapters for various compiler intrinsics
*/
#pragma once
#ifndef COMPILERADAPTERS_INTRINSICS_H
@ -10,12 +10,12 @@
/** Macro that calls compiler intrinsics to terminate the application and bypass all exception handlers */
#if defined(__clang__) || defined(__GNUC__)
#define MSOFASTFAIL(arg) __builtin_trap()
#define MSO_FUNC_RETURN_ADDRESS() __builtin_return_address(0)
#define MSOFASTFAIL(arg) __builtin_trap()
#define MSO_FUNC_RETURN_ADDRESS() __builtin_return_address(0)
#else
#include <intrin.h>
#define MSOFASTFAIL(arg) __fastfail(arg)
#define MSO_FUNC_RETURN_ADDRESS() _ReturnAddress()
#include <intrin.h>
#define MSOFASTFAIL(arg) __fastfail(arg)
#define MSO_FUNC_RETURN_ADDRESS() _ReturnAddress()
#endif
#endif

Просмотреть файл

@ -2,29 +2,30 @@
// Licensed under the MIT license.
/**
Things related to linking
Things related to linking
*/
#pragma once
#ifndef COMPILERADAPTERS_LINKER_H
#define COMPILERADAPTERS_LINKER_H
/**
If a library has no direct entry points, it may be necessary to force
the linker to include it. There are two ways to accomplish this:
If a library has no direct entry points, it may be necessary to force
the linker to include it. There are two ways to accomplish this:
1) Preferably - link the library as a LOB instead.
1) Preferably - link the library as a LOB instead.
2) Use MSO_DEFINE_SYMBOL to define a symbol in the source file that needs to
be included. Then, add the corresponding MSO_LINK_SYMBOL macro to one of the
source files that gets compiled directly into your binary (as an *.obj file)
2) Use MSO_DEFINE_SYMBOL to define a symbol in the source file that needs to
be included. Then, add the corresponding MSO_LINK_SYMBOL macro to one of the
source files that gets compiled directly into your binary (as an *.obj file)
*/
#define MSO_DEFINE_SYMBOL(symbol) extern "C" void __cdecl symbol() {}
#define MSO_DEFINE_SYMBOL(symbol) \
extern "C" void __cdecl symbol() {}
// MSO_LINK_INCLUDE and MSO_LINK_SYMBOL macros are only needed for MSVC.
#if MS_TARGET_WINDOWS
/**
Machinery for the MSO_LINK_SYMBOL macro
Machinery for the MSO_LINK_SYMBOL macro
*/
#if defined(_M_HYBRID)
#define MSO_LINK_INCLUDE(symbol) "/INCLUDE:#" symbol
@ -37,24 +38,24 @@
#endif
/**
See MSO_DEFINE_SYMBOL above
See MSO_DEFINE_SYMBOL above
*/
#define MSO_LINK_SYMBOL( symbol ) __pragma( comment( linker, MSO_LINK_INCLUDE( #symbol ) ) )
#define MSO_LINK_SYMBOL(symbol) __pragma(comment(linker, MSO_LINK_INCLUDE(#symbol)))
/**
Platform-agnostic macro to define dll export name ("foo" vs "_foo@4")
The number is generally [# of params * 4].
Platform-agnostic macro to define dll export name ("foo" vs "_foo@4")
The number is generally [# of params * 4].
Note: using GetProcAddress is usually wrong. Prefer linker delay-loading.
Note: using GetProcAddress is usually wrong. Prefer linker delay-loading.
Example:
void Foo(int bar);
auto pFoo = (decltype(Foo) *) GetProcAddress(hMod, SzDllExport("Foo", 4));
Example:
void Foo(int bar);
auto pFoo = (decltype(Foo) *) GetProcAddress(hMod, SzDllExport("Foo", 4));
*/
#if defined(_M_X64) || defined(_M_ARM)
#define SzDllExport( fn, c ) fn
#define SzDllExport(fn, c) fn
#elif defined(_M_IX86)
#define SzDllExport( fn, c ) "_" fn "@" #c
#define SzDllExport(fn, c) "_" fn "@" #c
#else
#error Unknown Platform!
#endif // x64 || _M_ARM

Просмотреть файл

@ -2,22 +2,22 @@
// Licensed under the MIT license.
/**
Support for managed C++ compilation available only in VC++.
Support for managed C++ compilation available only in VC++.
*/
#pragma once
#ifndef COMPILERADAPTERS_MANAGEDCPP_H
#define COMPILERADAPTERS_MANAGEDCPP_H
/**
VC++ specific pragmas to indicate that code must not be compiled as managed.
Functions are compiled as managed by default when /clr is used.
The pragmas below allow explicitly indicate that code is unmanaged, but these
pragmas are not recognized by Clang compiler.
VC++ specific pragmas to indicate that code must not be compiled as managed.
Functions are compiled as managed by default when /clr is used.
The pragmas below allow explicitly indicate that code is unmanaged, but these
pragmas are not recognized by Clang compiler.
*/
#if !defined(__clang__)
#define MSO_PRAGMA_MANAGED_PUSH_OFF __pragma(managed(push, off))
#define MSO_PRAGMA_MANAGED_POP __pragma(managed(pop))
#define MSO_PRAGMA_MANAGED_POP __pragma(managed(pop))
#else // !defined(__clang__)

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Helper classes to automatically restore/cleanup/undo an operation.
Helper classes to automatically restore/cleanup/undo an operation.
*/
#ifndef _CPPEXTENSIONS_AUTORESTORE_H_
#define _CPPEXTENSIONS_AUTORESTORE_H_
@ -15,224 +15,244 @@
// 4472: 'pointer_safety' is a native enum: add an access specifier (private/public) to declare a managed enum
// 4996: 'wmemcpy': This function or variable may be unsafe. Consider using wmemcpy_s instead
#pragma warning(push)
#pragma warning(disable: 4091 4472 4996)
#pragma warning(disable : 4091 4472 4996)
#include <memory>
#pragma warning(pop)
// 4996: 'wmemcpy': This function or variable may be unsafe. Consider using wmemcpy_s instead
#pragma warning(push)
#pragma warning(disable: 4996)
#pragma warning(disable : 4996)
#include <utility>
#pragma warning(pop)
namespace Mso {
/**
Restores a variable to its original value in an exception-safe way.
For example:
{
Mso::TRestorer<bool> restoreFlag(m_fFlag, true);
... // do something that might throw an exception
} // m_fFlag is automatically restored to its original value
Restores a variable to its original value in an exception-safe way.
For example:
{
Mso::TRestorer<bool> restoreFlag(m_fFlag, true);
... // do something that might throw an exception
} // m_fFlag is automatically restored to its original value
*/
template<typename T> class TRestorer
template <typename T>
class TRestorer
{
public:
TRestorer(T& value) noexcept : m_pValue(std::addressof(value)), m_previousValue(value) {}
TRestorer(T& value, T newValue) noexcept : m_pValue(std::addressof(value)), m_previousValue(value)
{ *m_pValue = newValue; }
TRestorer(TRestorer&& other) noexcept : m_pValue(other.m_pValue), m_previousValue(other.m_previousValue)
{ other.Disable(); }
~TRestorer() noexcept { *m_pValue = m_previousValue; }
TRestorer(T& value) noexcept : m_pValue(std::addressof(value)), m_previousValue(value) {}
TRestorer(T& value, T newValue) noexcept : m_pValue(std::addressof(value)), m_previousValue(value)
{
*m_pValue = newValue;
}
TRestorer(TRestorer&& other) noexcept : m_pValue(other.m_pValue), m_previousValue(other.m_previousValue)
{
other.Disable();
}
~TRestorer() noexcept
{
*m_pValue = m_previousValue;
}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TRestorer);
TRestorer& operator=(TRestorer&& other) noexcept = delete;
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TRestorer);
TRestorer& operator=(TRestorer&& other) noexcept = delete;
bool IsEnabled() noexcept { return (m_pValue != std::addressof(m_previousValue)); }
void Disable() noexcept { m_pValue = std::addressof(m_previousValue); }
bool IsEnabled() noexcept
{
return (m_pValue != std::addressof(m_previousValue));
}
void Disable() noexcept
{
m_pValue = std::addressof(m_previousValue);
}
private:
T* m_pValue;
T m_previousValue;
T* m_pValue;
T m_previousValue;
};
/**
AutoRestorer() can be used to avoid being explicit with TRestorer
AutoRestorer() can be used to avoid being explicit with TRestorer
Instead of:
Mso::TRestorer<bool> restorer(m_inLayout);
Do this:
auto restorer = Mso::AutoRestorer(m_inLayout);
Instead of:
Mso::TRestorer<bool> restorer(m_inLayout);
Do this:
auto restorer = Mso::AutoRestorer(m_inLayout);
*/
template <typename T>
Mso::TRestorer<T> AutoRestorer(T &value) noexcept
Mso::TRestorer<T> AutoRestorer(T& value) noexcept
{
return Mso::TRestorer<T>(value);
return Mso::TRestorer<T>(value);
}
template <typename T>
Mso::TRestorer<T> AutoRestorer(T &value, T newValue) noexcept
Mso::TRestorer<T> AutoRestorer(T& value, T newValue) noexcept
{
return Mso::TRestorer<T>(value, newValue);
return Mso::TRestorer<T>(value, newValue);
}
/**
Restores a value to its original value (using a getter/setter) in an exception-safe way. For example:
Restores a value to its original value (using a getter/setter) in an exception-safe way. For example:
Foo* GetGlobalFoo()
{
return s_pFooGlobal;
}
Foo* GetGlobalFoo()
{
return s_pFooGlobal;
}
void SetGlobalFoo(Foo* pFoo)
{
s_pFooGlobal = pFoo;
}
void SetGlobalFoo(Foo* pFoo)
{
s_pFooGlobal = pFoo;
}
using GlobalFooRestorer = Mso::TPropertyRestorer<Foo*, GetGlobalFoo, SetGlobalFoo>;
using GlobalFooRestorer = Mso::TPropertyRestorer<Foo*, GetGlobalFoo, SetGlobalFoo>;
void MyMethod(Foo* pFoo)
{
GlobalFooRestorer rstGlobalFoo(pFoo);
... // do something that might throw an exception
} // s_pFooGlobal is automatically restored to its original value
void MyMethod(Foo* pFoo)
{
GlobalFooRestorer rstGlobalFoo(pFoo);
... // do something that might throw an exception
} // s_pFooGlobal is automatically restored to its original value
*/
template<
typename T,
T PfnGetter(),
void PfnSetter(T value)>
template <typename T, T PfnGetter(), void PfnSetter(T value)>
struct TPropertyRestorer final
{
public:
TPropertyRestorer() = default;
TPropertyRestorer(T newValue) noexcept(noexcept(PfnSetter(PfnGetter()))) // noexcept(any expression with both Get and Set)
{
PfnSetter(std::forward<T>(newValue));
}
TPropertyRestorer(TPropertyRestorer&& other) noexcept :
m_isDisabled(other.m_isDisabled),
m_valueToRestore(std::forward<T>(other.m_valueToRestore))
{
other.Disable();
}
TPropertyRestorer() = default;
TPropertyRestorer(T newValue) noexcept(
noexcept(PfnSetter(PfnGetter()))) // noexcept(any expression with both Get and Set)
{
PfnSetter(std::forward<T>(newValue));
}
TPropertyRestorer(TPropertyRestorer&& other) noexcept
: m_isDisabled(other.m_isDisabled), m_valueToRestore(std::forward<T>(other.m_valueToRestore))
{
other.Disable();
}
~TPropertyRestorer()
{
if (!m_isDisabled)
{
PfnSetter(std::forward<T>(m_valueToRestore));
}
}
~TPropertyRestorer()
{
if (!m_isDisabled)
{
PfnSetter(std::forward<T>(m_valueToRestore));
}
}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TPropertyRestorer); // No copying!
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TPropertyRestorer); // No copying!
template<typename TSelf = TPropertyRestorer, typename = typename std::enable_if_t<std::is_move_assignable<typename std::remove_reference<T>::type>::value, TSelf>>
TSelf& operator=(TSelf&& other) noexcept
{
if (this != &other)
{
m_isDisabled = other.m_isDisabled;
m_valueToRestore = std::move(other.m_valueToRestore);
template <
typename TSelf = TPropertyRestorer,
typename =
typename std::enable_if_t<std::is_move_assignable<typename std::remove_reference<T>::type>::value, TSelf>>
TSelf& operator=(TSelf&& other) noexcept
{
if (this != &other)
{
m_isDisabled = other.m_isDisabled;
m_valueToRestore = std::move(other.m_valueToRestore);
other.Disable();
}
other.Disable();
}
return *this;
}
return *this;
}
bool IsEnabled() const noexcept { return !m_isDisabled; }
void Disable() noexcept { m_isDisabled = true; }
bool IsEnabled() const noexcept
{
return !m_isDisabled;
}
void Disable() noexcept
{
m_isDisabled = true;
}
T& ValueToRestore() noexcept { return m_valueToRestore; }
T& ValueToRestore() noexcept
{
return m_valueToRestore;
}
private:
bool m_isDisabled = false;
T m_valueToRestore{PfnGetter()};
bool m_isDisabled = false;
T m_valueToRestore{PfnGetter()};
};
namespace TCleanup
{
namespace TCleanup {
/**
TCleanup
The last resort. If none of the other helper classes work for you,
or there is only a single occurrence that you feel doesn't warrant its own
helper class, the cleanup lambda option is available.
TCleanup
The last resort. If none of the other helper classes work for you,
or there is only a single occurrence that you feel doesn't warrant its own
helper class, the cleanup lambda option is available.
Runs the passed cleanup function on destruction.
This is a handy utility to use previous "goto LError" style cleanup code
with the early return pattern.
Runs the passed cleanup function on destruction.
This is a handy utility to use previous "goto LError" style cleanup code
with the early return pattern.
EXAMPLE:
// Specify the code to run on return in a capture-by-reference lambda
auto cleanupCloseOLDoc = TCleanup::Make([&m_pOrigFile, &m_pNewFile]
{
// Close out the local file if appropriate
if (m_pOrigFile != m_pNewFile && m_pNewFile->GetOpenCount())
{
m_pNewFile->BeginCmd(msoiolcmdClose);
m_pNewFile->RecordEvent(msoiolevtCmdCompleted);
}
});
EXAMPLE:
// Specify the code to run on return in a capture-by-reference lambda
auto cleanupCloseOLDoc = TCleanup::Make([&m_pOrigFile, &m_pNewFile]
{
// Close out the local file if appropriate
if (m_pOrigFile != m_pNewFile && m_pNewFile->GetOpenCount())
{
m_pNewFile->BeginCmd(msoiolcmdClose);
m_pNewFile->RecordEvent(msoiolevtCmdCompleted);
}
});
hr = /some code that uses and OLDocument/;
if (FAILED(hr))
return hr;
// Runs the cleanup code above before returning
hr = /some code that uses and OLDocument/;
if (FAILED(hr))
return hr;
// Runs the cleanup code above before returning
If you want to be able to disable the TCleanup from running on exit,
you can do so by:
If you want to be able to disable the TCleanup from running on exit,
you can do so by:
if (/some condition/)
cleanupCloseOLDoc.disable(); // The TCleanup will now not run on exit
if (/some condition/)
cleanupCloseOLDoc.disable(); // The TCleanup will now not run on exit
*/
template<typename Func>
template <typename Func>
struct TCleanup
{
public:
explicit TCleanup(const Func& fnCleanup) noexcept :
m_fnCleanup(fnCleanup)
{}
explicit TCleanup(const Func& fnCleanup) noexcept : m_fnCleanup(fnCleanup) {}
explicit TCleanup(Func&& fnCleanup) noexcept :
m_fnCleanup(std::move(fnCleanup))
{}
explicit TCleanup(Func&& fnCleanup) noexcept : m_fnCleanup(std::move(fnCleanup)) {}
TCleanup(TCleanup&& rVal) noexcept :
m_fnCleanup(rVal.m_fnCleanup),
m_isEnabled(rVal.m_isEnabled)
{
// We don't want to run the cleanup twice, so disable the original
rVal.disable();
}
TCleanup(TCleanup&& rVal) noexcept : m_fnCleanup(rVal.m_fnCleanup), m_isEnabled(rVal.m_isEnabled)
{
// We don't want to run the cleanup twice, so disable the original
rVal.disable();
}
~TCleanup() noexcept
{
if (m_isEnabled)
m_fnCleanup();
}
~TCleanup() noexcept
{
if (m_isEnabled)
m_fnCleanup();
}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TCleanup);
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TCleanup);
void enable() noexcept { m_isEnabled = true; }
void disable() noexcept { m_isEnabled = false; }
void enable() noexcept
{
m_isEnabled = true;
}
void disable() noexcept
{
m_isEnabled = false;
}
private:
const Func m_fnCleanup;
bool m_isEnabled = true;
const Func m_fnCleanup;
bool m_isEnabled = true;
};
// Constructs a TCleanup from the passed function or lambda
template<typename Func>
template <typename Func>
inline TCleanup<Func> Make(const Func& pfnCleanup) noexcept
{
return TCleanup<Func>(pfnCleanup);
return TCleanup<Func>(pfnCleanup);
}
} // end TCleanup namespace
} // namespace TCleanup
} // Mso
} // namespace Mso
#endif // __cplusplus

Просмотреть файл

@ -2,14 +2,14 @@
// Licensed under the MIT license.
/**
Use this type to enforce that an actual literal string is provided.
void DoSomething(const StringLiteral<char>& input) { s_name = input; }
DoSomething("Hi"_S);
To use this class and _S, you need to pull in the namespace.
using namespace Mso::StringLiterals;
Use this type to enforce that an actual literal string is provided.
void DoSomething(const StringLiteral<char>& input) { s_name = input; }
DoSomething("Hi"_S);
To use this class and _S, you need to pull in the namespace.
using namespace Mso::StringLiterals;
*/
#ifndef _CPPEXTENSIONS_STRINGLITERAL_H_
@ -19,92 +19,94 @@
#include <stddef.h>
#include <stdint.h>
namespace Mso {
namespace StringLiterals {
namespace Mso { namespace StringLiterals {
template<typename char_type>
template <typename char_type>
class StringLiteral;
constexpr StringLiteral<char> operator""_S(const char* str, size_t) noexcept;
/**
StringLiteral can only be constructed using the user-defined-literal operators below.
StringLiteral can only be constructed using the user-defined-literal operators below.
*/
template<typename char_type>
template <typename char_type>
class StringLiteral
{
public:
constexpr operator _Null_terminated_ const char_type*() const noexcept { return m_string; }
constexpr operator _Null_terminated_ const char_type *() const noexcept
{
return m_string;
}
constexpr size_t length() const noexcept
{
// std::char_traits<>::length() is preferred, but it's not constexpr (even though it optimizes away).
// note: using recursion until next version of msvc compiler which supports loops
return length_worker(m_string);
}
constexpr size_t length() const noexcept
{
// std::char_traits<>::length() is preferred, but it's not constexpr (even though it optimizes away).
// note: using recursion until next version of msvc compiler which supports loops
return length_worker(m_string);
}
constexpr const char_type* const* operator&() const noexcept { return &m_string; }
//private:
constexpr StringLiteral(_In_z_ const char_type* str) noexcept : m_string(str)
{
}
constexpr static size_t length_worker(_In_z_ const char_type* str) noexcept
{
return *str ? length_worker(str + 1) + 1 : 0;
}
constexpr const char_type* const* operator&() const noexcept
{
return &m_string;
}
const char_type* const m_string;
// private:
constexpr StringLiteral(_In_z_ const char_type* str) noexcept : m_string(str) {}
//friend constexpr StringLiteral<char> operator""_S(const char*, size_t) noexcept;
// friend constexpr StringLiteral<wchar_t> operator""_S(const wchar_t*, size_t);
// friend constexpr StringLiteral<char16_t> operator""_S(const char16_t*, size_t);
// friend constexpr StringLiteral<char32_t> operator""_S(const char32_t*, size_t);
constexpr static size_t length_worker(_In_z_ const char_type* str) noexcept
{
return *str ? length_worker(str + 1) + 1 : 0;
}
const char_type* const m_string;
// friend constexpr StringLiteral<char> operator""_S(const char*, size_t) noexcept;
// friend constexpr StringLiteral<wchar_t> operator""_S(const wchar_t*, size_t);
// friend constexpr StringLiteral<char16_t> operator""_S(const char16_t*, size_t);
// friend constexpr StringLiteral<char32_t> operator""_S(const char32_t*, size_t);
};
constexpr StringLiteral<char> operator""_S(const char* str, size_t) noexcept
{
return { str };
return {str};
}
inline constexpr StringLiteral<wchar_t> operator""_S(const wchar_t* str, size_t) noexcept
{
return { str };
return {str};
}
inline constexpr StringLiteral<char16_t> operator""_S(const char16_t* str, size_t) noexcept
{
return { str };
return {str};
}
inline constexpr StringLiteral<char32_t> operator""_S(const char32_t* str, size_t) noexcept
{
return { str };
return {str};
}
/**
Special tag used with overloads accepting a raw string pointer.
Special tag used with overloads accepting a raw string pointer.
struct HoldSomething
{
HoldSomething(const StringLiteral<char>& input) : m_string(input) {}
HoldSomething(const char* input, const NonStringLiteral_lifetime_semantics_reviewed&) : m_string(input) {}
private: const char* m_string = nullptr;
};
void SafeCall()
{
const char* sz = GetName();
HoldSomething h(sz, NonStringLiteral_lifetime_semantics_reviewed);
}
struct HoldSomething
{
HoldSomething(const StringLiteral<char>& input) : m_string(input) {}
HoldSomething(const char* input, const NonStringLiteral_lifetime_semantics_reviewed&) : m_string(input) {}
private: const char* m_string = nullptr;
};
void SafeCall()
{
const char* sz = GetName();
HoldSomething h(sz, NonStringLiteral_lifetime_semantics_reviewed);
}
*/
constexpr struct NonStringLiteral_lifetime_semantics_reviewed_t
{
} NonStringLiteral_lifetime_semantics_reviewed {};
} NonStringLiteral_lifetime_semantics_reviewed{};
} // StringLiterals
} // Mso
}} // namespace Mso::StringLiterals
#endif // _CPPEXTENSIONS_STRINGLITERAL_H_

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
FLS-based implementation of TLS
FLS-based implementation of TLS
*/
#ifndef _CPPEXTENSIONS_THREADLOCAL_FLS_H_
#define _CPPEXTENSIONS_THREADLOCAL_FLS_H_
@ -16,67 +16,65 @@ namespace Mso { namespace Details {
struct ThreadLocalImpl
{
DECLARE_COPYCONSTR_AND_ASSIGNMENT(ThreadLocalImpl);
static_assert(FLS_OUT_OF_INDEXES == TLS_OUT_OF_INDEXES, "Assumption violation");
DECLARE_COPYCONSTR_AND_ASSIGNMENT(ThreadLocalImpl);
static_assert(FLS_OUT_OF_INDEXES == TLS_OUT_OF_INDEXES, "Assumption violation");
ThreadLocalImpl() noexcept : ThreadLocalImpl(nullptr)
{
}
ThreadLocalImpl() noexcept : ThreadLocalImpl(nullptr) {}
/**
Callback will be invoked with the TLS data on each thread exit
*/
ThreadLocalImpl(void (__stdcall *pfnCleanup)(void*) noexcept) noexcept
{
if (pfnCleanup)
{
m_index = ::FlsAlloc(pfnCleanup);
m_isFls = true;
}
else
{
m_index = ::TlsAlloc();
}
/**
Callback will be invoked with the TLS data on each thread exit
*/
ThreadLocalImpl(void(__stdcall* pfnCleanup)(void*) noexcept) noexcept
{
if (pfnCleanup)
{
m_index = ::FlsAlloc(pfnCleanup);
m_isFls = true;
}
else
{
m_index = ::TlsAlloc();
}
CheckFatal(m_index != TLS_OUT_OF_INDEXES);
}
CheckFatal(m_index != TLS_OUT_OF_INDEXES);
}
~ThreadLocalImpl() noexcept
{
if (m_isFls)
::FlsFree(m_index);
else
::TlsFree(m_index);
}
~ThreadLocalImpl() noexcept
{
if (m_isFls)
::FlsFree(m_index);
else
::TlsFree(m_index);
}
void* Get() const noexcept
{
if (m_isFls)
return ::FlsGetValue(m_index);
else
return ::TlsGetValue(m_index);
}
void* Get() const noexcept
{
if (m_isFls)
return ::FlsGetValue(m_index);
else
return ::TlsGetValue(m_index);
}
void Set(void* t) noexcept
{
if (m_isFls)
CheckFatal(!!::FlsSetValue(m_index, t));
else
CheckFatal(!!::TlsSetValue(m_index, t));
}
void Set(void* t) noexcept
{
if (m_isFls)
CheckFatal(!!::FlsSetValue(m_index, t));
else
CheckFatal(!!::TlsSetValue(m_index, t));
}
private:
static void CheckFatal(bool result) noexcept
{
if (!result)
__fastfail(FAST_FAIL_FATAL_APP_EXIT);
}
static void CheckFatal(bool result) noexcept
{
if (!result)
__fastfail(FAST_FAIL_FATAL_APP_EXIT);
}
uint32_t m_index = TLS_OUT_OF_INDEXES;
bool m_isFls = false;
uint32_t m_index = TLS_OUT_OF_INDEXES;
bool m_isFls = false;
};
}} // Mso::Details
}} // namespace Mso::Details
#endif // __cplusplus
#endif // _CPPEXTENSIONS_THREADLOCAL_FLS_H_

Просмотреть файл

@ -13,41 +13,41 @@ namespace Mso { namespace Details {
struct ThreadLocalImpl
{
DECLARE_COPYCONSTR_AND_ASSIGNMENT(ThreadLocalImpl);
DECLARE_COPYCONSTR_AND_ASSIGNMENT(ThreadLocalImpl);
ThreadLocalImpl() noexcept
{
if (pthread_key_create(&m_pthread_key, nullptr) != 0)
std::abort();
}
ThreadLocalImpl() noexcept
{
if (pthread_key_create(&m_pthread_key, nullptr) != 0)
std::abort();
}
ThreadLocalImpl(void (*pfnCleanup)(void*) noexcept) noexcept
{
if (pthread_key_create(&m_pthread_key, pfnCleanup) != 0)
std::abort();
}
ThreadLocalImpl(void (*pfnCleanup)(void*) noexcept) noexcept
{
if (pthread_key_create(&m_pthread_key, pfnCleanup) != 0)
std::abort();
}
~ThreadLocalImpl() noexcept
{
if (m_pthread_key)
pthread_key_delete(m_pthread_key);
}
~ThreadLocalImpl() noexcept
{
if (m_pthread_key)
pthread_key_delete(m_pthread_key);
}
void* Get() const noexcept
{
return pthread_getspecific(m_pthread_key);
}
void Set(const void* t) noexcept
{
if (pthread_setspecific(m_pthread_key, t) != 0)
std::abort();
}
void* Get() const noexcept
{
return pthread_getspecific(m_pthread_key);
}
void Set(const void* t) noexcept
{
if (pthread_setspecific(m_pthread_key, t) != 0)
std::abort();
}
private:
pthread_key_t m_pthread_key {};
pthread_key_t m_pthread_key{};
};
}} // Mso::Details
}} // namespace Mso::Details
#endif // _CPPEXTENSIONS_THREADLOCAL_PTHREAD_H_

Просмотреть файл

@ -8,41 +8,40 @@ Basic testing for Mso::TPropertyRestorer<T, PfnGetter, PfnSetter>
#include <cppextensions/autoRestore.h>
#include <motifcpp/motifcpptest.h>
template<typename T>
template <typename T>
struct TestProperty
{
static T Get() noexcept
{
static typename std::decay<T>::type s_value;
return std::forward<T>(s_value); // Return any value that compiles.
}
static T Get() noexcept
{
static typename std::decay<T>::type s_value;
return std::forward<T>(s_value); // Return any value that compiles.
}
static void Set(T /*value*/) noexcept
{
}
static void Set(T /*value*/) noexcept {}
using Restorer = typename Mso::TPropertyRestorer<T, Get, Set>;
using Restorer = typename Mso::TPropertyRestorer<T, Get, Set>;
template<bool expectingMoveAssignmentToCompile = true>
static void VerifyRestorerCompiles() noexcept
{
Restorer rst(Get()); // Ensure class template instantiation compiles.
Restorer rst2(std::move(rst)); // Ensure move semantics compile too.
template <bool expectingMoveAssignmentToCompile = true>
static void VerifyRestorerCompiles() noexcept
{
Restorer rst(Get()); // Ensure class template instantiation compiles.
Restorer rst2(std::move(rst)); // Ensure move semantics compile too.
rst = std::move(rst2);
}
rst = std::move(rst2);
}
template<>
static void VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>() noexcept
{
Restorer rst(Get()); // Ensure class template instantiation compiles.
Restorer rst2(std::move(rst)); // Ensure move semantics compile too.
template <>
static void VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>() noexcept
{
Restorer rst(Get()); // Ensure class template instantiation compiles.
Restorer rst2(std::move(rst)); // Ensure move semantics compile too.
static_assert(!std::is_move_assignable<T>::value, "If T has a valid move assignment operator, then why can't we move assign it?");
}
static_assert(
!std::is_move_assignable<T>::value,
"If T has a valid move assignment operator, then why can't we move assign it?");
}
};
static const int c_nDefaultValue = 123;
static const int c_nNonDefaultValue = 456;
static_assert(c_nDefaultValue != c_nNonDefaultValue, "If you break this, then these tests are pretty useless");
@ -51,199 +50,198 @@ static int s_nGlobal = c_nDefaultValue;
void SetTestGlobal(int value) noexcept
{
s_nGlobal = value;
s_nGlobal = value;
}
int GetTestGlobal() noexcept
{
return s_nGlobal;
return s_nGlobal;
}
// Hungarian: tr
using TestRestorer = Mso::TPropertyRestorer<int, GetTestGlobal, SetTestGlobal>;
TEST_CLASS(TPropertyRestorerTest)
TEST_CLASS (TPropertyRestorerTest)
{
TEST_METHOD_INITIALIZE(Setup)
{
SetTestGlobal(c_nDefaultValue); // Ensure every test starts with default global value
}
TEST_METHOD_INITIALIZE(Setup)
{
SetTestGlobal(c_nDefaultValue); // Ensure every test starts with default global value
}
TEST_METHOD(DefaultConstructor_GlobalIsReverted)
{
// Arrange & Act
{
TestRestorer tr;
TestAssert::AreEqual(c_nDefaultValue, GetTestGlobal(), L"Global should not be updated");
TEST_METHOD(DefaultConstructor_GlobalIsReverted)
{
// Arrange & Act
{
TestRestorer tr;
TestAssert::AreEqual(c_nDefaultValue, GetTestGlobal(), L"Global should not be updated");
SetTestGlobal(c_nNonDefaultValue);
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
}
SetTestGlobal(c_nNonDefaultValue);
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
}
// Assert
TestAssert::AreEqual(c_nDefaultValue, GetTestGlobal(), L"Global should be reverted");
}
// Assert
TestAssert::AreEqual(c_nDefaultValue, GetTestGlobal(), L"Global should be reverted");
}
TEST_METHOD(ConstructorDestructor_Nested_GlobalIsUpdated)
{
// Arrange & Act
{
TestRestorer tr(c_nNonDefaultValue);
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
TEST_METHOD(ConstructorDestructor_Nested_GlobalIsUpdated)
{
// Arrange & Act
{
TestRestorer tr(c_nNonDefaultValue);
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
{
TestRestorer tr2(123456789);
TestAssert::AreEqual(123456789, GetTestGlobal(), L"Global should be updated");
}
{
TestRestorer tr2(123456789);
TestAssert::AreEqual(123456789, GetTestGlobal(), L"Global should be updated");
}
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be reverted");
}
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be reverted");
}
// Assert
TestAssert::AreEqual(c_nDefaultValue, GetTestGlobal(), L"Global should be reverted");
}
// Assert
TestAssert::AreEqual(c_nDefaultValue, GetTestGlobal(), L"Global should be reverted");
}
TEST_METHOD(Disable_OriginallyEnabled_NotReverted)
{
// Arrange & Act
{
TestRestorer tr(c_nNonDefaultValue);
TEST_METHOD(Disable_OriginallyEnabled_NotReverted)
{
// Arrange & Act
{
TestRestorer tr(c_nNonDefaultValue);
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
TestAssert::IsTrue(tr.IsEnabled());
tr.Disable();
TestAssert::IsFalse(tr.IsEnabled());
}
TestAssert::IsTrue(tr.IsEnabled());
tr.Disable();
TestAssert::IsFalse(tr.IsEnabled());
}
// Assert
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should not be reverted");
}
// Assert
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should not be reverted");
}
TEST_METHOD(MoveOperator_OriginallyEnabled_OriginalIsDisabled)
{
// Arrange & Act
{
TestRestorer tr(c_nNonDefaultValue);
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
TEST_METHOD(MoveOperator_OriginallyEnabled_OriginalIsDisabled)
{
// Arrange & Act
{
TestRestorer tr(c_nNonDefaultValue);
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
{
TestRestorer tr2(123456789);
TestAssert::AreEqual(123456789, GetTestGlobal(), L"Global should be updated");
{
TestRestorer tr2(123456789);
TestAssert::AreEqual(123456789, GetTestGlobal(), L"Global should be updated");
TestAssert::IsTrue(tr2.IsEnabled());
tr = std::move(tr2);
TestAssert::IsFalse(tr2.IsEnabled());
}
TestAssert::IsTrue(tr2.IsEnabled());
tr = std::move(tr2);
TestAssert::IsFalse(tr2.IsEnabled());
}
TestAssert::AreEqual(123456789, GetTestGlobal(), L"Global should not be reverted");
}
TestAssert::AreEqual(123456789, GetTestGlobal(), L"Global should not be reverted");
}
// Assert
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be reverted to tr2's previous value");
}
// Assert
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be reverted to tr2's previous value");
}
TEST_METHOD(MoveConstructor_OriginallyEnabled_OriginalIsDisabled)
{
// Arrange & Act
{
TestRestorer tr(std::move(TrSetGlobalToNonDefault()));
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
}
TEST_METHOD(MoveConstructor_OriginallyEnabled_OriginalIsDisabled)
{
// Arrange & Act
{
TestRestorer tr(std::move(TrSetGlobalToNonDefault()));
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
}
// Assert
TestAssert::AreEqual(c_nDefaultValue, GetTestGlobal(), L"Global should be reverted");
}
// Assert
TestAssert::AreEqual(c_nDefaultValue, GetTestGlobal(), L"Global should be reverted");
}
TEST_METHOD(MoveConstructor_SetRestoreTo123456789_RestoreTo123456789)
{
// Arrange & Act
{
TestRestorer tr(std::move(TrSetGlobalToNonDefaultAndRestoreTo123456789()));
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
}
TEST_METHOD(MoveConstructor_SetRestoreTo123456789_RestoreTo123456789)
{
// Arrange & Act
{
TestRestorer tr(std::move(TrSetGlobalToNonDefaultAndRestoreTo123456789()));
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
}
// Assert
TestAssert::AreEqual(123456789, GetTestGlobal(), L"Global should be reverted");
}
// Assert
TestAssert::AreEqual(123456789, GetTestGlobal(), L"Global should be reverted");
}
TEST_METHOD(SetValueToRestore_SetRestoreTo123456789_RestoreTo123456789)
{
// Arrange & Act
{
TestRestorer tr(c_nNonDefaultValue);
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
TEST_METHOD(SetValueToRestore_SetRestoreTo123456789_RestoreTo123456789)
{
// Arrange & Act
{
TestRestorer tr(c_nNonDefaultValue);
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
TestAssert::AreEqual(c_nDefaultValue, tr.ValueToRestore());
tr.ValueToRestore() = 123456789;
TestAssert::AreEqual(123456789, tr.ValueToRestore());
TestAssert::AreEqual(c_nDefaultValue, tr.ValueToRestore());
tr.ValueToRestore() = 123456789;
TestAssert::AreEqual(123456789, tr.ValueToRestore());
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should not be reverted yet");
}
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should not be reverted yet");
}
// Assert
TestAssert::AreEqual(123456789, GetTestGlobal(), L"Global should be reverted");
}
// Assert
TestAssert::AreEqual(123456789, GetTestGlobal(), L"Global should be reverted");
}
TEST_METHOD(ComplexTemplatedTypes_Compiles)
{
struct Unmovable final
{
Unmovable() = default;
private:
Unmovable(Unmovable&&) = delete;
Unmovable& operator=(Unmovable&&) = delete;
DECLARE_COPYCONSTR_AND_ASSIGNMENT(Unmovable); // No copying!
};
TEST_METHOD(ComplexTemplatedTypes_Compiles)
{
struct Unmovable final
{
Unmovable() = default;
// Ensure PropertyRestorer doesn't cause any extra constructor calls.
TestProperty<Unmovable&>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
TestProperty<Unmovable&&>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
TestProperty<const Unmovable&>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
private:
Unmovable(Unmovable&&) = delete;
Unmovable& operator=(Unmovable&&) = delete;
DECLARE_COPYCONSTR_AND_ASSIGNMENT(Unmovable); // No copying!
};
TestProperty<int>::VerifyRestorerCompiles();
TestProperty<int*>::VerifyRestorerCompiles();
TestProperty<int&>::VerifyRestorerCompiles();
TestProperty<const int>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
TestProperty<const int*>::VerifyRestorerCompiles();
TestProperty<const int&>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
// Ensure PropertyRestorer doesn't cause any extra constructor calls.
TestProperty<Unmovable&>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
TestProperty<Unmovable&&>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
TestProperty<const Unmovable&>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
TestProperty<std::unique_ptr<int>>::VerifyRestorerCompiles();
TestProperty<std::unique_ptr<int>&>::VerifyRestorerCompiles();
TestProperty<std::unique_ptr<int>&&>::VerifyRestorerCompiles();
TestProperty<const std::unique_ptr<int>&>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
}
TestProperty<int>::VerifyRestorerCompiles();
TestProperty<int*>::VerifyRestorerCompiles();
TestProperty<int&>::VerifyRestorerCompiles();
TestProperty<const int>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
TestProperty<const int*>::VerifyRestorerCompiles();
TestProperty<const int&>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
TestProperty<std::unique_ptr<int>>::VerifyRestorerCompiles();
TestProperty<std::unique_ptr<int>&>::VerifyRestorerCompiles();
TestProperty<std::unique_ptr<int>&&>::VerifyRestorerCompiles();
TestProperty<const std::unique_ptr<int>&>::VerifyRestorerCompiles<false /*expectingMoveAssignmentToCompile*/>();
}
private:
// any helper type methods
// any helper type methods
static TestRestorer TrSetGlobalToNonDefault()
{
TestAssert::AreNotEqual(c_nNonDefaultValue, GetTestGlobal(), L"This test is less useful if the global already is c_nNonDefaultValue");
static TestRestorer TrSetGlobalToNonDefault()
{
TestAssert::AreNotEqual(
c_nNonDefaultValue, GetTestGlobal(), L"This test is less useful if the global already is c_nNonDefaultValue");
auto verifyPostCondition = Mso::TCleanup::Make([]()
{
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should not be reverted");
});
auto verifyPostCondition = Mso::TCleanup::Make(
[]() { TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should not be reverted"); });
TestRestorer tr(c_nNonDefaultValue);
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
TestRestorer tr(c_nNonDefaultValue);
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should be updated");
return tr;
}
return tr;
}
static TestRestorer TrSetGlobalToNonDefaultAndRestoreTo123456789()
{
TestAssert::AreNotEqual(c_nNonDefaultValue, GetTestGlobal(), L"This test is less useful if the global already is c_nNonDefaultValue");
TestAssert::AreNotEqual(123456789, GetTestGlobal(), L"This test is less useful if the global already is 123456789");
static TestRestorer TrSetGlobalToNonDefaultAndRestoreTo123456789()
{
TestAssert::AreNotEqual(
c_nNonDefaultValue, GetTestGlobal(), L"This test is less useful if the global already is c_nNonDefaultValue");
TestAssert::AreNotEqual(123456789, GetTestGlobal(), L"This test is less useful if the global already is 123456789");
SetTestGlobal(123456789);
SetTestGlobal(123456789);
auto verifyPostCondition = Mso::TCleanup::Make([]()
{
TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should not be reverted");
});
auto verifyPostCondition = Mso::TCleanup::Make(
[]() { TestAssert::AreEqual(c_nNonDefaultValue, GetTestGlobal(), L"Global should not be reverted"); });
return TrSetGlobalToNonDefault();
}
return TrSetGlobalToNonDefault();
}
};

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Basic testing for StringLiteral classes
Basic testing for StringLiteral classes
*/
#include <cppextensions/stringliteral.h>
#include <oacr.h>
@ -11,66 +11,65 @@
#include <string>
using namespace Mso::StringLiterals;
template<typename char_type>
template <typename char_type>
static void CheckLength(size_t expected, const StringLiteral<char_type>& s)
{
TestAssert::AreEqual(expected, std::char_traits<char_type>::length(s));
TestAssert::AreEqual(expected, std::char_traits<char_type>::length(s));
}
TEST_CLASS(StringLiteralTests)
TEST_CLASS (StringLiteralTests)
{
static void ConstLengths() noexcept
{
static_assert(""_S.length() == 0, "Invalid compile-time length");
static_assert("Test"_S.length() == 4, "Invalid compile-time length");
}
static void ConstLengths() noexcept
{
static_assert(""_S.length() == 0, "Invalid compile-time length");
static_assert("Test"_S.length() == 4, "Invalid compile-time length");
}
TEST_METHOD(TestEmpty)
{
CheckLength(0, ""_S);
CheckLength(0, L""_S);
CheckLength(0, u""_S);
CheckLength(0, U""_S);
}
TEST_METHOD(TestEmpty)
{
CheckLength(0, ""_S);
CheckLength(0, L""_S);
CheckLength(0, u""_S);
CheckLength(0, U""_S);
}
TEST_METHOD(TestNonEmpty)
{
CheckLength(3, "Yes"_S);
CheckLength(3, L"Yes"_S);
CheckLength(3, u"Yes"_S);
CheckLength(3, U"Yes"_S);
}
TEST_METHOD(TestNonEmpty)
{
CheckLength(3, "Yes"_S);
CheckLength(3, L"Yes"_S);
CheckLength(3, u"Yes"_S);
CheckLength(3, U"Yes"_S);
}
};
TEST_CLASS(StringLiteralArrayTests)
TEST_CLASS (StringLiteralArrayTests)
{
struct HoldString
{
template<size_t Count>
constexpr HoldString(const std::array<StringLiteral<char>, Count>& strings) noexcept :
m_strings(&strings[0]),
m_count(Count)
{
static_assert(Count != 0, "Must pass at least 1 string");
}
const char* const* m_strings;
const size_t m_count;
};
TEST_METHOD(TestArray)
{
static const std::array<StringLiteral<char>, 3> strings =
{
"Hi"_S, "This"_S, "Works"_S,
};
const HoldString hold(strings);
//static_assert(hold.m_count == 3, "Incorrect count"); Look at this later
TestAssert::AreEqual("Hi", hold.m_strings[0]);
TestAssert::AreEqual("This", hold.m_strings[1]);
TestAssert::AreEqual("Works", hold.m_strings[2]);
}
struct HoldString
{
template <size_t Count>
constexpr HoldString(const std::array<StringLiteral<char>, Count>& strings) noexcept
: m_strings(&strings[0]), m_count(Count)
{
static_assert(Count != 0, "Must pass at least 1 string");
}
const char* const* m_strings;
const size_t m_count;
};
TEST_METHOD(TestArray)
{
static const std::array<StringLiteral<char>, 3> strings = {
"Hi"_S,
"This"_S,
"Works"_S,
};
const HoldString hold(strings);
// static_assert(hold.m_count == 3, "Incorrect count"); Look at this later
TestAssert::AreEqual("Hi", hold.m_strings[0]);
TestAssert::AreEqual("This", hold.m_strings[1]);
TestAssert::AreEqual("Works", hold.m_strings[2]);
}
};

Просмотреть файл

@ -4,4 +4,3 @@
#include <motifcpp/motifcpptest.h>
ImplementTestModule();

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Various C++ helpers for working with function types
Various C++ helpers for working with function types
*/
#pragma once
#ifndef LIBLET_CPPTYPE_FUNCTIONTYPETRAITS_H
@ -11,94 +11,91 @@
#include <type_traits>
#include <tuple>
namespace Mso
{
namespace Mso {
/**
Turns a function pointer or method pointer type into a normal function type.
Error otherwise.
Turns a function pointer or method pointer type into a normal function type.
Error otherwise.
Note: does not strip volatile/const qualifiers on the pointer.
Note: does not strip volatile/const qualifiers on the pointer.
Note: std::remove_reference<T> is used instead of std::common_type<T>
because of a bug in the STL that causes common_type to not return the
identity with function types.
Note: std::remove_reference<T> is used instead of std::common_type<T>
because of a bug in the STL that causes common_type to not return the
identity with function types.
*/
template <typename FunctionPointerType>
struct fnptr_to_fn;
// Handle a member function pointer that is non-const
template <typename Return, typename Class, typename ... Arguments>
struct fnptr_to_fn<Return(Class::*)(Arguments ...)>
template <typename Return, typename Class, typename... Arguments>
struct fnptr_to_fn<Return (Class::*)(Arguments...)>
{
typedef typename std::remove_reference<Return(Arguments ...)>::type type;
typedef typename std::remove_reference<Return(Arguments...)>::type type;
};
// Handle a pointer to a const member function
template <typename Return, typename Class, typename ... Arguments>
struct fnptr_to_fn<Return(Class::*)(Arguments ...) const>
template <typename Return, typename Class, typename... Arguments>
struct fnptr_to_fn<Return (Class::*)(Arguments...) const>
{
typedef typename std::remove_reference<Return(Arguments ...)>::type type;
typedef typename std::remove_reference<Return(Arguments...)>::type type;
};
// Handle a pointer to a function
template <typename Return, typename ... Arguments>
struct fnptr_to_fn<Return(*)(Arguments ...)>
template <typename Return, typename... Arguments>
struct fnptr_to_fn<Return (*)(Arguments...)>
{
typedef typename std::remove_reference<Return(Arguments ...)>::type type;
typedef typename std::remove_reference<Return(Arguments...)>::type type;
};
#if defined(__cpp_noexcept_function_type) || (_HAS_NOEXCEPT_FUNCTION_TYPES == 1)
// Handle a noexcept member function pointer that is non-const
template <typename Return, typename Class, typename ... Arguments>
struct fnptr_to_fn<Return(Class::*)(Arguments ...) noexcept>
template <typename Return, typename Class, typename... Arguments>
struct fnptr_to_fn<Return (Class::*)(Arguments...) noexcept>
{
typedef typename std::remove_reference<Return(Arguments ...)>::type type;
typedef typename std::remove_reference<Return(Arguments...)>::type type;
};
// Handle a pointer to a const noexcept member function
template <typename Return, typename Class, typename ... Arguments>
struct fnptr_to_fn<Return(Class::*)(Arguments ...) const noexcept>
template <typename Return, typename Class, typename... Arguments>
struct fnptr_to_fn<Return (Class::*)(Arguments...) const noexcept>
{
typedef typename std::remove_reference<Return(Arguments ...)>::type type;
typedef typename std::remove_reference<Return(Arguments...)>::type type;
};
// Handle a pointer to a noexcept function
template <typename Return, typename ... Arguments>
struct fnptr_to_fn<Return(*)(Arguments ...) noexcept>
template <typename Return, typename... Arguments>
struct fnptr_to_fn<Return (*)(Arguments...) noexcept>
{
typedef typename std::remove_reference<Return(Arguments ...)>::type type;
typedef typename std::remove_reference<Return(Arguments...)>::type type;
};
#endif
/**
Checks types of two function types to ensure that it is safe to replace the
first [From] function's invocation with the second [To].
Checks types of two function types to ensure that it is safe to replace the
first [From] function's invocation with the second [To].
Guaranteed to work if both From and To are function types.
Error otherwise.
Guaranteed to work if both From and To are function types.
Error otherwise.
i.e.: (struct A {}; struct B : A {};)
void() -> void() // good
void(int) -> void(void*) // bad
void(B*) -> void(A*) // good because a B* can always be converted to an A*
A*() -> B*() // good because the same reason as the previous
void(int, double) -> void(int) // bad because parameter count mismatch
i.e.: (struct A {}; struct B : A {};)
void() -> void() // good
void(int) -> void(void*) // bad
void(B*) -> void(A*) // good because a B* can always be converted to an A*
A*() -> B*() // good because the same reason as the previous
void(int, double) -> void(int) // bad because parameter count mismatch
The helper class uses a std::tuple to pack lists of arguments to recurse on.
This is because recursing using function templates causes and ICE on this version
of the compiler. Dev
The helper class uses a std::tuple to pack lists of arguments to recurse on.
This is because recursing using function templates causes and ICE on this version
of the compiler. Dev
*/
template <typename From, typename To>
struct are_function_types_convertible;
namespace details
{
namespace details {
template <typename FromTuple, typename ToTuple>
struct are_function_types_convertible_arguments_helper;
@ -107,53 +104,51 @@ struct are_function_types_convertible_arguments_helper;
template <>
struct are_function_types_convertible_arguments_helper<std::tuple<>, std::tuple<>>
{
static bool const value = true;
static bool const value = true;
};
// base case - false - too many arguments in From.
template <typename ... FromArguments>
struct are_function_types_convertible_arguments_helper<
std::tuple<FromArguments ...>,
std::tuple<>>
template <typename... FromArguments>
struct are_function_types_convertible_arguments_helper<std::tuple<FromArguments...>, std::tuple<>>
{
static const bool value = false;
static const bool value = false;
};
// base case - false - too many arguments in To.
template <typename ... ToArguments>
struct are_function_types_convertible_arguments_helper<
std::tuple<>,
std::tuple<ToArguments ...>>
template <typename... ToArguments>
struct are_function_types_convertible_arguments_helper<std::tuple<>, std::tuple<ToArguments...>>
{
static const bool value = false;
static const bool value = false;
};
// recursive step - valid if the head arguments are compatible and the recursive check on the tails are compatible.
template <typename FromArgumentsHead, typename ... FromArgumentsTail, typename ToArgumentsHead, typename ... ToArgumentsTail>
template <
typename FromArgumentsHead,
typename... FromArgumentsTail,
typename ToArgumentsHead,
typename... ToArgumentsTail>
struct are_function_types_convertible_arguments_helper<
std::tuple<FromArgumentsHead, FromArgumentsTail ...>,
std::tuple<ToArgumentsHead, ToArgumentsTail ...>>
std::tuple<FromArgumentsHead, FromArgumentsTail...>,
std::tuple<ToArgumentsHead, ToArgumentsTail...>>
{
static const bool value =
std::is_convertible<FromArgumentsHead, ToArgumentsHead>::value &&
are_function_types_convertible_arguments_helper<std::tuple<FromArgumentsTail ...>, std::tuple<ToArgumentsTail ...>>::value;
static const bool value = std::is_convertible<FromArgumentsHead, ToArgumentsHead>::value
&& are_function_types_convertible_arguments_helper<
std::tuple<FromArgumentsTail...>,
std::tuple<ToArgumentsTail...>>::value;
};
}
} // namespace details
// entry point - matches two function types passed in.
template <typename FromReturnType, typename ... FromArguments, typename ToReturnType, typename ... ToArguments>
struct are_function_types_convertible<FromReturnType(FromArguments ...), ToReturnType(ToArguments ...)>
template <typename FromReturnType, typename... FromArguments, typename ToReturnType, typename... ToArguments>
struct are_function_types_convertible<FromReturnType(FromArguments...), ToReturnType(ToArguments...)>
{
static const bool value =
std::is_convertible<ToReturnType, FromReturnType>::value &&
details::are_function_types_convertible_arguments_helper<
std::tuple<FromArguments ...>,
std::tuple<ToArguments ...>
>::value;
static const bool value = std::is_convertible<ToReturnType, FromReturnType>::value
&& details::are_function_types_convertible_arguments_helper<
std::tuple<FromArguments...>,
std::tuple<ToArguments...>>::value;
};
} // namespace Mso
#endif // LIBLET_CPPTYPE_FUNCTIONTYPETRAITS_H

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
A collection of functions to help with restricting the behavior of
A collection of functions to help with restricting the behavior of
C++ templates based on properties of template parameters. Search the
Interweb for "SFINAE" if you want to understand how this works.
*/
@ -28,12 +28,16 @@
*
* @see MSO_ENABLE_FUNC_IF for enabling a function overload based on a compile-time constraint
*/
#define MSO_ENABLE_CLASS_IF( ... ) typename std::enable_if< __VA_ARGS__ >::type
#define MSO_ENABLE_CLASS_IF(...) typename std::enable_if<__VA_ARGS__>::type
// The Mso::Enabled enumeration is part of the `MSO_ENABLE_FUNC_IF` SFINAE magic.
// @see MSO_ENABLE_FUNC_IF
namespace Mso { enum class Enabled { _ }; }
namespace Mso {
enum class Enabled
{
_
};
}
/**
* The `MSO_ENABLE_FUNC_IF` macro allows a function template to apply only when a certain compile-time constraint is
@ -63,26 +67,23 @@ namespace Mso { enum class Enabled { _ }; }
*
* @see MSO_ENABLE_CLASS_IF for enabling a partial specialization of a class template based on a compile-time constraint
*/
#define MSO_ENABLE_FUNC_IF( ... ) typename std::enable_if< __VA_ARGS__, ::Mso::Enabled >::type = ::Mso::Enabled::_
#define MSO_ENABLE_FUNC_IF(...) typename std::enable_if<__VA_ARGS__, ::Mso::Enabled>::type = ::Mso::Enabled::_
// Helper macro for constraining function templates to only match certain types via the SFINAE pattern.
// Append this macro as the last item in a function template's template parameter list in order to disable
// that function template when FROM is not implicitly convertible to TO (note that if what you want is to mimic the
// implicit conversion rules for raw pointers, you'll need to specify FROM and TO as pointer types in the macro
// invocation, like: MSO_ENABLE_IF_IMPLICITLY_CONVERTIBLE( X*, Y* )
#define MSO_ENABLE_IF_IMPLICITLY_CONVERTIBLE( FROM, TO ) \
typename Enable = typename std::enable_if< std::is_convertible< FROM, TO >::value >::type
#define MSO_ENABLE_IF_IMPLICITLY_CONVERTIBLE(FROM, TO) \
typename Enable = typename std::enable_if<std::is_convertible<FROM, TO>::value>::type
// Macro for stamping out embedded typedefs for TYPE.
//
// This is primarily intended to be invoked within the body of a "smart pointer" class definition, and used in
// conjunction with the MSO_IMPLICIT_CONVERSION_[FROM|TO] macros, below.
#define MSO_SMART_POINTER_TYPEDEFS( TYPE ) \
typedef TYPE ValueType; \
typedef ValueType* PointerType;
#define MSO_SMART_POINTER_TYPEDEFS(TYPE) \
typedef TYPE ValueType; \
typedef ValueType* PointerType;
// Helper macros for constraining smart pointer conversions to mimic builtin ptr implicit conversion rules. Use these
// with constructor, assignment operator, or cast operators that are implemented as function templates, in order to
@ -98,9 +99,8 @@ namespace Mso { enum class Enabled { _ }; }
//
// Use MSO_IMPLICIT_CONVERSION_TO when implementing a cast operator, and MSO_IMPLICIT_CONVERSION_FROM when implementing
// a converting constructor or assignment operator.
#define MSO_IMPLICIT_CONVERSION_FROM( TYPE ) TYPE, MSO_ENABLE_IF_IMPLICITLY_CONVERTIBLE( TYPE*, PointerType )
#define MSO_IMPLICIT_CONVERSION_TO( TYPE ) TYPE, MSO_ENABLE_IF_IMPLICITLY_CONVERTIBLE( PointerType, TYPE* )
#define MSO_IMPLICIT_CONVERSION_FROM(TYPE) TYPE, MSO_ENABLE_IF_IMPLICITLY_CONVERTIBLE(TYPE*, PointerType)
#define MSO_IMPLICIT_CONVERSION_TO(TYPE) TYPE, MSO_ENABLE_IF_IMPLICITLY_CONVERTIBLE(PointerType, TYPE*)
#endif // __cplusplus

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Various C++ templates to help with compile-time type information.
Various C++ templates to help with compile-time type information.
*/
#pragma once
#ifndef LIBLET_CPPTYPE_TYPETRAITS_H
@ -15,179 +15,254 @@
namespace Mso {
/**
Empty type used for terminating typelists and other places where
a concept of 'no type' is needed.
Note that 'no type' is different than 'void'.
Empty type used for terminating typelists and other places where
a concept of 'no type' is needed.
Note that 'no type' is different than 'void'.
*/
class NilType
{
};
/**
Type2Type< T >
Can be used to overload functions which otherwise would differ only by Return type.
e.g.
Since following is not allowed,
Window* Create();
Scrollbar* Create();
Type2Type< T >
Can be used to overload functions which otherwise would differ only by Return type.
e.g.
Since following is not allowed,
Window* Create();
Scrollbar* Create();
Use:
Window* Create( const Type2Type< Window >& );
Scrollbar* Create( const Type2Type< Scrollbar >& );
Use:
Window* Create( const Type2Type< Window >& );
Scrollbar* Create( const Type2Type< Scrollbar >& );
*/
template< typename T >
template <typename T>
struct Type2Type
{
typedef T OriginalType;
typedef T OriginalType;
};
/**
RawTraits can be used in templates that support pointer and non-pointer
types to retrieve const and non-const versions.
RawTraits can be used in templates that support pointer and non-pointer
types to retrieve const and non-const versions.
T = wchar_t, RawTraits< T >::ArrowType = wchar_t
T = wchar_t, RawTraits< T >::AddrType = wchar_t*
T = wchar_t, RawTraits< T >::ArrowType = wchar_t
T = wchar_t, RawTraits< T >::AddrType = wchar_t*
T = wchar_t&, RawTraits< T >::ArrowType = wchar_t*
T = wchar_t&, RawTraits< T >::AddrType = wchar_t*
T = wchar_t&, RawTraits< T >::ArrowType = wchar_t*
T = wchar_t&, RawTraits< T >::AddrType = wchar_t*
T = wchar_t*, RawTraits< T >::ArrowType = wchar_t*
T = wchar_t*, RawTraits< T >::AddrType = wchar_t**
T = wchar_t*, RawTraits< T >::ArrowType = wchar_t*
T = wchar_t*, RawTraits< T >::AddrType = wchar_t**
T = const wchar_t*, RawTraits< T >::ArrowType = const wchar_t*
T = const wchar_t*, RawTraits< T >::AddrType = const wchar_t**
T = const wchar_t*, RawTraits< T >::ArrowType = const wchar_t*
T = const wchar_t*, RawTraits< T >::AddrType = const wchar_t**
*/
template< typename T >
template <typename T>
class RawTraits
{
{
public:
using ArrowType = T;
using AddrType = T*;
using ArrowType = T;
using AddrType = T*;
static T& GetArrowType(T& t) noexcept { return t; }
enum R { isPointer = false, isReference = false };
};
static T& GetArrowType(T& t) noexcept
{
return t;
}
enum R
{
isPointer = false,
isReference = false
};
};
template< typename T >
class RawTraits< T& >
{
template <typename T>
class RawTraits<T&>
{
public:
using ArrowType = T*;
using AddrType = T*;
using ArrowType = T*;
using AddrType = T*;
static T* GetArrowType(T& t) noexcept { return &t; }
enum R { isPointer = false, isReference = true };
};
static T* GetArrowType(T& t) noexcept
{
return &t;
}
enum R
{
isPointer = false,
isReference = true
};
};
template< typename T >
class RawTraits< T* >
{
template <typename T>
class RawTraits<T*>
{
public:
using ArrowType = T*;
using AddrType = T**;
using ArrowType = T*;
using AddrType = T**;
static ArrowType GetArrowType(T* t) noexcept { return t; }
enum R { isPointer = true, isReference = false };
};
static ArrowType GetArrowType(T* t) noexcept
{
return t;
}
enum R
{
isPointer = true,
isReference = false
};
};
/**
EmptyTraits provides methods to deal with whether variables are 'empty'.
EmptyTraits provides methods to deal with whether variables are 'empty'.
*/
/**
EmptyTraits to use with simple value types
EmptyTraits to use with simple value types
*/
template< typename T >
template <typename T>
struct EmptyTraits
{
static T EmptyVal() noexcept { return T(); }
static bool IsEmpty(const T& t) noexcept { return (t == EmptyVal()); }
static void Empty(T& t) noexcept { t = EmptyVal(); }
DECLSPEC_DEPRECATED static void UnsafeEmpty(T& t) noexcept { Empty(t); }
};
{
static T EmptyVal() noexcept
{
return T();
}
static bool IsEmpty(const T& t) noexcept
{
return (t == EmptyVal());
}
static void Empty(T& t) noexcept
{
t = EmptyVal();
}
DECLSPEC_DEPRECATED static void UnsafeEmpty(T& t) noexcept
{
Empty(t);
}
};
/**
EmptyTraits to use with pointer types
EmptyTraits to use with pointer types
*/
template< typename T >
template <typename T>
struct EmptyTraits<T*>
{
static T* EmptyVal() noexcept { return nullptr; }
static bool IsEmpty(std::add_const_t<T>* t) noexcept { return (t == EmptyVal()); }
static void Empty(T*& t) noexcept { t = EmptyVal(); }
DECLSPEC_DEPRECATED static void UnsafeEmpty(T*& t) noexcept { Empty(t); }
};
{
static T* EmptyVal() noexcept
{
return nullptr;
}
static bool IsEmpty(std::add_const_t<T>* t) noexcept
{
return (t == EmptyVal());
}
static void Empty(T*& t) noexcept
{
t = EmptyVal();
}
DECLSPEC_DEPRECATED static void UnsafeEmpty(T*& t) noexcept
{
Empty(t);
}
};
/**
EmptyTraits to use with reference types
EmptyTraits to use with reference types
*/
template< typename T >
struct EmptyTraits< T& >
{
// EmptyVal is explicitly not present
static bool IsEmpty(const T& /*t*/) noexcept { return false; }
// Empty is explicitly not present
DECLSPEC_DEPRECATED static void UnsafeEmpty(T& /*t*/) noexcept {} // Can't empty a reference
};
template <typename T>
struct EmptyTraits<T&>
{
// EmptyVal is explicitly not present
static bool IsEmpty(const T& /*t*/) noexcept
{
return false;
}
// Empty is explicitly not present
DECLSPEC_DEPRECATED static void UnsafeEmpty(T& /*t*/) noexcept {} // Can't empty a reference
};
/**
Custom EmptyTraits to use with non-zero defaults, TEmptyVal must be a constant
Custom EmptyTraits to use with non-zero defaults, TEmptyVal must be a constant
*/
template< typename T, T TEmptyVal >
template <typename T, T TEmptyVal>
struct CustomEmptyTraits
{
static T EmptyVal() noexcept { return TEmptyVal; }
static bool IsEmpty(const T& t) noexcept { return (t == EmptyVal()); }
static void Empty(T& t) noexcept { t = EmptyVal(); }
DECLSPEC_DEPRECATED static void UnsafeEmpty(T& t) noexcept { Empty(t); }
};
{
static T EmptyVal() noexcept
{
return TEmptyVal;
}
static bool IsEmpty(const T& t) noexcept
{
return (t == EmptyVal());
}
static void Empty(T& t) noexcept
{
t = EmptyVal();
}
DECLSPEC_DEPRECATED static void UnsafeEmpty(T& t) noexcept
{
Empty(t);
}
};
/**
Custom EmptyTraits to use with zero-init structures like STATSTG
Custom EmptyTraits to use with zero-init structures like STATSTG
*/
template< typename T >
template <typename T>
struct PODEmptyTraits
{
static T EmptyVal() noexcept { T t = {0}; return t; }
static bool IsEmpty(const T& t) noexcept { T tEmpty = EmptyVal(); return memcmp(&t, &tEmpty, sizeof(t)) == 0; }
static void Empty(T& t) noexcept { t = EmptyVal(); }
DECLSPEC_DEPRECATED static void UnsafeEmpty(T& t) noexcept { Empty(t); }
};
{
static T EmptyVal() noexcept
{
T t = {0};
return t;
}
static bool IsEmpty(const T& t) noexcept
{
T tEmpty = EmptyVal();
return memcmp(&t, &tEmpty, sizeof(t)) == 0;
}
static void Empty(T& t) noexcept
{
t = EmptyVal();
}
DECLSPEC_DEPRECATED static void UnsafeEmpty(T& t) noexcept
{
Empty(t);
}
};
/**
Helper for use with template arguments to force callers to specify type explicitly.
Helper for use with template arguments to force callers to specify type explicitly.
template <typename T> Bar(const typename Mso::DisableTypeDeduction<T>::type& value)
[...]
Bar(someInt); // compile fails with C2783
Bar<int>(someInt); // compiles successfully
template <typename T> Bar(const typename Mso::DisableTypeDeduction<T>::type& value)
[...]
Bar(someInt); // compile fails with C2783
Bar<int>(someInt); // compiles successfully
*/
template <typename T>
struct DisableTypeDeduction
{
using type = T;
using type = T;
};
/**
OverloadTag can be used be used to disambiguate two function overloads.
OverloadTag instance passed to an overloaded function will give a higher priority to a function accepting
OverloadTagP1 versus function that accepts OverloadTagP2.
OverloadTag can be used be used to disambiguate two function overloads.
OverloadTag instance passed to an overloaded function will give a higher priority to a function accepting
OverloadTagP1 versus function that accepts OverloadTagP2.
For example, we can use it to call a method if it is defined, or do something else if it is not defined.
template <typename T> auto Foo(Mso::OverloadTagP1, T* x) -> decltype(x->Bar()) { return x->Bar(); }
template <typename T> int Foo(Mso::OverloadTagP2, T* x) { return DefaultBar(x); }
For example, we can use it to call a method if it is defined, or do something else if it is not defined.
template <typename T> auto Foo(Mso::OverloadTagP1, T* x) -> decltype(x->Bar()) { return x->Bar(); }
template <typename T> int Foo(Mso::OverloadTagP2, T* x) { return DefaultBar(x); }
The right function overload will be chosen depending on whether type T has Bar() method or not:
Foo(Mso::OverloadTag(), &x);
The right function overload will be chosen depending on whether type T has Bar() method or not:
Foo(Mso::OverloadTag(), &x);
*/
using OverloadTagP1 = int;
struct OverloadTagP2 { OverloadTagP2(OverloadTagP1) noexcept {} };
struct OverloadTagP2
{
OverloadTagP2(OverloadTagP1) noexcept {}
};
using OverloadTag = OverloadTagP1;
/**
Identifies the largest type from a variadic set of types.
Identifies the largest type from a variadic set of types.
*/
template <typename... Ts>
struct LargestType;
@ -195,13 +270,13 @@ struct LargestType;
template <typename T>
struct LargestType<T>
{
using type = T;
using type = T;
};
template <typename T1, typename T2, typename... Ts>
struct LargestType<T1, T2, Ts...>
{
using type = typename LargestType<typename std::conditional<sizeof(T1) >= sizeof(T2), T1, T2>::type, Ts...>::type;
using type = typename LargestType<typename std::conditional<sizeof(T1) >= sizeof(T2), T1, T2>::type, Ts...>::type;
};
} // namespace Mso

Просмотреть файл

@ -18,29 +18,19 @@ DECLSPEC_NORETURN void CrashWithRecovery(uint32_t tag) noexcept;
// Asserts first so the dev can easily attach. If already attached, it does not assert
// because bringing up the assert dialog can cause more code to run (OM:278842).
#define VerifyElseCrashSzTag(f, sz, tag) \
Statement( \
if (!(f)) \
{ \
AssertSz1Tag(DisableVecAssert(), "Fatal error: %s", (sz), (tag)); \
CrashWithRecovery(tag); \
} \
)
#define VerifyElseCrashSzTag(f, sz, tag) \
Statement(if (!(f)) { \
AssertSz1Tag(DisableVecAssert(), "Fatal error: %s", (sz), (tag)); \
CrashWithRecovery(tag); \
})
#define VerifySucceededElseCrashTag(hr, tag) \
Statement( \
const HRESULT _vec_hr_ = (hr); \
if (FAILED(_vec_hr_)) \
{ \
AssertSzTag(DisableVecAssert(), "Failed: " #hr, tag); \
CrashWithRecovery(/*static_cast<int32_t>(_vec_hr_), */tag); \
})
#define VerifySucceededElseCrashTag(hr, tag) \
Statement(const HRESULT _vec_hr_ = (hr); if (FAILED(_vec_hr_)) { \
AssertSzTag(DisableVecAssert(), "Failed: " #hr, tag); \
CrashWithRecovery(/*static_cast<int32_t>(_vec_hr_), */ tag); \
})
#define VerifyAllocElseCrashTag(ptr, tag) \
Statement( \
if (!(ptr)) \
CrashWithRecovery(tag); \
)
#define VerifyAllocElseCrashTag(ptr, tag) Statement(if (!(ptr)) CrashWithRecovery(tag);)
#define CrashWithRecoveryOnOOM() CrashWithRecovery(0)

Просмотреть файл

@ -11,28 +11,28 @@
void CrashWithRecovery(uint32_t /*tag*/) noexcept
{
*((volatile int*)0) = 1;
__builtin_trap();
*((volatile int*)0) = 1;
__builtin_trap();
}
#else
int CrashHandler(const EXCEPTION_POINTERS* excPtr, uint32_t tag) noexcept
{
excPtr->ExceptionRecord->ExceptionCode = tag;
return EXCEPTION_CONTINUE_SEARCH;
excPtr->ExceptionRecord->ExceptionCode = tag;
return EXCEPTION_CONTINUE_SEARCH;
}
void CrashWithRecovery(uint32_t tag) noexcept
{
__try
{
*((int*)0) = 1;
}
__except (CrashHandler(GetExceptionInformation(), tag))
{
}
__fastfail(tag);
__try
{
*((int*)0) = 1;
}
__except (CrashHandler(GetExceptionInformation(), tag))
{
}
__fastfail(tag);
}
#endif

Просмотреть файл

@ -2,13 +2,13 @@
// Licensed under the MIT license.
/**
API for debug asserts. Must support C callers
API for debug asserts. Must support C callers
*/
#pragma once
#ifndef LIBLET_DEBUGASSERTAPI_DEBUGASSERTAPI_H
#define LIBLET_DEBUGASSERTAPI_DEBUGASSERTAPI_H
#ifndef RC_INVOKED
#pragma pack(push,8)
#pragma pack(push, 8)
#include <compilerAdapters/cppMacros.h>
#include <compilerAdapters/functionDecorations.h>
@ -22,22 +22,22 @@ Basic debug assert macros to use.
Assert: evaluate in debug, call the debug handler on failure
AssertDo: always evaluate, call the debug handler on failure
*/
#define Assert(f) AssertTag(f, UNTAGGED)
#define AssertSz(f, _sz) AssertSzTag(f, _sz, UNTAGGED)
#define AssertSz0(f, _sz) AssertSzTag(f, _sz, UNTAGGED)
#define AssertSz1(f, _sz, a) AssertSz1Tag(f, _sz, a, UNTAGGED)
#define AssertSz2(f, _sz, a, b) AssertSz2Tag(f, _sz, a, b, UNTAGGED)
#define AssertSz3(f, _sz, a, b, c) AssertSz3Tag(f, _sz, a, b, c, UNTAGGED)
#define AssertSz4(f, _sz, a, b, c, d) AssertSz4Tag(f, _sz, a, b, c, d, UNTAGGED)
#define AssertSz5(f, _sz, a, b, c, d, e) AssertSz5Tag(f, _sz, a, b, c, d, e, UNTAGGED)
#define Assert(f) AssertTag(f, UNTAGGED)
#define AssertSz(f, _sz) AssertSzTag(f, _sz, UNTAGGED)
#define AssertSz0(f, _sz) AssertSzTag(f, _sz, UNTAGGED)
#define AssertSz1(f, _sz, a) AssertSz1Tag(f, _sz, a, UNTAGGED)
#define AssertSz2(f, _sz, a, b) AssertSz2Tag(f, _sz, a, b, UNTAGGED)
#define AssertSz3(f, _sz, a, b, c) AssertSz3Tag(f, _sz, a, b, c, UNTAGGED)
#define AssertSz4(f, _sz, a, b, c, d) AssertSz4Tag(f, _sz, a, b, c, d, UNTAGGED)
#define AssertSz5(f, _sz, a, b, c, d, e) AssertSz5Tag(f, _sz, a, b, c, d, e, UNTAGGED)
#define AssertDo(f) AssertDoTag(f, UNTAGGED)
#define AssertDoSz(f, _sz) AssertDoSzTag(f, _sz, UNTAGGED)
#define AssertDoSz1(f, _sz, a) AssertDoSz1Tag(f, _sz, a, UNTAGGED)
#define AssertDoSz2(f, _sz, a, b) AssertDoSz2Tag(f, _sz, a, b, UNTAGGED)
#define AssertDoSz3(f, _sz, a, b, c) AssertDoSz3Tag(f, _sz, a, b, c, UNTAGGED)
#define AssertDoSz4(f, _sz, a, b, c, d) AssertDoSz4Tag(f, _sz, a, b, c, d, UNTAGGED)
#define AssertDoSz5(f, _sz, a, b, c, d, e) AssertDoSz5Tag(f, _sz, a, b, c, d, e, UNTAGGED)
#define AssertDo(f) AssertDoTag(f, UNTAGGED)
#define AssertDoSz(f, _sz) AssertDoSzTag(f, _sz, UNTAGGED)
#define AssertDoSz1(f, _sz, a) AssertDoSz1Tag(f, _sz, a, UNTAGGED)
#define AssertDoSz2(f, _sz, a, b) AssertDoSz2Tag(f, _sz, a, b, UNTAGGED)
#define AssertDoSz3(f, _sz, a, b, c) AssertDoSz3Tag(f, _sz, a, b, c, UNTAGGED)
#define AssertDoSz4(f, _sz, a, b, c, d) AssertDoSz4Tag(f, _sz, a, b, c, d, UNTAGGED)
#define AssertDoSz5(f, _sz, a, b, c, d, e) AssertDoSz5Tag(f, _sz, a, b, c, d, e, UNTAGGED)
/**
The following macros can be used to assert inside an expression.
@ -46,39 +46,39 @@ LATER: add more if needed or ShipAssert versions.
if (FAssertDo(f)) { ... } // same as "if (f) { ... } else Assert(false);"
*/
#define FAssertDo(f) FAssertDoTag(f, UNTAGGED)
#define FAssertDoSz(f, _sz) FAssertDoSzTag(f, _sz, UNTAGGED)
#define FAssertDoSz1(f, _sz, a) FAssertDoSz1Tag(f, _sz, a, UNTAGGED)
#define FAssertDoSz2(f, _sz, a, b) FAssertDoSz2Tag(f, _sz, a, b, UNTAGGED)
#define FAssertDo(f) FAssertDoTag(f, UNTAGGED)
#define FAssertDoSz(f, _sz) FAssertDoSzTag(f, _sz, UNTAGGED)
#define FAssertDoSz1(f, _sz, a) FAssertDoSz1Tag(f, _sz, a, UNTAGGED)
#define FAssertDoSz2(f, _sz, a, b) FAssertDoSz2Tag(f, _sz, a, b, UNTAGGED)
#ifdef __cplusplus
#define AssertDetails_SzCast(sz) static_cast<const char*>(sz)
#else
#define AssertDetails_SzCast(sz) (const char*) (sz)
#define AssertDetails_SzCast(sz) (const char*)(sz)
#endif
/**
Suppressed warnings in Assert macros:
C4127 - if/while loop condition is a constant
C4018 - signed/unsigned compare was converted to unsigned/unsigned compare
C4389 - operation involved signed/unsigned variables
6239 - OACR left expression is always false
25011 - OACR missing 'break' or '__fallthrough' statement
25037 - OACR expression is always false
25038 - OACR expression is always false
25039 - OACR expression is always true
25041 - OACR if/while loop condition is true
25042 - OACR if/while loop condition is false
25064 - OACR function called twice in macro
C4127 - if/while loop condition is a constant
C4018 - signed/unsigned compare was converted to unsigned/unsigned compare
C4389 - operation involved signed/unsigned variables
6239 - OACR left expression is always false
25011 - OACR missing 'break' or '__fallthrough' statement
25037 - OACR expression is always false
25038 - OACR expression is always false
25039 - OACR expression is always true
25041 - OACR if/while loop condition is true
25042 - OACR if/while loop condition is false
25064 - OACR function called twice in macro
*/
#define AssertDetails_Statement_Begin \
__pragma(warning(push)) \
__pragma(warning(disable:4127 4018 4389 6239 25037 25038 25039 25041 25042 25064 25306)) \
do {
#define AssertDetails_Statement_Begin \
__pragma(warning(push)) \
__pragma(warning(disable : 4127 4018 4389 6239 25037 25038 25039 25041 25042 25064 25306)) do \
{
#define AssertDetails_Statement_End \
} while(0) \
__pragma(warning(suppress:25011)) \
__pragma(warning(pop)) \
} \
while (0) \
__pragma(warning(suppress : 25011)) __pragma(warning(pop))
// NOTE: OACR_ASSUME uses the Assert macro, so oacr.h must be included after Assert is defined
#include <oacr.h>
@ -89,7 +89,7 @@ FUTURE: get rid of this and just use void*
*/
typedef struct _MSORADDR
{
void* pfnCaller;
void* pfnCaller;
} MSORADDR;
/**
@ -111,7 +111,7 @@ using MsoAssertParamsType = const struct _MsoAssertParams&;
#else // __cplusplus
typedef struct _MsoAssertParams* MsoAssertParamsType;
#ifdef DEBUG
#define DeclareMsoAssertParams(...) (__pragma(warning(suppress:4204)) MsoAssertParams params = { __VA_ARGS__ })
#define DeclareMsoAssertParams(...) (__pragma(warning(suppress : 4204)) MsoAssertParams params = {__VA_ARGS__})
#else
#define DeclareMsoAssertParams(...)
#endif // DEBUG
@ -129,50 +129,69 @@ This structure is duplicated in MotifTest project.
*/
typedef struct _MsoAssertParams
{
uint32_t dwTag;
const char* szFile;
uint32_t iLine;
const char* szTitle;
const MSORADDR* rgCallstack;
uint32_t cCallstack;
const char* szCondition;
uint32_t dwTag;
const char* szFile;
uint32_t iLine;
const char* szTitle;
const MSORADDR* rgCallstack;
uint32_t cCallstack;
const char* szCondition;
// Skip this many frames if a callstack is generated.
// Skip this many frames if a callstack is generated.
#ifdef __cplusplus
mutable
mutable
#endif // __cplusplus
uint32_t framesToSkip;
uint32_t framesToSkip;
#ifdef __cplusplus
explicit _MsoAssertParams(uint32_t dwTagLocal = UNTAGGED,
_In_z_ const char* szFileLocal = __FILE__, uint32_t iLineLocal = __LINE__,
_In_opt_z_ const char* szTitleLocal = nullptr,
_In_opt_count_(cCallstackLocal) const MSORADDR* rgCallstackLocal = nullptr, uint32_t cCallstackLocal = 0,
_In_opt_z_ const char* szConditionLocal = "false") MSONOEXCEPT :
dwTag(dwTagLocal), szFile(szFileLocal), iLine(iLineLocal), szTitle(szTitleLocal),
rgCallstack(rgCallstackLocal), cCallstack(cCallstackLocal),
szCondition(szConditionLocal), framesToSkip(0)
{
}
explicit _MsoAssertParams(
uint32_t dwTagLocal = UNTAGGED,
_In_z_ const char* szFileLocal = __FILE__,
uint32_t iLineLocal = __LINE__,
_In_opt_z_ const char* szTitleLocal = nullptr,
_In_opt_count_(cCallstackLocal) const MSORADDR* rgCallstackLocal = nullptr,
uint32_t cCallstackLocal = 0,
_In_opt_z_ const char* szConditionLocal = "false") MSONOEXCEPT
: dwTag(dwTagLocal)
, szFile(szFileLocal)
, iLine(iLineLocal)
, szTitle(szTitleLocal)
, rgCallstack(rgCallstackLocal)
, cCallstack(cCallstackLocal)
, szCondition(szConditionLocal)
, framesToSkip(0)
{
}
explicit _MsoAssertParams(_In_z_ const char* szConditionLocal, uint32_t dwTagLocal, _In_z_ const char* szFileLocal, int32_t iLineLocal) MSONOEXCEPT :
dwTag(dwTagLocal), szFile(szFileLocal), iLine(static_cast<uint32_t>(iLineLocal)), szTitle(nullptr),
rgCallstack(nullptr), cCallstack(0), szCondition(szConditionLocal), framesToSkip(0)
{
}
explicit _MsoAssertParams(
_In_z_ const char* szConditionLocal,
uint32_t dwTagLocal,
_In_z_ const char* szFileLocal,
int32_t iLineLocal) MSONOEXCEPT
: dwTag(dwTagLocal)
, szFile(szFileLocal)
, iLine(static_cast<uint32_t>(iLineLocal))
, szTitle(nullptr)
, rgCallstack(nullptr)
, cCallstack(0)
, szCondition(szConditionLocal)
, framesToSkip(0)
{
}
#endif // __cplusplus
} MsoAssertParams;
/**
Function for handling asserts with strings. Return value is AssertResult.
Note: this function has to be callable from C code
Function for handling asserts with strings. Return value is AssertResult.
Note: this function has to be callable from C code
*/
#if defined(__cplusplus)
extern "C" {
extern "C"
{
#endif // C++
LIBLET_PUBLICAPI int32_t MsoAssertSzTagProc(MsoAssertParamsType params, _Printf_format_string_ const char* szFmt, va_list argList) MSONOEXCEPT;
LIBLET_PUBLICAPI int32_t
MsoAssertSzTagProc(MsoAssertParamsType params, _Printf_format_string_ const char* szFmt, va_list argList) MSONOEXCEPT;
#if defined(__cplusplus)
}
#endif // C++
@ -182,99 +201,95 @@ LIBLET_PUBLICAPI int32_t MsoAssertSzTagProc(MsoAssertParamsType params, _Printf_
#ifdef DEBUG
#ifdef __cplusplus
namespace Mso {
namespace DebugAsserts {
namespace Mso { namespace DebugAsserts {
using AssertIgnorer = bool(*)(const MsoAssertParams& params, const char* szMsg);
using AssertIgnorer = bool (*)(const MsoAssertParams& params, const char* szMsg);
/**
Add an assert ignorer for this process.
Note: this API is not thread-safe.
Add an assert ignorer for this process.
Note: this API is not thread-safe.
*/
LIBLET_PUBLICAPI void AddAssertIgnorer(AssertIgnorer ignorer) noexcept;
/**
Remove an assert ignorer for this process.
Note: this API is not thread-safe.
Remove an assert ignorer for this process.
Note: this API is not thread-safe.
*/
LIBLET_PUBLICAPI void RemoveAssertIgnorer(AssertIgnorer ignorer) noexcept;
struct AutoRegisterAssertIgnorer
{
AutoRegisterAssertIgnorer(AssertIgnorer ignorer) noexcept : m_ignorer(ignorer)
{
AddAssertIgnorer(m_ignorer);
}
AutoRegisterAssertIgnorer(AssertIgnorer ignorer) noexcept : m_ignorer(ignorer)
{
AddAssertIgnorer(m_ignorer);
}
~AutoRegisterAssertIgnorer() noexcept
{
RemoveAssertIgnorer(m_ignorer);
}
~AutoRegisterAssertIgnorer() noexcept
{
RemoveAssertIgnorer(m_ignorer);
}
private:
AssertIgnorer m_ignorer;
AssertIgnorer m_ignorer;
};
using AssertListener = void(*)(const MsoAssertParams& params, const char* szMsg);
using AssertListener = void (*)(const MsoAssertParams& params, const char* szMsg);
/**
Add an assert listener for this process.
Note: this API is not thread-safe.
Add an assert listener for this process.
Note: this API is not thread-safe.
*/
LIBLET_PUBLICAPI void AddAssertListener(AssertListener listener) noexcept;
/**
Remove a previously registered assert listener for this process.
Note: this API is not thread-safe.
Remove a previously registered assert listener for this process.
Note: this API is not thread-safe.
*/
LIBLET_PUBLICAPI void RemoveAssertListener(AssertListener listener) noexcept;
struct AutoRegisterAssertListener
{
AutoRegisterAssertListener(AssertListener listener) noexcept : m_listener(listener)
{
AddAssertListener(m_listener);
}
AutoRegisterAssertListener(AssertListener listener) noexcept : m_listener(listener)
{
AddAssertListener(m_listener);
}
~AutoRegisterAssertListener() noexcept
{
RemoveAssertListener(m_listener);
}
~AutoRegisterAssertListener() noexcept
{
RemoveAssertListener(m_listener);
}
private:
AssertListener m_listener;
AssertListener m_listener;
};
using AssertHandler = int32_t(*)(const MsoAssertParams& params, const char* szMsg);
using AssertHandler = int32_t (*)(const MsoAssertParams& params, const char* szMsg);
/**
Set the assert handler for this process. The previous handler is returned.
Note: this API is not thread-safe.
Set the assert handler for this process. The previous handler is returned.
Note: this API is not thread-safe.
*/
LIBLET_PUBLICAPI AssertHandler SetAssertHandler(AssertHandler handler) noexcept;
/**
Get the current assert handler for this process.
Get the current assert handler for this process.
*/
LIBLET_PUBLICAPI AssertHandler GetAssertHandler() noexcept;
struct AutoRegisterAssertHandler
{
AutoRegisterAssertHandler(AssertHandler handler) noexcept : m_previous(SetAssertHandler(handler))
{
}
AutoRegisterAssertHandler(AssertHandler handler) noexcept : m_previous(SetAssertHandler(handler)) {}
~AutoRegisterAssertHandler() noexcept
{
SetAssertHandler(m_previous);
}
~AutoRegisterAssertHandler() noexcept
{
SetAssertHandler(m_previous);
}
private:
AssertHandler m_previous;
AssertHandler m_previous;
};
} // DebugAsserts
} // Mso
}} // namespace Mso::DebugAsserts
#endif // __cplusplus
#endif // DEBUG

Просмотреть файл

@ -2,11 +2,11 @@
// Licensed under the MIT license.
/**
Private implementation details for debug assert macros
This header should not be included directly - only through debugAssertApi.h
Private implementation details for debug assert macros
This header should not be included directly - only through debugAssertApi.h
Note that C4706 is purposely left enabled. Assignments in inside Assert
statements are almost always a bug (e.g. Assert(m_foo = fooBar))
Note that C4706 is purposely left enabled. Assignments in inside Assert
statements are almost always a bug (e.g. Assert(m_foo = fooBar))
*/
#pragma once
#ifndef LIBLET_DEBUGASSERTAPI_DEBUGASSERTDETAILS_H
@ -18,19 +18,25 @@
/**
Mappings for core Debug asserts.
*/
#pragma warning(suppress:4005) // macro redefinition :(
#define AssertTag(f, tag) AssertAnnotatedSzNTagImpl(f, L## #f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), "%s", #f)
#define AssertSzTag(f, sz, tag) AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), "%s", AssertDetails_SzCast(sz))
#define AssertSz1Tag(f, sz, a, tag) AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), sz, a)
#define AssertSz2Tag(f, sz, a, b, tag) AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), sz, a, b)
#define AssertSz3Tag(f, sz, a, b, c, tag) AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), sz, a, b, c)
#define AssertSz4Tag(f, sz, a, b, c, d, tag) AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), sz, a, b, c, d)
#define AssertSz5Tag(f, sz, a, b, c, d, e, tag) AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), sz, a, b, c, d, e)
#pragma warning(suppress : 4005) // macro redefinition :(
#define AssertTag(f, tag) \
AssertAnnotatedSzNTagImpl(f, L## #f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), "%s", #f)
#define AssertSzTag(f, sz, tag) \
AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), "%s", AssertDetails_SzCast(sz))
#define AssertSz1Tag(f, sz, a, tag) AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), sz, a)
#define AssertSz2Tag(f, sz, a, b, tag) AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), sz, a, b)
#define AssertSz3Tag(f, sz, a, b, c, tag) \
AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), sz, a, b, c)
#define AssertSz4Tag(f, sz, a, b, c, d, tag) \
AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), sz, a, b, c, d)
#define AssertSz5Tag(f, sz, a, b, c, d, e, tag) \
AssertSzNTagImpl(f, InlineMsoAssertParams(#f, tag, __FILE__, __LINE__), sz, a, b, c, d, e)
#define FAssertDoTag(f, tag) FAssertDoSzNTagImpl(f, tag, __FILE__, __LINE__, L## #f, "%s", #f)
#define FAssertDoSzTag(f, sz, tag) FAssertDoSzNTagImpl(f, tag, __FILE__, __LINE__, L##sz, "%s", AssertDetails_SzCast(sz))
#define FAssertDoSz1Tag(f, sz, a, tag) FAssertDoSzNTagImpl(f, tag, __FILE__, __LINE__, L##sz, sz, a)
#define FAssertDoSz2Tag(f, sz, a, b, tag) FAssertDoSzNTagImpl(f, tag, __FILE__, __LINE__, L##sz, sz, a, b)
#define FAssertDoTag(f, tag) FAssertDoSzNTagImpl(f, tag, __FILE__, __LINE__, L## #f, "%s", #f)
#define FAssertDoSzTag(f, sz, tag) \
FAssertDoSzNTagImpl(f, tag, __FILE__, __LINE__, L##sz, "%s", AssertDetails_SzCast(sz))
#define FAssertDoSz1Tag(f, sz, a, tag) FAssertDoSzNTagImpl(f, tag, __FILE__, __LINE__, L##sz, sz, a)
#define FAssertDoSz2Tag(f, sz, a, b, tag) FAssertDoSzNTagImpl(f, tag, __FILE__, __LINE__, L##sz, sz, a, b)
/**
Return values from MsoAssertSzTagProc(Inline)(2)
@ -41,21 +47,18 @@ static const uint32_t c_assertAlwaysIgnore = 2;
#ifdef __cplusplus
#ifdef DEBUG
namespace Mso {
namespace DebugAsserts {
namespace Mso { namespace DebugAsserts {
/**
Return values from MsoAssertSzTagProc(Inline)(2)
Return values from MsoAssertSzTagProc(Inline)(2)
*/
__pragma(warning(suppress:4472)) enum class AssertResult : uint32_t
{
Ignore = c_assertIgnore,
Break = c_assertDebugBreak,
AlwaysIgnore = c_assertAlwaysIgnore,
__pragma(warning(suppress : 4472)) enum class AssertResult : uint32_t {
Ignore = c_assertIgnore,
Break = c_assertDebugBreak,
AlwaysIgnore = c_assertAlwaysIgnore,
};
} // DebugAsserts
} // Mso
}} // namespace Mso::DebugAsserts
#endif // DEBUG
#endif // C++
@ -63,58 +66,57 @@ __pragma(warning(suppress:4472)) enum class AssertResult : uint32_t
#if defined(__clang__) || defined(__cplusplus_cli) || defined(__INTELLISENSE__)
#define AssertBreak(wzMsg) __debugbreak()
#elif defined(_DBGRAISEASSERTIONFAILURE_)
#define AssertBreak(wzMsg) \
(__annotation(L"Debug", L"AssertFail", wzMsg), DbgRaiseAssertionFailure())
#define AssertBreak(wzMsg) (__annotation(L"Debug", L"AssertFail", wzMsg), DbgRaiseAssertionFailure())
#else
#define AssertBreak(wzMsg) \
(__annotation(L"Debug", L"AssertFail", wzMsg), __debugbreak())
#define AssertBreak(wzMsg) (__annotation(L"Debug", L"AssertFail", wzMsg), __debugbreak())
#endif
#if DEBUG
/**
MsoAssertSzTagProcInline
MsoAssertSzTagProcInline
Converts variable arguments into the arg list format
Converts variable arguments into the arg list format
*/
#ifndef __cplusplus
static
#endif
__inline int32_t MsoAssertSzTagProcInline(MsoAssertParamsType params, _Printf_format_string_ const char* szFmt, ...) MSONOEXCEPT
{
va_list argList;
va_start(argList, szFmt);
AccessMsoAssertParams(params)->framesToSkip++;
return MsoAssertSzTagProc(params, szFmt, argList);
__inline int32_t
MsoAssertSzTagProcInline(MsoAssertParamsType params, _Printf_format_string_ const char* szFmt, ...) MSONOEXCEPT
{
va_list argList;
va_start(argList, szFmt);
AccessMsoAssertParams(params)->framesToSkip++;
return MsoAssertSzTagProc(params, szFmt, argList);
}
#ifdef __cplusplus
#ifdef __cplusplus
/**
MsoAssertSzTagProcInline2
MsoAssertSzTagProcInline2
Converts variable arguments into the arg list format
Converts variable arguments into the arg list format
Use a lamba function to generate a unique function providing storage of
_fIgnore_ (for in-proc based assert management) and unique break address.
Use a lamba function to generate a unique function providing storage of
_fIgnore_ (for in-proc based assert management) and unique break address.
*/
#define MsoAssertSzTagProcInline2(dwTag, szFile, iLine, wzAnnotation, szFmt, ...) \
[&]() -> int32_t { \
__pragma(warning(suppress:4456)) /* declaration of '_fIgnore_' hides previous local declaration */ \
static int32_t _fIgnore_ = false; \
if (!_fIgnore_) \
{ \
__pragma(warning(suppress:4456)) /* declaration of 'params' hides previous local declaration */ \
DeclareMsoAssertParams(dwTag, szFile, iLine); \
params.framesToSkip++; \
const int32_t _assertResult_ = MsoAssertSzTagProcInline(PassMsoAssertParams(params), szFmt, __VA_ARGS__); \
__pragma(warning(suppress:4700)) /* MSVC is unhappy with this used in a loop conditional */ \
if(_assertResult_ == c_assertDebugBreak) \
{ \
AssertBreak(wzAnnotation); \
} \
_fIgnore_ = (_assertResult_ == c_assertAlwaysIgnore); \
} \
return FALSE; \
}()
#define MsoAssertSzTagProcInline2(dwTag, szFile, iLine, wzAnnotation, szFmt, ...) \
[&]() -> int32_t { \
__pragma(warning(suppress : 4456)) /* declaration of '_fIgnore_' hides previous local declaration */ \
static int32_t _fIgnore_ = false; \
if (!_fIgnore_) \
{ \
__pragma(warning(suppress : 4456)) /* declaration of 'params' hides previous local declaration */ \
DeclareMsoAssertParams(dwTag, szFile, iLine); \
params.framesToSkip++; \
const int32_t _assertResult_ = MsoAssertSzTagProcInline(PassMsoAssertParams(params), szFmt, __VA_ARGS__); \
__pragma(warning(suppress : 4700)) /* MSVC is unhappy with this used in a loop conditional */ \
if (_assertResult_ == c_assertDebugBreak) \
{ \
AssertBreak(wzAnnotation); \
} \
_fIgnore_ = (_assertResult_ == c_assertAlwaysIgnore); \
} \
return FALSE; \
}()
#endif // __cplusplus
#else
@ -122,7 +124,7 @@ __inline int32_t MsoAssertSzTagProcInline(MsoAssertParamsType params, _Printf_fo
#endif // DEBUG
/**
Hide the debug assert 'f' condition from OACR so it acts more like a ship build
Hide the debug assert 'f' condition from OACR so it acts more like a ship build
*/
#if OACR
#define AssertDetails_ShouldRaiseDebugAssert(f, fIgnore) 0
@ -133,27 +135,25 @@ __inline int32_t MsoAssertSzTagProcInline(MsoAssertParamsType params, _Printf_fo
#if DEBUG
/**
AssertSzNTagImpl - all debug asserts funnel into here
TODO: need to move the Ignore logic, should it be on params?
Params is MsoAssertParams, only C callers need to do something weird.
AssertSzNTagImpl - all debug asserts funnel into here
TODO: need to move the Ignore logic, should it be on params?
Params is MsoAssertParams, only C callers need to do something weird.
Note: be aware that ... requires at least one argument
Note: be aware that ... requires at least one argument
*/
#define AssertSzNTagImpl(f, params, sz, ...) \
AssertAnnotatedSzNTagImpl(f, L## #f, params, sz, __VA_ARGS__)
#define AssertSzNTagImpl(f, params, sz, ...) AssertAnnotatedSzNTagImpl(f, L## #f, params, sz, __VA_ARGS__)
#define AssertAnnotatedSzNTagImpl(f, wzAnnotation, params, sz, ...) \
AssertDetails_Statement_Begin \
static int32_t _fIgnore_ = 0; \
if (AssertDetails_ShouldRaiseDebugAssert(f, _fIgnore_)) \
{ \
DeclareInlineMsoAssertParams(params); \
const int32_t _assertResult_ = MsoAssertSzTagProcInline(PassMsoAssertParams(params), sz, __VA_ARGS__); \
if (_assertResult_ == c_assertDebugBreak) \
AssertBreak(wzAnnotation); \
_fIgnore_ = (_assertResult_ == c_assertAlwaysIgnore); \
} \
AssertDetails_Statement_End
#define AssertAnnotatedSzNTagImpl(f, wzAnnotation, params, sz, ...) \
AssertDetails_Statement_Begin static int32_t _fIgnore_ = 0; \
if (AssertDetails_ShouldRaiseDebugAssert(f, _fIgnore_)) \
{ \
DeclareInlineMsoAssertParams(params); \
const int32_t _assertResult_ = MsoAssertSzTagProcInline(PassMsoAssertParams(params), sz, __VA_ARGS__); \
if (_assertResult_ == c_assertDebugBreak) \
AssertBreak(wzAnnotation); \
_fIgnore_ = (_assertResult_ == c_assertAlwaysIgnore); \
} \
AssertDetails_Statement_End
#else
@ -165,15 +165,15 @@ __inline int32_t MsoAssertSzTagProcInline(MsoAssertParamsType params, _Printf_fo
#if DEBUG && !OACR // OACR can't understand FAssertDoSzNTagImpl
/**
FAssertDoSzNTagImpl - all debug FAsserts funnel into here
<condition> || <assertResult && false>
FAssertDoSzNTagImpl - all debug FAsserts funnel into here
<condition> || <assertResult && false>
TODO: need to move the Ignore logic, handle these differently?
Note: be aware that ... requires at least one argument
TODO: need to move the Ignore logic, handle these differently?
Note: be aware that ... requires at least one argument
*/
#define FAssertDoSzNTagImpl(f, dwTag, szFile, iLine, wzAnnotation, sz, ...) \
((f) || (MsoAssertSzTagProcInline2(dwTag, szFile, iLine, wzAnnotation, sz, __VA_ARGS__)))
((f) || (MsoAssertSzTagProcInline2(dwTag, szFile, iLine, wzAnnotation, sz, __VA_ARGS__)))
#else
@ -183,40 +183,50 @@ __inline int32_t MsoAssertSzTagProcInline(MsoAssertParamsType params, _Printf_fo
#endif // DEBUG && !OACR
// Note: AssertDo may contain assignments so I'm using the != 0 syntax which allows that.
#define AssertDoTag(f, tag) Statement(if ((f) == 0) { AssertSzTag(0, #f, tag); })
#define AssertDoSzTag(f, sz, tag) Statement(if ((f) == 0) { AssertSzTag(0, sz, tag); })
#define AssertDoSz1Tag(f, sz, a, tag) Statement(if ((f) == 0) { AssertSz1Tag(0, sz, a, tag); })
#define AssertDoSz2Tag(f, sz, a, b, tag) Statement(if ((f) == 0) { AssertSz2Tag(0, sz, a, b, tag); })
#define AssertDoSz3Tag(f, sz, a, b, c, tag) Statement(if ((f) == 0) { AssertSz3Tag(0, sz, a, b, c, tag); })
#define AssertDoSz4Tag(f, sz, a, b, c, d, tag) Statement(if ((f) == 0) { AssertSz4Tag(0, sz, a, b, c, d, tag); })
#define AssertDoSz5Tag(f, sz, a, b, c, d, e, tag) Statement(if ((f) == 0) { AssertSz5Tag(0, sz, a, b, c, d, e, tag); })
#define AssertDoTag(f, tag) Statement(if ((f) == 0) { AssertSzTag(0, #f, tag); })
#define AssertDoSzTag(f, sz, tag) Statement(if ((f) == 0) { AssertSzTag(0, sz, tag); })
#define AssertDoSz1Tag(f, sz, a, tag) Statement(if ((f) == 0) { AssertSz1Tag(0, sz, a, tag); })
#define AssertDoSz2Tag(f, sz, a, b, tag) Statement(if ((f) == 0) { AssertSz2Tag(0, sz, a, b, tag); })
#define AssertDoSz3Tag(f, sz, a, b, c, tag) Statement(if ((f) == 0) { AssertSz3Tag(0, sz, a, b, c, tag); })
#define AssertDoSz4Tag(f, sz, a, b, c, d, tag) Statement(if ((f) == 0) { AssertSz4Tag(0, sz, a, b, c, d, tag); })
#define AssertDoSz5Tag(f, sz, a, b, c, d, e, tag) Statement(if ((f) == 0) { AssertSz5Tag(0, sz, a, b, c, d, e, tag); })
/**
Helpers for debug HRESULT asserts.
Ship versions are not supported; consider VerifySucceededElseCrash
Helpers for debug HRESULT asserts.
Ship versions are not supported; consider VerifySucceededElseCrash
*/
#if DEBUG
#define AssertDoSucceededTag(expr, tag) \
AssertDetails_Statement_Begin \
HRESULT _hr_ = (expr); \
AssertAnnotatedSzNTagImpl(SUCCEEDED(_hr_), L#expr L" success. Check local variable _hr_.", InlineMsoAssertParams("SUCCEEDED(" #expr ")", tag, __FILE__, __LINE__), "%s failed with 0x%08x", #expr, _hr_); \
AssertDetails_Statement_End
#define AssertDoSucceededTag(expr, tag) \
AssertDetails_Statement_Begin HRESULT _hr_ = (expr); \
AssertAnnotatedSzNTagImpl( \
SUCCEEDED(_hr_), \
L#expr L" success. Check local variable _hr_.", \
InlineMsoAssertParams("SUCCEEDED(" #expr ")", tag, __FILE__, __LINE__), \
"%s failed with 0x%08x", \
#expr, \
_hr_); \
AssertDetails_Statement_End
#define FAssertDoSucceededTag(expr, tag) \
[&]() noexcept -> bool { \
HRESULT _hr_ = (expr); \
if (FAILED(_hr_)) \
{ \
if (MsoAssertSzTagProcInline(InlineMsoAssertParams("SUCCEEDED(" #expr ")", tag, __FILE__, __LINE__), "%s failed with 0x%08x", #expr, _hr_) == c_assertDebugBreak) \
{ \
AssertBreak(L#expr L" success. Check local variable _hr_."); \
} \
} \
return SUCCEEDED(_hr_); \
OACR_WARNING_SUPPRESS( NOEXCEPT_FUNC_THROWS, "Ignore whether expr throws." ); \
}() \
#define FAssertDoSucceededTag(expr, tag) \
[&]() noexcept -> bool { \
HRESULT _hr_ = (expr); \
if (FAILED(_hr_)) \
{ \
if (MsoAssertSzTagProcInline( \
InlineMsoAssertParams("SUCCEEDED(" #expr ")", tag, __FILE__, __LINE__), \
"%s failed with 0x%08x", \
#expr, \
_hr_) \
== c_assertDebugBreak) \
{ \
AssertBreak(L#expr L" success. Check local variable _hr_."); \
} \
} \
return SUCCEEDED(_hr_); \
OACR_WARNING_SUPPRESS(NOEXCEPT_FUNC_THROWS, "Ignore whether expr throws."); \
}()
#else
@ -226,9 +236,9 @@ __inline int32_t MsoAssertSzTagProcInline(MsoAssertParamsType params, _Printf_fo
#endif // DEBUG
/**
Random other deprecated assert macros
Random other deprecated assert macros
*/
#define AssertImpliesTag(a, b, tag) AssertSzTag(FImplies(a, b), #a " => " #b, tag)
#define AssertBiImpliesTag(a, b, tag) AssertSzTag(FBiImplies(a, b), #a " <==> " #b, tag)
#define AssertImpliesTag(a, b, tag) AssertSzTag(FImplies(a, b), #a " => " #b, tag)
#define AssertBiImpliesTag(a, b, tag) AssertSzTag(FBiImplies(a, b), #a " <==> " #b, tag)
#endif // LIBLET_DEBUGASSERTAPI_DEBUGASSERTDETAILS_H

Просмотреть файл

@ -4,13 +4,12 @@
#pragma once
#include <debugAssertApi/debugAssertApi.h>
namespace Mso {
namespace DebugAsserts {
namespace Mso { namespace DebugAsserts {
#ifdef DEBUG
/**
Legacy APIs for disabling asserts
Legacy APIs for disabling asserts
*/
LIBLET_PUBLICAPI void DisableAssertTag(uint32_t tag) noexcept;
LIBLET_PUBLICAPI void EnableAssertTag(uint32_t tag) noexcept;
@ -20,7 +19,10 @@ LIBLET_PUBLICAPI bool IsAssertTagDisabled(uint32_t tag) noexcept;
inline void DisableAssertTag(uint32_t) noexcept {}
inline void EnableAssertTag(uint32_t) noexcept {}
inline bool IsAssertTagDisabled(uint32_t) noexcept { return false; }
inline bool IsAssertTagDisabled(uint32_t) noexcept
{
return false;
}
#endif
@ -85,5 +87,4 @@ private:
};
#endif
} // DebugAsserts
} // Mso
}} // namespace Mso::DebugAsserts

Просмотреть файл

@ -12,130 +12,129 @@
#ifdef DEBUG
namespace Mso {
namespace DebugAsserts {
namespace Mso { namespace DebugAsserts {
struct Data
{
std::set<uint32_t> DisabledTags;
std::set<AssertIgnorer> Ignorers;
std::set<AssertListener> Listeners;
AssertHandler Handler = nullptr;
std::set<uint32_t> DisabledTags;
std::set<AssertIgnorer> Ignorers;
std::set<AssertListener> Listeners;
AssertHandler Handler = nullptr;
static Data& Get() noexcept
{
// To avoid static initializer ordering issues, this object is created on demand and purposely leaked
static auto s_data = Construct();
return *s_data;
}
static Data& Get() noexcept
{
// To avoid static initializer ordering issues, this object is created on demand and purposely leaked
static auto s_data = Construct();
return *s_data;
}
private:
static Data* Construct() noexcept
{
// xlsrv doesn't allow calling new from static initializers. Using std::allocator instead, which has been modified to call malloc.
std::allocator<Data> alloc;
auto p = alloc.allocate(1);
alloc.construct(p);
return p;
}
static Data* Construct() noexcept
{
// xlsrv doesn't allow calling new from static initializers. Using std::allocator instead, which has been modified
// to call malloc.
std::allocator<Data> alloc;
auto p = alloc.allocate(1);
alloc.construct(p);
return p;
}
};
void DisableAssertTag(uint32_t tag) noexcept
{
Data::Get().DisabledTags.insert(tag);
Data::Get().DisabledTags.insert(tag);
}
void EnableAssertTag(uint32_t tag) noexcept
{
Data::Get().DisabledTags.erase(tag);
Data::Get().DisabledTags.erase(tag);
}
bool IsAssertTagDisabled(uint32_t tag) noexcept
{
const auto& disabledTags = Data::Get().DisabledTags;
return (disabledTags.find(tag) != std::end(disabledTags));
const auto& disabledTags = Data::Get().DisabledTags;
return (disabledTags.find(tag) != std::end(disabledTags));
}
void AddAssertIgnorer(AssertIgnorer ignorer) noexcept
{
Data::Get().Ignorers.insert(ignorer);
Data::Get().Ignorers.insert(ignorer);
}
void RemoveAssertIgnorer(AssertIgnorer ignorer) noexcept
{
Data::Get().Ignorers.erase(ignorer);
Data::Get().Ignorers.erase(ignorer);
}
void AddAssertListener(AssertListener listener) noexcept
{
Data::Get().Listeners.insert(listener);
Data::Get().Listeners.insert(listener);
}
void RemoveAssertListener(AssertListener listener) noexcept
{
Data::Get().Listeners.erase(listener);
Data::Get().Listeners.erase(listener);
}
AssertHandler GetAssertHandler() noexcept
{
return Data::Get().Handler;
return Data::Get().Handler;
}
AssertHandler SetAssertHandler(AssertHandler handler) noexcept
{
std::swap(Data::Get().Handler, handler);
return handler;
std::swap(Data::Get().Handler, handler);
return handler;
}
static bool v_isInAssertHandler;
extern "C" int32_t MsoAssertSzTagProc(const MsoAssertParams& params, _Printf_format_string_ const char* szFormat, va_list argList) noexcept
extern "C" int32_t
MsoAssertSzTagProc(const MsoAssertParams& params, _Printf_format_string_ const char* szFormat, va_list argList) noexcept
{
if (IsAssertTagDisabled(params.dwTag))
return c_assertIgnore;
if (IsAssertTagDisabled(params.dwTag))
return c_assertIgnore;
char assertMessage[4096];
(void) vsnprintf(assertMessage, sizeof(assertMessage), szFormat, argList);
params.framesToSkip++;
char assertMessage[4096];
(void)vsnprintf(assertMessage, sizeof(assertMessage), szFormat, argList);
params.framesToSkip++;
const auto& data = Data::Get();
for (const auto& ignorer : data.Ignorers)
{
if (ignorer(params, assertMessage))
return c_assertIgnore;
}
for (const auto& listener : data.Listeners)
{
listener(params, assertMessage);
}
const auto& data = Data::Get();
for (const auto& ignorer : data.Ignorers)
{
if (ignorer(params, assertMessage))
return c_assertIgnore;
}
if (data.Handler)
{
Mso::TRestorer<bool> restoreInAssertHandler(v_isInAssertHandler, true);
return static_cast<int32_t>(data.Handler(params, assertMessage));
}
for (const auto& listener : data.Listeners)
{
listener(params, assertMessage);
}
return c_assertIgnore;
if (data.Handler)
{
Mso::TRestorer<bool> restoreInAssertHandler(v_isInAssertHandler, true);
return static_cast<int32_t>(data.Handler(params, assertMessage));
}
return c_assertIgnore;
}
bool IsInAssertHandler() noexcept
{
return v_isInAssertHandler;
return v_isInAssertHandler;
}
} // DebugAsserts
} // Mso
}} // namespace Mso::DebugAsserts
LIBLET_PUBLICAPI_APPLE MSOAPI_(void) MsoFAddIgnoredAssertTag(uint32_t tag) noexcept
{
Mso::DebugAsserts::DisableAssertTag(tag);
Mso::DebugAsserts::DisableAssertTag(tag);
}
LIBLET_PUBLICAPI_APPLE MSOAPI_(void) MsoFRemoveIgnoredAssertTag(uint32_t tag) noexcept
{
Mso::DebugAsserts::EnableAssertTag(tag);
Mso::DebugAsserts::EnableAssertTag(tag);
}
#endif // DEBUG

Просмотреть файл

@ -9,28 +9,27 @@
#include <compilerAdapters/functionDecorations.h>
#include <chrono>
namespace Mso {
namespace Async {
namespace Mso { namespace Async {
//! Shared event wait handle interface used by ManualResetEvent and AutoResetEvent.
//! Since, ManualResetEvent and AutoResetEvent are most commonly used between different threads, we used
//! shared ownership based on ref counting to ensure proper lifetime of the synchronization events.
struct IEventWaitHandle : Mso::IRefCounted
{
virtual void Set() const noexcept = 0;
virtual void Reset() const noexcept = 0;
virtual void Wait() const noexcept = 0;
virtual bool WaitFor(const std::chrono::milliseconds& waitDuration) const noexcept = 0;
virtual void Set() const noexcept = 0;
virtual void Reset() const noexcept = 0;
virtual void Wait() const noexcept = 0;
virtual bool WaitFor(const std::chrono::milliseconds& waitDuration) const noexcept = 0;
};
//! State of the IEventWaitHandle.
enum class EventWaitHandleState : int32_t
{
//! Threads are blocked when calling Wait() or WaitFor() methods.
NotSet,
//! Threads are blocked when calling Wait() or WaitFor() methods.
NotSet,
//! Threads are allowed to proceed or getting unblocked when calling Wait() or WaitFor() methods.
IsSet,
//! Threads are allowed to proceed or getting unblocked when calling Wait() or WaitFor() methods.
IsSet,
};
//! Notifies one or more waiting threads that an event has occurred. This class cannot be inherited.
@ -56,59 +55,55 @@ enum class EventWaitHandleState : int32_t
class ManualResetEvent final
{
public:
//! Creates new ManualResetEvent with the non-signaling state.
ManualResetEvent() noexcept : ManualResetEvent { EventWaitHandleState::NotSet }
{
}
//! Creates new ManualResetEvent with the non-signaling state.
ManualResetEvent() noexcept : ManualResetEvent{EventWaitHandleState::NotSet} {}
//! Creates new ManualResetEvent with the requested signaling state.
LIBLET_PUBLICAPI explicit ManualResetEvent(EventWaitHandleState state) noexcept;
//! Creates new ManualResetEvent with the requested signaling state.
LIBLET_PUBLICAPI explicit ManualResetEvent(EventWaitHandleState state) noexcept;
//! Creates new ManualResetEvent with the provided handle.
ManualResetEvent(IEventWaitHandle& handle) noexcept : m_handle { &handle }
{
}
//! Creates new ManualResetEvent with the provided handle.
ManualResetEvent(IEventWaitHandle& handle) noexcept : m_handle{&handle} {}
ManualResetEvent(const ManualResetEvent&) = default;
ManualResetEvent& operator=(const ManualResetEvent&) = default;
ManualResetEvent(const ManualResetEvent&) = default;
ManualResetEvent& operator=(const ManualResetEvent&) = default;
//! No move semantic
ManualResetEvent(ManualResetEvent&&) = delete;
ManualResetEvent& operator=(ManualResetEvent&&) = delete;
//! No move semantic
ManualResetEvent(ManualResetEvent&&) = delete;
ManualResetEvent& operator=(ManualResetEvent&&) = delete;
//! Sets the state of the event to signaled, which allows one or more waiting threads to proceed.
void Set() const noexcept
{
m_handle->Set();
}
//! Sets the state of the event to signaled, which allows one or more waiting threads to proceed.
void Set() const noexcept
{
m_handle->Set();
}
//! Sets the state of the event to non-signaled state, which causes waiting threads to block.
void Reset() const noexcept
{
m_handle->Reset();
}
//! Sets the state of the event to non-signaled state, which causes waiting threads to block.
void Reset() const noexcept
{
m_handle->Reset();
}
//! Blocks thread indefinitely and waits for the event signaling state.
void Wait() const noexcept
{
m_handle->Wait();
}
//! Blocks thread indefinitely and waits for the event signaling state.
void Wait() const noexcept
{
m_handle->Wait();
}
//! Blocks thread for waitDuration time and waits for the event signaling state.
template <typename TRep, typename TPeriod>
bool WaitFor(const std::chrono::duration<TRep, TPeriod>& waitDuration) const noexcept
{
return m_handle->WaitFor(std::chrono::duration_cast<std::chrono::milliseconds>(waitDuration));
}
//! Blocks thread for waitDuration time and waits for the event signaling state.
template <typename TRep, typename TPeriod>
bool WaitFor(const std::chrono::duration<TRep, TPeriod>& waitDuration) const noexcept
{
return m_handle->WaitFor(std::chrono::duration_cast<std::chrono::milliseconds>(waitDuration));
}
//! Gets the internal event handle.
IEventWaitHandle& GetHandle() const noexcept
{
return *m_handle;
}
//! Gets the internal event handle.
IEventWaitHandle& GetHandle() const noexcept
{
return *m_handle;
}
private:
Mso::TCntPtr<IEventWaitHandle> m_handle;
Mso::TCntPtr<IEventWaitHandle> m_handle;
};
//! Notifies a waiting thread that an event has occurred. This class cannot be inherited.
@ -130,62 +125,57 @@ private:
class AutoResetEvent final
{
public:
//! Creates new AutoResetEvent with the non-signaling state.
AutoResetEvent() noexcept : AutoResetEvent { EventWaitHandleState::NotSet }
{
}
//! Creates new AutoResetEvent with the non-signaling state.
AutoResetEvent() noexcept : AutoResetEvent{EventWaitHandleState::NotSet} {}
//! Creates new AutoResetEvent with the requested signaling state.
LIBLET_PUBLICAPI explicit AutoResetEvent(EventWaitHandleState state) noexcept;
//! Creates new AutoResetEvent with the requested signaling state.
LIBLET_PUBLICAPI explicit AutoResetEvent(EventWaitHandleState state) noexcept;
//! Creates new AutoResetEvent with the provided handle. Crash if handle is null.
AutoResetEvent(IEventWaitHandle& handle) noexcept : m_handle { &handle }
{
}
//! Creates new AutoResetEvent with the provided handle. Crash if handle is null.
AutoResetEvent(IEventWaitHandle& handle) noexcept : m_handle{&handle} {}
AutoResetEvent(const AutoResetEvent&) = default;
AutoResetEvent& operator=(const AutoResetEvent&) = default;
AutoResetEvent(const AutoResetEvent&) = default;
AutoResetEvent& operator=(const AutoResetEvent&) = default;
// No move semantic
AutoResetEvent(AutoResetEvent&&) = delete;
AutoResetEvent& operator=(AutoResetEvent&&) = delete;
// No move semantic
AutoResetEvent(AutoResetEvent&&) = delete;
AutoResetEvent& operator=(AutoResetEvent&&) = delete;
//! Sets the state of the event to signaled, which allows at most one waiting thread to proceed.
void Set() const noexcept
{
m_handle->Set();
}
//! Sets the state of the event to signaled, which allows at most one waiting thread to proceed.
void Set() const noexcept
{
m_handle->Set();
}
//! Sets the state of the event to non-signaled state, which causes waiting threads to block.
void Reset() const noexcept
{
m_handle->Reset();
}
//! Sets the state of the event to non-signaled state, which causes waiting threads to block.
void Reset() const noexcept
{
m_handle->Reset();
}
//! Blocks thread indefinitely and waits for the event signaling state.
void Wait() const noexcept
{
m_handle->Wait();
}
//! Blocks thread indefinitely and waits for the event signaling state.
void Wait() const noexcept
{
m_handle->Wait();
}
//! Blocks thread for waitDuration time and waits for the event signaling state.
template <typename TRep, typename TPeriod>
bool WaitFor(const std::chrono::duration<TRep, TPeriod>& waitDuration) const noexcept
{
return m_handle->WaitFor(std::chrono::duration_cast<std::chrono::milliseconds>(waitDuration));
}
//! Blocks thread for waitDuration time and waits for the event signaling state.
template <typename TRep, typename TPeriod>
bool WaitFor(const std::chrono::duration<TRep, TPeriod>& waitDuration) const noexcept
{
return m_handle->WaitFor(std::chrono::duration_cast<std::chrono::milliseconds>(waitDuration));
}
//! Gets the internal event handle.
IEventWaitHandle& GetHandle() const noexcept
{
return *m_handle;
}
//! Gets the internal event handle.
IEventWaitHandle& GetHandle() const noexcept
{
return *m_handle;
}
private:
Mso::TCntPtr<IEventWaitHandle> m_handle;
Mso::TCntPtr<IEventWaitHandle> m_handle;
};
} // namespace Async
} // namespace Mso
}} // namespace Mso::Async
#endif // LIBLET_DISPATCHQUEUE_EVENTWAITHANDLE_H

Просмотреть файл

@ -7,17 +7,16 @@
#include <limits>
#include <mutex>
namespace Mso {
namespace Async {
namespace Mso { namespace Async {
using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
struct WaitTimePoint
{
bool IsInfinite { false };
bool ShouldUpdateWaitDuration { false };
std::chrono::milliseconds WaitDuration {};
TimePoint WaitUntil {};
bool IsInfinite{false};
bool ShouldUpdateWaitDuration{false};
std::chrono::milliseconds WaitDuration{};
TimePoint WaitUntil{};
};
// Implementation of the IEventWaitHandle interface
@ -25,84 +24,82 @@ template <class TMutex, class TConditionVariable>
class EventWaitHandle final : public Mso::RefCountedObject<IEventWaitHandle>
{
public:
EventWaitHandle(bool isAutoReset, EventWaitHandleState state) noexcept
: m_isAutoReset { isAutoReset }
, m_state { state }
{
}
EventWaitHandle(bool isAutoReset, EventWaitHandleState state) noexcept : m_isAutoReset{isAutoReset}, m_state{state} {}
public: // IEventWaitHandle
void Set() const noexcept override
{
std::lock_guard<TMutex> lock { m_mutex };
m_state = EventWaitHandleState::IsSet;
void Set() const noexcept override
{
std::lock_guard<TMutex> lock{m_mutex};
m_state = EventWaitHandleState::IsSet;
// Notify under the lock to avoid missed signals in case if Wait loop is between
// checking variable and calling wait for signal API.
if (m_isAutoReset)
{
m_cond.NotifyOne();
}
else
{
m_cond.NotifyAll();
}
}
// Notify under the lock to avoid missed signals in case if Wait loop is between
// checking variable and calling wait for signal API.
if (m_isAutoReset)
{
m_cond.NotifyOne();
}
else
{
m_cond.NotifyAll();
}
}
void Reset() const noexcept override
{
std::lock_guard<TMutex> lock { m_mutex };
m_state = EventWaitHandleState::NotSet;
}
void Reset() const noexcept override
{
std::lock_guard<TMutex> lock{m_mutex};
m_state = EventWaitHandleState::NotSet;
}
void Wait() const noexcept override
{
WaitTimePoint waitTimePoint {};
waitTimePoint.IsInfinite = true;
VerifyElseCrashSzTag(WaitUntil(waitTimePoint), "Must not timeout", 0x026e348b /* tag_c19sl */);
}
void Wait() const noexcept override
{
WaitTimePoint waitTimePoint{};
waitTimePoint.IsInfinite = true;
VerifyElseCrashSzTag(WaitUntil(waitTimePoint), "Must not timeout", 0x026e348b /* tag_c19sl */);
}
bool WaitFor(const std::chrono::milliseconds& waitDuration) const noexcept override
{
VerifyElseCrashSzTag(waitDuration.count() < std::numeric_limits<uint32_t>::max(),
"waitDuration must not exceed uint32_t size for milliseconds.", 0x026e348c /* tag_c19sm */);
bool WaitFor(const std::chrono::milliseconds& waitDuration) const noexcept override
{
VerifyElseCrashSzTag(
waitDuration.count() < std::numeric_limits<uint32_t>::max(),
"waitDuration must not exceed uint32_t size for milliseconds.",
0x026e348c /* tag_c19sm */);
auto now = std::chrono::system_clock::now();
auto now = std::chrono::system_clock::now();
WaitTimePoint waitTimePoint {};
waitTimePoint.WaitDuration = waitDuration;
waitTimePoint.WaitUntil = now + waitDuration;
VerifyElseCrashSzTag(waitTimePoint.WaitUntil >= now, "waitDuration causes clock overflow", 0x026e348d /* tag_c19sn */);
WaitTimePoint waitTimePoint{};
waitTimePoint.WaitDuration = waitDuration;
waitTimePoint.WaitUntil = now + waitDuration;
VerifyElseCrashSzTag(
waitTimePoint.WaitUntil >= now, "waitDuration causes clock overflow", 0x026e348d /* tag_c19sn */);
return WaitUntil(waitTimePoint);
}
return WaitUntil(waitTimePoint);
}
private:
bool WaitUntil(WaitTimePoint& timePoint) const noexcept
{
std::lock_guard<TMutex> lock { m_mutex };
while (m_state != EventWaitHandleState::IsSet)
{
if (!m_cond.WaitUntil(m_mutex, timePoint))
{
return false;
}
}
bool WaitUntil(WaitTimePoint& timePoint) const noexcept
{
std::lock_guard<TMutex> lock{m_mutex};
while (m_state != EventWaitHandleState::IsSet)
{
if (!m_cond.WaitUntil(m_mutex, timePoint))
{
return false;
}
}
if (m_isAutoReset)
{
m_state = EventWaitHandleState::NotSet;
}
if (m_isAutoReset)
{
m_state = EventWaitHandleState::NotSet;
}
return true;
}
return true;
}
private:
mutable TMutex m_mutex;
mutable TConditionVariable m_cond;
const bool m_isAutoReset;
mutable EventWaitHandleState m_state;
mutable TMutex m_mutex;
mutable TConditionVariable m_cond;
const bool m_isAutoReset;
mutable EventWaitHandleState m_state;
};
} // namespace Async
} // namespace Mso
}} // namespace Mso::Async

Просмотреть файл

@ -5,93 +5,92 @@
#include "eventWaitHandle.h"
#include <pthread.h>
namespace Mso {
namespace Async {
namespace Mso { namespace Async {
namespace {
// Mutex class based on pthread_mutex_t that meets BasicLockable standard requirements.
struct PThreadMutex
{
~PThreadMutex() noexcept
{
pthread_mutex_destroy(&Handle);
}
~PThreadMutex() noexcept
{
pthread_mutex_destroy(&Handle);
}
void lock() noexcept
{
pthread_mutex_lock(&Handle);
}
void lock() noexcept
{
pthread_mutex_lock(&Handle);
}
void unlock() noexcept
{
pthread_mutex_unlock(&Handle);
}
void unlock() noexcept
{
pthread_mutex_unlock(&Handle);
}
pthread_mutex_t Handle = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t Handle = PTHREAD_MUTEX_INITIALIZER;
};
// pthread_cond_t wrapper
struct ConditionVariable
{
~ConditionVariable() noexcept
{
pthread_cond_destroy(&m_cond);
}
~ConditionVariable() noexcept
{
pthread_cond_destroy(&m_cond);
}
void NotifyOne() noexcept
{
pthread_cond_signal(&m_cond);
}
void NotifyOne() noexcept
{
pthread_cond_signal(&m_cond);
}
void NotifyAll() noexcept
{
pthread_cond_broadcast(&m_cond);
}
void NotifyAll() noexcept
{
pthread_cond_broadcast(&m_cond);
}
bool WaitUntil(PThreadMutex& mutex, const WaitTimePoint& waitTimePoint) noexcept
{
if (waitTimePoint.IsInfinite)
{
VerifyElseCrashSzTag(!pthread_cond_wait(&m_cond, &mutex.Handle), "pthread_cond_wait failed", 0x026e348e /* tag_c19so */);
return true;
}
bool WaitUntil(PThreadMutex& mutex, const WaitTimePoint& waitTimePoint) noexcept
{
if (waitTimePoint.IsInfinite)
{
VerifyElseCrashSzTag(
!pthread_cond_wait(&m_cond, &mutex.Handle), "pthread_cond_wait failed", 0x026e348e /* tag_c19so */);
return true;
}
auto tsWaitUntil = DurationToTimeSpec(waitTimePoint.WaitUntil.time_since_epoch());
if (int error = pthread_cond_timedwait(&m_cond, &mutex.Handle, &tsWaitUntil))
{
VerifyElseCrashSzTag(error == ETIMEDOUT, "pthread_cond_wait failed", 0x026e348f /* tag_c19sp */);
return false;
}
auto tsWaitUntil = DurationToTimeSpec(waitTimePoint.WaitUntil.time_since_epoch());
if (int error = pthread_cond_timedwait(&m_cond, &mutex.Handle, &tsWaitUntil))
{
VerifyElseCrashSzTag(error == ETIMEDOUT, "pthread_cond_wait failed", 0x026e348f /* tag_c19sp */);
return false;
}
return true;
}
return true;
}
private:
static timespec DurationToTimeSpec(const TimePoint::duration& duration) noexcept
{
using namespace std::chrono;
timespec ts;
ts.tv_sec = static_cast<time_t>(duration_cast<seconds>(duration).count());
ts.tv_nsec = static_cast<long>(duration_cast<nanoseconds>(duration % seconds { 1 }).count());
return ts;
}
static timespec DurationToTimeSpec(const TimePoint::duration& duration) noexcept
{
using namespace std::chrono;
timespec ts;
ts.tv_sec = static_cast<time_t>(duration_cast<seconds>(duration).count());
ts.tv_nsec = static_cast<long>(duration_cast<nanoseconds>(duration % seconds{1}).count());
return ts;
}
private:
pthread_cond_t m_cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t m_cond = PTHREAD_COND_INITIALIZER;
};
} // namespace
LIBLET_PUBLICAPI ManualResetEvent::ManualResetEvent(EventWaitHandleState state) noexcept
: m_handle { Mso::Make<EventWaitHandle<PThreadMutex, ConditionVariable>>(/*isAutoReset:*/false, state) }
: m_handle{Mso::Make<EventWaitHandle<PThreadMutex, ConditionVariable>>(/*isAutoReset:*/ false, state)}
{
}
LIBLET_PUBLICAPI AutoResetEvent::AutoResetEvent(EventWaitHandleState state) noexcept
: m_handle { Mso::Make<EventWaitHandle<PThreadMutex, ConditionVariable>>(/*isAutoReset:*/true, state) }
: m_handle{Mso::Make<EventWaitHandle<PThreadMutex, ConditionVariable>>(/*isAutoReset:*/ true, state)}
{
}
} // namespace Async
} // namespace Mso
}} // namespace Mso::Async

Просмотреть файл

@ -10,95 +10,90 @@
//! These APIs were added in Windows Vista and considered to be more
//! lightweight when events created with CreateEventEx Windows API.
namespace Mso {
namespace Async {
namespace Mso { namespace Async {
namespace {
// Mutex class based on SRWLOCK that meets BasicLockable standard requirements.
struct SRWMutex
{
_Requires_lock_not_held_(this->Handle)
_Acquires_lock_(this->Handle)
void lock() noexcept
{
AcquireSRWLockExclusive(&Handle);
}
_Requires_lock_not_held_(this->Handle) _Acquires_lock_(this->Handle) void lock() noexcept
{
AcquireSRWLockExclusive(&Handle);
}
_Requires_lock_held_(this->Handle)
_Releases_lock_(this->Handle)
void unlock() noexcept
{
ReleaseSRWLockExclusive(&Handle);
}
_Requires_lock_held_(this->Handle) _Releases_lock_(this->Handle) void unlock() noexcept
{
ReleaseSRWLockExclusive(&Handle);
}
SRWLOCK Handle{ SRWLOCK_INIT };
SRWLOCK Handle{SRWLOCK_INIT};
};
// Windows CONDITION_VARIABLE wrapper
struct ConditionVariable
{
void NotifyOne() noexcept
{
WakeConditionVariable(&m_cond);
}
void NotifyOne() noexcept
{
WakeConditionVariable(&m_cond);
}
void NotifyAll() noexcept
{
WakeAllConditionVariable(&m_cond);
}
void NotifyAll() noexcept
{
WakeAllConditionVariable(&m_cond);
}
bool WaitUntil(SRWMutex& mutex, WaitTimePoint& waitTimePoint) noexcept
{
if (!SleepConditionVariableSRW(&m_cond, &mutex.Handle, GetWaitTimeInMs(waitTimePoint), 0))
{
VerifyElseCrashSzTag(GetLastError() == ERROR_TIMEOUT, "SleepConditionVariableSRW failed.", 0x026e3490 /* tag_c19sq */);
return false;
}
bool WaitUntil(SRWMutex& mutex, WaitTimePoint& waitTimePoint) noexcept
{
if (!SleepConditionVariableSRW(&m_cond, &mutex.Handle, GetWaitTimeInMs(waitTimePoint), 0))
{
VerifyElseCrashSzTag(
GetLastError() == ERROR_TIMEOUT, "SleepConditionVariableSRW failed.", 0x026e3490 /* tag_c19sq */);
return false;
}
return true;
}
return true;
}
private:
static uint32_t GetWaitTimeInMs(WaitTimePoint& waitTimePoint) noexcept
{
if (waitTimePoint.IsInfinite)
{
return INFINITE;
}
static uint32_t GetWaitTimeInMs(WaitTimePoint& waitTimePoint) noexcept
{
if (waitTimePoint.IsInfinite)
{
return INFINITE;
}
// For the very first time here we use duration provided by user.
// If we get here again, then it means that the condition_variable was woken up
// due to sporatic wakeups, and we have to recalculate the wait duration.
if (waitTimePoint.ShouldUpdateWaitDuration)
{
using namespace std::chrono;
auto timeLeft = duration_cast<milliseconds>(waitTimePoint.WaitUntil - system_clock::now());
// Make sure that we do not have negative duration because we waited beyond the target time point,
// or because system_clock::now() gave inacccurate time due to internal implementation.
waitTimePoint.WaitDuration = std::max(timeLeft, milliseconds { 0 });
}
// For the very first time here we use duration provided by user.
// If we get here again, then it means that the condition_variable was woken up
// due to sporatic wakeups, and we have to recalculate the wait duration.
if (waitTimePoint.ShouldUpdateWaitDuration)
{
using namespace std::chrono;
auto timeLeft = duration_cast<milliseconds>(waitTimePoint.WaitUntil - system_clock::now());
// Make sure that we do not have negative duration because we waited beyond the target time point,
// or because system_clock::now() gave inacccurate time due to internal implementation.
waitTimePoint.WaitDuration = std::max(timeLeft, milliseconds{0});
}
waitTimePoint.ShouldUpdateWaitDuration = true;
waitTimePoint.ShouldUpdateWaitDuration = true;
return static_cast<uint32_t>(waitTimePoint.WaitDuration.count());
}
return static_cast<uint32_t>(waitTimePoint.WaitDuration.count());
}
private:
CONDITION_VARIABLE m_cond { CONDITION_VARIABLE_INIT };
CONDITION_VARIABLE m_cond{CONDITION_VARIABLE_INIT};
};
} // namespace
LIBLET_PUBLICAPI ManualResetEvent::ManualResetEvent(EventWaitHandleState state) noexcept
: m_handle { Mso::Make<EventWaitHandle<SRWMutex, ConditionVariable>>(/*isAutoReset:*/false, state) }
: m_handle{Mso::Make<EventWaitHandle<SRWMutex, ConditionVariable>>(/*isAutoReset:*/ false, state)}
{
}
LIBLET_PUBLICAPI AutoResetEvent::AutoResetEvent(EventWaitHandleState state) noexcept
: m_handle { Mso::Make<EventWaitHandle<SRWMutex, ConditionVariable>>(/*isAutoReset:*/true, state) }
: m_handle{Mso::Make<EventWaitHandle<SRWMutex, ConditionVariable>>(/*isAutoReset:*/ true, state)}
{
}
} // namespace Async
} // namespace Mso
}} // namespace Mso::Async

Просмотреть файл

@ -11,327 +11,323 @@
using namespace std::chrono_literals;
namespace Mso {
namespace Async {
namespace Test {
namespace Mso { namespace Async { namespace Test {
TEST_CLASS(EventWaitHandleTest)
TEST_CLASS (EventWaitHandleTest)
{
//TODO: enable MemoryLeakDetection
//MemoryLeakDetectionHook::TrackPerTest m_trackLeakPerTest;
// TODO: enable MemoryLeakDetection
// MemoryLeakDetectionHook::TrackPerTest m_trackLeakPerTest;
TEST_METHOD(ManualResetEvent_ctor_default)
{
ManualResetEvent ev;
TestCheck(&ev.GetHandle());
}
TEST_METHOD(ManualResetEvent_ctor_default)
{
ManualResetEvent ev;
TestCheck(&ev.GetHandle());
}
TEST_METHOD(ManualResetEvent_ctor_Signaling)
{
ManualResetEvent ev{ EventWaitHandleState::IsSet };
TestCheck(&ev.GetHandle());
ev.Wait();
}
TEST_METHOD(ManualResetEvent_ctor_Signaling)
{
ManualResetEvent ev{EventWaitHandleState::IsSet};
TestCheck(&ev.GetHandle());
ev.Wait();
}
TEST_METHOD(ManualResetEvent_ctor_NotSignaling)
{
ManualResetEvent ev { EventWaitHandleState::NotSet };
TestCheck(&ev.GetHandle());
TestCheck(!ev.WaitFor(1ms)); // Must timeout
}
TEST_METHOD(ManualResetEvent_ctor_NotSignaling)
{
ManualResetEvent ev{EventWaitHandleState::NotSet};
TestCheck(&ev.GetHandle());
TestCheck(!ev.WaitFor(1ms)); // Must timeout
}
TEST_METHOD(ManualResetEvent_ctor_handle)
{
ManualResetEvent ev1;
ManualResetEvent ev2 { ev1.GetHandle() };
TestCheck(&ev1.GetHandle() == &ev2.GetHandle());
}
TEST_METHOD(ManualResetEvent_ctor_handle)
{
ManualResetEvent ev1;
ManualResetEvent ev2{ev1.GetHandle()};
TestCheck(&ev1.GetHandle() == &ev2.GetHandle());
}
TEST_METHOD(ManualResetEvent_ctor_copy)
{
ManualResetEvent ev1;
ManualResetEvent ev2{ ev1 }; // Copy
TestCheck(&ev1.GetHandle() == &ev2.GetHandle());
}
TEST_METHOD(ManualResetEvent_ctor_copy)
{
ManualResetEvent ev1;
ManualResetEvent ev2{ev1}; // Copy
TestCheck(&ev1.GetHandle() == &ev2.GetHandle());
}
TEST_METHOD(ManualResetEvent_assignment_copy)
{
ManualResetEvent ev1;
ManualResetEvent ev2;
ev2 = ev1; // Copy
TestCheck(&ev1.GetHandle() == &ev2.GetHandle());
}
TEST_METHOD(ManualResetEvent_assignment_copy)
{
ManualResetEvent ev1;
ManualResetEvent ev2;
ev2 = ev1; // Copy
TestCheck(&ev1.GetHandle() == &ev2.GetHandle());
}
TEST_METHOD(ManualResetEvent_Set)
{
std::atomic<int32_t> value{ 0 };
ManualResetEvent ev;
// Note that we capture by value to make a copy of the pointer.
std::thread th([ev, &value]() noexcept {
ev.Set();
++value;
});
ev.Wait();
th.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(ManualResetEvent_Set)
{
std::atomic<int32_t> value{0};
ManualResetEvent ev;
// Note that we capture by value to make a copy of the pointer.
std::thread th([ev, &value]() noexcept {
ev.Set();
++value;
});
ev.Wait();
th.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(ManualResetEvent_NoAutoReset)
{
std::atomic<int32_t> value{ 0 };
ManualResetEvent ev;
std::thread th([ev, &value]() noexcept {
ev.Set();
++value;
});
ev.Wait();
ev.Wait(); // Second Wait succeeds because it is not auto-reset.
th.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(ManualResetEvent_NoAutoReset)
{
std::atomic<int32_t> value{0};
ManualResetEvent ev;
std::thread th([ev, &value]() noexcept {
ev.Set();
++value;
});
ev.Wait();
ev.Wait(); // Second Wait succeeds because it is not auto-reset.
th.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(ManualResetEvent_TwoWaitThreadsWakeup)
{
ManualResetEvent ev;
std::atomic<int32_t> value{ 0 };
std::thread th1([ev, &value]() noexcept {
ev.Wait();
++value;
});
std::thread th2([ev, &value]() noexcept {
ev.Wait();
++value;
});
ev.Set();
th1.join();
th2.join();
TestCheckEqual(2, value.load());
}
TEST_METHOD(ManualResetEvent_TwoWaitThreadsWakeup)
{
ManualResetEvent ev;
std::atomic<int32_t> value{0};
std::thread th1([ev, &value]() noexcept {
ev.Wait();
++value;
});
std::thread th2([ev, &value]() noexcept {
ev.Wait();
++value;
});
ev.Set();
th1.join();
th2.join();
TestCheckEqual(2, value.load());
}
TEST_METHOD(ManualResetEvent_Reset)
{
ManualResetEvent ev;
std::atomic<int32_t> value{ 0 };
std::thread th1([ev, &value]() noexcept {
ev.Wait();
++value;
ev.Reset();
});
ev.Set();
th1.join();
TestCheckEqual(1, value.load());
std::thread th2([ev, &value]() noexcept {
ev.Wait();
++value;
});
TestCheckEqual(1, value.load()); // Make sure that th2 waits
ev.Set();
th2.join();
TestCheckEqual(2, value.load());
}
TEST_METHOD(ManualResetEvent_Reset)
{
ManualResetEvent ev;
std::atomic<int32_t> value{0};
std::thread th1([ev, &value]() noexcept {
ev.Wait();
++value;
ev.Reset();
});
ev.Set();
th1.join();
TestCheckEqual(1, value.load());
std::thread th2([ev, &value]() noexcept {
ev.Wait();
++value;
});
TestCheckEqual(1, value.load()); // Make sure that th2 waits
ev.Set();
th2.join();
TestCheckEqual(2, value.load());
}
TEST_METHOD(ManualResetEvent_WaitFor0)
{
ManualResetEvent ev;
std::atomic<int32_t> value{ 0 };
std::thread th1([ev, &value]() noexcept {
TestCheck(!ev.WaitFor(0ms)); // Must always timeout in our case.
++value;
});
th1.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(ManualResetEvent_WaitFor0)
{
ManualResetEvent ev;
std::atomic<int32_t> value{0};
std::thread th1([ev, &value]() noexcept {
TestCheck(!ev.WaitFor(0ms)); // Must always timeout in our case.
++value;
});
th1.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(ManualResetEvent_WaitFor1)
{
ManualResetEvent ev;
std::atomic<int32_t> value{ 0 };
std::thread th1([ev, &value]() noexcept {
TestCheck(!ev.WaitFor(1ms)); // Must always timeout in our case.
++value;
});
th1.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(ManualResetEvent_WaitFor1)
{
ManualResetEvent ev;
std::atomic<int32_t> value{0};
std::thread th1([ev, &value]() noexcept {
TestCheck(!ev.WaitFor(1ms)); // Must always timeout in our case.
++value;
});
th1.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(ManualResetEvent_WaitFor_Succeed)
{
ManualResetEvent ev;
std::atomic<int32_t> value{ 0 };
std::thread th1([ev, &value]() noexcept {
TestCheck(ev.WaitFor(1000s)); // Must succeed because we call Set.
++value;
});
ev.Set();
th1.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(ManualResetEvent_WaitFor_Succeed)
{
ManualResetEvent ev;
std::atomic<int32_t> value{0};
std::thread th1([ev, &value]() noexcept {
TestCheck(ev.WaitFor(1000s)); // Must succeed because we call Set.
++value;
});
ev.Set();
th1.join();
TestCheckEqual(1, value.load());
}
TESTMETHOD_REQUIRES_SEH(ManualResetEvent_WaitFor_CrashForOverflow)
{
//TODO: enable MemoryLeakDetection
//TEST_DISABLE_MEMORY_LEAK_DETECTION();
ManualResetEvent ev;
TestCheckCrash(ev.WaitFor(std::chrono::seconds::max()));
}
TESTMETHOD_REQUIRES_SEH(ManualResetEvent_WaitFor_CrashForOverflow)
{
// TODO: enable MemoryLeakDetection
// TEST_DISABLE_MEMORY_LEAK_DETECTION();
ManualResetEvent ev;
TestCheckCrash(ev.WaitFor(std::chrono::seconds::max()));
}
TEST_METHOD(ManualResetEvent_WaitFor_CrashForInfinite)
{
//TODO: enable MemoryLeakDetection
//TEST_DISABLE_MEMORY_LEAK_DETECTION();
ManualResetEvent ev;
TestCheckCrash(ev.WaitFor(std::chrono::milliseconds(std::numeric_limits<uint32_t>::max())));
}
TEST_METHOD(ManualResetEvent_WaitFor_CrashForInfinite)
{
// TODO: enable MemoryLeakDetection
// TEST_DISABLE_MEMORY_LEAK_DETECTION();
ManualResetEvent ev;
TestCheckCrash(ev.WaitFor(std::chrono::milliseconds(std::numeric_limits<uint32_t>::max())));
}
TEST_METHOD(AutoResetEvent_ctor_default)
{
AutoResetEvent ev;
TestCheck(&ev.GetHandle());
}
TEST_METHOD(AutoResetEvent_ctor_default)
{
AutoResetEvent ev;
TestCheck(&ev.GetHandle());
}
TEST_METHOD(AutoResetEvent_ctor_Signaling)
{
AutoResetEvent ev { EventWaitHandleState::IsSet };
TestCheck(&ev.GetHandle());
ev.Wait();
}
TEST_METHOD(AutoResetEvent_ctor_Signaling)
{
AutoResetEvent ev{EventWaitHandleState::IsSet};
TestCheck(&ev.GetHandle());
ev.Wait();
}
TEST_METHOD(AutoResetEvent_ctor_NotSignaling)
{
AutoResetEvent ev { EventWaitHandleState::NotSet };
TestCheck(&ev.GetHandle());
TestCheck(!ev.WaitFor(1ms)); // Must timeout
}
TEST_METHOD(AutoResetEvent_ctor_NotSignaling)
{
AutoResetEvent ev{EventWaitHandleState::NotSet};
TestCheck(&ev.GetHandle());
TestCheck(!ev.WaitFor(1ms)); // Must timeout
}
TEST_METHOD(AutoResetEvent_ctor_handle)
{
AutoResetEvent ev1;
AutoResetEvent ev2 { ev1.GetHandle() };
TestCheck(&ev1.GetHandle() == &ev2.GetHandle());
}
TEST_METHOD(AutoResetEvent_ctor_handle)
{
AutoResetEvent ev1;
AutoResetEvent ev2{ev1.GetHandle()};
TestCheck(&ev1.GetHandle() == &ev2.GetHandle());
}
TEST_METHOD(AutoResetEvent_Set)
{
std::atomic<int32_t> value{ 0 };
AutoResetEvent ev;
// Note that we capture by value to make a copy of the pointer.
std::thread th([ev, &value]() noexcept {
ev.Set();
++value;
});
ev.Wait();
th.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(AutoResetEvent_Set)
{
std::atomic<int32_t> value{0};
AutoResetEvent ev;
// Note that we capture by value to make a copy of the pointer.
std::thread th([ev, &value]() noexcept {
ev.Set();
++value;
});
ev.Wait();
th.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(AutoResetEvent_AutoReset)
{
std::atomic<int32_t> value{ 0 };
AutoResetEvent ev;
std::thread th([ev, &value]() noexcept {
ev.Set();
++value;
});
ev.Wait();
TestCheck(!ev.WaitFor(1ms)); // Second Wait fails because it is auto-reset.
th.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(AutoResetEvent_AutoReset)
{
std::atomic<int32_t> value{0};
AutoResetEvent ev;
std::thread th([ev, &value]() noexcept {
ev.Set();
++value;
});
ev.Wait();
TestCheck(!ev.WaitFor(1ms)); // Second Wait fails because it is auto-reset.
th.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(AutoResetEvent_TwoWaitThreadsWakeup)
{
AutoResetEvent ev;
ManualResetEvent valueChanged;
std::atomic<int32_t> value{ 0 };
std::thread th1([ev, &value, valueChanged]() noexcept {
ev.Wait();
++value;
valueChanged.Set();
});
std::thread th2([ev, &value, valueChanged]() noexcept {
ev.Wait();
++value;
valueChanged.Set();
});
ev.Set();
valueChanged.Wait();
TestCheckEqual(1, value.load());
ev.Set();
th1.join();
th2.join();
TestCheckEqual(2, value.load());
}
TEST_METHOD(AutoResetEvent_TwoWaitThreadsWakeup)
{
AutoResetEvent ev;
ManualResetEvent valueChanged;
std::atomic<int32_t> value{0};
std::thread th1([ev, &value, valueChanged]() noexcept {
ev.Wait();
++value;
valueChanged.Set();
});
std::thread th2([ev, &value, valueChanged]() noexcept {
ev.Wait();
++value;
valueChanged.Set();
});
ev.Set();
valueChanged.Wait();
TestCheckEqual(1, value.load());
ev.Set();
th1.join();
th2.join();
TestCheckEqual(2, value.load());
}
TEST_METHOD(AutoResetEvent_Reset)
{
AutoResetEvent ev;
std::atomic<int32_t> value{ 0 };
ev.Set();
ev.Reset();
TestCheck(!ev.WaitFor(1ms)); // Make sure that ev is not signaling.
std::thread th([ev, &value]() noexcept {
ev.Wait();
++value;
});
ev.Set();
th.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(AutoResetEvent_Reset)
{
AutoResetEvent ev;
std::atomic<int32_t> value{0};
ev.Set();
ev.Reset();
TestCheck(!ev.WaitFor(1ms)); // Make sure that ev is not signaling.
std::thread th([ev, &value]() noexcept {
ev.Wait();
++value;
});
ev.Set();
th.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(AutoResetEvent_WaitFor0)
{
AutoResetEvent ev;
std::atomic<int32_t> value{ 0 };
std::thread th1([ev, &value]() noexcept {
TestCheck(!ev.WaitFor(0ms)); // Must always timeout in our case.
++value;
});
th1.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(AutoResetEvent_WaitFor0)
{
AutoResetEvent ev;
std::atomic<int32_t> value{0};
std::thread th1([ev, &value]() noexcept {
TestCheck(!ev.WaitFor(0ms)); // Must always timeout in our case.
++value;
});
th1.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(AutoResetEvent_WaitFor1)
{
AutoResetEvent ev;
std::atomic<int32_t> value{ 0 };
std::thread th1([ev, &value]() noexcept {
TestCheck(!ev.WaitFor(1ms)); // Must always timeout in our case.
++value;
});
th1.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(AutoResetEvent_WaitFor1)
{
AutoResetEvent ev;
std::atomic<int32_t> value{0};
std::thread th1([ev, &value]() noexcept {
TestCheck(!ev.WaitFor(1ms)); // Must always timeout in our case.
++value;
});
th1.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(AutoResetEvent_WaitFor_Succeed)
{
AutoResetEvent ev;
std::atomic<int32_t> value{ 0 };
std::thread th1([ev, &value]() noexcept {
TestCheck(ev.WaitFor(1000s)); // Must succeed because we call Set.
++value;
});
ev.Set();
th1.join();
TestCheckEqual(1, value.load());
}
TEST_METHOD(AutoResetEvent_WaitFor_Succeed)
{
AutoResetEvent ev;
std::atomic<int32_t> value{0};
std::thread th1([ev, &value]() noexcept {
TestCheck(ev.WaitFor(1000s)); // Must succeed because we call Set.
++value;
});
ev.Set();
th1.join();
TestCheckEqual(1, value.load());
}
TESTMETHOD_REQUIRES_SEH(AutoResetEvent_WaitFor_CrashForOverflow)
{
//TODO: enable MemoryLeakDetection
//TEST_DISABLE_MEMORY_LEAK_DETECTION();
AutoResetEvent ev;
TestCheckCrash(ev.WaitFor(std::chrono::seconds::max()));
}
TESTMETHOD_REQUIRES_SEH(AutoResetEvent_WaitFor_CrashForOverflow)
{
// TODO: enable MemoryLeakDetection
// TEST_DISABLE_MEMORY_LEAK_DETECTION();
AutoResetEvent ev;
TestCheckCrash(ev.WaitFor(std::chrono::seconds::max()));
}
TESTMETHOD_REQUIRES_SEH(AutoResetEvent_WaitFor_CrashForInfinite)
{
//TODO: enable MemoryLeakDetection
//TEST_DISABLE_MEMORY_LEAK_DETECTION();
AutoResetEvent ev;
TestCheckCrash(ev.WaitFor(std::chrono::milliseconds(std::numeric_limits<uint32_t>::max())));
}
TESTMETHOD_REQUIRES_SEH(AutoResetEvent_WaitFor_CrashForInfinite)
{
// TODO: enable MemoryLeakDetection
// TEST_DISABLE_MEMORY_LEAK_DETECTION();
AutoResetEvent ev;
TestCheckCrash(ev.WaitFor(std::chrono::milliseconds(std::numeric_limits<uint32_t>::max())));
}
};
} // namespace Testing
} // namespace Async
} // namespace Mso
}}} // namespace Mso::Async::Test

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -17,7 +17,7 @@
//! stored as a field in an object.
//!
//! Mso::FunctorRef has the following semantics:
//!
//!
//! - Only keeps a reference to the function object.
//! - Never copies or moves the provided function object.
//! - Does not do a heap allocation and has size of two pointers (one is
@ -29,10 +29,10 @@
//! unlike std::function<>.
//! - Supports optional semantic by allowing to be initialized with nullptr, and
//! then to be checked for non-null by the explicit bool operator.
//!
//!
//! The Mso::FunctorRef only supports noexcept function objects.
//! Use Mso::FunctorRefThrow for throwing function objects.
//!
//!
//! In case if you want to store function object or transfer its ownership, you can use:
//! - Mso::Functor that is an Mso::TCntPtr to a ref counted heap-allocated object.
//! - Mso::SmallFunctor that uses in-place storage.
@ -45,7 +45,7 @@
//! virtual MyObject FindInCache(const Mso::FunctorRef<bool(MyObject&)>& predicate) = 0;
//!
//! This method can be called as following:
//!
//!
//! myCache->FindInCache([this](MyObject& obj) noexcept { return this->CheckObj(obj); });
//!
//! Note that we can simply pass lambda as a parameter because we allow use of
@ -115,91 +115,91 @@ using FunctorRefStorage = std::aligned_storage<sizeof(uintptr_t) * 2, 8>::type;
} // namespace Details
//! Reference to a non-throwing function object.
//! Reference to a non-throwing function object.
template <typename TResult, typename... TArgs>
class FunctorRef<TResult(TArgs...)>
#if !defined(__cpp_noexcept_function_type) && (_HAS_NOEXCEPT_FUNCTION_TYPES != 1)
final
final
#endif
{
public:
//! Creates an empty FunctorRef
_Allow_implicit_ctor_ FunctorRef(std::nullptr_t) noexcept
{
}
//! Creates an empty FunctorRef
_Allow_implicit_ctor_ FunctorRef(std::nullptr_t) noexcept {}
//! Creates a non-empty FunctorRef
template <typename T>
_Allow_implicit_ctor_ FunctorRef(T&& func) noexcept
{
using WrapperType = FunctorRefWrapper<std::remove_reference_t<T>>;
//! Creates a non-empty FunctorRef
template <typename T>
_Allow_implicit_ctor_ FunctorRef(T&& func) noexcept
{
using WrapperType = FunctorRefWrapper<std::remove_reference_t<T>>;
// Make sure that WrapperType storage requirements match the FunctorRefStorage.
static_assert(sizeof(WrapperType) <= sizeof(Details::FunctorRefStorage),
"WrapperType is too big to fit in FunctorRefStorage.");
static_assert(std::alignment_of<WrapperType>::value <= std::alignment_of<Details::FunctorRefStorage>::value,
"WrapperType alignment does not match to FunctorRefStorage.");
// Make sure that WrapperType storage requirements match the FunctorRefStorage.
static_assert(
sizeof(WrapperType) <= sizeof(Details::FunctorRefStorage),
"WrapperType is too big to fit in FunctorRefStorage.");
static_assert(
std::alignment_of<WrapperType>::value <= std::alignment_of<Details::FunctorRefStorage>::value,
"WrapperType alignment does not match to FunctorRefStorage.");
::new (std::addressof(m_storage)) WrapperType{&func};
}
::new (std::addressof(m_storage)) WrapperType{&func};
}
//! Delete copy and move constructors and assignment operators.
DECLARE_COPYCONSTR_AND_ASSIGNMENT(FunctorRef);
//! Delete copy and move constructors and assignment operators.
DECLARE_COPYCONSTR_AND_ASSIGNMENT(FunctorRef);
//! Calls referenced function object.
//! Crash if referenced function object is nullptr.
TResult operator()(TArgs... args) const noexcept
{
// It's important that we don't use '&&' on TArgs here. Since TArgs is a class
// template parameter, the '&&' would force each argument to become an rvalue
// (or, subject to ref-collapsing, an lvalue ref) which could prevent us from
// being able to correctly invoke the underlying function object. With
// that said, it is important that the wrapper's 'Invoke' uses '&&' to prevent
// a second copy of any non-ref-qualified parameter since a copy would already
// have been made here.
//! Calls referenced function object.
//! Crash if referenced function object is nullptr.
TResult operator()(TArgs... args) const noexcept
{
// It's important that we don't use '&&' on TArgs here. Since TArgs is a class
// template parameter, the '&&' would force each argument to become an rvalue
// (or, subject to ref-collapsing, an lvalue ref) which could prevent us from
// being able to correctly invoke the underlying function object. With
// that said, it is important that the wrapper's 'Invoke' uses '&&' to prevent
// a second copy of any non-ref-qualified parameter since a copy would already
// have been made here.
VerifyElseCrashSzTag(*this, "FunctorRef must not be empty", 0x025d9804 /* tag_cxz6e */);
return reinterpret_cast<const IFunctorRef*>(std::addressof(m_storage))->Invoke(std::forward<TArgs>(args)...);
}
VerifyElseCrashSzTag(*this, "FunctorRef must not be empty", 0x025d9804 /* tag_cxz6e */);
return reinterpret_cast<const IFunctorRef*>(std::addressof(m_storage))->Invoke(std::forward<TArgs>(args)...);
}
//! True if wrapped function object is not nullptr.
explicit operator bool() const noexcept
{
return *reinterpret_cast<const uintptr_t*>(std::addressof(m_storage)) != 0;
}
//! True if wrapped function object is not nullptr.
explicit operator bool() const noexcept
{
return *reinterpret_cast<const uintptr_t*>(std::addressof(m_storage)) != 0;
}
private:
//! The interface to be implemented by FunctorRefWrapper<T>.
struct IFunctorRef
{
virtual TResult Invoke(TArgs&&...) const noexcept = 0;
};
//! The interface to be implemented by FunctorRefWrapper<T>.
struct IFunctorRef
{
virtual TResult Invoke(TArgs&&...) const noexcept = 0;
};
//! A wrapper for a function object reference.
//! We do not call destructor for this class because it does not need to free any resources.
template <typename T>
struct FunctorRefWrapper final : IFunctorRef
{
FunctorRefWrapper(T* func) noexcept : m_func(func) {}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(FunctorRefWrapper);
~FunctorRefWrapper() = delete;
//! A wrapper for a function object reference.
//! We do not call destructor for this class because it does not need to free any resources.
template <typename T>
struct FunctorRefWrapper final : IFunctorRef
{
FunctorRefWrapper(T* func) noexcept : m_func(func) {}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(FunctorRefWrapper);
~FunctorRefWrapper() = delete;
TResult Invoke(TArgs&&... args) const noexcept override
{
// If you see OACR warning "Nothrow Func Throws" here then it means that the
// provided lambda or function object's operator() are not marked as noexcept.
TResult Invoke(TArgs&&... args) const noexcept override
{
// If you see OACR warning "Nothrow Func Throws" here then it means that the
// provided lambda or function object's operator() are not marked as noexcept.
// We use const_cast to enable support for mutable lambdas
return (*const_cast<FunctorRefWrapper*>(this)->m_func)(std::forward<TArgs>(args)...);
}
// We use const_cast to enable support for mutable lambdas
return (*const_cast<FunctorRefWrapper*>(this)->m_func)(std::forward<TArgs>(args)...);
}
private:
T* m_func;
};
private:
T* m_func;
};
private:
// Storage for 2 pointers: v_table + reference
Details::FunctorRefStorage m_storage { 0 };
// Storage for 2 pointers: v_table + reference
Details::FunctorRefStorage m_storage{0};
};
#if defined(__cpp_noexcept_function_type) || (_HAS_NOEXCEPT_FUNCTION_TYPES == 1)
@ -210,7 +210,7 @@ template <typename TResult, typename... TArgs>
class FunctorRef<TResult(TArgs...) noexcept> : public FunctorRef<TResult(TArgs...)>
{
public:
using FunctorRef<TResult(TArgs...)>::FunctorRef;
using FunctorRef<TResult(TArgs...)>::FunctorRef;
};
#endif
@ -220,88 +220,88 @@ template <typename TResult, typename... TArgs>
class FunctorRefThrow<TResult(TArgs...)> final
{
public:
//! Creates an empty FunctorRefThrow
_Allow_implicit_ctor_ FunctorRefThrow(std::nullptr_t) noexcept
{
}
//! Creates an empty FunctorRefThrow
_Allow_implicit_ctor_ FunctorRefThrow(std::nullptr_t) noexcept {}
//! Creates an non-empty FunctorRefThrow
template <typename T>
_Allow_implicit_ctor_ FunctorRefThrow(T&& func) noexcept
{
using WrapperType = FunctorRefThrowWrapper<std::remove_reference_t<T>>;
//! Creates an non-empty FunctorRefThrow
template <typename T>
_Allow_implicit_ctor_ FunctorRefThrow(T&& func) noexcept
{
using WrapperType = FunctorRefThrowWrapper<std::remove_reference_t<T>>;
// Make sure that WrapperType storage requirements match the FunctorRefStorage.
static_assert(sizeof(WrapperType) <= sizeof(Details::FunctorRefStorage),
"WrapperType is too big to fit in FunctorRefStorage.");
static_assert(std::alignment_of<WrapperType>::value <= std::alignment_of<Details::FunctorRefStorage>::value,
"WrapperType alignment does not match to FunctorRefStorage.");
// Make sure that WrapperType storage requirements match the FunctorRefStorage.
static_assert(
sizeof(WrapperType) <= sizeof(Details::FunctorRefStorage),
"WrapperType is too big to fit in FunctorRefStorage.");
static_assert(
std::alignment_of<WrapperType>::value <= std::alignment_of<Details::FunctorRefStorage>::value,
"WrapperType alignment does not match to FunctorRefStorage.");
::new (std::addressof(m_storage)) WrapperType{&func};
}
::new (std::addressof(m_storage)) WrapperType{&func};
}
//! Delete copy and move constructors and assignment operators.
DECLARE_COPYCONSTR_AND_ASSIGNMENT(FunctorRefThrow);
//! Delete copy and move constructors and assignment operators.
DECLARE_COPYCONSTR_AND_ASSIGNMENT(FunctorRefThrow);
//! Calls referenced function object.
//! Crash if referenced function object is nullptr.
TResult operator()(TArgs... args) const
{
// It's important that we don't use '&&' on TArgs here. Since TArgs is a class
// template parameter, the '&&' would force each argument to become an rvalue
// (or, subject to ref-collapsing, an lvalue ref) which could prevent us from
// being able to correctly invoke the underlying function object. With
// that said, it is important that the wrapper's 'Invoke' uses '&&' to prevent
// a second copy of any non-ref-qualified parameter since a copy would already
// have been made here.
//! Calls referenced function object.
//! Crash if referenced function object is nullptr.
TResult operator()(TArgs... args) const
{
// It's important that we don't use '&&' on TArgs here. Since TArgs is a class
// template parameter, the '&&' would force each argument to become an rvalue
// (or, subject to ref-collapsing, an lvalue ref) which could prevent us from
// being able to correctly invoke the underlying function object. With
// that said, it is important that the wrapper's 'Invoke' uses '&&' to prevent
// a second copy of any non-ref-qualified parameter since a copy would already
// have been made here.
VerifyElseCrashSzTag(*this, "FunctorRefThrow must not be empty", 0x025d9805 /* tag_cxz6f */);
return reinterpret_cast<const IFunctorRefThrow*>(std::addressof(m_storage))->Invoke(std::forward<TArgs>(args)...);
}
VerifyElseCrashSzTag(*this, "FunctorRefThrow must not be empty", 0x025d9805 /* tag_cxz6f */);
return reinterpret_cast<const IFunctorRefThrow*>(std::addressof(m_storage))->Invoke(std::forward<TArgs>(args)...);
}
//! True if wrapped function object is not nullptr.
explicit operator bool() const noexcept
{
return *reinterpret_cast<const uintptr_t*>(std::addressof(m_storage)) != 0;
}
//! True if wrapped function object is not nullptr.
explicit operator bool() const noexcept
{
return *reinterpret_cast<const uintptr_t*>(std::addressof(m_storage)) != 0;
}
private:
//! The interface to be implemented by FunctorRefThrowWrapper<T>.
struct IFunctorRefThrow
{
virtual TResult Invoke(TArgs&&...) const = 0;
};
//! The interface to be implemented by FunctorRefThrowWrapper<T>.
struct IFunctorRefThrow
{
virtual TResult Invoke(TArgs&&...) const = 0;
};
//! A wrapper for a function object reference.
//! We do not call destructor for this class because it does not need to free any resources.
template <typename T>
struct FunctorRefThrowWrapper final : IFunctorRefThrow
{
FunctorRefThrowWrapper(T* func) noexcept : m_func(func) {}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(FunctorRefThrowWrapper);
~FunctorRefThrowWrapper() = delete;
//! A wrapper for a function object reference.
//! We do not call destructor for this class because it does not need to free any resources.
template <typename T>
struct FunctorRefThrowWrapper final : IFunctorRefThrow
{
FunctorRefThrowWrapper(T* func) noexcept : m_func(func) {}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(FunctorRefThrowWrapper);
~FunctorRefThrowWrapper() = delete;
TResult Invoke(TArgs&&... args) const override
{
OACR_POSSIBLE_THROW;
// We use const_cast to enable support for mutable lambdas
return (*const_cast<FunctorRefThrowWrapper*>(this)->m_func)(std::forward<TArgs>(args)...);
}
TResult Invoke(TArgs&&... args) const override
{
OACR_POSSIBLE_THROW;
// We use const_cast to enable support for mutable lambdas
return (*const_cast<FunctorRefThrowWrapper*>(this)->m_func)(std::forward<TArgs>(args)...);
}
private:
T* m_func;
};
private:
T* m_func;
};
private:
// Storage for 2 pointers: v_table + reference
Details::FunctorRefStorage m_storage { 0 };
// Storage for 2 pointers: v_table + reference
Details::FunctorRefStorage m_storage{0};
};
/// Aliases for the most common function object type "void()".
using VoidFunctorRef = FunctorRef<void()>;
using VoidFunctorRefThrow = FunctorRefThrow<void()>;
}
} // namespace Mso
#pragma pop_macro("new")

Просмотреть файл

@ -16,353 +16,370 @@ Unit tests for classes in the Functor.h
namespace {
struct MyParam
{
void AddRef() const { ++AddRefCount; }
void Release() const { UNREFERENCED_OACR(this); /* Do not decrement */ }
mutable int AddRefCount = 0; // AddRef() call count
int Value;
void AddRef() const
{
++AddRefCount;
}
void Release() const
{
UNREFERENCED_OACR(this); /* Do not decrement */
}
mutable int AddRefCount = 0; // AddRef() call count
int Value;
};
}
} // namespace
struct TestClass
{
static void Execute(const Mso::VoidFunctorRef& func) noexcept
{
func();
}
static void Execute(const Mso::VoidFunctorRef& func) noexcept
{
func();
}
static void ExecuteThrow(const Mso::VoidFunctorRefThrow& func)
{
func();
}
static void ExecuteThrow(const Mso::VoidFunctorRefThrow& func)
{
func();
}
static void ExecuteNullable(const Mso::VoidFunctorRef& func) noexcept
{
if (func)
{
func();
}
}
static void ExecuteNullable(const Mso::VoidFunctorRef& func) noexcept
{
if (func)
{
func();
}
}
static void ExecuteNullableThrow(const Mso::VoidFunctorRefThrow& func)
{
if (func)
{
func();
}
}
static void ExecuteNullableThrow(const Mso::VoidFunctorRefThrow& func)
{
if (func)
{
func();
}
}
static int Aggregate(int x, int y, const Mso::FunctorRef<int(int, int)>& func) noexcept
{
return func(x, y);
}
static int Aggregate(int x, int y, const Mso::FunctorRef<int(int, int)>& func) noexcept
{
return func(x, y);
}
static int AggregateThrow(int x, int y, const Mso::FunctorRefThrow<int(int, int)>& func)
{
return func(x, y);
}
static int AggregateThrow(int x, int y, const Mso::FunctorRefThrow<int(int, int)>& func)
{
return func(x, y);
}
static int PassByRef(const Mso::TCntPtr<MyParam>& p, const Mso::FunctorRef<int(const Mso::TCntPtr<MyParam>&)>& func) noexcept
{
return func(p);
}
static int PassByRef(
const Mso::TCntPtr<MyParam>& p,
const Mso::FunctorRef<int(const Mso::TCntPtr<MyParam>&)>& func) noexcept
{
return func(p);
}
static int PassByRefThrow(const Mso::TCntPtr<MyParam>& p, const Mso::FunctorRefThrow<int(const Mso::TCntPtr<MyParam>&)>& func)
{
return func(p);
}
static int PassByRefThrow(
const Mso::TCntPtr<MyParam>& p,
const Mso::FunctorRefThrow<int(const Mso::TCntPtr<MyParam>&)>& func)
{
return func(p);
}
static Mso::TCntPtr<MyParam> PassAsRValue(Mso::TCntPtr<MyParam>&& p, const Mso::FunctorRef<Mso::TCntPtr<MyParam>(Mso::TCntPtr<MyParam>&&)>& func) noexcept
{
return func(std::move(p));
}
static Mso::TCntPtr<MyParam> PassAsRValue(
Mso::TCntPtr<MyParam>&& p,
const Mso::FunctorRef<Mso::TCntPtr<MyParam>(Mso::TCntPtr<MyParam>&&)>& func) noexcept
{
return func(std::move(p));
}
static Mso::TCntPtr<MyParam> PassAsRValueThrow(Mso::TCntPtr<MyParam>&& p, const Mso::FunctorRefThrow<Mso::TCntPtr<MyParam>(Mso::TCntPtr<MyParam>&&)>& func)
{
return func(std::move(p));
}
static Mso::TCntPtr<MyParam> PassAsRValueThrow(
Mso::TCntPtr<MyParam>&& p,
const Mso::FunctorRefThrow<Mso::TCntPtr<MyParam>(Mso::TCntPtr<MyParam>&&)>& func)
{
return func(std::move(p));
}
OACR_WARNING_PUSH
OACR_WARNING_DISABLE(BY_VALUE_TEMPLATEFORMAL_WITH_DTOR, "We want to test that we can pass by value")
OACR_WARNING_PUSH
OACR_WARNING_DISABLE(BY_VALUE_TEMPLATEFORMAL_WITH_DTOR, "We want to test that we can pass by value")
static std::unique_ptr<int> PassByValue(std::unique_ptr<int> p, const Mso::FunctorRef<std::unique_ptr<int>(std::unique_ptr<int>)>& func) noexcept
{
return func(std::move(p));
}
static std::unique_ptr<int> PassByValue(
std::unique_ptr<int> p,
const Mso::FunctorRef<std::unique_ptr<int>(std::unique_ptr<int>)>& func) noexcept
{
return func(std::move(p));
}
static std::unique_ptr<int> PassByValueThrow(std::unique_ptr<int> p, const Mso::FunctorRefThrow<std::unique_ptr<int>(std::unique_ptr<int>)>& func)
{
return func(std::move(p));
}
static std::unique_ptr<int> PassByValueThrow(
std::unique_ptr<int> p,
const Mso::FunctorRefThrow<std::unique_ptr<int>(std::unique_ptr<int>)>& func)
{
return func(std::move(p));
}
OACR_WARNING_POP
OACR_WARNING_POP
};
struct TestClassNoexcept
{
static void Execute(const Mso::FunctorRef<void() noexcept>& func) noexcept
{
func();
}
static void Execute(const Mso::FunctorRef<void() noexcept>& func) noexcept
{
func();
}
static int Aggregate(int x, int y, const Mso::FunctorRef<int(int, int) noexcept>& func) noexcept
{
return func(x, y);
}
static int Aggregate(int x, int y, const Mso::FunctorRef<int(int, int) noexcept>& func) noexcept
{
return func(x, y);
}
static int PassByRef(const Mso::TCntPtr<MyParam>& p, const Mso::FunctorRef<int(const Mso::TCntPtr<MyParam>&) noexcept>& func) noexcept
{
return func(p);
}
static int PassByRef(
const Mso::TCntPtr<MyParam>& p,
const Mso::FunctorRef<int(const Mso::TCntPtr<MyParam>&) noexcept>& func) noexcept
{
return func(p);
}
static Mso::TCntPtr<MyParam> PassAsRValue(Mso::TCntPtr<MyParam>&& p, const Mso::FunctorRef<Mso::TCntPtr<MyParam>(Mso::TCntPtr<MyParam>&&) noexcept>& func) noexcept
{
return func(std::move(p));
}
static Mso::TCntPtr<MyParam> PassAsRValue(
Mso::TCntPtr<MyParam>&& p,
const Mso::FunctorRef<Mso::TCntPtr<MyParam>(Mso::TCntPtr<MyParam>&&) noexcept>& func) noexcept
{
return func(std::move(p));
}
};
TEST_CLASS(FunctorRefTest)
TEST_CLASS (FunctorRefTest)
{
TEST_METHOD(FunctorRef_Lambda)
{
bool isCalled = false;
TestClass::Execute([&isCalled]() noexcept { isCalled = true; });
TestCheck(isCalled);
}
TEST_METHOD(FunctorRef_Lambda)
{
bool isCalled = false;
TestClass::Execute([&isCalled]() noexcept { isCalled = true; });
TestCheck(isCalled);
}
TEST_METHOD(FunctorRefThrow_Lambda)
{
bool isCalled = false;
TestClass::ExecuteThrow([&isCalled]() noexcept { isCalled = true; });
TestCheck(isCalled);
}
TEST_METHOD(FunctorRefThrow_Lambda)
{
bool isCalled = false;
TestClass::ExecuteThrow([&isCalled]() noexcept { isCalled = true; });
TestCheck(isCalled);
}
TEST_METHOD(FunctorRef_Lambda2)
{
bool isCalled = false;
auto lambda = [&isCalled]() noexcept { isCalled = true; };
TestClass::Execute(lambda);
TestCheck(isCalled);
}
TEST_METHOD(FunctorRef_Lambda2)
{
bool isCalled = false;
auto lambda = [&isCalled]() noexcept { isCalled = true; };
TestClass::Execute(lambda);
TestCheck(isCalled);
}
TEST_METHOD(FunctorRefThrow_Lambda2)
{
bool isCalled = false;
auto lambda = [&isCalled]() noexcept { isCalled = true; };
TestClass::ExecuteThrow(lambda);
TestCheck(isCalled);
}
TEST_METHOD(FunctorRefThrow_Lambda2)
{
bool isCalled = false;
auto lambda = [&isCalled]() noexcept { isCalled = true; };
TestClass::ExecuteThrow(lambda);
TestCheck(isCalled);
}
TEST_METHOD(FunctorRef_Nullable)
{
TestClass::ExecuteNullable(nullptr);
TEST_METHOD(FunctorRef_Nullable)
{
TestClass::ExecuteNullable(nullptr);
bool isCalled = false;
TestClass::ExecuteNullable([&isCalled]() noexcept { isCalled = true; });
TestCheck(isCalled);
}
bool isCalled = false;
TestClass::ExecuteNullable([&isCalled]() noexcept { isCalled = true; });
TestCheck(isCalled);
}
TEST_METHOD(FunctorRefThrow_Nullable)
{
TestClass::ExecuteNullableThrow(nullptr);
TEST_METHOD(FunctorRefThrow_Nullable)
{
TestClass::ExecuteNullableThrow(nullptr);
bool isCalled = false;
TestClass::ExecuteNullableThrow([&isCalled]() noexcept { isCalled = true; });
TestCheck(isCalled);
}
bool isCalled = false;
TestClass::ExecuteNullableThrow([&isCalled]() noexcept { isCalled = true; });
TestCheck(isCalled);
}
TESTMETHOD_REQUIRES_SEH(FunctorRef_Nullable_Crash)
{
TestCheckCrash(TestClass::Execute(nullptr));
}
TESTMETHOD_REQUIRES_SEH(FunctorRef_Nullable_Crash)
{
TestCheckCrash(TestClass::Execute(nullptr));
}
TESTMETHOD_REQUIRES_SEH(FunctorRefThrow_Nullable_Crash)
{
TestCheckCrash(TestClass::ExecuteThrow(nullptr));
}
TESTMETHOD_REQUIRES_SEH(FunctorRefThrow_Nullable_Crash)
{
TestCheckCrash(TestClass::ExecuteThrow(nullptr));
}
TEST_METHOD(FunctorRef_MsoFunctor)
{
// It can be useful in case when we have an std::function available.
bool isCalled = false;
auto func = Mso::VoidFunctor([&isCalled]() noexcept { isCalled = true; });
TestClass::Execute(func);
TestCheck(isCalled);
}
TEST_METHOD(FunctorRef_MsoFunctor)
{
// It can be useful in case when we have an std::function available.
bool isCalled = false;
auto func = Mso::VoidFunctor([&isCalled]() noexcept { isCalled = true; });
TestClass::Execute(func);
TestCheck(isCalled);
}
TEST_METHOD(FunctorRef_LambdaReturnValue)
{
int addResult = TestClass::Aggregate(3, 5, [](int x, int y) noexcept { return x + y; });
TestCheckEqual(8, addResult);
TEST_METHOD(FunctorRef_LambdaReturnValue)
{
int addResult = TestClass::Aggregate(3, 5, [](int x, int y) noexcept { return x + y; });
TestCheckEqual(8, addResult);
int multResult = TestClass::Aggregate(3, 5, [](int x, int y) noexcept { return x * y; });
TestCheckEqual(15, multResult);
}
int multResult = TestClass::Aggregate(3, 5, [](int x, int y) noexcept { return x * y; });
TestCheckEqual(15, multResult);
}
TEST_METHOD(FunctorRef_LambdaPassParamByRef)
{
// Pass an Mso::TCntPtr as an const reference and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
param.Value = 10;
TEST_METHOD(FunctorRef_LambdaPassParamByRef)
{
// Pass an Mso::TCntPtr as an const reference and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
param.Value = 10;
int result = TestClass::PassByRef(spParam, [](const Mso::TCntPtr<MyParam>& p) noexcept { return p->Value; });
TestCheckEqual(10, result);
TestCheckEqual(1, param.AddRefCount);
}
int result = TestClass::PassByRef(spParam, [](const Mso::TCntPtr<MyParam>& p) noexcept { return p->Value; });
TestCheckEqual(10, result);
TestCheckEqual(1, param.AddRefCount);
}
TEST_METHOD(FunctorRef_LambdaPassParamAsRValue)
{
// Pass an Mso::TCntPtr as an r-value and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
auto spParam2 = TestClass::PassAsRValue(std::move(spParam), [](Mso::TCntPtr<MyParam>&& p) noexcept { return std::move(p); });
TestCheckEqual(1, param.AddRefCount);
}
TEST_METHOD(FunctorRef_LambdaPassParamAsRValue)
{
// Pass an Mso::TCntPtr as an r-value and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
TEST_METHOD(FunctorRef_noexcept_Lambda)
{
bool isCalled = false;
TestClass::Execute([&isCalled]() noexcept { isCalled = true; });
TestCheck(isCalled);
}
auto spParam2 =
TestClass::PassAsRValue(std::move(spParam), [](Mso::TCntPtr<MyParam>&& p) noexcept { return std::move(p); });
TestCheckEqual(1, param.AddRefCount);
}
TEST_METHOD(FunctorRef_noexcept_MsoFunctor)
{
// It can be useful in case when we have an std::function available.
bool isCalled = false;
auto func = Mso::VoidFunctor([&isCalled]() noexcept { isCalled = true; });
TestClass::Execute(func);
TestCheck(isCalled);
}
TEST_METHOD(FunctorRef_noexcept_Lambda)
{
bool isCalled = false;
TestClass::Execute([&isCalled]() noexcept { isCalled = true; });
TestCheck(isCalled);
}
TEST_METHOD(FunctorRef_noexcept_LambdaReturnValue)
{
int addResult = TestClass::Aggregate(3, 5, [](int x, int y) noexcept { return x + y; });
TestCheckEqual(8, addResult);
TEST_METHOD(FunctorRef_noexcept_MsoFunctor)
{
// It can be useful in case when we have an std::function available.
bool isCalled = false;
auto func = Mso::VoidFunctor([&isCalled]() noexcept { isCalled = true; });
TestClass::Execute(func);
TestCheck(isCalled);
}
int multResult = TestClass::Aggregate(3, 5, [](int x, int y) noexcept { return x * y; });
TestCheckEqual(15, multResult);
}
TEST_METHOD(FunctorRef_noexcept_LambdaReturnValue)
{
int addResult = TestClass::Aggregate(3, 5, [](int x, int y) noexcept { return x + y; });
TestCheckEqual(8, addResult);
TEST_METHOD(FunctorRef_noexcept_LambdaPassParamByRef)
{
// Pass an Mso::TCntPtr as an const reference and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
param.Value = 10;
int multResult = TestClass::Aggregate(3, 5, [](int x, int y) noexcept { return x * y; });
TestCheckEqual(15, multResult);
}
int result = TestClass::PassByRef(spParam, [](const Mso::TCntPtr<MyParam>& p) noexcept { return p->Value; });
TestCheckEqual(10, result);
TestCheckEqual(1, param.AddRefCount);
}
TEST_METHOD(FunctorRef_noexcept_LambdaPassParamByRef)
{
// Pass an Mso::TCntPtr as an const reference and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
param.Value = 10;
TEST_METHOD(FunctorRef_noexcept_LambdaPassParamAsRValue)
{
// Pass an Mso::TCntPtr as an r-value and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
int result = TestClass::PassByRef(spParam, [](const Mso::TCntPtr<MyParam>& p) noexcept { return p->Value; });
TestCheckEqual(10, result);
TestCheckEqual(1, param.AddRefCount);
}
auto spParam2 = TestClass::PassAsRValue(std::move(spParam), [](Mso::TCntPtr<MyParam>&& p) noexcept { return std::move(p); });
TestCheckEqual(1, param.AddRefCount);
}
TEST_METHOD(FunctorRef_noexcept_LambdaPassParamAsRValue)
{
// Pass an Mso::TCntPtr as an r-value and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
TEST_METHOD(FunctorRefThrow_StdFunction)
{
// We use the std::function as an example of throwing function object.
bool isCalled = false;
TestClass::ExecuteThrow(std::function<void()>([&isCalled]() noexcept { isCalled = true; }));
TestCheck(isCalled);
}
auto spParam2 =
TestClass::PassAsRValue(std::move(spParam), [](Mso::TCntPtr<MyParam>&& p) noexcept { return std::move(p); });
TestCheckEqual(1, param.AddRefCount);
}
TEST_METHOD(FunctorRefThrow_LambdaReturnValue)
{
int addResult = TestClass::AggregateThrow(3, 5, std::function<int(int, int)>([](int x, int y) noexcept { return x + y; }));
TestCheckEqual(8, addResult);
TEST_METHOD(FunctorRefThrow_StdFunction)
{
// We use the std::function as an example of throwing function object.
bool isCalled = false;
TestClass::ExecuteThrow(std::function<void()>([&isCalled]() noexcept { isCalled = true; }));
TestCheck(isCalled);
}
int multResult = TestClass::AggregateThrow(3, 5, std::function<int(int, int)>([](int x, int y) noexcept{ return x * y; }));
TestCheckEqual(15, multResult);
}
TEST_METHOD(FunctorRefThrow_LambdaReturnValue)
{
int addResult =
TestClass::AggregateThrow(3, 5, std::function<int(int, int)>([](int x, int y) noexcept { return x + y; }));
TestCheckEqual(8, addResult);
TEST_METHOD(FunctorRefThrow_LambdaPassParamByRef)
{
// Pass an Mso::TCntPtr as an const reference and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
param.Value = 10;
int multResult =
TestClass::AggregateThrow(3, 5, std::function<int(int, int)>([](int x, int y) noexcept { return x * y; }));
TestCheckEqual(15, multResult);
}
using Function = std::function<int(const Mso::TCntPtr<MyParam>&)>;
int result = TestClass::PassByRefThrow(spParam, Function([](const Mso::TCntPtr<MyParam>& p) noexcept { return p->Value; }));
TestCheckEqual(10, result);
TestCheckEqual(1, param.AddRefCount);
}
TEST_METHOD(FunctorRefThrow_LambdaPassParamByRef)
{
// Pass an Mso::TCntPtr as an const reference and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
param.Value = 10;
TEST_METHOD(FunctorRefThrow_LambdaPassParamAsRValue)
{
// Pass an Mso::TCntPtr as an r-value and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
using Function = std::function<int(const Mso::TCntPtr<MyParam>&)>;
int result =
TestClass::PassByRefThrow(spParam, Function([](const Mso::TCntPtr<MyParam>& p) noexcept { return p->Value; }));
TestCheckEqual(10, result);
TestCheckEqual(1, param.AddRefCount);
}
using Function = std::function<Mso::TCntPtr<MyParam>(Mso::TCntPtr<MyParam>&&)>;
auto spParam2 = TestClass::PassAsRValueThrow(std::move(spParam), Function([](Mso::TCntPtr<MyParam>&& p) noexcept { return std::move(p); }));
TestCheckEqual(1, param.AddRefCount);
}
TEST_METHOD(FunctorRefThrow_LambdaPassParamAsRValue)
{
// Pass an Mso::TCntPtr as an r-value and see that it was never called AddRef()
MyParam param;
auto spParam = Mso::TCntPtr<MyParam>(&param);
TestCheckEqual(1, param.AddRefCount);
TEST_METHOD(FunctorRef_MutableLambda)
{
std::unique_ptr<bool> isCalled { nullptr };
auto mutableValue = std::make_unique<bool>(true);
using Function = std::function<Mso::TCntPtr<MyParam>(Mso::TCntPtr<MyParam> &&)>;
auto spParam2 = TestClass::PassAsRValueThrow(
std::move(spParam), Function([](Mso::TCntPtr<MyParam>&& p) noexcept { return std::move(p); }));
TestCheckEqual(1, param.AddRefCount);
}
TestClass::Execute([&isCalled, mutableValue = std::move(mutableValue)]() mutable noexcept
{
isCalled = std::move(mutableValue);
});
TEST_METHOD(FunctorRef_MutableLambda)
{
std::unique_ptr<bool> isCalled{nullptr};
auto mutableValue = std::make_unique<bool>(true);
TestCheck(*isCalled);
}
TestClass::Execute(
[&isCalled, mutableValue = std::move(mutableValue)]() mutable noexcept { isCalled = std::move(mutableValue); });
TEST_METHOD(FunctorRefThrow_MutableLambda)
{
std::unique_ptr<bool> isCalled { nullptr };
auto mutableValue = std::make_unique<bool>(true);
TestCheck(*isCalled);
}
TestClass::ExecuteThrow([&isCalled, mutableValue = std::move(mutableValue)]() mutable noexcept
{
isCalled = std::move(mutableValue);
});
TEST_METHOD(FunctorRefThrow_MutableLambda)
{
std::unique_ptr<bool> isCalled{nullptr};
auto mutableValue = std::make_unique<bool>(true);
TestCheck(*isCalled);
}
TestClass::ExecuteThrow(
[&isCalled, mutableValue = std::move(mutableValue)]() mutable noexcept { isCalled = std::move(mutableValue); });
OACR_WARNING_PUSH
OACR_WARNING_DISABLE(BY_VALUE_TEMPLATEFORMAL_WITH_DTOR, "We want to test that we can pass by value")
TestCheck(*isCalled);
}
TEST_METHOD(FunctorRef_LambdaPassParamByValue)
{
auto inValue = std::make_unique<int>(5);
auto result = TestClass::PassByValue(std::move(inValue), [](std::unique_ptr<int> p) noexcept
{
return p;
});
TestCheckEqual(5, *result);
}
OACR_WARNING_PUSH
OACR_WARNING_DISABLE(BY_VALUE_TEMPLATEFORMAL_WITH_DTOR, "We want to test that we can pass by value")
TEST_METHOD(FunctorRefThrow_LambdaPassParamByValue)
{
auto inValue = std::make_unique<int>(5);
auto result = TestClass::PassByValueThrow(std::move(inValue), [](std::unique_ptr<int> p) noexcept
{
return p;
});
TestCheckEqual(5, *result);
}
TEST_METHOD(FunctorRef_LambdaPassParamByValue)
{
auto inValue = std::make_unique<int>(5);
auto result = TestClass::PassByValue(std::move(inValue), [](std::unique_ptr<int> p) noexcept { return p; });
TestCheckEqual(5, *result);
}
OACR_WARNING_POP
TEST_METHOD(FunctorRefThrow_LambdaPassParamByValue)
{
auto inValue = std::make_unique<int>(5);
auto result = TestClass::PassByValueThrow(std::move(inValue), [](std::unique_ptr<int> p) noexcept { return p; });
TestCheckEqual(5, *result);
}
OACR_WARNING_POP
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -9,79 +9,87 @@ Common code for functor (Functor, SmallFunctor) unit tests.
namespace FunctorTestsCommon {
class TestData
: public Mso::RefCountedObjectNoVTable<TestData>
class TestData : public Mso::RefCountedObjectNoVTable<TestData>
{
using Super = Mso::RefCountedObjectNoVTable<TestData>;
using Super = Mso::RefCountedObjectNoVTable<TestData>;
public:
TestData(int& addRefCalls, int& releaseCalls) noexcept
: m_addRefCalls(addRefCalls)
, m_releaseCalls(releaseCalls)
, Value(0)
{
}
TestData(int& addRefCalls, int& releaseCalls) noexcept
: m_addRefCalls(addRefCalls), m_releaseCalls(releaseCalls), Value(0)
{
}
void AddRef() const
{
++m_addRefCalls;
Super::AddRef();
}
void AddRef() const
{
++m_addRefCalls;
Super::AddRef();
}
void Release() const
{
++m_releaseCalls;
Super::Release();
}
void Release() const
{
++m_releaseCalls;
Super::Release();
}
int Value;
int Value;
private:
int& m_addRefCalls;
int& m_releaseCalls;
int& m_addRefCalls;
int& m_releaseCalls;
};
struct StaticMethod
{
static int Add(int x, int y) noexcept
{
return x + y;
}
static int Add(int x, int y) noexcept
{
return x + y;
}
OACR_WARNING_PUSH
OACR_WARNING_DISABLE(FUNC_COULD_BE_NOEXCEPT, "Simple non-nonexcept function for use in unit tests")
static int AddThrow(int x, int y)
{
return x + y;
}
OACR_WARNING_POP
OACR_WARNING_PUSH
OACR_WARNING_DISABLE(FUNC_COULD_BE_NOEXCEPT, "Simple non-nonexcept function for use in unit tests")
static int AddThrow(int x, int y)
{
return x + y;
}
OACR_WARNING_POP
};
struct StructParam
{
void AddRef() const { UNREFERENCED_OACR(this); }
void Release() const { UNREFERENCED_OACR(this); }
void AddRef() const
{
UNREFERENCED_OACR(this);
}
void Release() const
{
UNREFERENCED_OACR(this);
}
};
struct BaseClass
{
virtual int GetInt() noexcept { return 0; }
virtual int GetInt() noexcept
{
return 0;
}
};
struct Derived final
: public BaseClass
struct Derived final : public BaseClass
{
int i;
int i;
int GetInt() noexcept override { return i; }
int GetInt() noexcept override
{
return i;
}
};
static Derived& DerivedFromBaseClass(BaseClass& baseClass) noexcept
{
static Derived derived;
static Derived derived;
derived.i = baseClass.GetInt();
return derived;
derived.i = baseClass.GetInt();
return derived;
}
} // namespace FunctorTestsCommon

Просмотреть файл

@ -21,7 +21,7 @@ See MsoMemory.h for information about operator new.
#ifndef MsoSetLazyLeakDetection
#ifdef DEBUG
LIBLET_PUBLICAPI_EX("android", "win") MSOAPI_(void) MsoSetLazyLeakDetection(const void* pv) noexcept;
#else
#else
#define MsoSetLazyLeakDetection(pv) 0
#endif // DEBUG
#endif // !MsoSetLazyLeakDetection
@ -29,89 +29,87 @@ LIBLET_PUBLICAPI_EX("android", "win") MSOAPI_(void) MsoSetLazyLeakDetection(cons
#ifndef MsoSetShutdownLeakDetection
#ifdef DEBUG
LIBLET_PUBLICAPI_EX("android", "win") MSOAPI_(void) MsoSetShutdownLeakDetection(const void* pv) noexcept;
#else
#else
#define MsoSetShutdownLeakDetection(pv) 0
#endif // DEBUG
#endif // !MsoSetShutdownLeakDetection
#ifdef __cplusplus
namespace Mso {
namespace LibletAPI {
struct ILibletMemoryMarking
{
virtual void MarkLiblets(intptr_t lParam) noexcept = 0;
};
}
}
namespace Mso { namespace LibletAPI {
struct ILibletMemoryMarking
{
virtual void MarkLiblets(intptr_t lParam) noexcept = 0;
};
}} // namespace Mso::LibletAPI
#ifdef DEBUG
struct IMsoMemHeap;
LIBLET_PUBLICAPI_EX("android", "win") MSOAPI_(BOOL) FMemHeapMsoSaveBeHost(void* pinst, LPARAM lParam, const void* pvBlock, LONG_PTR cb, IMsoMemHeap* pmmh) MSONOEXCEPT;
LIBLET_PUBLICAPI_EX("android", "win")
MSOAPI_(BOOL)
FMemHeapMsoSaveBeHost(void* pinst, LPARAM lParam, const void* pvBlock, LONG_PTR cb, IMsoMemHeap* pmmh) MSONOEXCEPT;
LIBLET_PUBLICAPI_EX("android", "win") MSOAPI_(void) MsoCheckShutdownLeaks() noexcept;
LIBLET_PUBLICAPI_EX("win") MSOAPI_(void) HeapEnableLeakTracking(bool isEnabled);
LIBLET_PUBLICAPI_EX("win") MSOAPI_(void) MsoBeforeThreadTerminatesThreaded(DWORD mainThreadId) noexcept;
#endif
LIBLET_PUBLICAPI_EX("android", "win") __declspec(noreturn) void ThrowOOM();
namespace Mso {
namespace Memory {
namespace Mso { namespace Memory {
#ifdef DEBUG
LIBLET_PUBLICAPI_EX("android", "win") MSOCPPAPI_(void) RegisterCallback(Mso::LibletAPI::ILibletMemoryMarking& libletCallback) noexcept;
LIBLET_PUBLICAPI_EX("android", "win") MSOCPPAPI_(void) UnregisterCallback(Mso::LibletAPI::ILibletMemoryMarking& libletCallback) noexcept;
LIBLET_PUBLICAPI_EX("android", "win")
MSOCPPAPI_(void) RegisterCallback(Mso::LibletAPI::ILibletMemoryMarking& libletCallback) noexcept;
LIBLET_PUBLICAPI_EX("android", "win")
MSOCPPAPI_(void) UnregisterCallback(Mso::LibletAPI::ILibletMemoryMarking& libletCallback) noexcept;
/**
Helper class to register arbitrary callback for memory marking
*/
struct RegisterMarkMemoryCallback : public Mso::LibletAPI::ILibletMemoryMarking
{
using MarkMemHandler = std::add_pointer_t<void(intptr_t) noexcept>;
/**
Helper class to register arbitrary callback for memory marking
*/
struct RegisterMarkMemoryCallback : public Mso::LibletAPI::ILibletMemoryMarking
{
using MarkMemHandler = std::add_pointer_t<void(intptr_t) noexcept>;
DECLARE_COPYCONSTR_AND_ASSIGNMENT(RegisterMarkMemoryCallback);
RegisterMarkMemoryCallback(MarkMemHandler handler) noexcept
: m_handler(handler)
{
RegisterCallback(*this);
}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(RegisterMarkMemoryCallback);
RegisterMarkMemoryCallback(MarkMemHandler handler) noexcept : m_handler(handler)
{
RegisterCallback(*this);
}
virtual ~RegisterMarkMemoryCallback() noexcept
{
UnregisterCallback(*this);
}
virtual ~RegisterMarkMemoryCallback() noexcept
{
UnregisterCallback(*this);
}
void MarkLiblets(intptr_t lParam) noexcept override
{
m_handler(lParam);
}
void MarkLiblets(intptr_t lParam) noexcept override
{
m_handler(lParam);
}
private:
MarkMemHandler m_handler;
};
private:
MarkMemHandler m_handler;
};
#endif
}
}
}} // namespace Mso::Memory
#ifdef DEBUG
namespace Mso {
namespace Memory {
// Legacy API
inline _Ret_notnull_ _Post_writable_byte_size_(cb) void* Allocate(size_t cb FILELINEPARAMSUNUSED) noexcept
{
return AllocateEx(cb, 0);
}
// Legacy API
inline _Ret_maybenull_ _Post_writable_byte_size_(cb) void* AllocateEx(size_t cb, DWORD allocFlags FILELINEPARAMSUNUSED) noexcept
{
return AllocateEx(cb, allocFlags);
}
// Legacy API
inline _Ret_maybenull_ void* Reallocate(_Inout_ void** ppv, size_t cb FILELINEPARAMSUNUSED) noexcept
{
return Reallocate(ppv, cb);
}
}
namespace Mso { namespace Memory {
// Legacy API
inline _Ret_notnull_ _Post_writable_byte_size_(cb) void* Allocate(size_t cb FILELINEPARAMSUNUSED) noexcept
{
return AllocateEx(cb, 0);
}
// Legacy API
inline _Ret_maybenull_ _Post_writable_byte_size_(
cb) void* AllocateEx(size_t cb, DWORD allocFlags FILELINEPARAMSUNUSED) noexcept
{
return AllocateEx(cb, allocFlags);
}
// Legacy API
inline _Ret_maybenull_ void* Reallocate(_Inout_ void** ppv, size_t cb FILELINEPARAMSUNUSED) noexcept
{
return Reallocate(ppv, cb);
}
}} // namespace Mso::Memory
#endif
#endif

Просмотреть файл

@ -2,20 +2,20 @@
// Licensed under the MIT license.
/**
Deprecated APIs related to leak detection
Deprecated APIs related to leak detection
*/
#pragma once
#include <memoryLeakScope/memoryLeakScope.h>
/**
When this object is active, allocations on this thread are marked as
needing to be cleaned up by shutdown.
When this object is active, allocations on this thread are marked as
needing to be cleaned up by shutdown.
*/
using MsoDebugShutdownLazyScope = Mso::Memory::AutoShutdownLeakScope;
/**
When this object is active, allocations on this thread are not tracked
for leak detection. Typically used when the memory lifetime is the life of
the DLL or is managed by an external dependency.
When this object is active, allocations on this thread are not tracked
for leak detection. Typically used when the memory lifetime is the life of
the DLL or is managed by an external dependency.
*/
using MsoDebugLazyScope = Mso::Memory::AutoIgnoreLeakScope;

Просмотреть файл

@ -28,421 +28,421 @@ See MsoMemory.h for information about operator new.
#undef New
#include <memory>
namespace Mso {
namespace Memory {
namespace Details {
template <typename T>
struct Emplacer
{
template <typename... Args>
static void Place(_Inout_updates_bytes_all_(sizeof(T)) void* mem, Args&&... args) noexcept
{
new (mem) T(std::forward<Args>(args)...);
}
};
namespace Mso { namespace Memory {
namespace Details {
template <typename T>
struct Emplacer
{
template <typename... Args>
static void Place(_Inout_updates_bytes_all_(sizeof(T)) void* mem, Args&&... args) noexcept
{
new (mem) T(std::forward<Args>(args)...);
}
};
template <typename T, size_t N>
struct Emplacer < T[N] >
{
template <typename... Args>
static void Place(void* mem, Args&&... args)
{
new (mem) T[N]
{
std::forward<Args>(args)...
};
}
};
template <typename T, size_t N>
struct Emplacer<T[N]>
{
template <typename... Args>
static void Place(void* mem, Args&&... args)
{
new (mem) T[N]{std::forward<Args>(args)...};
}
};
template <typename T, typename Enable = void>
struct Destructor
{
static void Destruct(T&) noexcept { /* noop */ }
};
template <typename T, typename Enable = void>
struct Destructor
{
static void Destruct(T&) noexcept
{ /* noop */
}
};
template <typename T>
struct Destructor < T,
typename std::enable_if<std::is_destructible<T>::value && !std::is_pod<T>::value>::type >
{
static void Destruct(T& obj) noexcept
{
UNREFERENCED_PARAMETER(obj);
obj.~T();
}
};
} // Details
/**
Mso::Memory::AllocFlags
*/
namespace AllocFlags {
enum Enum : unsigned int
{
// check this memory during shutdown leak detection
ShutdownLeak = 0x0001,
// ignore this memory during leak detection
IgnoreLeak = 0x0002,
// track this memory using memory marking / idle time leak detection
MarkingLeak = 0x0004,
};
};
/**
Return a new allocation of the requested size (cb)
Returns nullptr on failure
*/
LIBLET_PUBLICAPI_EX("win", "android") _Ret_maybenull_ _Post_writable_byte_size_(cb) void* AllocateEx(size_t cb, DWORD allocFlags) noexcept;
/**
Return a new allocation of the requested size (cb)
Returns nullptr on failure
*/
inline _Ret_maybenull_ _Post_writable_byte_size_(cb) void* Allocate(size_t cb) noexcept
{
return Mso::Memory::AllocateEx(cb, 0);
}
/**
Reallocate an existing allocation to a new size
Returns nullptr on failure
TODO: Do we need ReallocateEx? Only if allocFlags grows.
*/
LIBLET_PUBLICAPI_EX("win", "android") _Ret_maybenull_ void* Reallocate(_Inout_ void** ppv, size_t cb) noexcept;
template<typename T>
_Ret_maybenull_ T* Reallocate(T* pT, size_t cb) noexcept
{
return reinterpret_cast<T*>(Reallocate(reinterpret_cast<void**>(&pT), cb));
}
/**
Return the allocation size of a given pointer
*/
LIBLET_PUBLICAPI_EX("win", "android") size_t AllocationSize(_In_opt_ const void* pv) noexcept;
/**
Release a previously allocated block of memory
*/
LIBLET_PUBLICAPI_EX("win", "android") void Free(_Pre_maybenull_ _Post_invalid_ void* pv) noexcept;
/**
Disambiguator used to ensure a throwing new
new (Mso::Memory::throwNew) Zoo();
*/
OACR_WARNING_SUPPRESS(SPECIFY_SELECTANY, "Not needed for marker type")
static const struct throwNew_t
{
throwNew_t() noexcept = default;
} throwNew;
/**
Disambiguator used to ensure a crashing new
new (Mso::Memory::failFast) Zoo();
*/
OACR_WARNING_SUPPRESS(SPECIFY_SELECTANY, "Not needed for marker type")
static const struct failFast_t
{
failFast_t() noexcept = default;
} failFast;
/**
Construct a object of type `T` stored at `mem`.
Arguments are forwarded to constructor of `T`.
*/
template <typename T, typename... Args>
static void Place(__inout_bcount(sizeof(T)) void* mem, Args&&... args)
{
Details::Emplacer<T>::Place(mem, std::forward<Args>(args)...);
}
/**
Manually destruct an object of type `T`.
*/
template <typename T,
typename = typename std::enable_if<!std::is_array<T>::value>::type>
static void Destruct(T& obj) noexcept
{
Details::Destructor<T>::Destruct(obj);
}
/**
Manually destruct a `T[N]`.
Destructs contents of the array in reverse order.
*/
template <typename T, size_t N>
static void Destruct(T(&obj)[N]) noexcept
{
size_t i = N;
while (i--)
Destruct(obj[i]);
}
} // Memory
} // Mso
namespace Mso {
namespace Memory {
namespace FailFast {
/**
Return a new allocation of the requested size (cb)
Never returns nullptr
*/
_Ret_maybenull_ _Post_writable_byte_size_(cb) inline void* AllocateEx(size_t cb, DWORD allocFlags) noexcept
{
auto pv = Mso::Memory::AllocateEx(cb, allocFlags);
if (pv == nullptr)
CrashWithRecoveryOnOOM();
return pv;
}
_Ret_maybenull_ _Post_writable_byte_size_(cb) inline void* Allocate(size_t cb) noexcept
{
return AllocateEx(cb, 0);
}
} // FailFast
} // Memory
} // Mso
namespace Mso {
namespace Memory {
namespace NoThrow {
template <typename T>
struct Destructor<T, typename std::enable_if<std::is_destructible<T>::value && !std::is_pod<T>::value>::type>
{
static void Destruct(T& obj) noexcept
{
UNREFERENCED_PARAMETER(obj);
obj.~T();
}
};
} // namespace Details
/**
non-throwing operator new using memory-marking leak detection
new (Mso::Memory::NoThrow::MarkingLeak) Zoo();
Mso::Memory::AllocFlags
*/
namespace AllocFlags {
enum Enum : unsigned int
{
// check this memory during shutdown leak detection
ShutdownLeak = 0x0001,
// ignore this memory during leak detection
IgnoreLeak = 0x0002,
// track this memory using memory marking / idle time leak detection
MarkingLeak = 0x0004,
};
};
/**
Return a new allocation of the requested size (cb)
Returns nullptr on failure
*/
LIBLET_PUBLICAPI_EX("win", "android")
_Ret_maybenull_ _Post_writable_byte_size_(cb) void* AllocateEx(size_t cb, DWORD allocFlags) noexcept;
/**
Return a new allocation of the requested size (cb)
Returns nullptr on failure
*/
inline _Ret_maybenull_ _Post_writable_byte_size_(cb) void* Allocate(size_t cb) noexcept
{
return Mso::Memory::AllocateEx(cb, 0);
}
/**
Reallocate an existing allocation to a new size
Returns nullptr on failure
TODO: Do we need ReallocateEx? Only if allocFlags grows.
*/
LIBLET_PUBLICAPI_EX("win", "android") _Ret_maybenull_ void* Reallocate(_Inout_ void** ppv, size_t cb) noexcept;
template <typename T>
_Ret_maybenull_ T* Reallocate(T* pT, size_t cb) noexcept
{
return reinterpret_cast<T*>(Reallocate(reinterpret_cast<void**>(&pT), cb));
}
/**
Return the allocation size of a given pointer
*/
LIBLET_PUBLICAPI_EX("win", "android") size_t AllocationSize(_In_opt_ const void* pv) noexcept;
/**
Release a previously allocated block of memory
*/
LIBLET_PUBLICAPI_EX("win", "android") void Free(_Pre_maybenull_ _Post_invalid_ void* pv) noexcept;
/**
Disambiguator used to ensure a throwing new
new (Mso::Memory::throwNew) Zoo();
*/
OACR_WARNING_SUPPRESS(SPECIFY_SELECTANY, "Not needed for marker type")
static const struct throwNew_t
{
throwNew_t() noexcept = default;
} throwNew;
/**
Disambiguator used to ensure a crashing new
new (Mso::Memory::failFast) Zoo();
*/
OACR_WARNING_SUPPRESS(SPECIFY_SELECTANY, "Not needed for marker type")
static const struct failFast_t
{
failFast_t() noexcept = default;
} failFast;
/**
Construct a object of type `T` stored at `mem`.
Arguments are forwarded to constructor of `T`.
*/
template <typename T, typename... Args>
static void Place(__inout_bcount(sizeof(T)) void* mem, Args&&... args)
{
Details::Emplacer<T>::Place(mem, std::forward<Args>(args)...);
}
/**
Manually destruct an object of type `T`.
*/
template <typename T, typename = typename std::enable_if<!std::is_array<T>::value>::type>
static void Destruct(T& obj) noexcept
{
Details::Destructor<T>::Destruct(obj);
}
/**
Manually destruct a `T[N]`.
Destructs contents of the array in reverse order.
*/
template <typename T, size_t N>
static void Destruct(T (&obj)[N]) noexcept
{
size_t i = N;
while (i--)
Destruct(obj[i]);
}
}} // namespace Mso::Memory
namespace Mso { namespace Memory { namespace FailFast {
/**
Return a new allocation of the requested size (cb)
Never returns nullptr
*/
_Ret_maybenull_ _Post_writable_byte_size_(cb) inline void* AllocateEx(size_t cb, DWORD allocFlags) noexcept
{
auto pv = Mso::Memory::AllocateEx(cb, allocFlags);
if (pv == nullptr)
CrashWithRecoveryOnOOM();
return pv;
}
_Ret_maybenull_ _Post_writable_byte_size_(cb) inline void* Allocate(size_t cb) noexcept
{
return AllocateEx(cb, 0);
}
}}} // namespace Mso::Memory::FailFast
namespace Mso { namespace Memory { namespace NoThrow {
/**
non-throwing operator new using memory-marking leak detection
new (Mso::Memory::NoThrow::MarkingLeak) Zoo();
*/
OACR_WARNING_SUPPRESS(SPECIFY_SELECTANY, "Not needed for marker type")
static const struct MarkingLeak_t
{
MarkingLeak_t() noexcept = default;
MarkingLeak_t() noexcept = default;
} MarkingLeak;
} // NoThrow
} // Memory
} // Mso
}}} // namespace Mso::Memory::NoThrow
namespace Mso {
namespace Memory {
namespace Throw {
namespace Mso { namespace Memory { namespace Throw {
#pragma warning(push)
#pragma warning(disable:4100)
/**
Mso::Memory::Throw::New<T>(args)
#pragma warning(disable : 4100)
/**
Mso::Memory::Throw::New<T>(args)
Allocates object T by passing args to its constructor.
*/
template <typename T, typename ...TArgs>
OACR_WARNING_SUPPRESS( NULL_ON_NON_POINTER, "false positive" )
_Ret_notnull_ T* New(TArgs&&... t)
{
Debug(Mso::Memory::AutoShutdownLeakScope scope);
T* pT = new(std::nothrow) T(std::forward<TArgs>(t)...);
if (pT == nullptr)
throw std::bad_alloc();
return pT;
}
Allocates object T by passing args to its constructor.
*/
template <typename T, typename... TArgs>
OACR_WARNING_SUPPRESS(NULL_ON_NON_POINTER, "false positive")
_Ret_notnull_ T* New(TArgs&&... t)
{
Debug(Mso::Memory::AutoShutdownLeakScope scope);
T* pT = new (std::nothrow) T(std::forward<TArgs>(t)...);
if (pT == nullptr)
throw std::bad_alloc();
return pT;
}
#pragma warning(pop)
} // Throw
} // Memory
} // Mso
}}} // namespace Mso::Memory::Throw
namespace Mso {
/**
Frees memory allocated by Mso::Memory
*/
template< typename T > struct MemoryPtrHelper
{
static void Free(T* pT) noexcept { Mso::Memory::Free(pT); }
};
/**
Frees memory allocated by Mso::Memory
*/
template <typename T>
struct MemoryPtrHelper
{
static void Free(T* pT) noexcept
{
Mso::Memory::Free(pT);
}
};
/**
Mso::MemoryPtr
/**
Mso::MemoryPtr
Smart pointer for memory allocated by Mso::Memory.
Suitable for raw memory or vanilla structs.
Does not run copy constructors or destructors.
Smart pointer for memory allocated by Mso::Memory.
Suitable for raw memory or vanilla structs.
Does not run copy constructors or destructors.
The equals operator is purposely left out. Use the c'tor or Attach().
The equals operator is purposely left out. Use the c'tor or Attach().
Mso::MemoryPtr<BYTE> pFoo; // equivalent to BYTE* pFoo;
*/
template< typename T, DWORD allocFlags = 0 > class MemoryPtr : public Mso::THolder< T*, MemoryPtrHelper< T > >
{
typedef Mso::THolder< T*, MemoryPtrHelper< T > > Super;
Mso::MemoryPtr<BYTE> pFoo; // equivalent to BYTE* pFoo;
*/
template <typename T, DWORD allocFlags = 0>
class MemoryPtr : public Mso::THolder<T*, MemoryPtrHelper<T>>
{
typedef Mso::THolder<T*, MemoryPtrHelper<T>> Super;
public:
MemoryPtr() noexcept {}
explicit MemoryPtr(_In_opt_ T* pT) noexcept { this->Attach(pT); } // Takes ownership
IMPLEMENT_THOLDER_RVALUE_REFS_(MemoryPtr, Super);
public:
MemoryPtr() noexcept {}
explicit MemoryPtr(_In_opt_ T* pT) noexcept
{
this->Attach(pT);
} // Takes ownership
IMPLEMENT_THOLDER_RVALUE_REFS_(MemoryPtr, Super);
/**
AllocBytes
/**
AllocBytes
Allocate space for the given number of bytes.
On success, any previously held data is replaced.
Returns false on OOM / overflow.
Allocate space for the given number of bytes.
On success, any previously held data is replaced.
Returns false on OOM / overflow.
AllocElem-variants are strongly preferred to avoid integer overflows.
AllocElem-variants are strongly preferred to avoid integer overflows.
Mso::MemoryPtr<BYTE> pbFoo;
if (pbFoo.AllocBytes(cbData)) { ... }
*/
bool AllocBytes(size_t cb) noexcept
{
T* pT = static_cast<T*>(Mso::Memory::AllocateEx(cb, allocFlags));
if (pT != nullptr)
this->Attach(pT);
return (pT != nullptr);
}
Mso::MemoryPtr<BYTE> pbFoo;
if (pbFoo.AllocBytes(cbData)) { ... }
*/
bool AllocBytes(size_t cb) noexcept
{
T* pT = static_cast<T*>(Mso::Memory::AllocateEx(cb, allocFlags));
if (pT != nullptr)
this->Attach(pT);
return (pT != nullptr);
}
/**
AllocElem
/**
AllocElem
Allocate space for cElements + cExtra instances.
On success, any previously held data is replaced.
Optional out parameters to receive the number of elements/bytes allocated
Returns false on OOM / overflow.
Allocate space for cElements + cExtra instances.
On success, any previously held data is replaced.
Optional out parameters to receive the number of elements/bytes allocated
Returns false on OOM / overflow.
Mso::MemoryPtr<wchar_t> wzFoo;
size_t cchFoo = 0;
if (wzFoo.AllocElemCb(cch, 1, &cchFoo)) { ... }
*/
bool AllocElem(size_t cElements, size_t cExtra = 0, _Out_opt_ size_t* pcElements = nullptr, _Out_opt_ size_t* pcbAlloc = nullptr) noexcept
{
// TODO: size_t cbAlloc = (msl::utilities::SafeInt<size_t>(cElements) +cExtra) * sizeof(T);
size_t cbAlloc = (cElements + cExtra) * sizeof(T);
bool fRet = AllocBytes(cbAlloc);
if (pcElements != nullptr)
*pcElements = (fRet ? cbAlloc / sizeof(T) : 0);
if (pcbAlloc != nullptr)
*pcbAlloc = (fRet ? cbAlloc : 0);
return fRet;
}
Mso::MemoryPtr<wchar_t> wzFoo;
size_t cchFoo = 0;
if (wzFoo.AllocElemCb(cch, 1, &cchFoo)) { ... }
*/
bool AllocElem(
size_t cElements,
size_t cExtra = 0,
_Out_opt_ size_t* pcElements = nullptr,
_Out_opt_ size_t* pcbAlloc = nullptr) noexcept
{
// TODO: size_t cbAlloc = (msl::utilities::SafeInt<size_t>(cElements) +cExtra) * sizeof(T);
size_t cbAlloc = (cElements + cExtra) * sizeof(T);
bool fRet = AllocBytes(cbAlloc);
if (pcElements != nullptr)
*pcElements = (fRet ? cbAlloc / sizeof(T) : 0);
if (pcbAlloc != nullptr)
*pcbAlloc = (fRet ? cbAlloc : 0);
return fRet;
}
/**
AllocOne
/**
AllocOne
Allocate space for 1 instance.
On success, any previously held data is replaced.
Returns false on OOM / overflow.
Allocate space for 1 instance.
On success, any previously held data is replaced.
Returns false on OOM / overflow.
Mso::MemoryPtr<Foo> pFoo;
if (pFoo.AllocOne()) { ... }
*/
bool AllocOne() noexcept
{
return AllocElem(1);
}
Mso::MemoryPtr<Foo> pFoo;
if (pFoo.AllocOne()) { ... }
*/
bool AllocOne() noexcept
{
return AllocElem(1);
}
// TODO: Does it make sense for CallocElemCb? See if there is need.
// TODO: Does it make sense for CallocElemCb? See if there is need.
/**
ReallocBytes
/**
ReallocBytes
Reallocate the exact number of bytes.
Returns false on OOM / overflow.
Reallocate the exact number of bytes.
Returns false on OOM / overflow.
ReallocElem is strongly preferred.
*/
bool ReallocBytes(size_t cb) noexcept
{
const T* pT = static_cast<const T*>(Mso::Memory::Reallocate(reinterpret_cast<void**>(&this->m_pT), cb));
return (pT != nullptr);
}
ReallocElem is strongly preferred.
*/
bool ReallocBytes(size_t cb) noexcept
{
const T* pT = static_cast<const T*>(Mso::Memory::Reallocate(reinterpret_cast<void**>(&this->m_pT), cb));
return (pT != nullptr);
}
/**
ReallocElem
/**
ReallocElem
Reallocate space for cElements + cExtra instances.
Optional out parameters to receive the number of elements/bytes allocated
Returns false on OOM / overflow.
*/
bool ReallocElem(size_t cElements, size_t cExtra = 0, _Out_opt_ size_t* pcElements = nullptr, _Out_opt_ size_t* pcbAlloc = nullptr) noexcept
{
// TODO: size_t cbAlloc = (msl::utilities::SafeInt<size_t>(cElements) +cExtra) * sizeof(T);
size_t cbAlloc = (cElements + cExtra) * sizeof(T);
bool fRet = ReallocBytes(cbAlloc);
if (pcElements != nullptr)
*pcElements = (fRet ? cbAlloc / sizeof(T) : 0);
if (pcbAlloc != nullptr)
*pcbAlloc = (fRet ? cbAlloc : 0);
return fRet;
}
Reallocate space for cElements + cExtra instances.
Optional out parameters to receive the number of elements/bytes allocated
Returns false on OOM / overflow.
*/
bool ReallocElem(
size_t cElements,
size_t cExtra = 0,
_Out_opt_ size_t* pcElements = nullptr,
_Out_opt_ size_t* pcbAlloc = nullptr) noexcept
{
// TODO: size_t cbAlloc = (msl::utilities::SafeInt<size_t>(cElements) +cExtra) * sizeof(T);
size_t cbAlloc = (cElements + cExtra) * sizeof(T);
bool fRet = ReallocBytes(cbAlloc);
if (pcElements != nullptr)
*pcElements = (fRet ? cbAlloc / sizeof(T) : 0);
if (pcbAlloc != nullptr)
*pcbAlloc = (fRet ? cbAlloc : 0);
return fRet;
}
/**
CloneBytes
/**
CloneBytes
Allocates a new buffer and copies the data into it.
On success, any previously held data is replaced.
Returns false on OOM / overflow.
Allocates a new buffer and copies the data into it.
On success, any previously held data is replaced.
Returns false on OOM / overflow.
CloneElem-variants are strongly preferred to avoid integer overflow.
FUTURE: I could add cbExtra parameter if it makes sense.
CloneElem-variants are strongly preferred to avoid integer overflow.
FUTURE: I could add cbExtra parameter if it makes sense.
Mso::MemoryPtr<BYTE> pbFoo;
if (pbFoo.CloneBytes(pbSrc, cbSrc)) { ... }
*/
bool CloneBytes(_In_opt_bytecount_(cb) const T* pT, size_t cb) noexcept
{
if (pT != nullptr)
{
Mso::MemoryPtr<T, allocFlags> pNew;
if (pNew.AllocBytes(cb))
{
memcpy_s(pNew.Get(), cb, pT, cb);
this->Swap(pNew);
return true;
}
}
Mso::MemoryPtr<BYTE> pbFoo;
if (pbFoo.CloneBytes(pbSrc, cbSrc)) { ... }
*/
bool CloneBytes(_In_opt_bytecount_(cb) const T* pT, size_t cb) noexcept
{
if (pT != nullptr)
{
Mso::MemoryPtr<T, allocFlags> pNew;
if (pNew.AllocBytes(cb))
{
memcpy_s(pNew.Get(), cb, pT, cb);
this->Swap(pNew);
return true;
}
}
return false;
}
return false;
}
/**
CloneElem
/**
CloneElem
Allocate space and copies cElements instances from the source.
On success, any previously held data is replaced.
Returns false on OOM / overflow.
Allocate space and copies cElements instances from the source.
On success, any previously held data is replaced.
Returns false on OOM / overflow.
Mso::MemoryPtr<FooData> rgFooData;
if (rgFooData.CloneElem(rgFooDataSrc, cFooDataSrc) { ... }
*/
bool CloneElem(_In_opt_count_(cElements) const T* pT, size_t cElements) noexcept
{
// TODO: size_t cbAlloc = msl::utilities::SafeInt<size_t>(cElements) * sizeof(T);
size_t cbAlloc = (cElements)* sizeof(T);
return CloneBytes(pT, cbAlloc);
}
Mso::MemoryPtr<FooData> rgFooData;
if (rgFooData.CloneElem(rgFooDataSrc, cFooDataSrc) { ... }
*/
bool CloneElem(_In_opt_count_(cElements) const T* pT, size_t cElements) noexcept
{
// TODO: size_t cbAlloc = msl::utilities::SafeInt<size_t>(cElements) * sizeof(T);
size_t cbAlloc = (cElements) * sizeof(T);
return CloneBytes(pT, cbAlloc);
}
/**
CloneOne
/**
CloneOne
Allocates space and copies 1 instance from the source.
Any previously held data is replaced on success.
Allocates space and copies 1 instance from the source.
Any previously held data is replaced on success.
Mso::MemoryPtr<Foo> pFoo;
if (pFoo.AllocOne(pFooSrc)) { ... }
*/
bool CloneOne(_In_opt_count_(1) const T* pT) noexcept
{
return CloneElem(pT, 1);
}
Mso::MemoryPtr<Foo> pFoo;
if (pFoo.AllocOne(pFooSrc)) { ... }
*/
bool CloneOne(_In_opt_count_(1) const T* pT) noexcept
{
return CloneElem(pT, 1);
}
#ifdef MSO_THOLDER_EXPLICIT_GET_ONLY
T& operator*() const noexcept
{
return *this->Get();
}
T& operator*() const noexcept
{
return *this->Get();
}
#endif
private:
DECLARE_COPYCONSTR_AND_ASSIGNMENT(MemoryPtr);
};
} // Mso
private:
DECLARE_COPYCONSTR_AND_ASSIGNMENT(MemoryPtr);
};
} // namespace Mso
#pragma pop_macro("New")
#pragma pop_macro("new")

Просмотреть файл

@ -13,68 +13,65 @@ namespace Mso {
Acts like unique_ptr for a thread-local variable, automatically deletes on thread-exit.
Use as static variable since this object lifetime controls the backing thread-storage.
*/
template<typename T, typename Deleter = std::default_delete<T>>
template <typename T, typename Deleter = std::default_delete<T>>
class threadlocal_unique_ptr : private Mso::ThreadLocal<T*>
{
using Super = Mso::ThreadLocal<T*>;
using Super = Mso::ThreadLocal<T*>;
public:
threadlocal_unique_ptr() noexcept : Super(Delete)
{
}
threadlocal_unique_ptr() noexcept : Super(Delete) {}
explicit operator bool() const noexcept
{
return get() != nullptr;
}
explicit operator bool() const noexcept
{
return get() != nullptr;
}
T* operator ->() const noexcept
{
return get();
}
T* operator->() const noexcept
{
return get();
}
T* get() const noexcept
{
return Super::GetValue();
}
T* get() const noexcept
{
return Super::GetValue();
}
T& getOrCreate() noexcept
{
auto t = get();
if (!t)
{
T& getOrCreate() noexcept
{
auto t = get();
if (!t)
{
#ifdef DEBUG
Mso::Memory::AutoIgnoreLeakScope ignoreTlsVar;
Mso::Memory::AutoIgnoreLeakScope ignoreTlsVar;
#endif
t = new T();
reset(t);
}
t = new T();
reset(t);
}
return *t;
}
return *t;
}
void reset(T* t) noexcept
{
Delete(release());
Super::SetValue(t);
}
void reset(T* t) noexcept
{
Delete(release());
Super::SetValue(t);
}
T* release() noexcept
{
auto t = get();
Super::SetValue(nullptr);
return t;
}
T* release() noexcept
{
auto t = get();
Super::SetValue(nullptr);
return t;
}
private:
static void __stdcall Delete(T* t) noexcept
{
Deleter()(t);
}
static void __stdcall Delete(T* t) noexcept
{
Deleter()(t);
}
};
} // Mso
} // namespace Mso
#endif // C++
#endif // _CPPEXTENSIONS_THREADLOCALUNIQUEPTR_H_

Просмотреть файл

@ -7,22 +7,24 @@
#ifdef __cplusplus
#include <compilerAdapters/functionDecorations.h>
namespace Mso {
namespace Memory {
namespace Mso { namespace Memory {
/**
Is the ShutdownLeakScope currently active?
Is the ShutdownLeakScope currently active?
*/
#ifdef DEBUG
LIBLET_PUBLICAPI bool IsInShutdownLeakScope() noexcept;
#else
inline bool IsInShutdownLeakScope() noexcept { return false; }
inline bool IsInShutdownLeakScope() noexcept
{
return false;
}
#endif
/**
Enter the scope so allocations on this thread should be marked for shutdown leak detection.
Scope can be entered a limited number of times.
Frames to skip is used to track which caller address is associated with this Enter.
Enter the scope so allocations on this thread should be marked for shutdown leak detection.
Scope can be entered a limited number of times.
Frames to skip is used to track which caller address is associated with this Enter.
*/
#ifdef DEBUG
LIBLET_PUBLICAPI void EnterShutdownLeakScope(unsigned int framesToSkip = 0) noexcept;
@ -31,7 +33,7 @@ inline void EnterShutdownLeakScope(unsigned int /*framesToSkip*/ = 0) noexcept {
#endif
/**
Leave
Leave
*/
#ifdef DEBUG
LIBLET_PUBLICAPI void LeaveShutdownLeakScope() noexcept;
@ -40,18 +42,21 @@ inline void LeaveShutdownLeakScope() noexcept {}
#endif
/**
Is the IgnoreLeakScope currently active?
Is the IgnoreLeakScope currently active?
*/
#ifdef DEBUG
LIBLET_PUBLICAPI bool IsInIgnoreLeakScope() noexcept;
#else
inline bool IsInIgnoreLeakScope() noexcept { return false; }
inline bool IsInIgnoreLeakScope() noexcept
{
return false;
}
#endif
/**
Enter the scope so allocations on this thread should be ignored for leak detection.
Scope can be entered a limited number of times.
Frames to skip is used to track which caller address is associated with this Enter.
Enter the scope so allocations on this thread should be ignored for leak detection.
Scope can be entered a limited number of times.
Frames to skip is used to track which caller address is associated with this Enter.
*/
#ifdef DEBUG
LIBLET_PUBLICAPI void EnterIgnoreLeakScope(unsigned int framesToSkip = 0) noexcept;
@ -60,7 +65,7 @@ inline void EnterIgnoreLeakScope(unsigned int /*framesToSkip*/ = 0) noexcept {}
#endif
/**
Leave
Leave
*/
#ifdef DEBUG
LIBLET_PUBLICAPI void LeaveIgnoreLeakScope() noexcept;
@ -70,38 +75,37 @@ inline void LeaveIgnoreLeakScope() noexcept {}
struct AutoShutdownLeakScope
{
AutoShutdownLeakScope(unsigned int framesToSkip = 0) noexcept
{
EnterShutdownLeakScope(++framesToSkip);
}
AutoShutdownLeakScope(const AutoShutdownLeakScope& /*other*/) noexcept : AutoShutdownLeakScope(1) {}
AutoShutdownLeakScope(AutoShutdownLeakScope&& /*other*/) noexcept : AutoShutdownLeakScope(1) {}
AutoShutdownLeakScope(unsigned int framesToSkip = 0) noexcept
{
EnterShutdownLeakScope(++framesToSkip);
}
~AutoShutdownLeakScope() noexcept
{
LeaveShutdownLeakScope();
}
AutoShutdownLeakScope(const AutoShutdownLeakScope& /*other*/) noexcept : AutoShutdownLeakScope(1) {}
AutoShutdownLeakScope(AutoShutdownLeakScope&& /*other*/) noexcept : AutoShutdownLeakScope(1) {}
~AutoShutdownLeakScope() noexcept
{
LeaveShutdownLeakScope();
}
};
struct AutoIgnoreLeakScope
{
AutoIgnoreLeakScope(unsigned int framesToSkip = 0) noexcept
{
EnterIgnoreLeakScope(++framesToSkip);
}
AutoIgnoreLeakScope(unsigned int framesToSkip = 0) noexcept
{
EnterIgnoreLeakScope(++framesToSkip);
}
AutoIgnoreLeakScope(const AutoIgnoreLeakScope& /*other*/) noexcept : AutoIgnoreLeakScope(1) {}
AutoIgnoreLeakScope(AutoIgnoreLeakScope&& /*other*/) noexcept : AutoIgnoreLeakScope(1) {}
AutoIgnoreLeakScope(const AutoIgnoreLeakScope& /*other*/) noexcept : AutoIgnoreLeakScope(1) {}
AutoIgnoreLeakScope(AutoIgnoreLeakScope&& /*other*/) noexcept : AutoIgnoreLeakScope(1) {}
~AutoIgnoreLeakScope() noexcept
{
LeaveIgnoreLeakScope();
}
~AutoIgnoreLeakScope() noexcept
{
LeaveIgnoreLeakScope();
}
};
}
} // Mso::Memory
}} // namespace Mso::Memory
#endif // C++
#endif // LIBLET_MEMORYAPI_SCOPE

Просмотреть файл

@ -8,98 +8,101 @@
#include <sal.h>
//#include <intsafe.h>
/*
* MsoCbBufSizeT
* This function returns the bytes needed to allocate a buffer for (cElements + cExtra)
* instances of type T. This is a low level function, and typical usage would be to call
* one of the wrappers that deal with (for example) WCHAR arrays.
*
* Note: Strictly speaking, this isn't an exported MSO function, as it's instantiated by
* the caller, and simply picked up from the header.
*
* Arguments:
* cElements - the number of elements needed
* cExtra - any additional elements needed
* cbMaxBufSize - optional argument for the maximum bytes allowed. Default is the maximum
* possible value for the architecture.
*
* Return:
* Either a mathematically correct number of bytes required, or in the case of an error,
* INVALID_BUFFER_SIZE
*
* Revision history:
* 10/22/04 - dleblanc - created
*/
* MsoCbBufSizeT
* This function returns the bytes needed to allocate a buffer for (cElements + cExtra)
* instances of type T. This is a low level function, and typical usage would be to call
* one of the wrappers that deal with (for example) WCHAR arrays.
*
* Note: Strictly speaking, this isn't an exported MSO function, as it's instantiated by
* the caller, and simply picked up from the header.
*
* Arguments:
* cElements - the number of elements needed
* cExtra - any additional elements needed
* cbMaxBufSize - optional argument for the maximum bytes allowed. Default is the maximum
* possible value for the architecture.
*
* Return:
* Either a mathematically correct number of bytes required, or in the case of an error,
* INVALID_BUFFER_SIZE
*
* Revision history:
* 10/22/04 - dleblanc - created
*/
const size_t INVALID_BUFFER_SIZE = ((size_t)~0);
const size_t MAXIMUM_BUFFER_SIZE = ((size_t)INT_MAX);
template <typename T>
_Ret_range_(==, (cElements + cExtra) * sizeof(T))
size_t MsoCbBufSizeT(size_t cElements, size_t cExtra = 0, size_t cbMaxBufSize = MAXIMUM_BUFFER_SIZE) noexcept
_Ret_range_(==, (cElements + cExtra) * sizeof(T)) size_t
MsoCbBufSizeT(size_t cElements, size_t cExtra = 0, size_t cbMaxBufSize = MAXIMUM_BUFFER_SIZE) noexcept
{
//first calculate maximum allowed
//typical case is a compile time constant
const size_t cMax = cbMaxBufSize/sizeof(T);
const size_t cMaxAllowed = cMax - cExtra;
// first calculate maximum allowed
// typical case is a compile time constant
const size_t cMax = cbMaxBufSize / sizeof(T);
const size_t cMaxAllowed = cMax - cExtra;
if(cExtra > cMax || //cExtra is too large
cElements > cMaxAllowed) //real check here
{
if (cExtra > cMax || // cExtra is too large
cElements > cMaxAllowed) // real check here
{
#if DEBUG
// TODO: This should be changed to a tagged function
//__asm int 3
// TODO: This should be changed to a tagged function
//__asm int 3
#endif
//we have a problem
return INVALID_BUFFER_SIZE;
}
// we have a problem
return INVALID_BUFFER_SIZE;
}
return (cElements + cExtra) * sizeof(T);
return (cElements + cExtra) * sizeof(T);
}
/*
* MsoCbBufSizeExT
*
* Variant of MsoCbBufSizeT in which you may specify an additional "cbExtra" size
* (for array headers, etc.)
*
* Arguments:
* cElements - the number of elements needed
* cbExtra - any additional bytes needed
* cExtra - any additional elements needed
* cbMaxBufSize - optional argument for the maximum bytes allowed. Default is the maximum
* possible value for the architecture.
*
* Return:
* Either a mathematically correct number of bytes required, or in the case of an error,
* INVALID_BUFFER_SIZE
*
* Revision history:
* 8/14/05 - LeeHu - created
*/
* MsoCbBufSizeExT
*
* Variant of MsoCbBufSizeT in which you may specify an additional "cbExtra" size
* (for array headers, etc.)
*
* Arguments:
* cElements - the number of elements needed
* cbExtra - any additional bytes needed
* cExtra - any additional elements needed
* cbMaxBufSize - optional argument for the maximum bytes allowed. Default is the maximum
* possible value for the architecture.
*
* Return:
* Either a mathematically correct number of bytes required, or in the case of an error,
* INVALID_BUFFER_SIZE
*
* Revision history:
* 8/14/05 - LeeHu - created
*/
template <typename T>
_Ret_range_(==, (cElements + cExtra) * sizeof(T) + cbExtra)
size_t MsoCbBufSizeExT(size_t cElements, size_t cbExtra, size_t cExtra = 0, size_t cbMaxBufSize = MAXIMUM_BUFFER_SIZE) noexcept
_Ret_range_(==, (cElements + cExtra) * sizeof(T) + cbExtra) size_t MsoCbBufSizeExT(
size_t cElements,
size_t cbExtra,
size_t cExtra = 0,
size_t cbMaxBufSize = MAXIMUM_BUFFER_SIZE) noexcept
{
//first calculate maximum allowed
const size_t cbMax = cbMaxBufSize - cbExtra;
const size_t cMax = cbMax/sizeof(T);
const size_t cMaxAllowed = cMax - cExtra;
// first calculate maximum allowed
const size_t cbMax = cbMaxBufSize - cbExtra;
const size_t cMax = cbMax / sizeof(T);
const size_t cMaxAllowed = cMax - cExtra;
if(cbExtra > cbMaxBufSize || //cbExtra is too large
cExtra > cMax || //cExtra is too large
cElements > cMaxAllowed //"real" buf size check here
)
{
if (cbExtra > cbMaxBufSize || // cbExtra is too large
cExtra > cMax || // cExtra is too large
cElements > cMaxAllowed //"real" buf size check here
)
{
#if DEBUG
// TODO: This should be changed to a tagged function
//__asm int 3
// TODO: This should be changed to a tagged function
//__asm int 3
#endif
//we have a problem
return INVALID_BUFFER_SIZE;
}
// we have a problem
return INVALID_BUFFER_SIZE;
}
return (cElements + cExtra) * sizeof(T) + cbExtra;
return (cElements + cExtra) * sizeof(T) + cbExtra;
}
#endif // __cplusplus

Просмотреть файл

@ -2,21 +2,17 @@
// Licensed under the MIT license.
/**
CRT based implementation for Mso::Memory
CRT based implementation for Mso::Memory
*/
#include <core/memoryApi.h>
#include <malloc.h>
namespace Mso
namespace Mso { namespace Memory {
MSOCPPAPI_(size_t) AllocationSize(_In_opt_ const void* pv) noexcept
{
namespace Memory
{
MSOCPPAPI_(size_t) AllocationSize(_In_opt_ const void* pv) noexcept
{
if (pv == nullptr)
return 0;
if (pv == nullptr)
return 0;
return ::_msize(const_cast<void *>(pv));
}
}
return ::_msize(const_cast<void*>(pv));
}
}} // namespace Mso::Memory

Просмотреть файл

@ -2,19 +2,15 @@
// Licensed under the MIT license.
/**
CRT based implementation for Mso::Memory
CRT based implementation for Mso::Memory
*/
#include <core/memoryApi.h>
#include <malloc.h>
namespace Mso
namespace Mso { namespace Memory {
MSOCPPAPI_(size_t) AllocationSize(_In_opt_ const void* pv) noexcept
{
namespace Memory
{
MSOCPPAPI_(size_t) AllocationSize(_In_opt_ const void* pv) noexcept
{
AssertSzTag(false, "AllocationSize is not implemented for this platform", 0x006951de /* tag_a0vh4 */);
return 0;
}
}
AssertSzTag(false, "AllocationSize is not implemented for this platform", 0x006951de /* tag_a0vh4 */);
return 0;
}
}} // namespace Mso::Memory

Просмотреть файл

@ -2,18 +2,14 @@
// Licensed under the MIT license.
/**
CRT based implementation for Mso::Memory
CRT based implementation for Mso::Memory
*/
#include <core/memoryApi.h>
#include <malloc.h>
namespace Mso
namespace Mso { namespace Memory {
MSOCPPAPI_(size_t) AllocationSize(_In_opt_ const void* pv) noexcept
{
namespace Memory
{
MSOCPPAPI_(size_t) AllocationSize(_In_opt_ const void* pv) noexcept
{
return malloc_usable_size(pv);
}
}
return malloc_usable_size(pv);
}
}} // namespace Mso::Memory

Просмотреть файл

@ -7,16 +7,12 @@ CRT based implementation for Mso::Memory on Apple platform
#include <core/memoryApi.h>
#include <malloc.h>
namespace Mso
namespace Mso { namespace Memory {
MSOCPPAPI_(size_t) AllocationSize(_In_opt_ const void* pv) noexcept
{
namespace Memory
{
MSOCPPAPI_(size_t) AllocationSize(_In_opt_ const void* pv) noexcept
{
if (pv == nullptr)
return 0;
if (pv == nullptr)
return 0;
return ::malloc_size(const_cast<void *>(pv));
}
}
return ::malloc_size(const_cast<void*>(pv));
}
}} // namespace Mso::Memory

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
CRT based implementation for Mso::Memory
CRT based implementation for Mso::Memory
*/
#include <core/memoryApi.h>
#include <platformadapters/windowsfirst.h>
@ -12,8 +12,7 @@
MSOAPI_(BOOL) MsoCheckHeap(void) noexcept
{
return ::_heapchk() == _HEAPOK;
return ::_heapchk() == _HEAPOK;
}
#endif // DEBUG

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
CRT based implementation for Mso::Memory
CRT based implementation for Mso::Memory
*/
#include <core/memoryApi.h>
#include <malloc.h>
@ -11,8 +11,8 @@
MSOAPI_(BOOL) MsoCheckHeap(void) noexcept
{
AssertSzTag(false, "MsoCheckHeap is not implemented for this platform", 0x0125310c /* tag_bjtem */);
return true;
AssertSzTag(false, "MsoCheckHeap is not implemented for this platform", 0x0125310c /* tag_bjtem */);
return true;
}
#endif // DEBUG

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
CRT based implementation for Mso::Memory
CRT based implementation for Mso::Memory
*/
#include <core/memoryApi.h>
#include <malloc.h>
@ -11,8 +11,8 @@
MSOAPI_(BOOL) MsoCheckHeap(void) noexcept
{
AssertSzTag(false, "MsoCheckHeap is not implemented for this platform", 0x027c404d /* tag_c5ebn */);
return true;
AssertSzTag(false, "MsoCheckHeap is not implemented for this platform", 0x027c404d /* tag_c5ebn */);
return true;
}
#endif // DEBUG

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
CRT based implementation for Mso::Memory
CRT based implementation for Mso::Memory
*/
#include <core/memoryApi.h>
#include <malloc.h>
@ -11,8 +11,8 @@
MSOAPI_(BOOL) MsoCheckHeap(void) noexcept
{
// passing nullptr checks all zones
return malloc_zone_check(nullptr);
// passing nullptr checks all zones
return malloc_zone_check(nullptr);
}
#endif // DEBUG

Просмотреть файл

@ -2,87 +2,89 @@
// Licensed under the MIT license.
/**
CRT based implementation for Mso::Memory
CRT based implementation for Mso::Memory
*/
#include <core/memoryApi.h>
#include <cstdlib>
#include <memory>
#if !__clang__ && !__GNUC__
#pragma detect_mismatch("Allocator", "Crt")
#pragma detect_mismatch("Allocator", "Crt")
#endif
__declspec(noreturn) void ThrowOOM() { throw std::bad_alloc(); }
namespace Mso { namespace Memory {
_Use_decl_annotations_
void* AllocateEx(size_t cb, DWORD /*allocFlags*/) noexcept
__declspec(noreturn) void ThrowOOM()
{
return ::malloc(cb);
throw std::bad_alloc();
}
_Use_decl_annotations_
void* Reallocate(void** ppv, size_t cb) noexcept
namespace Mso { namespace Memory {
_Use_decl_annotations_ void* AllocateEx(size_t cb, DWORD /*allocFlags*/) noexcept
{
if (ppv == nullptr)
return Mso::Memory::Allocate(cb);
if (*ppv == nullptr)
{
*ppv = Mso::Memory::Allocate(cb);
return *ppv;
}
void* pv = ::realloc(*ppv, cb);
if (pv != nullptr)
{
*ppv = pv;
}
else if (cb == 0)
{
// HeapReAlloc with 0 size returns valid pointer and we want all implementations do the same
// realloc(ptr, 0) on Windows or Mac/iOS with ASAN frees the original pointer and returns null
// std lib on Mac/iOS returns a valid 0-sized pointer
// We want to standardize to have only one behavior in shared code
// so let's allocate a new 0-sized block if resize(ptr, 0) returns nullptr
pv = ::malloc(0);
*ppv = pv;
}
//else pv = nullptr, cb != 0: if realloc truly failed, the original ptr is untouched
return pv;
return ::malloc(cb);
}
_Use_decl_annotations_
void Free(void* pv) noexcept
_Use_decl_annotations_ void* Reallocate(void** ppv, size_t cb) noexcept
{
::free(pv);
if (ppv == nullptr)
return Mso::Memory::Allocate(cb);
if (*ppv == nullptr)
{
*ppv = Mso::Memory::Allocate(cb);
return *ppv;
}
void* pv = ::realloc(*ppv, cb);
if (pv != nullptr)
{
*ppv = pv;
}
else if (cb == 0)
{
// HeapReAlloc with 0 size returns valid pointer and we want all implementations do the same
// realloc(ptr, 0) on Windows or Mac/iOS with ASAN frees the original pointer and returns null
// std lib on Mac/iOS returns a valid 0-sized pointer
// We want to standardize to have only one behavior in shared code
// so let's allocate a new 0-sized block if resize(ptr, 0) returns nullptr
pv = ::malloc(0);
*ppv = pv;
}
// else pv = nullptr, cb != 0: if realloc truly failed, the original ptr is untouched
return pv;
}
_Use_decl_annotations_ void Free(void* pv) noexcept
{
::free(pv);
}
#ifdef DEBUG
void RegisterCallback(Mso::LibletAPI::ILibletMemoryMarking&) noexcept {}
void UnregisterCallback(Mso::LibletAPI::ILibletMemoryMarking&) noexcept {}
#endif
#endif
}} // Mso::Memory
}} // namespace Mso::Memory
#ifdef DEBUG
MSOAPI_(void) MsoSetLazyLeakDetection(const void *) noexcept
MSOAPI_(void) MsoSetLazyLeakDetection(const void*) noexcept {}
MSOAPI_(void) MsoSetShutdownLeakDetection(const void*) noexcept {}
MSOAPI_(BOOL)
FMemHeapMsoSaveBeHost(
void* /*pinst*/,
LPARAM /*lParam*/,
const void* /*pvBlock*/,
LONG_PTR /*cb*/,
struct IMsoMemHeap* /*pmmh*/) noexcept
{
return true;
}
MSOAPI_(void) MsoSetShutdownLeakDetection(const void *) noexcept
{
}
MSOAPI_(BOOL) FMemHeapMsoSaveBeHost(void* /*pinst*/, LPARAM /*lParam*/, const void* /*pvBlock*/, LONG_PTR /*cb*/, struct IMsoMemHeap* /*pmmh*/) noexcept
{
return true;
}
//MSOAPI_(VOID) MsoDebugRegisterLazyObject(IMsoDebugLazyObject* /*pidlo*/) noexcept {}
//MSOAPI_(VOID) MsoDebugUnregisterLazyObjectThreaded(IMsoDebugLazyObject* /*pidlo*/, bool /*fMainThread*/) noexcept {}
// MSOAPI_(VOID) MsoDebugRegisterLazyObject(IMsoDebugLazyObject* /*pidlo*/) noexcept {}
// MSOAPI_(VOID) MsoDebugUnregisterLazyObjectThreaded(IMsoDebugLazyObject* /*pidlo*/, bool /*fMainThread*/) noexcept {}
#endif // DEBUG

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
CRT based implementation for Mso::Memory
CRT based implementation for Mso::Memory
*/
#include <core/memoryApi.h>
#include <malloc.h>
@ -10,58 +10,73 @@
#pragma detect_mismatch("Allocator", "EmptyImpl")
__declspec(noreturn) void ThrowOOM() { throw std::bad_alloc(); }
__declspec(noreturn) void ThrowOOM()
{
throw std::bad_alloc();
}
namespace Mso { namespace Memory {
namespace Mso { namespace Memory {
MSOCPPAPI_(size_t) AllocationSize(_In_opt_ const void*) noexcept
{
VerifyElseCrashTag(false, 0x0115e605 /* tag_bf4yf */);
VerifyElseCrashTag(false, 0x0115e605 /* tag_bf4yf */);
}
MSOCPPAPI_(void*) AllocateEx(size_t /*cb*/, DWORD /*allocFlags*/) noexcept
{
VerifyElseCrashTag(false, 0x006cc64b /* tag_a1mzl */);
VerifyElseCrashTag(false, 0x006cc64b /* tag_a1mzl */);
}
MSOCPPAPI_(void*) Reallocate(_Inout_ void** /*ppv*/, size_t /*cb*/) noexcept
{
VerifyElseCrashTag(false, 0x006cc64c /* tag_a1mzm */);
VerifyElseCrashTag(false, 0x006cc64c /* tag_a1mzm */);
}
MSOCPPAPI_(void) Free(_In_opt_ void* /*pv*/) noexcept
{
VerifyElseCrashTag(false, 0x006cc64d /* tag_a1mzn */);
VerifyElseCrashTag(false, 0x006cc64d /* tag_a1mzn */);
}
#ifdef DEBUG
MSOCPPAPI_(void) RegisterCallback(Mso::LibletAPI::ILibletMemoryMarking&) noexcept { VerifyElseCrashTag(false, 0x006cc64e /* tag_a1mzo */); }
MSOCPPAPI_(void) UnregisterCallback(Mso::LibletAPI::ILibletMemoryMarking&) noexcept { VerifyElseCrashTag(false, 0x006cc64f /* tag_a1mzp */); }
#endif
MSOCPPAPI_(void) RegisterCallback(Mso::LibletAPI::ILibletMemoryMarking&) noexcept
{
VerifyElseCrashTag(false, 0x006cc64e /* tag_a1mzo */);
}
MSOCPPAPI_(void) UnregisterCallback(Mso::LibletAPI::ILibletMemoryMarking&) noexcept
{
VerifyElseCrashTag(false, 0x006cc64f /* tag_a1mzp */);
}
#endif
}} // Mso::Memory
}} // namespace Mso::Memory
#ifdef DEBUG
MSOAPI_(BOOL) MsoCheckHeap(void) noexcept
{
VerifyElseCrashTag(false, 0x0125310d /* tag_bjten */);
return true;
VerifyElseCrashTag(false, 0x0125310d /* tag_bjten */);
return true;
}
MSOAPI_(void) MsoSetLazyLeakDetection(const void *) noexcept
MSOAPI_(void) MsoSetLazyLeakDetection(const void*) noexcept
{
VerifyElseCrashTag(false, 0x006cc650 /* tag_a1mzq */);
VerifyElseCrashTag(false, 0x006cc650 /* tag_a1mzq */);
}
MSOAPI_(void) MsoSetShutdownLeakDetection(const void *) noexcept
MSOAPI_(void) MsoSetShutdownLeakDetection(const void*) noexcept
{
VerifyElseCrashTag(false, 0x006cc651 /* tag_a1mzr */);
VerifyElseCrashTag(false, 0x006cc651 /* tag_a1mzr */);
}
MSOAPI_(BOOL) FMemHeapMsoSaveBeHost(void* /*pinst*/, LPARAM /*lParam*/, const void* /*pvBlock*/, LONG_PTR /*cb*/, struct IMsoMemHeap* /*pmmh*/) noexcept
MSOAPI_(BOOL)
FMemHeapMsoSaveBeHost(
void* /*pinst*/,
LPARAM /*lParam*/,
const void* /*pvBlock*/,
LONG_PTR /*cb*/,
struct IMsoMemHeap* /*pmmh*/) noexcept
{
VerifyElseCrashTag(false, 0x006cc652 /* tag_a1mzs */);
VerifyElseCrashTag(false, 0x006cc652 /* tag_a1mzs */);
}
MSOAPI_(VOID) MsoDebugRegisterLazyObject(IMsoDebugLazyObject* /*pidlo*/) noexcept {}

Просмотреть файл

@ -2,46 +2,35 @@
// Licensed under the MIT license.
/**
Empty implementation for memoryleakscope
Empty implementation for memoryleakscope
DO NOT INCLUDE THIS HEADER - LINK WITH THE LOB
(unless you need to link in pass0 e.g. msoprep\legacy)
DO NOT INCLUDE THIS HEADER - LINK WITH THE LOB
(unless you need to link in pass0 e.g. msoprep\legacy)
*/
#include <memoryleakscope/memoryLeakScope.h>
#ifdef DEBUG
namespace Mso {
namespace Memory {
namespace Mso { namespace Memory {
bool IsInShutdownLeakScope() noexcept
{
return false;
return false;
}
void EnterShutdownLeakScope(unsigned int /*framesToSkip*/) noexcept
{
}
void EnterShutdownLeakScope(unsigned int /*framesToSkip*/) noexcept {}
void LeaveShutdownLeakScope() noexcept
{
}
void LeaveShutdownLeakScope() noexcept {}
bool IsInIgnoreLeakScope() noexcept
{
return false;
return false;
}
void EnterIgnoreLeakScope(unsigned int /*framesToSkip*/) noexcept
{
}
void EnterIgnoreLeakScope(unsigned int /*framesToSkip*/) noexcept {}
void LeaveIgnoreLeakScope() noexcept
{
}
void LeaveIgnoreLeakScope() noexcept {}
} // Memory
} // Mso
}} // namespace Mso::Memory
#endif // DEBUG

Просмотреть файл

@ -1,3 +1,2 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

Просмотреть файл

@ -18,72 +18,71 @@
// UNTAGGED that can conflict with tagutils.h.
extern "C"
{
typedef UInt32 nl_assert_tag_t;
Boolean NLFAssertsEnabled();
void NLEnableAllAsserts(Boolean inEnabled);
typedef UInt32 nl_assert_tag_t;
Boolean NLIsAssertEnabledByTag(nl_assert_tag_t inTag);
void NLDisableAssertByTag(nl_assert_tag_t inTag);
void NLEnableAssertByTag(nl_assert_tag_t inTag);
Boolean NLFAssertsEnabled();
void NLEnableAllAsserts(Boolean inEnabled);
Boolean NLIsAssertEnabledByTag(nl_assert_tag_t inTag);
void NLDisableAssertByTag(nl_assert_tag_t inTag);
void NLEnableAssertByTag(nl_assert_tag_t inTag);
}
#endif
namespace Mso {
#if DEBUG
class IgnoreAllAssertsPlatformImpl
class IgnoreAllAssertsPlatformImpl
{
public:
IgnoreAllAssertsPlatformImpl() : m_nlEnabled(NLFAssertsEnabled())
{
NLEnableAllAsserts(false);
}
~IgnoreAllAssertsPlatformImpl()
{
NLEnableAllAsserts(m_nlEnabled);
}
private:
const bool m_nlEnabled;
};
class IgnoreAssertPlatformImpl
{
public:
IgnoreAssertPlatformImpl(DWORD tag) : m_tag(tag), m_tagEnabled(NLIsAssertEnabledByTag(tag))
{
if (m_tagEnabled)
{
public:
IgnoreAllAssertsPlatformImpl() :
m_nlEnabled(NLFAssertsEnabled())
{
NLEnableAllAsserts(false);
}
~IgnoreAllAssertsPlatformImpl()
{
NLEnableAllAsserts(m_nlEnabled);
}
private:
const bool m_nlEnabled;
};
class IgnoreAssertPlatformImpl
NLDisableAssertByTag(m_tag);
}
}
~IgnoreAssertPlatformImpl()
{
if (m_tagEnabled)
{
public:
IgnoreAssertPlatformImpl(DWORD tag) :
m_tag(tag),
m_tagEnabled(NLIsAssertEnabledByTag(tag))
{
if (m_tagEnabled)
{
NLDisableAssertByTag(m_tag);
}
}
~IgnoreAssertPlatformImpl()
{
if (m_tagEnabled)
{
NLEnableAssertByTag(m_tag);
}
}
private:
const bool m_tagEnabled;
const nl_assert_tag_t m_tag;
};
NLEnableAssertByTag(m_tag);
}
}
private:
const bool m_tagEnabled;
const nl_assert_tag_t m_tag;
};
#else // DEBUG
class IgnoreAllAssertsPlatformImpl {};
class IgnoreAssertPlatformImpl
{
public:
IgnoreAssertPlatformImpl(uint32_t) {}
};
class IgnoreAllAssertsPlatformImpl
{
};
class IgnoreAssertPlatformImpl
{
public:
IgnoreAssertPlatformImpl(uint32_t) {}
};
#endif
} // Mso
} // namespace Mso
#endif // MOTIFCPP_ASSERT_IGNOREPLAT_APPLE_H

Просмотреть файл

@ -12,14 +12,16 @@
namespace Mso {
class IgnoreAllAssertsPlatformImpl {};
class IgnoreAllAssertsPlatformImpl
{
};
class IgnoreAssertPlatformImpl
{
public:
IgnoreAssertPlatformImpl(uint32_t) {}
};
class IgnoreAssertPlatformImpl
{
public:
IgnoreAssertPlatformImpl(uint32_t) {}
};
} // Mso
} // namespace Mso
#endif // MOTIFCPP_ASSERT_IGNOREPLAT_EMPTYIMPL_H

Просмотреть файл

@ -6,10 +6,10 @@
#define MOTIFCPP_ASSERT_MOTIFAPI_H
#include "motifCppTest.h"
#define BeginSupportFileMap() \
#define BeginSupportFileMap()
#define Dependency(filepath) \
#define Dependency(filepath)
#define EndSupportFileMap() \
#define EndSupportFileMap()
#endif // MOTIFCPP_ASSERT_MOTIFAPI_H

Просмотреть файл

@ -14,8 +14,7 @@ namespace Mso { namespace UnitTests { namespace GTest {
struct GTestFixture : ::testing::Test
{
explicit GTestFixture(const TestClassInfo& classInfo, const TestMethodInfo& methodInfo)
: m_methodInfo { methodInfo }
, m_test { classInfo.CreateTest() }
: m_methodInfo{methodInfo}, m_test{classInfo.CreateTest()}
{
}
@ -24,26 +23,18 @@ struct GTestFixture : ::testing::Test
m_methodInfo.Invoke(*m_test);
}
static void SetUpTestSuite()
{
}
static void SetUpTestSuite() {}
static void TearDownTestSuite()
{
}
static void TearDownTestSuite() {}
void SetUp() override
{
}
void SetUp() override {}
void TearDown() override
{
}
void TearDown() override {}
private:
const TestMethodInfo& m_methodInfo;
std::unique_ptr<TestClass> m_test;
};
private:
const TestMethodInfo& m_methodInfo;
std::unique_ptr<TestClass> m_test;
};
inline void RegisterUnitTests()
{
@ -52,13 +43,15 @@ inline void RegisterUnitTests()
for (const TestMethodInfo* methodInfo : classInfo->MethodInfos())
{
::testing::RegisterTest(
/*test_suite_name:*/classInfo->ClassName(),
/*test_name:*/methodInfo->MethodName(),
/*type_param:*/nullptr,
/*value_param:*/nullptr,
/*file:*/classInfo->FileName(),
/*line:*/methodInfo->SourceLine(),
/*factory:*/[classInfo, methodInfo]() { return new GTestFixture { *classInfo, *methodInfo }; });
/*test_suite_name:*/ classInfo->ClassName(),
/*test_name:*/ methodInfo->MethodName(),
/*type_param:*/ nullptr,
/*value_param:*/ nullptr,
/*file:*/ classInfo->FileName(),
/*line:*/ methodInfo->SourceLine(),
/*factory:*/ [classInfo, methodInfo]() {
return new GTestFixture{*classInfo, *methodInfo};
});
}
}
}

Просмотреть файл

@ -11,11 +11,11 @@
#include <csignal>
#if defined(MSO_USE_GTEST)
# include <motifCpp/gTestAdapter.h>
#include <motifCpp/gTestAdapter.h>
#elif defined(MSO_USE_XCTEST)
# include <motifCpp/xcTestAdapter.h>
#include <motifCpp/xcTestAdapter.h>
#else
# error "Undefined unit test framework"
#error "Undefined unit test framework"
#endif
typedef wchar_t WCHAR;
@ -25,175 +25,186 @@ namespace TestAssert {
// Asserts that the specified condition is true, if it is false the unit test will fail
inline void IsTrue(bool condition, _In_z_ const WCHAR* message = L"")
{
ASSERT_TRUE(condition) << message;
ASSERT_TRUE(condition) << message;
}
// Verify that a condition is true:
template<typename T, typename TEnable = typename std::enable_if<!std::is_same<bool, T>::value>::type>
template <typename T, typename TEnable = typename std::enable_if<!std::is_same<bool, T>::value>::type>
inline void IsTrue(const T& condition, _In_z_ const WCHAR* message = L"")
{
return IsTrue(!!condition, message);
return IsTrue(!!condition, message);
}
// Asserts that the specified condition is false, if it is true the unit test will fail
inline void IsFalse(bool condition, const WCHAR* message = L"")
{
ASSERT_FALSE(condition) << message;
ASSERT_FALSE(condition) << message;
}
template<typename T, typename TEnable = typename std::enable_if<!std::is_same<bool, T>::value>::type>
template <typename T, typename TEnable = typename std::enable_if<!std::is_same<bool, T>::value>::type>
inline void IsFalse(const T& condition, _In_z_ const WCHAR* message = L"")
{
return IsFalse(!!condition, message);
return IsFalse(!!condition, message);
}
template <typename ExpectedType, typename ActualType>
inline void AreEqual(_In_ const ExpectedType& expected, _In_ const ActualType& actual, _In_z_ const WCHAR* message = L"")
inline void
AreEqual(_In_ const ExpectedType& expected, _In_ const ActualType& actual, _In_z_ const WCHAR* message = L"")
{
std::wstring wstrMessage(message);
ASSERT_EQ(expected, actual) << wstrMessage.c_str();
std::wstring wstrMessage(message);
ASSERT_EQ(expected, actual) << wstrMessage.c_str();
}
template <typename ExpectedType, typename ActualType,
typename TEnable = typename std::enable_if<std::is_same<ExpectedType, ActualType>::value
&& !std::is_same<ExpectedType, wchar_t>::value && !std::is_same<ExpectedType, char>::value>::type>
template <
typename ExpectedType,
typename ActualType,
typename TEnable = typename std::enable_if<
std::is_same<ExpectedType, ActualType>::value && !std::is_same<ExpectedType, wchar_t>::value
&& !std::is_same<ExpectedType, char>::value>::type>
void AreEqual(_In_ const ExpectedType* expected, _In_ const ActualType* actual, _In_z_ const WCHAR* message = L"")
{
AreEqual(*expected, *actual, message);
AreEqual(*expected, *actual, message);
}
inline void AreEqual(_In_ const wchar_t* expected, _In_ const wchar_t* actual, _In_z_ const WCHAR* message = L"")
{
std::wstring wstrMessage(message);
ASSERT_STREQ(expected, actual) << wstrMessage.c_str();
std::wstring wstrMessage(message);
ASSERT_STREQ(expected, actual) << wstrMessage.c_str();
}
inline void AreEqual(_In_ const char* expected, _In_ const char* actual, _In_z_ const WCHAR* message = L"")
{
std::wstring wstrMessage(message);
ASSERT_STREQ(expected, actual) << wstrMessage.c_str();
std::wstring wstrMessage(message);
ASSERT_STREQ(expected, actual) << wstrMessage.c_str();
}
inline void AreEqual(_In_ wchar_t* expected, _In_ const wchar_t* actual, _In_z_ const WCHAR* message = L"")
{
std::wstring wstrMessage(message);
ASSERT_STREQ(expected, actual) << wstrMessage.c_str();
std::wstring wstrMessage(message);
ASSERT_STREQ(expected, actual) << wstrMessage.c_str();
}
inline void AreEqual(_In_ char* expected, _In_ const char* actual, _In_z_ const WCHAR* message = L"")
{
std::wstring wstrMessage(message);
ASSERT_STREQ(expected, actual) << wstrMessage.c_str();
std::wstring wstrMessage(message);
ASSERT_STREQ(expected, actual) << wstrMessage.c_str();
}
template <typename ExpectedType, typename ActualType>
inline void AreNotEqual(_In_ const ExpectedType& expected, _In_ const ActualType& actual, _In_z_ const WCHAR* message = L"")
inline void
AreNotEqual(_In_ const ExpectedType& expected, _In_ const ActualType& actual, _In_z_ const WCHAR* message = L"")
{
std::wstring wstrMessage(message);
ASSERT_NE(expected, actual) << wstrMessage.c_str();
std::wstring wstrMessage(message);
ASSERT_NE(expected, actual) << wstrMessage.c_str();
}
template <typename ExpectedType, typename ActualType,
typename TEnable = typename std::enable_if<std::is_same<ExpectedType, ActualType>::value
&& !std::is_same<ExpectedType, wchar_t>::value && !std::is_same<ExpectedType, char>::value>::type>
template <
typename ExpectedType,
typename ActualType,
typename TEnable = typename std::enable_if<
std::is_same<ExpectedType, ActualType>::value && !std::is_same<ExpectedType, wchar_t>::value
&& !std::is_same<ExpectedType, char>::value>::type>
void AreNotEqual(_In_ const ExpectedType* expected, _In_ const ActualType* actual, _In_z_ const WCHAR* message = L"")
{
AreNotEqual(*expected, *actual, message);
AreNotEqual(*expected, *actual, message);
}
inline void AreNotEqual(_In_ const wchar_t* expected, _In_ const wchar_t* actual, _In_z_ const WCHAR* message = L"")
{
std::wstring wstrMessage(message);
ASSERT_STRNE(expected, actual) << wstrMessage.c_str();
std::wstring wstrMessage(message);
ASSERT_STRNE(expected, actual) << wstrMessage.c_str();
}
inline void AreNotEqual(_In_ const char* expected, _In_ const char* actual, _In_z_ const WCHAR* message = L"")
{
std::wstring wstrMessage(message);
ASSERT_STRNE(expected, actual) << wstrMessage.c_str();
std::wstring wstrMessage(message);
ASSERT_STRNE(expected, actual) << wstrMessage.c_str();
}
inline void AreNotEqual(_In_ wchar_t* expected, _In_ const wchar_t* actual, _In_z_ const WCHAR* message = L"")
{
std::wstring wstrMessage(message);
ASSERT_STRNE(expected, actual) << wstrMessage.c_str();
std::wstring wstrMessage(message);
ASSERT_STRNE(expected, actual) << wstrMessage.c_str();
}
inline void AreNotEqual(_In_ char* expected, _In_ const char* actual, _In_z_ const WCHAR* message = L"")
{
std::wstring wstrMessage(message);
ASSERT_STRNE(expected, actual) << wstrMessage.c_str();
std::wstring wstrMessage(message);
ASSERT_STRNE(expected, actual) << wstrMessage.c_str();
}
inline void Comment(_In_ const WCHAR* message)
{
std::wcerr << L"[ INFO ] " << message << std::endl;
std::wcerr << L"[ INFO ] " << message << std::endl;
}
inline void CommentEx(_In_z_ _Printf_format_string_ const WCHAR* format, va_list args) noexcept
{
fwprintf(stderr, L"[ INFO ] ");
vfwprintf(stderr, format, args);
fwprintf(stderr, L"\n");
fwprintf(stderr, L"[ INFO ] ");
vfwprintf(stderr, format, args);
fwprintf(stderr, L"\n");
}
inline void CommentEx(_In_z_ _Printf_format_string_ const WCHAR* format, ...) noexcept
{
va_list args;
va_start(args, format);
fwprintf(stderr, L"[ INFO ] ");
vfwprintf(stderr, format, args);
va_end(args);
fwprintf(stderr, L"\n");
va_list args;
va_start(args, format);
fwprintf(stderr, L"[ INFO ] ");
vfwprintf(stderr, format, args);
va_end(args);
fwprintf(stderr, L"\n");
}
inline void Pass(_In_z_ const WCHAR* message = L"") noexcept
{
ASSERT_TRUE(true) << message;
ASSERT_TRUE(true) << message;
}
inline void Fail(_In_z_ const WCHAR* message = L"")
{
ASSERT_TRUE(false) << message;
ASSERT_TRUE(false) << message;
}
template<typename ValueType>
template <typename ValueType>
inline void IsNull(const ValueType& ptr, _In_z_ const WCHAR* message = L"")
{
AreEqual(ptr, nullptr, message);
AreEqual(ptr, nullptr, message);
}
template<typename ValueType>
template <typename ValueType>
inline void IsNotNull(const ValueType& ptr, _In_z_ const WCHAR* message = L"")
{
AreNotEqual(ptr, nullptr, message);
AreNotEqual(ptr, nullptr, message);
}
template<typename ExceptionType>
inline void ExpectException(const std::function<void ()>& statement, const WCHAR* message = L"")
template <typename ExceptionType>
inline void ExpectException(const std::function<void()>& statement, const WCHAR* message = L"")
{
EXPECT_THROW(statement(), ExceptionType) << message;
EXPECT_THROW(statement(), ExceptionType) << message;
}
template<typename ExceptionType>
inline void ExpectException(const std::function<void ()>& statement, const std::function<void ()>& onException, const WCHAR* message = L"")
template <typename ExceptionType>
inline void ExpectException(
const std::function<void()>& statement,
const std::function<void()>& onException,
const WCHAR* message = L"")
{
EXPECT_THROW(statement(), ExceptionType) << message;
EXPECT_THROW(statement(), ExceptionType) << message;
}
inline void ExpectNoThrow(const std::function<void ()>& statement, const WCHAR* message = L"")
inline void ExpectNoThrow(const std::function<void()>& statement, const WCHAR* message = L"")
{
EXPECT_NO_THROW(statement()) << message;
EXPECT_NO_THROW(statement()) << message;
}
inline void HrSucceeded(HRESULT hr, _In_z_ const WCHAR* message = L"")
{
ASSERT_TRUE(SUCCEEDED(hr)) << message;
ASSERT_TRUE(SUCCEEDED(hr)) << message;
}
inline void HrFailed(HRESULT hr, _In_z_ const WCHAR* message = L"")
{
ASSERT_FALSE(SUCCEEDED(hr)) << message;
ASSERT_FALSE(SUCCEEDED(hr)) << message;
}
#ifdef MS_TARGET_WINDOWS
@ -202,35 +213,35 @@ static const DWORD EXCEPTION_CPLUSPLUS = static_cast<DWORD>(0xE06D7363);
inline DWORD FilterCrashExceptions(DWORD exceptionCode) noexcept
{
if ((exceptionCode == EXCEPTION_BREAKPOINT) // allow exceptions to get to the debugger
|| (exceptionCode == EXCEPTION_SINGLE_STEP) // allow exceptions to get to the debugger
|| (exceptionCode == EXCEPTION_GUARD_PAGE) // allow to crash on memory page access violation
|| (exceptionCode == EXCEPTION_STACK_OVERFLOW)) // allow to crash on stack overflow
{
return EXCEPTION_CONTINUE_SEARCH;
}
if (exceptionCode == EXCEPTION_CPLUSPLUS) // log C++ exception and pass it through
{
TestAssert::Fail(L"Test function did not crash, but exception is thrown!");
return EXCEPTION_CONTINUE_SEARCH;
}
return EXCEPTION_EXECUTE_HANDLER;
if ((exceptionCode == EXCEPTION_BREAKPOINT) // allow exceptions to get to the debugger
|| (exceptionCode == EXCEPTION_SINGLE_STEP) // allow exceptions to get to the debugger
|| (exceptionCode == EXCEPTION_GUARD_PAGE) // allow to crash on memory page access violation
|| (exceptionCode == EXCEPTION_STACK_OVERFLOW)) // allow to crash on stack overflow
{
return EXCEPTION_CONTINUE_SEARCH;
}
if (exceptionCode == EXCEPTION_CPLUSPLUS) // log C++ exception and pass it through
{
TestAssert::Fail(L"Test function did not crash, but exception is thrown!");
return EXCEPTION_CONTINUE_SEARCH;
}
return EXCEPTION_EXECUTE_HANDLER;
}
template<typename Fn>
template <typename Fn>
inline bool ExpectCrashCore(const Fn& fn, const WCHAR* message)
{
__try
{
fn();
}
__except (FilterCrashExceptions(GetExceptionCode()))
{
//Pass(message == nullptr || message[0] == L'\0' ? L"Crash occurred as expected." : message);
return true;
}
//Fail(message == nullptr || message[0] == L'\0' ? L"Test function did not crash!" : message);
return false;
__try
{
fn();
}
__except (FilterCrashExceptions(GetExceptionCode()))
{
// Pass(message == nullptr || message[0] == L'\0' ? L"Crash occurred as expected." : message);
return true;
}
// Fail(message == nullptr || message[0] == L'\0' ? L"Test function did not crash!" : message);
return false;
}
#else
@ -240,49 +251,48 @@ using SigAction = void (*)(int, siginfo_t*, void*);
// restores the old one in the destructor.
struct CrashState
{
CrashState(SigAction action) noexcept
{
sigemptyset(&m_action.sa_mask);
m_action.sa_sigaction = action;
m_action.sa_flags = SA_NODEFER;
sigaction(SIGSEGV, &m_action, &m_oldAction);
}
CrashState(SigAction action) noexcept
{
sigemptyset(&m_action.sa_mask);
m_action.sa_sigaction = action;
m_action.sa_flags = SA_NODEFER;
sigaction(SIGSEGV, &m_action, &m_oldAction);
}
~CrashState() noexcept
{
sigaction(SIGSEGV, &m_oldAction, nullptr);
}
~CrashState() noexcept
{
sigaction(SIGSEGV, &m_oldAction, nullptr);
}
private:
struct sigaction m_action{};
struct sigaction m_oldAction{};
struct sigaction m_action
{
};
struct sigaction m_oldAction
{
};
};
// Returns true if crash (segmentation fault happened)
template <class Fn>
inline bool ExpectCrashCore(const Fn& fn, const WCHAR* message)
{
static sigjmp_buf buf{};
static sigjmp_buf buf{};
// Set sigaction and save the previous action to be restored in the end of
// function.
CrashState crashState{
[](int signal, siginfo_t *si, void *arg)
{
longjmp(buf, 1);
}
};
// Set sigaction and save the previous action to be restored in the end of
// function.
CrashState crashState{[](int signal, siginfo_t* si, void* arg) { longjmp(buf, 1); }};
// setjmp originally returns 0, and when longjmp is called it returns 1.
if (!setjmp(buf))
{
fn();
return true; // must not be executed if fn() caused crash and the longjmp is executed.
}
else
{
return true; // executed if longjmp is executed in the SigAction handler.
}
// setjmp originally returns 0, and when longjmp is called it returns 1.
if (!setjmp(buf))
{
fn();
return true; // must not be executed if fn() caused crash and the longjmp is executed.
}
else
{
return true; // executed if longjmp is executed in the SigAction handler.
}
}
#endif
@ -290,10 +300,10 @@ inline bool ExpectCrashCore(const Fn& fn, const WCHAR* message)
template <typename Fn>
inline void ExpectVEC(const Fn& fn, const WCHAR* message = L"")
{
if (!ExpectCrashCore(fn, message))
{
Fail(message);
}
if (!ExpectCrashCore(fn, message))
{
Fail(message);
}
}
} // namespace TestAssert
} // namespace TestAssert

Просмотреть файл

@ -8,19 +8,18 @@ typedef wchar_t WCHAR;
class MotifCppTestBase
{
public:
MotifCppTestBase()
{}
MotifCppTestBase() {}
~MotifCppTestBase()
{
TestClassTeardown();
}
~MotifCppTestBase()
{
TestClassTeardown();
}
virtual void TestClassSetup() {}
virtual void TestClassSetup() {}
virtual void TestClassTeardown() {}
virtual void TestClassTeardown() {}
virtual void Setup() {}
virtual void Setup() {}
virtual void Teardown() {}
virtual void Teardown() {}
};

Просмотреть файл

@ -10,37 +10,33 @@
#include <vector>
#include <motifCpp/motifCppTestBase.h>
#define TEST_CLASS(className) \
struct className; \
\
struct TestClassInfo_##className final \
: Mso::UnitTests::Internal::TestClassInfoReg<TestClassInfo_##className, className> \
{ \
TestClassInfo_##className() noexcept \
: TestClassInfoRegType{ #className, __FILE__, __LINE__ } {} \
};\
\
struct className : Mso::UnitTests::Internal::TestClassBase<className, TestClassInfo_##className>
#define TEST_CLASS(className) \
struct className; \
\
struct TestClassInfo_##className final \
: Mso::UnitTests::Internal::TestClassInfoReg<TestClassInfo_##className, className> \
{ \
TestClassInfo_##className() noexcept : TestClassInfoRegType{#className, __FILE__, __LINE__} {} \
}; \
\
struct className : Mso::UnitTests::Internal::TestClassBase<className, TestClassInfo_##className>
#define TEST_METHOD(methodName) \
struct TestMethodInfo_##methodName final \
: Mso::UnitTests::Internal::TestMethodInfoReg<TestMethodInfo_##methodName> \
{ \
TestMethodInfo_##methodName() \
: TestMethodInfoRegType{ TestClassInfoType::Instance, #methodName, __LINE__ } {} \
\
void Invoke(Mso::UnitTests::TestClass& test) const override \
{ \
static_cast<TestClassType&>(test).methodName(); \
} \
}; \
virtual void methodName()
#define TEST_METHOD(methodName) \
struct TestMethodInfo_##methodName final : Mso::UnitTests::Internal::TestMethodInfoReg<TestMethodInfo_##methodName> \
{ \
TestMethodInfo_##methodName() : TestMethodInfoRegType{TestClassInfoType::Instance, #methodName, __LINE__} {} \
\
void Invoke(Mso::UnitTests::TestClass& test) const override \
{ \
static_cast<TestClassType&>(test).methodName(); \
} \
}; \
virtual void methodName()
#define TestClassComponent(x1, x2)
// Allows a test to be compiled, but not executed
#define SKIPTESTMETHOD(methodName) \
virtual void skipped_##methodName()
#define SKIPTESTMETHOD(methodName) virtual void skipped_##methodName()
namespace Mso { namespace UnitTests {
@ -51,7 +47,7 @@ struct TestMethodInfo;
template <class T>
struct TestClassInfos
{
static std::vector<TestClassInfo*> s_classInfos;
static std::vector<TestClassInfo*> s_classInfos;
};
template <class T>
@ -59,56 +55,76 @@ std::vector<TestClassInfo*> TestClassInfos<T>::s_classInfos;
struct TestClassInfo
{
TestClassInfo(const char* className, const char* fileName, int sourceLine) noexcept
: m_className { className }
, m_fileName { fileName }
, m_sourceLine { sourceLine }
{
TestClassInfos<int>::s_classInfos.push_back(this);
}
TestClassInfo(const char* className, const char* fileName, int sourceLine) noexcept
: m_className{className}, m_fileName{fileName}, m_sourceLine{sourceLine}
{
TestClassInfos<int>::s_classInfos.push_back(this);
}
const char* ClassName() const noexcept { return m_className; }
const char* FileName() const noexcept { return m_fileName; }
int SourceLine() const noexcept { return m_sourceLine; }
const std::vector<TestMethodInfo*>& MethodInfos() const noexcept { return m_methodInfos; }
static const std::vector<TestClassInfo*>& ClassInfos() noexcept { return TestClassInfos<int>::s_classInfos; }
const char* ClassName() const noexcept
{
return m_className;
}
const char* FileName() const noexcept
{
return m_fileName;
}
int SourceLine() const noexcept
{
return m_sourceLine;
}
const std::vector<TestMethodInfo*>& MethodInfos() const noexcept
{
return m_methodInfos;
}
static const std::vector<TestClassInfo*>& ClassInfos() noexcept
{
return TestClassInfos<int>::s_classInfos;
}
void AddMethodInfo(TestMethodInfo& methodInfo) noexcept
{
m_methodInfos.push_back(&methodInfo);
}
void AddMethodInfo(TestMethodInfo& methodInfo) noexcept
{
m_methodInfos.push_back(&methodInfo);
}
public: // To implement in derived classes
virtual std::unique_ptr<TestClass> CreateTest() const = 0;
virtual std::unique_ptr<TestClass> CreateTest() const = 0;
private:
const char* m_className { nullptr };
const char* m_fileName { nullptr };
int m_sourceLine { 0 };
std::vector<TestMethodInfo*> m_methodInfos;
const char* m_className{nullptr};
const char* m_fileName{nullptr};
int m_sourceLine{0};
std::vector<TestMethodInfo*> m_methodInfos;
};
struct TestMethodInfo
{
TestMethodInfo(TestClassInfo& classInfo, const char* methodName, int sourceLine) noexcept
: m_classInfo { classInfo }
, m_methodName { methodName }
, m_sourceLine { sourceLine }
{
classInfo.AddMethodInfo(*this);
}
TestMethodInfo(TestClassInfo& classInfo, const char* methodName, int sourceLine) noexcept
: m_classInfo{classInfo}, m_methodName{methodName}, m_sourceLine{sourceLine}
{
classInfo.AddMethodInfo(*this);
}
const TestClassInfo& ClassInfo() const noexcept { return m_classInfo; }
const char* MethodName() const noexcept { return m_methodName; }
int SourceLine() const noexcept { return m_sourceLine; }
const TestClassInfo& ClassInfo() const noexcept
{
return m_classInfo;
}
const char* MethodName() const noexcept
{
return m_methodName;
}
int SourceLine() const noexcept
{
return m_sourceLine;
}
public: // To implement in derived classes
virtual void Invoke(TestClass& test) const = 0;
virtual void Invoke(TestClass& test) const = 0;
private:
const TestClassInfo& m_classInfo;
const char* m_methodName { nullptr };
int m_sourceLine { 0 };
const TestClassInfo& m_classInfo;
const char* m_methodName{nullptr};
int m_sourceLine{0};
};
}} // namespace Mso::UnitTests
@ -125,15 +141,15 @@ struct TestClassBase : TestClass
template <class TClassInfo, class TTestClass>
struct TestClassInfoReg : TestClassInfo
{
using TestClassInfoRegType = TestClassInfoReg;
using TestClassInfo::TestClassInfo;
using TestClassInfoRegType = TestClassInfoReg;
using TestClassInfo::TestClassInfo;
static TClassInfo Instance;
static TClassInfo Instance;
std::unique_ptr<TestClass> CreateTest() const override
{
return std::unique_ptr<TestClass> { new TTestClass() };
}
std::unique_ptr<TestClass> CreateTest() const override
{
return std::unique_ptr<TestClass>{new TTestClass()};
}
};
template <class TClassInfo, class TTestClass>
@ -142,15 +158,15 @@ TClassInfo TestClassInfoReg<TClassInfo, TTestClass>::Instance;
template <class TMethodInfo>
struct TestMethodInfoReg : TestMethodInfo
{
using TestMethodInfoRegType = TestMethodInfoReg;
using TestMethodInfoRegType = TestMethodInfoReg;
TestMethodInfoReg(TestClassInfo& classInfo, const char* methodName, int sourceLine) noexcept
: TestMethodInfo { classInfo, methodName, sourceLine }
{
(void)&Instance; // To ensure that we create static instance
}
TestMethodInfoReg(TestClassInfo& classInfo, const char* methodName, int sourceLine) noexcept
: TestMethodInfo{classInfo, methodName, sourceLine}
{
(void)&Instance; // To ensure that we create static instance
}
static TMethodInfo Instance;
static TMethodInfo Instance;
};
template <class TMethodInfo>

Просмотреть файл

@ -7,9 +7,7 @@
class LibletAwareMemLeakDetection : public MotifCppTestBase
{
protected:
void InitLiblets() noexcept
{}
void InitLiblets() noexcept {}
void UninitLiblets() noexcept
{}
void UninitLiblets() noexcept {}
};

Просмотреть файл

@ -1,12 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
// This file is added temporary for the purpose of excluding the liblet UT's that used SEH. //
// This file is added temporary for the purpose of excluding the liblet UT's that used SEH. //
// Currently there is no support for filtering in Android. Bug # OM: 1706117 Need Filter support for Android Unit tests.
//
//
// Action item post this bug will be fixed ...
// we need to remove this file and all the occurrences of the macro TESTMETHOD_REQUIRES_SEH should be
// we need to remove this file and all the occurrences of the macro TESTMETHOD_REQUIRES_SEH should be
// replaced with TESTMETHODEX(${1}, TestCategory(RequriesSEH)).
#pragma once

Просмотреть файл

@ -24,46 +24,41 @@
// A helper macro to provide current line number as a wide char string.
//=============================================================================
#ifndef MSO_TO_STR
# define MSO_INTERNAL_TO_STR(value) #value
# define MSO_TO_STR(value) MSO_INTERNAL_TO_STR(value)
#define MSO_INTERNAL_TO_STR(value) #value
#define MSO_TO_STR(value) MSO_INTERNAL_TO_STR(value)
#endif
#ifndef MSO_WIDE_STR
# define MSO_INTERNAL_WIDE_STR(str) L ## str
# define MSO_WIDE_STR(str) MSO_INTERNAL_WIDE_STR(str)
#define MSO_INTERNAL_WIDE_STR(str) L##str
#define MSO_WIDE_STR(str) MSO_INTERNAL_WIDE_STR(str)
#endif
#define MSO_LINE_STR MSO_TO_STR(__LINE__)
#define MSO_LINE_WIDE_STR MSO_WIDE_STR(MSO_LINE_STR)
#define MSO_LINE_STR MSO_TO_STR(__LINE__)
#define MSO_LINE_WIDE_STR MSO_WIDE_STR(MSO_LINE_STR)
//=============================================================================
// TestCheckFail fails the test unconditionally.
//=============================================================================
#define TestCheckFailL(message, line) \
TestAssert::Fail(MSO_WIDE_STR("Line: " line " " message))
#define TestCheckFailL(message, line) TestAssert::Fail(MSO_WIDE_STR("Line: " line " " message))
#define TestCheckFail(message) TestCheckFailL(message, MSO_LINE_STR)
//=============================================================================
// TestCheck checks if provided expression evaluates to true.
// If check fails then it reports the line number and the failed expression.
//=============================================================================
#define TestCheckL(expr, line) \
TestAssert::IsTrue(expr, MSO_WIDE_STR("Line: " line " [ " MSO_TO_STR(expr) " ]"))
#define TestCheckL(expr, line) TestAssert::IsTrue(expr, MSO_WIDE_STR("Line: " line " [ " MSO_TO_STR(expr) " ]"))
#define TestCheck(expr) TestCheckL(expr, MSO_LINE_STR)
//=============================================================================
// TestCheckEqual checks if two provided values are equal.
// If check fails then it reports the line number and the failed expression.
// In addition the TestAssert::AreEqual reports expected and actual values.
//=============================================================================
#define TestCheckEqualL(expected, actual, line) \
TestAssert::AreEqual(expected, actual, \
MSO_WIDE_STR("Line: " line " [ " MSO_TO_STR(expected) " == " MSO_TO_STR(actual) " ]"))
TestAssert::AreEqual( \
expected, actual, MSO_WIDE_STR("Line: " line " [ " MSO_TO_STR(expected) " == " MSO_TO_STR(actual) " ]"))
#define TestCheckEqual(expected, actual) TestCheckEqualL(expected, actual, MSO_LINE_STR)
//=============================================================================
// TestCheckIgnore ignores the provided expression.
// It can be used to avoid compilation errors related to unused variables.
@ -71,17 +66,19 @@
//=============================================================================
#define TestCheckIgnore(expr) (void)expr
//=============================================================================
// TestCheckCrash expects that the provided expression causes a crash.
//=============================================================================
// Mso::IgnoreAllAsserts ignore;
#define TestCheckCrashL(expr, line) \
TestAssert::ExpectVEC([&]() { OACR_POSSIBLE_THROW; expr; }, \
MSO_WIDE_STR("Line: " line " Must crash: [ " MSO_TO_STR(expr) " ]"))
TestAssert::ExpectVEC( \
[&]() { \
OACR_POSSIBLE_THROW; \
expr; \
}, \
MSO_WIDE_STR("Line: " line " Must crash: [ " MSO_TO_STR(expr) " ]"))
#define TestCheckCrash(expr) TestCheckCrashL(expr, MSO_LINE_STR)
//=============================================================================
// TestCheckTerminate expects that the provided expression causes process termination
// with a call to std::terminate().
@ -92,38 +89,28 @@
// You should disable memory leak detection in tests that use TestCheckTerminate.
//=============================================================================
#define TestCheckTerminateL(expr, line) \
TestAssert::ExpectTerminate([&]() { expr; }, \
MSO_WIDE_STR("Line: " line " Must terminate: [ " MSO_TO_STR(expr) " ]"))
TestAssert::ExpectTerminate([&]() { expr; }, MSO_WIDE_STR("Line: " line " Must terminate: [ " MSO_TO_STR(expr) " ]"))
#define TestCheckTerminate(expr) TestCheckTerminateL(expr, MSO_LINE_STR)
//=============================================================================
// TestCheckException expects that the provided expression throws an exception.
//=============================================================================
#define TestCheckExceptionL(ex, expr, line) \
TestAssert::ExpectException<ex>([&]() { expr; }, \
MSO_WIDE_STR("Line: " line " Must throw: " MSO_TO_STR(ex) " [ " MSO_TO_STR(expr) " ]"))
TestAssert::ExpectException<ex>( \
[&]() { expr; }, MSO_WIDE_STR("Line: " line " Must throw: " MSO_TO_STR(ex) " [ " MSO_TO_STR(expr) " ]"))
#define TestCheckException(ex, expr) TestCheckExceptionL(ex, expr, MSO_LINE_STR)
//=============================================================================
// TestCheckNoThrow expects that the provided expression does not throw an exception.
//=============================================================================
#define TestCheckNoThrowL(expr, line) \
TestAssert::ExpectNoThrow([&]() { expr; }, \
MSO_WIDE_STR("Line: " line " Must not throw: [ " MSO_TO_STR(expr) " ]"))
TestAssert::ExpectNoThrow([&]() { expr; }, MSO_WIDE_STR("Line: " line " Must not throw: [ " MSO_TO_STR(expr) " ]"))
#define TestCheckNoThrow(expr) TestCheckNoThrowL(expr, MSO_LINE_STR)
//=============================================================================
// TestCheckAssert checks for the code to produce assert with specified tag.
//=============================================================================
#define TestCheckShipAssert(tag, expr) \
Statement( \
Mso::ExpectShipAssert expectAssert(tag); \
expr; \
);
#define TestCheckShipAssert(tag, expr) Statement(Mso::ExpectShipAssert expectAssert(tag); expr;);
//=============================================================================
// A macro to disable memory leak detection in unit tests where we expect crash
@ -134,12 +121,8 @@
// MemoryLeakDetectionHook::TrackPerTest m_trackLeakPerTest;
//=============================================================================
#define TEST_DISABLE_MEMORY_LEAK_DETECTION() \
StopTrackingMemoryAllocations(); \
auto restartTrackingMemoryAllocations = Mso::TCleanup::Make([&]() noexcept \
{ \
StartTrackingMemoryAllocations(); \
});
StopTrackingMemoryAllocations(); \
auto restartTrackingMemoryAllocations = Mso::TCleanup::Make([&]() noexcept { StartTrackingMemoryAllocations(); });
//=============================================================================
// Helper functions to implement TestCheckTerminate.
@ -148,49 +131,44 @@ namespace TestAssert {
struct TerminateHandlerRestorer
{
~TerminateHandlerRestorer() noexcept
{
std::set_terminate(Handler);
}
~TerminateHandlerRestorer() noexcept
{
std::set_terminate(Handler);
}
std::terminate_handler Handler;
std::terminate_handler Handler;
};
#pragma warning(push)
#pragma warning(disable:4611) // interaction between '_setjmp' and C++ object destruction is non-portable
#pragma warning(disable : 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
template <class Fn>
inline bool ExpectTerminateCore(const Fn& fn)
{
static jmp_buf buf;
static jmp_buf buf;
// Set a terminate handler and save the previous terminate handler to be restored in the end of function.
TerminateHandlerRestorer terminateRestore = {
std::set_terminate([]()
{
longjmp(buf, 1);
})
};
// Set a terminate handler and save the previous terminate handler to be restored in the end of function.
TerminateHandlerRestorer terminateRestore = {std::set_terminate([]() { longjmp(buf, 1); })};
// setjmp originally returns 0, and when longjmp is called it returns 1.
if (!setjmp(buf))
{
fn();
return false; // must not be executed if fn() caused termination and the longjmp is executed.
}
else
{
return true; // executed if longjmp is executed in the terminate handler.
}
// setjmp originally returns 0, and when longjmp is called it returns 1.
if (!setjmp(buf))
{
fn();
return false; // must not be executed if fn() caused termination and the longjmp is executed.
}
else
{
return true; // executed if longjmp is executed in the terminate handler.
}
}
#pragma warning(pop)
template <class Fn>
inline void ExpectTerminate(const Fn& fn, const WCHAR* message = L"")
{
if (!ExpectTerminateCore(fn))
{
Fail(message == nullptr || message[0] == L'\0' ? L"Test function did not terminate!" : message);
}
if (!ExpectTerminateCore(fn))
{
Fail(message == nullptr || message[0] == L'\0' ? L"Test function did not terminate!" : message);
}
}
} // namespace TestAssert

Просмотреть файл

@ -3,7 +3,7 @@
#include <motifCpp/gTestAdapter.h>
int main(int argc, char **argv)
int main(int argc, char** argv)
{
Mso::UnitTests::GTest::RegisterUnitTests();
::testing::InitGoogleTest(&argc, argv);

Просмотреть файл

@ -28,7 +28,7 @@
#endif
#if defined(__cplusplus)
#define __extern_c extern "C"
#define __extern_c extern "C"
#define __extern_cplus extern "C++"
#else
#define __extern_c
@ -37,7 +37,7 @@
#ifndef __noreturn
#ifndef __clang__
#define __noreturn __declspec( noreturn )
#define __noreturn __declspec(noreturn)
#else
#define __noreturn __attribute__((noreturn))
#endif
@ -51,21 +51,18 @@
#define _Sealed_method_ __oacr_sealed_method
#endif // _Sealed_method_
#if !defined(_Sealed_class_)
// use _Sealed_class_ to specify C# style 'sealed' behavior for classes
#define _Sealed_class_ __oacr_sealed_class
#endif // _Sealed_class_
#if !defined(_SA_deprecated_)
// use _SA_deprecated_ to mark functions or classes that should not be called any more
// pass the replacement function or class as an argument to the macro
#define _SA_deprecated_(NewFunctionName) __oacr_sa_deprecated(NewFunctionName)
#endif // _SA_deprecated_
#if( defined(OACR) && OACR )
#if (defined(OACR) && OACR)
// use OACR_MARK_CLASS_DEPRECATED to mark classes that should not be used any more
// this macro is a workaround for template classes. Vanilla classes should use _SA_deprecated_
// pass the replacement class as argument to the macro
@ -74,7 +71,6 @@
#define OACR_MARK_CLASS_DEPRECATED(NewFunctionName)
#endif
#if !defined(_SA_deprecated_staging_)
// use _SA_deprecated_staging_ to mark functions or classes that should not be called any more
// pass the replacement function or class as an argument to the macro
@ -83,17 +79,16 @@
#define _SA_deprecated_staging_(NewFunctionName) __oacr_sa_deprecated_staging(NewFunctionName)
#endif // _SA_deprecated_staging_
#if( defined(OACR) && OACR )
#if (defined(OACR) && OACR)
// use OACR_MARK_CLASS_DEPRECATED_STAGING to mark classes that should not be used any more
// this macro is a workaround for template classes. Vanilla classes should use _SA_deprecated_
// pass the replacement function as argument to the macro
#define OACR_MARK_CLASS_DEPRECATED_STAGING(NewFunctionName) _SA_deprecated_staging_(NewFunctionName) void OACRMarkClass();
#define OACR_MARK_CLASS_DEPRECATED_STAGING(NewFunctionName) \
_SA_deprecated_staging_(NewFunctionName) void OACRMarkClass();
#else
#define OACR_MARK_CLASS_DEPRECATED_STAGING(NewFunctionName)
#endif
#if !defined(_Intl_deprecated_)
// annotation used by warning UNMARKED_INTL_DEPRECATED_FUNCTION (25114)
// to mark deprecated functions using LCID parameters
@ -101,13 +96,11 @@
#define _Intl_deprecated_ __oacr_intl_deprecated
#endif // _Intl_deprecated_
#if !defined(_Oleo_deprecated_)
// Office specifix annotation used by the OLEO effort
#define _Oleo_deprecated_( NewFunctionName ) __oacr_oleo_deprecated(NewFunctionName)
#define _Oleo_deprecated_(NewFunctionName) __oacr_oleo_deprecated(NewFunctionName)
#endif // _Oleo_deprecated_
#if !defined(_Norefcapture_asynclambda_)
//
// use _Norefcapture_asynclambda_ on async function. This warns user of possible unsafe variable capture.
@ -146,7 +139,7 @@
//
// Example:
// _Noexcept_mayterminate_ignore_("what") void Foo() noexcept;
#define _Noexcept_mayterminate_ignore_(FunctionName) __oacr_noexcept_mayterminate_ignore(FunctionName)
#define _Noexcept_mayterminate_ignore_(FunctionName) __oacr_noexcept_mayterminate_ignore(FunctionName)
#endif // _Noexcept_mayterminate_ignore_
#if !defined(_Dont_swap_)
@ -163,33 +156,29 @@
#define _Rpc_ __oacr_rpc
#endif // _Rpc_
#if !defined(_RequireNoThrow_)
// use _RequireNoThrow_ inside a compound statement to indicate that the rest of the block
// should not emit exceptions.
#define _RequireNoThrow_ __oacr_requireNoThrow
#endif // _RequireNoThrow_
#if !defined(_Canthrow_)
// use _Canthrow_ for method declarations of template classes that have throwing and non-throwing
// specializations to suppress warning FUNC_COULD_BE_NOTHROW (25307).
#define _Canthrow_ __oacr_canthrow
#endif // __requireNoThrow
#if !defined(_Genericfunctype_)
// use _Genericfunctype_ for function typedefs used for arrays of functions of different function types.
// if the typedef is marked as _Genericfunctype_, OACR will not generate DIFFERENT_CALLING_CONVENTION (25018) warnings
// e.g. typedef _Genericfunctype_ void (*FUNCPTR)();
#if( defined(OACR) && OACR )
#if (defined(OACR) && OACR)
#define _Genericfunctype_ __oacr_genericfunctype
#else
#define _Genericfunctype_
#endif
#endif // _Genericfunctype_
#if !defined(_Nothrowfunctype_)
// use _Nothrowfunctype_ for function typedefs of non exception throwing function pointers
// e.g. typedef _Nothrowfunctype_ void (*FUNCPTR)();
@ -197,7 +186,6 @@
#define _Nothrowfunctype_ __oacr_nothrowfunctype
#endif // _Nothrowfunctype_
#if !defined(_BindReturn_)
// stronger than __checkReturn, typically used by functions that return
// a pointer to an allocated object
@ -211,7 +199,6 @@
#define _BindReturn_ __oacr_bindReturn
#endif // _BindReturn_
#if !defined(_Memberinitializer_)
// use _Memberinitializer_ for init functions that initialize all members of a class
// e.g.:
@ -226,7 +213,6 @@
#define _Memberinitializer_ __oacr_memberinitializer
#endif // _Memberinitializer_
#if !defined(_Noheap_)
// use _Noheap_ classes that should not be instantiated on the heap
// e.g.:
@ -239,8 +225,7 @@
#define _Noheap_ __oacr_noheap
#endif // _Noheap_
#if( defined(OACR) && OACR )
#if (defined(OACR) && OACR)
// use OACR_MARK_CLASS_NOHEAP to mark classes that should not be instantiated on the heap
// this macro is a workaround for template classes. Vanilla classes should use _Noheap_
#define OACR_MARK_CLASS_NOHEAP _Noheap_ void OACRMarkClass();
@ -248,7 +233,6 @@
#define OACR_MARK_CLASS_NOHEAP
#endif
#if !defined(_Unsafe_string_api_)
// use _Unsafe_string_api_ to phase out functions that pass unbound writable buffers
// e.g.
@ -256,12 +240,12 @@
#define _Unsafe_string_api_ __oacr_unsafe_string_api
#endif // _Unsafe_string_api_
#if !defined(_Needsreview_)
// use _Needsreview_ to mark functions whose calls need to be reviewed for a
// special reason.
// e.g. a wrapper function to another function that needs to be reviewed
//_Needsreview_ __inline BOOL MsoGetStringTypeExW(LCID Locale, DWORD dwInfoType, LPCWSTR lpSrcStr, int cchSrc, LPWORD lpCharType)
//_Needsreview_ __inline BOOL MsoGetStringTypeExW(LCID Locale, DWORD dwInfoType, LPCWSTR lpSrcStr, int cchSrc, LPWORD
//lpCharType)
//{
// return OACR_REVIEWED_CALL("hannesr", GetStringTypeExW(Locale, dwInfoType, lpSrcStr, cchSrc, lpCharType));
//}
@ -269,7 +253,6 @@
#define _Needsreview_ __oacr_needsreview
#endif // _Needsreview_
#if !defined(_Notrunccast_)
// use _Notrunccast_ to find unsafe truncating cast on allocating functions taking
// a 16 bit size parameter
@ -278,96 +261,95 @@
#define _Notrunccast_ __oacr_notrunccast
#endif // _Notrunccast_
#if !defined(_Noinference_)
// keyword to disable (wrong) Hungarian inference of __count annotations
// inference is disabled for the all formals of the function
// e.g. _Noinference_ void FreePv( void* pv, size_t cb );
#define _Noinference_ __oacr_noinference
#define _Noinference_ __oacr_noinference
#endif // _Noinference_
#if !defined(_Allow_implicit_ctor_)
// use _Allow_implicit_ctor_ when a constructors is expected to be implicit.
//
// e.g.
//
//
// _Allow_implicit_ctor_ CPoint( const POINT& );
//
#define _Allow_implicit_ctor_ __oacr_allow_implicit_ctor
#endif // _Allow_implicit_ctor_
// Pre Orcas style annotations are deprecated
#if( OACR_DEPRECATED )
#if (OACR_DEPRECATED)
#if !defined(__sealed_method)
#define __sealed_method _Sealed_method_
#define __sealed_method _Sealed_method_
#endif
#if !defined(__sealed_class)
#define __sealed_class _Sealed_class_
#define __sealed_class _Sealed_class_
#endif
#if !defined(__sa_deprecated)
#define __sa_deprecated(NewFunctionName) _SA_deprecated_(NewFunctionName)
#define __sa_deprecated(NewFunctionName) _SA_deprecated_(NewFunctionName)
#endif
#if !defined(__intl_deprecated)
#define __intl_deprecated _Intl_deprecated_
#define __intl_deprecated _Intl_deprecated_
#endif
#if !defined(__oleo_deprecated)
#define __oleo_deprecated( NewFunctionName ) _Oleo_deprecated_(NewFunctionName)
#define __oleo_deprecated(NewFunctionName) _Oleo_deprecated_(NewFunctionName)
#endif
#if !defined(__rpc)
#define __rpc _Rpc_
#define __rpc _Rpc_
#endif
#if !defined(__requireNoThrow)
#define __requireNoThrow _RequireNoThrow_
#define __requireNoThrow _RequireNoThrow_
#endif
#if !defined(__canthrow)
#define __canthrow _Canthrow_
#define __canthrow _Canthrow_
#endif
#if !defined(__genericfunctype)
#define __genericfunctype _Genericfunctype_
#define __genericfunctype _Genericfunctype_
#endif
#if !defined(__nothrowfunctype)
#define __nothrowfunctype _Nothrowfunctype_
#define __nothrowfunctype _Nothrowfunctype_
#endif
#if !defined(__bindReturn)
#define __bindReturn _BindReturn_
#define __bindReturn _BindReturn_
#endif
#if !defined(__memberinitializer)
#define __memberinitializer _Memberinitializer_
#define __memberinitializer _Memberinitializer_
#endif
#if !defined(__noheap)
#define __noheap _Noheap_
#define __noheap _Noheap_
#endif
#if !defined(__nostack)
#define __nostack // not supported
#define __nostack // not supported
#endif
#if !defined(__unsafe_string_api)
#define __unsafe_string_api _Unsafe_string_api_
#define __unsafe_string_api _Unsafe_string_api_
#endif
#if !defined(__needsreview)
#define __needsreview _Needsreview_
#define __needsreview _Needsreview_
#endif
#if !defined(__notrunccast)
#define __notrunccast _Notrunccast_
#define __notrunccast _Notrunccast_
#endif
#if !defined(__noinference)
#define __noinference _Noinference_
#define __noinference _Noinference_
#endif
#if !defined(__min_function)
#define __min_function // deprecated, use range annotations
#define __min_function // deprecated, use range annotations
#endif
#if !defined(__max_function)
#define __max_function // deprecated, use range annotations
#define __max_function // deprecated, use range annotations
#endif
#if !defined(__printf_format_string)
#define __printf_format_string _Printf_format_string_
#define __printf_format_string _Printf_format_string_
#endif
#undef __callback
#define __callback _Callback_
#define __callback _Callback_
#if !defined(__sa_sealed) // use __sealed_method and __sealed_class instead
#if( defined(OACR) && OACR )
#if (defined(OACR) && OACR)
#define __sa_sealed __declspec("_Sealed_")
#else
#define __sa_sealed
@ -382,13 +364,13 @@
#if !defined(OACR_USE_PTR)
// use to suppress constness and related warnings:
// NONCONST_LOCAL (25003), NONCONST_PARAM( 25004), NONCONST_FUNCTION (25005),
// NONCONST_LOCAL (25003), NONCONST_PARAM( 25004), NONCONST_FUNCTION (25005),
// NONCONST_LOCAL_BUFFERPTR (25032), NONCONST_BUFFER_PARAM (25033)
#if( defined(OACR) && OACR )
__extern_c void OACRUsePtr( void* p );
#define OACR_USE_PTR( p ) OACRUsePtr( p )
#if (defined(OACR) && OACR)
__extern_c void OACRUsePtr(void* p);
#define OACR_USE_PTR(p) OACRUsePtr(p)
#else
#define OACR_USE_PTR( p ) __oacr_noop()
#define OACR_USE_PTR(p) __oacr_noop()
#endif
#endif // OACR_USE_PTR
@ -400,7 +382,7 @@ __extern_c void OACRUsePtr( void* p );
// is spread across both ctor initializer list and a _Memberinitializer_ method).
// NOTES: This is functionally to OACR_USE_PTR(&m).
// Contrast with OACR_MEMBER_IS_INITIALIZED_IN_MEMBERINITIALIZER.
#define OACR_MEMBER_IS_INITIALIZED_IN_CTOR( m ) OACR_USE_PTR( &m )
#define OACR_MEMBER_IS_INITIALIZED_IN_CTOR(m) OACR_USE_PTR(&m)
#endif // OACR_MEMBER_IS_INITIALIZED_IN_CTOR
#if !defined(OACR_MEMBER_IS_INITIALIZED_IN_MEMBERINITIALIZER)
@ -410,13 +392,13 @@ __extern_c void OACRUsePtr( void* p );
// is spread across both ctor initializer list and a _Memberinitializer_ method).
// NOTES: This is functionally equivalent to OACR_USE_PTR(&m).
// Contrast with OACR_MEMBER_IS_INITIALIZED_IN_CTOR.
#define OACR_MEMBER_IS_INITIALIZED_IN_MEMBERINITIALIZER( m ) OACR_USE_PTR( &m )
#define OACR_MEMBER_IS_INITIALIZED_IN_MEMBERINITIALIZER(m) OACR_USE_PTR(&m)
#endif // OACR_MEMBER_IS_INITIALIZED_IN_MEMBERINITIALIZER
#endif // !RC_INVOKED
#if !defined(OACR_POSSIBLE_THROW)
// use to suppress __nothrow related warnings NOTHROW_FUNC_THROWS (25306) and FUNC_COULD_BE_NOTHROW (25307)
#if( defined(OACR) && OACR )
#if (defined(OACR) && OACR)
__extern_cplus void OACRPossibleThrow();
#define OACR_POSSIBLE_THROW OACRPossibleThrow()
#else
@ -425,12 +407,19 @@ __extern_cplus void OACRPossibleThrow();
#endif // OACR_POSSIBLE_THROW
#if !defined(OACR_ASSUME_NOTHROW_BEGIN)
// use with OACR_ASSUME_NOTHROW_END to suppress NOTHROW_FUNC_THROWS warnings around functions that don't throw in this context
// macro pair needs to be on the same scope
#if( defined(OACR) && OACR )
// use with OACR_ASSUME_NOTHROW_END to suppress NOTHROW_FUNC_THROWS warnings around functions that don't throw in this
// context macro pair needs to be on the same scope
#if (defined(OACR) && OACR)
__extern_c __noreturn void OACRNoReturn();
#define OACR_ASSUME_NOTHROW_BEGIN try{
#define OACR_ASSUME_NOTHROW_END }catch(...){ OACRNoReturn(); }
#define OACR_ASSUME_NOTHROW_BEGIN \
try \
{
#define OACR_ASSUME_NOTHROW_END \
} \
catch (...) \
{ \
OACRNoReturn(); \
}
#else
#define OACR_ASSUME_NOTHROW_BEGIN
#define OACR_ASSUME_NOTHROW_END
@ -439,86 +428,81 @@ __extern_c __noreturn void OACRNoReturn();
#if !defined(UNREFERENCED_OACR)
// use to function staticness and related warnings: STATIC_FUNCTION (25007)
#if( defined(OACR) && OACR )
#define UNREFERENCED_OACR( p ) __assume( p == p )
#if (defined(OACR) && OACR)
#define UNREFERENCED_OACR(p) __assume(p == p)
#else
#define UNREFERENCED_OACR( p )
#define UNREFERENCED_OACR(p)
#endif
#endif // UNREFERENCED_OACR
#if !defined(OACR_OWN_PTR)
// can be used for objects that attach themselves to an owner
// in their constructors
#if( defined(OACR) && OACR )
__extern_c void OACROwnPtr( const void* p );
#define OACR_OWN_PTR( p ) OACROwnPtr( p )
#if (defined(OACR) && OACR)
__extern_c void OACROwnPtr(const void* p);
#define OACR_OWN_PTR(p) OACROwnPtr(p)
#else
#define OACR_OWN_PTR( p ) __oacr_noop()
#define OACR_OWN_PTR(p) __oacr_noop()
#endif
#endif // OACR_OWN_PTR
#if !defined(OACR_PTR_NOT_NULL)
// tells OACR that a pointer is not null at this point
#if( defined(OACR) && OACR )
#define OACR_PTR_NOT_NULL( p ) OACR_ASSUME( 0 != p )
#if (defined(OACR) && OACR)
#define OACR_PTR_NOT_NULL(p) OACR_ASSUME(0 != p)
#else
#define OACR_PTR_NOT_NULL( p ) __oacr_noop()
#define OACR_PTR_NOT_NULL(p) __oacr_noop()
#endif
#endif // OACR_PTR_NOT_NULL
#if !defined(OACR_NOT_IMPLEMENTED_MEMBER)
#if( defined(OACR) && OACR )
#define OACR_NOT_IMPLEMENTED_MEMBER OACR_USE_PTR( (void*)this )
#if (defined(OACR) && OACR)
#define OACR_NOT_IMPLEMENTED_MEMBER OACR_USE_PTR((void*)this)
#else
#define OACR_NOT_IMPLEMENTED_MEMBER
#endif
#endif // OACR_NOT_IMPLEMENTED_MEMBER
#if !defined(OACR_DECLARE_FILLER)
#if( defined(OACR) && OACR )
#define OACR_DECLARE_FILLER( type, inst ) type __filler##inst;
#if (defined(OACR) && OACR)
#define OACR_DECLARE_FILLER(type, inst) type __filler##inst;
#else
#define OACR_DECLARE_FILLER( type, inst )
#define OACR_DECLARE_FILLER(type, inst)
#endif
#endif // OACR_DECLARE_FILLER
// use this macro once you have inspected warnings FUNCTION_NEEDS_REVIEW (25028)
#if !defined(OACR_REVIEWED_CALL)
#if( defined(OACR) && OACR )
#if (defined(OACR) && OACR)
__extern_c void __OACRReviewedCall();
#define OACR_REVIEWED_CALL( reviewer, functionCall ) ( __OACRReviewedCall(), functionCall )
#define OACR_REVIEWED_CALL(reviewer, functionCall) (__OACRReviewedCall(), functionCall)
#else
#define OACR_REVIEWED_CALL( reviewer, functionCall ) functionCall
#define OACR_REVIEWED_CALL(reviewer, functionCall) functionCall
#endif
#endif // OACR_REVIEWED_CALL
// use this macro once you have inspected warnings URL_NEEDS_TO_BE_REVIEWED (25085)
#if !defined(OACR_REVIEWED_URL)
#if( defined(OACR) && OACR )
#if (defined(OACR) && OACR)
__extern_c void __OACRReviewedUrl();
#define OACR_REVIEWED_URL( reviewer, reviewedUrl ) ( __OACRReviewedUrl(), reviewedUrl )
#define OACR_REVIEWED_URL(reviewer, reviewedUrl) (__OACRReviewedUrl(), reviewedUrl)
#else
#define OACR_REVIEWED_URL( reviewer, reviewedUrl ) reviewedUrl
#define OACR_REVIEWED_URL(reviewer, reviewedUrl) reviewedUrl
#endif
#endif // OACR_REVIEWED_URL
#if !defined(OACR_DONT_SWAP)
// use to suppress warnings MISSING_MEMBER_SWAP (25146) for nonswappable data members like refcounts, critical sections, etc.
#if( defined(OACR) && OACR )
__extern_c void OACRDontSwap( void* p );
#define OACR_DONT_SWAP( m ) OACRDontSwap( &( m ) )
// use to suppress warnings MISSING_MEMBER_SWAP (25146) for nonswappable data members like refcounts, critical sections,
// etc.
#if (defined(OACR) && OACR)
__extern_c void OACRDontSwap(void* p);
#define OACR_DONT_SWAP(m) OACRDontSwap(&(m))
#else
#define OACR_DONT_SWAP( m ) __oacr_noop()
#define OACR_DONT_SWAP(m) __oacr_noop()
#endif
#endif // OACR_DONT_SWAP
#if( defined(OACR) && OACR && defined(_WINDEF_) && 0 )
#if (defined(OACR) && OACR && defined(_WINDEF_) && 0)
// redefine FALSE & TRUE for better HRESULT<->BOOL conversion detection
#if defined(FALSE)
@ -543,11 +527,11 @@ __extern_c void OACRDontSwap( void* p );
// p->Foo();
#if !defined(OACR_WARNING_PUSH)
#if( defined(OACR) && OACR && !defined(OACR_NO_WARNING_MACROS) )
#if( 1400 <=_MSC_VER )
#define OACR_WARNING_PUSH __pragma ( warning( push ) )
#if (defined(OACR) && OACR && !defined(OACR_NO_WARNING_MACROS))
#if (1400 <= _MSC_VER)
#define OACR_WARNING_PUSH __pragma(warning(push))
#else
#define OACR_WARNING_PUSH __pragma ( prefast( push ) )
#define OACR_WARNING_PUSH __pragma(prefast(push))
#endif
#else
#define OACR_WARNING_PUSH
@ -555,11 +539,11 @@ __extern_c void OACRDontSwap( void* p );
#endif
#if !defined(OACR_WARNING_POP)
#if( defined(OACR) && OACR && !defined(OACR_NO_WARNING_MACROS) )
#if( 1400 <=_MSC_VER )
#define OACR_WARNING_POP __pragma ( warning( pop ) )
#if (defined(OACR) && OACR && !defined(OACR_NO_WARNING_MACROS))
#if (1400 <= _MSC_VER)
#define OACR_WARNING_POP __pragma(warning(pop))
#else
#define OACR_WARNING_POP __pragma ( prefast( pop ) )
#define OACR_WARNING_POP __pragma(prefast(pop))
#endif
#else
#define OACR_WARNING_POP
@ -567,38 +551,38 @@ __extern_c void OACRDontSwap( void* p );
#endif
#if !defined(OACR_WARNING_ENABLE)
#if( defined(OACR) && OACR && !defined(OACR_NO_WARNING_MACROS) )
#if( 1400 <=_MSC_VER )
#define OACR_WARNING_ENABLE( cWarning, comment ) __pragma ( warning( default: __WARNING_##cWarning ) )
#if (defined(OACR) && OACR && !defined(OACR_NO_WARNING_MACROS))
#if (1400 <= _MSC_VER)
#define OACR_WARNING_ENABLE(cWarning, comment) __pragma(warning(default : __WARNING_##cWarning))
#else
#define OACR_WARNING_ENABLE( cWarning, comment )
#define OACR_WARNING_ENABLE(cWarning, comment)
#endif
#else
#define OACR_WARNING_ENABLE( cWarning, comment )
#define OACR_WARNING_ENABLE(cWarning, comment)
#endif
#endif
#if !defined(OACR_WARNING_DISABLE)
#if( defined(OACR) && OACR && !defined(OACR_NO_WARNING_MACROS) )
#if( 1400 <=_MSC_VER )
#define OACR_WARNING_DISABLE( cWarning, comment ) __pragma ( warning( disable: __WARNING_##cWarning ) )
#if (defined(OACR) && OACR && !defined(OACR_NO_WARNING_MACROS))
#if (1400 <= _MSC_VER)
#define OACR_WARNING_DISABLE(cWarning, comment) __pragma(warning(disable : __WARNING_##cWarning))
#else
#define OACR_WARNING_DISABLE( cWarning, comment ) __pragma ( prefast( disable: __WARNING_##cWarning, comment ) )
#define OACR_WARNING_DISABLE(cWarning, comment) __pragma(prefast(disable : __WARNING_##cWarning, comment))
#endif
#else
#define OACR_WARNING_DISABLE( cWarning, comment )
#define OACR_WARNING_DISABLE(cWarning, comment)
#endif
#endif
#if !defined(OACR_WARNING_SUPPRESS)
#if( defined(OACR) && OACR && !defined(OACR_NO_WARNING_MACROS) )
#if( 1400 <=_MSC_VER )
#define OACR_WARNING_SUPPRESS( cWarning, comment ) __pragma ( warning( suppress: __WARNING_##cWarning ) )
#if (defined(OACR) && OACR && !defined(OACR_NO_WARNING_MACROS))
#if (1400 <= _MSC_VER)
#define OACR_WARNING_SUPPRESS(cWarning, comment) __pragma(warning(suppress : __WARNING_##cWarning))
#else
#define OACR_WARNING_SUPPRESS( cWarning, comment ) __pragma ( prefast( suppress: __WARNING_##cWarning, comment) )
#define OACR_WARNING_SUPPRESS(cWarning, comment) __pragma(prefast(suppress : __WARNING_##cWarning, comment))
#endif
#else
#define OACR_WARNING_SUPPRESS( cWarning, comment )
#define OACR_WARNING_SUPPRESS(cWarning, comment)
#endif
#endif
@ -608,54 +592,53 @@ __extern_c void OACRDontSwap( void* p );
// if( g_pRoot == NULL ) // global variable g_pRoot
// {
// InitRoot();
// OACR_ASSUME( NULL != g_pRoot );
// OACR_ASSUME( NULL != g_pRoot );
// }
// g_pRoot->Traverse(); // without OACR_ASSUME this would cause warning 11
#if( defined(OACR) && OACR )
#define OACR_ASSUME( fCondition ) __assume( fCondition )
#if (defined(OACR) && OACR)
#define OACR_ASSUME(fCondition) __assume(fCondition)
#elif defined(Assert)
#define OACR_ASSUME( fCondition ) Assert( fCondition )
#define OACR_ASSUME(fCondition) Assert(fCondition)
#else
#define OACR_ASSUME( fCondition ) __oacr_noop()
#define OACR_ASSUME(fCondition) __oacr_noop()
#endif
// macro to tell OACR that a string is null terminated at this point of execution
#if( defined(OACR) && OACR && defined(_Post_z_) )
__extern_c void __OACRAssumeNullterminated( _Post_z_ const char* sz );
#define OACR_ASSUME_NULLTERMINATED( string ) __OACRAssumeNullterminated( (const char*)string )
#if (defined(OACR) && OACR && defined(_Post_z_))
__extern_c void __OACRAssumeNullterminated(_Post_z_ const char* sz);
#define OACR_ASSUME_NULLTERMINATED(string) __OACRAssumeNullterminated((const char*)string)
#else
#define OACR_ASSUME_NULLTERMINATED( string ) __oacr_noop()
#define OACR_ASSUME_NULLTERMINATED(string) __oacr_noop()
#endif
// macro to tell OACR that a pointer is null valid at this point of execution
#if( defined(OACR) && OACR && defined(_Post_valid_) )
__extern_c void __OACRAssumeValid( _Post_valid_ const void* pv );
#define OACR_ASSUME_VALID( ptr ) __OACRAssumeValid( ptr )
#if (defined(OACR) && OACR && defined(_Post_valid_))
__extern_c void __OACRAssumeValid(_Post_valid_ const void* pv);
#define OACR_ASSUME_VALID(ptr) __OACRAssumeValid(ptr)
#else
#define OACR_ASSUME_VALID( ptr ) __oacr_noop()
#define OACR_ASSUME_VALID(ptr) __oacr_noop()
#endif
// macro to tell OACR that a buffer has a certain readable extent at this point of execution
// it can be used to silent noisy espX INCORRECT_ANNOTATION warnings
#if( defined(OACR) && OACR && defined(_Post_bytecount_) )
__extern_c void __OACRAssumeByteCount( _Post_bytecount_(cb) const void* pv, size_t cb );
#define OACR_ASSUME_BYTECOUNT( pv, cb ) __OACRAssumeByteCount( pv, cb )
#if (defined(OACR) && OACR && defined(_Post_bytecount_))
__extern_c void __OACRAssumeByteCount(_Post_bytecount_(cb) const void* pv, size_t cb);
#define OACR_ASSUME_BYTECOUNT(pv, cb) __OACRAssumeByteCount(pv, cb)
#else
#define OACR_ASSUME_BYTECOUNT( pv, cb ) __oacr_noop()
#define OACR_ASSUME_BYTECOUNT(pv, cb) __oacr_noop()
#endif
// macro indicate lambda mayterminate
#if( defined(OACR) && OACR && defined(__cplusplus))
#if (defined(OACR) && OACR && defined(__cplusplus))
void _lambda_noexcept_mayterminate_() noexcept {};
#define OACR_LAMBDA_NOEXCEPT_MAYTERMINATE _lambda_noexcept_mayterminate_()
#define OACR_NOEXCEPT_MAYTERMINATE _lambda_noexcept_mayterminate_()
@ -665,7 +648,7 @@ void _lambda_noexcept_mayterminate_() noexcept {};
#endif
// macro indicate mayterminate ignore stl
#if( defined(OACR) && OACR && defined(__cplusplus))
#if (defined(OACR) && OACR && defined(__cplusplus))
void _noexcept_mayterminate_ignore_stl_() noexcept {};
#define OACR_NOEXCEPT_MAYTERMINATE_IGNORE_STL _noexcept_mayterminate_ignore_stl_()
#else
@ -673,28 +656,28 @@ void _noexcept_mayterminate_ignore_stl_() noexcept {};
#endif
// macro indicate mayterminate ignore
#if( defined(OACR) && OACR && defined(__cplusplus))
#if (defined(OACR) && OACR && defined(__cplusplus))
__extern_c void _noexcept_mayterminate_ignore_(const char*) noexcept;
#define OACR_NOEXCEPT_MAYTERMINATE_IGNORE( funcs ) _noexcept_mayterminate_ignore_(funcs)
#define OACR_NOEXCEPT_MAYTERMINATE_IGNORE(funcs) _noexcept_mayterminate_ignore_(funcs)
#else
#define OACR_NOEXCEPT_MAYTERMINATE_IGNORE( funcs ) __oacr_noop()
#define OACR_NOEXCEPT_MAYTERMINATE_IGNORE(funcs) __oacr_noop()
#endif
// OACR custom plugin specific extensions
//=======================================================================
#define _Callback_ __oacr_callback
#define _Callback_ __oacr_callback
//======================================================================
// OACR custom attributes
// OACR custom plugin specific extensions
#if( _USE_DECLSPECS_FOR_SAL )
#if (_USE_DECLSPECS_FOR_SAL)
#ifndef _SA_SPECSTRIZE
#define _SA_SPECSTRIZE( x ) #x
#define _SA_SPECSTRIZE(x) #x
#endif
__ANNOTATION(_Callback_(void));
@ -707,8 +690,8 @@ __ANNOTATION(_Intl_deprecated_(void));
__ANNOTATION(_Noinference_(void));
__ANNOTATION(_Canthrow_(void));
__ANNOTATION(_BindReturn_(void));
__ANNOTATION(_SA_deprecated_(__AuToQuOtE char *));
__ANNOTATION(_Oleo_deprecated_(__AuToQuOtE char *));
__ANNOTATION(_SA_deprecated_(__AuToQuOtE char*));
__ANNOTATION(_Oleo_deprecated_(__AuToQuOtE char*));
__ANNOTATION(_Genericfunctype_(void));
__ANNOTATION(__nothrowfunctype(void));
__ANNOTATION(_Noheap_(void));
@ -717,36 +700,38 @@ __ANNOTATION(_Sealed_(void));
__ANNOTATION(_Allow_implicit_ctor_(void));
__ANNOTATION(_Norefcapture_asynclambda_(void));
__ANNOTATION(_Nodecl_lambda_(void));
__ANNOTATION(_Noexcept_maythrow_( void ) );
__ANNOTATION(_Noexcept_mayterminate_( void ));
__ANNOTATION(_Noexcept_mayterminate_ignore_( __AuToQuOtE char * ));
__ANNOTATION(_Dont_swap_( void ));
__ANNOTATION(_Noexcept_maythrow_(void));
__ANNOTATION(_Noexcept_mayterminate_(void));
__ANNOTATION(_Noexcept_mayterminate_ignore_(__AuToQuOtE char*));
__ANNOTATION(_Dont_swap_(void));
#define __oacr_callback __declspec("_Callback_")
#define __oacr_rpc __declspec("_Rpc_")
#define __oacr_sealed_method __declspec("_Sealed_")
#define __oacr_memberinitializer __declspec("_Memberinitializer_")
#define __oacr_unsafe_string_api __declspec("_Unsafe_string_api_")
#define __oacr_needsreview __declspec("_Needsreview_")
#define __oacr_intl_deprecated __declspec("_Intl_deprecated_")
#define __oacr_noinference __declspec("_Noinference_")
#define __oacr_canthrow __declspec("_Canthrow_")
#define __oacr_bindReturn __declspec("_BindReturn_")
#define __oacr_sa_deprecated(NewFunctionName) __declspec("_SA_deprecated_("_SA_SPECSTRIZE(NewFunctionName)")")
#define __oacr_sa_deprecated_staging(NewFunctionName) __declspec("_SA_deprecated_staging_("_SA_SPECSTRIZE(NewFunctionName)")")
#define __oacr_oleo_deprecated(NewFunctionName) __declspec("_Oleo_deprecated_("_SA_SPECSTRIZE(NewFunctionName)")")
#define __oacr_genericfunctype __declspec("_Genericfunctype_")
#define __oacr_nothrowfunctype __declspec("__nothrowfunctype")
#define __oacr_noheap __declspec("_Noheap_")
#define __oacr_notrunccast __declspec("_Notrunccast_")
#define __oacr_sealed_class __declspec("_Sealed_")
#define __oacr_allow_implicit_ctor __declspec("_Allow_implicit_ctor_")
#define __oacr_norefcapture_asynclambda __declspec("_Norefcapture_asynclambda_")
#define __oacr_nodecl_lambda __declspec("_Nodecl_lambda_")
#define __oacr_noexcept_maythrow __declspec("_Noexcept_maythrow_")
#define __oacr_noexcept_mayterminate __declspec("_Noexcept_mayterminate_")
#define __oacr_noexcept_mayterminate_ignore(FunctionName) __declspec("_Noexcept_mayterminate_ignore_("_SA_SPECSTRIZE(FunctionName)")")
#define __oacr_dont_swap __declspec("_Dont_swap_")
#define __oacr_callback __declspec("_Callback_")
#define __oacr_rpc __declspec("_Rpc_")
#define __oacr_sealed_method __declspec("_Sealed_")
#define __oacr_memberinitializer __declspec("_Memberinitializer_")
#define __oacr_unsafe_string_api __declspec("_Unsafe_string_api_")
#define __oacr_needsreview __declspec("_Needsreview_")
#define __oacr_intl_deprecated __declspec("_Intl_deprecated_")
#define __oacr_noinference __declspec("_Noinference_")
#define __oacr_canthrow __declspec("_Canthrow_")
#define __oacr_bindReturn __declspec("_BindReturn_")
#define __oacr_sa_deprecated(NewFunctionName) __declspec("_SA_deprecated_("_SA_SPECSTRIZE(NewFunctionName) ")")
#define __oacr_sa_deprecated_staging(NewFunctionName) \
__declspec("_SA_deprecated_staging_("_SA_SPECSTRIZE(NewFunctionName) ")")
#define __oacr_oleo_deprecated(NewFunctionName) __declspec("_Oleo_deprecated_("_SA_SPECSTRIZE(NewFunctionName) ")")
#define __oacr_genericfunctype __declspec("_Genericfunctype_")
#define __oacr_nothrowfunctype __declspec("__nothrowfunctype")
#define __oacr_noheap __declspec("_Noheap_")
#define __oacr_notrunccast __declspec("_Notrunccast_")
#define __oacr_sealed_class __declspec("_Sealed_")
#define __oacr_allow_implicit_ctor __declspec("_Allow_implicit_ctor_")
#define __oacr_norefcapture_asynclambda __declspec("_Norefcapture_asynclambda_")
#define __oacr_nodecl_lambda __declspec("_Nodecl_lambda_")
#define __oacr_noexcept_maythrow __declspec("_Noexcept_maythrow_")
#define __oacr_noexcept_mayterminate __declspec("_Noexcept_mayterminate_")
#define __oacr_noexcept_mayterminate_ignore(FunctionName) \
__declspec("_Noexcept_mayterminate_ignore_("_SA_SPECSTRIZE(FunctionName) ")")
#define __oacr_dont_swap __declspec("_Dont_swap_")
__extern_c int __RequireNoThrow();
#define __oacr_requireNoThrow __RequireNoThrow();

Просмотреть файл

@ -25,207 +25,349 @@
// Annotations for _t (pascal string) and _tz (nullterminated pascal string)
#define _In_t_ _Pre_t_ _Deref_pre_readonly_
#define _In_opt_t_ _Pre_opt_t_ _Deref_pre_readonly_
#define _In_tz_ _Pre_tz_ _Deref_pre_readonly_
#define _In_opt_tz_ _Pre_opt_tz_ _Deref_pre_readonly_
#define _In_t_ _Pre_t_ _Deref_pre_readonly_
#define _In_opt_t_ _Pre_opt_t_ _Deref_pre_readonly_
#define _In_tz_ _Pre_tz_ _Deref_pre_readonly_
#define _In_opt_tz_ _Pre_opt_tz_ _Deref_pre_readonly_
#define _Out_t_cap_(size) _Pre_cap_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_cap_(size) _Pre_opt_cap_(size) _Pre_invalid_ _Post_t_
#define _Out_t_bytecap_(size) _Pre_bytecap_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_bytecap_(size) _Pre_opt_bytecap_(size) _Pre_invalid_ _Post_t_
#define _Out_tz_cap_(size) _Pre_cap_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_cap_(size) _Pre_opt_cap_(size) _Pre_invalid_ _Post_tz_
#define _Out_tz_bytecap_(size) _Pre_bytecap_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_bytecap_(size) _Pre_opt_bytecap_(size) _Pre_invalid_ _Post_tz_
#define _Out_t_cap_(size) _Pre_cap_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_cap_(size) _Pre_opt_cap_(size) _Pre_invalid_ _Post_t_
#define _Out_t_bytecap_(size) _Pre_bytecap_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_bytecap_(size) _Pre_opt_bytecap_(size) _Pre_invalid_ _Post_t_
#define _Out_tz_cap_(size) _Pre_cap_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_cap_(size) _Pre_opt_cap_(size) _Pre_invalid_ _Post_tz_
#define _Out_tz_bytecap_(size) _Pre_bytecap_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_bytecap_(size) _Pre_opt_bytecap_(size) _Pre_invalid_ _Post_tz_
#define _Out_t_cap_c_(size) _Pre_cap_c_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_cap_c_(size) _Pre_opt_cap_c_(size) _Pre_invalid_ _Post_t_
#define _Out_t_bytecap_c_(size) _Pre_bytecap_c_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_bytecap_c_(size) _Pre_opt_bytecap_c_(size) _Pre_invalid_ _Post_t_
#define _Out_tz_cap_c_(size) _Pre_cap_c_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_cap_c_(size) _Pre_opt_cap_c_(size) _Pre_invalid_ _Post_tz_
#define _Out_tz_bytecap_c_(size) _Pre_bytecap_c_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_bytecap_c_(size) _Pre_opt_bytecap_c_(size) _Pre_invalid_ _Post_tz_
#define _Out_t_cap_c_(size) _Pre_cap_c_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_cap_c_(size) _Pre_opt_cap_c_(size) _Pre_invalid_ _Post_t_
#define _Out_t_bytecap_c_(size) _Pre_bytecap_c_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_bytecap_c_(size) _Pre_opt_bytecap_c_(size) _Pre_invalid_ _Post_t_
#define _Out_tz_cap_c_(size) _Pre_cap_c_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_cap_c_(size) _Pre_opt_cap_c_(size) _Pre_invalid_ _Post_tz_
#define _Out_tz_bytecap_c_(size) _Pre_bytecap_c_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_bytecap_c_(size) _Pre_opt_bytecap_c_(size) _Pre_invalid_ _Post_tz_
#define _Out_t_cap_x_(size) _Pre_cap_x_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_cap_x_(size) _Pre_opt_cap_x_(size) _Pre_invalid_ _Post_t_
#define _Out_t_bytecap_x_(size) _Pre_bytecap_x_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_bytecap_x_(size) _Pre_opt_bytecap_x_(size) _Pre_invalid_ _Post_t_
#define _Out_tz_cap_x_(size) _Pre_cap_x_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_cap_x_(size) _Pre_opt_cap_x_(size) _Pre_invalid_ _Post_tz_
#define _Out_tz_bytecap_x_(size) _Pre_bytecap_x_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_bytecap_x_(size) _Pre_opt_bytecap_x_(size) _Pre_invalid_ _Post_tz_
#define _Out_t_cap_x_(size) _Pre_cap_x_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_cap_x_(size) _Pre_opt_cap_x_(size) _Pre_invalid_ _Post_t_
#define _Out_t_bytecap_x_(size) _Pre_bytecap_x_(size) _Pre_invalid_ _Post_t_
#define _Out_opt_t_bytecap_x_(size) _Pre_opt_bytecap_x_(size) _Pre_invalid_ _Post_t_
#define _Out_tz_cap_x_(size) _Pre_cap_x_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_cap_x_(size) _Pre_opt_cap_x_(size) _Pre_invalid_ _Post_tz_
#define _Out_tz_bytecap_x_(size) _Pre_bytecap_x_(size) _Pre_invalid_ _Post_tz_
#define _Out_opt_tz_bytecap_x_(size) _Pre_opt_bytecap_x_(size) _Pre_invalid_ _Post_tz_
#define _Out_tz_cap_post_count_(cap,count) _Pre_cap_(cap) _Pre_invalid_ _Post_tz_count_(count)
#define _Out_opt_tz_cap_post_count_(cap,count) _Pre_opt_cap_(cap) _Pre_invalid_ _Post_tz_count_(count)
#define _Out_tz_bytecap_post_bytecount_(cap,count) _Pre_bytecap_(cap) _Pre_invalid_ _Post_tz_bytecount_(count)
#define _Out_opt_tz_bytecap_post_bytecount_(cap,count) _Pre_opt_bytecap_(cap) _Pre_invalid_ _Post_tz_bytecount_(count)
#define _Out_tz_cap_post_count_(cap, count) _Pre_cap_(cap) _Pre_invalid_ _Post_tz_count_(count)
#define _Out_opt_tz_cap_post_count_(cap, count) _Pre_opt_cap_(cap) _Pre_invalid_ _Post_tz_count_(count)
#define _Out_tz_bytecap_post_bytecount_(cap, count) _Pre_bytecap_(cap) _Pre_invalid_ _Post_tz_bytecount_(count)
#define _Out_opt_tz_bytecap_post_bytecount_(cap, count) _Pre_opt_bytecap_(cap) _Pre_invalid_ _Post_tz_bytecount_(count)
#define _Out_tz_capcount_(capcount) _Pre_cap_(capcount) _Pre_invalid_ _Post_tz_count_(capcount)
#define _Out_opt_tz_capcount_(capcount) _Pre_opt_cap_(capcount) _Pre_invalid_ _Post_tz_count_(capcount)
#define _Out_tz_bytecapcount_(capcount) _Pre_bytecap_(capcount) _Pre_invalid_ _Post_tz_bytecount_(capcount)
#define _Out_opt_tz_bytecapcount_(capcount) _Pre_opt_bytecap_(capcount) _Pre_invalid_ _Post_tz_bytecount_(capcount)
#define _Out_tz_capcount_(capcount) _Pre_cap_(capcount) _Pre_invalid_ _Post_tz_count_(capcount)
#define _Out_opt_tz_capcount_(capcount) _Pre_opt_cap_(capcount) _Pre_invalid_ _Post_tz_count_(capcount)
#define _Out_tz_bytecapcount_(capcount) _Pre_bytecap_(capcount) _Pre_invalid_ _Post_tz_bytecount_(capcount)
#define _Out_opt_tz_bytecapcount_(capcount) _Pre_opt_bytecap_(capcount) _Pre_invalid_ _Post_tz_bytecount_(capcount)
#define _Inout_t_ _Prepost_t_
#define _Inout_opt_t_ _Prepost_opt_t_
#define _Inout_tz_ _Prepost_tz_
#define _Inout_opt_tz_ _Prepost_opt_tz_
#define _Inout_t_ _Prepost_t_
#define _Inout_opt_t_ _Prepost_opt_t_
#define _Inout_tz_ _Prepost_tz_
#define _Inout_opt_tz_ _Prepost_opt_tz_
#define _Inout_t_cap_(size) _Pre_t_cap_(size) _Post_t_
#define _Inout_opt_t_cap_(size) _Pre_opt_t_cap_(size) _Post_t_
#define _Inout_t_bytecap_(size) _Pre_t_bytecap_(size) _Post_t_
#define _Inout_opt_t_bytecap_(size) _Pre_opt_t_bytecap_(size) _Post_t_
#define _Inout_tz_cap_(size) _Pre_tz_cap_(size) _Post_tz_
#define _Inout_opt_tz_cap_(size) _Pre_opt_tz_cap_(size) _Post_tz_
#define _Inout_tz_bytecap_(size) _Pre_tz_bytecap_(size) _Post_tz_
#define _Inout_opt_tz_bytecap_(size) _Pre_opt_tz_bytecap_(size) _Post_tz_
#define _Inout_t_cap_(size) _Pre_t_cap_(size) _Post_t_
#define _Inout_opt_t_cap_(size) _Pre_opt_t_cap_(size) _Post_t_
#define _Inout_t_bytecap_(size) _Pre_t_bytecap_(size) _Post_t_
#define _Inout_opt_t_bytecap_(size) _Pre_opt_t_bytecap_(size) _Post_t_
#define _Inout_tz_cap_(size) _Pre_tz_cap_(size) _Post_tz_
#define _Inout_opt_tz_cap_(size) _Pre_opt_tz_cap_(size) _Post_tz_
#define _Inout_tz_bytecap_(size) _Pre_tz_bytecap_(size) _Post_tz_
#define _Inout_opt_tz_bytecap_(size) _Pre_opt_tz_bytecap_(size) _Post_tz_
#define _Inout_t_cap_c_(size) _Pre_t_cap_c_(size) _Post_t_
#define _Inout_opt_t_cap_c_(size) _Pre_opt_t_cap_c_(size) _Post_t_
#define _Inout_t_bytecap_c_(size) _Pre_t_bytecap_c_(size) _Post_t_
#define _Inout_opt_t_bytecap_c_(size) _Pre_opt_t_bytecap_c_(size) _Post_t_
#define _Inout_tz_cap_c_(size) _Pre_tz_cap_c_(size) _Post_tz_
#define _Inout_opt_tz_cap_c_(size) _Pre_opt_tz_cap_c_(size) _Post_tz_
#define _Inout_tz_bytecap_c_(size) _Pre_tz_bytecap_c_(size) _Post_tz_
#define _Inout_opt_tz_bytecap_c_(size) _Pre_opt_tz_bytecap_c_(size) _Post_tz_
#define _Inout_t_cap_c_(size) _Pre_t_cap_c_(size) _Post_t_
#define _Inout_opt_t_cap_c_(size) _Pre_opt_t_cap_c_(size) _Post_t_
#define _Inout_t_bytecap_c_(size) _Pre_t_bytecap_c_(size) _Post_t_
#define _Inout_opt_t_bytecap_c_(size) _Pre_opt_t_bytecap_c_(size) _Post_t_
#define _Inout_tz_cap_c_(size) _Pre_tz_cap_c_(size) _Post_tz_
#define _Inout_opt_tz_cap_c_(size) _Pre_opt_tz_cap_c_(size) _Post_tz_
#define _Inout_tz_bytecap_c_(size) _Pre_tz_bytecap_c_(size) _Post_tz_
#define _Inout_opt_tz_bytecap_c_(size) _Pre_opt_tz_bytecap_c_(size) _Post_tz_
#define _Inout_t_cap_x_(size) _Pre_t_cap_x_(size) _Post_t_
#define _Inout_opt_t_cap_x_(size) _Pre_opt_t_cap_x_(size) _Post_t_
#define _Inout_t_bytecap_x_(size) _Pre_t_bytecap_x_(size) _Post_t_
#define _Inout_opt_t_bytecap_x_(size) _Pre_opt_t_bytecap_x_(size) _Post_t_
#define _Inout_tz_cap_x_(size) _Pre_tz_cap_x_(size) _Post_tz_
#define _Inout_opt_tz_cap_x_(size) _Pre_opt_tz_cap_x_(size) _Post_tz_
#define _Inout_tz_bytecap_x_(size) _Pre_tz_bytecap_x_(size) _Post_tz_
#define _Inout_opt_tz_bytecap_x_(size) _Pre_opt_tz_bytecap_x_(size) _Post_tz_
#define _Inout_t_cap_x_(size) _Pre_t_cap_x_(size) _Post_t_
#define _Inout_opt_t_cap_x_(size) _Pre_opt_t_cap_x_(size) _Post_t_
#define _Inout_t_bytecap_x_(size) _Pre_t_bytecap_x_(size) _Post_t_
#define _Inout_opt_t_bytecap_x_(size) _Pre_opt_t_bytecap_x_(size) _Post_t_
#define _Inout_tz_cap_x_(size) _Pre_tz_cap_x_(size) _Post_tz_
#define _Inout_opt_tz_cap_x_(size) _Pre_opt_tz_cap_x_(size) _Post_tz_
#define _Inout_tz_bytecap_x_(size) _Pre_tz_bytecap_x_(size) _Post_tz_
#define _Inout_opt_tz_bytecap_x_(size) _Pre_opt_tz_bytecap_x_(size) _Post_tz_
#define _Ret_t_ _Ret2_impl_(__notnull_impl, __count_x_impl([0])) _Ret_valid_impl_ _$RET_STR_TYPE(_$postTStr)
#define _Ret_opt_t_ _Ret2_impl_(__maybenull_impl,__count_x_impl([0])) _Ret_valid_impl_ _$RET_STR_TYPE(_$postTStr)
#define _Ret_tz_ _Ret2_impl_(__notnull_impl, __zterm_impl) _Ret_valid_impl_ _$RET_STR_TYPE(_$postTZStr)
#define _Ret_opt_tz_ _Ret2_impl_(__maybenull_impl,__zterm_impl) _Ret_valid_impl_ _$RET_STR_TYPE(_$postTZStr)
#define _Ret_t_ _Ret2_impl_(__notnull_impl, __count_x_impl([0])) _Ret_valid_impl_ _$RET_STR_TYPE(_$postTStr)
#define _Ret_opt_t_ _Ret2_impl_(__maybenull_impl, __count_x_impl([0])) _Ret_valid_impl_ _$RET_STR_TYPE(_$postTStr)
#define _Ret_tz_ _Ret2_impl_(__notnull_impl, __zterm_impl) _Ret_valid_impl_ _$RET_STR_TYPE(_$postTZStr)
#define _Ret_opt_tz_ _Ret2_impl_(__maybenull_impl, __zterm_impl) _Ret_valid_impl_ _$RET_STR_TYPE(_$postTZStr)
#define _Pre_t_ _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__count_x_impl([0])) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_ _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__count_x_impl([0])) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_tz_ _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__zterm_impl) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_ _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__zterm_impl) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_t_ \
_Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__count_x_impl([0])) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_ \
_Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__count_x_impl([0])) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_tz_ _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__zterm_impl) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_ \
_Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__zterm_impl) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_t_cap_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__cap_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_cap_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__cap_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_t_bytecap_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__bytecap_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_bytecap_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__bytecap_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_tz_cap_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_cap_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_tz_bytecap_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_bytecap_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_t_cap_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __cap_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_cap_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __cap_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_t_bytecap_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __bytecap_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_bytecap_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __bytecap_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_tz_cap_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl, __cap_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_cap_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl, __cap_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_tz_bytecap_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl, __bytecap_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_bytecap_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl, __bytecap_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_t_cap_c_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__cap_c_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_cap_c_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__cap_c_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_t_bytecap_c_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__bytecap_c_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_bytecap_c_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__bytecap_c_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_tz_cap_c_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_c_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_cap_c_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_c_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_tz_bytecap_c_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_c_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_bytecap_c_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_c_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_t_cap_c_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __cap_c_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_cap_c_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __cap_c_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_t_bytecap_c_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __bytecap_c_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_bytecap_c_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __bytecap_c_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_tz_cap_c_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl, __cap_c_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_cap_c_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl, __cap_c_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_tz_bytecap_c_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl, __bytecap_c_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_bytecap_c_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl, __bytecap_c_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_t_cap_x_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__cap_x_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_cap_x_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__cap_x_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_t_bytecap_x_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__bytecap_x_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_bytecap_x_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]),__bytecap_x_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_tz_cap_x_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_x_impl(_csize)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_cap_x_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_x_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_tz_bytecap_x_(size) _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_x_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_bytecap_x_(size) _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_x_impl(size)) _Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_t_cap_x_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __cap_x_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_cap_x_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __cap_x_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_t_bytecap_x_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __bytecap_x_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_opt_t_bytecap_x_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__count_x_impl([0]), __bytecap_x_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTStr)
#define _Pre_tz_cap_x_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl, __cap_x_impl(_csize)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_cap_x_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl, __cap_x_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_tz_bytecap_x_(size) \
_Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl, __bytecap_x_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Pre_opt_tz_bytecap_x_(size) \
_Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl, __bytecap_x_impl(size)) \
_Pre_valid_impl_ _$STR_TYPE(_$preTZStr)
#define _Post_t_ _Post1_impl_(__count_x_impl([0])) _Post_valid_impl_ _$STR_TYPE(_$postTStr)
#define _Post_tz_ _Post1_impl_(__zterm_impl) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_t_ _Post1_impl_(__count_x_impl([0])) _Post_valid_impl_ _$STR_TYPE(_$postTStr)
#define _Post_tz_ _Post1_impl_(__zterm_impl) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
// _Post_t_count family not possible, conflicting WritableElements property
// _Post_t_count family not possible, conflicting WritableElements property
#define _Post_tz_count_(size) _Post2_impl_(__zterm_impl,__count_impl(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_tz_bytecount_(size) _Post2_impl_(__zterm_impl,__bytecount_impl(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_tz_count_c_(size) _Post2_impl_(__zterm_impl,__count_c_impl(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_tz_bytecount_c_(size) _Post2_impl_(__zterm_impl,__bytecount_c_impl(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_tz_count_x_(size) _Post2_impl_(__zterm_impl,__count_x_impl(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_tz_bytecount_x_(size) _Post2_impl_(__zterm_impl,__bytecount_impl_x(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_tz_count_(size) _Post2_impl_(__zterm_impl, __count_impl(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_tz_bytecount_(size) \
_Post2_impl_(__zterm_impl, __bytecount_impl(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_tz_count_c_(size) \
_Post2_impl_(__zterm_impl, __count_c_impl(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_tz_bytecount_c_(size) \
_Post2_impl_(__zterm_impl, __bytecount_c_impl(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_tz_count_x_(size) \
_Post2_impl_(__zterm_impl, __count_x_impl(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Post_tz_bytecount_x_(size) \
_Post2_impl_(__zterm_impl, __bytecount_impl_x(size)) _Post_valid_impl_ _$STR_TYPE(_$postTZStr)
#define _Deref_out_t_ _Out_ _Deref_post_t_
#define _Deref_out_opt_t_ _Out_ _Deref_post_opt_t_
#define _Deref_out_tz_ _Out_ _Deref_post_tz_
#define _Deref_out_opt_tz_ _Out_ _Deref_post_opt_tz_
#define _Deref_out_t_ _Out_ _Deref_post_t_
#define _Deref_out_opt_t_ _Out_ _Deref_post_opt_t_
#define _Deref_out_tz_ _Out_ _Deref_post_tz_
#define _Deref_out_opt_tz_ _Out_ _Deref_post_opt_tz_
#define _Deref_pre_t_ _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__count_x_impl([0])) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_ _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__count_x_impl([0])) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_tz_ _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__zterm_impl) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_ _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__zterm_impl) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_t_ \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__count_x_impl([0])) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_ \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__count_x_impl([0])) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_tz_ \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__zterm_impl) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_ \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__zterm_impl) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_t_cap_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__cap_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_cap_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__cap_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_t_bytecap_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__bytecap_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_bytecap_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__bytecap_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_tz_cap_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_cap_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_tz_bytecap_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_bytecap_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_t_cap_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __cap_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_cap_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __cap_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_t_bytecap_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __bytecap_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_bytecap_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __bytecap_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_tz_cap_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __cap_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_cap_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __cap_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_tz_bytecap_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __bytecap_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_bytecap_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __bytecap_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_t_cap_c_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__cap_c_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_cap_c_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__cap_c_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_t_bytecap_c_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__bytecap_c_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_bytecap_c_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__bytecap_c_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_tz_cap_c_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_c_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_cap_c_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_c_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_tz_bytecap_c_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_c_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_bytecap_c_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_c_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_t_cap_c_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __cap_c_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_cap_c_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __cap_c_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_t_bytecap_c_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __bytecap_c_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_bytecap_c_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __bytecap_c_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_tz_cap_c_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __cap_c_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_cap_c_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __cap_c_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_tz_bytecap_c_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __bytecap_c_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_bytecap_c_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __bytecap_c_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_t_cap_x_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__cap_x_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_cap_x_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__cap_x_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_t_bytecap_x_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__bytecap_x_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_bytecap_x_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]),__bytecap_x_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_tz_cap_x_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_x_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_cap_x_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_x_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_tz_bytecap_x_(size) _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_x_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_bytecap_x_(size) _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_x_impl(size)) _Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_t_cap_x_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __cap_x_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_cap_x_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __cap_x_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_t_bytecap_x_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __bytecap_x_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_opt_t_bytecap_x_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__count_x_impl([0]), __bytecap_x_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTStr)
#define _Deref_pre_tz_cap_x_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __cap_x_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_cap_x_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __cap_x_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_tz_bytecap_x_(size) \
_Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __bytecap_x_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_pre_opt_tz_bytecap_x_(size) \
_Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl, __bytecap_x_impl(size)) \
_Pre_valid_impl_ _$DEREF_STR_TYPE(_$preTZStr)
#define _Deref_post_t_ _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__count_x_impl([0])) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_ _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__count_x_impl([0])) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_tz_ _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__zterm_impl) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_opt_tz_ _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__zterm_impl) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_t_ \
_Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__count_x_impl([0])) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_ \
_Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__count_x_impl([0])) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_tz_ \
_Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__zterm_impl) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_opt_tz_ \
_Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__zterm_impl) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_t_cap_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__cap_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_cap_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__cap_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_t_bytecap_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__bytecap_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_bytecap_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__bytecap_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_t_cap_(size) \
_Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __cap_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_cap_(size) \
_Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __cap_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_t_bytecap_(size) \
_Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __bytecap_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_bytecap_(size) \
_Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __bytecap_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_tz_cap_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl),__cap_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_opt_tz_cap_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl),__cap_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_tz_bytecap_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl),__bytecap_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_opt_tz_bytecap_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl),__bytecap_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_t_cap_c_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__cap_c_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_cap_c_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__cap_c_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_t_bytecap_c_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__bytecap_c_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_bytecap_c_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__bytecap_c_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_t_cap_c_(size) \
_Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __cap_c_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_cap_c_(size) \
_Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __cap_c_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_t_bytecap_c_(size) \
_Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __bytecap_c_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_bytecap_c_(size) \
_Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __bytecap_c_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_tz_cap_c_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl),__cap_c_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_opt_tz_cap_c_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl),__cap_c_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_tz_bytecap_c_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl),__bytecap_c_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_opt_tz_bytecap_c_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl),__bytecap_c_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_t_cap_x_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__cap_x_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_cap_x_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__cap_x_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_t_bytecap_x_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__bytecap_x_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_bytecap_x_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]),__bytecap_x_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_t_cap_x_(size) \
_Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __cap_x_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_cap_x_(size) \
_Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __cap_x_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_t_bytecap_x_(size) \
_Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __bytecap_x_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_opt_t_bytecap_x_(size) \
_Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__count_x_impl([0]), __bytecap_x_impl(size)) \
_Post_valid_impl_ _$DEREF_STR_TYPE(_$postTStr)
#define _Deref_post_tz_cap_x_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl),__cap_x_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_opt_tz_cap_x_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl),__cap_x_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_tz_bytecap_x_(size) _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl),__bytecap_x_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Deref_post_opt_tz_bytecap_x_(size) _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl),__bytecap_x_impl(size)) _Post_valid_impl_ _$DEREF_STR_TYPE(_$postTZStr)
#define _Prepost_t_ _Pre_t_ _Post_t_
#define _Prepost_opt_t_ _Pre_opt_t_ _Post_t_
#define _Prepost_tz_ _Pre_tz_ _Post_tz_
#define _Prepost_opt_tz_ _Pre_opt_tz_ _Post_tz_
#define _Prepost_t_ _Pre_t_ _Post_t_
#define _Prepost_opt_t_ _Pre_opt_t_ _Post_t_
#define _Prepost_tz_ _Pre_tz_ _Post_tz_
#define _Prepost_opt_tz_ _Pre_opt_tz_ _Post_tz_
#define _Deref_prepost_t_ _Deref_pre_t_ _Deref_post_t_
#define _Deref_prepost_opt_t_ _Deref_pre_opt_t_ _Deref_post_opt_t_
#define _Deref_prepost_tz_ _Deref_pre_tz_ _Deref_post_tz_
#define _Deref_prepost_opt_tz_ _Deref_pre_opt_tz_ _Deref_post_opt_tz_
#define _Deref_prepost_t_ _Deref_pre_t_ _Deref_post_t_
#define _Deref_prepost_opt_t_ _Deref_pre_opt_t_ _Deref_post_opt_t_
#define _Deref_prepost_tz_ _Deref_pre_tz_ _Deref_post_tz_
#define _Deref_prepost_opt_tz_ _Deref_pre_opt_tz_ _Deref_post_opt_tz_
// These are stronger than the related _opt_ annotations, in that the buffer pointer must be non-null if and only if
// the associated count parameter is non-zero. For example:
@ -243,9 +385,11 @@
//
// Read( rgBooks, 0 );
//
#define _In_reads_or_null_if_zero_(size) _In_reads_(size) _When_(0 == size, _Pre_null_) _When_(0 < size, _Pre_notnull_)
#define _Out_writes_or_null_if_zero_(size) _Out_writes_(size) _When_(0 == size, _Pre_null_) _When_(0 < size, _Pre_notnull_)
#define _Inout_updates_or_null_if_zero_(size) _Inout_updates_(size) _When_(0 == size, _Pre_null_) _When_(0 < size, _Pre_notnull_)
#define _In_reads_or_null_if_zero_(size) _In_reads_(size) _When_(0 == size, _Pre_null_) _When_(0 < size, _Pre_notnull_)
#define _Out_writes_or_null_if_zero_(size) \
_Out_writes_(size) _When_(0 == size, _Pre_null_) _When_(0 < size, _Pre_notnull_)
#define _Inout_updates_or_null_if_zero_(size) \
_Inout_updates_(size) _When_(0 == size, _Pre_null_) _When_(0 < size, _Pre_notnull_)
#define _$STR_TYPE(type)
#define _$RET_STR_TYPE(type)
@ -264,5 +408,5 @@
#endif
#if !defined(OACR_CAPTURE_FIXUP)
#define OACR_CAPTURE_FIXUP(tag,match,replace) _SA_annotes3(SAL_OACRCapture, tag_FIXUP, match, replace)
#define OACR_CAPTURE_FIXUP(tag, match, replace) _SA_annotes3(SAL_OACRCapture, tag_FIXUP, match, replace)
#endif

Просмотреть файл

@ -26,7 +26,7 @@
#define _Ret_z_
#define _Ret_maybenull_
#define _Ret_notnull_
#define _Ret_range_(x,y)
#define _Ret_range_(x, y)
#define _Post_writable_byte_size_(x)
#define _Deref_pre_valid_
#define _Deref_post_valid_
@ -35,7 +35,7 @@
#define _Printf_format_string_
#define _Use_decl_annotations_
#define _Null_terminated_
#define _Out_cap_post_count_(x,y)
#define _Out_cap_post_count_(x, y)
#define _Out_cap_(x)
#define UNREFERENCED_PARAMETER(x)
#define _In_reads_bytes_(x)

Просмотреть файл

@ -24,7 +24,8 @@ share the same reference counter.
//
// Mso::FixedSwarmBase does only one memory allocation for all objects in the swarm.
// It is very compact: on 64 bit platform the size is 16 bytes for ObjectWeakRef
// (8 bytes v-table + 4 bytes ref count + 4 bytes weak ref count) and one pointer for each swarm member to point to the ObjectWeakRef.
// (8 bytes v-table + 4 bytes ref count + 4 bytes weak ref count) and one pointer for each swarm member to point to the
// ObjectWeakRef.
//
// To create an Mso::FixedSwarmBase use Mso::Make method..
// To create a swarm member call MakeMember() instance methods.
@ -40,7 +41,7 @@ namespace Mso {
namespace Details {
/**
Storage for FixedSwarmBase class. In some sense this is a specialized std::tuple.
Storage for FixedSwarmBase class. In some sense this is a specialized std::tuple.
*/
template <typename... Ts>
struct FixedSwarmStorage;
@ -48,39 +49,39 @@ struct FixedSwarmStorage;
template <>
struct FixedSwarmStorage<>
{
void DestroyObject() const noexcept
{
// Do nothing because there is no storage in this class
UNREFERENCED_OACR(this);
}
void DestroyObject() const noexcept
{
// Do nothing because there is no storage in this class
UNREFERENCED_OACR(this);
}
};
template <typename T0, typename... Ts>
struct FixedSwarmStorage<T0, Ts...> : public FixedSwarmStorage<Ts...>
{
using Super = FixedSwarmStorage<Ts...>;
using Super = FixedSwarmStorage<Ts...>;
FixedSwarmStorage() noexcept
{
Mso::Details::SetWeakRef(&m_memberStorage, nullptr);
}
FixedSwarmStorage() noexcept
{
Mso::Details::SetWeakRef(&m_memberStorage, nullptr);
}
void DestroyObject() const noexcept
{
if (Mso::Details::GetWeakRef(&m_memberStorage))
{
T0::RefCountPolicy::Deleter::template Delete(static_cast<typename T0::TypeToDelete*>((void*) &m_memberStorage));
}
void DestroyObject() const noexcept
{
if (Mso::Details::GetWeakRef(&m_memberStorage))
{
T0::RefCountPolicy::Deleter::template Delete(static_cast<typename T0::TypeToDelete*>((void*)&m_memberStorage));
}
Super::DestroyObject();
}
Super::DestroyObject();
}
ObjectWeakRef* m_weakRefPlaceholder; // reserves negative space before m_memberStorage.
typename std::aligned_storage<sizeof(T0), std::alignment_of<T0>::value>::type m_memberStorage;
ObjectWeakRef* m_weakRefPlaceholder; // reserves negative space before m_memberStorage.
typename std::aligned_storage<sizeof(T0), std::alignment_of<T0>::value>::type m_memberStorage;
};
/**
A helper type to access FixedSwarmStorage member by index similar to std::tuple.
A helper type to access FixedSwarmStorage member by index similar to std::tuple.
*/
template <size_t Index, typename Storage>
struct FixedSwarmStorageMember;
@ -88,13 +89,13 @@ struct FixedSwarmStorageMember;
template <typename T, typename... Ts>
struct FixedSwarmStorageMember<0, FixedSwarmStorage<T, Ts...>>
{
using Type = T;
using StorageType = FixedSwarmStorage<T, Ts...>;
using Type = T;
using StorageType = FixedSwarmStorage<T, Ts...>;
};
template <size_t Index, typename T, typename... Ts>
struct FixedSwarmStorageMember<Index, FixedSwarmStorage<T, Ts...>>
: public FixedSwarmStorageMember<Index - 1, FixedSwarmStorage<Ts...>>
: public FixedSwarmStorageMember<Index - 1, FixedSwarmStorage<Ts...>>
{
};
@ -103,123 +104,123 @@ struct FixedSwarmStorageMember<Index, FixedSwarmStorage<T, Ts...>>
template <typename T, typename TContainer>
struct FixedSwarmMemberMemoryGuard
{
using Type = T;
using Type = T;
~FixedSwarmMemberMemoryGuard() noexcept
{
if (ObjMemory)
{
Container->ReleaseWeakRef();
Mso::Details::SetWeakRef(ObjMemory, nullptr);
}
else if (Obj)
{
// Initialize method failed.
T::RefCountPolicy::Deleter::template Delete(static_cast<typename T::TypeToDelete*>(Obj));
Mso::Details::SetWeakRef(Obj, nullptr);
}
}
~FixedSwarmMemberMemoryGuard() noexcept
{
if (ObjMemory)
{
Container->ReleaseWeakRef();
Mso::Details::SetWeakRef(ObjMemory, nullptr);
}
else if (Obj)
{
// Initialize method failed.
T::RefCountPolicy::Deleter::template Delete(static_cast<typename T::TypeToDelete*>(Obj));
Mso::Details::SetWeakRef(Obj, nullptr);
}
}
public: // We use a public fields to reduce number of generated methods.
// VC++ bug: Make sure that the order of the fields is the same for all memory guards. Otherwise, VC++ generates incorrect code for ship builds.
void* ObjMemory;
T* Obj;
TContainer* Container;
// VC++ bug: Make sure that the order of the fields is the same for all memory guards. Otherwise, VC++ generates
// incorrect code for ship builds.
void* ObjMemory;
T* Obj;
TContainer* Container;
};
/**
FixedSwarmBase is a fixed size swarm which knows all its member type at the creation.
It is like an std::tuple.
By knowing all types upfront we can make the most compact representation of the swarm, and be very flexible about
swarm member types because we know their type in swarm.
Members can be IUnknown, IRefCounted, or object without v-table with AddRef() and Release() methods.
The only requirement is that the members must support the weak ref count where pointer to ObjectWeakRef is in
the nearest negative offset from the object.
When FixedSwarmBase ref count goes to zero it destroys all objects in the Swarm.
FixedSwarmBase is a fixed size swarm which knows all its member type at the creation.
It is like an std::tuple.
By knowing all types upfront we can make the most compact representation of the swarm, and be very flexible about
swarm member types because we know their type in swarm.
Members can be IUnknown, IRefCounted, or object without v-table with AddRef() and Release() methods.
The only requirement is that the members must support the weak ref count where pointer to ObjectWeakRef is in
the nearest negative offset from the object.
When FixedSwarmBase ref count goes to zero it destroys all objects in the Swarm.
*/
template <typename TBase, typename... Ts>
class FixedSwarmBase
: public TBase
class FixedSwarmBase : public TBase
{
static_assert(std::is_base_of<ObjectWeakRef, TBase>::value, "TBase must be inherited from ObjectWeakRef.");
static_assert(std::is_base_of<ObjectWeakRef, TBase>::value, "TBase must be inherited from ObjectWeakRef.");
using Super = TBase;
using StorageType = Details::FixedSwarmStorage<Ts...>;
template <size_t Index> using MemberType = typename Details::FixedSwarmStorageMember<Index, StorageType>::Type;
template <size_t Index> using MemberStorageType = typename Details::FixedSwarmStorageMember<Index, StorageType>::StorageType;
using Super = TBase;
using StorageType = Details::FixedSwarmStorage<Ts...>;
template <size_t Index>
using MemberType = typename Details::FixedSwarmStorageMember<Index, StorageType>::Type;
template <size_t Index>
using MemberStorageType = typename Details::FixedSwarmStorageMember<Index, StorageType>::StorageType;
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
FixedSwarmBase() noexcept
: Super()
, m_storage()
{
}
FixedSwarmBase() noexcept : Super(), m_storage() {}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(FixedSwarmBase);
DECLARE_COPYCONSTR_AND_ASSIGNMENT(FixedSwarmBase);
template <size_t Index>
MemberType<Index>* Get() const noexcept
{
void* item = &static_cast<MemberStorageType<Index>*>(const_cast<StorageType*>(&m_storage))->m_memberStorage;
if (Mso::Details::GetWeakRef(item))
{
return static_cast<MemberType<Index>*>(item);
}
template <size_t Index>
MemberType<Index>* Get() const noexcept
{
void* item = &static_cast<MemberStorageType<Index>*>(const_cast<StorageType*>(&m_storage))->m_memberStorage;
if (Mso::Details::GetWeakRef(item))
{
return static_cast<MemberType<Index>*>(item);
}
return nullptr;
}
return nullptr;
}
template <size_t Index, typename TResult = MemberType<Index>>
Mso::WeakPtr<TResult> GetWeakPtr() const noexcept
{
Mso::WeakPtr<TResult> result;
template <size_t Index, typename TResult = MemberType<Index>>
Mso::WeakPtr<TResult> GetWeakPtr() const noexcept
{
Mso::WeakPtr<TResult> result;
void* member = &static_cast<MemberStorageType<Index>*>(const_cast<StorageType*>(&m_storage))->m_memberStorage;
if (Mso::Details::GetWeakRef(member))
{
result = Mso::WeakPtr<TResult>(reinterpret_cast<MemberType<Index>*>(member), const_cast<ObjectWeakRef*>(static_cast<const ObjectWeakRef*>(this)));
}
void* member = &static_cast<MemberStorageType<Index>*>(const_cast<StorageType*>(&m_storage))->m_memberStorage;
if (Mso::Details::GetWeakRef(member))
{
result = Mso::WeakPtr<TResult>(
reinterpret_cast<MemberType<Index>*>(member),
const_cast<ObjectWeakRef*>(static_cast<const ObjectWeakRef*>(this)));
}
return result;
}
return result;
}
template <size_t Index, typename... TArgs>
void MakeMember(TArgs&&... args) noexcept(MemberType<Index>::MakePolicy::IsNoExcept)
{
using TMember = MemberType<Index>;
template <size_t Index, typename... TArgs>
void MakeMember(TArgs&&... args) noexcept(MemberType<Index>::MakePolicy::IsNoExcept)
{
using TMember = MemberType<Index>;
void* memberMemory = &static_cast<MemberStorageType<Index>*>(const_cast<StorageType*>(&m_storage))->m_memberStorage;
void* memberMemory = &static_cast<MemberStorageType<Index>*>(const_cast<StorageType*>(&m_storage))->m_memberStorage;
// Initialize weak reference for the member
Mso::Details::SetWeakRef(memberMemory, this);
Super::AddWeakRef(); // To match ReleaseWeakRef() call in member destructor.
// Initialize weak reference for the member
Mso::Details::SetWeakRef(memberMemory, this);
Super::AddWeakRef(); // To match ReleaseWeakRef() call in member destructor.
FixedSwarmMemberMemoryGuard<TMember, FixedSwarmBase> memoryGuard = { memberMemory, nullptr, this };
TMember::MakePolicy::template Make<TMember>(memoryGuard, std::forward<TArgs>(args)...);
FixedSwarmMemberMemoryGuard<TMember, FixedSwarmBase> memoryGuard = {memberMemory, nullptr, this};
TMember::MakePolicy::template Make<TMember>(memoryGuard, std::forward<TArgs>(args)...);
Debug(TMember::RefCountPolicy::ValidateObject(memoryGuard));
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
}
Debug(TMember::RefCountPolicy::ValidateObject(memoryGuard));
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
}
protected:
using FixedSwarmType = FixedSwarmBase;
using FixedSwarmType = FixedSwarmBase;
virtual void DestroyObject() noexcept override
{
m_storage.DestroyObject();
Super::ReleaseWeakRef();
}
virtual void DestroyObject() noexcept override
{
m_storage.DestroyObject();
Super::ReleaseWeakRef();
}
virtual void DestroyContainer() const noexcept override
{
this->~FixedSwarmBase();
Super::RefCountPolicy::Allocator::Deallocate(const_cast<FixedSwarmBase*>(this));
}
virtual void DestroyContainer() const noexcept override
{
this->~FixedSwarmBase();
Super::RefCountPolicy::Allocator::Deallocate(const_cast<FixedSwarmBase*>(this));
}
private:
StorageType m_storage;
StorageType m_storage;
};
template <typename... Ts>

Просмотреть файл

@ -35,63 +35,64 @@ namespace Mso { namespace Object {
template <class TObject, class TInterface = TObject>
class LazyInit final
{
static_assert(std::is_base_of<Mso::IRefCounted, TInterface>::value || std::is_base_of<IUnknown, TInterface>::value,
"The type must be derived from Mso::IRefCounted or IUnknown.");
static_assert(
std::is_base_of<Mso::IRefCounted, TInterface>::value || std::is_base_of<IUnknown, TInterface>::value,
"The type must be derived from Mso::IRefCounted or IUnknown.");
public:
DECLARE_COPYCONSTR_AND_ASSIGNMENT(LazyInit);
DECLARE_COPYCONSTR_AND_ASSIGNMENT(LazyInit);
explicit LazyInit() noexcept = default;
explicit LazyInit() noexcept = default;
~LazyInit() noexcept
{
Release();
}
~LazyInit() noexcept
{
Release();
}
template <class... TArgs>
TInterface& Get(TArgs&&... args) noexcept
{
bool unused{ false };
return Get(unused, std::forward<TArgs>(args)...);
}
template <class... TArgs>
TInterface& Get(TArgs&&... args) noexcept
{
bool unused{false};
return Get(unused, std::forward<TArgs>(args)...);
}
template <class... TArgs>
TInterface& Get(bool& created, TArgs&&... args) noexcept
{
created = false;
auto instance{ m_instance.load(std::memory_order_acquire) };
if (!instance)
{
auto newInstance{ Mso::Make<TObject, TInterface>(std::forward<TArgs>(args)...) };
if (m_instance.compare_exchange_strong(instance, newInstance.Get()))
{
// The current thread won the race.
// Ensure that a pointer with a reference count of 1 is stored.
instance = newInstance.Detach();
created = true;
}
}
template <class... TArgs>
TInterface& Get(bool& created, TArgs&&... args) noexcept
{
created = false;
auto instance{m_instance.load(std::memory_order_acquire)};
if (!instance)
{
auto newInstance{Mso::Make<TObject, TInterface>(std::forward<TArgs>(args)...)};
if (m_instance.compare_exchange_strong(instance, newInstance.Get()))
{
// The current thread won the race.
// Ensure that a pointer with a reference count of 1 is stored.
instance = newInstance.Detach();
created = true;
}
}
return *instance;
}
return *instance;
}
bool IsInitialized() const noexcept
{
return m_instance.load(std::memory_order_acquire) != nullptr;
}
bool IsInitialized() const noexcept
{
return m_instance.load(std::memory_order_acquire) != nullptr;
}
void Release() noexcept
{
auto instance{ m_instance.exchange(nullptr) };
if (instance)
{
// Release the reference count added in Create().
instance->Release();
}
}
void Release() noexcept
{
auto instance{m_instance.exchange(nullptr)};
if (instance)
{
// Release the reference count added in Create().
instance->Release();
}
}
private:
std::atomic<TInterface*> m_instance{ nullptr };
std::atomic<TInterface*> m_instance{nullptr};
};
}} // namespace Mso::Object

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Support for reference counting.
Support for reference counting.
*/
#pragma once
@ -20,128 +20,127 @@
namespace Mso {
/**
Mso::Make creates a new instance of class T and returns a TCntPtr to the instance of type TResult.
TResult is either the original type T (default), or one of its interfaces.
Returning an interface type can help to avoid creation of unnecessary TCntPtr template instances.
Mso::Make creates a new instance of class T and returns a TCntPtr to the instance of type TResult.
TResult is either the original type T (default), or one of its interfaces.
Returning an interface type can help to avoid creation of unnecessary TCntPtr template instances.
Method Make is noexcept depending on the Make policy IsNoExcept value.
Method Make is noexcept depending on the Make policy IsNoExcept value.
*/
template <typename T, typename TResult = T, typename... TArgs>
inline Mso::TCntPtr<TResult> Make(TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
typename T::RefCountPolicy::template MemoryGuard<T> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard);
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x01117748 /* tag_bex3i */);
typename T::RefCountPolicy::template MemoryGuard<T> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard);
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x01117748 /* tag_bex3i */);
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef:*/ false);
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef:*/ false);
}
/**
Mso::MakeAlloc is an Mso::Make method for types T that use allocators accepting an argument.
The allocator argument allows to implement stateful allocators.
Mso::MakeAlloc is an Mso::Make method for types T that use allocators accepting an argument.
The allocator argument allows to implement stateful allocators.
MakeAlloc creates a new instance of class T and returns a TCntPtr to the instance of type TResult.
TResult is either the original type T (default), or one of its interfaces.
Returning an interface type can help to avoid creation of unnecessary TCntPtr template instantiations.
MakeAlloc creates a new instance of class T and returns a TCntPtr to the instance of type TResult.
TResult is either the original type T (default), or one of its interfaces.
Returning an interface type can help to avoid creation of unnecessary TCntPtr template instantiations.
Method MakeAlloc is noexcept depending on the Make policy IsNoExcept value.
Method MakeAlloc is noexcept depending on the Make policy IsNoExcept value.
*/
template <typename T, typename TResult = T, typename TAllocArg, typename... TArgs>
inline Mso::TCntPtr<TResult> MakeAlloc(TAllocArg&& allocArg, TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
typename T::RefCountPolicy::template MemoryGuard<T> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard, std::forward<TAllocArg>(allocArg));
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x01117749 /* tag_bex3j */);
typename T::RefCountPolicy::template MemoryGuard<T> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard, std::forward<TAllocArg>(allocArg));
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x01117749 /* tag_bex3j */);
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef:*/ false);
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef:*/ false);
}
/**
Mso::MakeElseNull creates a new instance of class T and returns a TCntPtr to the instance of type TResult.
If memory cannot be allocated then it returns nullptr.
Mso::MakeElseNull creates a new instance of class T and returns a TCntPtr to the instance of type TResult.
If memory cannot be allocated then it returns nullptr.
TResult is either the original type T (default), or one of its interfaces.
Returning an interface type can help to avoid creation of unnecessary TCntPtr template instances.
TResult is either the original type T (default), or one of its interfaces.
Returning an interface type can help to avoid creation of unnecessary TCntPtr template instances.
Method MakeElseNull is noexcept depending on the Make policy IsNoExcept value.
Method MakeElseNull is noexcept depending on the Make policy IsNoExcept value.
*/
template <typename T, typename TResult = T, typename... TArgs>
inline Mso::TCntPtr<TResult> MakeElseNull(TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
Mso::TCntPtr<TResult> result; // Hopefully we can benefit from NRVO
Mso::TCntPtr<TResult> result; // Hopefully we can benefit from NRVO
typename T::RefCountPolicy::template MemoryGuard<T> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard);
if (memoryGuard.ObjMemory)
{
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
typename T::RefCountPolicy::template MemoryGuard<T> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard);
if (memoryGuard.ObjMemory)
{
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
result = Mso::TCntPtr<TResult>(memoryGuard.Obj, /*fDoAddRef:*/ false);
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
}
result = Mso::TCntPtr<TResult>(memoryGuard.Obj, /*fDoAddRef:*/ false);
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
}
return result;
return result;
}
/**
Mso::MakeAllocElseNull is an Mso::MakeElseNull method for types T that use allocators accepting an argument.
The allocator argument allows to implement stateful allocators.
If memory cannot be allocated then it returns nullptr.
Mso::MakeAllocElseNull is an Mso::MakeElseNull method for types T that use allocators accepting an argument.
The allocator argument allows to implement stateful allocators.
If memory cannot be allocated then it returns nullptr.
MakeAllocElseNull creates a new instance of class T and returns a TCntPtr to the instance of type TResult.
TResult is either the original type T (default), or one of its interfaces.
Returning an interface type can help to avoid creation of unnecessary TCntPtr template instantiations.
MakeAllocElseNull creates a new instance of class T and returns a TCntPtr to the instance of type TResult.
TResult is either the original type T (default), or one of its interfaces.
Returning an interface type can help to avoid creation of unnecessary TCntPtr template instantiations.
Method MakeAllocElseNull is noexcept depending on the Make policy IsNoExcept value.
Method MakeAllocElseNull is noexcept depending on the Make policy IsNoExcept value.
*/
template <typename T, typename TResult = T, typename TAllocArg, typename... TArgs>
inline Mso::TCntPtr<TResult> MakeAllocElseNull(TAllocArg&& allocArg, TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
inline Mso::TCntPtr<TResult> MakeAllocElseNull(TAllocArg&& allocArg, TArgs&&... args) noexcept(
T::MakePolicy::IsNoExcept)
{
Mso::TCntPtr<TResult> result; // Hopefully we can benefit from NRVO
Mso::TCntPtr<TResult> result; // Hopefully we can benefit from NRVO
typename T::RefCountPolicy::template MemoryGuard<T> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard, std::forward<TAllocArg>(allocArg));
if (memoryGuard.ObjMemory)
{
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
typename T::RefCountPolicy::template MemoryGuard<T> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard, std::forward<TAllocArg>(allocArg));
if (memoryGuard.ObjMemory)
{
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
result = Mso::TCntPtr<TResult>(memoryGuard.Obj, /*fDoAddRef:*/ false);
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
}
result = Mso::TCntPtr<TResult>(memoryGuard.Obj, /*fDoAddRef:*/ false);
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
}
return result;
return result;
}
// Make policy defines how an instance is created in the pre-allocated memory.
namespace MakePolicy
{
namespace MakePolicy {
/// ThrowCtor MakePolicy passes all parameters to the constructor.
/// ThrowCtor::Make may throw an exception if constructor throws.
/// To allow this class to access private constructor add "friend MakePolicy;" to your class.
struct ThrowCtor
{
static const bool IsNoExcept = false;
static const bool IsNoExcept = false;
template <typename T, typename TMemoryGuard, typename ... TArgs>
static void Make(TMemoryGuard& memoryGuard, TArgs&&... args)
{
OACR_POSSIBLE_THROW;
memoryGuard.Obj = ::new (memoryGuard.ObjMemory) T(std::forward<TArgs>(args)...);
memoryGuard.ObjMemory = nullptr; // Memory is now controlled by the object. Set to null to avoid memory destruction.
}
template <typename T, typename TMemoryGuard, typename... TArgs>
static void Make(TMemoryGuard& memoryGuard, TArgs&&... args)
{
OACR_POSSIBLE_THROW;
memoryGuard.Obj = ::new (memoryGuard.ObjMemory) T(std::forward<TArgs>(args)...);
memoryGuard.ObjMemory = nullptr; // Memory is now controlled by the object. Set to null to avoid memory destruction.
}
};
/// NoThrowCtor MakePolicy passes all parameters to the constructor.
@ -149,66 +148,66 @@ struct ThrowCtor
/// To allow this class to access private constructor add "friend MakePolicy;" to your class.
struct NoThrowCtor
{
static const bool IsNoExcept = true;
static const bool IsNoExcept = true;
template <typename T, typename TMemoryGuard, typename ... TArgs>
static void Make(TMemoryGuard& memoryGuard, TArgs&&... args) noexcept
{
memoryGuard.Obj = ::new (memoryGuard.ObjMemory) T(std::forward<TArgs>(args)...);
memoryGuard.ObjMemory = nullptr; // Memory is now controlled by the object. Set to null to avoid memory destruction.
}
template <typename T, typename TMemoryGuard, typename... TArgs>
static void Make(TMemoryGuard& memoryGuard, TArgs&&... args) noexcept
{
memoryGuard.Obj = ::new (memoryGuard.ObjMemory) T(std::forward<TArgs>(args)...);
memoryGuard.ObjMemory = nullptr; // Memory is now controlled by the object. Set to null to avoid memory destruction.
}
};
/// ThrowCtorAndInitializeThis MakePolicy calls default constructor and then passes all parameters to InitializeThis method.
/// ThrowCtor::Make may throw an exception if constructor or InitializeThis throw.
/// To allow this class to access private constructor add "friend MakePolicy;" to your class.
/// ThrowCtorAndInitializeThis MakePolicy calls default constructor and then passes all parameters to InitializeThis
/// method. ThrowCtor::Make may throw an exception if constructor or InitializeThis throw. To allow this class to access
/// private constructor add "friend MakePolicy;" to your class.
struct ThrowCtorAndInitializeThis
{
static const bool IsNoExcept = false;
static const bool IsNoExcept = false;
template <typename T, typename TMemoryGuard, typename ... TArgs>
static void Make(TMemoryGuard& memoryGuard, TArgs&&... args)
{
OACR_POSSIBLE_THROW;
memoryGuard.Obj = ::new (memoryGuard.ObjMemory) T();
memoryGuard.ObjMemory = nullptr; // Memory is now controlled by the object. Set to null to avoid memory destruction.
memoryGuard.Obj->InitializeThis(std::forward<TArgs>(args)...);
}
template <typename T, typename TMemoryGuard, typename... TArgs>
static void Make(TMemoryGuard& memoryGuard, TArgs&&... args)
{
OACR_POSSIBLE_THROW;
memoryGuard.Obj = ::new (memoryGuard.ObjMemory) T();
memoryGuard.ObjMemory = nullptr; // Memory is now controlled by the object. Set to null to avoid memory destruction.
memoryGuard.Obj->InitializeThis(std::forward<TArgs>(args)...);
}
};
/// NoThrowCtorAndInitializeThis MakePolicy calls default constructor and then passes all parameters to InitializeThis method.
/// NoThrowCtor::Make does not throw exception and crashes the app if constructor or InitializeThis throw.
/// To allow this class to access private constructor add "friend MakePolicy;" to your class.
/// NoThrowCtorAndInitializeThis MakePolicy calls default constructor and then passes all parameters to InitializeThis
/// method. NoThrowCtor::Make does not throw exception and crashes the app if constructor or InitializeThis throw. To
/// allow this class to access private constructor add "friend MakePolicy;" to your class.
struct NoThrowCtorAndInitializeThis
{
static const bool IsNoExcept = true;
static const bool IsNoExcept = true;
template <typename T, typename TMemoryGuard, typename ... TArgs>
static void Make(TMemoryGuard& memoryGuard, TArgs&&... args) noexcept
{
memoryGuard.Obj = ::new (memoryGuard.ObjMemory) T();
memoryGuard.ObjMemory = nullptr; // Memory is now controlled by the object. Set to null to avoid memory destruction.
memoryGuard.Obj->InitializeThis(std::forward<TArgs>(args)...);
}
template <typename T, typename TMemoryGuard, typename... TArgs>
static void Make(TMemoryGuard& memoryGuard, TArgs&&... args) noexcept
{
memoryGuard.Obj = ::new (memoryGuard.ObjMemory) T();
memoryGuard.ObjMemory = nullptr; // Memory is now controlled by the object. Set to null to avoid memory destruction.
memoryGuard.Obj->InitializeThis(std::forward<TArgs>(args)...);
}
};
} // namespace MakePolicy
/**
Default memory allocator for ref counted objects.
Default memory allocator for ref counted objects.
*/
struct MakeAllocator
{
static void* Allocate(size_t size) noexcept
{
Debug(Mso::Memory::AutoIgnoreLeakScope lazy);
return Mso::Memory::AllocateEx(size, Mso::Memory::AllocFlags::ShutdownLeak);
}
static void* Allocate(size_t size) noexcept
{
Debug(Mso::Memory::AutoIgnoreLeakScope lazy);
return Mso::Memory::AllocateEx(size, Mso::Memory::AllocFlags::ShutdownLeak);
}
static void Deallocate(void* ptr) noexcept
{
Mso::Memory::Free(ptr);
}
static void Deallocate(void* ptr) noexcept
{
Mso::Memory::Free(ptr);
}
};
} // namespace Mso

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Support for reference counting.
Support for reference counting.
*/
#pragma once
@ -23,192 +23,201 @@
#pragma push_macro("new")
#undef new
#define _MSO_OBJECT_SIMPLEREFCOUNT(TObject) \
public: \
bool IsUniqueRef() const noexcept { return m_refCount.load(std::memory_order_acquire) == 1; } \
Debug(uint32_t RefCount() const noexcept { return m_refCount.load(std::memory_order_acquire); }) \
\
template <typename UseMsoMakeInsteadOfOperatorNew> void* operator new(size_t, UseMsoMakeInsteadOfOperatorNew* = nullptr); \
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TObject)
#define _MSO_OBJECT_SIMPLEREFCOUNT(TObject) \
public: \
bool IsUniqueRef() const noexcept \
{ \
return m_refCount.load(std::memory_order_acquire) == 1; \
} \
Debug(uint32_t RefCount() const noexcept { return m_refCount.load(std::memory_order_acquire); }) \
\
template <typename UseMsoMakeInsteadOfOperatorNew> \
void* operator new(size_t, UseMsoMakeInsteadOfOperatorNew* = nullptr); \
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TObject)
#define _MSO_OBJECT_NOREFCOUNT(TObject) \
public: \
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TObject)
public: \
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TObject)
namespace Mso {
template <typename T, typename TAllocator = MakeAllocator>
struct SimpleRefCountMemoryGuard
{
~SimpleRefCountMemoryGuard() noexcept
{
if (ObjMemory)
{
TAllocator::Deallocate(ObjMemory);
}
else if (Obj)
{
Obj->Release();
}
}
~SimpleRefCountMemoryGuard() noexcept
{
if (ObjMemory)
{
TAllocator::Deallocate(ObjMemory);
}
else if (Obj)
{
Obj->Release();
}
}
public: // We use public fields to reduce number of generated methods.
// VC++ bug: Make sure that the order of the fields is the same for all memory guards. Otherwise, VC++ generates incorrect code for ship builds.
void* ObjMemory;
T* Obj;
// VC++ bug: Make sure that the order of the fields is the same for all memory guards. Otherwise, VC++ generates
// incorrect code for ship builds.
void* ObjMemory;
T* Obj;
};
template <typename TDeleter, typename TAllocator = MakeAllocator>
struct SimpleRefCountPolicy
{
using Deleter = TDeleter;
using Allocator = TAllocator;
using Deleter = TDeleter;
using Allocator = TAllocator;
template <typename T>
using MemoryGuard = SimpleRefCountMemoryGuard<T, TAllocator>;
template <typename T>
using MemoryGuard = SimpleRefCountMemoryGuard<T, TAllocator>;
template <typename T>
static void AllocateMemory(_Out_ MemoryGuard<T>& memoryGuard) noexcept
{
memoryGuard.ObjMemory = TAllocator::Allocate(sizeof(T));
}
template <typename T>
static void AllocateMemory(_Out_ MemoryGuard<T>& memoryGuard) noexcept
{
memoryGuard.ObjMemory = TAllocator::Allocate(sizeof(T));
}
template <typename T, typename TAllocArg>
static void AllocateMemory(_Out_ MemoryGuard<T>& memoryGuard, TAllocArg&& allocArg) noexcept
{
memoryGuard.ObjMemory = TAllocator::Allocate(sizeof(T), std::forward<TAllocArg>(allocArg));
}
template <typename T, typename TAllocArg>
static void AllocateMemory(_Out_ MemoryGuard<T>& memoryGuard, TAllocArg&& allocArg) noexcept
{
memoryGuard.ObjMemory = TAllocator::Allocate(sizeof(T), std::forward<TAllocArg>(allocArg));
}
template <typename T>
static void Delete(T* obj) noexcept
{
obj->~T();
TAllocator::Deallocate(obj);
}
template <typename T>
static void Delete(T* obj) noexcept
{
obj->~T();
TAllocator::Deallocate(obj);
}
#if DEBUG
template <typename T>
static void ValidateObject(MemoryGuard<T>& memoryGuard) noexcept
{
static_assert(offsetof(typename T::TypeToDelete, m_refCount) == offsetof(T, m_refCount),
"Ref counted object must be the first type in T inheritance list.");
template <typename T>
static void ValidateObject(MemoryGuard<T>& memoryGuard) noexcept
{
static_assert(
offsetof(typename T::TypeToDelete, m_refCount) == offsetof(T, m_refCount),
"Ref counted object must be the first type in T inheritance list.");
VerifyElseCrashSzTag(memoryGuard.Obj, "Object was not created", 0x01105590 /* tag_befwq */);
VerifyElseCrashSzTag(reinterpret_cast<void*>(memoryGuard.Obj) == static_cast<typename T::TypeToDelete*>(memoryGuard.Obj),
"Ref counted object must be the first type in T inheritance list.", 0x01105591 /* tag_befwr */);
}
VerifyElseCrashSzTag(memoryGuard.Obj, "Object was not created", 0x01105590 /* tag_befwq */);
VerifyElseCrashSzTag(
reinterpret_cast<void*>(memoryGuard.Obj) == static_cast<typename T::TypeToDelete*>(memoryGuard.Obj),
"Ref counted object must be the first type in T inheritance list.",
0x01105591 /* tag_befwr */);
}
#endif
};
struct DefaultRefCountedDeleter
{
template <typename TObject>
static void Delete(TObject* obj) noexcept
{
TObject::RefCountPolicy::template Delete(obj);
}
template <typename TObject>
static void Delete(TObject* obj) noexcept
{
TObject::RefCountPolicy::template Delete(obj);
}
};
/**
Supported Object ref count strategies. They are used to select base class for ref counting and to choose Make algorithm.
The struct can be changed to a namespace if in future we need many strategies in different files.
Supported Object ref count strategies. They are used to select base class for ref counting and to choose Make
algorithm. The struct can be changed to a namespace if in future we need many strategies in different files.
*/
namespace RefCountStrategy {
using Simple = SimpleRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
struct SimpleNoQuery;
struct NoRefCount;
struct NoRefCountNoQuery;
};
using Simple = SimpleRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
struct SimpleNoQuery;
struct NoRefCount;
struct NoRefCountNoQuery;
}; // namespace RefCountStrategy
/**
std::shared_ptr<T> is large - it's 2 pointers.
This is handy for cases where memory management (one pointer) is separated from the actual
data (second pointer). But in cases where we have std::shared_ptr<T> and construct it using
std::make_shared<T>() it does not make much sense - we waste one pointer.
An example would be well-defined final types - like std::shared_ptr<std::vector<T>>.
To avoid wasting memory, created 2 new concepts that mirror STL - RefCountedPtr<> & Make_RefCounted<>()
Helper class RefCountedWrapper is used to facilitate change
std::shared_ptr<T> is large - it's 2 pointers.
This is handy for cases where memory management (one pointer) is separated from the actual
data (second pointer). But in cases where we have std::shared_ptr<T> and construct it using
std::make_shared<T>() it does not make much sense - we waste one pointer.
An example would be well-defined final types - like std::shared_ptr<std::vector<T>>.
To avoid wasting memory, created 2 new concepts that mirror STL - RefCountedPtr<> & Make_RefCounted<>()
Helper class RefCountedWrapper is used to facilitate change
NOTE: there are potentially 2 types of objects we need:
1) final & no vtable. Useful for case of std::shared_ptr<std::vector<T>>.
2) with virtual destructor. Useful for type eraser, to make sure object is deleted properly.
NOTE: there are potentially 2 types of objects we need:
1) final & no vtable. Useful for case of std::shared_ptr<std::vector<T>>.
2) with virtual destructor. Useful for type eraser, to make sure object is deleted properly.
Also we can do various optimizations / specializations, like
- ref-counted without interlocked operations (where it's safe)
- ref-counting using short (2 bytes), vs. int (useful if to pack better, like case of
RefCountedWrapper<std::pair<short, T>> in CallbackStoreCombined
That said, this comes at the cost of complexity - more types, harder to navigate and easier to make mistakes.
Should be done through optional template args.
Also we can do various optimizations / specializations, like
- ref-counted without interlocked operations (where it's safe)
- ref-counting using short (2 bytes), vs. int (useful if to pack better, like case of
RefCountedWrapper<std::pair<short, T>> in CallbackStoreCombined
That said, this comes at the cost of complexity - more types, harder to navigate and easier to make mistakes.
Should be done through optional template args.
*/
class RefCountedWrapperBase
{
public:
using RefCountPolicy = SimpleRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
friend RefCountPolicy;
using RefCountPolicy = SimpleRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
friend RefCountPolicy;
using TypeToDelete = RefCountedWrapperBase; // To verify that TypeToDelete is the first in the inheritance chain.
using TypeToDelete = RefCountedWrapperBase; // To verify that TypeToDelete is the first in the inheritance chain.
_MSO_OBJECT_SIMPLEREFCOUNT(RefCountedWrapperBase);
_MSO_OBJECT_SIMPLEREFCOUNT(RefCountedWrapperBase);
void AddRef() const noexcept
{
uint32_t refCount = ++m_refCount;
(void)(refCount);
Debug(VerifyElseCrashSzTag(static_cast<int32_t>(refCount) > 1, "Ref count must not bounce from zero", 0x01105592 /* tag_befws */));
}
void AddRef() const noexcept
{
uint32_t refCount = ++m_refCount;
(void)(refCount);
Debug(VerifyElseCrashSzTag(
static_cast<int32_t>(refCount) > 1, "Ref count must not bounce from zero", 0x01105592 /* tag_befws */));
}
void Release() const noexcept
{
uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x01105593 /* tag_befwt */));
if (refCount == 0)
{
RefCountPolicy::Delete(const_cast<RefCountedWrapperBase*>(this));
}
}
void Release() const noexcept
{
uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(
static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x01105593 /* tag_befwt */));
if (refCount == 0)
{
RefCountPolicy::Delete(const_cast<RefCountedWrapperBase*>(this));
}
}
protected:
RefCountedWrapperBase() noexcept = default;
virtual ~RefCountedWrapperBase() noexcept = default; // for type erasure
RefCountedWrapperBase() noexcept = default;
virtual ~RefCountedWrapperBase() noexcept = default; // for type erasure
private:
mutable std::atomic<uint32_t> m_refCount { 1 };
mutable std::atomic<uint32_t> m_refCount{1};
};
template <typename T>
class RefCountedWrapper : public RefCountedWrapperBase, public T
class RefCountedWrapper
: public RefCountedWrapperBase
, public T
{
public:
DECLARE_COPYCONSTR_AND_ASSIGNMENT(RefCountedWrapper);
DECLARE_COPYCONSTR_AND_ASSIGNMENT(RefCountedWrapper);
using MakePolicy = Mso::MakePolicy::ThrowCtor;
using MakePolicy = Mso::MakePolicy::ThrowCtor;
template <typename... U>
RefCountedWrapper(U&&... args) noexcept
: T(std::forward<U>(args)...)
{
}
template <typename... U>
RefCountedWrapper(U&&... args) noexcept : T(std::forward<U>(args)...)
{
}
};
/**
Special case for base object that does not know about its type.
Useful for generic containers, where container does not care about the type,
but has external user that can differentiate between instances of these objects
(for example by storing property ID as a first field, i.e.
RefCountedWrapper<std::pair<PropertyId, SomeObject>>)
Special case for base object that does not know about its type.
Useful for generic containers, where container does not care about the type,
but has external user that can differentiate between instances of these objects
(for example by storing property ID as a first field, i.e.
RefCountedWrapper<std::pair<PropertyId, SomeObject>>)
*/
template<>
template <>
class RefCountedWrapper<void> : public RefCountedWrapperBase
{
public:
DECLARE_COPYCONSTR_AND_ASSIGNMENT(RefCountedWrapper);
RefCountedWrapper() noexcept = default;
DECLARE_COPYCONSTR_AND_ASSIGNMENT(RefCountedWrapper);
RefCountedWrapper() noexcept = default;
};
/**
The actual type / Make() function everybody would use
The actual type / Make() function everybody would use
*/
template <typename T>
using RefCountedPtr = Mso::TCntPtr<RefCountedWrapper<T>>;
@ -216,7 +225,7 @@ using RefCountedPtr = Mso::TCntPtr<RefCountedWrapper<T>>;
template <typename T, typename... U>
RefCountedPtr<T> Make_RefCounted(U&&... args) noexcept
{
return Mso::Make<RefCountedWrapper<T>>(std::forward<U>(args)...);
return Mso::Make<RefCountedWrapper<T>>(std::forward<U>(args)...);
}
} // namespace Mso

Просмотреть файл

@ -18,7 +18,7 @@ To implement your classes please use classes defined in the msoUnknownObject.h o
// - Expose the reference counting control block as a public API - ObjectWeakRef class.
// - Add a base class ObjectWithWeakRef to support TCntPtr.
//
// Classes must be inherited from the ObjectWithWeakRef and assigned an instance of ObjectWeakRef right after
// Classes must be inherited from the ObjectWithWeakRef and assigned an instance of ObjectWeakRef right after
// the construction. ObjectWithWeakRef delegates all ref counting to ObjectWeakRef.
//
// ObjectWeakRef is an ObjectRefCount that maintains a m_strongRefCount variable to control the lifetime of classes
@ -34,11 +34,12 @@ To implement your classes please use classes defined in the msoUnknownObject.h o
//
// To allocate memory we use ObjectWeakRefContainer. It is inherited from the ObjectWeakRef and has storage
// for the constructed object. So, we have only one memory allocation instead of two.
//
//
// It is very similar to how the std::make_shared works.
// The main difference here is that the base class for the ObjectWeakRefContainer is a template which
// gives ability to have different base classes. They just required to have a virtual method DestroyOwnedObject() to signal
// when object must be destroyed. The base class must also have a virtual destructor and be responsible for its destruction.
// gives ability to have different base classes. They just required to have a virtual method DestroyOwnedObject() to
// signal when object must be destroyed. The base class must also have a virtual destructor and be responsible for its
// destruction.
//
// -------------------------------------------------------------------------------------------
// | ObjectWeakRefContainer |
@ -69,112 +70,121 @@ To implement your classes please use classes defined in the msoUnknownObject.h o
#pragma push_macro("new")
#undef new
#define _MSO_OBJECT_WEAKREFCOUNT(TObject) \
public: \
Mso::ObjectWeakRef& GetWeakRef() const noexcept { return *Mso::Details::GetWeakRef(this); } \
bool IsUniqueRef() const noexcept { return GetWeakRef().IsUniqueRef(); } \
Debug(uint32_t RefCount() const noexcept { return GetWeakRef().RefCount(); }) \
\
template <typename UseMsoMakeInsteadOfOperatorNew> void* operator new(size_t, UseMsoMakeInsteadOfOperatorNew* = nullptr); \
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TObject)
#define _MSO_OBJECT_WEAKREFCOUNT(TObject) \
public: \
Mso::ObjectWeakRef& GetWeakRef() const noexcept \
{ \
return *Mso::Details::GetWeakRef(this); \
} \
bool IsUniqueRef() const noexcept \
{ \
return GetWeakRef().IsUniqueRef(); \
} \
Debug(uint32_t RefCount() const noexcept { return GetWeakRef().RefCount(); }) \
\
template <typename UseMsoMakeInsteadOfOperatorNew> \
void* operator new(size_t, UseMsoMakeInsteadOfOperatorNew* = nullptr); \
DECLARE_COPYCONSTR_AND_ASSIGNMENT(TObject)
namespace Mso {
/**
Reference counting block to support weak pointers.
Reference counting block to support weak pointers.
*/
MSO_CLASS_GUID(ObjectWeakRef, "3063C26C-DB10-4BCC-AF5C-340E4D7AA0F6")
class ObjectWeakRef
{
public:
using RefCountPolicy = Mso::SimpleRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
friend RefCountPolicy;
using RefCountPolicy = Mso::SimpleRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
friend RefCountPolicy;
using TypeToDelete = ObjectWeakRef; // To verify that TypeToDelete is the first in the inheritance chain.
using TypeToDelete = ObjectWeakRef; // To verify that TypeToDelete is the first in the inheritance chain.
_MSO_OBJECT_SIMPLEREFCOUNT(ObjectWeakRef);
_MSO_OBJECT_SIMPLEREFCOUNT(ObjectWeakRef);
ObjectWeakRef() = default;
ObjectWeakRef() = default;
void AddRef() const noexcept
{
if (++m_refCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Ref count must not bounce from zero", 0x01105594 /* tag_befwu */));
}
}
void AddRef() const noexcept
{
if (++m_refCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Ref count must not bounce from zero", 0x01105594 /* tag_befwu */));
}
}
void Release() const noexcept
{
const uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x008c2685 /* tag_a9c0f */));
if (refCount == 0)
{
const_cast<ObjectWeakRef*>(this)->DestroyObject();
}
}
void Release() const noexcept
{
const uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(
static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x008c2685 /* tag_a9c0f */));
if (refCount == 0)
{
const_cast<ObjectWeakRef*>(this)->DestroyObject();
}
}
void AddWeakRef() const noexcept
{
if (++m_weakRefCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Weak ref count must not bounce from zero", 0x01105595 /* tag_befwv */));
}
}
void AddWeakRef() const noexcept
{
if (++m_weakRefCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Weak ref count must not bounce from zero", 0x01105595 /* tag_befwv */));
}
}
void ReleaseWeakRef() const noexcept
{
const uint32_t weakRefCount = --m_weakRefCount;
Debug(VerifyElseCrashSzTag(static_cast<int32_t>(weakRefCount) >= 0, "Weak ref count must not be negative.", 0x008c2686 /* tag_a9c0g */));
if (weakRefCount == 0)
{
DestroyContainer();
}
}
void ReleaseWeakRef() const noexcept
{
const uint32_t weakRefCount = --m_weakRefCount;
Debug(VerifyElseCrashSzTag(
static_cast<int32_t>(weakRefCount) >= 0, "Weak ref count must not be negative.", 0x008c2686 /* tag_a9c0g */));
if (weakRefCount == 0)
{
DestroyContainer();
}
}
Debug(uint32_t WeakRefCount() const noexcept { return m_weakRefCount.load(std::memory_order_acquire); })
Debug(uint32_t WeakRefCount() const noexcept { return m_weakRefCount.load(std::memory_order_acquire); })
Mso::ObjectWeakRef& GetWeakRef() const noexcept
{
return *const_cast<ObjectWeakRef*>(this);
}
Mso::ObjectWeakRef& GetWeakRef() const noexcept
{
return *const_cast<ObjectWeakRef*>(this);
}
virtual void* QueryCastWeakRef(const GUID& /*riid*/) noexcept
{
return nullptr;
}
virtual void* QueryCastWeakRef(const GUID& /*riid*/) noexcept
{
return nullptr;
}
bool IsExpired() const noexcept
{
return (m_refCount.load(std::memory_order_acquire) == 0);
}
bool IsExpired() const noexcept
{
return (m_refCount.load(std::memory_order_acquire) == 0);
}
bool IncrementRefCountIfNotZero() noexcept
{
uint32_t count = m_refCount.load(std::memory_order_acquire);
for (;;)
{
if (count == 0)
{
return false;
}
bool IncrementRefCountIfNotZero() noexcept
{
uint32_t count = m_refCount.load(std::memory_order_acquire);
for (;;)
{
if (count == 0)
{
return false;
}
if (m_refCount.compare_exchange_weak(/*ref*/count, count + 1))
{
return true;
}
}
}
if (m_refCount.compare_exchange_weak(/*ref*/ count, count + 1))
{
return true;
}
}
}
virtual void DestroyObject() noexcept {}
virtual void DestroyObject() noexcept {}
protected:
virtual void DestroyContainer() const noexcept = 0;
virtual ~ObjectWeakRef() = default;
virtual void DestroyContainer() const noexcept = 0;
virtual ~ObjectWeakRef() = default;
private:
mutable std::atomic<uint32_t> m_refCount { 1 };
mutable std::atomic<uint32_t> m_weakRefCount { 1 }; // Controls ObjectWeakRef lifetime.
mutable std::atomic<uint32_t> m_refCount{1};
mutable std::atomic<uint32_t> m_weakRefCount{1}; // Controls ObjectWeakRef lifetime.
};
namespace Details {
@ -182,195 +192,213 @@ namespace Details {
// Weak reference is always stored in object negative space.
inline Mso::ObjectWeakRef* GetWeakRef(const void* obj) noexcept
{
return *(static_cast<Mso::ObjectWeakRef**>(const_cast<void*>(obj)) - 1);
return *(static_cast<Mso::ObjectWeakRef**>(const_cast<void*>(obj)) - 1);
}
inline void SetWeakRef(const void* obj, Mso::ObjectWeakRef* weakRef) noexcept
{
*(static_cast<Mso::ObjectWeakRef**>(const_cast<void*>(obj)) - 1) = weakRef;
*(static_cast<Mso::ObjectWeakRef**>(const_cast<void*>(obj)) - 1) = weakRef;
}
} // namespace Details
/**
Allocates RefCountBlock and the target object in the same chunk of memory.
TWeakRef is expected to have a virtual destructor and virtual DestroyOwnedObject method.
Allocates RefCountBlock and the target object in the same chunk of memory.
TWeakRef is expected to have a virtual destructor and virtual DestroyOwnedObject method.
*/
template <typename TObject, typename TWeakRef>
class ObjectWeakRefContainer
: public TWeakRef
class ObjectWeakRefContainer : public TWeakRef
{
public:
DECLARE_COPYCONSTR_AND_ASSIGNMENT(ObjectWeakRefContainer);
DECLARE_COPYCONSTR_AND_ASSIGNMENT(ObjectWeakRefContainer);
ObjectWeakRefContainer() = default;
ObjectWeakRefContainer() = default;
TObject* Get() noexcept
{
return reinterpret_cast<TObject*>(&m_objectStorage);
}
TObject* Get() noexcept
{
return reinterpret_cast<TObject*>(&m_objectStorage);
}
protected:
virtual void DestroyObject() noexcept override
{
TWeakRef::DestroyObject();
virtual void DestroyObject() noexcept override
{
TWeakRef::DestroyObject();
TObject* obj = Get();
if (Mso::Details::GetWeakRef(obj)) // Check if object was correctly initialized.
{
// Call the TObject destructor last: this call may destroy the ObjectWeakRefContainer because it may hold the last reference.
TObject::RefCountPolicy::Deleter::Delete(static_cast<typename TObject::TypeToDelete*>(obj));
}
}
TObject* obj = Get();
if (Mso::Details::GetWeakRef(obj)) // Check if object was correctly initialized.
{
// Call the TObject destructor last: this call may destroy the ObjectWeakRefContainer because it may hold the last
// reference.
TObject::RefCountPolicy::Deleter::Delete(static_cast<typename TObject::TypeToDelete*>(obj));
}
}
virtual void DestroyContainer() const noexcept override
{
this->~ObjectWeakRefContainer();
TObject::RefCountPolicy::Allocator::Deallocate(const_cast<ObjectWeakRefContainer*>(this));
}
virtual void DestroyContainer() const noexcept override
{
this->~ObjectWeakRefContainer();
TObject::RefCountPolicy::Allocator::Deallocate(const_cast<ObjectWeakRefContainer*>(this));
}
private:
ObjectWeakRef* m_weakRefPlaceholder; // reserves negative space before m_objectStorage
typename std::aligned_storage<sizeof(TObject), std::alignment_of<TObject>::value>::type m_objectStorage;
ObjectWeakRef* m_weakRefPlaceholder; // reserves negative space before m_objectStorage
typename std::aligned_storage<sizeof(TObject), std::alignment_of<TObject>::value>::type m_objectStorage;
};
template <typename T, typename TContainer>
struct WeakRefCountMemoryGuard
{
using Type = T;
using Type = T;
~WeakRefCountMemoryGuard() noexcept
{
if (ObjMemory)
{
// Constructor failed, Make sure that destructor is not called.
ObjectWeakRef* weakRef = Mso::Details::GetWeakRef(ObjMemory);
Mso::Details::SetWeakRef(ObjMemory, nullptr); // This should prevent destructor call.
Container->Release(); // Release the strong reference which we add to object when we create it.
weakRef->ReleaseWeakRef(); // WeakRef is released when object is destroyed. This call may destroy container and must be the last.
}
else if (Obj)
{
// Initialization failed. Use normal object destruction sequence.
Obj->Release();
}
}
~WeakRefCountMemoryGuard() noexcept
{
if (ObjMemory)
{
// Constructor failed, Make sure that destructor is not called.
ObjectWeakRef* weakRef = Mso::Details::GetWeakRef(ObjMemory);
Mso::Details::SetWeakRef(ObjMemory, nullptr); // This should prevent destructor call.
Container->Release(); // Release the strong reference which we add to object when we create it.
weakRef->ReleaseWeakRef(); // WeakRef is released when object is destroyed. This call may destroy container and
// must be the last.
}
else if (Obj)
{
// Initialization failed. Use normal object destruction sequence.
Obj->Release();
}
}
public: // We use a public fields to reduce number of generated methods.
// VC++ bug: Make sure that the order of the fields is the same for all memory guards. Otherwise, VC++ generates incorrect code for ship builds.
void* ObjMemory;
T* Obj;
TContainer* Container;
// VC++ bug: Make sure that the order of the fields is the same for all memory guards. Otherwise, VC++ generates
// incorrect code for ship builds.
void* ObjMemory;
T* Obj;
TContainer* Container;
};
template <typename TDeleter, typename TAllocator = MakeAllocator>
struct WeakRefCountPolicy
{
using Deleter = TDeleter;
using Allocator = TAllocator;
using Deleter = TDeleter;
using Allocator = TAllocator;
template <typename T, typename TContainer = ObjectWeakRefContainer<T, ObjectWeakRef>>
using MemoryGuard = WeakRefCountMemoryGuard<T, TContainer>;
template <typename T, typename TContainer = ObjectWeakRefContainer<T, ObjectWeakRef>>
using MemoryGuard = WeakRefCountMemoryGuard<T, TContainer>;
template <typename T, typename TContainer>
static void AllocateMemory(_Out_ MemoryGuard<T, TContainer>& memoryGuard) noexcept
{
void* containerMemory = TAllocator::Allocate(sizeof(TContainer));
if (containerMemory)
{
memoryGuard.Container = ::new (containerMemory) TContainer();
memoryGuard.ObjMemory = memoryGuard.Container->Get();
Mso::Details::SetWeakRef(memoryGuard.ObjMemory, memoryGuard.Container);
}
}
template <typename T, typename TContainer>
static void AllocateMemory(_Out_ MemoryGuard<T, TContainer>& memoryGuard) noexcept
{
void* containerMemory = TAllocator::Allocate(sizeof(TContainer));
if (containerMemory)
{
memoryGuard.Container = ::new (containerMemory) TContainer();
memoryGuard.ObjMemory = memoryGuard.Container->Get();
Mso::Details::SetWeakRef(memoryGuard.ObjMemory, memoryGuard.Container);
}
}
template <typename T, typename TContainer, typename TAllocArg>
static void AllocateMemory(_Out_ MemoryGuard<T, TContainer>& memoryGuard, TAllocArg&& allocArg) noexcept
{
void* containerMemory = TAllocator::Allocate(sizeof(TContainer), std::forward<TAllocArg>(allocArg));
if (containerMemory)
{
memoryGuard.Container = ::new (containerMemory) TContainer();
memoryGuard.ObjMemory = memoryGuard.Container->Get();
Mso::Details::SetWeakRef(memoryGuard.ObjMemory, memoryGuard.Container);
}
}
template <typename T, typename TContainer, typename TAllocArg>
static void AllocateMemory(_Out_ MemoryGuard<T, TContainer>& memoryGuard, TAllocArg&& allocArg) noexcept
{
void* containerMemory = TAllocator::Allocate(sizeof(TContainer), std::forward<TAllocArg>(allocArg));
if (containerMemory)
{
memoryGuard.Container = ::new (containerMemory) TContainer();
memoryGuard.ObjMemory = memoryGuard.Container->Get();
Mso::Details::SetWeakRef(memoryGuard.ObjMemory, memoryGuard.Container);
}
}
template <typename T>
static void Delete(T* obj) noexcept
{
obj->~T();
ObjectWeakRef* weakRef = Mso::Details::GetWeakRef(obj);
Mso::Details::SetWeakRef(obj, nullptr);
weakRef->ReleaseWeakRef(); // This call may destroy container and must be the last.
}
template <typename T>
static void Delete(T* obj) noexcept
{
obj->~T();
ObjectWeakRef* weakRef = Mso::Details::GetWeakRef(obj);
Mso::Details::SetWeakRef(obj, nullptr);
weakRef->ReleaseWeakRef(); // This call may destroy container and must be the last.
}
#if DEBUG
template <typename TMemoryGuard>
static void ValidateObject(TMemoryGuard& memoryGuard) noexcept
{
VerifyElseCrashSzTag(memoryGuard.Obj, "Object was not created", 0x01105596 /* tag_befww */);
VerifyElseCrashSzTag(reinterpret_cast<void*>(memoryGuard.Obj) == static_cast<typename TMemoryGuard::Type::TypeToDelete*>(memoryGuard.Obj),
"Ref counted object must be the first type in T inheritance list.", 0x008c2687 /* tag_a9c0h */);
VerifyElseCrashSzTag(reinterpret_cast<void*>(memoryGuard.Container) == &memoryGuard.Obj->GetWeakRef(), "Bad WeakRef", 0x008c2688 /* tag_a9c0i */);
}
template <typename TMemoryGuard>
static void ValidateObject(TMemoryGuard& memoryGuard) noexcept
{
VerifyElseCrashSzTag(memoryGuard.Obj, "Object was not created", 0x01105596 /* tag_befww */);
VerifyElseCrashSzTag(
reinterpret_cast<void*>(memoryGuard.Obj)
== static_cast<typename TMemoryGuard::Type::TypeToDelete*>(memoryGuard.Obj),
"Ref counted object must be the first type in T inheritance list.",
0x008c2687 /* tag_a9c0h */);
VerifyElseCrashSzTag(
reinterpret_cast<void*>(memoryGuard.Container) == &memoryGuard.Obj->GetWeakRef(),
"Bad WeakRef",
0x008c2688 /* tag_a9c0i */);
}
#endif
};
/**
Extend the supported Object ref count strategies with WeakRef.
Extend the supported Object ref count strategies with WeakRef.
*/
namespace RefCountStrategy {
using WeakRef = WeakRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
using WeakRef = WeakRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
}
namespace Details {
/**
Mso::MakeWeakRefObject creates a new instance of class T in container TContainer and returns a TCntPtr to the instance of type TResult.
TResult is either the original type T (default), or one of its interfaces.
Returning an interface type can help to avoid creation of unnecessary TCntPtr template instances.
Mso::MakeWeakRefObject creates a new instance of class T in container TContainer and returns a TCntPtr to the instance
of type TResult. TResult is either the original type T (default), or one of its interfaces. Returning an interface
type can help to avoid creation of unnecessary TCntPtr template instances.
Method MakeWeakRefObject is noexcept depending on the Make policy noexcept value.
Method MakeWeakRefObject is noexcept depending on the Make policy noexcept value.
*/
template <typename T, typename TResult = T, typename TContainer = ObjectWeakRefContainer<T, ObjectWeakRef>, typename... TArgs>
template <
typename T,
typename TResult = T,
typename TContainer = ObjectWeakRefContainer<T, ObjectWeakRef>,
typename... TArgs>
inline Mso::TCntPtr<TResult> MakeWeakRefObject(TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
typename T::RefCountPolicy::template MemoryGuard<T, TContainer> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard);
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x0111774a /* tag_bex3k */);
typename T::RefCountPolicy::template MemoryGuard<T, TContainer> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard);
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x0111774a /* tag_bex3k */);
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef*/ false);
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef*/ false);
}
/**
Mso::MakeAllocWeakRefObject is an Mso::MakeWeakRefObject method for types T that use allocators accepting an argument.
The allocator argument allows to implement stateful allocators.
Mso::MakeAllocWeakRefObject is an Mso::MakeWeakRefObject method for types T that use allocators accepting an argument.
The allocator argument allows to implement stateful allocators.
MakeAllocWeakRefObject creates a new instance of class T in container TContainer and returns a TCntPtr to the instance of type TResult.
TResult is either the original type T (default), or one of its interfaces.
Returning an interface type can help to avoid creation of unnecessary TCntPtr template instantiations.
MakeAllocWeakRefObject creates a new instance of class T in container TContainer and returns a TCntPtr to the instance
of type TResult. TResult is either the original type T (default), or one of its interfaces. Returning an interface
type can help to avoid creation of unnecessary TCntPtr template instantiations.
Method MakeAllocWeakRefObject is noexcept depending on the Make policy noexcept value.
Method MakeAllocWeakRefObject is noexcept depending on the Make policy noexcept value.
*/
template <typename T, typename TResult = T, typename TContainer = ObjectWeakRefContainer<T, ObjectWeakRef>, typename TAllocArg, typename... TArgs>
inline Mso::TCntPtr<TResult> MakeAllocWeakRefObject(TAllocArg&& allocArg, TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
template <
typename T,
typename TResult = T,
typename TContainer = ObjectWeakRefContainer<T, ObjectWeakRef>,
typename TAllocArg,
typename... TArgs>
inline Mso::TCntPtr<TResult> MakeAllocWeakRefObject(TAllocArg&& allocArg, TArgs&&... args) noexcept(
T::MakePolicy::IsNoExcept)
{
typename T::RefCountPolicy::template MemoryGuard<T, TContainer> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard, std::forward<TAllocArg>(allocArg));
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x0111774b /* tag_bex3l */);
typename T::RefCountPolicy::template MemoryGuard<T, TContainer> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard, std::forward<TAllocArg>(allocArg));
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x0111774b /* tag_bex3l */);
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef*/ false);
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef*/ false);
}
} // namespace Details

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Support for IUnknown::QueryInterface implementation.
Support for IUnknown::QueryInterface implementation.
*/
#pragma once
#include <debugAssertApi/debugAssertApi.h>
@ -37,9 +37,12 @@ Here we provide a number of helper templates to implement QueryCast for a type:
// Disable warnings 4625 and 4626 because templates below may have or may not have default copy constructor and
// copy assignment operator depending on the template type parameter. We do not want just to delete them because
// they could be useful in some scenarios when generated.
#pragma warning(disable: 4625) // copy constructor could not be generated because a base class copy constructor is inaccessible or deleted
#pragma warning(disable: 4626) // assignment operator could not be generated because a base class assignment operator is inaccessible or deleted
#pragma warning(disable: 4995) // 'IsDebuggerPresent': name was marked as #pragma deprecated. It is part of VerifyElseCrash macro.
#pragma warning(disable : 4625) // copy constructor could not be generated because a base class copy constructor is
// inaccessible or deleted
#pragma warning(disable : 4626) // assignment operator could not be generated because a base class assignment operator
// is inaccessible or deleted
#pragma warning(disable : 4995) // 'IsDebuggerPresent': name was marked as #pragma deprecated. It is part of
// VerifyElseCrash macro.
namespace Mso {
@ -47,52 +50,52 @@ namespace Mso {
/// Note that we do not call AddRef() here. It is a responsibility of a method that implements IUnknown::QueryInterface.
struct QueryCastHelper
{
/// Implements QueryCast similar to the classic IUnknown::QueryInterface implementation.
template <typename T>
static void* QueryCast(_In_ void* obj, const GUID& riid) noexcept
{
// It has lower priority than the next overload because we use void* instead of T* for the obj.
return (riid == __uuidof(T)) ? obj : nullptr;
}
/// Implements QueryCast similar to the classic IUnknown::QueryInterface implementation.
template <typename T>
static void* QueryCast(_In_ void* obj, const GUID& riid) noexcept
{
// It has lower priority than the next overload because we use void* instead of T* for the obj.
return (riid == __uuidof(T)) ? obj : nullptr;
}
/// Delegates the QueryCast implementation to the object if it has a QueryCast method.
/// If QueryCast fails then we check type's GUID if it is assigned by MSO_STRUCT_GUID or MSO_CLASS_GUID.
template <typename T>
static auto QueryCast(_In_ T* obj, const GUID& riid) noexcept -> decltype(obj->QueryCast(riid))
{
void* result = obj->QueryCast(riid);
return (result) ? result : GuidQueryCast<T>(obj, riid, static_cast<typename Mso::TypeHasGuid<T>::Type*>(nullptr));
}
/// Delegates the QueryCast implementation to the object if it has a QueryCast method.
/// If QueryCast fails then we check type's GUID if it is assigned by MSO_STRUCT_GUID or MSO_CLASS_GUID.
template <typename T>
static auto QueryCast(_In_ T* obj, const GUID& riid) noexcept -> decltype(obj->QueryCast(riid))
{
void* result = obj->QueryCast(riid);
return (result) ? result : GuidQueryCast<T>(obj, riid, static_cast<typename Mso::TypeHasGuid<T>::Type*>(nullptr));
}
/// Recursively calls itself while we have two or more base types.
template <typename TSource, typename TBase0, typename TBase1, typename... TBases>
static void* QueryCastList(TSource& obj, const GUID& riid) noexcept
{
void* result = QueryCastList<TSource, TBase0>(obj, riid);
return (result) ? result : QueryCastList<TSource, TBase1, TBases...>(obj, riid);
}
/// Recursively calls itself while we have two or more base types.
template <typename TSource, typename TBase0, typename TBase1, typename... TBases>
static void* QueryCastList(TSource& obj, const GUID& riid) noexcept
{
void* result = QueryCastList<TSource, TBase0>(obj, riid);
return (result) ? result : QueryCastList<TSource, TBase1, TBases...>(obj, riid);
}
/// An implementation for a type list with just one type.
template <typename TSource, typename TBase>
static void* QueryCastList(TSource& obj, const GUID& riid) noexcept
{
return QueryCast<TBase>(static_cast<TBase*>(&obj), riid);
}
/// An implementation for a type list with just one type.
template <typename TSource, typename TBase>
static void* QueryCastList(TSource& obj, const GUID& riid) noexcept
{
return QueryCast<TBase>(static_cast<TBase*>(&obj), riid);
}
private:
template <typename T>
static void* GuidQueryCast(_In_ T* /*obj*/, const GUID& /*riid*/, Mso::Details::GuidUtils::FalseType*) noexcept
{
// Type has no GUID: do nothing
return nullptr;
}
template <typename T>
static void* GuidQueryCast(_In_ T* /*obj*/, const GUID& /*riid*/, Mso::Details::GuidUtils::FalseType*) noexcept
{
// Type has no GUID: do nothing
return nullptr;
}
template <typename T>
static void* GuidQueryCast(_In_ T* obj, const GUID& riid, Mso::Details::GuidUtils::TrueType*) noexcept
{
// Typecast to void* to force choosing QueryCast overload that checks type's GUID.
return QueryCast<T>(static_cast<void*>(obj), riid);
}
template <typename T>
static void* GuidQueryCast(_In_ T* obj, const GUID& riid, Mso::Details::GuidUtils::TrueType*) noexcept
{
// Typecast to void* to force choosing QueryCast overload that checks type's GUID.
return QueryCast<T>(static_cast<void*>(obj), riid);
}
};
/// Helps to implement static cast for the cases when multiple base types implement the same interface.
@ -105,58 +108,61 @@ struct StaticCastHelper;
template <typename TTarget>
struct StaticCastHelper<TTarget*>
{
/// Try to cast the first base type if it is inherited from TTarget.
template <typename TSource, typename TBase0, typename... TBases>
static TTarget* CastFirst(TSource* source) noexcept
{
return CastIf<TSource, TBase0, TBases...>(typename std::is_base_of<TTarget, TBase0>::type(), source);
}
/// Try to cast the first base type if it is inherited from TTarget.
template <typename TSource, typename TBase0, typename... TBases>
static TTarget* CastFirst(TSource* source) noexcept
{
return CastIf<TSource, TBase0, TBases...>(typename std::is_base_of<TTarget, TBase0>::type(), source);
}
/// A case when no base types are inherited from TTarget.
template <typename TSource>
static TTarget* CastFirst(TSource* /*source*/) noexcept
{
return nullptr;
}
/// A case when no base types are inherited from TTarget.
template <typename TSource>
static TTarget* CastFirst(TSource* /*source*/) noexcept
{
return nullptr;
}
private:
/// First base type is inherited from TTarget. Cast it to TTarget.
template <typename TSource, typename TBase0, typename... TBases>
static TTarget* CastIf(std::true_type /*isConvertible?*/, TSource* source) noexcept
{
return Cast<TBase0>(/*tag:*/ 0, static_cast<TBase0*>(source));
}
/// First base type is inherited from TTarget. Cast it to TTarget.
template <typename TSource, typename TBase0, typename... TBases>
static TTarget* CastIf(std::true_type /*isConvertible?*/, TSource* source) noexcept
{
return Cast<TBase0>(/*tag:*/ 0, static_cast<TBase0*>(source));
}
/// First base type is not inherited from TTarget. Recursively call CastFirst for the remaining base types.
template <typename TSource, typename TBase0, typename... TBases>
static TTarget* CastIf(std::false_type /*isConvertible?*/, TSource* source) noexcept
{
return CastFirst<TSource, TBases...>(source);
}
/// First base type is not inherited from TTarget. Recursively call CastFirst for the remaining base types.
template <typename TSource, typename TBase0, typename... TBases>
static TTarget* CastIf(std::false_type /*isConvertible?*/, TSource* source) noexcept
{
return CastFirst<TSource, TBases...>(source);
}
/// To have a lower priority when matching an int tag parameter.
struct IntWrapper { IntWrapper(int) noexcept {} };
/// To have a lower priority when matching an int tag parameter.
struct IntWrapper
{
IntWrapper(int) noexcept {}
};
/// If TSource has a StaticCastElseNull method then call it to do the static cast.
template <typename TSource>
static auto Cast(int /*tag*/, TSource* source) noexcept -> decltype(source->template StaticCastElseNull<TTarget*>())
{
return source->template StaticCastElseNull<TTarget*>();
}
/// If TSource has a StaticCastElseNull method then call it to do the static cast.
template <typename TSource>
static auto Cast(int /*tag*/, TSource* source) noexcept -> decltype(source->template StaticCastElseNull<TTarget*>())
{
return source->template StaticCastElseNull<TTarget*>();
}
/// Cast using static_cast. It has a lower priority than previous method because we use IntWrapper tag instead of int.
template <typename TSource>
static TTarget* Cast(IntWrapper /*tag*/, TSource* source) noexcept
{
return static_cast<TTarget*>(source);
}
/// Cast using static_cast. It has a lower priority than previous method because we use IntWrapper tag instead of int.
template <typename TSource>
static TTarget* Cast(IntWrapper /*tag*/, TSource* source) noexcept
{
return static_cast<TTarget*>(source);
}
};
//
// Helper templates to implement QueryCast.
//
/// Implements QueryCast for the case when object implements an interface derived from a base interface, and we want to
/// Implements QueryCast for the case when object implements an interface derived from a base interface, and we want to
/// to query the base interface by its GUID.
/// E.g. struct IDerived : IBase {}
/// class MyClass : Mso::QueryCastChain&lt; IDerived, IBase &gt;
@ -164,32 +170,32 @@ template <typename T, typename... TBaseTypes>
class DECLSPEC_NOVTABLE QueryCastChain : public T
{
public:
void* QueryCast(const GUID& riid) noexcept
{
return InternalQueryCast<T, TBaseTypes...>(riid);
}
void* QueryCast(const GUID& riid) noexcept
{
return InternalQueryCast<T, TBaseTypes...>(riid);
}
protected:
template <typename... TArgs>
QueryCastChain(TArgs&&... args) noexcept : T(std::forward<TArgs>(args)...)
{
}
template <typename... TArgs>
QueryCastChain(TArgs&&... args) noexcept : T(std::forward<TArgs>(args)...)
{
}
private:
// Recursively calls itself while we have two or more base types.
template <typename TBaseType0, typename TBaseType1, typename... TOtherBaseTypes>
void* InternalQueryCast(const GUID& riid) noexcept
{
void* result = InternalQueryCast<TBaseType0>(riid);
return (result) ? result : InternalQueryCast<TBaseType1, TOtherBaseTypes...>(riid);
}
// Recursively calls itself while we have two or more base types.
template <typename TBaseType0, typename TBaseType1, typename... TOtherBaseTypes>
void* InternalQueryCast(const GUID& riid) noexcept
{
void* result = InternalQueryCast<TBaseType0>(riid);
return (result) ? result : InternalQueryCast<TBaseType1, TOtherBaseTypes...>(riid);
}
template <typename TBaseType>
void* InternalQueryCast(const GUID& riid) noexcept
{
static_assert(std::is_base_of<TBaseType, T>::value, "T must be inherited from TBaseType");
return QueryCastHelper::QueryCast<TBaseType>(static_cast<TBaseType*>(this), riid);
}
template <typename TBaseType>
void* InternalQueryCast(const GUID& riid) noexcept
{
static_assert(std::is_base_of<TBaseType, T>::value, "T must be inherited from TBaseType");
return QueryCastHelper::QueryCast<TBaseType>(static_cast<TBaseType*>(this), riid);
}
};
/// Implements the QueryCast that can return the derived type by its GUID.
@ -198,39 +204,38 @@ template <typename T>
class QueryCastDerived
{
public:
void* QueryCast(const GUID& riid) noexcept
{
if (riid == __uuidof(T))
{
return static_cast<T*>(this);
}
void* QueryCast(const GUID& riid) noexcept
{
if (riid == __uuidof(T))
{
return static_cast<T*>(this);
}
return nullptr;
}
return nullptr;
}
};
/// Allows to associate a GUID for a type that works only in the scope of the QueryCast operation.
/// This method can be used if type has no associated GUID, but we still want to query for it.
template <typename T, const GUID* piid = static_cast<const GUID *>(nullptr)>
template <typename T, const GUID* piid = static_cast<const GUID*>(nullptr)>
class DECLSPEC_NOVTABLE QueryCastGuid : public T
{
public:
void* QueryCast(const GUID& riid) noexcept
{
if (*Mso::ResolveGuidPtr<T, piid>::Guid == riid)
{
return static_cast<T*>(this);
}
void* QueryCast(const GUID& riid) noexcept
{
if (*Mso::ResolveGuidPtr<T, piid>::Guid == riid)
{
return static_cast<T*>(this);
}
return nullptr;
}
return nullptr;
}
protected:
template <typename... TArgs>
QueryCastGuid(TArgs&&... args) noexcept : T(std::forward<TArgs>(args)...)
{
}
template <typename... TArgs>
QueryCastGuid(TArgs&&... args) noexcept : T(std::forward<TArgs>(args)...)
{
}
};
/// Implements the QueryCast that does not do any query cast for a type.
@ -240,63 +245,67 @@ template <typename T>
class DECLSPEC_NOVTABLE QueryCastHidden : public T
{
public:
void* QueryCast(const GUID& /*riid*/) noexcept
{
(void)(this); // To avoid OACR warning that method can be static
return nullptr;
}
void* QueryCast(const GUID& /*riid*/) noexcept
{
(void)(this); // To avoid OACR warning that method can be static
return nullptr;
}
protected:
template <typename... TArgs>
QueryCastHidden(TArgs&&... args) noexcept : T(std::forward<TArgs>(args)...)
{
}
template <typename... TArgs>
QueryCastHidden(TArgs&&... args) noexcept : T(std::forward<TArgs>(args)...)
{
}
};
/// Delegates the QueryCast implementation to the list of the base types.
/// If a constructor with a non-empty set of parameters then they are forwarded to the TBase0.
template <typename TBase0, typename... TBases>
class DECLSPEC_NOVTABLE QueryCastList : public TBase0, public TBases...
class DECLSPEC_NOVTABLE QueryCastList
: public TBase0
, public TBases...
{
using CastList = int; //TODO: This is a temporary variable. We will have to expand this concept to implement shallow inheritance tree for UnknownObject.
// The goal is to have "using CastList = CastList<TBase0, TBases...>" in UnknownObject.
using ThisType = QueryCastList;
using CastList = int; // TODO: This is a temporary variable. We will have to expand this concept to implement shallow
// inheritance tree for UnknownObject.
// The goal is to have "using CastList = CastList<TBase0, TBases...>" in UnknownObject.
using ThisType = QueryCastList;
protected:
template <typename... TArgs>
QueryCastList(TArgs&&... args) noexcept : TBase0(std::forward<TArgs>(args)...)
{
}
template <typename... TArgs>
QueryCastList(TArgs&&... args) noexcept : TBase0(std::forward<TArgs>(args)...)
{
}
public:
void* QueryCast(const GUID& riid) noexcept
{
return QueryCastHelper::QueryCastList<ThisType, TBase0, TBases...>(*this, riid);
}
void* QueryCast(const GUID& riid) noexcept
{
return QueryCastHelper::QueryCastList<ThisType, TBase0, TBases...>(*this, riid);
}
template <typename TTarget>
TTarget StaticCastElseNull() noexcept
{
return StaticCastHelper<TTarget>::template CastFirst<ThisType, TBase0, TBases...>(this);
}
template <typename TTarget>
TTarget StaticCastElseNull() noexcept
{
return StaticCastHelper<TTarget>::template CastFirst<ThisType, TBase0, TBases...>(this);
}
#pragma warning(suppress: 4265) // class has virtual functions, but destructor is not virtual
#pragma warning(suppress : 4265) // class has virtual functions, but destructor is not virtual
};
/**
A helper class to call QueryCast method for an object.
There are two supported cases:
(1) type has a QueryCast instance method
(2) type is inherited from IUnknown and the implementation supports initialization of a QueryCastBridge instance
inside its IUnknown::QueryInterface() implementation.
The QueryCast typecasting does not call AddRef.
A helper class to call QueryCast method for an object.
There are two supported cases:
(1) type has a QueryCast instance method
(2) type is inherited from IUnknown and the implementation supports initialization of a QueryCastBridge instance
inside its IUnknown::QueryInterface() implementation.
The QueryCast typecasting does not call AddRef.
*/
MSO_STRUCT_GUID(QueryCastBridge, "A39D5FC8-0641-4EEE-8C97-DDEF114D487D")
struct QueryCastBridge
{
// DECLARE_COPYCONSTR_AND_ASSIGNMENT(QueryCastBridge);
void* Object; // It must be a first field. In that case **ppvObject in QueryInterface will have the same semantic as with the normal QueryInterface calls.
const GUID& ObjectId;
// DECLARE_COPYCONSTR_AND_ASSIGNMENT(QueryCastBridge);
void* Object; // It must be a first field. In that case **ppvObject in QueryInterface will have the same semantic as
// with the normal QueryInterface calls.
const GUID& ObjectId;
};
namespace Details {
@ -309,69 +318,72 @@ struct QueryCastConverter; // Default case is undefined.
template <typename TTarget>
struct QueryCastConverter<TTarget&>
{
template <typename TSource>
static TTarget& QueryCast(const TSource& source) noexcept
{
using SourceType = std::decay_t<TSource>;
using TargetType = std::decay_t<TTarget>;
static_assert(!std::is_pointer<SourceType>::value, "Cannot convert pointer to a reference.");
template <typename TSource>
static TTarget& QueryCast(const TSource& source) noexcept
{
using SourceType = std::decay_t<TSource>;
using TargetType = std::decay_t<TTarget>;
static_assert(!std::is_pointer<SourceType>::value, "Cannot convert pointer to a reference.");
SourceType* nonConstSource = const_cast<SourceType*>(&source);
QueryCastBridge bridge = { nullptr, __uuidof(TargetType) };
VerifySucceededElseCrashTag(nonConstSource->QueryInterface(__uuidof(QueryCastBridge), reinterpret_cast<void**>(&bridge)), 0x0100370d /* tag_bad2n */);
SourceType* nonConstSource = const_cast<SourceType*>(&source);
QueryCastBridge bridge = {nullptr, __uuidof(TargetType)};
VerifySucceededElseCrashTag(
nonConstSource->QueryInterface(__uuidof(QueryCastBridge), reinterpret_cast<void**>(&bridge)),
0x0100370d /* tag_bad2n */);
TargetType* target = static_cast<TargetType*>(bridge.Object);
VerifyElseCrashSzTag(target, "Query cast failed for a reference type.", 0x0100370e /* tag_bad2o */);
return static_cast<TTarget&>(*target);
}
TargetType* target = static_cast<TargetType*>(bridge.Object);
VerifyElseCrashSzTag(target, "Query cast failed for a reference type.", 0x0100370e /* tag_bad2o */);
return static_cast<TTarget&>(*target);
}
};
// Specialization for pointer conversion
template <typename TTarget>
struct QueryCastConverter<TTarget*>
{
template <typename TSource>
static TTarget* QueryCast(const TSource& source) noexcept
{
using SourceType = std::remove_const_t<std::remove_pointer_t<std::decay_t<TSource>>>;
using TargetType = std::decay_t<TTarget>;
static_assert(std::is_pointer<TSource>::value, "Cannot convert non-pointer to a pointer.");
template <typename TSource>
static TTarget* QueryCast(const TSource& source) noexcept
{
using SourceType = std::remove_const_t<std::remove_pointer_t<std::decay_t<TSource>>>;
using TargetType = std::decay_t<TTarget>;
static_assert(std::is_pointer<TSource>::value, "Cannot convert non-pointer to a pointer.");
if (source != nullptr)
{
SourceType* nonConstSource = const_cast<SourceType*>(source);
QueryCastBridge bridge = { nullptr, __uuidof(TargetType) };
if (nonConstSource->QueryInterface(__uuidof(QueryCastBridge), reinterpret_cast<void**>(&bridge)) == S_OK)
{
TargetType* target = static_cast<TargetType*>(bridge.Object);
return static_cast<TTarget*>(target);
}
}
if (source != nullptr)
{
SourceType* nonConstSource = const_cast<SourceType*>(source);
QueryCastBridge bridge = {nullptr, __uuidof(TargetType)};
if (nonConstSource->QueryInterface(__uuidof(QueryCastBridge), reinterpret_cast<void**>(&bridge)) == S_OK)
{
TargetType* target = static_cast<TargetType*>(bridge.Object);
return static_cast<TTarget*>(target);
}
}
return nullptr;
}
return nullptr;
}
};
}} // namespace Mso::Details
} // namespace Details
} // namespace Mso
/**
query_cast does a dynamic cast based on a type GUID.
It does not call AddRef. Caller of this method is responsible for the object's lifetime management.
TTarget is required to be either a pointer or a reference (similar to dynamic_cast).
E.g. query_cast< IMyIntf* >( x ), or query_cast< IMyIntf& >( x ).
query_cast does a dynamic cast based on a type GUID.
It does not call AddRef. Caller of this method is responsible for the object's lifetime management.
TTarget is required to be either a pointer or a reference (similar to dynamic_cast).
E.g. query_cast< IMyIntf* >( x ), or query_cast< IMyIntf& >( x ).
If query_cast fails to convert to a pointer type then it returns nullptr.
If query_cast fails to convert to a reference type then it crashes the app.
If query_cast fails to convert to a pointer type then it returns nullptr.
If query_cast fails to convert to a reference type then it crashes the app.
For this method to work, the TSource class must support initialization of QueryCastBridge struct
when queried for its GUID. UnknownObject in core\msoUnknownObject.h provides all necessary support.
For this method to work, the TSource class must support initialization of QueryCastBridge struct
when queried for its GUID. UnknownObject in core\msoUnknownObject.h provides all necessary support.
query_cast can be used when we want to do a dynamic cast and do not need to call AddRef to control object lifetime.
query_cast can be used when we want to do a dynamic cast and do not need to call AddRef to control object lifetime.
*/
template <typename TTarget, typename TSource>
TTarget query_cast(TSource&& source) noexcept
{
return Mso::Details::QueryCastConverter<TTarget>::QueryCast(std::forward<TSource>(source));
return Mso::Details::QueryCastConverter<TTarget>::QueryCast(std::forward<TSource>(source));
}
#pragma warning(pop)

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Helper classes for internal ref-counting
Helper classes for internal ref-counting
*/
#pragma once
#include <core/TCntPtr.h>

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
IRefCounted implementation.
IRefCounted implementation.
*/
#pragma once
@ -21,528 +21,538 @@ BEGIN_DISABLE_WARNING_INCONSISTENT_MISSING_OVERRIDE()
namespace Mso {
/**
RefCountedObject is a class template to implement the IRefCounted interface.
RefCountedObject is a class template to implement the IRefCounted interface.
Because RefCountedObject overrides AddRef and Release, at least one of your base types should
declare virtual AddRef/Release methods. Usually you'd specify at least "Mso::IRefCounted" or
some interface that derives from IRefCounted.
Because RefCountedObject overrides AddRef and Release, at least one of your base types should
declare virtual AddRef/Release methods. Usually you'd specify at least "Mso::IRefCounted" or
some interface that derives from IRefCounted.
If you want to avoid the overhead of a v-table, you can use RefCountedObjectNoVTable, which
defines non-virtual AddRef/Release methods. These are still compatible with templated
smart pointers like TCntPtr and ComPtr because those smart pointers don't actually use
virtual method dispatch to call AddRef/Release.
If you want to avoid the overhead of a v-table, you can use RefCountedObjectNoVTable, which
defines non-virtual AddRef/Release methods. These are still compatible with templated
smart pointers like TCntPtr and ComPtr because those smart pointers don't actually use
virtual method dispatch to call AddRef/Release.
To implement IUnknown, use Mso::UnknownObject.
To implement IUnknown, use Mso::UnknownObject.
RefCountedObject provides variants that allow for various combinations of weak references,
multiple inheritance, or just implementing IRefCounted.
RefCountedObject provides variants that allow for various combinations of weak references,
multiple inheritance, or just implementing IRefCounted.
Use Mso::Make to instantiate classes that derive from RefCountedObject.
Use Mso::Make to instantiate classes that derive from RefCountedObject.
EXAMPLES
--------
EXAMPLES
--------
1) A simple class that implements IRefCounted:
1) A simple class that implements IRefCounted:
class Foo : public Mso::RefCountedObject<Mso::IRefCounted>
{
...
};
class Foo : public Mso::RefCountedObject<Mso::IRefCounted>
{
...
};
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
2) A class that implements some interface that derives from IRefCounted:
2) A class that implements some interface that derives from IRefCounted:
struct IBar : public Mso::IRefCounted { ... };
struct IBar : public Mso::IRefCounted { ... };
class Foo : public Mso::RefCountedObject<IBar>
{
...
};
class Foo : public Mso::RefCountedObject<IBar>
{
...
};
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
Mso::TCntPtr<IBar> spBar = Mso::Make<Foo, IBar>(); // Create a TCntPtr<IBar> directly.
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
Mso::TCntPtr<IBar> spBar = Mso::Make<Foo, IBar>(); // Create a TCntPtr<IBar> directly.
3) A class that inherits from multiple base types and implements IRefCounted:
3) A class that inherits from multiple base types and implements IRefCounted:
class Foo : public Mso::RefCountedObject<SomeBaseType, SomeOtherBaseType, Mso::IRefCounted>
{
...
};
class Foo : public Mso::RefCountedObject<SomeBaseType, SomeOtherBaseType, Mso::IRefCounted>
{
...
};
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
4) A class that implements IRefCounted and has support for weak references:
4) A class that implements IRefCounted and has support for weak references:
class Foo : public Mso::RefCountedObject<Mso::RefCountStrategy::WeakRef, Mso::IRefCounted>
{
...
};
class Foo : public Mso::RefCountedObject<Mso::RefCountStrategy::WeakRef, Mso::IRefCounted>
{
...
};
void Foo::RegisterForEventRequiringWeakRef(SomeEventSource& event)
{
// Use WeakPtr to capture a weak reference.
Mso::WeakPtr<Foo> wrThis(this);
event.Register([wrThis]
{
// Use GetStrongPtr to resolve the weak reference.
auto spThis = wrThis.GetStrongPtr();
if (spThis)
spThis->DoSomethingInResponseToEvent();
});
}
void Foo::RegisterForEventRequiringWeakRef(SomeEventSource& event)
{
// Use WeakPtr to capture a weak reference.
Mso::WeakPtr<Foo> wrThis(this);
event.Register([wrThis]
{
// Use GetStrongPtr to resolve the weak reference.
auto spThis = wrThis.GetStrongPtr();
if (spThis)
spThis->DoSomethingInResponseToEvent();
});
}
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
5) A class that implements IRefCounted with weak references and a custom deleter:
5) A class that implements IRefCounted with weak references and a custom deleter:
struct FooDeleter
{
template <typename T>
static void Delete(T* obj) noexcept
{
...
}
};
struct FooDeleter
{
template <typename T>
static void Delete(T* obj) noexcept
{
...
}
};
using FooRefCountPolicy = Mso::WeakRefCountPolicy<FooDeleter>;
using FooRefCountPolicy = Mso::WeakRefCountPolicy<FooDeleter>;
class Foo : public Mso::RefCountedObject<FooRefCountPolicy, Mso::IRefCounted>
{
...
};
class Foo : public Mso::RefCountedObject<FooRefCountPolicy, Mso::IRefCounted>
{
...
};
void Foo::RegisterForEventRequiringWeakRef(SomeEventSource& event)
{
// Use WeakPtr to capture a weak reference.
Mso::WeakPtr<Foo> wrThis(this);
event.Register([wrThis]
{
// Use GetStrongPtr to resolve the weak reference.
auto spThis = wrThis.GetStrongPtr();
if (spThis)
spThis->DoSomethingInResponseToEvent();
});
}
void Foo::RegisterForEventRequiringWeakRef(SomeEventSource& event)
{
// Use WeakPtr to capture a weak reference.
Mso::WeakPtr<Foo> wrThis(this);
event.Register([wrThis]
{
// Use GetStrongPtr to resolve the weak reference.
auto spThis = wrThis.GetStrongPtr();
if (spThis)
spThis->DoSomethingInResponseToEvent();
});
}
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
6) A class that implements some IRefCounted-derived interface, with a private constructor.
6) A class that implements some IRefCounted-derived interface, with a private constructor.
Use 'friend MakePolicy' to make your constructor private. This helps ensure that
people only use Mso::Make to instantiate your class.
Use 'friend MakePolicy' to make your constructor private. This helps ensure that
people only use Mso::Make to instantiate your class.
struct IBar : public Mso::IRefCounted { ... };
struct IBar : public Mso::IRefCounted { ... };
class Foo : public Mso::RefCountedObject<IBar>
{
friend MakePolicy;
class Foo : public Mso::RefCountedObject<IBar>
{
friend MakePolicy;
private:
Foo(const Bar& bar) noexcept { ... } // Private constructor
private:
Foo(const Bar& bar) noexcept { ... } // Private constructor
...
};
...
};
const Bar& bar = ...;
Mso::TCntPtr<Foo> spFoo = Mso::Make(bar);
const Bar& bar = ...;
Mso::TCntPtr<Foo> spFoo = Mso::Make(bar);
7) A class that uses the 'InitializeThis' pattern, which allows you to separate object construction
from other initialization.
7) A class that uses the 'InitializeThis' pattern, which allows you to separate object construction
from other initialization.
If InitializeThis returns false, Mso::Make will crash the app.
If InitializeThis returns false, Mso::Make will crash the app.
struct IBar : public Mso::IRefCounted { ... };
struct IBar : public Mso::IRefCounted { ... };
class Foo : public Mso::RefCountedObject<IBar>
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
class Foo : public Mso::RefCountedObject<IBar>
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
Foo() noexcept { ... }
Foo() noexcept { ... }
bool InitializeThis(const Baz& baz, const Qux& qux)
{
...
bool InitializeThis(const Baz& baz, const Qux& qux)
{
...
// Return 'true' to indicate the object was successfully initialized. 'false' will crash the app.
return true;
}
};
// Return 'true' to indicate the object was successfully initialized. 'false' will crash the app.
return true;
}
};
const Baz& baz = ...;
const Qux& qux = ...;
Mso::TCntPtr<Foo> spFoo = Mso::Make(baz, qux);
const Baz& baz = ...;
const Qux& qux = ...;
Mso::TCntPtr<Foo> spFoo = Mso::Make(baz, qux);
8) A class that uses ref counting without a v-table.
8) A class that uses ref counting without a v-table.
Non-virtual AddRef and Release methods are implemented. These are still compatible with most
template-based smart-pointers (like TCntPtr and ComPtr) since they call 'AddRef' and 'Release'
by name and not necessarily through virtual-method dispatch.
Non-virtual AddRef and Release methods are implemented. These are still compatible with most
template-based smart-pointers (like TCntPtr and ComPtr) since they call 'AddRef' and 'Release'
by name and not necessarily through virtual-method dispatch.
Note that RefCountedObjectNoVTable uses the "Curiously Recursive Template Pattern" which requires
that the derived type be passed in as a template parameter.
Note that RefCountedObjectNoVTable uses the "Curiously Recursive Template Pattern" which requires
that the derived type be passed in as a template parameter.
class Foo : public Mso::RefCountedObjectNoVTable<Foo>
{
...
};
class Foo : public Mso::RefCountedObjectNoVTable<Foo>
{
...
};
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
9) A class that implements IRefCounted without actual ref counting.
9) A class that implements IRefCounted without actual ref counting.
This can be useful if the object's lifetime is managed via some other method, but the object
still needs to be used with TCntPtr or other code that expects AddRef/Release.
This often happens in two scenarios:
This can be useful if the object's lifetime is managed via some other method, but the object
still needs to be used with TCntPtr or other code that expects AddRef/Release.
This often happens in two scenarios:
- Singletons that want to avoid any AddRef/Release because there is one long-lived instance.
- Stack-based allocations for unit tests.
- Singletons that want to avoid any AddRef/Release because there is one long-lived instance.
- Stack-based allocations for unit tests.
class Foo : public Mso::RefCountedObject<Mso::RefCountStrategy::NoRefCount, Mso::IRefCounted>
{
...
};
class Foo : public Mso::RefCountedObject<Mso::RefCountStrategy::NoRefCount, Mso::IRefCounted>
{
...
};
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
10) A class that implements IRefCounted with a custom stateless allocator.
10) A class that implements IRefCounted with a custom stateless allocator.
struct FooAllocator
{
static void* Allocate(size_t size) noexcept
{
...
}
struct FooAllocator
{
static void* Allocate(size_t size) noexcept
{
...
}
static void Deallocate(void* ptr) noexcept
{
...
}
};
static void Deallocate(void* ptr) noexcept
{
...
}
};
struct IBar : public Mso::IRefCounted { ... };
struct IBar : public Mso::IRefCounted { ... };
class Foo : public Mso::RefCountedObject<Mso::SimpleRefCountPolicy<Mso::DefaultRefCountedDeleter, FooAllocator>, IBar>
{
...
};
class Foo : public Mso::RefCountedObject<Mso::SimpleRefCountPolicy<Mso::DefaultRefCountedDeleter, FooAllocator>,
IBar>
{
...
};
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>();
11) A class that implements IRefCounted with a custom stateful allocator.
11) A class that implements IRefCounted with a custom stateful allocator.
struct ICustomHeap
{
virtual void* Alloc(size_t size) noexcept = 0;
virtual void Free(void* ptr) noexcept = 0;
};
struct ICustomHeap
{
virtual void* Alloc(size_t size) noexcept = 0;
virtual void Free(void* ptr) noexcept = 0;
};
struct FooAllocator
{
static void* Allocate(size_t size, ICustomHeap* heap) noexcept
{
...
}
struct FooAllocator
{
static void* Allocate(size_t size, ICustomHeap* heap) noexcept
{
...
}
static void Deallocate(void* ptr) noexcept
{
...
}
};
static void Deallocate(void* ptr) noexcept
{
...
}
};
struct IBar : public Mso::IRefCounted { ... };
struct IBar : public Mso::IRefCounted { ... };
class Foo : public Mso::RefCountedObject<Mso::SimpleRefCountPolicy<Mso::DefaultRefCountedDeleter, FooAllocator>, IBar>
{
...
};
class Foo : public Mso::RefCountedObject<Mso::SimpleRefCountPolicy<Mso::DefaultRefCountedDeleter, FooAllocator>,
IBar>
{
...
};
ICustomHeap& heap = ...;
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>(&heap);
ICustomHeap& heap = ...;
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>(&heap);
12) A class that has a throwing ctor and implements IRefCounted:
12) A class that has a throwing ctor and implements IRefCounted:
struct Foo : public Mso::RefCountedObject<Mso::IRefCounted>
{
using MakePolicy = Mso::MakePolicy::ThrowCtor;
struct Foo : public Mso::RefCountedObject<Mso::IRefCounted>
{
using MakePolicy = Mso::MakePolicy::ThrowCtor;
Foo(); // can throw
...
};
Foo(); // can throw
...
};
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>(); // can throw
Mso::TCntPtr<Foo> spFoo = Mso::Make<Foo>(); // can throw
*/
template <typename TBaseType0, typename... TBaseTypes>
class RefCountedObject
: public TBaseType0
, public TBaseTypes...
: public TBaseType0
, public TBaseTypes...
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::SimpleRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
friend RefCountPolicy;
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::SimpleRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
friend RefCountPolicy;
using RefCountedObjectType = RefCountedObject; // To use in derived class as "using Super = RefCountedObjectType"
using TypeToDelete = RefCountedObject; // To verify that TypeToDelete is the first in the inheritance chain.
using RefCountedObjectType = RefCountedObject; // To use in derived class as "using Super = RefCountedObjectType"
using TypeToDelete = RefCountedObject; // To verify that TypeToDelete is the first in the inheritance chain.
_MSO_OBJECT_SIMPLEREFCOUNT(RefCountedObject);
_MSO_OBJECT_SIMPLEREFCOUNT(RefCountedObject);
void AddRef() const noexcept override
{
if (++m_refCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Ref count must not bounce from zero", 0x01105597 /* tag_befwx */));
}
}
void AddRef() const noexcept override
{
if (++m_refCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Ref count must not bounce from zero", 0x01105597 /* tag_befwx */));
}
}
void Release() const noexcept override
{
const uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x01105598 /* tag_befwy */));
if (refCount == 0)
{
RefCountPolicy::Delete(const_cast<RefCountedObject*>(this));
}
}
void Release() const noexcept override
{
const uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(
static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x01105598 /* tag_befwy */));
if (refCount == 0)
{
RefCountPolicy::Delete(const_cast<RefCountedObject*>(this));
}
}
protected:
template <typename... TArgs>
RefCountedObject(TArgs&&... args) noexcept : TBaseType0(std::forward<TArgs>(args)...) {}
template <typename... TArgs>
RefCountedObject(TArgs&&... args) noexcept : TBaseType0(std::forward<TArgs>(args)...)
{
}
virtual ~RefCountedObject() = default;
virtual ~RefCountedObject() = default;
private:
mutable std::atomic<uint32_t> m_refCount { 1 };
mutable std::atomic<uint32_t> m_refCount{1};
};
template <typename TDeleter, typename TAllocator, typename TBaseType0, typename... TBaseTypes>
class RefCountedObject<Mso::SimpleRefCountPolicy<TDeleter, TAllocator>, TBaseType0, TBaseTypes...>
: public TBaseType0
, public TBaseTypes...
: public TBaseType0
, public TBaseTypes...
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::SimpleRefCountPolicy<TDeleter, TAllocator>;
friend RefCountPolicy;
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::SimpleRefCountPolicy<TDeleter, TAllocator>;
friend RefCountPolicy;
using RefCountedObjectType = RefCountedObject; // To use in derived class as "using Super = RefCountedObjectType"
using TypeToDelete = RefCountedObject; // To verify that TypeToDelete is the first in the inheritance chain.
using RefCountedObjectType = RefCountedObject; // To use in derived class as "using Super = RefCountedObjectType"
using TypeToDelete = RefCountedObject; // To verify that TypeToDelete is the first in the inheritance chain.
_MSO_OBJECT_SIMPLEREFCOUNT(RefCountedObject);
_MSO_OBJECT_SIMPLEREFCOUNT(RefCountedObject);
void AddRef() const noexcept override
{
if (++m_refCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Ref count must not bounce from zero", 0x01105599 /* tag_befwz */));
}
}
void AddRef() const noexcept override
{
if (++m_refCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Ref count must not bounce from zero", 0x01105599 /* tag_befwz */));
}
}
void Release() const noexcept override
{
const uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x0110559a /* tag_befw0 */));
if (refCount == 0)
{
TDeleter::Delete(const_cast<RefCountedObject*>(this));
}
}
void Release() const noexcept override
{
const uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(
static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x0110559a /* tag_befw0 */));
if (refCount == 0)
{
TDeleter::Delete(const_cast<RefCountedObject*>(this));
}
}
protected:
template <typename... TArgs>
RefCountedObject(TArgs&&... args) noexcept : TBaseType0(std::forward<TArgs>(args)...) {}
template <typename... TArgs>
RefCountedObject(TArgs&&... args) noexcept : TBaseType0(std::forward<TArgs>(args)...)
{
}
virtual ~RefCountedObject() = default;
virtual ~RefCountedObject() = default;
private:
mutable std::atomic<uint32_t> m_refCount { 1 };
mutable std::atomic<uint32_t> m_refCount{1};
};
template <typename TDeleter, typename TAllocator, typename TBaseType0, typename... TBaseTypes>
class RefCountedObject<Mso::WeakRefCountPolicy<TDeleter, TAllocator>, TBaseType0, TBaseTypes...>
: public TBaseType0
, public TBaseTypes...
: public TBaseType0
, public TBaseTypes...
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::WeakRefCountPolicy<TDeleter, TAllocator>;
friend RefCountPolicy;
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::WeakRefCountPolicy<TDeleter, TAllocator>;
friend RefCountPolicy;
using RefCountedObjectType = RefCountedObject; // To use in derived class as "using Super = RefCountedObjectType"
using TypeToDelete = RefCountedObject; // To verify that TypeToDelete is the first in the inheritance chain.
using RefCountedObjectType = RefCountedObject; // To use in derived class as "using Super = RefCountedObjectType"
using TypeToDelete = RefCountedObject; // To verify that TypeToDelete is the first in the inheritance chain.
_MSO_OBJECT_WEAKREFCOUNT(RefCountedObject);
_MSO_OBJECT_WEAKREFCOUNT(RefCountedObject);
void AddRef() const noexcept override
{
GetWeakRef().AddRef();
}
void AddRef() const noexcept override
{
GetWeakRef().AddRef();
}
void Release() const noexcept override
{
GetWeakRef().Release();
}
void Release() const noexcept override
{
GetWeakRef().Release();
}
protected:
template <typename... TArgs>
RefCountedObject(TArgs&&... args) noexcept : TBaseType0(std::forward<TArgs>(args)...) {}
template <typename... TArgs>
RefCountedObject(TArgs&&... args) noexcept : TBaseType0(std::forward<TArgs>(args)...)
{
}
virtual ~RefCountedObject() = default;
virtual ~RefCountedObject() = default;
};
template <typename TBaseType0, typename... TBaseTypes>
class RefCountedObject<Mso::RefCountStrategy::NoRefCount, TBaseType0, TBaseTypes...>
: public TBaseType0
, public TBaseTypes...
: public TBaseType0
, public TBaseTypes...
{
public:
using RefCountedObjectType = RefCountedObject; // To use in derived class as "using Super = RefCountedObjectType"
using RefCountedObjectType = RefCountedObject; // To use in derived class as "using Super = RefCountedObjectType"
_MSO_OBJECT_NOREFCOUNT(RefCountedObject);
_MSO_OBJECT_NOREFCOUNT(RefCountedObject);
template <typename... TArgs>
RefCountedObject(TArgs&&... args) noexcept : TBaseType0(std::forward<TArgs>(args)...) {}
template <typename... TArgs>
RefCountedObject(TArgs&&... args) noexcept : TBaseType0(std::forward<TArgs>(args)...)
{
}
void AddRef() const noexcept override {}
void Release() const noexcept override {}
virtual ~RefCountedObject() = default;
void AddRef() const noexcept override {}
void Release() const noexcept override {}
virtual ~RefCountedObject() = default;
};
template <typename... Ts>
class RefCountedObjectNoVTable;
/**
A base class for ref counted objects that do not have v-table and need a simple ref count.
A base class for ref counted objects that do not have v-table and need a simple ref count.
*/
template <typename TDerived>
class RefCountedObjectNoVTable<TDerived>
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::SimpleRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
friend RefCountPolicy;
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::SimpleRefCountPolicy<DefaultRefCountedDeleter, MakeAllocator>;
friend RefCountPolicy;
using RefCountedObjectNoVTableType = RefCountedObjectNoVTable; // To use in derived class as "using Super = RefCountedObjectNoVTableType"
using TypeToDelete = TDerived; // To verify that TypeToDelete is the first in the inheritance chain.
using RefCountedObjectNoVTableType =
RefCountedObjectNoVTable; // To use in derived class as "using Super = RefCountedObjectNoVTableType"
using TypeToDelete = TDerived; // To verify that TypeToDelete is the first in the inheritance chain.
_MSO_OBJECT_SIMPLEREFCOUNT(RefCountedObjectNoVTable);
_MSO_OBJECT_SIMPLEREFCOUNT(RefCountedObjectNoVTable);
void AddRef() const noexcept
{
if (++m_refCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Ref count must not bounce from zero", 0x0110559b /* tag_befw1 */));
}
}
void AddRef() const noexcept
{
if (++m_refCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Ref count must not bounce from zero", 0x0110559b /* tag_befw1 */));
}
}
void Release() const noexcept
{
const uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x0110559c /* tag_befw2 */));
if (refCount == 0)
{
RefCountPolicy::Delete(const_cast<TDerived*>(static_cast<const TDerived*>(this)));
}
}
void Release() const noexcept
{
const uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(
static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x0110559c /* tag_befw2 */));
if (refCount == 0)
{
RefCountPolicy::Delete(const_cast<TDerived*>(static_cast<const TDerived*>(this)));
}
}
protected:
RefCountedObjectNoVTable() = default;
RefCountedObjectNoVTable() = default;
private:
mutable std::atomic<uint32_t> m_refCount { 1 };
mutable std::atomic<uint32_t> m_refCount{1};
};
/**
A base class for RefCounted objects that do not have v-table and need a simple ref count.
A base class for RefCounted objects that do not have v-table and need a simple ref count.
*/
template <typename TDeleter, typename TAllocator, typename TDerived>
class RefCountedObjectNoVTable<Mso::SimpleRefCountPolicy<TDeleter, TAllocator>, TDerived>
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::SimpleRefCountPolicy<TDeleter, TAllocator>;
friend RefCountPolicy;
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::SimpleRefCountPolicy<TDeleter, TAllocator>;
friend RefCountPolicy;
using RefCountedObjectNoVTableType = RefCountedObjectNoVTable; // To use in derived class as "using Super = RefCountedObjectNoVTableType"
using TypeToDelete = TDerived; // To verify that TypeToDelete is the first in the inheritance chain.
using RefCountedObjectNoVTableType =
RefCountedObjectNoVTable; // To use in derived class as "using Super = RefCountedObjectNoVTableType"
using TypeToDelete = TDerived; // To verify that TypeToDelete is the first in the inheritance chain.
_MSO_OBJECT_SIMPLEREFCOUNT(RefCountedObjectNoVTable);
_MSO_OBJECT_SIMPLEREFCOUNT(RefCountedObjectNoVTable);
void AddRef() const noexcept
{
if (++m_refCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Ref count must not bounce from zero", 0x0110559d /* tag_befw3 */));
}
}
void AddRef() const noexcept
{
if (++m_refCount == 1)
{
Debug(VerifyElseCrashSzTag(false, "Ref count must not bounce from zero", 0x0110559d /* tag_befw3 */));
}
}
void Release() const noexcept
{
const uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x0110559e /* tag_befw4 */));
if (refCount == 0)
{
TDeleter::Delete(const_cast<TDerived*>(static_cast<const TDerived*>(this)));
}
}
void Release() const noexcept
{
const uint32_t refCount = --m_refCount;
Debug(VerifyElseCrashSzTag(
static_cast<int32_t>(refCount) >= 0, "Ref count must not be negative.", 0x0110559e /* tag_befw4 */));
if (refCount == 0)
{
TDeleter::Delete(const_cast<TDerived*>(static_cast<const TDerived*>(this)));
}
}
protected:
RefCountedObjectNoVTable() = default;
RefCountedObjectNoVTable() = default;
private:
mutable std::atomic<uint32_t> m_refCount { 1 };
mutable std::atomic<uint32_t> m_refCount{1};
};
/**
A base class for RefCounted objects that do not have v-table and need support for weak ref count.
A base class for RefCounted objects that do not have v-table and need support for weak ref count.
*/
template <typename TDeleter, typename TAllocator, typename TDerived>
class RefCountedObjectNoVTable<Mso::WeakRefCountPolicy<TDeleter, TAllocator>, TDerived>
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::WeakRefCountPolicy<TDeleter, TAllocator>;
friend RefCountPolicy;
using MakePolicy = Mso::MakePolicy::NoThrowCtor;
using RefCountPolicy = Mso::WeakRefCountPolicy<TDeleter, TAllocator>;
friend RefCountPolicy;
using RefCountedObjectNoVTableType = RefCountedObjectNoVTable; // To use in derived class as "using Super = RefCountedObjectNoVTableType"
using TypeToDelete = TDerived; // To verify that TypeToDelete is the first in the inheritance chain.
using RefCountedObjectNoVTableType =
RefCountedObjectNoVTable; // To use in derived class as "using Super = RefCountedObjectNoVTableType"
using TypeToDelete = TDerived; // To verify that TypeToDelete is the first in the inheritance chain.
_MSO_OBJECT_WEAKREFCOUNT(RefCountedObjectNoVTable);
_MSO_OBJECT_WEAKREFCOUNT(RefCountedObjectNoVTable);
void AddRef() const noexcept
{
GetWeakRef().AddRef();
}
void AddRef() const noexcept
{
GetWeakRef().AddRef();
}
void Release() const noexcept
{
GetWeakRef().Release();
}
void Release() const noexcept
{
GetWeakRef().Release();
}
protected:
RefCountedObjectNoVTable() = default;
RefCountedObjectNoVTable() = default;
};
} // namespace Mso

Просмотреть файл

@ -21,7 +21,7 @@ share the same reference counter.
//
// Any class that is inherited from UnknownObjectWithWeakRef can be part of a swarm.
//
// Use SwarmMemberPtr or WeakPtr to reference swarm members between each other. Using TCntPtr between
// Use SwarmMemberPtr or WeakPtr to reference swarm members between each other. Using TCntPtr between
// swarm members may cause a memory leak because of an extra ref count to itself.
// SwarmMemberPtr may be used for strong pointers and WeakPtr for weak pointers.
// Do not use the ObjectWeakRef for weak pointers because there is only one ObjectWeakRef for all swarm members.
@ -35,8 +35,10 @@ share the same reference counter.
#pragma pack(push, _CRT_PACKING)
#pragma warning(push)
#pragma warning(disable: 4625) // copy constructor could not be generated because a base class copy constructor is inaccessible or deleted
#pragma warning(disable: 4626) // assignment operator could not be generated because a base class assignment operator is inaccessible or deleted
#pragma warning(disable : 4625) // copy constructor could not be generated because a base class copy constructor is
// inaccessible or deleted
#pragma warning(disable : 4626) // assignment operator could not be generated because a base class assignment operator
// is inaccessible or deleted
#pragma push_macro("new")
#undef new
@ -48,44 +50,43 @@ namespace Details {
template <typename T>
struct ObjectWeakRefContainerDeleter
{
void operator ()(T* ptr) noexcept
{
if (ptr)
{
ptr->DestroyContainer();
}
}
void operator()(T* ptr) noexcept
{
if (ptr)
{
ptr->DestroyContainer();
}
}
};
} // namespace Details
/**
A base class to hold a swarm members.
A swarm member is allocated as a part of the ObjectWeakRefContainer<T, SwarmMemberHolder> class instance.
SwarmMemberHolder instances form a single linked list.
A base class to hold a swarm members.
A swarm member is allocated as a part of the ObjectWeakRefContainer<T, SwarmMemberHolder> class instance.
SwarmMemberHolder instances form a single linked list.
*/
class SwarmMemberHolder
{
public:
using UniquePtrType = std::unique_ptr<SwarmMemberHolder, Details::ObjectWeakRefContainerDeleter<SwarmMemberHolder>>;
static_assert(sizeof(UniquePtrType) == sizeof(void*), "SwarmMemberHolder::UniquePtrType must have a pointer size. It is needed for using InterlockedCompareExchangePointer below.");
using UniquePtrType = std::unique_ptr<SwarmMemberHolder, Details::ObjectWeakRefContainerDeleter<SwarmMemberHolder>>;
static_assert(
sizeof(UniquePtrType) == sizeof(void*),
"SwarmMemberHolder::UniquePtrType must have a pointer size. It is needed for using InterlockedCompareExchangePointer below.");
virtual ~SwarmMemberHolder() noexcept
{
}
virtual ~SwarmMemberHolder() noexcept {}
protected:
virtual void DestroyObject() noexcept
{
}
virtual void DestroyObject() noexcept {}
virtual void DestroyContainer() const noexcept = 0;
virtual void DestroyContainer() const noexcept = 0;
private:
UniquePtrType m_nextMember; // Pointer to the next member in a list.
UniquePtrType m_nextMember; // Pointer to the next member in a list.
friend class Swarm;
template <typename T> friend struct Details::ObjectWeakRefContainerDeleter;
friend class Swarm;
template <typename T>
friend struct Details::ObjectWeakRefContainerDeleter;
};
// Forward declaration
@ -94,481 +95,474 @@ class Swarm;
template <typename T, typename TContainer>
struct SwarmMemberMemoryGuard
{
using Type = T;
using Type = T;
~SwarmMemberMemoryGuard() noexcept;
~SwarmMemberMemoryGuard() noexcept;
public: // We use a public fields to reduce number of generated methods.
// VC++ bug: Make sure that the order of the fields is the same for all memory guards. Otherwise, VC++ generates incorrect code for ship builds.
void* ObjMemory;
T* Obj;
Swarm* Container;
TContainer* MemberContainer;
// VC++ bug: Make sure that the order of the fields is the same for all memory guards. Otherwise, VC++ generates
// incorrect code for ship builds.
void* ObjMemory;
T* Obj;
Swarm* Container;
TContainer* MemberContainer;
};
/**
Swarm is a special ObjectWeakRef that owns 1 or more objects.
When Swarm ref count goes to zero it destroys all objects in the Swarm.
Swarm may have any object inherited from a WeakSourceRefCount.
Swarm is a special ObjectWeakRef that owns 1 or more objects.
When Swarm ref count goes to zero it destroys all objects in the Swarm.
Swarm may have any object inherited from a WeakSourceRefCount.
*/
MSO_CLASS_GUID(Swarm, "A0252DA6-7817-4536-B265-0A0152781652")
class Swarm
: public ObjectWeakRef
class Swarm : public ObjectWeakRef
{
using Super = ObjectWeakRef;
using UniquePtrType = SwarmMemberHolder::UniquePtrType;
using Super = ObjectWeakRef;
using UniquePtrType = SwarmMemberHolder::UniquePtrType;
public:
Swarm() noexcept
: ObjectWeakRef()
, m_headMember()
{
}
Swarm() noexcept : ObjectWeakRef(), m_headMember() {}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(Swarm);
DECLARE_COPYCONSTR_AND_ASSIGNMENT(Swarm);
template <typename T, typename TResult = T, typename... TArgs>
static Mso::TCntPtr<TResult> Make(TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
typename T::RefCountPolicy::template MemoryGuard<T, ObjectWeakRefContainer<T, Swarm>> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard);
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x0111774c /* tag_bex3m */);
template <typename T, typename TResult = T, typename... TArgs>
static Mso::TCntPtr<TResult> Make(TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
typename T::RefCountPolicy::template MemoryGuard<T, ObjectWeakRefContainer<T, Swarm>> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard);
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x0111774c /* tag_bex3m */);
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef*/ false);
}
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef*/ false);
}
template <typename T, typename TResult = T, typename TAllocArg, typename... TArgs>
static Mso::TCntPtr<TResult> MakeAlloc(TAllocArg&& allocArg, TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
typename T::RefCountPolicy::template MemoryGuard<T, ObjectWeakRefContainer<T, Swarm>> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard, std::forward<TAllocArg>(allocArg));
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x0111774d /* tag_bex3n */);
template <typename T, typename TResult = T, typename TAllocArg, typename... TArgs>
static Mso::TCntPtr<TResult> MakeAlloc(TAllocArg&& allocArg, TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
typename T::RefCountPolicy::template MemoryGuard<T, ObjectWeakRefContainer<T, Swarm>> memoryGuard = {};
T::RefCountPolicy::AllocateMemory(memoryGuard, std::forward<TAllocArg>(allocArg));
VerifyAllocElseCrashTag(memoryGuard.ObjMemory, 0x0111774d /* tag_bex3n */);
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef*/ false);
}
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return Mso::TCntPtr<TResult>(result, /*fDoAddRef*/ false);
}
// We return swarm member as a raw pointer because the new object shares ref count with the swarm and in many cases
// we want to avoid the extra AddRef/Release because object's lifetime is already tracked.
template <typename T, typename TResult = T, typename... TArgs>
TResult* MakeMember(TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
using Container = ObjectWeakRefContainer<T, SwarmMemberHolder>;
// We return swarm member as a raw pointer because the new object shares ref count with the swarm and in many cases
// we want to avoid the extra AddRef/Release because object's lifetime is already tracked.
template <typename T, typename TResult = T, typename... TArgs>
TResult* MakeMember(TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
using Container = ObjectWeakRefContainer<T, SwarmMemberHolder>;
void* containerMemory = T::RefCountPolicy::Allocator::Allocate(sizeof(Container));
VerifyAllocElseCrashTag(containerMemory, 0x0111774e /* tag_bex3o */);
Container* container = ::new (containerMemory) Container();
void* objMemory = container->Get();
SwarmMemberMemoryGuard<T, Container> memoryGuard = { objMemory, nullptr, this, container };
Mso::Details::SetWeakRef(memoryGuard.ObjMemory, this);
AddWeakRef(); // To match ReleaseWeakRef() call in object destructor.
void* containerMemory = T::RefCountPolicy::Allocator::Allocate(sizeof(Container));
VerifyAllocElseCrashTag(containerMemory, 0x0111774e /* tag_bex3o */);
Container* container = ::new (containerMemory) Container();
void* objMemory = container->Get();
SwarmMemberMemoryGuard<T, Container> memoryGuard = {objMemory, nullptr, this, container};
Mso::Details::SetWeakRef(memoryGuard.ObjMemory, this);
AddWeakRef(); // To match ReleaseWeakRef() call in object destructor.
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
AddSwarmMember(container);
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
AddSwarmMember(container);
memoryGuard.MemberContainer = nullptr; // To prevent memoryGuard from destroying the member container.
memoryGuard.MemberContainer = nullptr; // To prevent memoryGuard from destroying the member container.
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return result;
}
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return result;
}
template <typename T, typename TResult = T, typename TAllocArg, typename... TArgs>
TResult* MakeMemberAlloc(TAllocArg&& allocArg, TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
using Container = ObjectWeakRefContainer<T, SwarmMemberHolder>;
template <typename T, typename TResult = T, typename TAllocArg, typename... TArgs>
TResult* MakeMemberAlloc(TAllocArg&& allocArg, TArgs&&... args) noexcept(T::MakePolicy::IsNoExcept)
{
using Container = ObjectWeakRefContainer<T, SwarmMemberHolder>;
void* containerMemory = T::RefCountPolicy::Allocator::Allocate(sizeof(Container), std::forward<TAllocArg>(allocArg));
VerifyAllocElseCrashTag(containerMemory, 0x0111774f /* tag_bex3p */);
Container* container = ::new (containerMemory) Container();
void* objMemory = container->Get();
SwarmMemberMemoryGuard<T, Container> memoryGuard = { objMemory, nullptr, this, container };
Mso::Details::SetWeakRef(memoryGuard.ObjMemory, this);
AddWeakRef(); // To match ReleaseWeakRef() call in object destructor.
void* containerMemory =
T::RefCountPolicy::Allocator::Allocate(sizeof(Container), std::forward<TAllocArg>(allocArg));
VerifyAllocElseCrashTag(containerMemory, 0x0111774f /* tag_bex3p */);
Container* container = ::new (containerMemory) Container();
void* objMemory = container->Get();
SwarmMemberMemoryGuard<T, Container> memoryGuard = {objMemory, nullptr, this, container};
Mso::Details::SetWeakRef(memoryGuard.ObjMemory, this);
AddWeakRef(); // To match ReleaseWeakRef() call in object destructor.
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
AddSwarmMember(container);
T::MakePolicy::template Make<T>(memoryGuard, std::forward<TArgs>(args)...);
Debug(T::RefCountPolicy::ValidateObject(memoryGuard));
AddSwarmMember(container);
memoryGuard.MemberContainer = nullptr; // To prevent memoryGuard from destroying the member container.
memoryGuard.MemberContainer = nullptr; // To prevent memoryGuard from destroying the member container.
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return result;
}
TResult* result = memoryGuard.Obj;
memoryGuard.Obj = nullptr; // To prevent memoryGuard from destroying the object.
return result;
}
virtual void* QueryCastWeakRef(const GUID& riid) noexcept override
{
if (riid == __uuidof(Swarm))
{
return this;
}
virtual void* QueryCastWeakRef(const GUID& riid) noexcept override
{
if (riid == __uuidof(Swarm))
{
return this;
}
return Super::QueryCastWeakRef(riid);
}
return Super::QueryCastWeakRef(riid);
}
static TCntPtr<Swarm> FromWeakRef(_In_opt_ const ObjectWeakRef* weakRef) noexcept
{
TCntPtr<Swarm> swarm;
if (weakRef)
{
swarm = static_cast<Swarm*>(const_cast<ObjectWeakRef*>(weakRef)->QueryCastWeakRef(__uuidof(Swarm)));
}
return swarm;
}
static TCntPtr<Swarm> FromWeakRef(_In_opt_ const ObjectWeakRef* weakRef) noexcept
{
TCntPtr<Swarm> swarm;
if (weakRef)
{
swarm = static_cast<Swarm*>(const_cast<ObjectWeakRef*>(weakRef)->QueryCastWeakRef(__uuidof(Swarm)));
}
template <typename T>
static TCntPtr<Swarm> FromObject(_In_opt_ T* obj) noexcept
{
return FromObjectInternal(obj, OverloadTag());
}
return swarm;
}
template <typename T>
bool Contains(_In_opt_ T* obj) const noexcept
{
TCntPtr<Swarm> swarm = Swarm::FromObjectInternal(obj, OverloadTag());
return this == swarm.Get();
}
template <typename T>
static TCntPtr<Swarm> FromObject(_In_opt_ T* obj) noexcept
{
return FromObjectInternal(obj, OverloadTag());
}
template <typename T>
bool Contains(_In_opt_ T* obj) const noexcept
{
TCntPtr<Swarm> swarm = Swarm::FromObjectInternal(obj, OverloadTag());
return this == swarm.Get();
}
protected:
using SwarmType = Swarm;
using SwarmType = Swarm;
virtual void DestroyObject() noexcept override
{
for (SwarmMemberHolder* member = m_headMember.get(); member != nullptr; member = member->m_nextMember.get())
{
member->DestroyObject();
}
virtual void DestroyObject() noexcept override
{
for (SwarmMemberHolder* member = m_headMember.get(); member != nullptr; member = member->m_nextMember.get())
{
member->DestroyObject();
}
Super::DestroyObject();
}
Super::DestroyObject();
}
private:
template <typename T>
static auto FromObjectInternal(_In_opt_ T* obj, OverloadTagP1) noexcept -> decltype(obj->GetWeakRef(), TCntPtr<Swarm>())
{
TCntPtr<Swarm> swarm;
if (obj)
{
swarm = Swarm::FromWeakRef(&obj->GetWeakRef());
}
template <typename T>
static auto FromObjectInternal(_In_opt_ T* obj, OverloadTagP1) noexcept
-> decltype(obj->GetWeakRef(), TCntPtr<Swarm>())
{
TCntPtr<Swarm> swarm;
if (obj)
{
swarm = Swarm::FromWeakRef(&obj->GetWeakRef());
}
return swarm;
}
return swarm;
}
// This method assumes that obj implements IUnknown.
template <typename T>
static TCntPtr<Swarm> FromObjectInternal(_In_opt_ T* obj, OverloadTagP2) noexcept
{
TCntPtr<Swarm> swarm;
ObjectWeakRef* weakRef = query_cast<ObjectWeakRef*>(obj);
if (weakRef)
{
swarm = FromWeakRef(weakRef);
}
// This method assumes that obj implements IUnknown.
template <typename T>
static TCntPtr<Swarm> FromObjectInternal(_In_opt_ T* obj, OverloadTagP2) noexcept
{
TCntPtr<Swarm> swarm;
ObjectWeakRef* weakRef = query_cast<ObjectWeakRef*>(obj);
if (weakRef)
{
swarm = FromWeakRef(weakRef);
}
return swarm;
}
return swarm;
}
void AddSwarmMember(SwarmMemberHolder* holder) noexcept
{
// Atomically set the new member as a head member in the single linked list
for (;;)
{
SwarmMemberHolder* headMember = m_headMember.get();
UniquePtrType& nextMember = holder->m_nextMember;
nextMember.release(); // To make sure that reset will not delete value when we do second iteration.
nextMember.reset(headMember);
if (std::atomic_compare_exchange_weak((std::atomic<SwarmMemberHolder*>*)(void*)&m_headMember, &headMember, holder))
{
// Success: We were able to put pointer to our new member to the m_headMember without any conflicts.
// The object is now owned by the m_headMember. Make sure that memberContainer does not delete it.
break;
}
}
}
void AddSwarmMember(SwarmMemberHolder* holder) noexcept
{
// Atomically set the new member as a head member in the single linked list
for (;;)
{
SwarmMemberHolder* headMember = m_headMember.get();
UniquePtrType& nextMember = holder->m_nextMember;
nextMember.release(); // To make sure that reset will not delete value when we do second iteration.
nextMember.reset(headMember);
if (std::atomic_compare_exchange_weak(
(std::atomic<SwarmMemberHolder*>*)(void*)&m_headMember, &headMember, holder))
{
// Success: We were able to put pointer to our new member to the m_headMember without any conflicts.
// The object is now owned by the m_headMember. Make sure that memberContainer does not delete it.
break;
}
}
}
private:
UniquePtrType m_headMember;
UniquePtrType m_headMember;
};
// Define SwarmMemberMemoryGuard destructor here to avoid using Swarm class before it is defined.
template <typename T, typename TContainer>
inline SwarmMemberMemoryGuard<T, TContainer>::~SwarmMemberMemoryGuard() noexcept
{
if (ObjMemory)
{
// Object construction failed. Make sure that we release the weak reference added before construction.
Container->ReleaseWeakRef();
}
else if (Obj)
{
// Initialize method failed.
T::RefCountPolicy::Deleter::template Delete(static_cast<typename T::TypeToDelete*>(Obj));
}
if (ObjMemory)
{
// Object construction failed. Make sure that we release the weak reference added before construction.
Container->ReleaseWeakRef();
}
else if (Obj)
{
// Initialize method failed.
T::RefCountPolicy::Deleter::template Delete(static_cast<typename T::TypeToDelete*>(Obj));
}
if (MemberContainer)
{
MemberContainer->~TContainer();
T::RefCountPolicy::Allocator::Deallocate(MemberContainer);
}
if (MemberContainer)
{
MemberContainer->~TContainer();
T::RefCountPolicy::Allocator::Deallocate(MemberContainer);
}
}
/**
SwarmMemberPtr can be used by a swarm member to point to another swarm member.
The pointer represents a strong reference. It does not contribute to the reference count if the pointed object
is from the same swarm. This is done to avoid extra add ref count which may cause a memory leak.
SwarmMemberPtr assumes that swarm members implement IUnknown.
SwarmMemberPtr can be used by a swarm member to point to another swarm member.
The pointer represents a strong reference. It does not contribute to the reference count if the pointed object
is from the same swarm. This is done to avoid extra add ref count which may cause a memory leak.
SwarmMemberPtr assumes that swarm members implement IUnknown.
*/
template <typename T, bool KnownSameSwarm = false>
class SwarmMemberPtr
{
public:
DECLARE_COPYCONSTR_AND_ASSIGNMENT(SwarmMemberPtr);
DECLARE_COPYCONSTR_AND_ASSIGNMENT(SwarmMemberPtr);
SwarmMemberPtr() noexcept
{
}
SwarmMemberPtr() noexcept {}
#if __clang__
//save the clang warning state and silence warnings about [-Wtautological-undefined-compare].
// save the clang warning state and silence warnings about [-Wtautological-undefined-compare].
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-undefined-compare"
#endif
template <typename TOther, typename = std::enable_if_t<std::is_base_of<T, TOther>::value>>
SwarmMemberPtr(_In_opt_ TOther* ptr, _In_ const Swarm& ownerSwarm, _In_opt_ const Swarm* otherSwarm = nullptr) noexcept
: m_ptr(ptr)
, m_isDifferentSwarm(&ownerSwarm != (otherSwarm ? otherSwarm : Swarm::FromObject(ptr).Get()))
{
if (m_ptr && m_isDifferentSwarm)
{
m_ptr->AddRef();
}
}
template <typename TOther, typename = std::enable_if_t<std::is_base_of<T, TOther>::value>>
SwarmMemberPtr(
_In_opt_ TOther* ptr,
_In_ const Swarm& ownerSwarm,
_In_opt_ const Swarm* otherSwarm = nullptr) noexcept
: m_ptr(ptr), m_isDifferentSwarm(&ownerSwarm != (otherSwarm ? otherSwarm : Swarm::FromObject(ptr).Get()))
{
if (m_ptr && m_isDifferentSwarm)
{
m_ptr->AddRef();
}
}
template <typename TOther, typename = std::enable_if_t<std::is_base_of<T, TOther>::value>>
SwarmMemberPtr(_In_opt_ TOther* ptr, _In_ const Mso::ObjectWeakRef& ownerWeak, _In_opt_ const Mso::ObjectWeakRef* otherWeak = nullptr) noexcept
: m_ptr(ptr)
, m_isDifferentSwarm(&ownerWeak != (otherWeak ? otherWeak : Details::WeakPtrBase::GetWeakRef(ptr)))
{
if (m_ptr && m_isDifferentSwarm)
{
m_ptr->AddRef();
}
}
template <typename TOther, typename = std::enable_if_t<std::is_base_of<T, TOther>::value>>
SwarmMemberPtr(
_In_opt_ TOther* ptr,
_In_ const Mso::ObjectWeakRef& ownerWeak,
_In_opt_ const Mso::ObjectWeakRef* otherWeak = nullptr) noexcept
: m_ptr(ptr), m_isDifferentSwarm(&ownerWeak != (otherWeak ? otherWeak : Details::WeakPtrBase::GetWeakRef(ptr)))
{
if (m_ptr && m_isDifferentSwarm)
{
m_ptr->AddRef();
}
}
//resume clang warning state
// resume clang warning state
#if __clang__
#pragma clang diagnostic pop
#endif
SwarmMemberPtr(SwarmMemberPtr&& from) noexcept
: m_ptr(from.m_ptr)
, m_isDifferentSwarm(from.m_isDifferentSwarm)
{
from.m_ptr = nullptr;
from.m_isDifferentSwarm = false;
}
SwarmMemberPtr(SwarmMemberPtr&& from) noexcept : m_ptr(from.m_ptr), m_isDifferentSwarm(from.m_isDifferentSwarm)
{
from.m_ptr = nullptr;
from.m_isDifferentSwarm = false;
}
~SwarmMemberPtr() noexcept
{
Reset();
}
~SwarmMemberPtr() noexcept
{
Reset();
}
SwarmMemberPtr& operator=(SwarmMemberPtr&& from) noexcept
{
if (this != &from)
{
SwarmMemberPtr<T>(std::move(from)).Swap(*this);
}
SwarmMemberPtr& operator=(SwarmMemberPtr&& from) noexcept
{
if (this != &from)
{
SwarmMemberPtr<T>(std::move(from)).Swap(*this);
}
return *this;
}
return *this;
}
void Swap(SwarmMemberPtr& other) noexcept
{
using std::swap;
OACR_ASSUME_NOTHROW_BEGIN
swap(m_ptr, other.m_ptr);
swap(m_isDifferentSwarm, other.m_isDifferentSwarm);
OACR_ASSUME_NOTHROW_END
}
void Swap(SwarmMemberPtr& other) noexcept
{
using std::swap;
OACR_ASSUME_NOTHROW_BEGIN
swap(m_ptr, other.m_ptr);
swap(m_isDifferentSwarm, other.m_isDifferentSwarm);
OACR_ASSUME_NOTHROW_END
}
void Reset() noexcept
{
if (m_ptr && m_isDifferentSwarm)
{
m_ptr->Release();
}
void Reset() noexcept
{
if (m_ptr && m_isDifferentSwarm)
{
m_ptr->Release();
}
m_ptr = nullptr;
}
m_ptr = nullptr;
}
T* Get() const noexcept
{
return m_ptr;
}
T* Get() const noexcept
{
return m_ptr;
}
T** GetRaw() const noexcept
{
return &m_ptr;
}
T** GetRaw() const noexcept
{
return &m_ptr;
}
bool IsEmpty() const noexcept
{
return m_ptr == nullptr;
}
bool IsEmpty() const noexcept
{
return m_ptr == nullptr;
}
bool IsDifferentSwarm() const noexcept
{
return m_isDifferentSwarm;
}
bool IsDifferentSwarm() const noexcept
{
return m_isDifferentSwarm;
}
T* operator ->() const noexcept
{
AssertTag(!IsEmpty(), 0x01003713 /* tag_bad2t */);
return Get();
}
T* operator->() const noexcept
{
AssertTag(!IsEmpty(), 0x01003713 /* tag_bad2t */);
return Get();
}
T& operator *() const noexcept
{
AssertTag(!IsEmpty(), 0x01003714 /* tag_bad2u */);
return *m_ptr;
}
T& operator*() const noexcept
{
AssertTag(!IsEmpty(), 0x01003714 /* tag_bad2u */);
return *m_ptr;
}
private:
T* m_ptr = nullptr;
bool m_isDifferentSwarm = false;
T* m_ptr = nullptr;
bool m_isDifferentSwarm = false;
};
/**
SwarmMemberPtr specialization for a case when we know for sure that we have a pointer inside of the same Swarm.
In that case we can have just a single pointer field and have less code.
It is preferable to use this smart pointer instead of raw pointer because we preserve semantic of the pointer.
I.e. this is not just a random raw pointer, but a raw pointer which is made according to the specific design decision.
SwarmMemberPtr specialization for a case when we know for sure that we have a pointer inside of the same Swarm.
In that case we can have just a single pointer field and have less code.
It is preferable to use this smart pointer instead of raw pointer because we preserve semantic of the pointer.
I.e. this is not just a random raw pointer, but a raw pointer which is made according to the specific design decision.
*/
template <typename T>
class SwarmMemberPtr<T, /*KnownSameSwarm*/true>
class SwarmMemberPtr<T, /*KnownSameSwarm*/ true>
{
public:
DECLARE_COPYCONSTR_AND_ASSIGNMENT(SwarmMemberPtr);
DECLARE_COPYCONSTR_AND_ASSIGNMENT(SwarmMemberPtr);
SwarmMemberPtr() noexcept
{
}
SwarmMemberPtr() noexcept {}
template <typename TOther, typename = typename std::enable_if<std::is_base_of<T, TOther>::value>::type>
SwarmMemberPtr(_In_opt_ TOther* ptr) noexcept
: m_ptr(ptr)
{
}
template <typename TOther, typename = typename std::enable_if<std::is_base_of<T, TOther>::value>::type>
SwarmMemberPtr(_In_opt_ TOther* ptr) noexcept : m_ptr(ptr)
{
}
SwarmMemberPtr(SwarmMemberPtr&& from) noexcept
: m_ptr(from.m_ptr)
{
from.m_ptr = nullptr;
}
SwarmMemberPtr(SwarmMemberPtr&& from) noexcept : m_ptr(from.m_ptr)
{
from.m_ptr = nullptr;
}
SwarmMemberPtr& operator=(SwarmMemberPtr&& from) noexcept
{
if (this != &from)
{
SwarmMemberPtr<T, /*KnownSameSwarm*/true>(std::move(from)).Swap(*this);
}
SwarmMemberPtr& operator=(SwarmMemberPtr&& from) noexcept
{
if (this != &from)
{
SwarmMemberPtr<T, /*KnownSameSwarm*/ true>(std::move(from)).Swap(*this);
}
return *this;
}
return *this;
}
void Swap(SwarmMemberPtr& other) noexcept
{
using std::swap;
OACR_ASSUME_NOTHROW_BEGIN
swap(m_ptr, other.m_ptr);
OACR_ASSUME_NOTHROW_END
}
void Swap(SwarmMemberPtr& other) noexcept
{
using std::swap;
OACR_ASSUME_NOTHROW_BEGIN
swap(m_ptr, other.m_ptr);
OACR_ASSUME_NOTHROW_END
}
void Reset() noexcept
{
m_ptr = nullptr;
}
void Reset() noexcept
{
m_ptr = nullptr;
}
T* Get() const noexcept
{
return m_ptr;
}
T* Get() const noexcept
{
return m_ptr;
}
T** GetRaw() noexcept
{
return &m_ptr;
}
T** GetRaw() noexcept
{
return &m_ptr;
}
bool IsEmpty() const noexcept
{
return m_ptr == nullptr;
}
bool IsEmpty() const noexcept
{
return m_ptr == nullptr;
}
bool IsDifferentSwarm() const noexcept
{
return false;
}
bool IsDifferentSwarm() const noexcept
{
return false;
}
T* operator ->() const noexcept
{
AssertTag(!IsEmpty(), 0x01003715 /* tag_bad2v */);
return m_ptr;
}
T* operator->() const noexcept
{
AssertTag(!IsEmpty(), 0x01003715 /* tag_bad2v */);
return m_ptr;
}
T& operator *() const noexcept
{
AssertTag(!IsEmpty(), 0x01003716 /* tag_bad2w */);
return *m_ptr;
}
T& operator*() const noexcept
{
AssertTag(!IsEmpty(), 0x01003716 /* tag_bad2w */);
return *m_ptr;
}
private:
T* m_ptr = nullptr;
T* m_ptr = nullptr;
};
template <typename T, bool KnownSameSwarm>
void swap(SwarmMemberPtr<T, KnownSameSwarm>& left, SwarmMemberPtr<T, KnownSameSwarm>& right) noexcept
{
left.Swap(right);
left.Swap(right);
}
template <typename T, bool KnownSameSwarm>
bool operator==(const SwarmMemberPtr<T, KnownSameSwarm>& left, std::nullptr_t) noexcept
{
return left.IsEmpty();
return left.IsEmpty();
}
template <typename T, bool KnownSameSwarm>
bool operator==(std::nullptr_t, const SwarmMemberPtr<T, KnownSameSwarm>& right) noexcept
{
return right.IsEmpty();
return right.IsEmpty();
}
template <typename T, bool KnownSameSwarm>
bool operator!=(const SwarmMemberPtr<T, KnownSameSwarm>& left, std::nullptr_t) noexcept
{
return !left.IsEmpty();
return !left.IsEmpty();
}
template <typename T, bool KnownSameSwarm>
bool operator!=(std::nullptr_t, const SwarmMemberPtr<T, KnownSameSwarm>& right) noexcept
{
return !right.IsEmpty();
return !right.IsEmpty();
}
} // namespace Mso

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Support for object lifetime management using ref counting.
Support for object lifetime management using ref counting.
*/
#pragma once
@ -11,361 +11,359 @@
namespace Mso {
template <class T> class WeakPtr;
template <class T>
class WeakPtr;
namespace Details {
class WeakPtrBase
{
public:
void Reset() noexcept
{
CheckedReleaseWeakRef();
m_ptr = nullptr;
m_weakRef = nullptr;
}
void Reset() noexcept
{
CheckedReleaseWeakRef();
m_ptr = nullptr;
m_weakRef = nullptr;
}
bool IsEmpty() const noexcept
{
return m_ptr == nullptr;
}
bool IsEmpty() const noexcept
{
return m_ptr == nullptr;
}
bool IsExpired() const noexcept
{
return !m_ptr || m_weakRef->IsExpired();
}
bool IsExpired() const noexcept
{
return !m_ptr || m_weakRef->IsExpired();
}
template <class T>
static Mso::ObjectWeakRef* GetWeakRef(_In_opt_ T* from) noexcept
{
return GetWeakRefCore(from, 0, 0);
}
template <class T>
static Mso::ObjectWeakRef* GetWeakRef(_In_opt_ T* from) noexcept
{
return GetWeakRefCore(from, 0, 0);
}
protected:
enum { AttachTag = 0 };
enum
{
AttachTag = 0
};
WeakPtrBase() noexcept
: m_ptr(nullptr)
, m_weakRef(nullptr)
{
}
WeakPtrBase() noexcept : m_ptr(nullptr), m_weakRef(nullptr) {}
WeakPtrBase(_In_opt_ void* ptr, _In_opt_ Mso::ObjectWeakRef* weakRef) noexcept
: m_ptr(ptr)
, m_weakRef(ptr ? weakRef : nullptr)
{
CheckedAddWeakRef();
}
WeakPtrBase(_In_opt_ void* ptr, _In_opt_ Mso::ObjectWeakRef* weakRef) noexcept
: m_ptr(ptr), m_weakRef(ptr ? weakRef : nullptr)
{
CheckedAddWeakRef();
}
WeakPtrBase(_In_opt_ void* ptr, _In_opt_ Mso::ObjectWeakRef* weakRef, int /*attachTag*/) noexcept
: m_ptr(ptr)
, m_weakRef(weakRef)
{
}
WeakPtrBase(_In_opt_ void* ptr, _In_opt_ Mso::ObjectWeakRef* weakRef, int /*attachTag*/) noexcept
: m_ptr(ptr), m_weakRef(weakRef)
{
}
~WeakPtrBase() noexcept
{
CheckedReleaseWeakRef();
}
~WeakPtrBase() noexcept
{
CheckedReleaseWeakRef();
}
void Assign(_In_opt_ void* ptr, _In_opt_ ObjectWeakRef* weakRef) noexcept
{
CheckedReleaseWeakRef();
m_ptr = ptr;
m_weakRef = weakRef;
CheckedAddWeakRef();
}
void Assign(_In_opt_ void* ptr, _In_opt_ ObjectWeakRef* weakRef) noexcept
{
CheckedReleaseWeakRef();
m_ptr = ptr;
m_weakRef = weakRef;
CheckedAddWeakRef();
}
void Assign(_In_opt_ void* ptr, _In_opt_ ObjectWeakRef* weakRef, int /*attachTag*/) noexcept
{
CheckedReleaseWeakRef();
m_ptr = ptr;
m_weakRef = weakRef;
}
void Assign(_In_opt_ void* ptr, _In_opt_ ObjectWeakRef* weakRef, int /*attachTag*/) noexcept
{
CheckedReleaseWeakRef();
m_ptr = ptr;
m_weakRef = weakRef;
}
bool IncrementRefCountIfNotZero() const noexcept
{
return m_weakRef && m_weakRef->IncrementRefCountIfNotZero();
}
bool IncrementRefCountIfNotZero() const noexcept
{
return m_weakRef && m_weakRef->IncrementRefCountIfNotZero();
}
private:
void CheckedAddWeakRef() const noexcept
{
if (m_weakRef) m_weakRef->AddWeakRef();
}
void CheckedReleaseWeakRef() const noexcept
{
if (m_weakRef) m_weakRef->ReleaseWeakRef();
}
void CheckedAddWeakRef() const noexcept
{
if (m_weakRef)
m_weakRef->AddWeakRef();
}
// Called when T has GetWeakRef method.
template <class T>
static auto GetWeakRefCore(_In_opt_ T* from, int, int) noexcept -> decltype(&from->GetWeakRef())
{
if (from)
{
Mso::ObjectWeakRef* result = &from->GetWeakRef();
VerifyElseCrashSzTag(result, "GetWeakRef() returned null", 0x0100371a /* tag_bad20 */);
return result;
}
void CheckedReleaseWeakRef() const noexcept
{
if (m_weakRef)
m_weakRef->ReleaseWeakRef();
}
return nullptr;
}
// Called when T has GetWeakRef method.
template <class T>
static auto GetWeakRefCore(_In_opt_ T* from, int, int) noexcept -> decltype(&from->GetWeakRef())
{
if (from)
{
Mso::ObjectWeakRef* result = &from->GetWeakRef();
VerifyElseCrashSzTag(result, "GetWeakRef() returned null", 0x0100371a /* tag_bad20 */);
return result;
}
// Called when T has QueryInterface method.
template <class T>
static auto GetWeakRefCore(_In_opt_ T* from, int, ...) noexcept -> decltype(from->QueryInterface(__uuidof(Mso::ObjectWeakRef), nullptr), (Mso::ObjectWeakRef*)nullptr)
{
if (from)
{
Mso::ObjectWeakRef* result = query_cast<Mso::ObjectWeakRef*>(from);
VerifyElseCrashSzTag(result, "query_cast<Mso::ObjectWeakRef*>() returned null", 0x0100371b /* tag_bad21 */);
return result;
}
return nullptr;
}
return nullptr;
}
// Called when T has QueryInterface method.
template <class T>
static auto GetWeakRefCore(_In_opt_ T* from, int, ...) noexcept
-> decltype(from->QueryInterface(__uuidof(Mso::ObjectWeakRef), nullptr), (Mso::ObjectWeakRef*)nullptr)
{
if (from)
{
Mso::ObjectWeakRef* result = query_cast<Mso::ObjectWeakRef*>(from);
VerifyElseCrashSzTag(result, "query_cast<Mso::ObjectWeakRef*>() returned null", 0x0100371b /* tag_bad21 */);
return result;
}
// Called when T does not have GetWeakRef method.
template <class T>
static Mso::ObjectWeakRef* GetWeakRefCore(_In_opt_ T* /*from*/, ...) noexcept
{
VerifyElseCrashSzTag(false, "Cannot get ObjectWeakRef for an object.", 0x0100371c /* tag_bad22 */);
return nullptr;
}
return nullptr;
}
friend const void* GetUnsafePtr(const WeakPtrBase& weakPtrBase) noexcept
{
return weakPtrBase.m_ptr;
}
// Called when T does not have GetWeakRef method.
template <class T>
static Mso::ObjectWeakRef* GetWeakRefCore(_In_opt_ T* /*from*/, ...) noexcept
{
VerifyElseCrashSzTag(false, "Cannot get ObjectWeakRef for an object.", 0x0100371c /* tag_bad22 */);
return nullptr;
}
friend const void* GetUnsafePtr(const WeakPtrBase& weakPtrBase) noexcept
{
return weakPtrBase.m_ptr;
}
private:
void* m_ptr;
Mso::ObjectWeakRef* m_weakRef;
void* m_ptr;
Mso::ObjectWeakRef* m_weakRef;
template <class T> friend class Mso::WeakPtr;
template <class T>
friend class Mso::WeakPtr;
};
} // namespace Details
/**
A weak pointer based on the ObjectWeakRef.
It has two pointers: a pointer to the ObjectWeakRef and a pointer to the object.
Having two pointers allow us to address the following scenarios:
- We do not want to do any casting when retrieving a strong pointer.
- Multiple objects share the same ObjectWeakRef.
A weak pointer based on the ObjectWeakRef.
It has two pointers: a pointer to the ObjectWeakRef and a pointer to the object.
Having two pointers allow us to address the following scenarios:
- We do not want to do any casting when retrieving a strong pointer.
- Multiple objects share the same ObjectWeakRef.
*/
template <class T>
class WeakPtr final : public Details::WeakPtrBase
{
using Super = Details::WeakPtrBase;
using Super = Details::WeakPtrBase;
public:
WeakPtr() noexcept : Super() {}
WeakPtr(std::nullptr_t) noexcept : Super() {}
WeakPtr() noexcept : Super() {}
WeakPtr(std::nullptr_t) noexcept : Super() {}
WeakPtr(_In_opt_ T* from, _In_opt_ Mso::ObjectWeakRef* weakRef = nullptr) noexcept
: Super(from, weakRef ? weakRef : GetWeakRefCore(from, 0, 0))
{
}
WeakPtr(_In_opt_ T* from, _In_opt_ Mso::ObjectWeakRef* weakRef = nullptr) noexcept
: Super(from, weakRef ? weakRef : GetWeakRefCore(from, 0, 0))
{
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr(_In_opt_ TOther* from, _In_opt_ Mso::ObjectWeakRef* weakRef = nullptr) noexcept
: Super(static_cast<T*>(from), weakRef ? weakRef : GetWeakRefCore(from, 0, 0))
{
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr(_In_opt_ TOther* from, _In_opt_ Mso::ObjectWeakRef* weakRef = nullptr) noexcept
: Super(static_cast<T*>(from), weakRef ? weakRef : GetWeakRefCore(from, 0, 0))
{
}
WeakPtr(const Mso::TCntPtr<T>& from, _In_opt_ Mso::ObjectWeakRef* weakRef = nullptr) noexcept
: Super(from.Get(), weakRef ? weakRef : GetWeakRefCore(from.Get(), 0, 0))
{
}
WeakPtr(const Mso::TCntPtr<T>& from, _In_opt_ Mso::ObjectWeakRef* weakRef = nullptr) noexcept
: Super(from.Get(), weakRef ? weakRef : GetWeakRefCore(from.Get(), 0, 0))
{
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr(const Mso::TCntPtr<TOther>& from, _In_opt_ Mso::ObjectWeakRef* weakRef = nullptr) noexcept
: Super(static_cast<T*>(from.Get()), weakRef ? weakRef : GetWeakRefCore(from.Get(), 0, 0))
{
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr(const Mso::TCntPtr<TOther>& from, _In_opt_ Mso::ObjectWeakRef* weakRef = nullptr) noexcept
: Super(static_cast<T*>(from.Get()), weakRef ? weakRef : GetWeakRefCore(from.Get(), 0, 0))
{
}
WeakPtr(const WeakPtr& from) noexcept
: Super(from.m_ptr, from.m_weakRef)
{
}
WeakPtr(const WeakPtr& from) noexcept : Super(from.m_ptr, from.m_weakRef) {}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr(const WeakPtr<TOther>& from) noexcept
: Super(static_cast<T*>(static_cast<TOther*>(from.m_ptr)), from.m_weakRef)
{
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr(const WeakPtr<TOther>& from) noexcept
: Super(static_cast<T*>(static_cast<TOther*>(from.m_ptr)), from.m_weakRef)
{
}
WeakPtr(WeakPtr&& from) noexcept
: Super(from.m_ptr, from.m_weakRef, AttachTag)
{
from.m_ptr = nullptr;
from.m_weakRef = nullptr;
}
WeakPtr(WeakPtr&& from) noexcept : Super(from.m_ptr, from.m_weakRef, AttachTag)
{
from.m_ptr = nullptr;
from.m_weakRef = nullptr;
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr(WeakPtr<TOther>&& from) noexcept
: Super(static_cast<T*>(static_cast<TOther*>(from.m_ptr)), from.m_weakRef, AttachTag)
{
from.m_ptr = nullptr;
from.m_weakRef = nullptr;
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr(WeakPtr<TOther>&& from) noexcept
: Super(static_cast<T*>(static_cast<TOther*>(from.m_ptr)), from.m_weakRef, AttachTag)
{
from.m_ptr = nullptr;
from.m_weakRef = nullptr;
}
WeakPtr& operator=(std::nullptr_t) noexcept
{
Reset();
return *this;
}
WeakPtr& operator=(std::nullptr_t) noexcept
{
Reset();
return *this;
}
WeakPtr& operator=(_In_opt_ T* from) noexcept
{
if (m_ptr != from)
{
Assign(from, GetWeakRefCore(from, 0, 0));
}
WeakPtr& operator=(_In_opt_ T* from) noexcept
{
if (m_ptr != from)
{
Assign(from, GetWeakRefCore(from, 0, 0));
}
return *this;
}
return *this;
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr& operator=(_In_opt_ TOther* from) noexcept
{
T* ptr = static_cast<T*>(from);
if (m_ptr != ptr)
{
Assign(ptr, GetWeakRefCore(from, 0, 0));
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr& operator=(_In_opt_ TOther* from) noexcept
{
T* ptr = static_cast<T*>(from);
if (m_ptr != ptr)
{
Assign(ptr, GetWeakRefCore(from, 0, 0));
}
return *this;
}
return *this;
}
WeakPtr& operator=(const Mso::TCntPtr<T>& from) noexcept
{
T* ptr = from.Get();
if (m_ptr != ptr)
{
Assign(ptr, GetWeakRefCore(ptr, 0, 0));
}
WeakPtr& operator=(const Mso::TCntPtr<T>& from) noexcept
{
T* ptr = from.Get();
if (m_ptr != ptr)
{
Assign(ptr, GetWeakRefCore(ptr, 0, 0));
}
return *this;
}
return *this;
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr& operator=(const Mso::TCntPtr<TOther>& from) noexcept
{
TOther* otherPtr = from.Get();
T* ptr = static_cast<T*>(otherPtr);
if (m_ptr != ptr)
{
Assign(ptr, GetWeakRefCore(otherPtr, 0, 0));
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr& operator=(const Mso::TCntPtr<TOther>& from) noexcept
{
TOther* otherPtr = from.Get();
T* ptr = static_cast<T*>(otherPtr);
if (m_ptr != ptr)
{
Assign(ptr, GetWeakRefCore(otherPtr, 0, 0));
}
return *this;
}
return *this;
}
WeakPtr& operator=(const WeakPtr& from) noexcept
{
if (m_ptr != from.m_ptr)
{
Assign(from.m_ptr, from.m_weakRef);
}
WeakPtr& operator=(const WeakPtr& from) noexcept
{
if (m_ptr != from.m_ptr)
{
Assign(from.m_ptr, from.m_weakRef);
}
return *this;
}
return *this;
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr& operator=(const WeakPtr<TOther>& from) noexcept
{
T* ptr = static_cast<T*>(static_cast<TOther*>(from.m_ptr));
if (m_ptr != ptr)
{
Assign(ptr, from.m_weakRef);
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr& operator=(const WeakPtr<TOther>& from) noexcept
{
T* ptr = static_cast<T*>(static_cast<TOther*>(from.m_ptr));
if (m_ptr != ptr)
{
Assign(ptr, from.m_weakRef);
}
return *this;
}
return *this;
}
WeakPtr& operator=(WeakPtr&& from) noexcept
{
if (m_ptr != from.m_ptr)
{
Assign(from.m_ptr, from.m_weakRef, AttachTag);
from.m_ptr = nullptr;
from.m_weakRef = nullptr;
}
WeakPtr& operator=(WeakPtr&& from) noexcept
{
if (m_ptr != from.m_ptr)
{
Assign(from.m_ptr, from.m_weakRef, AttachTag);
from.m_ptr = nullptr;
from.m_weakRef = nullptr;
}
return *this;
}
return *this;
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr& operator=(WeakPtr<TOther>&& from) noexcept
{
T* ptr = static_cast<T*>(static_cast<TOther*>(from.m_ptr));
if (m_ptr != ptr)
{
Assign(ptr, from.m_weakRef, AttachTag);
from.m_ptr = nullptr;
from.m_weakRef = nullptr;
}
template <class TOther, class = typename std::enable_if<std::is_convertible<TOther*, T*>::value>::type>
WeakPtr& operator=(WeakPtr<TOther>&& from) noexcept
{
T* ptr = static_cast<T*>(static_cast<TOther*>(from.m_ptr));
if (m_ptr != ptr)
{
Assign(ptr, from.m_weakRef, AttachTag);
from.m_ptr = nullptr;
from.m_weakRef = nullptr;
}
return *this;
}
return *this;
}
Mso::TCntPtr<T> GetStrongPtr() const noexcept
{
Mso::TCntPtr<T> ptr;
if (IncrementRefCountIfNotZero())
{
*ptr.GetRaw() = static_cast<T*>(m_ptr);
}
Mso::TCntPtr<T> GetStrongPtr() const noexcept
{
Mso::TCntPtr<T> ptr;
if (IncrementRefCountIfNotZero())
{
*ptr.GetRaw() = static_cast<T*>(m_ptr);
}
return ptr;
}
return ptr;
}
void Swap(WeakPtr& other) noexcept
{
using std::swap;
std::swap(m_ptr, other.m_ptr);
std::swap(m_weakRef, other.m_weakRef);
}
void Swap(WeakPtr& other) noexcept
{
using std::swap;
std::swap(m_ptr, other.m_ptr);
std::swap(m_weakRef, other.m_weakRef);
}
};
template <typename T1, typename T2>
bool operator==(const WeakPtr<T1>& left, const WeakPtr<T2>& right) noexcept
{
return GetUnsafePtr(left) == GetUnsafePtr(right);
return GetUnsafePtr(left) == GetUnsafePtr(right);
}
template <typename T>
bool operator==(const WeakPtr<T>& left, std::nullptr_t) noexcept
{
return left.IsEmpty();
return left.IsEmpty();
}
template <typename T>
bool operator==(std::nullptr_t, const WeakPtr<T>& right) noexcept
{
return right.IsEmpty();
return right.IsEmpty();
}
template <typename T1, typename T2>
bool operator!=(const WeakPtr<T1>& left, const WeakPtr<T2>& right) noexcept
{
return GetUnsafePtr(left) != GetUnsafePtr(right);
return GetUnsafePtr(left) != GetUnsafePtr(right);
}
template <typename T>
bool operator!=(const WeakPtr<T>& left, std::nullptr_t) noexcept
{
return !left.IsEmpty();
return !left.IsEmpty();
}
template <typename T>
bool operator!=(std::nullptr_t, const WeakPtr<T>& right) noexcept
{
return !right.IsEmpty();
return !right.IsEmpty();
}
} // namespace Mso

Просмотреть файл

@ -16,177 +16,189 @@ Unit tests for the TCntPtrRef class
MSO_STRUCT_GUID(ISimpleUnknown, "C70B7853-1EDB-4AB8-B2D2-F9951A99A847")
struct DECLSPEC_NOVTABLE ISimpleUnknown : public IUnknown
{
virtual void DoSomething() = 0;
virtual void DoSomething() = 0;
};
struct ISimple : public Mso::IRefCounted
{
virtual void DoSomething() = 0;
virtual void DoSomething() = 0;
};
class SimpleTestRef : public Mso::TRefCountedImpl<ISimple>
{
void DoSomething() override {}
void DoSomething() override {}
};
inline static std::wstring ToString(ISimple* q) { return L""; }
inline static std::wstring ToString(ISimple** q) { return L""; }
inline static std::wstring ToString(const ISimple* q) { return L""; }
inline static std::wstring ToString(ISimple* const* q) { return L""; }
inline static std::wstring ToString(const Mso::TCntPtr<ISimple>* q) { return L""; }
TestClassComponent(TCntPtrRefTest, Mso.TCntPtrRef)
TEST_CLASS(TCntPtrRefTest)
inline static std::wstring ToString(ISimple* q)
{
TEST_METHOD(TCntPtr_TCntPtrRef_GetRaw)
return L"";
}
inline static std::wstring ToString(ISimple** q)
{
Mso::TCntPtr<ISimple> spObj;
TestAssert::AreEqual(spObj.GetRaw(), (&spObj).GetRaw());
return L"";
}
inline static std::wstring ToString(const ISimple* q)
{
return L"";
}
inline static std::wstring ToString(ISimple* const* q)
{
return L"";
}
inline static std::wstring ToString(const Mso::TCntPtr<ISimple>* q)
{
return L"";
}
TEST_METHOD(TCntPtr_TCntPtrRef_StarOperator)
TestClassComponent(TCntPtrRefTest, Mso.TCntPtrRef) TEST_CLASS (TCntPtrRefTest)
{
Mso::TCntPtr<ISimple> spObj;
TestAssert::AreEqual(spObj.Get(), *(&spObj));
}
TEST_METHOD(TCntPtr_TCntPtrRef_GetRaw)
{
Mso::TCntPtr<ISimple> spObj;
TestAssert::AreEqual(spObj.GetRaw(), (&spObj).GetRaw());
}
TEST_METHOD(TCntPtr_TCntPtrRef_GetAddressOf)
{
Mso::TCntPtr<ISimple> spObj;
TestAssert::AreEqual(spObj.GetAddressOf(), const_cast<ISimple**>((&spObj).GetAddressOf()));
}
TEST_METHOD(TCntPtr_TCntPtrRef_StarOperator)
{
Mso::TCntPtr<ISimple> spObj;
TestAssert::AreEqual(spObj.Get(), *(&spObj));
}
TEST_METHOD(TCntPtr_TCntPtrRef_ClearAndGetAddressOf)
{
Mso::TCntPtr<ISimple> spObj = new SimpleTestRef();
TestAssert::AreEqual(spObj.GetRaw(), (&spObj).ClearAndGetAddressOf());
TestAssert::IsNull(spObj.Get());
}
TEST_METHOD(TCntPtr_TCntPtrRef_GetAddressOf)
{
Mso::TCntPtr<ISimple> spObj;
TestAssert::AreEqual(spObj.GetAddressOf(), const_cast<ISimple**>((&spObj).GetAddressOf()));
}
TEST_METHOD(TCntPtr_TCntPtrRef_IID_PPV_ARGS_Helper)
{
Mso::TCntPtr<IUnknown> spObj;
void** ppObj = IID_PPV_ARGS_Helper(&spObj);
void** ppDesired = &spObj;
TestAssert::AreEqual((void*)ppDesired, (void*)ppObj);
}
TEST_METHOD(TCntPtr_TCntPtrRef_ClearAndGetAddressOf)
{
Mso::TCntPtr<ISimple> spObj = new SimpleTestRef();
TestAssert::AreEqual(spObj.GetRaw(), (&spObj).ClearAndGetAddressOf());
TestAssert::IsNull(spObj.Get());
}
TEST_METHOD(TCntPtr_TCntPtrRef_EqualOperator)
{
Mso::TCntPtr<IUnknown> spObj1;
Mso::TCntPtr<IUnknown> spObj2;
TestAssert::IsTrue(&spObj1 == &spObj1);
TestAssert::IsTrue(&spObj2 == &spObj2);
TestAssert::IsFalse(&spObj1 == &spObj2);
TestAssert::IsFalse(&spObj2 == &spObj1);
}
TEST_METHOD(TCntPtr_TCntPtrRef_IID_PPV_ARGS_Helper)
{
Mso::TCntPtr<IUnknown> spObj;
void** ppObj = IID_PPV_ARGS_Helper(&spObj);
void** ppDesired = &spObj;
TestAssert::AreEqual((void*)ppDesired, (void*)ppObj);
}
TEST_METHOD(TCntPtr_TCntPtrRef_NotEqualOperator)
{
Mso::TCntPtr<IUnknown> spObj1;
Mso::TCntPtr<IUnknown> spObj2;
TestAssert::IsTrue(&spObj1 != &spObj2);
TestAssert::IsTrue(&spObj2 != &spObj1);
TestAssert::IsFalse(&spObj2 != &spObj2);
TestAssert::IsFalse(&spObj1 != &spObj1);
}
TEST_METHOD(TCntPtr_TCntPtrRef_EqualOperator)
{
Mso::TCntPtr<IUnknown> spObj1;
Mso::TCntPtr<IUnknown> spObj2;
TestAssert::IsTrue(&spObj1 == &spObj1);
TestAssert::IsTrue(&spObj2 == &spObj2);
TestAssert::IsFalse(&spObj1 == &spObj2);
TestAssert::IsFalse(&spObj2 == &spObj1);
}
static void TestFunc1(_In_ _Notnull_ ISimple* pObj, _Out_ ISimple** ppObj)
{
*ppObj = pObj;
}
TEST_METHOD(TCntPtr_TCntPtrRef_NotEqualOperator)
{
Mso::TCntPtr<IUnknown> spObj1;
Mso::TCntPtr<IUnknown> spObj2;
TestAssert::IsTrue(&spObj1 != &spObj2);
TestAssert::IsTrue(&spObj2 != &spObj1);
TestAssert::IsFalse(&spObj2 != &spObj2);
TestAssert::IsFalse(&spObj1 != &spObj1);
}
static void TestFunc2(_In_ _Notnull_ ISimple* pObj, _Out_ Mso::TCntPtr<ISimple>* spObj)
{
*spObj = Mso::TCntPtr<ISimple>(pObj, false);
}
static void TestFunc1(_In_ _Notnull_ ISimple * pObj, _Out_ ISimple * *ppObj)
{
*ppObj = pObj;
}
static void TestFunc3(_In_ _Notnull_ ISimple* pObj, _Out_ void** ppT)
{
*ppT = pObj;
}
static void TestFunc2(_In_ _Notnull_ ISimple * pObj, _Out_ Mso::TCntPtr<ISimple> * spObj)
{
*spObj = Mso::TCntPtr<ISimple>(pObj, false);
}
static void TestFunc4(_In_ _Notnull_ const ISimple* pObj, _Out_ const void** ppT)
{
*ppT = pObj;
}
static void TestFunc3(_In_ _Notnull_ ISimple * pObj, _Out_ void** ppT)
{
*ppT = pObj;
}
template<typename T, typename U>
static void TestTCntPtrRef(U&& func)
{
T spObjOutput;
Mso::TCntPtr<ISimple> spObjInput = new SimpleTestRef();
ISimple* pObjInput = spObjInput.Detach();
static void TestFunc4(_In_ _Notnull_ const ISimple* pObj, _Out_ const void** ppT)
{
*ppT = pObj;
}
func(pObjInput, &spObjOutput);
template <typename T, typename U>
static void TestTCntPtrRef(U && func)
{
T spObjOutput;
Mso::TCntPtr<ISimple> spObjInput = new SimpleTestRef();
ISimple* pObjInput = spObjInput.Detach();
TestAssert::AreEqual(pObjInput, spObjOutput.Get());
}
func(pObjInput, &spObjOutput);
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_ppT)
{
TestTCntPtrRef<Mso::TCntPtr<ISimple>>(TestFunc1);
}
TestAssert::AreEqual(pObjInput, spObjOutput.Get());
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_pTCntPtr)
{
TestTCntPtrRef<Mso::TCntPtr<ISimple>>(TestFunc2);
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_ppT)
{
TestTCntPtrRef<Mso::TCntPtr<ISimple>>(TestFunc1);
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_ppVoid)
{
TestTCntPtrRef<Mso::TCntPtr<ISimple>>(TestFunc3);
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_pTCntPtr)
{
TestTCntPtrRef<Mso::TCntPtr<ISimple>>(TestFunc2);
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_ppConstVoid)
{
TestTCntPtrRef<Mso::TCntPtr<ISimple>>(TestFunc4);
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_ppVoid)
{
TestTCntPtrRef<Mso::TCntPtr<ISimple>>(TestFunc3);
}
TEST_METHOD(TCntPtr_TCntPtrRef_Const_TCntPtr)
{
const Mso::TCntPtr<ISimple> spObj;
TestAssert::AreEqual(spObj.GetThis(), &spObj);
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_ppConstVoid)
{
TestTCntPtrRef<Mso::TCntPtr<ISimple>>(TestFunc4);
}
template<typename T, typename U>
static void TestTCntPtrRef_Reinterpret_Cast()
{
using TNonConst = typename std::remove_const<T>::type;
T spObj;
U ppObjDesired = reinterpret_cast<U>(const_cast<TNonConst&>(spObj).GetAddressOf());
U ppObj = static_cast<U>(&spObj);
TestAssert::AreEqual((void*)ppObjDesired, (void*)ppObj);
}
TEST_METHOD(TCntPtr_TCntPtrRef_Const_TCntPtr)
{
const Mso::TCntPtr<ISimple> spObj;
TestAssert::AreEqual(spObj.GetThis(), &spObj);
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_Reinterpret_Cast_ppVoid)
{
TestTCntPtrRef_Reinterpret_Cast<Mso::TCntPtr<ISimple>, void**>();
}
template <typename T, typename U>
static void TestTCntPtrRef_Reinterpret_Cast()
{
using TNonConst = typename std::remove_const<T>::type;
T spObj;
U ppObjDesired = reinterpret_cast<U>(const_cast<TNonConst&>(spObj).GetAddressOf());
U ppObj = static_cast<U>(&spObj);
TestAssert::AreEqual((void*)ppObjDesired, (void*)ppObj);
}
class SimpleTestRefUnknown : public Mso::UnknownObject<ISimpleUnknown>
{
void DoSomething() override {}
};
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_Reinterpret_Cast_ppVoid)
{
TestTCntPtrRef_Reinterpret_Cast<Mso::TCntPtr<ISimple>, void**>();
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_Reinterpret_Cast_ppIUnknown)
{
TestTCntPtrRef_Reinterpret_Cast<Mso::TCntPtr<SimpleTestRefUnknown>, IUnknown**>();
}
class SimpleTestRefUnknown : public Mso::UnknownObject<ISimpleUnknown>
{
void DoSomething() override {}
};
template<typename T>
static void TestTCntPtrRef_Cast_pVoid()
{
T spObj;
void* pVoid = &spObj;
Mso::TCntPtr<ISimple>* pTCntPtr = &spObj;
TestAssert::AreEqual(pVoid, (void*)pTCntPtr);
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_Reinterpret_Cast_ppIUnknown)
{
TestTCntPtrRef_Reinterpret_Cast<Mso::TCntPtr<SimpleTestRefUnknown>, IUnknown**>();
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_Cast_pVoid)
{
TestTCntPtrRef_Cast_pVoid<Mso::TCntPtr<ISimple>>();
}
template <typename T>
static void TestTCntPtrRef_Cast_pVoid()
{
T spObj;
void* pVoid = &spObj;
Mso::TCntPtr<ISimple>* pTCntPtr = &spObj;
TestAssert::AreEqual(pVoid, (void*)pTCntPtr);
}
TEST_METHOD(TCntPtr_TCntPtrRef_NonConst_Cast_pVoid)
{
TestTCntPtrRef_Cast_pVoid<Mso::TCntPtr<ISimple>>();
}
};

Просмотреть файл

@ -15,430 +15,411 @@ Unit tests for the TCntPtr smart pointer
MSO_STRUCT_GUID(IUnkSimple, "9FEAB33F-E5D0-4A52-9216-6BA8BA9990A4")
struct IUnkSimple : public IUnknown
{
virtual void DoSomething() = 0;
virtual void DoSomething() = 0;
};
MSO_STRUCT_GUID(IUnkSample, "8A2560F5-E28D-4342-8716-1BBD3A4603B3")
struct IUnkSample : public IUnknown
{
virtual void DoAnything() = 0;
virtual void DoAnything() = 0;
};
struct ISimple : public Mso::IRefCounted
{
virtual void DoSomething() = 0;
virtual void DoSomething() = 0;
};
typedef std::function<void(bool inc)> RefCountChangedCallback;
class SimpleClass : public ISimple
{
public:
SimpleClass(RefCountChangedCallback&& onRefCountChanged)
: m_refCount(0)
, m_onRefCountChanged(std::move(onRefCountChanged))
{
}
SimpleClass(RefCountChangedCallback&& onRefCountChanged)
: m_refCount(0), m_onRefCountChanged(std::move(onRefCountChanged))
{
}
virtual void AddRef() const noexcept override
{
OACR_ASSUME_NOTHROW_BEGIN
virtual void AddRef() const noexcept override
{
OACR_ASSUME_NOTHROW_BEGIN
m_onRefCountChanged(/*incremented*/true);
m_onRefCountChanged(/*incremented*/ true);
OACR_ASSUME_NOTHROW_END
OACR_ASSUME_NOTHROW_END
++m_refCount;
}
++m_refCount;
}
virtual void Release() const noexcept override
{
OACR_ASSUME_NOTHROW_BEGIN
virtual void Release() const noexcept override
{
OACR_ASSUME_NOTHROW_BEGIN
m_onRefCountChanged(/*incremented*/false);
m_onRefCountChanged(/*incremented*/ false);
OACR_ASSUME_NOTHROW_END
OACR_ASSUME_NOTHROW_END
if (--m_refCount == 0)
{
delete this;
}
}
if (--m_refCount == 0)
{
delete this;
}
}
virtual void DoSomething() noexcept override
{
}
virtual void DoSomething() noexcept override {}
void ClassDoSomething() noexcept
{
OACR_USE_PTR(this); // simulates access to 'this' for OACR build
}
void ClassDoSomething() noexcept
{
OACR_USE_PTR(this); // simulates access to 'this' for OACR build
}
private:
mutable std::atomic<uint32_t> m_refCount;
RefCountChangedCallback m_onRefCountChanged;
mutable std::atomic<uint32_t> m_refCount;
RefCountChangedCallback m_onRefCountChanged;
};
class UnkSimpleClass : public IUnkSimple
{
public:
UnkSimpleClass(RefCountChangedCallback&& onRefCountChanged)
: m_refCount(0)
, m_onRefCountChanged(std::move(onRefCountChanged))
{
}
UnkSimpleClass(RefCountChangedCallback&& onRefCountChanged)
: m_refCount(0), m_onRefCountChanged(std::move(onRefCountChanged))
{
}
_Success_(return == S_OK)
STDMETHOD(QueryInterface)(const GUID& /*riid*/, _Outptr_ void** /*ppvObject*/) noexcept override
{
return E_NOINTERFACE;
}
_Success_(return == S_OK)
STDMETHOD(QueryInterface)(const GUID& /*riid*/, _Outptr_ void** /*ppvObject*/) noexcept override
{
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)() noexcept override
{
OACR_ASSUME_NOTHROW_BEGIN
m_onRefCountChanged(/*incremented*/true);
OACR_ASSUME_NOTHROW_END
++m_refCount;
return 1;
}
STDMETHOD_(ULONG, AddRef)() noexcept override
{
OACR_ASSUME_NOTHROW_BEGIN
m_onRefCountChanged(/*incremented*/ true);
OACR_ASSUME_NOTHROW_END
++m_refCount;
return 1;
}
STDMETHOD_(ULONG, Release)() noexcept override
{
OACR_ASSUME_NOTHROW_BEGIN
m_onRefCountChanged(/*incremented*/false);
OACR_ASSUME_NOTHROW_END
if (--m_refCount == 0)
{
delete this;
}
STDMETHOD_(ULONG, Release)() noexcept override
{
OACR_ASSUME_NOTHROW_BEGIN
m_onRefCountChanged(/*incremented*/ false);
OACR_ASSUME_NOTHROW_END
if (--m_refCount == 0)
{
delete this;
}
return 1;
}
return 1;
}
virtual void DoSomething() noexcept override
{
}
virtual void DoSomething() noexcept override {}
void ClassDoSomething() noexcept
{
OACR_USE_PTR(this); // simulates access to 'this' for OACR build
}
void ClassDoSomething() noexcept
{
OACR_USE_PTR(this); // simulates access to 'this' for OACR build
}
private:
mutable std::atomic<uint32_t> m_refCount;
RefCountChangedCallback m_onRefCountChanged;
mutable std::atomic<uint32_t> m_refCount;
RefCountChangedCallback m_onRefCountChanged;
};
inline static std::wstring ToString(UnkSimpleClass* q) { return L""; }
inline static std::wstring ToString(SimpleClass* q) { return L""; }
inline static std::wstring ToString(const UnkSimpleClass* q) { return L""; }
inline static std::wstring ToString(const SimpleClass* q) { return L""; }
inline static std::wstring ToString(UnkSimpleClass* q)
{
return L"";
}
inline static std::wstring ToString(SimpleClass* q)
{
return L"";
}
inline static std::wstring ToString(const UnkSimpleClass* q)
{
return L"";
}
inline static std::wstring ToString(const SimpleClass* q)
{
return L"";
}
class AggregatedObject : public Mso::UnknownObject<IUnkSimple, IUnkSample>
{
public:
virtual void DoSomething() noexcept override
{
}
virtual void DoSomething() noexcept override {}
virtual void DoAnything() noexcept override
{
}
virtual void DoAnything() noexcept override {}
};
template <typename TAction>
static void ValidateRefCount(uint32_t expectedIncRefCountCallCount, TAction action)
{
uint32_t actualIncRefCountCallCount = 0;
uint32_t actualDecRefCountCallCount = 0;
auto callback = [&actualIncRefCountCallCount, &actualDecRefCountCallCount](bool incremented) noexcept
{
if (incremented)
{
++actualIncRefCountCallCount;
}
else
{
++actualDecRefCountCallCount;
}
};
uint32_t actualIncRefCountCallCount = 0;
uint32_t actualDecRefCountCallCount = 0;
auto callback = [&actualIncRefCountCallCount, &actualDecRefCountCallCount](bool incremented) noexcept {
if (incremented)
{
++actualIncRefCountCallCount;
}
else
{
++actualDecRefCountCallCount;
}
};
action(RefCountChangedCallback(callback));
action(RefCountChangedCallback(callback));
TestAssert::AreEqual(actualIncRefCountCallCount, actualDecRefCountCallCount, L"IncCount != DecCount.");
TestAssert::AreEqual(expectedIncRefCountCallCount, actualIncRefCountCallCount, L"Unexpected IncCount.");
TestAssert::AreEqual(actualIncRefCountCallCount, actualDecRefCountCallCount, L"IncCount != DecCount.");
TestAssert::AreEqual(expectedIncRefCountCallCount, actualIncRefCountCallCount, L"Unexpected IncCount.");
}
TestClassComponent(TCntPtrTest, Mso.TCntPtr)
TEST_CLASS(TCntPtrTest)
{
TestClassComponent(TCntPtrTest, Mso.TCntPtr) TEST_CLASS (TCntPtrTest){
TEST_METHOD(TCntPtr_EmptyCtor)
{
Mso::TCntPtr<SimpleClass> spObj;
TEST_METHOD(TCntPtr_EmptyCtor){Mso::TCntPtr<SimpleClass> spObj;
TestAssert::IsNull(spObj.Get(), L"Expected null");
TestAssert::IsNull(spObj.Get(), L"Expected null");
}
TEST_METHOD(TCntPtr_NullCtor)
{
Mso::TCntPtr<SimpleClass> spObj = nullptr;
Mso::TCntPtr<SimpleClass> spObj = nullptr;
TestAssert::IsNull(spObj.Get(), L"Expected null");
TestAssert::IsNull(spObj.Get(), L"Expected null");
}
TEST_METHOD(TCntPtr_DeprecatedNullCtor)
{
//TODO: Remove when we stop using NULL
Mso::TCntPtr<SimpleClass> spObj;
// TODO: Remove when we stop using NULL
Mso::TCntPtr<SimpleClass> spObj;
TestAssert::IsNull(spObj.Get(), L"Expected null");
TestAssert::IsNull(spObj.Get(), L"Expected null");
}
TEST_METHOD(TCntPtr_Create)
{
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged)
{
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged) {
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
TestAssert::AreEqual((void*)ptr, (void*)spObj.Get(), L"Expected ptr");
});
TestAssert::AreEqual((void*)ptr, (void*)spObj.Get(), L"Expected ptr");
});
}
TEST_METHOD(TCntPtr_CreateInterface)
{
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged)
{
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<ISimple> spIntf(ptr);
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged) {
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<ISimple> spIntf(ptr);
TestAssert::AreEqual((void*)ptr, (void*)spIntf.Get(), L"Expected ptr");
});
TestAssert::AreEqual((void*)ptr, (void*)spIntf.Get(), L"Expected ptr");
});
}
TEST_METHOD(TCntPtr_CopyConstructor)
{
ValidateRefCount(2, [](RefCountChangedCallback&& onRefCountChanged)
{
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<SimpleClass> spSameObj(spObj);
ValidateRefCount(2, [](RefCountChangedCallback&& onRefCountChanged) {
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<SimpleClass> spSameObj(spObj);
TestAssert::AreEqual((void*)ptr, (void*)spObj.Get(), L"Expected ptr");
TestAssert::AreEqual((void*)ptr, (void*)spSameObj.Get(), L"Expected ptr");
});
TestAssert::AreEqual((void*)ptr, (void*)spObj.Get(), L"Expected ptr");
TestAssert::AreEqual((void*)ptr, (void*)spSameObj.Get(), L"Expected ptr");
});
}
TEST_METHOD(TCntPtr_CopyConstructorInterface)
{
ValidateRefCount(2, [](RefCountChangedCallback&& onRefCountChanged)
{
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<ISimple> spIntf(spObj);
ValidateRefCount(2, [](RefCountChangedCallback&& onRefCountChanged) {
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<ISimple> spIntf(spObj);
TestAssert::AreEqual((void*) ptr, (void*) spObj.Get(), L"Expected ptr");
TestAssert::AreEqual((void*)ptr, (void*)spIntf.Get(), L"Expected ptr");
});
TestAssert::AreEqual((void*)ptr, (void*)spObj.Get(), L"Expected ptr");
TestAssert::AreEqual((void*)ptr, (void*)spIntf.Get(), L"Expected ptr");
});
}
TEST_METHOD(TCntPtr_MoveConstructor)
{
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged)
{
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<SimpleClass> spSameObj(std::move(spObj));
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged) {
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<SimpleClass> spSameObj(std::move(spObj));
TestAssert::IsNull(spObj.Get(), L"Expected null");
TestAssert::AreEqual((void*)ptr, (void*)spSameObj.Get(), L"Expected ptr");
});
TestAssert::IsNull(spObj.Get(), L"Expected null");
TestAssert::AreEqual((void*)ptr, (void*)spSameObj.Get(), L"Expected ptr");
});
}
TEST_METHOD(TCntPtr_MoveConstructorInterface)
{
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged)
{
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<ISimple> spIntf(std::move(spObj));
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged) {
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<ISimple> spIntf(std::move(spObj));
TestAssert::IsNull(spObj.Get(), L"Expected null");
TestAssert::AreEqual((void*)ptr, (void*)spIntf.Get(), L"Expected ptr");
});
TestAssert::IsNull(spObj.Get(), L"Expected null");
TestAssert::AreEqual((void*)ptr, (void*)spIntf.Get(), L"Expected ptr");
});
}
// Factory method to get benefits from using the move constructor
static Mso::TCntPtr<SimpleClass> CreateSimpleClass(RefCountChangedCallback&& onRefCountChanged)
{
Mso::TCntPtr<SimpleClass> spObj = new SimpleClass(std::move(onRefCountChanged));
spObj->ClassDoSomething();
return spObj; // std::move() not needed because the same type allows the named return value optimization.
Mso::TCntPtr<SimpleClass> spObj = new SimpleClass(std::move(onRefCountChanged));
spObj->ClassDoSomething();
return spObj; // std::move() not needed because the same type allows the named return value optimization.
}
TEST_METHOD(TCntPtr_CallCreateSimpleClass)
{
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged)
{
Mso::TCntPtr<ISimple> spObj = CreateSimpleClass(std::move(onRefCountChanged));
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged) {
Mso::TCntPtr<ISimple> spObj = CreateSimpleClass(std::move(onRefCountChanged));
TestAssert::IsNotNull(spObj.Get(), L"Expected not a null value");
});
TestAssert::IsNotNull(spObj.Get(), L"Expected not a null value");
});
}
// Factory method to get benefits from using the move constructor
static Mso::TCntPtr<ISimple> CreateISimple(RefCountChangedCallback&& onRefCountChanged)
{
Mso::TCntPtr<SimpleClass> spObj = new SimpleClass(std::move(onRefCountChanged));
spObj->ClassDoSomething();
return std::move(spObj); // We should use std::move() here to avoid use of copy constructor.
// Named value return optimization will not work because we have different types.
Mso::TCntPtr<SimpleClass> spObj = new SimpleClass(std::move(onRefCountChanged));
spObj->ClassDoSomething();
return std::move(spObj); // We should use std::move() here to avoid use of copy constructor.
// Named value return optimization will not work because we have different types.
}
TEST_METHOD(TCntPtr_CallCreateISimple)
{
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged)
{
Mso::TCntPtr<ISimple> spIntf = CreateISimple(std::move(onRefCountChanged));
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged) {
Mso::TCntPtr<ISimple> spIntf = CreateISimple(std::move(onRefCountChanged));
TestAssert::IsNotNull(spIntf.Get(), L"Expected not a null value");
});
TestAssert::IsNotNull(spIntf.Get(), L"Expected not a null value");
});
}
TEST_METHOD(TCntPtr_CopyAssignment)
{
ValidateRefCount(3, [](RefCountChangedCallback&& onRefCountChanged)
{
Mso::TCntPtr<SimpleClass> spObj1(new SimpleClass(RefCountChangedCallback(onRefCountChanged)));
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj2(ptr);
spObj1 = spObj2;
ValidateRefCount(3, [](RefCountChangedCallback&& onRefCountChanged) {
Mso::TCntPtr<SimpleClass> spObj1(new SimpleClass(RefCountChangedCallback(onRefCountChanged)));
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj2(ptr);
spObj1 = spObj2;
TestAssert::AreEqual((void*)ptr, (void*)spObj1.Get(), L"Expected ptr");
TestAssert::AreEqual((void*)ptr, (void*)spObj2.Get(), L"Expected ptr");
});
TestAssert::AreEqual((void*)ptr, (void*)spObj1.Get(), L"Expected ptr");
TestAssert::AreEqual((void*)ptr, (void*)spObj2.Get(), L"Expected ptr");
});
}
TEST_METHOD(TCntPtr_CopyAssignmentInterface)
{
ValidateRefCount(3, [](RefCountChangedCallback&& onRefCountChanged)
{
SimpleClass* ptr = new SimpleClass(RefCountChangedCallback(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<ISimple> spIntf = new SimpleClass(std::move(onRefCountChanged));
spIntf = spObj;
ValidateRefCount(3, [](RefCountChangedCallback&& onRefCountChanged) {
SimpleClass* ptr = new SimpleClass(RefCountChangedCallback(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<ISimple> spIntf = new SimpleClass(std::move(onRefCountChanged));
spIntf = spObj;
TestAssert::AreEqual((void*)ptr, (void*)spObj.Get(), L"Expected ptr");
TestAssert::AreEqual((void*)ptr, (void*)spIntf.Get(), L"Expected ptr");
});
TestAssert::AreEqual((void*)ptr, (void*)spObj.Get(), L"Expected ptr");
TestAssert::AreEqual((void*)ptr, (void*)spIntf.Get(), L"Expected ptr");
});
}
TEST_METHOD(TCntPtr_CopyAssignmentSameObject)
{
// See what happens when we assign TCntPtr to itself.
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged)
{
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
// See what happens when we assign TCntPtr to itself.
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged) {
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
OACR_WARNING_SUPPRESS(IDENTITY_ASSIGNMENT, "We want to test our code that nothing bad happens in this case");
spObj = spObj;
OACR_WARNING_SUPPRESS(IDENTITY_ASSIGNMENT, "We want to test our code that nothing bad happens in this case");
spObj = spObj;
TestAssert::AreEqual((void*)ptr, (void*)spObj.Get(), L"Expected ptr");
});
TestAssert::AreEqual((void*)ptr, (void*)spObj.Get(), L"Expected ptr");
});
}
TEST_METHOD(TCntPtr_CopyAssignmentConst)
{
// Test that TCntPtr can accept a const variable and AddRef/Release methods are not const.
ValidateRefCount(3, [](RefCountChangedCallback&& onRefCountChanged)
{
Mso::TCntPtr<const UnkSimpleClass> spObj1(new UnkSimpleClass(RefCountChangedCallback(onRefCountChanged)));
const UnkSimpleClass* ptr = new UnkSimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<const UnkSimpleClass> spObj2(ptr);
spObj1 = spObj2;
// Test that TCntPtr can accept a const variable and AddRef/Release methods are not const.
ValidateRefCount(3, [](RefCountChangedCallback&& onRefCountChanged) {
Mso::TCntPtr<const UnkSimpleClass> spObj1(new UnkSimpleClass(RefCountChangedCallback(onRefCountChanged)));
const UnkSimpleClass* ptr = new UnkSimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<const UnkSimpleClass> spObj2(ptr);
spObj1 = spObj2;
TestAssert::AreEqual((void*)ptr, (void*)spObj1.Get(), L"Expected ptr");
TestAssert::AreEqual((void*)ptr, (void*)spObj2.Get(), L"Expected ptr");
});
TestAssert::AreEqual((void*)ptr, (void*)spObj1.Get(), L"Expected ptr");
TestAssert::AreEqual((void*)ptr, (void*)spObj2.Get(), L"Expected ptr");
});
}
TEST_METHOD(TCntPtr_MoveAssignment)
{
ValidateRefCount(2, [](RefCountChangedCallback&& onRefCountChanged)
{
Mso::TCntPtr<SimpleClass> spObj1 = new SimpleClass(RefCountChangedCallback(onRefCountChanged));
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj2(ptr);
spObj1 = std::move(spObj2);
ValidateRefCount(2, [](RefCountChangedCallback&& onRefCountChanged) {
Mso::TCntPtr<SimpleClass> spObj1 = new SimpleClass(RefCountChangedCallback(onRefCountChanged));
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj2(ptr);
spObj1 = std::move(spObj2);
TestAssert::AreEqual((void*)ptr, (void*)spObj1.Get(), L"Expected ptr");
TestAssert::IsNull(spObj2.Get(), L"Expected null");
});
TestAssert::AreEqual((void*)ptr, (void*)spObj1.Get(), L"Expected ptr");
TestAssert::IsNull(spObj2.Get(), L"Expected null");
});
}
TEST_METHOD(TCntPtr_MoveAssignmentInterface)
{
ValidateRefCount(2, [](RefCountChangedCallback&& onRefCountChanged)
{
SimpleClass* ptr = new SimpleClass(RefCountChangedCallback(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<ISimple> spIntf = new SimpleClass(std::move(onRefCountChanged));
spIntf = std::move(spObj);
ValidateRefCount(2, [](RefCountChangedCallback&& onRefCountChanged) {
SimpleClass* ptr = new SimpleClass(RefCountChangedCallback(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
Mso::TCntPtr<ISimple> spIntf = new SimpleClass(std::move(onRefCountChanged));
spIntf = std::move(spObj);
TestAssert::IsNull(spObj.Get(), L"Expected null");
TestAssert::AreEqual((void*)ptr, (void*)spIntf.Get(), L"Expected ptr");
});
TestAssert::IsNull(spObj.Get(), L"Expected null");
TestAssert::AreEqual((void*)ptr, (void*)spIntf.Get(), L"Expected ptr");
});
}
TEST_METHOD(TCntPtr_MoveAssignmentSameObject)
{
// Our copy assignment does not check if we use the same object. This test is to see that nothing bad happens.
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged)
{
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
spObj = std::move(spObj);
// Our copy assignment does not check if we use the same object. This test is to see that nothing bad happens.
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged) {
SimpleClass* ptr = new SimpleClass(std::move(onRefCountChanged));
Mso::TCntPtr<SimpleClass> spObj(ptr);
spObj = std::move(spObj);
TestAssert::AreEqual((void*)ptr, (void*)spObj.Get(), L"Expected ptr");
});
TestAssert::AreEqual((void*)ptr, (void*)spObj.Get(), L"Expected ptr");
});
}
TEST_METHOD(TCntPtr_NullAssignment)
{
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged)
{
Mso::TCntPtr<SimpleClass> spObj = new SimpleClass(RefCountChangedCallback(onRefCountChanged));
spObj = nullptr;
ValidateRefCount(1, [](RefCountChangedCallback&& onRefCountChanged) {
Mso::TCntPtr<SimpleClass> spObj = new SimpleClass(RefCountChangedCallback(onRefCountChanged));
spObj = nullptr;
TestAssert::IsNull(spObj.Get(), L"Expected null");
});
TestAssert::IsNull(spObj.Get(), L"Expected null");
});
}
TEST_METHOD(TCntPtr_IsEqualObject_BothISimpleClass_AreEqual)
{
Mso::TCntPtr<IUnkSimple> spObj = Mso::Make<AggregatedObject>();
Mso::TCntPtr<IUnkSimple> spObjTwo = spObj;
Mso::TCntPtr<IUnkSimple> spObj = Mso::Make<AggregatedObject>();
Mso::TCntPtr<IUnkSimple> spObjTwo = spObj;
TestAssert::IsTrue(Mso::ComUtil::AreEqualObjects(spObj, spObjTwo));
TestAssert::IsTrue(Mso::ComUtil::AreEqualObjects(spObj, spObjTwo));
}
TEST_METHOD(TCntPtr_IsEqualObject_DifferentInterfaceTypes_AreEqual)
{
Mso::TCntPtr<IUnkSimple> spObj = Mso::Make<AggregatedObject>();
Mso::TCntPtr<IUnkSample> spSample;
TestAssert::HrSucceeded(Mso::ComUtil::HrQueryFrom(spSample, spObj));
Mso::TCntPtr<IUnkSimple> spObj = Mso::Make<AggregatedObject>();
Mso::TCntPtr<IUnkSample> spSample;
TestAssert::HrSucceeded(Mso::ComUtil::HrQueryFrom(spSample, spObj));
TestAssert::IsTrue(Mso::ComUtil::AreEqualObjects(spObj, spSample));
TestAssert::IsTrue(Mso::ComUtil::AreEqualObjects(spObj, spSample));
}
TEST_METHOD(TCntPtr_IsEqualObject_DifferentObject_AreNotEqual)
{
Mso::TCntPtr<IUnkSimple> spObj = Mso::Make<AggregatedObject>();
Mso::TCntPtr<IUnkSimple> spObjTwo = Mso::Make<AggregatedObject>();
Mso::TCntPtr<IUnkSimple> spObj = Mso::Make<AggregatedObject>();
Mso::TCntPtr<IUnkSimple> spObjTwo = Mso::Make<AggregatedObject>();
TestAssert::IsFalse(Mso::ComUtil::AreEqualObjects(spObj, spObjTwo));
TestAssert::IsFalse(Mso::ComUtil::AreEqualObjects(spObj, spObjTwo));
}
};
}
;

Просмотреть файл

@ -12,337 +12,319 @@ Unit tests for classes in the ObjectSwarm.h
#include <test/skipSEHUT.h>
#include <test/testCheck.h>
//#define TEST_BAD_INHERITANCE1 // Uncomment to confirm VEC, but observe a memory leak. We cannot safely destroy this class.
//#define TEST_BAD_INHERITANCE1 // Uncomment to confirm VEC, but observe a memory leak. We cannot safely destroy this
//class.
MSO_STRUCT_GUID(IFixedSwarmSample1, "AA2EB60A-06DD-486F-AC9B-DBF1DDE21408")
struct DECLSPEC_NOVTABLE IFixedSwarmSample1 : IUnknown
{
virtual int GetValue1() = 0;
virtual int GetValue1() = 0;
};
struct DECLSPEC_NOVTABLE IFixedSwarmSample2 : Mso::IRefCounted
{
virtual int GetValue2() = 0;
virtual int GetValue2() = 0;
};
struct DECLSPEC_NOVTABLE IFixedSwarmSample3 : Mso::IRefCounted
{
virtual int GetValue3() = 0;
virtual int GetValue3() = 0;
};
class FixedSwarmMemberSample1 final
: public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, IFixedSwarmSample1>
class FixedSwarmMemberSample1 final : public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, IFixedSwarmSample1>
{
public:
FixedSwarmMemberSample1(bool& created, bool& deleted) noexcept
: m_deleted(deleted)
{
created = true;
}
FixedSwarmMemberSample1(bool& created, bool& deleted) noexcept : m_deleted(deleted)
{
created = true;
}
virtual int GetValue1() noexcept override
{
return 1;
}
virtual int GetValue1() noexcept override
{
return 1;
}
protected:
virtual ~FixedSwarmMemberSample1() noexcept
{
m_deleted = true;
}
virtual ~FixedSwarmMemberSample1() noexcept
{
m_deleted = true;
}
private:
bool& m_deleted;
bool& m_deleted;
};
// We can add to FixedSwarm IRefCounted objects
class FixedSwarmMemberSample2 final
: public Mso::RefCountedObject<Mso::RefCountStrategy::WeakRef, IFixedSwarmSample2>
class FixedSwarmMemberSample2 final : public Mso::RefCountedObject<Mso::RefCountStrategy::WeakRef, IFixedSwarmSample2>
{
public:
virtual int GetValue2() noexcept override
{
return 2;
}
virtual int GetValue2() noexcept override
{
return 2;
}
};
class FixedSwarmMemberSample3 final
: public Mso::RefCountedObject<Mso::RefCountStrategy::WeakRef, IFixedSwarmSample3>
class FixedSwarmMemberSample3 final : public Mso::RefCountedObject<Mso::RefCountStrategy::WeakRef, IFixedSwarmSample3>
{
public:
virtual int GetValue3() noexcept override
{
return 3;
}
virtual int GetValue3() noexcept override
{
return 3;
}
};
class FixedSwarmMemberSampleBase
: public Mso::RefCountedObject<Mso::RefCountStrategy::WeakRef, IFixedSwarmSample2>
class FixedSwarmMemberSampleBase : public Mso::RefCountedObject<Mso::RefCountStrategy::WeakRef, IFixedSwarmSample2>
{
public:
FixedSwarmMemberSampleBase() noexcept
{
}
FixedSwarmMemberSampleBase() noexcept {}
virtual int GetValue2() noexcept override
{
return 2;
}
virtual int GetValue2() noexcept override
{
return 2;
}
protected:
virtual ~FixedSwarmMemberSampleBase() noexcept
{
}
virtual ~FixedSwarmMemberSampleBase() noexcept {}
};
class FixedSwarmMemberSample4Throw
: public FixedSwarmMemberSampleBase
class FixedSwarmMemberSample4Throw : public FixedSwarmMemberSampleBase
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtor;
using MakePolicy = Mso::MakePolicy::ThrowCtor;
FixedSwarmMemberSample4Throw()
{
throw std::runtime_error("Test");
}
FixedSwarmMemberSample4Throw()
{
throw std::runtime_error("Test");
}
};
class FixedSwarmMemberSample5InitThrow
: public FixedSwarmMemberSampleBase
class FixedSwarmMemberSample5InitThrow : public FixedSwarmMemberSampleBase
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
void InitializeThis()
{
UNREFERENCED_OACR(this);
throw std::runtime_error("Test");
}
void InitializeThis()
{
UNREFERENCED_OACR(this);
throw std::runtime_error("Test");
}
};
#ifdef TEST_BAD_INHERITANCE1
class SomeVirtualClass
{
public:
virtual ~SomeVirtualClass() = default;
virtual ~SomeVirtualClass() = default;
int x;
int y;
int x;
int y;
};
// !!! Mso::UnknownObject must be always the first one in the inheritance !!!
class BadFixedSwarmMember1 final
: public SomeVirtualClass
, public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, IFixedSwarmSample1>
: public SomeVirtualClass
, public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, IFixedSwarmSample1>
{
public:
virtual int GetValue1() override
{
return 1;
}
virtual int GetValue1() override
{
return 1;
}
};
#endif
TEST_CLASS(ObjectFixedSwarmTest)
TEST_CLASS (ObjectFixedSwarmTest)
{
TEST_METHOD(ObjectFixedSwarm_NoMemberInit)
{
using Swarm1 = Mso::FixedSwarm<FixedSwarmMemberSample1>;
Mso::TCntPtr<Swarm1> swarm1 = Mso::Make<Swarm1>();
TestAssert::IsFalse(swarm1.IsEmpty());
TEST_METHOD(ObjectFixedSwarm_NoMemberInit)
{
using Swarm1 = Mso::FixedSwarm<FixedSwarmMemberSample1>;
Mso::TCntPtr<Swarm1> swarm1 = Mso::Make<Swarm1>();
TestAssert::IsFalse(swarm1.IsEmpty());
using Swarm2 = Mso::FixedSwarm<FixedSwarmMemberSample1, FixedSwarmMemberSample2>;
Mso::TCntPtr<Swarm2> swarm2 = Mso::Make<Swarm2>();
TestAssert::IsFalse(swarm2.IsEmpty());
using Swarm2 = Mso::FixedSwarm<FixedSwarmMemberSample1, FixedSwarmMemberSample2>;
Mso::TCntPtr<Swarm2> swarm2 = Mso::Make<Swarm2>();
TestAssert::IsFalse(swarm2.IsEmpty());
using Swarm3 = Mso::FixedSwarm<FixedSwarmMemberSample1, FixedSwarmMemberSample2, FixedSwarmMemberSample3>;
Mso::TCntPtr<Swarm3> swarm3 = Mso::Make<Swarm3>();
TestAssert::IsFalse(swarm3.IsEmpty());
}
using Swarm3 = Mso::FixedSwarm<FixedSwarmMemberSample1, FixedSwarmMemberSample2, FixedSwarmMemberSample3>;
Mso::TCntPtr<Swarm3> swarm3 = Mso::Make<Swarm3>();
TestAssert::IsFalse(swarm3.IsEmpty());
}
TEST_METHOD(ObjectFixedSwarm_NoMemberRefCount)
{
using Swarm1 = Mso::FixedSwarm<FixedSwarmMemberSample1>;
Mso::TCntPtr<Swarm1> swarm1 = Mso::Make<Swarm1>();
TestAssert::IsFalse(swarm1.IsEmpty());
Debug(TestAssert::AreEqual(1, swarm1->RefCount()));
Debug(TestAssert::AreEqual(1, swarm1->WeakRefCount()));
TEST_METHOD(ObjectFixedSwarm_NoMemberRefCount)
{
using Swarm1 = Mso::FixedSwarm<FixedSwarmMemberSample1>;
Mso::TCntPtr<Swarm1> swarm1 = Mso::Make<Swarm1>();
TestAssert::IsFalse(swarm1.IsEmpty());
Mso::TCntPtr<Swarm1> swarm11 = swarm1;
Debug(TestAssert::AreEqual(2, swarm1->RefCount()));
Debug(TestAssert::AreEqual(1, swarm1->WeakRefCount()));
Debug(TestAssert::AreEqual(1, swarm1->RefCount()));
Debug(TestAssert::AreEqual(1, swarm1->WeakRefCount()));
Mso::WeakPtr<Swarm1> weakSwarm1 = swarm1;
Debug(TestAssert::AreEqual(2, swarm1->RefCount()));
Debug(TestAssert::AreEqual(2, swarm1->WeakRefCount()));
Mso::TCntPtr<Swarm1> swarm11 = swarm1;
Debug(TestAssert::AreEqual(2, swarm1->RefCount()));
Debug(TestAssert::AreEqual(1, swarm1->WeakRefCount()));
Mso::WeakPtr<Swarm1> weakSwarm11 = swarm1;
Debug(TestAssert::AreEqual(2, swarm1->RefCount()));
Debug(TestAssert::AreEqual(3, swarm1->WeakRefCount()));
}
Mso::WeakPtr<Swarm1> weakSwarm1 = swarm1;
Debug(TestAssert::AreEqual(2, swarm1->RefCount()));
Debug(TestAssert::AreEqual(2, swarm1->WeakRefCount()));
TEST_METHOD(ObjectFixedSwarm_GetMember)
{
using Swarm3 = Mso::FixedSwarm<FixedSwarmMemberSample1, FixedSwarmMemberSample2, FixedSwarmMemberSample3>;
Mso::TCntPtr<Swarm3> swarm3 = Mso::Make<Swarm3>();
TestAssert::IsFalse(swarm3.IsEmpty());
Mso::WeakPtr<Swarm1> weakSwarm11 = swarm1;
Debug(TestAssert::AreEqual(2, swarm1->RefCount()));
Debug(TestAssert::AreEqual(3, swarm1->WeakRefCount()));
}
FixedSwarmMemberSample1* sample1 = swarm3->Get<0>();
TestAssert::IsNull(sample1);
TEST_METHOD(ObjectFixedSwarm_GetMember)
{
using Swarm3 = Mso::FixedSwarm<FixedSwarmMemberSample1, FixedSwarmMemberSample2, FixedSwarmMemberSample3>;
Mso::TCntPtr<Swarm3> swarm3 = Mso::Make<Swarm3>();
TestAssert::IsFalse(swarm3.IsEmpty());
FixedSwarmMemberSample2* sample2 = swarm3->Get<1>();
TestAssert::IsNull(sample2);
FixedSwarmMemberSample1* sample1 = swarm3->Get<0>();
TestAssert::IsNull(sample1);
FixedSwarmMemberSample3* sample3 = swarm3->Get<2>();
TestAssert::IsNull(sample3);
}
FixedSwarmMemberSample2* sample2 = swarm3->Get<1>();
TestAssert::IsNull(sample2);
TEST_METHOD(ObjectFixedSwarm_OneMember)
{
using Swarm1 = Mso::FixedSwarm<FixedSwarmMemberSample1>;
bool created = false;
bool deleted = false;
FixedSwarmMemberSample3* sample3 = swarm3->Get<2>();
TestAssert::IsNull(sample3);
}
{
Mso::TCntPtr<Swarm1> swarm1 = Mso::Make<Swarm1>();
TEST_METHOD(ObjectFixedSwarm_OneMember)
{
using Swarm1 = Mso::FixedSwarm<FixedSwarmMemberSample1>;
bool created = false;
bool deleted = false;
{
swarm1->MakeMember<0>(created, deleted);
Mso::TCntPtr<IFixedSwarmSample1> member0 = swarm1->Get<0>();
TestAssert::IsFalse(member0.IsEmpty());
TestAssert::IsTrue(created);
TestAssert::IsFalse(deleted);
{
Mso::TCntPtr<Swarm1> swarm1 = Mso::Make<Swarm1>();
Debug(TestAssert::AreEqual(2, swarm1->RefCount()));
Debug(TestAssert::AreEqual(2, swarm1->WeakRefCount()));
}
{
swarm1->MakeMember<0>(created, deleted);
Mso::TCntPtr<IFixedSwarmSample1> member0 = swarm1->Get<0>();
TestAssert::IsFalse(member0.IsEmpty());
TestAssert::IsTrue(created);
TestAssert::IsFalse(deleted);
TestAssert::IsFalse(deleted);
Debug(TestAssert::AreEqual(1, swarm1->RefCount()));
Debug(TestAssert::AreEqual(2, swarm1->WeakRefCount()));
}
Debug(TestAssert::AreEqual(2, swarm1->RefCount()));
Debug(TestAssert::AreEqual(2, swarm1->WeakRefCount()));
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsFalse(deleted);
Debug(TestAssert::AreEqual(1, swarm1->RefCount()));
Debug(TestAssert::AreEqual(2, swarm1->WeakRefCount()));
}
TEST_METHOD(ObjectFixedSwarm_ThreeMembers)
{
using Swarm3 = Mso::FixedSwarm<FixedSwarmMemberSample1, FixedSwarmMemberSample2, FixedSwarmMemberSample3>;
bool created = false;
bool deleted = false;
TestAssert::IsTrue(deleted);
}
{
Mso::TCntPtr<Swarm3> swarm3 = Mso::Make<Swarm3>();
TEST_METHOD(ObjectFixedSwarm_ThreeMembers)
{
using Swarm3 = Mso::FixedSwarm<FixedSwarmMemberSample1, FixedSwarmMemberSample2, FixedSwarmMemberSample3>;
bool created = false;
bool deleted = false;
{
swarm3->MakeMember<0>(created, deleted);
Mso::TCntPtr<IFixedSwarmSample1> member0 = swarm3->Get<0>();
TestAssert::IsFalse(member0.IsEmpty());
Debug(TestAssert::AreEqual(2, swarm3->RefCount()));
Debug(TestAssert::AreEqual(2, swarm3->WeakRefCount()));
{
Mso::TCntPtr<Swarm3> swarm3 = Mso::Make<Swarm3>();
swarm3->MakeMember<1>();
Mso::TCntPtr<IFixedSwarmSample2> member1 = swarm3->Get<1>();
TestAssert::IsFalse(member1.IsEmpty());
Debug(TestAssert::AreEqual(3, swarm3->RefCount()));
Debug(TestAssert::AreEqual(3, swarm3->WeakRefCount()));
{
swarm3->MakeMember<0>(created, deleted);
Mso::TCntPtr<IFixedSwarmSample1> member0 = swarm3->Get<0>();
TestAssert::IsFalse(member0.IsEmpty());
Debug(TestAssert::AreEqual(2, swarm3->RefCount()));
Debug(TestAssert::AreEqual(2, swarm3->WeakRefCount()));
swarm3->MakeMember<2>();
Mso::TCntPtr<FixedSwarmMemberSample3> member2 = swarm3->Get<2>();
TestAssert::IsFalse(member2.IsEmpty());
Debug(TestAssert::AreEqual(4, swarm3->RefCount()));
Debug(TestAssert::AreEqual(4, swarm3->WeakRefCount()));
}
swarm3->MakeMember<1>();
Mso::TCntPtr<IFixedSwarmSample2> member1 = swarm3->Get<1>();
TestAssert::IsFalse(member1.IsEmpty());
Debug(TestAssert::AreEqual(3, swarm3->RefCount()));
Debug(TestAssert::AreEqual(3, swarm3->WeakRefCount()));
TestAssert::IsFalse(deleted);
Debug(TestAssert::AreEqual(1, swarm3->RefCount()));
// Each object +1 for weak reference count, +1 weak reference if strong ref count != 0.
Debug(TestAssert::AreEqual(4, swarm3->WeakRefCount()));
}
swarm3->MakeMember<2>();
Mso::TCntPtr<FixedSwarmMemberSample3> member2 = swarm3->Get<2>();
TestAssert::IsFalse(member2.IsEmpty());
Debug(TestAssert::AreEqual(4, swarm3->RefCount()));
Debug(TestAssert::AreEqual(4, swarm3->WeakRefCount()));
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsFalse(deleted);
Debug(TestAssert::AreEqual(1, swarm3->RefCount()));
// Each object +1 for weak reference count, +1 weak reference if strong ref count != 0.
Debug(TestAssert::AreEqual(4, swarm3->WeakRefCount()));
}
TEST_METHOD(ObjectFixedSwarm_WeakPtr)
{
using Swarm3 = Mso::FixedSwarm<FixedSwarmMemberSample1, FixedSwarmMemberSample2, FixedSwarmMemberSample3>;
bool created = false;
bool deleted = false;
TestAssert::IsTrue(deleted);
}
Mso::WeakPtr<IFixedSwarmSample1> weakMember0;
Mso::WeakPtr<FixedSwarmMemberSample2> weakMember1;
Mso::WeakPtr<IFixedSwarmSample3> weakMember2;
TEST_METHOD(ObjectFixedSwarm_WeakPtr)
{
using Swarm3 = Mso::FixedSwarm<FixedSwarmMemberSample1, FixedSwarmMemberSample2, FixedSwarmMemberSample3>;
bool created = false;
bool deleted = false;
{
Mso::TCntPtr<Swarm3> swarm3 = Mso::Make<Swarm3>();
swarm3->MakeMember<0>(created, deleted);
swarm3->MakeMember<1>();
swarm3->MakeMember<2>();
Mso::WeakPtr<IFixedSwarmSample1> weakMember0;
Mso::WeakPtr<FixedSwarmMemberSample2> weakMember1;
Mso::WeakPtr<IFixedSwarmSample3> weakMember2;
weakMember0 = swarm3->GetWeakPtr<0>();
weakMember1 = swarm3->GetWeakPtr<1>();
weakMember2 = swarm3->GetWeakPtr<2>();
{
Mso::TCntPtr<Swarm3> swarm3 = Mso::Make<Swarm3>();
swarm3->MakeMember<0>(created, deleted);
swarm3->MakeMember<1>();
swarm3->MakeMember<2>();
TestAssert::IsFalse(weakMember0.IsExpired());
TestAssert::IsFalse(weakMember1.IsExpired());
TestAssert::IsFalse(weakMember2.IsExpired());
weakMember0 = swarm3->GetWeakPtr<0>();
weakMember1 = swarm3->GetWeakPtr<1>();
weakMember2 = swarm3->GetWeakPtr<2>();
TestAssert::AreEqual(1, weakMember0.GetStrongPtr()->GetValue1());
TestAssert::AreEqual(2, weakMember1.GetStrongPtr()->GetValue2());
TestAssert::AreEqual(3, weakMember2.GetStrongPtr()->GetValue3());
}
TestAssert::IsFalse(weakMember0.IsExpired());
TestAssert::IsFalse(weakMember1.IsExpired());
TestAssert::IsFalse(weakMember2.IsExpired());
TestAssert::IsTrue(weakMember0.IsExpired());
TestAssert::IsTrue(weakMember1.IsExpired());
TestAssert::IsTrue(weakMember2.IsExpired());
TestAssert::AreEqual(1, weakMember0.GetStrongPtr()->GetValue1());
TestAssert::AreEqual(2, weakMember1.GetStrongPtr()->GetValue2());
TestAssert::AreEqual(3, weakMember2.GetStrongPtr()->GetValue3());
}
TestAssert::IsNull(weakMember0.GetStrongPtr().Get());
TestAssert::IsNull(weakMember1.GetStrongPtr().Get());
TestAssert::IsNull(weakMember2.GetStrongPtr().Get());
}
TestAssert::IsTrue(weakMember0.IsExpired());
TestAssert::IsTrue(weakMember1.IsExpired());
TestAssert::IsTrue(weakMember2.IsExpired());
TEST_METHOD(ObjectFixedSwarm_ConstructorThrows)
{
using Swarm2 = Mso::FixedSwarm<FixedSwarmMemberSample3, FixedSwarmMemberSample4Throw>;
TestAssert::IsNull(weakMember0.GetStrongPtr().Get());
TestAssert::IsNull(weakMember1.GetStrongPtr().Get());
TestAssert::IsNull(weakMember2.GetStrongPtr().Get());
}
Mso::TCntPtr<Swarm2> swarm2 = Mso::Make<Swarm2>();
swarm2->MakeMember<0>();
TestAssert::ExpectException<std::runtime_error>([&]()
{
swarm2->MakeMember<1>();
});
TEST_METHOD(ObjectFixedSwarm_ConstructorThrows)
{
using Swarm2 = Mso::FixedSwarm<FixedSwarmMemberSample3, FixedSwarmMemberSample4Throw>;
Debug(TestAssert::AreEqual(1u, swarm2->RefCount()));
Debug(TestAssert::AreEqual(2u, swarm2->WeakRefCount()));
}
Mso::TCntPtr<Swarm2> swarm2 = Mso::Make<Swarm2>();
swarm2->MakeMember<0>();
TestAssert::ExpectException<std::runtime_error>([&]() { swarm2->MakeMember<1>(); });
TEST_METHOD(ObjectFixedSwarm_InitializeThrows)
{
using Swarm2 = Mso::FixedSwarm<FixedSwarmMemberSample3, FixedSwarmMemberSample5InitThrow>;
Debug(TestAssert::AreEqual(1u, swarm2->RefCount()));
Debug(TestAssert::AreEqual(2u, swarm2->WeakRefCount()));
}
Mso::TCntPtr<Swarm2> swarm2 = Mso::Make<Swarm2>();
swarm2->MakeMember<0>();
TestAssert::ExpectException<std::runtime_error>([&]()
{
swarm2->MakeMember<1>();
});
TEST_METHOD(ObjectFixedSwarm_InitializeThrows)
{
using Swarm2 = Mso::FixedSwarm<FixedSwarmMemberSample3, FixedSwarmMemberSample5InitThrow>;
Debug(TestAssert::AreEqual(1u, swarm2->RefCount()));
Debug(TestAssert::AreEqual(2u, swarm2->WeakRefCount()));
}
Mso::TCntPtr<Swarm2> swarm2 = Mso::Make<Swarm2>();
swarm2->MakeMember<0>();
TestAssert::ExpectException<std::runtime_error>([&]() { swarm2->MakeMember<1>(); });
Debug(TestAssert::AreEqual(1u, swarm2->RefCount()));
Debug(TestAssert::AreEqual(2u, swarm2->WeakRefCount()));
}
#if defined(DEBUG) && defined(TEST_BAD_INHERITANCE1)
TESTMETHOD_REQUIRES_SEH(ObjectFixedSwarm_BadInheritance1)
{
using Swarm2 = Mso::FixedSwarm<BadFixedSwarmMember1, FixedSwarmMemberSample2>;
Mso::TCntPtr<Swarm2> swarm2 = Mso::Make<Swarm2>();
TestAssert::ExpectVEC([&]() noexcept
{
// You will see a memory leak here because we cannot destroy object correctly.
swarm2->MakeMember<0>();
});
}
TESTMETHOD_REQUIRES_SEH(ObjectFixedSwarm_BadInheritance1)
{
using Swarm2 = Mso::FixedSwarm<BadFixedSwarmMember1, FixedSwarmMemberSample2>;
Mso::TCntPtr<Swarm2> swarm2 = Mso::Make<Swarm2>();
TestAssert::ExpectVEC([&]() noexcept {
// You will see a memory leak here because we cannot destroy object correctly.
swarm2->MakeMember<0>();
});
}
#endif
};

Просмотреть файл

@ -2,9 +2,9 @@
// Licensed under the MIT license.
/****************************************************************************
Holder.cpp
Holder.cpp
Unit tests for the smart pointers
Unit tests for the smart pointers
****************************************************************************/
#include "precomp.h"
@ -17,277 +17,295 @@
#include <cppExtensions/autoRestore.h>
/*------------------------------------------------------------------------------
%%Id: e308ef40-4b24-4cd2-98cb-a269c6345d81
%%Id: e308ef40-4b24-4cd2-98cb-a269c6345d81
------------------------------------------------------------------------------*/
class CUnknown : public IUnknown
{
{
public:
/*---------------------------------------------------------------------------
%%Id: 8cf178db-8f93-40d9-beb1-c2cbe04feb60
---------------------------------------------------------------------------*/
CUnknown() noexcept : m_cRef(0) {}
/*---------------------------------------------------------------------------
%%Id: b3d41d41-7d5f-4190-a215-abbdf1149345
---------------------------------------------------------------------------*/
virtual ~CUnknown() noexcept {}
/*---------------------------------------------------------------------------
%%Id: eae6ae85-b193-4bdc-9e77-032456318605
---------------------------------------------------------------------------*/
STDMETHOD(QueryInterface)(REFIID riid, void **ppv) noexcept override { if (riid == __uuidof(IUnknown)) { *ppv = this; AddRef(); return S_OK; } return E_NOTIMPL; }
/*---------------------------------------------------------------------------
%%Id: 997c38a7-d5fe-456f-aaff-f3061bd07693
---------------------------------------------------------------------------*/
STDMETHOD_(ULONG, AddRef)() noexcept override { return ++m_cRef; }
/*---------------------------------------------------------------------------
%%Id: 997c38a7-d5fe-456f-aaff-f3061bd07693
---------------------------------------------------------------------------*/
OACR_WARNING_SUPPRESS(NOTHROW_FUNC_THROWS, "This is test code and we want to use throwing TestAssert::IsTrue. It does not affect ship code.")
STDMETHOD_(ULONG, Release)() noexcept override { ULONG cRef = --m_cRef; TestAssert::IsTrue(static_cast<LONG>(cRef) >= 0, L""); if (cRef == 0) delete this; return cRef; }
ULONG m_cRef;
};
/*---------------------------------------------------------------------------
%%Id: 8cf178db-8f93-40d9-beb1-c2cbe04feb60
---------------------------------------------------------------------------*/
CUnknown() noexcept : m_cRef(0) {}
/*---------------------------------------------------------------------------
%%Id: b3d41d41-7d5f-4190-a215-abbdf1149345
---------------------------------------------------------------------------*/
virtual ~CUnknown() noexcept {}
/*---------------------------------------------------------------------------
%%Id: eae6ae85-b193-4bdc-9e77-032456318605
---------------------------------------------------------------------------*/
STDMETHOD(QueryInterface)(REFIID riid, void** ppv) noexcept override
{
if (riid == __uuidof(IUnknown))
{
*ppv = this;
AddRef();
return S_OK;
}
return E_NOTIMPL;
}
/*---------------------------------------------------------------------------
%%Id: 997c38a7-d5fe-456f-aaff-f3061bd07693
---------------------------------------------------------------------------*/
STDMETHOD_(ULONG, AddRef)() noexcept override
{
return ++m_cRef;
}
/*---------------------------------------------------------------------------
%%Id: 997c38a7-d5fe-456f-aaff-f3061bd07693
---------------------------------------------------------------------------*/
OACR_WARNING_SUPPRESS(
NOTHROW_FUNC_THROWS,
"This is test code and we want to use throwing TestAssert::IsTrue. It does not affect ship code.")
STDMETHOD_(ULONG, Release)() noexcept override
{
ULONG cRef = --m_cRef;
TestAssert::IsTrue(static_cast<LONG>(cRef) >= 0, L"");
if (cRef == 0)
delete this;
return cRef;
}
ULONG m_cRef;
};
MSO_STRUCT_GUID(ICustom, "5c58ced6-4f43-4b56-8d47-2236d00f7ccd")
struct ICustom : IUnknown
{
virtual void SomeMethod() = 0;
virtual void SomeMethod() = 0;
};
TEST_CLASS(HolderTests)
TEST_CLASS (HolderTests)
{
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
TEST_METHOD(Ctor)
{
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb1;
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb2(NULL);
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb3 = NULL;
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb4 = new BYTE;
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
TEST_METHOD(Assignment)
{
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb1;
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb2;
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb3 = new BYTE;
TestAssert::IsTrue(pb1 == nullptr, L"");
TestAssert::IsTrue(pb1 == pb2, L"");
TestAssert::IsTrue(pb1 != pb3, L"");
TestAssert::IsTrue(pb3 != nullptr, L"");
const BYTE* pbRaw = pb1;
TestAssert::IsTrue(pbRaw == nullptr, L"");
TestAssert::IsTrue(pbRaw == pb1, L"");
TestAssert::IsTrue(pbRaw != pb3, L"");
pbRaw = pb3;
TestAssert::IsTrue(pbRaw != nullptr, L"");
TestAssert::IsTrue(pbRaw != pb1, L"");
TestAssert::IsTrue(pbRaw == pb3, L"");
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
TEST_METHOD(Swap)
{
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb1;
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb2 = new BYTE;
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb3 = new BYTE;
const BYTE* pb1Raw = pb1;
const BYTE* pb2Raw = pb2;
const BYTE* pb3Raw = pb3;
TestAssert::IsTrue(pb1Raw == nullptr, L"");
TestAssert::IsTrue(pb2Raw != nullptr, L"");
TestAssert::IsTrue(pb3Raw != nullptr, L"");
TestAssert::IsTrue(pb2Raw != pb3Raw, L"");
pb2.Swap(pb3);
TestAssert::IsTrue(pb2Raw != pb2, L"");
TestAssert::IsTrue(pb2Raw == pb3, L"");
TestAssert::IsTrue(pb3Raw != pb3, L"");
TestAssert::IsTrue(pb3Raw == pb2, L"");
pb3.Swap(pb2);
TestAssert::IsTrue(pb2Raw == pb2, L"");
TestAssert::IsTrue(pb2Raw != pb3, L"");
TestAssert::IsTrue(pb3Raw == pb3, L"");
TestAssert::IsTrue(pb3Raw != pb2, L"");
pb1.Swap(pb2);
TestAssert::IsTrue(pb2Raw != pb2, L"");
TestAssert::IsTrue(pb2Raw == pb1, L"");
TestAssert::IsTrue(pb1Raw != pb1, L"");
TestAssert::IsTrue(pb1Raw == pb2, L"");
pb2.Swap(pb1);
}
/*------------------------------------------------------------------------------
%%Id: 4a8bb941-2f5c-488a-8bc9-9f5b8c0897be
------------------------------------------------------------------------------*/
TEST_METHOD(Transfer)
{
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb1;
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb2 = new BYTE;
TestAssert::IsTrue(pb1 == nullptr, L"");
TestAssert::IsTrue(pb2 != nullptr, L"");
pb1.Transfer(pb2);
TestAssert::IsTrue(pb1 != nullptr, L"");
TestAssert::IsTrue(pb2 == nullptr, L"");
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
TEST_METHOD(Place)
{
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb1;
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb2 = new BYTE;
TestAssert::IsTrue(pb1 == nullptr, L"");
TestAssert::IsTrue(pb2 != nullptr, L"");
pb1.Place(pb2.Detach());
TestAssert::IsTrue(pb1 != nullptr, L"");
TestAssert::IsTrue(pb2 == nullptr, L"");
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
TEST_METHOD(Attach)
{
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb1 = new BYTE;
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb2 = new BYTE;
TestAssert::IsTrue(pb1 != nullptr, L"");
TestAssert::IsTrue(pb2 != nullptr, L"");
pb1.Attach(pb2.Detach());
TestAssert::IsTrue(pb1 != nullptr, L"");
TestAssert::IsTrue(pb2 == nullptr, L"");
}
/*------------------------------------------------------------------------------
%%Id: 040b6350-5468-48ff-b8cf-defc6ef412ad
------------------------------------------------------------------------------*/
TEST_METHOD(Address)
{
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb1;
Mso::THolder<BYTE*, Mso::TDeleteHelper<BYTE*>> pb2 = new BYTE;
TestAssert::IsTrue(pb1 == nullptr, L"");
TestAssert::IsTrue(pb2 != nullptr, L"");
BYTE** ppb = &pb1;
TestAssert::IsTrue(ppb == pb1.Address(), L"");
TestAssert::IsTrue(ppb == pb1.GetRaw(), L"");
*ppb = pb2.Detach();
TestAssert::IsTrue(pb1 != nullptr, L"");
TestAssert::IsTrue(pb2 == nullptr, L"");
}
/*------------------------------------------------------------------------------
%%Id: afe52e28-6314-446a-bb29-d2d07ce4a845
------------------------------------------------------------------------------*/
TEST_METHOD(CntPtrCore)
{
Mso::TCntPtr<CUnknown> punk1;
Mso::TCntPtr<CUnknown> punk2(new CUnknown());
Mso::TCntPtr<CUnknown> punk3(new CUnknown(), false);
punk3->AddRef();
Mso::TCntPtr<CUnknown> punk4(punk3);
Mso::TCntPtr<CUnknown> punk5;
punk5 = new CUnknown();
TestAssert::IsTrue(punk1 == nullptr, L"");
TestAssert::IsTrue(punk2 != nullptr, L"");
TestAssert::IsTrue(punk3 != nullptr, L"");
TestAssert::IsTrue(punk4 != nullptr, L"");
TestAssert::IsTrue(punk5 != nullptr, L"");
punk1 = punk2;
TestAssert::IsTrue(punk1->m_cRef == 2, L"");
TestAssert::IsTrue(punk2->m_cRef == 2, L"");
punk1 = punk4;
TestAssert::IsTrue(punk1->m_cRef == 3, L"");
TestAssert::IsTrue(punk2->m_cRef == 1, L"");
TestAssert::IsTrue(punk4->m_cRef == 3, L"");
punk1 = NULL;
punk1.Swap(punk3);
punk3.Swap(punk5);
punk5.Swap(punk1);
punk3.Swap(punk5);
punk1.Transfer(punk2);
punk2.Transfer(punk1);
punk1.Place(punk2.Detach());
punk2.Place(punk1.Detach());
punk1.Attach(punk2.Detach());
punk2.Attach(punk1.Detach());
TestAssert::IsTrue(punk1 == nullptr, L"");
TestAssert::IsTrue(punk2 != nullptr, L"");
TestAssert::IsTrue(punk2->m_cRef == 1, L"");
TestAssert::IsTrue(punk3 != nullptr, L"");
TestAssert::IsTrue(punk3->m_cRef == 2, L"");
TestAssert::IsTrue(punk4 != nullptr, L"");
TestAssert::IsTrue(punk4->m_cRef == 2, L"");
TestAssert::IsTrue(punk3 == punk4, L"");
TestAssert::IsTrue(punk5 != nullptr, L"");
TestAssert::IsTrue(punk5->m_cRef == 1, L"");
}
/*------------------------------------------------------------------------------
%%Id: 5938c5b2-5d47-40a6-bd0a-903a7e126059
------------------------------------------------------------------------------*/
TEST_METHOD(CntPtrMixed)
{
Mso::TCntPtr<IUnknown> punk;
Mso::TCntPtr<ICustom> pistm;
TestAssert::IsTrue(pistm == nullptr, L"");
TestAssert::IsTrue(punk == nullptr, L"");
punk = pistm;
punk = &*pistm;
punk = *pistm.GetRaw();
punk = pistm.Copy();
*punk.Address() = pistm.Copy();
*punk.GetRaw() = pistm.Copy();
pistm = static_cast<ICustom*>(static_cast<IUnknown*>(punk));
pistm = static_cast<ICustom*>(&*punk);
pistm = static_cast<ICustom*>(*punk.GetRaw());
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
TEST_METHOD(Ctor)
{
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb1;
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb2(NULL);
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb3 = NULL;
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb4 = new BYTE;
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
TEST_METHOD(Assignment)
{
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb1;
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb2;
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb3 = new BYTE;
TestAssert::IsTrue(pb1 == nullptr, L"");
TestAssert::IsTrue(pb1 == pb2, L"");
TestAssert::IsTrue(pb1 != pb3, L"");
TestAssert::IsTrue(pb3 != nullptr, L"");
const BYTE *pbRaw = pb1;
TestAssert::IsTrue(pbRaw == nullptr, L"");
TestAssert::IsTrue(pbRaw == pb1, L"");
TestAssert::IsTrue(pbRaw != pb3, L"");
pbRaw = pb3;
TestAssert::IsTrue(pbRaw != nullptr, L"");
TestAssert::IsTrue(pbRaw != pb1, L"");
TestAssert::IsTrue(pbRaw == pb3, L"");
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
TEST_METHOD(Swap)
{
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb1;
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb2 = new BYTE;
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb3 = new BYTE;
const BYTE *pb1Raw = pb1;
const BYTE *pb2Raw = pb2;
const BYTE *pb3Raw = pb3;
TestAssert::IsTrue(pb1Raw == nullptr, L"");
TestAssert::IsTrue(pb2Raw != nullptr, L"");
TestAssert::IsTrue(pb3Raw != nullptr, L"");
TestAssert::IsTrue(pb2Raw != pb3Raw, L"");
pb2.Swap(pb3);
TestAssert::IsTrue(pb2Raw != pb2, L"");
TestAssert::IsTrue(pb2Raw == pb3, L"");
TestAssert::IsTrue(pb3Raw != pb3, L"");
TestAssert::IsTrue(pb3Raw == pb2, L"");
pb3.Swap(pb2);
TestAssert::IsTrue(pb2Raw == pb2, L"");
TestAssert::IsTrue(pb2Raw != pb3, L"");
TestAssert::IsTrue(pb3Raw == pb3, L"");
TestAssert::IsTrue(pb3Raw != pb2, L"");
pb1.Swap(pb2);
TestAssert::IsTrue(pb2Raw != pb2, L"");
TestAssert::IsTrue(pb2Raw == pb1, L"");
TestAssert::IsTrue(pb1Raw != pb1, L"");
TestAssert::IsTrue(pb1Raw == pb2, L"");
pb2.Swap(pb1);
}
/*------------------------------------------------------------------------------
%%Id: 4a8bb941-2f5c-488a-8bc9-9f5b8c0897be
------------------------------------------------------------------------------*/
TEST_METHOD(Transfer)
{
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb1;
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb2 = new BYTE;
TestAssert::IsTrue(pb1 == nullptr, L"");
TestAssert::IsTrue(pb2 != nullptr, L"");
pb1.Transfer(pb2);
TestAssert::IsTrue(pb1 != nullptr, L"");
TestAssert::IsTrue(pb2 == nullptr, L"");
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
TEST_METHOD(Place)
{
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb1;
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb2 = new BYTE;
TestAssert::IsTrue(pb1 == nullptr, L"");
TestAssert::IsTrue(pb2 != nullptr, L"");
pb1.Place(pb2.Detach());
TestAssert::IsTrue(pb1 != nullptr, L"");
TestAssert::IsTrue(pb2 == nullptr, L"");
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
TEST_METHOD(Attach)
{
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb1 = new BYTE;
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb2 = new BYTE;
TestAssert::IsTrue(pb1 != nullptr, L"");
TestAssert::IsTrue(pb2 != nullptr, L"");
pb1.Attach(pb2.Detach());
TestAssert::IsTrue(pb1 != nullptr, L"");
TestAssert::IsTrue(pb2 == nullptr, L"");
}
/*------------------------------------------------------------------------------
%%Id: 040b6350-5468-48ff-b8cf-defc6ef412ad
------------------------------------------------------------------------------*/
TEST_METHOD(Address)
{
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb1;
Mso::THolder<BYTE *, Mso::TDeleteHelper<BYTE *>> pb2 = new BYTE;
TestAssert::IsTrue(pb1 == nullptr, L"");
TestAssert::IsTrue(pb2 != nullptr, L"");
BYTE **ppb = &pb1;
TestAssert::IsTrue(ppb == pb1.Address(), L"");
TestAssert::IsTrue(ppb == pb1.GetRaw(), L"");
*ppb = pb2.Detach();
TestAssert::IsTrue(pb1 != nullptr, L"");
TestAssert::IsTrue(pb2 == nullptr, L"");
}
/*------------------------------------------------------------------------------
%%Id: afe52e28-6314-446a-bb29-d2d07ce4a845
------------------------------------------------------------------------------*/
TEST_METHOD(CntPtrCore)
{
Mso::TCntPtr<CUnknown> punk1;
Mso::TCntPtr<CUnknown> punk2( new CUnknown() );
Mso::TCntPtr<CUnknown> punk3( new CUnknown(), false );
punk3->AddRef();
Mso::TCntPtr<CUnknown> punk4(punk3);
Mso::TCntPtr<CUnknown> punk5;
punk5 = new CUnknown();
TestAssert::IsTrue(punk1 == nullptr, L"");
TestAssert::IsTrue(punk2 != nullptr, L"");
TestAssert::IsTrue(punk3 != nullptr, L"");
TestAssert::IsTrue(punk4 != nullptr, L"");
TestAssert::IsTrue(punk5 != nullptr, L"");
punk1 = punk2;
TestAssert::IsTrue(punk1->m_cRef == 2, L"");
TestAssert::IsTrue(punk2->m_cRef == 2, L"");
punk1 = punk4;
TestAssert::IsTrue(punk1->m_cRef == 3, L"");
TestAssert::IsTrue(punk2->m_cRef == 1, L"");
TestAssert::IsTrue(punk4->m_cRef == 3, L"");
punk1 = NULL;
punk1.Swap(punk3);
punk3.Swap(punk5);
punk5.Swap(punk1);
punk3.Swap(punk5);
punk1.Transfer(punk2);
punk2.Transfer(punk1);
punk1.Place(punk2.Detach());
punk2.Place(punk1.Detach());
punk1.Attach(punk2.Detach());
punk2.Attach(punk1.Detach());
TestAssert::IsTrue(punk1 == nullptr, L"");
TestAssert::IsTrue(punk2 != nullptr, L"");
TestAssert::IsTrue(punk2->m_cRef == 1, L"");
TestAssert::IsTrue(punk3 != nullptr, L"");
TestAssert::IsTrue(punk3->m_cRef == 2, L"");
TestAssert::IsTrue(punk4 != nullptr, L"");
TestAssert::IsTrue(punk4->m_cRef == 2, L"");
TestAssert::IsTrue(punk3 == punk4, L"");
TestAssert::IsTrue(punk5 != nullptr, L"");
TestAssert::IsTrue(punk5->m_cRef == 1, L"");
}
/*------------------------------------------------------------------------------
%%Id: 5938c5b2-5d47-40a6-bd0a-903a7e126059
------------------------------------------------------------------------------*/
TEST_METHOD(CntPtrMixed)
{
Mso::TCntPtr<IUnknown> punk;
Mso::TCntPtr<ICustom> pistm;
TestAssert::IsTrue(pistm == nullptr, L"");
TestAssert::IsTrue(punk == nullptr, L"");
punk = pistm;
punk = &*pistm;
punk = *pistm.GetRaw();
punk = pistm.Copy();
*punk.Address() = pistm.Copy();
*punk.GetRaw() = pistm.Copy();
pistm = static_cast<ICustom*>(static_cast<IUnknown*>(punk));
pistm = static_cast<ICustom*>(&*punk);
pistm = static_cast<ICustom*>(*punk.GetRaw());
}
/*------------------------------------------------------------------------------
%%Id: b32deb10-ad98-452e-a307-8eb5d212429e
%%Id: b32deb10-ad98-452e-a307-8eb5d212429e
------------------------------------------------------------------------------*/
#ifdef MS_TARGET_WINDOWS
TEST_METHOD(CntQIPtrCore)
{
Mso::TCntPtr<IUnknown> punk1(new CUnknown());
Mso::TCntPtr<IUnknown> punk2(new CUnknown());
Mso::TCntPtr<IStream> pistmQI;
TestAssert::IsTrue(FAILED(Mso::ComUtil::HrQueryFrom(pistmQI, punk1)), L"");
TestAssert::IsTrue(SUCCEEDED(CreateStreamOnHGlobal(NULL, TRUE, &pistmQI)), L"");
punk1 = pistmQI;
TestAssert::IsTrue(Mso::ComUtil::AreEqualObjects(pistmQI, punk1), L"");
pistmQI.Empty();
TestAssert::AreEqual(S_OK, Mso::ComUtil::HrQueryFrom(pistmQI, punk1));
TestAssert::IsTrue(Mso::ComUtil::AreEqualObjects(pistmQI, punk1), L"");
}
TEST_METHOD(CntQIPtrCore)
{
Mso::TCntPtr<IUnknown> punk1(new CUnknown());
Mso::TCntPtr<IUnknown> punk2(new CUnknown());
Mso::TCntPtr<IStream> pistmQI;
TestAssert::IsTrue(FAILED(Mso::ComUtil::HrQueryFrom(pistmQI, punk1)), L"");
TestAssert::IsTrue(SUCCEEDED(CreateStreamOnHGlobal(NULL, TRUE, &pistmQI)), L"");
punk1 = pistmQI;
TestAssert::IsTrue(Mso::ComUtil::AreEqualObjects(pistmQI, punk1), L"");
pistmQI.Empty();
TestAssert::AreEqual(S_OK, Mso::ComUtil::HrQueryFrom(pistmQI, punk1));
TestAssert::IsTrue(Mso::ComUtil::AreEqualObjects(pistmQI, punk1), L"");
}
#endif
TEST_METHOD(TCleanup)
// Use TCleanup to increment the variable.
{
int i = 0;
{
auto cuIncrement = Mso::TCleanup::Make([&]() noexcept { ++i; });
TestAssert::AreEqual(0, i, L"");
}
TestAssert::AreEqual(1, i, L"");
}
TEST_METHOD(TCleanup)
// Use TCleanup to increment the variable.
{
int i = 0;
{
auto cuIncrement = Mso::TCleanup::Make([&]() noexcept { ++i; });
TestAssert::AreEqual(0, i, L"");
}
TestAssert::AreEqual(1, i, L"");
}
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -12,127 +12,114 @@ Unit tests for classes in the ObjectRefCount.h
#include "testAllocators.h"
#include <test/testCheck.h>
class ObjectRefCountSample1 final
: public Mso::RefCountedObjectNoVTable<ObjectRefCountSample1>
class ObjectRefCountSample1 final : public Mso::RefCountedObjectNoVTable<ObjectRefCountSample1>
{
public:
int Value() const noexcept
{
return m_value;
}
int Value() const noexcept
{
return m_value;
}
private:
ObjectRefCountSample1(int value, bool& deleted) noexcept
: m_value(value)
, m_deleted(deleted)
{
}
ObjectRefCountSample1(int value, bool& deleted) noexcept : m_value(value), m_deleted(deleted) {}
~ObjectRefCountSample1() noexcept
{
m_deleted = true;
}
~ObjectRefCountSample1() noexcept
{
m_deleted = true;
}
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
private:
int m_value;
bool& m_deleted;
int m_value;
bool& m_deleted;
};
class ObjectRefCountSample2Init final
: public Mso::RefCountedObjectNoVTable<ObjectRefCountSample2Init>
class ObjectRefCountSample2Init final : public Mso::RefCountedObjectNoVTable<ObjectRefCountSample2Init>
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
int Value() const noexcept
{
return m_value;
}
int Value() const noexcept
{
return m_value;
}
private:
void InitializeThis(int value, bool& deleted) noexcept
{
m_value = value;
m_deleted = &deleted;
}
void InitializeThis(int value, bool& deleted) noexcept
{
m_value = value;
m_deleted = &deleted;
}
ObjectRefCountSample2Init() noexcept = default;
ObjectRefCountSample2Init() noexcept = default;
~ObjectRefCountSample2Init() noexcept
{
*m_deleted = true;
}
~ObjectRefCountSample2Init() noexcept
{
*m_deleted = true;
}
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
private:
int m_value;
bool* m_deleted;
int m_value;
bool* m_deleted;
};
class ObjectRefCountSample3CannotAllocate final
: public Mso::RefCountedObjectNoVTable<BadAllocSimpleRefCount, ObjectRefCountSample3CannotAllocate>
: public Mso::RefCountedObjectNoVTable<BadAllocSimpleRefCount, ObjectRefCountSample3CannotAllocate>
{
};
class ObjectRefCountSample4Throw final
: public Mso::RefCountedObjectNoVTable<ObjectRefCountSample4Throw>
class ObjectRefCountSample4Throw final : public Mso::RefCountedObjectNoVTable<ObjectRefCountSample4Throw>
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtor;
using MakePolicy = Mso::MakePolicy::ThrowCtor;
private:
ObjectRefCountSample4Throw(bool& deleted)
: m_deleted(deleted)
{
throw std::runtime_error("Test");
}
ObjectRefCountSample4Throw(bool& deleted) : m_deleted(deleted)
{
throw std::runtime_error("Test");
}
~ObjectRefCountSample4Throw() noexcept
{
m_deleted = true;
}
~ObjectRefCountSample4Throw() noexcept
{
m_deleted = true;
}
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
private:
bool& m_deleted;
bool& m_deleted;
};
class ObjectRefCountSample5InitThrow final
: public Mso::RefCountedObjectNoVTable<ObjectRefCountSample5InitThrow>
class ObjectRefCountSample5InitThrow final : public Mso::RefCountedObjectNoVTable<ObjectRefCountSample5InitThrow>
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
private:
void InitializeThis(bool& deleted)
{
m_deleted = &deleted;
throw std::runtime_error("Test");
}
void InitializeThis(bool& deleted)
{
m_deleted = &deleted;
throw std::runtime_error("Test");
}
ObjectRefCountSample5InitThrow() noexcept = default;
ObjectRefCountSample5InitThrow() noexcept = default;
~ObjectRefCountSample5InitThrow() noexcept
{
*m_deleted = true;
}
~ObjectRefCountSample5InitThrow() noexcept
{
*m_deleted = true;
}
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
private:
bool* m_deleted { nullptr };
bool* m_deleted{nullptr};
};
//=============================================================================
@ -140,397 +127,372 @@ private:
//=============================================================================
class ObjectRefCountSample11 final
: public Mso::RefCountedObjectNoVTable<StatefulAllocSimpleRefCount, ObjectRefCountSample11>
: public Mso::RefCountedObjectNoVTable<StatefulAllocSimpleRefCount, ObjectRefCountSample11>
{
public:
int Value() const noexcept
{
return m_value;
}
int Value() const noexcept
{
return m_value;
}
private:
ObjectRefCountSample11(int value, bool& deleted) noexcept
: m_value(value)
, m_deleted(deleted)
{
}
ObjectRefCountSample11(int value, bool& deleted) noexcept : m_value(value), m_deleted(deleted) {}
~ObjectRefCountSample11() noexcept
{
m_deleted = true;
}
~ObjectRefCountSample11() noexcept
{
m_deleted = true;
}
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
private:
int m_value;
bool& m_deleted;
int m_value;
bool& m_deleted;
};
class ObjectRefCountSample21Init final
: public Mso::RefCountedObjectNoVTable<StatefulAllocSimpleRefCount, ObjectRefCountSample21Init>
: public Mso::RefCountedObjectNoVTable<StatefulAllocSimpleRefCount, ObjectRefCountSample21Init>
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
int Value() const noexcept
{
return m_value;
}
int Value() const noexcept
{
return m_value;
}
private:
void InitializeThis(int value, bool& deleted) noexcept
{
m_value = value;
m_deleted = &deleted;
}
void InitializeThis(int value, bool& deleted) noexcept
{
m_value = value;
m_deleted = &deleted;
}
ObjectRefCountSample21Init() noexcept = default;
ObjectRefCountSample21Init() noexcept = default;
~ObjectRefCountSample21Init() noexcept
{
*m_deleted = true;
}
~ObjectRefCountSample21Init() noexcept
{
*m_deleted = true;
}
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
private:
int m_value;
bool* m_deleted;
int m_value;
bool* m_deleted;
};
class ObjectRefCountSample31CannotAllocate final
: public Mso::RefCountedObjectNoVTable<BadStatefulAllocSimpleRefCount, ObjectRefCountSample31CannotAllocate>
: public Mso::RefCountedObjectNoVTable<BadStatefulAllocSimpleRefCount, ObjectRefCountSample31CannotAllocate>
{
};
class ObjectRefCountSample41Throw final
: public Mso::RefCountedObjectNoVTable<StatefulAllocSimpleRefCount, ObjectRefCountSample41Throw>
: public Mso::RefCountedObjectNoVTable<StatefulAllocSimpleRefCount, ObjectRefCountSample41Throw>
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtor;
using MakePolicy = Mso::MakePolicy::ThrowCtor;
private:
ObjectRefCountSample41Throw(bool& deleted)
: m_deleted(deleted)
{
throw std::runtime_error("Test");
}
ObjectRefCountSample41Throw(bool& deleted) : m_deleted(deleted)
{
throw std::runtime_error("Test");
}
~ObjectRefCountSample41Throw() noexcept
{
m_deleted = true;
}
~ObjectRefCountSample41Throw() noexcept
{
m_deleted = true;
}
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
private:
bool& m_deleted;
bool& m_deleted;
};
class ObjectRefCountSample51InitThrow final
: public Mso::RefCountedObjectNoVTable<StatefulAllocSimpleRefCount, ObjectRefCountSample51InitThrow>
: public Mso::RefCountedObjectNoVTable<StatefulAllocSimpleRefCount, ObjectRefCountSample51InitThrow>
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
private:
void InitializeThis(bool& deleted)
{
m_deleted = &deleted;
throw std::runtime_error("Test");
}
void InitializeThis(bool& deleted)
{
m_deleted = &deleted;
throw std::runtime_error("Test");
}
ObjectRefCountSample51InitThrow() noexcept = default;
ObjectRefCountSample51InitThrow() noexcept = default;
~ObjectRefCountSample51InitThrow() noexcept
{
*m_deleted = true;
}
~ObjectRefCountSample51InitThrow() noexcept
{
*m_deleted = true;
}
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
private:
bool* m_deleted { nullptr };
bool* m_deleted{nullptr};
};
TEST_CLASS(ObjectRefCountTest)
TEST_CLASS (ObjectRefCountTest)
{
TEST_METHOD(ObjectRefCount_Make)
{
TestAssert::AreEqual(sizeof(uint32_t), sizeof(Mso::RefCountedObjectNoVTable<ObjectRefCountSample1>));
TEST_METHOD(ObjectRefCount_Make)
{
TestAssert::AreEqual(sizeof(uint32_t), sizeof(Mso::RefCountedObjectNoVTable<ObjectRefCountSample1>));
bool deleted = false;
{
Mso::TCntPtr<ObjectRefCountSample1> obj1 = Mso::Make<ObjectRefCountSample1>(5, /*ref*/deleted);
{
Debug(TestAssert::AreEqual(1u, obj1->RefCount()));
TestAssert::AreEqual(5, obj1->Value());
bool deleted = false;
{
Mso::TCntPtr<ObjectRefCountSample1> obj1 = Mso::Make<ObjectRefCountSample1>(5, /*ref*/ deleted);
{
Debug(TestAssert::AreEqual(1u, obj1->RefCount()));
TestAssert::AreEqual(5, obj1->Value());
Mso::TCntPtr<ObjectRefCountSample1> obj2(obj1);
Debug(TestAssert::AreEqual(2u, obj1->RefCount()));
TestAssert::IsNotNull(obj2.Get());
TestAssert::IsTrue(obj1.Get() == obj2.Get());
}
Debug(TestAssert::AreEqual(1u, obj1->RefCount()));
}
Mso::TCntPtr<ObjectRefCountSample1> obj2(obj1);
Debug(TestAssert::AreEqual(2u, obj1->RefCount()));
TestAssert::IsNotNull(obj2.Get());
TestAssert::IsTrue(obj1.Get() == obj2.Get());
}
Debug(TestAssert::AreEqual(1u, obj1->RefCount()));
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectRefCount_Make_InitializeThis)
{
bool deleted = false;
{
auto obj = Mso::Make<ObjectRefCountSample2Init>(5, /*ref*/deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectRefCount_Make_InitializeThis)
{
bool deleted = false;
{
auto obj = Mso::Make<ObjectRefCountSample2Init>(5, /*ref*/ deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectRefCount_Make_CannotAllocate)
{
Mso::TCntPtr<ObjectRefCountSample3CannotAllocate> obj;
TestAssert::ExpectVEC([&]() noexcept
{
obj = Mso::Make<ObjectRefCountSample3CannotAllocate>();
});
TEST_METHOD(ObjectRefCount_Make_CannotAllocate)
{
Mso::TCntPtr<ObjectRefCountSample3CannotAllocate> obj;
TestAssert::ExpectVEC([&]() noexcept { obj = Mso::Make<ObjectRefCountSample3CannotAllocate>(); });
TestAssert::IsTrue(obj.IsEmpty());
}
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectRefCount_Make_CtorThrows)
{
Mso::TCntPtr<ObjectRefCountSample4Throw> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>([&]()
{
obj = Mso::Make<ObjectRefCountSample4Throw>(/*ref*/deleted);
});
TEST_METHOD(ObjectRefCount_Make_CtorThrows)
{
Mso::TCntPtr<ObjectRefCountSample4Throw> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>(
[&]() { obj = Mso::Make<ObjectRefCountSample4Throw>(/*ref*/ deleted); });
TestAssert::IsFalse(deleted); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
TestAssert::IsFalse(deleted); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectRefCount_Make_InitializeThisThrows)
{
Mso::TCntPtr<ObjectRefCountSample5InitThrow> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>([&]()
{
obj = Mso::Make<ObjectRefCountSample5InitThrow>(/*ref*/deleted);
});
TEST_METHOD(ObjectRefCount_Make_InitializeThisThrows)
{
Mso::TCntPtr<ObjectRefCountSample5InitThrow> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>(
[&]() { obj = Mso::Make<ObjectRefCountSample5InitThrow>(/*ref*/ deleted); });
TestAssert::IsTrue(deleted); // If InitializeThis throws then destructor must be called.
TestAssert::IsTrue(obj.IsEmpty());
}
TestAssert::IsTrue(deleted); // If InitializeThis throws then destructor must be called.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectRefCount_MakeElseNull)
{
bool deleted = false;
{
auto obj = Mso::MakeElseNull<ObjectRefCountSample1>(5, /*ref*/deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectRefCount_MakeElseNull)
{
bool deleted = false;
{
auto obj = Mso::MakeElseNull<ObjectRefCountSample1>(5, /*ref*/ deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectRefCount_MakeElseNull_InitializeThis)
{
bool deleted = false;
{
auto obj = Mso::MakeElseNull<ObjectRefCountSample2Init>(5, /*ref*/deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectRefCount_MakeElseNull_InitializeThis)
{
bool deleted = false;
{
auto obj = Mso::MakeElseNull<ObjectRefCountSample2Init>(5, /*ref*/ deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectRefCount_MakeElseNull_CannotAllocate)
{
auto obj = Mso::MakeElseNull<ObjectRefCountSample3CannotAllocate>();
TestAssert::IsNull(obj.Get());
}
TEST_METHOD(ObjectRefCount_MakeElseNull_CannotAllocate)
{
auto obj = Mso::MakeElseNull<ObjectRefCountSample3CannotAllocate>();
TestAssert::IsNull(obj.Get());
}
TEST_METHOD(ObjectRefCount_MakeElseNull_CtorThrows)
{
Mso::TCntPtr<ObjectRefCountSample4Throw> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>([&]()
{
obj = Mso::MakeElseNull<ObjectRefCountSample4Throw>(/*ref*/deleted);
});
TEST_METHOD(ObjectRefCount_MakeElseNull_CtorThrows)
{
Mso::TCntPtr<ObjectRefCountSample4Throw> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>(
[&]() { obj = Mso::MakeElseNull<ObjectRefCountSample4Throw>(/*ref*/ deleted); });
TestAssert::IsFalse(deleted); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
TestAssert::IsFalse(deleted); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectRefCount_MakeElseNull_InitializeThisThrows)
{
Mso::TCntPtr<ObjectRefCountSample5InitThrow> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>([&]()
{
obj = Mso::MakeElseNull<ObjectRefCountSample5InitThrow>(/*ref*/deleted);
});
TEST_METHOD(ObjectRefCount_MakeElseNull_InitializeThisThrows)
{
Mso::TCntPtr<ObjectRefCountSample5InitThrow> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>(
[&]() { obj = Mso::MakeElseNull<ObjectRefCountSample5InitThrow>(/*ref*/ deleted); });
TestAssert::IsTrue(deleted); // If InitializeThis throws then we must call destructor.
TestAssert::IsTrue(obj.IsEmpty());
}
TestAssert::IsTrue(deleted); // If InitializeThis throws then we must call destructor.
TestAssert::IsTrue(obj.IsEmpty());
}
struct AllocTestState
{
bool AllocCalled;
bool FreeCalled;
bool Deleted;
};
struct AllocTestState
{
bool AllocCalled;
bool FreeCalled;
bool Deleted;
};
static void AssertAllocState(const AllocTestState& state, bool deleted = true) noexcept
{
TestAssert::IsTrue(state.AllocCalled, L"Allocate expected to be called");
TestAssert::IsTrue(state.FreeCalled, L"Deallocate expected to be called");
TestAssert::AreEqual(deleted, state.Deleted, L"Destructor to be called");
}
static void AssertAllocState(const AllocTestState& state, bool deleted = true) noexcept
{
TestAssert::IsTrue(state.AllocCalled, L"Allocate expected to be called");
TestAssert::IsTrue(state.FreeCalled, L"Deallocate expected to be called");
TestAssert::AreEqual(deleted, state.Deleted, L"Destructor to be called");
}
TEST_METHOD(ObjectRefCount_MakeAlloc)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
auto obj = Mso::MakeAlloc<ObjectRefCountSample11>(&memHeap, 5, /*ref*/state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectRefCount_MakeAlloc)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
auto obj = Mso::MakeAlloc<ObjectRefCountSample11>(&memHeap, 5, /*ref*/ state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
AssertAllocState(state);
}
AssertAllocState(state);
}
TEST_METHOD(ObjectRefCount_MakeAlloc_InitializeThis)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
auto obj = Mso::MakeAlloc<ObjectRefCountSample21Init>(&memHeap, 5, /*ref*/state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectRefCount_MakeAlloc_InitializeThis)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
auto obj = Mso::MakeAlloc<ObjectRefCountSample21Init>(&memHeap, 5, /*ref*/ state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
AssertAllocState(state);
}
AssertAllocState(state);
}
TEST_METHOD(ObjectRefCount_MakeAlloc_CannotAllocate)
{
Mso::TCntPtr<ObjectRefCountSample31CannotAllocate> obj;
TestAssert::ExpectVEC([&]() noexcept
{
AllocTestState state = {};
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
obj = Mso::MakeAlloc<ObjectRefCountSample31CannotAllocate>(&memHeap);
});
TEST_METHOD(ObjectRefCount_MakeAlloc_CannotAllocate)
{
Mso::TCntPtr<ObjectRefCountSample31CannotAllocate> obj;
TestAssert::ExpectVEC([&]() noexcept {
AllocTestState state = {};
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
obj = Mso::MakeAlloc<ObjectRefCountSample31CannotAllocate>(&memHeap);
});
TestAssert::IsTrue(obj.IsEmpty());
}
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectRefCount_MakeAlloc_CtorThrows)
{
Mso::TCntPtr<ObjectRefCountSample41Throw> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]()
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
obj = Mso::MakeAlloc<ObjectRefCountSample41Throw>(&memHeap, /*ref*/state.Deleted);
});
TEST_METHOD(ObjectRefCount_MakeAlloc_CtorThrows)
{
Mso::TCntPtr<ObjectRefCountSample41Throw> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]() {
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
obj = Mso::MakeAlloc<ObjectRefCountSample41Throw>(&memHeap, /*ref*/ state.Deleted);
});
AssertAllocState(state, /*deleted:*/false); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
AssertAllocState(state, /*deleted:*/ false); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectRefCount_MakeAlloc_InitializeThisThrows)
{
Mso::TCntPtr<ObjectRefCountSample51InitThrow> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]()
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
obj = Mso::MakeAlloc<ObjectRefCountSample51InitThrow>(&memHeap, /*ref*/state.Deleted);
});
TEST_METHOD(ObjectRefCount_MakeAlloc_InitializeThisThrows)
{
Mso::TCntPtr<ObjectRefCountSample51InitThrow> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]() {
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
obj = Mso::MakeAlloc<ObjectRefCountSample51InitThrow>(&memHeap, /*ref*/ state.Deleted);
});
AssertAllocState(state); // If InitializeThis throws then destructor must be called.
TestAssert::IsTrue(obj.IsEmpty());
}
AssertAllocState(state); // If InitializeThis throws then destructor must be called.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectRefCount_MakeAllocElseNull)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectRefCountSample11>(&memHeap, 5, /*ref*/state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectRefCount_MakeAllocElseNull)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectRefCountSample11>(&memHeap, 5, /*ref*/ state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
AssertAllocState(state);
}
AssertAllocState(state);
}
TEST_METHOD(ObjectRefCount_MakeAllocElseNull_InitializeThis)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectRefCountSample21Init>(&memHeap, 5, /*ref*/state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectRefCount_MakeAllocElseNull_InitializeThis)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectRefCountSample21Init>(&memHeap, 5, /*ref*/ state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
AssertAllocState(state);
}
AssertAllocState(state);
}
TEST_METHOD(ObjectRefCount_MakeAllocElseNull_CannotAllocate)
{
AllocTestState state = {};
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectRefCountSample31CannotAllocate>(&memHeap);
TestAssert::IsNull(obj.Get());
}
TEST_METHOD(ObjectRefCount_MakeAllocElseNull_CannotAllocate)
{
AllocTestState state = {};
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectRefCountSample31CannotAllocate>(&memHeap);
TestAssert::IsNull(obj.Get());
}
TEST_METHOD(ObjectRefCount_MakeAllocElseNull_CtorThrows)
{
Mso::TCntPtr<ObjectRefCountSample41Throw> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]()
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
obj = Mso::MakeAllocElseNull<ObjectRefCountSample41Throw>(&memHeap, /*ref*/state.Deleted);
});
TEST_METHOD(ObjectRefCount_MakeAllocElseNull_CtorThrows)
{
Mso::TCntPtr<ObjectRefCountSample41Throw> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]() {
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
obj = Mso::MakeAllocElseNull<ObjectRefCountSample41Throw>(&memHeap, /*ref*/ state.Deleted);
});
AssertAllocState(state, /*deleted:*/false); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
AssertAllocState(state, /*deleted:*/ false); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectRefCount_MakeAllocElseNull_InitializeThisThrows)
{
Mso::TCntPtr<ObjectRefCountSample51InitThrow> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]()
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
obj = Mso::MakeAllocElseNull<ObjectRefCountSample51InitThrow>(&memHeap, /*ref*/state.Deleted);
});
TEST_METHOD(ObjectRefCount_MakeAllocElseNull_InitializeThisThrows)
{
Mso::TCntPtr<ObjectRefCountSample51InitThrow> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]() {
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
obj = Mso::MakeAllocElseNull<ObjectRefCountSample51InitThrow>(&memHeap, /*ref*/ state.Deleted);
});
AssertAllocState(state); // If InitializeThis throws then we must call destructor.
TestAssert::IsTrue(obj.IsEmpty());
}
AssertAllocState(state); // If InitializeThis throws then we must call destructor.
TestAssert::IsTrue(obj.IsEmpty());
}
};

Просмотреть файл

@ -12,570 +12,534 @@ Unit tests for classes in the ObjectRefCount.h
#include <test/testCheck.h>
class ObjectWithWeakRefSample1 final
: public Mso::RefCountedObjectNoVTable<Mso::RefCountStrategy::WeakRef, ObjectWithWeakRefSample1>
: public Mso::RefCountedObjectNoVTable<Mso::RefCountStrategy::WeakRef, ObjectWithWeakRefSample1>
{
public:
int Value() const noexcept
{
return m_value;
}
int Value() const noexcept
{
return m_value;
}
private:
ObjectWithWeakRefSample1(int value, bool& deleted) noexcept
: m_value(value)
, m_deleted(deleted)
{
}
ObjectWithWeakRefSample1(int value, bool& deleted) noexcept : m_value(value), m_deleted(deleted) {}
~ObjectWithWeakRefSample1() noexcept
{
m_deleted = true;
}
~ObjectWithWeakRefSample1() noexcept
{
m_deleted = true;
}
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
private:
int m_value;
bool& m_deleted;
int m_value;
bool& m_deleted;
};
class ObjectWithWeakRefSample2Init final
: public Mso::RefCountedObjectNoVTable<Mso::RefCountStrategy::WeakRef, ObjectWithWeakRefSample2Init>
: public Mso::RefCountedObjectNoVTable<Mso::RefCountStrategy::WeakRef, ObjectWithWeakRefSample2Init>
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
int Value() const noexcept
{
return m_value;
}
int Value() const noexcept
{
return m_value;
}
private:
void InitializeThis(int value, bool& deleted) noexcept
{
m_value = value;
m_deleted = &deleted;
}
void InitializeThis(int value, bool& deleted) noexcept
{
m_value = value;
m_deleted = &deleted;
}
ObjectWithWeakRefSample2Init() noexcept = default;
ObjectWithWeakRefSample2Init() noexcept = default;
~ObjectWithWeakRefSample2Init() noexcept
{
*m_deleted = true;
}
~ObjectWithWeakRefSample2Init() noexcept
{
*m_deleted = true;
}
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
private:
int m_value;
bool* m_deleted;
int m_value;
bool* m_deleted;
};
class ObjectWithWeakRefSample3CannotAllocate final
: public Mso::RefCountedObjectNoVTable<BadAllocWeakRefCount, ObjectWithWeakRefSample3CannotAllocate>
: public Mso::RefCountedObjectNoVTable<BadAllocWeakRefCount, ObjectWithWeakRefSample3CannotAllocate>
{
};
class ObjectWithWeakRefSample4Throw final
: public Mso::RefCountedObjectNoVTable<Mso::RefCountStrategy::WeakRef, ObjectWithWeakRefSample4Throw>
: public Mso::RefCountedObjectNoVTable<Mso::RefCountStrategy::WeakRef, ObjectWithWeakRefSample4Throw>
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtor;
using MakePolicy = Mso::MakePolicy::ThrowCtor;
private:
ObjectWithWeakRefSample4Throw(bool& deleted)
: m_deleted(deleted)
{
throw std::runtime_error("Test");
}
ObjectWithWeakRefSample4Throw(bool& deleted) : m_deleted(deleted)
{
throw std::runtime_error("Test");
}
~ObjectWithWeakRefSample4Throw() noexcept
{
m_deleted = true;
}
~ObjectWithWeakRefSample4Throw() noexcept
{
m_deleted = true;
}
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
private:
bool& m_deleted;
bool& m_deleted;
};
class ObjectWithWeakRefSample5InitThrow final
: public Mso::RefCountedObjectNoVTable<Mso::RefCountStrategy::WeakRef, ObjectWithWeakRefSample5InitThrow>
: public Mso::RefCountedObjectNoVTable<Mso::RefCountStrategy::WeakRef, ObjectWithWeakRefSample5InitThrow>
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
private:
void InitializeThis(bool& deleted)
{
m_deleted = &deleted;
throw std::runtime_error("Test");
}
void InitializeThis(bool& deleted)
{
m_deleted = &deleted;
throw std::runtime_error("Test");
}
ObjectWithWeakRefSample5InitThrow() noexcept = default;
ObjectWithWeakRefSample5InitThrow() noexcept = default;
~ObjectWithWeakRefSample5InitThrow() noexcept
{
*m_deleted = true;
}
~ObjectWithWeakRefSample5InitThrow() noexcept
{
*m_deleted = true;
}
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
private:
bool* m_deleted { nullptr };
bool* m_deleted{nullptr};
};
//=============================================================================
// Classes below use stateful allocator
//=============================================================================
class ObjectWithWeakRefSample11 final
: public Mso::RefCountedObjectNoVTable<StatefulAllocWeakRefCount, ObjectWithWeakRefSample11>
: public Mso::RefCountedObjectNoVTable<StatefulAllocWeakRefCount, ObjectWithWeakRefSample11>
{
public:
int Value() const noexcept
{
return m_value;
}
int Value() const noexcept
{
return m_value;
}
private:
ObjectWithWeakRefSample11(int value, bool& deleted) noexcept
: m_value(value)
, m_deleted(deleted)
{
}
ObjectWithWeakRefSample11(int value, bool& deleted) noexcept : m_value(value), m_deleted(deleted) {}
~ObjectWithWeakRefSample11() noexcept
{
m_deleted = true;
}
~ObjectWithWeakRefSample11() noexcept
{
m_deleted = true;
}
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
private:
int m_value;
bool& m_deleted;
int m_value;
bool& m_deleted;
};
class ObjectWithWeakRefSample21Init final
: public Mso::RefCountedObjectNoVTable<StatefulAllocWeakRefCount, ObjectWithWeakRefSample21Init>
: public Mso::RefCountedObjectNoVTable<StatefulAllocWeakRefCount, ObjectWithWeakRefSample21Init>
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
int Value() const noexcept
{
return m_value;
}
int Value() const noexcept
{
return m_value;
}
private:
void InitializeThis(int value, bool& deleted) noexcept
{
m_value = value;
m_deleted = &deleted;
}
void InitializeThis(int value, bool& deleted) noexcept
{
m_value = value;
m_deleted = &deleted;
}
ObjectWithWeakRefSample21Init() noexcept = default;
ObjectWithWeakRefSample21Init() noexcept = default;
~ObjectWithWeakRefSample21Init() noexcept
{
*m_deleted = true;
}
~ObjectWithWeakRefSample21Init() noexcept
{
*m_deleted = true;
}
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
private:
int m_value;
bool* m_deleted;
int m_value;
bool* m_deleted;
};
class ObjectWithWeakRefSample31CannotAllocate final
: public Mso::RefCountedObjectNoVTable<BadStatefulAllocWeakRefCount, ObjectWithWeakRefSample31CannotAllocate>
: public Mso::RefCountedObjectNoVTable<BadStatefulAllocWeakRefCount, ObjectWithWeakRefSample31CannotAllocate>
{
};
class ObjectWithWeakRefSample41Throw final
: public Mso::RefCountedObjectNoVTable<StatefulAllocWeakRefCount, ObjectWithWeakRefSample41Throw>
: public Mso::RefCountedObjectNoVTable<StatefulAllocWeakRefCount, ObjectWithWeakRefSample41Throw>
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtor;
using MakePolicy = Mso::MakePolicy::ThrowCtor;
private:
ObjectWithWeakRefSample41Throw(bool& deleted)
: m_deleted(deleted)
{
throw std::runtime_error("Test");
}
ObjectWithWeakRefSample41Throw(bool& deleted) : m_deleted(deleted)
{
throw std::runtime_error("Test");
}
~ObjectWithWeakRefSample41Throw() noexcept
{
m_deleted = true;
}
~ObjectWithWeakRefSample41Throw() noexcept
{
m_deleted = true;
}
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor
friend RefCountPolicy; // To support private destructor
private:
bool& m_deleted;
bool& m_deleted;
};
class ObjectWithWeakRefSample51InitThrow final
: public Mso::RefCountedObjectNoVTable<StatefulAllocWeakRefCount, ObjectWithWeakRefSample51InitThrow>
: public Mso::RefCountedObjectNoVTable<StatefulAllocWeakRefCount, ObjectWithWeakRefSample51InitThrow>
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
private:
void InitializeThis(bool& deleted)
{
m_deleted = &deleted;
throw std::runtime_error("Test");
}
void InitializeThis(bool& deleted)
{
m_deleted = &deleted;
throw std::runtime_error("Test");
}
ObjectWithWeakRefSample51InitThrow() noexcept = default;
ObjectWithWeakRefSample51InitThrow() noexcept = default;
~ObjectWithWeakRefSample51InitThrow() noexcept
{
*m_deleted = true;
}
~ObjectWithWeakRefSample51InitThrow() noexcept
{
*m_deleted = true;
}
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
friend MakePolicy; // To support private constructor & InitializeThis
friend RefCountPolicy; // To support private destructor
private:
bool* m_deleted { nullptr };
bool* m_deleted{nullptr};
};
TEST_CLASS(ObjectWithWeakRefTest)
TEST_CLASS (ObjectWithWeakRefTest)
{
TEST_METHOD(ObjectWithWeakRef_Make)
{
bool deleted = false;
{
Mso::TCntPtr<ObjectWithWeakRefSample1> obj1 = Mso::Make<ObjectWithWeakRefSample1>(5, /*ref*/deleted);
{
Debug(TestAssert::AreEqual(1u, obj1->GetWeakRef().RefCount()));
TestAssert::AreEqual(5, obj1->Value());
TEST_METHOD(ObjectWithWeakRef_Make)
{
bool deleted = false;
{
Mso::TCntPtr<ObjectWithWeakRefSample1> obj1 = Mso::Make<ObjectWithWeakRefSample1>(5, /*ref*/ deleted);
{
Debug(TestAssert::AreEqual(1u, obj1->GetWeakRef().RefCount()));
TestAssert::AreEqual(5, obj1->Value());
Mso::TCntPtr<ObjectWithWeakRefSample1> obj2(obj1);
Debug(TestAssert::AreEqual(2u, obj1->GetWeakRef().RefCount()));
TestAssert::IsNotNull(obj2.Get());
TestAssert::IsTrue(obj1.Get() == obj2.Get());
}
Mso::TCntPtr<ObjectWithWeakRefSample1> obj2(obj1);
Debug(TestAssert::AreEqual(2u, obj1->GetWeakRef().RefCount()));
TestAssert::IsNotNull(obj2.Get());
TestAssert::IsTrue(obj1.Get() == obj2.Get());
}
Debug(TestAssert::AreEqual(1u, obj1->GetWeakRef().RefCount()));
}
Debug(TestAssert::AreEqual(1u, obj1->GetWeakRef().RefCount()));
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectWithWeakRef_WeakRef)
{
// Ref count for ObjectWeakRef behaves the same way as for the object.
bool deleted = false;
{
Mso::TCntPtr<ObjectWithWeakRefSample1> obj1 = Mso::Make<ObjectWithWeakRefSample1>(5, /*ref*/deleted);
Mso::TCntPtr<Mso::ObjectWeakRef> weakRef = &obj1->GetWeakRef();
{
Debug(TestAssert::AreEqual(2u, weakRef->RefCount()));
Debug(TestAssert::AreEqual(1u, weakRef->WeakRefCount()));
TEST_METHOD(ObjectWithWeakRef_WeakRef)
{
// Ref count for ObjectWeakRef behaves the same way as for the object.
bool deleted = false;
{
Mso::TCntPtr<ObjectWithWeakRefSample1> obj1 = Mso::Make<ObjectWithWeakRefSample1>(5, /*ref*/ deleted);
Mso::TCntPtr<Mso::ObjectWeakRef> weakRef = &obj1->GetWeakRef();
{
Debug(TestAssert::AreEqual(2u, weakRef->RefCount()));
Debug(TestAssert::AreEqual(1u, weakRef->WeakRefCount()));
Mso::TCntPtr<ObjectWithWeakRefSample1> obj2(obj1);
Debug(TestAssert::AreEqual(3u, weakRef->RefCount()));
}
Mso::TCntPtr<ObjectWithWeakRefSample1> obj2(obj1);
Debug(TestAssert::AreEqual(3u, weakRef->RefCount()));
}
Debug(TestAssert::AreEqual(2u, weakRef->RefCount()));
TestAssert::IsFalse(deleted);
TestAssert::IsFalse(weakRef->IsExpired());
}
Debug(TestAssert::AreEqual(2u, weakRef->RefCount()));
TestAssert::IsFalse(deleted);
TestAssert::IsFalse(weakRef->IsExpired());
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectWithWeakRef_WeakPtr)
{
bool deleted = false;
Mso::WeakPtr<ObjectWithWeakRefSample1> weakPtr;
{
Mso::TCntPtr<ObjectWithWeakRefSample1> obj1 = Mso::Make<ObjectWithWeakRefSample1>(5, /*ref*/deleted);
Mso::TCntPtr<Mso::ObjectWeakRef> weakRef = &obj1->GetWeakRef();
weakPtr = obj1;
{
Debug(TestAssert::AreEqual(2u, weakRef->RefCount()));
Debug(TestAssert::AreEqual(2u, weakRef->WeakRefCount()));
TEST_METHOD(ObjectWithWeakRef_WeakPtr)
{
bool deleted = false;
Mso::WeakPtr<ObjectWithWeakRefSample1> weakPtr;
{
Mso::TCntPtr<ObjectWithWeakRefSample1> obj1 = Mso::Make<ObjectWithWeakRefSample1>(5, /*ref*/ deleted);
Mso::TCntPtr<Mso::ObjectWeakRef> weakRef = &obj1->GetWeakRef();
weakPtr = obj1;
{
Debug(TestAssert::AreEqual(2u, weakRef->RefCount()));
Debug(TestAssert::AreEqual(2u, weakRef->WeakRefCount()));
Mso::TCntPtr<ObjectWithWeakRefSample1> obj2(obj1);
Debug(TestAssert::AreEqual(3u, weakRef->RefCount()));
}
Mso::TCntPtr<ObjectWithWeakRefSample1> obj2(obj1);
Debug(TestAssert::AreEqual(3u, weakRef->RefCount()));
}
Debug(TestAssert::AreEqual(2u, weakRef->RefCount()));
TestAssert::IsFalse(deleted);
TestAssert::IsFalse(weakPtr.IsExpired());
}
Debug(TestAssert::AreEqual(2u, weakRef->RefCount()));
TestAssert::IsFalse(deleted);
TestAssert::IsFalse(weakPtr.IsExpired());
}
TestAssert::IsTrue(deleted);
TestAssert::IsTrue(weakPtr.IsExpired());
}
TestAssert::IsTrue(deleted);
TestAssert::IsTrue(weakPtr.IsExpired());
}
TEST_METHOD(ObjectWithWeakRef_Make_InitializeThis)
{
bool deleted = false;
{
auto obj = Mso::Make<ObjectWithWeakRefSample2Init>(5, /*ref*/ deleted);
Debug(TestAssert::AreEqual(1u, obj->GetWeakRef().RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectWithWeakRef_Make_InitializeThis)
{
bool deleted = false;
{
auto obj = Mso::Make<ObjectWithWeakRefSample2Init>(5, /*ref*/deleted);
Debug(TestAssert::AreEqual(1u, obj->GetWeakRef().RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectWithWeakRef_Make_CannotAllocate)
{
Mso::TCntPtr<ObjectWithWeakRefSample3CannotAllocate> obj;
TestAssert::ExpectVEC([&]() { obj = Mso::Make<ObjectWithWeakRefSample3CannotAllocate>(); });
TEST_METHOD(ObjectWithWeakRef_Make_CannotAllocate)
{
Mso::TCntPtr<ObjectWithWeakRefSample3CannotAllocate> obj;
TestAssert::ExpectVEC([&]()
{
obj = Mso::Make<ObjectWithWeakRefSample3CannotAllocate>();
});
TestAssert::IsTrue(obj.IsEmpty());
}
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectWithWeakRef_Make_CtorThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample4Throw> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>(
[&]() { obj = Mso::Make<ObjectWithWeakRefSample4Throw>(/*ref*/ deleted); });
TEST_METHOD(ObjectWithWeakRef_Make_CtorThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample4Throw> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>([&]()
{
obj = Mso::Make<ObjectWithWeakRefSample4Throw>(/*ref*/deleted);
});
TestAssert::IsFalse(deleted); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
TestAssert::IsFalse(deleted); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectWithWeakRef_Make_InitializeThisThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample5InitThrow> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>(
[&]() { obj = Mso::Make<ObjectWithWeakRefSample5InitThrow>(/*ref*/ deleted); });
TEST_METHOD(ObjectWithWeakRef_Make_InitializeThisThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample5InitThrow> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>([&]()
{
obj = Mso::Make<ObjectWithWeakRefSample5InitThrow>(/*ref*/deleted);
});
TestAssert::IsTrue(deleted); // If InitializeThis throws then destructor must be called.
TestAssert::IsTrue(obj.IsEmpty());
}
TestAssert::IsTrue(deleted); // If InitializeThis throws then destructor must be called.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectWithWeakRef_MakeElseNull)
{
bool deleted = false;
{
auto obj = Mso::MakeElseNull<ObjectWithWeakRefSample1>(5, /*ref*/ deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectWithWeakRef_MakeElseNull)
{
bool deleted = false;
{
auto obj = Mso::MakeElseNull<ObjectWithWeakRefSample1>(5, /*ref*/deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectWithWeakRef_MakeElseNull_InitializeThis)
{
bool deleted = false;
{
auto obj = Mso::MakeElseNull<ObjectWithWeakRefSample2Init>(5, /*ref*/ deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectWithWeakRef_MakeElseNull_InitializeThis)
{
bool deleted = false;
{
auto obj = Mso::MakeElseNull<ObjectWithWeakRefSample2Init>(5, /*ref*/deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectWithWeakRef_MakeElseNull_CannotAllocate)
{
auto obj = Mso::MakeElseNull<ObjectWithWeakRefSample3CannotAllocate>();
TestAssert::IsNull(obj.Get());
}
TEST_METHOD(ObjectWithWeakRef_MakeElseNull_CannotAllocate)
{
auto obj = Mso::MakeElseNull<ObjectWithWeakRefSample3CannotAllocate>();
TestAssert::IsNull(obj.Get());
}
TEST_METHOD(ObjectWithWeakRef_MakeElseNull_CtorThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample4Throw> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>(
[&]() { obj = Mso::MakeElseNull<ObjectWithWeakRefSample4Throw>(/*ref*/ deleted); });
}
TEST_METHOD(ObjectWithWeakRef_MakeElseNull_CtorThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample4Throw> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>([&]()
{
obj = Mso::MakeElseNull<ObjectWithWeakRefSample4Throw>(/*ref*/deleted);
});
}
TEST_METHOD(ObjectWithWeakRef_MakeElseNull_InitializeThisThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample5InitThrow> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>(
[&]() { obj = Mso::MakeElseNull<ObjectWithWeakRefSample5InitThrow>(/*ref*/ deleted); });
TEST_METHOD(ObjectWithWeakRef_MakeElseNull_InitializeThisThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample5InitThrow> obj;
bool deleted = false;
TestAssert::ExpectException<std::runtime_error>([&]()
{
obj = Mso::MakeElseNull<ObjectWithWeakRefSample5InitThrow>(/*ref*/deleted);
});
TestAssert::IsTrue(deleted); // If InitializeThis throws then we must call destructor.
TestAssert::IsTrue(obj.IsEmpty());
}
TestAssert::IsTrue(deleted); // If InitializeThis throws then we must call destructor.
TestAssert::IsTrue(obj.IsEmpty());
}
struct AllocTestState
{
bool AllocCalled;
bool FreeCalled;
bool Deleted;
};
static void AssertAllocState(const AllocTestState& state, bool deleted = true) noexcept
{
TestAssert::IsTrue(state.AllocCalled, L"Allocate expected to be called");
TestAssert::IsTrue(state.FreeCalled, L"Deallocate expected to be called");
TestAssert::AreEqual(deleted, state.Deleted, L"Destructor to be called");
}
struct AllocTestState
{
bool AllocCalled;
bool FreeCalled;
bool Deleted;
};
TEST_METHOD(ObjectWithWeakRef_MakeAlloc)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
auto obj = Mso::MakeAlloc<ObjectWithWeakRefSample11>(&memHeap, 5, /*ref*/ state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
static void AssertAllocState(const AllocTestState& state, bool deleted = true) noexcept
{
TestAssert::IsTrue(state.AllocCalled, L"Allocate expected to be called");
TestAssert::IsTrue(state.FreeCalled, L"Deallocate expected to be called");
TestAssert::AreEqual(deleted, state.Deleted, L"Destructor to be called");
}
AssertAllocState(state);
}
TEST_METHOD(ObjectWithWeakRef_MakeAlloc)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
auto obj = Mso::MakeAlloc<ObjectWithWeakRefSample11>(&memHeap, 5, /*ref*/state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectWithWeakRef_MakeAlloc_InitializeThis)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
auto obj = Mso::MakeAlloc<ObjectWithWeakRefSample21Init>(&memHeap, 5, /*ref*/ state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
AssertAllocState(state);
}
AssertAllocState(state);
}
TEST_METHOD(ObjectWithWeakRef_MakeAlloc_InitializeThis)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
auto obj = Mso::MakeAlloc<ObjectWithWeakRefSample21Init>(&memHeap, 5, /*ref*/state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectWithWeakRef_MakeAlloc_CannotAllocate)
{
Mso::TCntPtr<ObjectWithWeakRefSample31CannotAllocate> obj;
TestAssert::ExpectVEC([&]() {
AllocTestState state = {};
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
obj = Mso::MakeAlloc<ObjectWithWeakRefSample31CannotAllocate>(&memHeap);
});
AssertAllocState(state);
}
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectWithWeakRef_MakeAlloc_CannotAllocate)
{
Mso::TCntPtr<ObjectWithWeakRefSample31CannotAllocate> obj;
TestAssert::ExpectVEC([&]()
{
AllocTestState state = {};
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
obj = Mso::MakeAlloc<ObjectWithWeakRefSample31CannotAllocate>(&memHeap);
});
TEST_METHOD(ObjectWithWeakRef_MakeAlloc_CtorThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample41Throw> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]() {
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
obj = Mso::MakeAlloc<ObjectWithWeakRefSample41Throw>(&memHeap, /*ref*/ state.Deleted);
});
TestAssert::IsTrue(obj.IsEmpty());
}
AssertAllocState(state, /*deleted:*/ false); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectWithWeakRef_MakeAlloc_CtorThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample41Throw> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]()
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
obj = Mso::MakeAlloc<ObjectWithWeakRefSample41Throw>(&memHeap, /*ref*/state.Deleted);
});
TEST_METHOD(ObjectWithWeakRef_MakeAlloc_InitializeThisThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample51InitThrow> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]() {
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
obj = Mso::MakeAlloc<ObjectWithWeakRefSample51InitThrow>(&memHeap, /*ref*/ state.Deleted);
});
AssertAllocState(state, /*deleted:*/false); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
AssertAllocState(state); // If InitializeThis throws then destructor must be called.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectWithWeakRef_MakeAlloc_InitializeThisThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample51InitThrow> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]()
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
obj = Mso::MakeAlloc<ObjectWithWeakRefSample51InitThrow>(&memHeap, /*ref*/state.Deleted);
});
TEST_METHOD(ObjectWithWeakRef_MakeAllocElseNull)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectWithWeakRefSample11>(&memHeap, 5, /*ref*/ state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
AssertAllocState(state); // If InitializeThis throws then destructor must be called.
TestAssert::IsTrue(obj.IsEmpty());
}
AssertAllocState(state);
}
TEST_METHOD(ObjectWithWeakRef_MakeAllocElseNull)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectWithWeakRefSample11>(&memHeap, 5, /*ref*/state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectWithWeakRef_MakeAllocElseNull_InitializeThis)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectWithWeakRefSample21Init>(&memHeap, 5, /*ref*/ state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
AssertAllocState(state);
}
AssertAllocState(state);
}
TEST_METHOD(ObjectWithWeakRef_MakeAllocElseNull_InitializeThis)
{
AllocTestState state = {};
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectWithWeakRefSample21Init>(&memHeap, 5, /*ref*/state.Deleted);
Debug(TestAssert::AreEqual(1u, obj->RefCount()));
TestAssert::AreEqual(5, obj->Value());
}
TEST_METHOD(ObjectWithWeakRef_MakeAllocElseNull_CannotAllocate)
{
AllocTestState state = {};
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectWithWeakRefSample31CannotAllocate>(&memHeap);
TestAssert::IsNull(obj.Get());
}
AssertAllocState(state);
}
TEST_METHOD(ObjectWithWeakRef_MakeAllocElseNull_CtorThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample41Throw> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]() {
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
obj = Mso::MakeAllocElseNull<ObjectWithWeakRefSample41Throw>(&memHeap, /*ref*/ state.Deleted);
});
TEST_METHOD(ObjectWithWeakRef_MakeAllocElseNull_CannotAllocate)
{
AllocTestState state = {};
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
auto obj = Mso::MakeAllocElseNull<ObjectWithWeakRefSample31CannotAllocate>(&memHeap);
TestAssert::IsNull(obj.Get());
}
AssertAllocState(state, /*deleted:*/ false); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectWithWeakRef_MakeAllocElseNull_CtorThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample41Throw> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]()
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
obj = Mso::MakeAllocElseNull<ObjectWithWeakRefSample41Throw>(&memHeap, /*ref*/state.Deleted);
});
TEST_METHOD(ObjectWithWeakRef_MakeAllocElseNull_InitializeThisThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample51InitThrow> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]() {
MyMemHeap memHeap(/*ref*/ state.AllocCalled, /*ref*/ state.FreeCalled);
obj = Mso::MakeAllocElseNull<ObjectWithWeakRefSample51InitThrow>(&memHeap, /*ref*/ state.Deleted);
});
AssertAllocState(state, /*deleted:*/false); // Destructor is not called if constructor throws.
TestAssert::IsTrue(obj.IsEmpty());
}
TEST_METHOD(ObjectWithWeakRef_MakeAllocElseNull_InitializeThisThrows)
{
Mso::TCntPtr<ObjectWithWeakRefSample51InitThrow> obj;
AllocTestState state = {};
TestAssert::ExpectException<std::runtime_error>([&]()
{
MyMemHeap memHeap(/*ref*/state.AllocCalled, /*ref*/state.FreeCalled);
obj = Mso::MakeAllocElseNull<ObjectWithWeakRefSample51InitThrow>(&memHeap, /*ref*/state.Deleted);
});
AssertAllocState(state); // If InitializeThis throws then we must call destructor.
TestAssert::IsTrue(obj.IsEmpty());
}
AssertAllocState(state); // If InitializeThis throws then we must call destructor.
TestAssert::IsTrue(obj.IsEmpty());
}
};

Просмотреть файл

@ -10,51 +10,56 @@ Unit tests for classes in the ObjectQueryCast.h
#include <test/testCheck.h>
#define DEFINE_STRING_GUID(var, guid) \
MSO_STRUCT_GUID(_test_##var, guid) \
struct _test_##var {}; \
GUID var = __uuidof(_test_##var);
MSO_STRUCT_GUID(_test_##var, guid) \
struct _test_##var \
{ \
}; \
GUID var = __uuidof(_test_##var);
MSO_STRUCT_GUID(IQueryCastBase1, "EAE07273-AEFC-4E94-8087-E72F5D028BFC")
struct DECLSPEC_NOVTABLE IQueryCastBase1
{
virtual int GetValue1() = 0;
virtual int GetValue1() = 0;
};
MSO_STRUCT_GUID(IQueryCastBase2, "D62D6F01-0A54-40C0-9D23-A1C95EAF234D")
struct DECLSPEC_NOVTABLE IQueryCastBase2
{
virtual int GetValue2() = 0;
virtual int GetValue2() = 0;
};
MSO_STRUCT_GUID(IQueryCastBase3, "54A5CAC7-4788-499E-BAD1-1BBEF60A30F9")
struct DECLSPEC_NOVTABLE IQueryCastBase3
{
virtual int GetValue3() = 0;
virtual int GetValue3() = 0;
};
MSO_STRUCT_GUID(IQueryCastDerived1, "26747765-CB3C-42BC-8CBE-810F19779169")
struct DECLSPEC_NOVTABLE IQueryCastDerived1 : public IQueryCastBase1
{
virtual int GetValue11() = 0;
virtual int GetValue11() = 0;
};
class QueryCastTraitsSample1 : public IQueryCastBase1
{
public:
virtual int GetValue1() override { return 1; }
virtual int GetValue1() override
{
return 1;
}
};
struct QueryCastTraitsBase2
{
void* QueryCast(const GUID& riid) noexcept
{
if (riid == __uuidof(IQueryCastBase1))
{
return this;
}
void* QueryCast(const GUID& riid) noexcept
{
if (riid == __uuidof(IQueryCastBase1))
{
return this;
}
return nullptr;
}
return nullptr;
}
};
class QueryCastTraitsSample2 : public QueryCastTraitsBase2
@ -64,91 +69,140 @@ class QueryCastTraitsSample2 : public QueryCastTraitsBase2
MSO_STRUCT_GUID(QueryCastTraitsBase3, "5AF7D77B-7620-403D-9684-98AC591CF1A6")
struct QueryCastTraitsBase3
{
void* QueryCast(const GUID& riid) noexcept
{
if (riid == __uuidof(IQueryCastBase1))
{
return this;
}
void* QueryCast(const GUID& riid) noexcept
{
if (riid == __uuidof(IQueryCastBase1))
{
return this;
}
return nullptr;
}
return nullptr;
}
};
class QueryCastTraitsSample3 : public QueryCastTraitsBase3
{
};
class QueryCastChainSample1
: public Mso::QueryCastChain<IQueryCastDerived1, IQueryCastBase1>
class QueryCastChainSample1 : public Mso::QueryCastChain<IQueryCastDerived1, IQueryCastBase1>
{
public:
virtual int GetValue1() override { return 1; }
virtual int GetValue11() override { return 11; }
virtual int GetValue1() override
{
return 1;
}
virtual int GetValue11() override
{
return 11;
}
};
class QueryCastChainSample2
: public Mso::QueryCastList<Mso::QueryCastChain<IQueryCastDerived1, IQueryCastBase1>, IQueryCastBase2>
: public Mso::QueryCastList<Mso::QueryCastChain<IQueryCastDerived1, IQueryCastBase1>, IQueryCastBase2>
{
public:
virtual int GetValue1() override { return 1; }
virtual int GetValue11() override { return 11; }
virtual int GetValue2() override { return 2; }
virtual int GetValue1() override
{
return 1;
}
virtual int GetValue11() override
{
return 11;
}
virtual int GetValue2() override
{
return 2;
}
};
MSO_CLASS_GUID(QueryCastDerivedSample1, "1B7B2202-8B80-4E08-B20B-85235696BE02")
class QueryCastDerivedSample1 : public Mso::QueryCastList<IQueryCastBase1, Mso::QueryCastDerived<QueryCastDerivedSample1>>
class QueryCastDerivedSample1
: public Mso::QueryCastList<IQueryCastBase1, Mso::QueryCastDerived<QueryCastDerivedSample1>>
{
public:
virtual int GetValue1() override { return 1; }
virtual int GetValue1() override
{
return 1;
}
};
DEFINE_STRING_GUID(MyTestGuid1, "65ADDF73-B4EE-4E36-AB61-FEEA1F01A169");
struct DECLSPEC_NOVTABLE IQueryCastNoGuid1
{
virtual int GetValue1() = 0;
virtual int GetValue1() = 0;
};
class QueryCastGuidSample1
: public Mso::QueryCastList<Mso::QueryCastGuid<IQueryCastNoGuid1, &MyTestGuid1>, Mso::QueryCastGuid<IQueryCastBase2>>
: public Mso::
QueryCastList<Mso::QueryCastGuid<IQueryCastNoGuid1, &MyTestGuid1>, Mso::QueryCastGuid<IQueryCastBase2>>
{
public:
virtual int GetValue1() override { return 1; }
virtual int GetValue2() override { return 2; }
virtual int GetValue1() override
{
return 1;
}
virtual int GetValue2() override
{
return 2;
}
};
class QueryCastHiddenSample1 : public Mso::QueryCastHidden<IQueryCastBase1>
{
public:
virtual int GetValue1() override { return 1; }
virtual int GetValue1() override
{
return 1;
}
};
class QueryCastListSample1 : public Mso::QueryCastList<IQueryCastBase1>
{
public:
virtual int GetValue1() override { return 1; }
virtual int GetValue1() override
{
return 1;
}
};
class QueryCastListSample2 : public Mso::QueryCastList<IQueryCastBase1, IQueryCastBase2>
{
public:
virtual int GetValue1() override { return 12; }
virtual int GetValue2() override { return 22; }
virtual int GetValue1() override
{
return 12;
}
virtual int GetValue2() override
{
return 22;
}
};
class QueryCastListSample3 : public Mso::QueryCastList<IQueryCastBase1, IQueryCastBase2, IQueryCastBase3>
{
public:
virtual int GetValue1() override { return 13; }
virtual int GetValue2() override { return 23; }
virtual int GetValue3() override { return 33; }
virtual int GetValue1() override
{
return 13;
}
virtual int GetValue2() override
{
return 23;
}
virtual int GetValue3() override
{
return 33;
}
};
class QueryCastListDerivedSample1 : public Mso::QueryCastList<QueryCastListSample2, IQueryCastBase3>
{
public:
virtual int GetValue3() override { return 3; }
virtual int GetValue3() override
{
return 3;
}
};
struct StaticCastSample1 : public Mso::QueryCastList<QueryCastListSample2, QueryCastListSample3>
@ -161,357 +215,487 @@ struct StaticCastSample1 : public Mso::QueryCastList<QueryCastListSample2, Query
struct IUnkStaticBase1 : IUnknown
{
virtual int GetValue1() = 0;
virtual int GetValue1() = 0;
};
struct IUnkStaticBase2 : IUnknown
{
virtual int GetValue2() = 0;
virtual int GetValue2() = 0;
};
struct IStaticBase3
{
virtual int GetValue3() = 0;
virtual int GetValue3() = 0;
};
struct IStaticBase4
{
virtual int GetValue4() = 0;
virtual int GetValue4() = 0;
};
// To see if StaticCastElseNull<IUnknown*> works for one interface inherited from IUnknown
struct StaticSample1 : Mso::QueryCastList<IUnkStaticBase1>
{
virtual int GetValue1() override { return 1; }
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override { return E_NOINTERFACE; }
STDMETHOD_(ULONG, AddRef)() noexcept override { return 1; }
STDMETHOD_(ULONG, Release)() noexcept override { return 1; }
virtual int GetValue1() override
{
return 1;
}
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override
{
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)() noexcept override
{
return 1;
}
STDMETHOD_(ULONG, Release)() noexcept override
{
return 1;
}
};
// To see if StaticCastElseNull<IUnknown*> works for two interfaces inherited from IUnknown
struct StaticSample2 : Mso::QueryCastList<IUnkStaticBase1, IUnkStaticBase2>
{
virtual int GetValue1() override { return 1; }
virtual int GetValue2() override { return 2; }
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override { return E_NOINTERFACE; }
STDMETHOD_(ULONG, AddRef)() noexcept override { return 1; }
STDMETHOD_(ULONG, Release)() noexcept override { return 1; }
virtual int GetValue1() override
{
return 1;
}
virtual int GetValue2() override
{
return 2;
}
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override
{
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)() noexcept override
{
return 1;
}
STDMETHOD_(ULONG, Release)() noexcept override
{
return 1;
}
};
// To see if StaticCastElseNull<IUnknown*> returns nullptr for one interface not inherited from IUnknown
struct StaticSample3 : Mso::QueryCastList<IStaticBase3>
{
virtual int GetValue3() override { return 3; }
virtual int GetValue3() override
{
return 3;
}
};
// To see if StaticCastElseNull<IUnknown*> returns nullptr for two interfaces not inherited from IUnknown
struct StaticSample4 : Mso::QueryCastList<IStaticBase3, IStaticBase4>
{
virtual int GetValue3() override { return 3; }
virtual int GetValue4() override { return 4; }
virtual int GetValue3() override
{
return 3;
}
virtual int GetValue4() override
{
return 4;
}
};
// To see if StaticCastElseNull<IUnknown*> works for two interfaces inherited from IUnknown preceded by
// an interface not inherited from IUnknown.
struct StaticSample5 : Mso::QueryCastList<IStaticBase3, IUnkStaticBase1, IUnkStaticBase2>
{
virtual int GetValue1() override { return 1; }
virtual int GetValue2() override { return 2; }
virtual int GetValue3() override { return 3; }
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override { return E_NOINTERFACE; }
STDMETHOD_(ULONG, AddRef)() noexcept override { return 1; }
STDMETHOD_(ULONG, Release)() noexcept override { return 1; }
virtual int GetValue1() override
{
return 1;
}
virtual int GetValue2() override
{
return 2;
}
virtual int GetValue3() override
{
return 3;
}
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override
{
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)() noexcept override
{
return 1;
}
STDMETHOD_(ULONG, Release)() noexcept override
{
return 1;
}
};
// To see if StaticCastElseNull<IUnknown*> works for two interfaces inherited from IUnknown preceded by
// two interfaces not inherited from IUnknown.
struct StaticSample6 : Mso::QueryCastList<IStaticBase3, IStaticBase4, IUnkStaticBase1, IUnkStaticBase2>
{
virtual int GetValue1() override { return 1; }
virtual int GetValue2() override { return 2; }
virtual int GetValue3() override { return 3; }
virtual int GetValue4() override { return 4; }
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override { return E_NOINTERFACE; }
STDMETHOD_(ULONG, AddRef)() noexcept override { return 1; }
STDMETHOD_(ULONG, Release)() noexcept override { return 1; }
virtual int GetValue1() override
{
return 1;
}
virtual int GetValue2() override
{
return 2;
}
virtual int GetValue3() override
{
return 3;
}
virtual int GetValue4() override
{
return 4;
}
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override
{
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)() noexcept override
{
return 1;
}
STDMETHOD_(ULONG, Release)() noexcept override
{
return 1;
}
};
// To test nested hierarchy: IUnknown is implemented by nested QueryCastList.
struct StaticSample7 : Mso::QueryCastList<IStaticBase3, Mso::QueryCastList<IStaticBase4, IUnkStaticBase1, IUnkStaticBase2>>
struct StaticSample7
: Mso::QueryCastList<IStaticBase3, Mso::QueryCastList<IStaticBase4, IUnkStaticBase1, IUnkStaticBase2>>
{
virtual int GetValue1() override { return 1; }
virtual int GetValue2() override { return 2; }
virtual int GetValue3() override { return 3; }
virtual int GetValue4() override { return 4; }
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override { return E_NOINTERFACE; }
STDMETHOD_(ULONG, AddRef)() noexcept override { return 1; }
STDMETHOD_(ULONG, Release)() noexcept override { return 1; }
virtual int GetValue1() override
{
return 1;
}
virtual int GetValue2() override
{
return 2;
}
virtual int GetValue3() override
{
return 3;
}
virtual int GetValue4() override
{
return 4;
}
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override
{
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)() noexcept override
{
return 1;
}
STDMETHOD_(ULONG, Release)() noexcept override
{
return 1;
}
};
// To test nested hierarchy: IUnknown is implemented by nested QueryCastList.
struct StaticSample8 : Mso::QueryCastList<Mso::QueryCastList<IStaticBase3, IStaticBase4>, Mso::QueryCastList<IUnkStaticBase1, IUnkStaticBase2>>
struct StaticSample8
: Mso::QueryCastList<
Mso::QueryCastList<IStaticBase3, IStaticBase4>,
Mso::QueryCastList<IUnkStaticBase1, IUnkStaticBase2>>
{
virtual int GetValue1() override { return 1; }
virtual int GetValue2() override { return 2; }
virtual int GetValue3() override { return 3; }
virtual int GetValue4() override { return 4; }
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override { return E_NOINTERFACE; }
STDMETHOD_(ULONG, AddRef)() noexcept override { return 1; }
STDMETHOD_(ULONG, Release)() noexcept override { return 1; }
virtual int GetValue1() override
{
return 1;
}
virtual int GetValue2() override
{
return 2;
}
virtual int GetValue3() override
{
return 3;
}
virtual int GetValue4() override
{
return 4;
}
STDMETHOD(QueryInterface)(const GUID& /*riid*/, void** /*ppvObject*/) noexcept override
{
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)() noexcept override
{
return 1;
}
STDMETHOD_(ULONG, Release)() noexcept override
{
return 1;
}
};
// To test nested hierarchy: IUnknown is not implemented.
struct StaticSample9 : Mso::QueryCastList<Mso::QueryCastList<IStaticBase3, IStaticBase4>>
{
virtual int GetValue3() override { return 3; }
virtual int GetValue4() override { return 4; }
virtual int GetValue3() override
{
return 3;
}
virtual int GetValue4() override
{
return 4;
}
};
class QueryCastBase1WithArgs : public IQueryCastBase1
{
public:
int m_int;
std::string m_string;
int m_int;
std::string m_string;
QueryCastBase1WithArgs(int i, const std::string& str) : m_int(i), m_string(str) {}
virtual int GetValue1() override { return 1; }
QueryCastBase1WithArgs(int i, const std::string& str) : m_int(i), m_string(str) {}
virtual int GetValue1() override
{
return 1;
}
};
// Wrapper so that we can call protected constructors
template <typename T>
struct StructWithBase : public T
{
template <typename... Args>
StructWithBase(Args&&... args) : T(std::forward<Args>(args)...) {}
template <typename... Args>
StructWithBase(Args&&... args) : T(std::forward<Args>(args)...)
{
}
};
// A helper method to call QueryCastTraits::QueryCast.
template <typename TTarget, typename TSource>
inline TTarget* TraitsQueryCast(const TSource& source, const GUID &riid = __uuidof(TTarget)) noexcept
inline TTarget* TraitsQueryCast(const TSource& source, const GUID& riid = __uuidof(TTarget)) noexcept
{
if (source != nullptr)
{
return static_cast<TTarget*>(Mso::QueryCastHelper::QueryCast<typename std::remove_pointer<TSource>::type>(source, riid));
}
if (source != nullptr)
{
return static_cast<TTarget*>(
Mso::QueryCastHelper::QueryCast<typename std::remove_pointer<TSource>::type>(source, riid));
}
return nullptr;
return nullptr;
}
TestClassComponent(ObjectQueryCastTest, Mso.ObjectQueryCast)
TEST_CLASS(ObjectQueryCastTest)
TEST_CLASS (ObjectQueryCastTest){// Use GUID by default.
TEST_METHOD(QueryCastTraits_Guid){QueryCastTraitsSample1 obj;
auto base1 = TraitsQueryCast<IQueryCastBase1, IQueryCastBase1*>(&obj);
TestAssert::IsNotNull(base1);
TestAssert::IsTrue((void*)&obj == (void*)base1);
auto base2 = TraitsQueryCast<IQueryCastBase1, IQueryCastBase1*>(&obj, __uuidof(IQueryCastBase2));
TestAssert::IsNull(base2);
}
// Use QueryCast method if it is present.
TEST_METHOD(QueryCastTraits_QueryCast)
{
// Use GUID by default.
TEST_METHOD(QueryCastTraits_Guid)
{
QueryCastTraitsSample1 obj;
QueryCastTraitsSample2 obj;
auto base1 = TraitsQueryCast<IQueryCastBase1, IQueryCastBase1*>(&obj);
TestAssert::IsNotNull(base1);
TestAssert::IsTrue((void*)&obj == (void*)base1);
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base2 = TraitsQueryCast<IQueryCastBase1, IQueryCastBase1*>(&obj, __uuidof(IQueryCastBase2));
TestAssert::IsNull(base2);
}
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNull(base2);
}
// Use QueryCast method if it is present.
TEST_METHOD(QueryCastTraits_QueryCast)
{
QueryCastTraitsSample2 obj;
// QueryCast has higher priority over the assigned GUID.
TEST_METHOD(QueryCastTraits_QueryCastOverridesGuid)
{
QueryCastTraitsSample3 obj;
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNull(base2);
}
auto base2 = TraitsQueryCast<QueryCastTraitsBase3>(&obj);
TestAssert::IsNull(base2);
}
// QueryCast has higher priority over the assigned GUID.
TEST_METHOD(QueryCastTraits_QueryCastOverridesGuid)
{
QueryCastTraitsSample3 obj;
// Test use of QueryCastChain to query for a base interface.
TEST_METHOD(QueryCastChain_Test)
{
QueryCastChainSample1 obj;
TestAssert::AreEqual(sizeof(uintptr_t), sizeof(obj), L"There must be only one v-table.");
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base2 = TraitsQueryCast<QueryCastTraitsBase3>(&obj);
TestAssert::IsNull(base2);
}
auto derived1 = TraitsQueryCast<IQueryCastDerived1>(&obj);
TestAssert::IsNotNull(derived1);
}
// Test use of QueryCastChain to query for a base interface.
TEST_METHOD(QueryCastChain_Test)
{
QueryCastChainSample1 obj;
TestAssert::AreEqual(sizeof(uintptr_t), sizeof(obj), L"There must be only one v-table.");
// Test use of QueryCastChain to query for a base interface.
TEST_METHOD(QueryCastChain_InList)
{
QueryCastChainSample2 obj;
TestAssert::AreEqual(sizeof(uintptr_t) * 2, sizeof(obj), L"There must be only two v-tables.");
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto derived1 = TraitsQueryCast<IQueryCastDerived1>(&obj);
TestAssert::IsNotNull(derived1);
}
auto derived1 = TraitsQueryCast<IQueryCastDerived1>(&obj);
TestAssert::IsNotNull(derived1);
// Test use of QueryCastChain to query for a base interface.
TEST_METHOD(QueryCastChain_InList)
{
QueryCastChainSample2 obj;
TestAssert::AreEqual(sizeof(uintptr_t) * 2, sizeof(obj), L"There must be only two v-tables.");
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNotNull(base2);
}
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
// Test use of QueryCastDerived to query the derived type by its GUID.
TEST_METHOD(QueryCastDerived_Test)
{
QueryCastDerivedSample1 obj;
TestAssert::AreEqual(sizeof(uintptr_t), sizeof(obj), L"There must be only one v-table.");
auto derived1 = TraitsQueryCast<IQueryCastDerived1>(&obj);
TestAssert::IsNotNull(derived1);
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNotNull(base2);
}
auto derived = TraitsQueryCast<QueryCastDerivedSample1>(&obj);
TestAssert::IsNotNull(derived);
}
// Test use of QueryCastDerived to query the derived type by its GUID.
TEST_METHOD(QueryCastDerived_Test)
{
QueryCastDerivedSample1 obj;
TestAssert::AreEqual(sizeof(uintptr_t), sizeof(obj), L"There must be only one v-table.");
// Test use of QueryCastGuid to query for a base interface.
TEST_METHOD(QueryCastGuid_Test)
{
QueryCastGuidSample1 obj;
TestAssert::AreEqual(sizeof(uintptr_t) * 2, sizeof(obj), L"There must be only two v-tables.");
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base1 = TraitsQueryCast<IQueryCastNoGuid1>(&obj, MyTestGuid1);
TestAssert::IsNotNull(base1);
auto derived = TraitsQueryCast<QueryCastDerivedSample1>(&obj);
TestAssert::IsNotNull(derived);
}
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNotNull(base2);
}
// Test use of QueryCastGuid to query for a base interface.
TEST_METHOD(QueryCastGuid_Test)
{
QueryCastGuidSample1 obj;
TestAssert::AreEqual(sizeof(uintptr_t) * 2, sizeof(obj), L"There must be only two v-tables.");
// QueryCastHidden hides the base interface from the query cast.
TEST_METHOD(QueryCastHidden_Test)
{
QueryCastHiddenSample1 obj;
auto base1 = TraitsQueryCast<IQueryCastNoGuid1>(&obj, MyTestGuid1);
TestAssert::IsNotNull(base1);
IQueryCastBase1* intf = &obj;
TestAssert::IsNotNull(intf);
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNotNull(base2);
}
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNull(base1);
}
// QueryCastHidden hides the base interface from the query cast.
TEST_METHOD(QueryCastHidden_Test)
{
QueryCastHiddenSample1 obj;
// Test use of QueryCastList with one base type.
TEST_METHOD(QueryCastList_OneBaseType)
{
QueryCastListSample1 obj;
IQueryCastBase1* intf = &obj;
TestAssert::IsNotNull(intf);
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
}
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNull(base1);
}
// Test use of QueryCastList with two base types.
TEST_METHOD(QueryCastList_TwoBaseTypes)
{
QueryCastListSample2 obj;
// Test use of QueryCastList with one base type.
TEST_METHOD(QueryCastList_OneBaseType)
{
QueryCastListSample1 obj;
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
}
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNotNull(base2);
}
// Test use of QueryCastList with two base types.
TEST_METHOD(QueryCastList_TwoBaseTypes)
{
QueryCastListSample2 obj;
// Test use of QueryCastList with three base types.
TEST_METHOD(QueryCastList_ThreeBaseTypes)
{
QueryCastListSample3 obj;
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNotNull(base2);
}
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNotNull(base2);
// Test use of QueryCastList with three base types.
TEST_METHOD(QueryCastList_ThreeBaseTypes)
{
QueryCastListSample3 obj;
auto base3 = TraitsQueryCast<IQueryCastBase3>(&obj);
TestAssert::IsNotNull(base3);
}
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
// Test use of QueryCastList with a type that already inherits from the QueryCastList.
TEST_METHOD(QueryCastList_DerivedQueryCastList)
{
QueryCastListDerivedSample1 obj;
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNotNull(base2);
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
auto base3 = TraitsQueryCast<IQueryCastBase3>(&obj);
TestAssert::IsNotNull(base3);
}
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNotNull(base2);
// Test use of QueryCastList with a type that already inherits from the QueryCastList.
TEST_METHOD(QueryCastList_DerivedQueryCastList)
{
QueryCastListDerivedSample1 obj;
auto base3 = TraitsQueryCast<IQueryCastBase3>(&obj);
TestAssert::IsNotNull(base3);
}
auto base1 = TraitsQueryCast<IQueryCastBase1>(&obj);
TestAssert::IsNotNull(base1);
TEST_METHOD(QueryCastList_StaticCast)
{
StaticCastSample1 obj;
auto base2 = TraitsQueryCast<IQueryCastBase2>(&obj);
TestAssert::IsNotNull(base2);
IQueryCastBase1* base1 = obj.StaticCastElseNull<IQueryCastBase1*>();
TestAssert::IsNotNull(base1);
TestAssert::AreEqual(12, base1->GetValue1());
auto base3 = TraitsQueryCast<IQueryCastBase3>(&obj);
TestAssert::IsNotNull(base3);
}
IQueryCastBase2* base2 = obj.StaticCastElseNull<IQueryCastBase2*>();
TestAssert::IsNotNull(base2);
TestAssert::AreEqual(22, base2->GetValue2());
TEST_METHOD(QueryCastList_StaticCast)
{
StaticCastSample1 obj;
IQueryCastBase3* base3 = obj.StaticCastElseNull<IQueryCastBase3*>();
TestAssert::IsNotNull(base3);
TestAssert::AreEqual(33, base3->GetValue3());
}
IQueryCastBase1* base1 = obj.StaticCastElseNull<IQueryCastBase1*>();
TestAssert::IsNotNull(base1);
TestAssert::AreEqual(12, base1->GetValue1());
TEST_METHOD(QueryCastList_StaticCast2)
{
StaticSample1 sample1;
StaticSample2 sample2;
StaticSample3 sample3;
StaticSample4 sample4;
StaticSample5 sample5;
StaticSample6 sample6;
StaticSample7 sample7;
StaticSample8 sample8;
StaticSample9 sample9;
TestAssert::IsNotNull(sample1.StaticCastElseNull<IUnknown*>(), L"sample1");
TestAssert::IsNotNull(sample2.StaticCastElseNull<IUnknown*>(), L"sample2");
TestAssert::IsNull(sample3.StaticCastElseNull<IUnknown*>(), L"sample3");
TestAssert::IsNull(sample4.StaticCastElseNull<IUnknown*>(), L"sample4");
TestAssert::IsNotNull(sample5.StaticCastElseNull<IUnknown*>(), L"sample5");
TestAssert::IsNotNull(sample6.StaticCastElseNull<IUnknown*>(), L"sample6");
TestAssert::IsNotNull(sample7.StaticCastElseNull<IUnknown*>(), L"sample7");
TestAssert::IsNotNull(sample8.StaticCastElseNull<IUnknown*>(), L"sample8");
TestAssert::IsNull(sample9.StaticCastElseNull<IUnknown*>(), L"sample9");
}
IQueryCastBase2* base2 = obj.StaticCastElseNull<IQueryCastBase2*>();
TestAssert::IsNotNull(base2);
TestAssert::AreEqual(22, base2->GetValue2());
TEST_METHOD(QueryCastChain_ForwardCtorArgs)
{
StructWithBase<Mso::QueryCastChain<QueryCastBase1WithArgs, IQueryCastBase1>> testStruct(5, "asdf");
TestAssert::AreEqual(5, testStruct.m_int);
TestAssert::AreEqual("asdf", testStruct.m_string.c_str());
}
IQueryCastBase3* base3 = obj.StaticCastElseNull<IQueryCastBase3*>();
TestAssert::IsNotNull(base3);
TestAssert::AreEqual(33, base3->GetValue3());
}
TEST_METHOD(QueryCastGuid_ForwardCtorArgs)
{
StructWithBase<Mso::QueryCastGuid<QueryCastBase1WithArgs, &MyTestGuid1>> testStruct(5, "asdf");
TestAssert::AreEqual(5, testStruct.m_int);
TestAssert::AreEqual("asdf", testStruct.m_string.c_str());
}
TEST_METHOD(QueryCastList_StaticCast2)
{
StaticSample1 sample1;
StaticSample2 sample2;
StaticSample3 sample3;
StaticSample4 sample4;
StaticSample5 sample5;
StaticSample6 sample6;
StaticSample7 sample7;
StaticSample8 sample8;
StaticSample9 sample9;
TestAssert::IsNotNull(sample1.StaticCastElseNull<IUnknown*>(), L"sample1");
TestAssert::IsNotNull(sample2.StaticCastElseNull<IUnknown*>(), L"sample2");
TestAssert::IsNull(sample3.StaticCastElseNull<IUnknown*>(), L"sample3");
TestAssert::IsNull(sample4.StaticCastElseNull<IUnknown*>(), L"sample4");
TestAssert::IsNotNull(sample5.StaticCastElseNull<IUnknown*>(), L"sample5");
TestAssert::IsNotNull(sample6.StaticCastElseNull<IUnknown*>(), L"sample6");
TestAssert::IsNotNull(sample7.StaticCastElseNull<IUnknown*>(), L"sample7");
TestAssert::IsNotNull(sample8.StaticCastElseNull<IUnknown*>(), L"sample8");
TestAssert::IsNull(sample9.StaticCastElseNull<IUnknown*>(), L"sample9");
}
TEST_METHOD(QueryCastChain_ForwardCtorArgs)
{
StructWithBase<Mso::QueryCastChain<QueryCastBase1WithArgs, IQueryCastBase1>> testStruct(5, "asdf");
TestAssert::AreEqual(5, testStruct.m_int);
TestAssert::AreEqual("asdf", testStruct.m_string.c_str());
}
TEST_METHOD(QueryCastGuid_ForwardCtorArgs)
{
StructWithBase<Mso::QueryCastGuid<QueryCastBase1WithArgs, &MyTestGuid1>> testStruct(5, "asdf");
TestAssert::AreEqual(5, testStruct.m_int);
TestAssert::AreEqual("asdf", testStruct.m_string.c_str());
}
TEST_METHOD(QueryCastHidden_ForwardCtorArgs)
{
StructWithBase<Mso::QueryCastHidden<QueryCastBase1WithArgs>> testStruct(5, "asdf");
TestAssert::AreEqual(5, testStruct.m_int);
TestAssert::AreEqual("asdf", testStruct.m_string.c_str());
}
};
TEST_METHOD(QueryCastHidden_ForwardCtorArgs)
{
StructWithBase<Mso::QueryCastHidden<QueryCastBase1WithArgs>> testStruct(5, "asdf");
TestAssert::AreEqual(5, testStruct.m_int);
TestAssert::AreEqual("asdf", testStruct.m_string.c_str());
}
}
;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -12,562 +12,523 @@ Unit tests for classes in the ObjectSwarm.h
#include "testAllocators.h"
#include <test/testCheck.h>
//#define TEST_BAD_INHERITANCE1 // Uncomment to confirm VEC, but observe a memory leak. We cannot safely destroy this class.
//#define TEST_BAD_INHERITANCE1 // Uncomment to confirm VEC, but observe a memory leak. We cannot safely destroy this
//class.
MSO_STRUCT_GUID(ISwarmSample1, "962D2470-7452-43AB-9F74-63545A3E8A58")
struct DECLSPEC_NOVTABLE ISwarmSample1 : public IUnknown
{
virtual int GetValue1() = 0;
virtual int GetValue1() = 0;
};
MSO_STRUCT_GUID(ISwarmSample2, "B7E82DB0-436F-4B05-950F-FC1FE1ACE651")
struct DECLSPEC_NOVTABLE ISwarmSample2 : public IUnknown
{
virtual int GetValue2() = 0;
virtual int GetValue2() = 0;
};
class SwarmMemberSample1 final
: public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, ISwarmSample1>
class SwarmMemberSample1 final : public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, ISwarmSample1>
{
public:
SwarmMemberSample1(bool& deleted) noexcept
: m_deleted(deleted)
{
}
SwarmMemberSample1(bool& deleted) noexcept : m_deleted(deleted) {}
virtual int GetValue1() noexcept override
{
return 1;
}
virtual int GetValue1() noexcept override
{
return 1;
}
protected:
virtual ~SwarmMemberSample1() noexcept
{
m_deleted = true;
}
virtual ~SwarmMemberSample1() noexcept
{
m_deleted = true;
}
private:
bool& m_deleted;
bool& m_deleted;
};
class SwarmMemberSample2 final
: public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, ISwarmSample2>
class SwarmMemberSample2 final : public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, ISwarmSample2>
{
public:
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
using MakePolicy = Mso::MakePolicy::NoThrowCtorAndInitializeThis;
SwarmMemberSample2() noexcept
: m_deleted(nullptr)
, m_other()
{
}
SwarmMemberSample2() noexcept : m_deleted(nullptr), m_other() {}
bool InitializeThis(bool& deleted) noexcept
{
m_deleted = &deleted;
return true;
}
bool InitializeThis(bool& deleted) noexcept
{
m_deleted = &deleted;
return true;
}
virtual int GetValue2() noexcept override
{
return 2;
}
virtual int GetValue2() noexcept override
{
return 2;
}
Mso::TCntPtr<SwarmMemberSample1> GetOther() noexcept
{
return m_other.Get();
}
Mso::TCntPtr<SwarmMemberSample1> GetOther() noexcept
{
return m_other.Get();
}
bool IsDifferentSwarm() const noexcept
{
return m_other.IsDifferentSwarm();
}
bool IsDifferentSwarm() const noexcept
{
return m_other.IsDifferentSwarm();
}
void SetOther(SwarmMemberSample1& other) noexcept
{
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(this);
VerifyElseCrashSzTag(!swarm.IsEmpty(), "This object must be part of a swarm.", 0x01003708 /* tag_bad2i */);
m_other = Mso::SwarmMemberPtr<SwarmMemberSample1>(&other, *swarm);
}
void SetOther(SwarmMemberSample1& other) noexcept
{
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(this);
VerifyElseCrashSzTag(!swarm.IsEmpty(), "This object must be part of a swarm.", 0x01003708 /* tag_bad2i */);
m_other = Mso::SwarmMemberPtr<SwarmMemberSample1>(&other, *swarm);
}
protected:
virtual ~SwarmMemberSample2() noexcept
{
*m_deleted = true;
}
virtual ~SwarmMemberSample2() noexcept
{
*m_deleted = true;
}
private:
bool* m_deleted;
Mso::SwarmMemberPtr<SwarmMemberSample1> m_other;
bool* m_deleted;
Mso::SwarmMemberPtr<SwarmMemberSample1> m_other;
};
class SwarmMemberSample2Base
: public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, ISwarmSample1>
class SwarmMemberSample2Base : public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, ISwarmSample1>
{
public:
SwarmMemberSample2Base(int index, const std::function<void(int)>& onDelete)
: m_index(index)
, m_onDelete(onDelete)
{
}
SwarmMemberSample2Base(int index, const std::function<void(int)>& onDelete) : m_index(index), m_onDelete(onDelete) {}
virtual int GetValue1() noexcept override
{
return 1;
}
virtual int GetValue1() noexcept override
{
return 1;
}
protected:
virtual ~SwarmMemberSample2Base() noexcept
{
OACR_ASSUME_NOTHROW_BEGIN
m_onDelete(m_index);
OACR_ASSUME_NOTHROW_END
}
virtual ~SwarmMemberSample2Base() noexcept
{
OACR_ASSUME_NOTHROW_BEGIN
m_onDelete(m_index);
OACR_ASSUME_NOTHROW_END
}
private:
int m_index;
std::function<void(int)> m_onDelete;
int m_index;
std::function<void(int)> m_onDelete;
};
class SwarmMemberSample21 : public SwarmMemberSample2Base
{
public:
SwarmMemberSample21(int index, const std::function<void(int)>& onDelete)
: SwarmMemberSample2Base(index, onDelete)
{
}
SwarmMemberSample21(int index, const std::function<void(int)>& onDelete) : SwarmMemberSample2Base(index, onDelete) {}
};
class SwarmMemberSample22 : public SwarmMemberSample2Base
{
public:
SwarmMemberSample22(int index, const std::function<void(int)>& onDelete)
: SwarmMemberSample2Base(index, onDelete)
{
}
SwarmMemberSample22(int index, const std::function<void(int)>& onDelete) : SwarmMemberSample2Base(index, onDelete) {}
};
class SwarmMemberSample3CannotAllocate
: public Mso::UnknownObject<BadAllocWeakRefCount, ISwarmSample1>
class SwarmMemberSample3CannotAllocate : public Mso::UnknownObject<BadAllocWeakRefCount, ISwarmSample1>
{
public:
SwarmMemberSample3CannotAllocate() noexcept
{
}
SwarmMemberSample3CannotAllocate() noexcept {}
virtual int GetValue1() noexcept override
{
return 1;
}
virtual int GetValue1() noexcept override
{
return 1;
}
protected:
virtual ~SwarmMemberSample3CannotAllocate() noexcept
{
}
virtual ~SwarmMemberSample3CannotAllocate() noexcept {}
};
class SwarmMemberSampleBase
: public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, ISwarmSample1>
class SwarmMemberSampleBase : public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, ISwarmSample1>
{
public:
SwarmMemberSampleBase() noexcept
{
}
SwarmMemberSampleBase() noexcept {}
virtual int GetValue1() noexcept override
{
return 1;
}
virtual int GetValue1() noexcept override
{
return 1;
}
protected:
virtual ~SwarmMemberSampleBase() noexcept
{
}
virtual ~SwarmMemberSampleBase() noexcept {}
};
class SwarmMemberSample4Throw
: public SwarmMemberSampleBase
class SwarmMemberSample4Throw : public SwarmMemberSampleBase
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtor;
using MakePolicy = Mso::MakePolicy::ThrowCtor;
SwarmMemberSample4Throw()
{
throw std::runtime_error("Test");
}
SwarmMemberSample4Throw()
{
throw std::runtime_error("Test");
}
};
class SwarmMemberSample5InitThrow
: public SwarmMemberSampleBase
class SwarmMemberSample5InitThrow : public SwarmMemberSampleBase
{
public:
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
using MakePolicy = Mso::MakePolicy::ThrowCtorAndInitializeThis;
void InitializeThis()
{
UNREFERENCED_OACR(this);
throw std::runtime_error("Test");
}
void InitializeThis()
{
UNREFERENCED_OACR(this);
throw std::runtime_error("Test");
}
};
#ifdef TEST_BAD_INHERITANCE1
class SomeVirtualClass
{
public:
virtual ~SomeVirtualClass() noexcept{}
virtual ~SomeVirtualClass() noexcept {}
int x;
int y;
int x;
int y;
};
// !!! Mso::UnknownObject must be always the first one in the inheritance !!!
class BadSwarmMember1 final
: public SomeVirtualClass
, public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, ISwarmSample1>
: public SomeVirtualClass
, public Mso::UnknownObject<Mso::RefCountStrategy::WeakRef, ISwarmSample1>
{
public:
virtual int GetValue1() override
{
return 1;
}
virtual int GetValue1() override
{
return 1;
}
};
#endif
TEST_CLASS(ObjectSwarmTest)
TEST_CLASS (ObjectSwarmTest)
{
TEST_METHOD(ObjectSwarm_OneMember)
{
bool deleted;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/deleted);
TestAssert::IsNotNull(member1.Get());
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectSwarm_OneMember)
{
bool deleted;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/ deleted);
TestAssert::IsNotNull(member1.Get());
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectSwarm_TwoMembers)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
Mso::TCntPtr<SwarmMemberSample2> member2 = swarm->MakeMember<SwarmMemberSample2>(/*ref*/deleted2);
TestAssert::IsNotNull(member2.Get());
}
TestAssert::IsTrue(deleted1, L"First Swarm member is not deleted.");
TestAssert::IsTrue(deleted2, L"Second Swarm member is not deleted.");
}
TEST_METHOD(ObjectSwarm_TwoMembers)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/ deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
Mso::TCntPtr<SwarmMemberSample2> member2 = swarm->MakeMember<SwarmMemberSample2>(/*ref*/ deleted2);
TestAssert::IsNotNull(member2.Get());
}
TestAssert::IsTrue(deleted1, L"First Swarm member is not deleted.");
TestAssert::IsTrue(deleted2, L"Second Swarm member is not deleted.");
}
TEST_METHOD(ObjectSwarm_ThreeMembers)
{
// Test that members are deleted in reverse order to how they were created.
const int memberCount = 3;
int deleteOrderIndex = 0;
int deleteOrder[memberCount];
std::function<void(int)> onDelete = [&deleteOrderIndex, &deleteOrder](int index) noexcept
{
deleteOrder[--deleteOrderIndex] = index;
};
TEST_METHOD(ObjectSwarm_ThreeMembers)
{
// Test that members are deleted in reverse order to how they were created.
const int memberCount = 3;
int deleteOrderIndex = 0;
int deleteOrder[memberCount];
std::function<void(int)> onDelete = [&deleteOrderIndex, &deleteOrder](int index) noexcept {
deleteOrder[--deleteOrderIndex] = index;
};
{
Mso::TCntPtr<SwarmMemberSample21> member1 = Mso::Swarm::Make<SwarmMemberSample21>(deleteOrderIndex++, onDelete);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
Mso::TCntPtr<SwarmMemberSample22> member2 = swarm->MakeMember<SwarmMemberSample22>(deleteOrderIndex++, onDelete);
TestAssert::IsNotNull(member2.Get());
// Members can be of the same type
Mso::TCntPtr<SwarmMemberSample22> member3 = swarm->MakeMember<SwarmMemberSample22>(deleteOrderIndex++, onDelete);
TestAssert::IsNotNull(member3.Get());
}
{
Mso::TCntPtr<SwarmMemberSample21> member1 = Mso::Swarm::Make<SwarmMemberSample21>(deleteOrderIndex++, onDelete);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
Mso::TCntPtr<SwarmMemberSample22> member2 = swarm->MakeMember<SwarmMemberSample22>(deleteOrderIndex++, onDelete);
TestAssert::IsNotNull(member2.Get());
// Members can be of the same type
Mso::TCntPtr<SwarmMemberSample22> member3 = swarm->MakeMember<SwarmMemberSample22>(deleteOrderIndex++, onDelete);
TestAssert::IsNotNull(member3.Get());
}
TestAssert::AreEqual(0, deleteOrderIndex, L"Not all members are deleted");
TestAssert::AreEqual(0, deleteOrderIndex, L"Not all members are deleted");
for (int i = 0; i < memberCount; i++)
{
TestAssert::AreEqual(i, deleteOrder[i], L"Wrong deletion order");
}
}
for (int i = 0; i < memberCount; i++)
{
TestAssert::AreEqual(i, deleteOrder[i], L"Wrong deletion order");
}
}
TEST_METHOD(ObjectSwarm_FromObject)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
TestAssert::IsNotNull(swarm.Get());
TEST_METHOD(ObjectSwarm_FromObject)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/ deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
TestAssert::IsNotNull(swarm.Get());
Mso::TCntPtr<SwarmMemberSample2> member2 = swarm->MakeMember<SwarmMemberSample2>(/*ref*/deleted2);
TestAssert::IsNotNull(member2.Get());
swarm = Mso::Swarm::FromObject(member2.Get());
TestAssert::IsNotNull(swarm.Get());
Mso::TCntPtr<SwarmMemberSample2> member2 = swarm->MakeMember<SwarmMemberSample2>(/*ref*/ deleted2);
TestAssert::IsNotNull(member2.Get());
swarm = Mso::Swarm::FromObject(member2.Get());
TestAssert::IsNotNull(swarm.Get());
Mso::TCntPtr<ISwarmSample1> memberIntf1 = qi_cast<ISwarmSample1>(member1.Get());
TestAssert::IsNotNull(memberIntf1.Get());
swarm = Mso::Swarm::FromObject(memberIntf1.Get());
TestAssert::IsNotNull(swarm.Get());
Mso::TCntPtr<ISwarmSample1> memberIntf1 = qi_cast<ISwarmSample1>(member1.Get());
TestAssert::IsNotNull(memberIntf1.Get());
swarm = Mso::Swarm::FromObject(memberIntf1.Get());
TestAssert::IsNotNull(swarm.Get());
//Mso::TCntPtr<ISwarmSample2> memberIntf2 = qi_cast<ISwarmSample2>(member2.Get());
//TestAssert::IsNotNull(memberIntf2.Get());
//swarm = Mso::Swarm::FromObject(memberIntf2.Get());
//TestAssert::IsNotNull(swarm.Get());
}
TestAssert::IsTrue(deleted1, L"First Swarm member is not deleted.");
TestAssert::IsTrue(deleted2, L"Second Swarm member is not deleted.");
}
// Mso::TCntPtr<ISwarmSample2> memberIntf2 = qi_cast<ISwarmSample2>(member2.Get());
// TestAssert::IsNotNull(memberIntf2.Get());
// swarm = Mso::Swarm::FromObject(memberIntf2.Get());
// TestAssert::IsNotNull(swarm.Get());
}
TestAssert::IsTrue(deleted1, L"First Swarm member is not deleted.");
TestAssert::IsTrue(deleted2, L"Second Swarm member is not deleted.");
}
TEST_METHOD(ObjectSwarm_WeakPtr)
{
bool deleted1;
bool deleted2;
{
Mso::WeakPtr<SwarmMemberSample1> memberWeak1;
Mso::WeakPtr<SwarmMemberSample2> memberWeak2;
Mso::WeakPtr<ISwarmSample1> memberIntfWeak1;
Mso::WeakPtr<ISwarmSample2> memberIntfWeak2;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
Mso::TCntPtr<SwarmMemberSample2> member2 = swarm->MakeMember<SwarmMemberSample2>(/*ref*/deleted2);
TEST_METHOD(ObjectSwarm_WeakPtr)
{
bool deleted1;
bool deleted2;
{
Mso::WeakPtr<SwarmMemberSample1> memberWeak1;
Mso::WeakPtr<SwarmMemberSample2> memberWeak2;
Mso::WeakPtr<ISwarmSample1> memberIntfWeak1;
Mso::WeakPtr<ISwarmSample2> memberIntfWeak2;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/ deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
Mso::TCntPtr<SwarmMemberSample2> member2 = swarm->MakeMember<SwarmMemberSample2>(/*ref*/ deleted2);
memberWeak1 = member1;
memberWeak2 = member2;
memberIntfWeak1 = qi_cast<ISwarmSample1>(member1.Get());
memberIntfWeak2 = qi_cast<ISwarmSample2>(member2.Get());
memberWeak1 = member1;
memberWeak2 = member2;
memberIntfWeak1 = qi_cast<ISwarmSample1>(member1.Get());
memberIntfWeak2 = qi_cast<ISwarmSample2>(member2.Get());
TestAssert::IsFalse(memberWeak1.IsExpired());
TestAssert::IsFalse(memberWeak2.IsExpired());
TestAssert::IsFalse(memberIntfWeak1.IsExpired());
TestAssert::IsFalse(memberIntfWeak2.IsExpired());
TestAssert::IsFalse(memberWeak1.IsExpired());
TestAssert::IsFalse(memberWeak2.IsExpired());
TestAssert::IsFalse(memberIntfWeak1.IsExpired());
TestAssert::IsFalse(memberIntfWeak2.IsExpired());
Debug(TestAssert::AreEqual(/*members*/2u + /*weakptr*/4u, member1->GetWeakRef().WeakRefCount()));
Debug(TestAssert::AreEqual(/*members*/2u + /*swarm*/1u, member1->GetWeakRef().RefCount()));
Debug(TestAssert::AreEqual(/*members*/ 2u + /*weakptr*/ 4u, member1->GetWeakRef().WeakRefCount()));
Debug(TestAssert::AreEqual(/*members*/ 2u + /*swarm*/ 1u, member1->GetWeakRef().RefCount()));
Mso::TCntPtr<SwarmMemberSample1> member11 = memberWeak1.GetStrongPtr();
Mso::TCntPtr<SwarmMemberSample2> member21 = memberWeak2.GetStrongPtr();
Mso::TCntPtr<ISwarmSample1> memberIntf11 = memberIntfWeak1.GetStrongPtr();
Mso::TCntPtr<ISwarmSample2> memberIntf21 = memberIntfWeak2.GetStrongPtr();
TestAssert::IsNotNull(member11.Get());
TestAssert::IsNotNull(member21.Get());
TestAssert::IsNotNull(memberIntf11.Get());
TestAssert::IsNotNull(memberIntf21.Get());
}
TestAssert::IsTrue(memberWeak1.IsExpired());
TestAssert::IsTrue(memberWeak2.IsExpired());
TestAssert::IsTrue(memberIntfWeak1.IsExpired());
TestAssert::IsTrue(memberIntfWeak2.IsExpired());
Mso::TCntPtr<SwarmMemberSample1> member11 = memberWeak1.GetStrongPtr();
Mso::TCntPtr<SwarmMemberSample2> member21 = memberWeak2.GetStrongPtr();
Mso::TCntPtr<ISwarmSample1> memberIntf11 = memberIntfWeak1.GetStrongPtr();
Mso::TCntPtr<ISwarmSample2> memberIntf21 = memberIntfWeak2.GetStrongPtr();
TestAssert::IsNotNull(member11.Get());
TestAssert::IsNotNull(member21.Get());
TestAssert::IsNotNull(memberIntf11.Get());
TestAssert::IsNotNull(memberIntf21.Get());
}
TestAssert::IsTrue(memberWeak1.IsExpired());
TestAssert::IsTrue(memberWeak2.IsExpired());
TestAssert::IsTrue(memberIntfWeak1.IsExpired());
TestAssert::IsTrue(memberIntfWeak2.IsExpired());
Mso::TCntPtr<SwarmMemberSample1> member11 = memberWeak1.GetStrongPtr();
Mso::TCntPtr<SwarmMemberSample2> member21 = memberWeak2.GetStrongPtr();
Mso::TCntPtr<ISwarmSample1> memberIntf11 = memberIntfWeak1.GetStrongPtr();
Mso::TCntPtr<ISwarmSample2> memberIntf21 = memberIntfWeak2.GetStrongPtr();
TestAssert::IsNull(member11.Get());
TestAssert::IsNull(member21.Get());
TestAssert::IsNull(memberIntf11.Get());
TestAssert::IsNull(memberIntf21.Get());
}
TestAssert::IsTrue(deleted1, L"First Swarm member is not deleted.");
TestAssert::IsTrue(deleted2, L"Second Swarm member is not deleted.");
}
Mso::TCntPtr<SwarmMemberSample1> member11 = memberWeak1.GetStrongPtr();
Mso::TCntPtr<SwarmMemberSample2> member21 = memberWeak2.GetStrongPtr();
Mso::TCntPtr<ISwarmSample1> memberIntf11 = memberIntfWeak1.GetStrongPtr();
Mso::TCntPtr<ISwarmSample2> memberIntf21 = memberIntfWeak2.GetStrongPtr();
TestAssert::IsNull(member11.Get());
TestAssert::IsNull(member21.Get());
TestAssert::IsNull(memberIntf11.Get());
TestAssert::IsNull(memberIntf21.Get());
}
TestAssert::IsTrue(deleted1, L"First Swarm member is not deleted.");
TestAssert::IsTrue(deleted2, L"Second Swarm member is not deleted.");
}
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_SameSwarm)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample2> member2 = Mso::Swarm::Make<SwarmMemberSample2>(/*ref*/deleted2);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member2.Get());
Mso::TCntPtr<SwarmMemberSample1> member1 = swarm->MakeMember<SwarmMemberSample1>(/*ref*/deleted1);
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_SameSwarm)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample2> member2 = Mso::Swarm::Make<SwarmMemberSample2>(/*ref*/ deleted2);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member2.Get());
Mso::TCntPtr<SwarmMemberSample1> member1 = swarm->MakeMember<SwarmMemberSample1>(/*ref*/ deleted1);
member2->SetOther(*member1);
TestAssert::IsTrue(member1.Get() == member2->GetOther().Get());
TestAssert::IsFalse(member2->IsDifferentSwarm());
}
TestAssert::IsTrue(deleted1);
TestAssert::IsTrue(deleted2);
}
member2->SetOther(*member1);
TestAssert::IsTrue(member1.Get() == member2->GetOther().Get());
TestAssert::IsFalse(member2->IsDifferentSwarm());
}
TestAssert::IsTrue(deleted1);
TestAssert::IsTrue(deleted2);
}
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_DifferentSwarm)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/deleted1);
Mso::TCntPtr<SwarmMemberSample2> member2 = Mso::Swarm::Make<SwarmMemberSample2>(/*ref*/deleted2);
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_DifferentSwarm)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/ deleted1);
Mso::TCntPtr<SwarmMemberSample2> member2 = Mso::Swarm::Make<SwarmMemberSample2>(/*ref*/ deleted2);
member2->SetOther(*member1);
TestAssert::IsTrue(member1.Get() == member2->GetOther().Get());
TestAssert::IsTrue(member2->IsDifferentSwarm());
}
TestAssert::IsTrue(deleted1);
TestAssert::IsTrue(deleted2);
}
member2->SetOther(*member1);
TestAssert::IsTrue(member1.Get() == member2->GetOther().Get());
TestAssert::IsTrue(member2->IsDifferentSwarm());
}
TestAssert::IsTrue(deleted1);
TestAssert::IsTrue(deleted2);
}
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_KnownSameSwarm)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample2> member0 = Mso::Swarm::Make<SwarmMemberSample2>(/*ref*/deleted2);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member0.Get());
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_KnownSameSwarm)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample2> member0 = Mso::Swarm::Make<SwarmMemberSample2>(/*ref*/ deleted2);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member0.Get());
Mso::SwarmMemberPtr<SwarmMemberSample1, /*KnownSameSwarm*/true> member1 =
swarm->MakeMember<SwarmMemberSample1>(/*ref*/deleted1);
TestAssert::IsNotNull(member1.Get());
Mso::SwarmMemberPtr<SwarmMemberSample1, /*KnownSameSwarm*/ true> member1 =
swarm->MakeMember<SwarmMemberSample1>(/*ref*/ deleted1);
TestAssert::IsNotNull(member1.Get());
Mso::SwarmMemberPtr<SwarmMemberSample1, /*KnownSameSwarm*/true> member2 = std::move(member1);
TestAssert::IsNull(member1.Get());
TestAssert::IsNotNull(member2.Get());
Mso::SwarmMemberPtr<SwarmMemberSample1, /*KnownSameSwarm*/ true> member2 = std::move(member1);
TestAssert::IsNull(member1.Get());
TestAssert::IsNotNull(member2.Get());
using std::swap;
swap(member1, member2);
TestAssert::IsNotNull(member1.Get());
TestAssert::IsNull(member2.Get());
TestAssert::IsFalse(member1.IsEmpty());
TestAssert::IsTrue(member2.IsEmpty());
}
TestAssert::IsTrue(deleted1);
TestAssert::IsTrue(deleted2);
}
using std::swap;
swap(member1, member2);
TestAssert::IsNotNull(member1.Get());
TestAssert::IsNull(member2.Get());
TestAssert::IsFalse(member1.IsEmpty());
TestAssert::IsTrue(member2.IsEmpty());
}
TestAssert::IsTrue(deleted1);
TestAssert::IsTrue(deleted2);
}
TEST_METHOD(ObjectSwarm_MakeMember_CannotAllocate)
{
bool deleted1;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
TEST_METHOD(ObjectSwarm_MakeMember_CannotAllocate)
{
bool deleted1;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/ deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
TestAssert::ExpectVEC([&]()
{
swarm->MakeMember<SwarmMemberSample3CannotAllocate>();
});
TestAssert::ExpectVEC([&]() { swarm->MakeMember<SwarmMemberSample3CannotAllocate>(); });
Debug(TestAssert::AreEqual(2u, swarm->RefCount()));
Debug(TestAssert::AreEqual(1u, swarm->WeakRefCount()));
}
TestAssert::IsTrue(deleted1);
}
Debug(TestAssert::AreEqual(2u, swarm->RefCount()));
Debug(TestAssert::AreEqual(1u, swarm->WeakRefCount()));
}
TestAssert::IsTrue(deleted1);
}
TEST_METHOD(ObjectSwarm_MakeMember_ConstructorThrows)
{
bool deleted1;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
TEST_METHOD(ObjectSwarm_MakeMember_ConstructorThrows)
{
bool deleted1;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/ deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
TestAssert::ExpectException<std::runtime_error>([&]()
{
swarm->MakeMember<SwarmMemberSample4Throw>();
});
TestAssert::ExpectException<std::runtime_error>([&]() { swarm->MakeMember<SwarmMemberSample4Throw>(); });
Debug(TestAssert::AreEqual(2u, swarm->RefCount()));
Debug(TestAssert::AreEqual(1u, swarm->WeakRefCount()));
}
TestAssert::IsTrue(deleted1);
}
Debug(TestAssert::AreEqual(2u, swarm->RefCount()));
Debug(TestAssert::AreEqual(1u, swarm->WeakRefCount()));
}
TestAssert::IsTrue(deleted1);
}
TEST_METHOD(ObjectSwarm_MakeMember_InitializeThrows)
{
bool deleted1;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
TEST_METHOD(ObjectSwarm_MakeMember_InitializeThrows)
{
bool deleted1;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/ deleted1);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member1.Get());
TestAssert::ExpectException<std::runtime_error>([&]()
{
swarm->MakeMember<SwarmMemberSample5InitThrow>();
});
TestAssert::ExpectException<std::runtime_error>([&]() { swarm->MakeMember<SwarmMemberSample5InitThrow>(); });
Debug(TestAssert::AreEqual(2u, swarm->RefCount()));
Debug(TestAssert::AreEqual(1u, swarm->WeakRefCount()));
}
TestAssert::IsTrue(deleted1);
}
Debug(TestAssert::AreEqual(2u, swarm->RefCount()));
Debug(TestAssert::AreEqual(1u, swarm->WeakRefCount()));
}
TestAssert::IsTrue(deleted1);
}
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_ObjectWeakRef_SameSwarm)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample2> member2 = Mso::Swarm::Make<SwarmMemberSample2>(/*ref*/deleted2);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member2.Get());
Mso::TCntPtr<Mso::ObjectWeakRef> weakRef2 = &member2->GetWeakRef();
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_ObjectWeakRef_SameSwarm)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample2> member2 = Mso::Swarm::Make<SwarmMemberSample2>(/*ref*/ deleted2);
Mso::TCntPtr<Mso::Swarm> swarm = Mso::Swarm::FromObject(member2.Get());
Mso::TCntPtr<Mso::ObjectWeakRef> weakRef2 = &member2->GetWeakRef();
Mso::TCntPtr<SwarmMemberSample1> member1 = swarm->MakeMember<SwarmMemberSample1>(/*ref*/deleted1);
Mso::TCntPtr<SwarmMemberSample1> member1 = swarm->MakeMember<SwarmMemberSample1>(/*ref*/ deleted1);
Mso::SwarmMemberPtr<SwarmMemberSample1> swarmPtr = Mso::SwarmMemberPtr<SwarmMemberSample1>(member1.Get(), *weakRef2);
TestAssert::IsTrue(swarmPtr.Get() == member1.Get());
TestAssert::IsFalse(swarmPtr.IsDifferentSwarm());
}
TestAssert::IsTrue(deleted1);
TestAssert::IsTrue(deleted2);
}
Mso::SwarmMemberPtr<SwarmMemberSample1> swarmPtr =
Mso::SwarmMemberPtr<SwarmMemberSample1>(member1.Get(), *weakRef2);
TestAssert::IsTrue(swarmPtr.Get() == member1.Get());
TestAssert::IsFalse(swarmPtr.IsDifferentSwarm());
}
TestAssert::IsTrue(deleted1);
TestAssert::IsTrue(deleted2);
}
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_ObjectWeakRef_DifferentSwarm)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/deleted1);
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_ObjectWeakRef_DifferentSwarm)
{
bool deleted1;
bool deleted2;
{
Mso::TCntPtr<SwarmMemberSample1> member1 = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/ deleted1);
Mso::TCntPtr<SwarmMemberSample2> member2 = Mso::Swarm::Make<SwarmMemberSample2>(/*ref*/deleted2);
Mso::TCntPtr<Mso::ObjectWeakRef> weakRef2 = &member2->GetWeakRef();
Mso::TCntPtr<SwarmMemberSample2> member2 = Mso::Swarm::Make<SwarmMemberSample2>(/*ref*/ deleted2);
Mso::TCntPtr<Mso::ObjectWeakRef> weakRef2 = &member2->GetWeakRef();
Mso::SwarmMemberPtr<SwarmMemberSample1> swarmPtr = Mso::SwarmMemberPtr<SwarmMemberSample1>(member1.Get(), *weakRef2);
TestAssert::IsTrue(swarmPtr.Get() == member1.Get());
TestAssert::IsTrue(swarmPtr.IsDifferentSwarm());
}
TestAssert::IsTrue(deleted1);
TestAssert::IsTrue(deleted2);
}
Mso::SwarmMemberPtr<SwarmMemberSample1> swarmPtr =
Mso::SwarmMemberPtr<SwarmMemberSample1>(member1.Get(), *weakRef2);
TestAssert::IsTrue(swarmPtr.Get() == member1.Get());
TestAssert::IsTrue(swarmPtr.IsDifferentSwarm());
}
TestAssert::IsTrue(deleted1);
TestAssert::IsTrue(deleted2);
}
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_EqualityToNull)
{
bool deleted = false;
{
Mso::TCntPtr<SwarmMemberSample1> member = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/deleted);
Mso::SwarmMemberPtr<SwarmMemberSample1> swarmPtr = Mso::SwarmMemberPtr<SwarmMemberSample1>(member.Get(), *Mso::Swarm::FromObject(member.Get()));
TestAssert::IsFalse(swarmPtr.IsDifferentSwarm());
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_EqualityToNull)
{
bool deleted = false;
{
Mso::TCntPtr<SwarmMemberSample1> member = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/ deleted);
Mso::SwarmMemberPtr<SwarmMemberSample1> swarmPtr =
Mso::SwarmMemberPtr<SwarmMemberSample1>(member.Get(), *Mso::Swarm::FromObject(member.Get()));
TestAssert::IsFalse(swarmPtr.IsDifferentSwarm());
TestAssert::IsTrue(swarmPtr != nullptr);
TestAssert::IsTrue(nullptr != swarmPtr);
TestAssert::IsTrue(swarmPtr != nullptr);
TestAssert::IsTrue(nullptr != swarmPtr);
swarmPtr.Reset();
swarmPtr.Reset();
TestAssert::IsTrue(swarmPtr == nullptr);
TestAssert::IsTrue(nullptr == swarmPtr);
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsTrue(swarmPtr == nullptr);
TestAssert::IsTrue(nullptr == swarmPtr);
}
TestAssert::IsTrue(deleted);
}
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_KnownSameSwarm_EqualityToNull)
{
bool deleted = false;
{
Mso::TCntPtr<SwarmMemberSample1> member = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/deleted);
Mso::SwarmMemberPtr<SwarmMemberSample1, /*KnownSameSwarm*/true> swarmPtr = Mso::SwarmMemberPtr<SwarmMemberSample1, /*KnownSameSwarm*/true>(member.Get());
TestAssert::IsFalse(swarmPtr.IsDifferentSwarm());
TEST_METHOD(ObjectSwarm_SwarmMemberPtr_KnownSameSwarm_EqualityToNull)
{
bool deleted = false;
{
Mso::TCntPtr<SwarmMemberSample1> member = Mso::Swarm::Make<SwarmMemberSample1>(/*ref*/ deleted);
Mso::SwarmMemberPtr<SwarmMemberSample1, /*KnownSameSwarm*/ true> swarmPtr =
Mso::SwarmMemberPtr<SwarmMemberSample1, /*KnownSameSwarm*/ true>(member.Get());
TestAssert::IsFalse(swarmPtr.IsDifferentSwarm());
TestAssert::IsTrue(swarmPtr != nullptr);
TestAssert::IsTrue(nullptr != swarmPtr);
TestAssert::IsTrue(swarmPtr != nullptr);
TestAssert::IsTrue(nullptr != swarmPtr);
swarmPtr.Reset();
swarmPtr.Reset();
TestAssert::IsTrue(swarmPtr == nullptr);
TestAssert::IsTrue(nullptr == swarmPtr);
}
TestAssert::IsTrue(deleted);
}
TestAssert::IsTrue(swarmPtr == nullptr);
TestAssert::IsTrue(nullptr == swarmPtr);
}
TestAssert::IsTrue(deleted);
}
#if defined(DEBUG) && defined(TEST_BAD_INHERITANCE1)
TESTMETHOD_REQUIRES_SEH(ObjectFixedSwarm_BadInheritance1)
{
TestAssert::ExpectVEC([&]() noexcept
{
// You will see a memory leak here because we cannot destroy object correctly.
Mso::Swarm::Make<BadSwarmMember1>();
});
}
TESTMETHOD_REQUIRES_SEH(ObjectFixedSwarm_BadInheritance1)
{
TestAssert::ExpectVEC([&]() noexcept {
// You will see a memory leak here because we cannot destroy object correctly.
Mso::Swarm::Make<BadSwarmMember1>();
});
}
#endif
};

Просмотреть файл

@ -14,96 +14,87 @@
// Special test allocator that cannot allocate memory and returns nullptr.
struct BadMakeAllocator
{
static void* Allocate(size_t /*size*/) noexcept
{
return nullptr;
}
static void* Allocate(size_t /*size*/) noexcept
{
return nullptr;
}
static void Deallocate(void* /*buffer*/) noexcept
{
}
static void Deallocate(void* /*buffer*/) noexcept {}
};
using BadAllocSimpleRefCount = Mso::SimpleRefCountPolicy<Mso::DefaultRefCountedDeleter, BadMakeAllocator>;
using BadAllocWeakRefCount = Mso::WeakRefCountPolicy<Mso::DefaultRefCountedDeleter, BadMakeAllocator>;
//=============================================================================
// StatefulMakeAllocator helps testing stateful allocators
//=============================================================================
struct IMyMemHeap
{
virtual void* Alloc(size_t size) noexcept = 0;
virtual void Free(void* ptr) noexcept = 0;
virtual void* Alloc(size_t size) noexcept = 0;
virtual void Free(void* ptr) noexcept = 0;
};
struct MyMemHeap : public IMyMemHeap
{
MyMemHeap(bool& allocCalled, bool& freeCalled) noexcept
: m_allocCalled(allocCalled)
, m_freeCalled(freeCalled)
{
}
MyMemHeap(bool& allocCalled, bool& freeCalled) noexcept : m_allocCalled(allocCalled), m_freeCalled(freeCalled) {}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(MyMemHeap);
virtual void* Alloc(size_t size) noexcept override
{
m_allocCalled = true;
return Mso::Memory::AllocateEx(size, Mso::Memory::AllocFlags::ShutdownLeak);
}
DECLARE_COPYCONSTR_AND_ASSIGNMENT(MyMemHeap);
virtual void Free(void* ptr) noexcept override
{
m_freeCalled = true;
Mso::Memory::Free(ptr);
}
virtual void* Alloc(size_t size) noexcept override
{
m_allocCalled = true;
return Mso::Memory::AllocateEx(size, Mso::Memory::AllocFlags::ShutdownLeak);
}
virtual void Free(void* ptr) noexcept override
{
m_freeCalled = true;
Mso::Memory::Free(ptr);
}
private:
bool& m_allocCalled;
bool& m_freeCalled;
bool& m_allocCalled;
bool& m_freeCalled;
};
struct StatefulMakeAllocator
{
static const size_t HeaderSize = 8; // To make sure that we can store a pointer and to have 8 byte alignment for object.
static const size_t HeaderSize =
8; // To make sure that we can store a pointer and to have 8 byte alignment for object.
static void* Allocate(size_t size, IMyMemHeap* memHeap) noexcept
{
size_t bufferSize = size + HeaderSize;
void* buffer = memHeap->Alloc(bufferSize);
*reinterpret_cast<IMyMemHeap**>(buffer) = memHeap;
return static_cast<uint8_t*>(buffer) + HeaderSize;
}
static void* Allocate(size_t size, IMyMemHeap* memHeap) noexcept
{
size_t bufferSize = size + HeaderSize;
void* buffer = memHeap->Alloc(bufferSize);
*reinterpret_cast<IMyMemHeap**>(buffer) = memHeap;
return static_cast<uint8_t*>(buffer) + HeaderSize;
}
static void Deallocate(void* ptr) noexcept
{
void* buffer = static_cast<uint8_t*>(ptr) - HeaderSize;
IMyMemHeap* memHeap = *reinterpret_cast<IMyMemHeap**>(buffer);
memHeap->Free(buffer);
}
static void Deallocate(void* ptr) noexcept
{
void* buffer = static_cast<uint8_t*>(ptr) - HeaderSize;
IMyMemHeap* memHeap = *reinterpret_cast<IMyMemHeap**>(buffer);
memHeap->Free(buffer);
}
};
using StatefulAllocSimpleRefCount = Mso::SimpleRefCountPolicy<Mso::DefaultRefCountedDeleter, StatefulMakeAllocator>;
using StatefulAllocWeakRefCount = Mso::WeakRefCountPolicy<Mso::DefaultRefCountedDeleter, StatefulMakeAllocator>;
//=============================================================================
// BadStatefulAllocator helps testing stateful allocators that may return
// BadStatefulAllocator helps testing stateful allocators that may return
// null from Allocate method.
//=============================================================================
struct BadStatefulAllocator
{
static void* Allocate(size_t /*size*/, IMyMemHeap* /*memHeap*/) noexcept
{
return nullptr;
}
static void* Allocate(size_t /*size*/, IMyMemHeap* /*memHeap*/) noexcept
{
return nullptr;
}
static void Deallocate(void* /*ptr*/) noexcept
{
}
static void Deallocate(void* /*ptr*/) noexcept {}
};
using BadStatefulAllocSimpleRefCount = Mso::SimpleRefCountPolicy<Mso::DefaultRefCountedDeleter, BadStatefulAllocator>;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -27,7 +27,8 @@ MSO_STRUCT_GUID(IUnknown, "00000000-0000-0000-C000-000000000046")
#define FACILITY_WIN32 7
#define __HRESULT_FROM_WIN32(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000)))
#define __HRESULT_FROM_WIN32(x) \
((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT)(((x)&0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000)))
#define HRESULT_FROM_WIN32(x) __HRESULT_FROM_WIN32(x)
#ifndef __LP64__
@ -36,18 +37,18 @@ typedef long HRESULT;
typedef int HRESULT;
#endif
#ifndef __GNUC__
#define STDMETHODCALLTYPE __stdcall
#define STDMETHODCALLTYPE __stdcall
#else
#define STDMETHODCALLTYPE
#endif
#define STDMETHOD(method) virtual HRESULT STDMETHODCALLTYPE method
#define STDMETHOD_(type,method) virtual type STDMETHODCALLTYPE method
#define STDMETHODIMP HRESULT STDMETHODCALLTYPE
#define STDMETHODIMP_(type) type STDMETHODCALLTYPE
#define STDMETHODIMPNOTHROW COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE
#define STDMETHODIMPNOTHROW_(type) COM_DECLSPEC_NOTHROW type STDMETHODCALLTYPE
#define STDMETHOD(method) virtual HRESULT STDMETHODCALLTYPE method
#define STDMETHOD_(type, method) virtual type STDMETHODCALLTYPE method
#define STDMETHODIMP HRESULT STDMETHODCALLTYPE
#define STDMETHODIMP_(type) type STDMETHODCALLTYPE
#define STDMETHODIMPNOTHROW COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE
#define STDMETHODIMPNOTHROW_(type) COM_DECLSPEC_NOTHROW type STDMETHODCALLTYPE
#define S_OK ((HRESULT)0L)
#define S_OK ((HRESULT)0L)
#define S_FALSE ((HRESULT)1L)
#define ERROR_INSUFFICIENT_BUFFER 122L
@ -82,9 +83,9 @@ MSO_STRUCT_GUID(IUnknown, "00000000-0000-0000-C000-000000000046")
#endif
struct IUnknown
{
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) = 0;
virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) = 0;
virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
};
#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
/**
Support for multi-platform GUID implementation.
Support for multi-platform GUID implementation.
*/
#pragma once
#ifndef LIBLET_PLATFORMADAPTERS_MSOGUID_H
@ -18,17 +18,17 @@
MSO_STRUCT_GUID or MSO_CLASS_GUID are used to associate a GUID with a type in platform independent way:
MSO_STRUCT_GUID(IMyInterface, "8665E4CE-50ED-4C12-A96D-13BD1432C219")
struct DECLSPEC_NOVTABLE IMyInterface : IBaseInterface
{
virtual ReturnType1 Method1() = 0;
virtual ReturnType2 Method1(ArgType1 arg1) = 0;
};
MSO_STRUCT_GUID(IMyInterface, "8665E4CE-50ED-4C12-A96D-13BD1432C219")
struct DECLSPEC_NOVTABLE IMyInterface : IBaseInterface
{
virtual ReturnType1 Method1() = 0;
virtual ReturnType2 Method1(ArgType1 arg1) = 0;
};
MSO_CLASS_GUID(MyClass, "8665E4CE-50ED-4C12-A96D-13BD1432C219")
class MyClass : public IBaseInterface
{
};
MSO_CLASS_GUID(MyClass, "8665E4CE-50ED-4C12-A96D-13BD1432C219")
class MyClass : public IBaseInterface
{
};
NOTE: GUID must not use curly braces around it.
@ -36,10 +36,10 @@ NOTE: GUID must not use curly braces around it.
To retrieve GUID for a type use the __uuidof():
const GUID& myTypeGuid = __uuidof(MyType);
const GUID& myTypeGuid = __uuidof(MyType);
template <typename T, typename TSource>
T* qi_cast(TSource* s, const GUID& riid = __uuidof(T));
template <typename T, typename TSource>
T* qi_cast(TSource* s, const GUID& riid = __uuidof(T));
The __uuidof() is a Visual C++ specific operator that accepts a variety of inputs.
@ -50,12 +50,11 @@ This macro can only accept a type. We recommend to change code that uses an expr
- Replace __uuidof(expr) with __uuidof_expr(expr)
*/
/**
++ FAQ ++
Q: Why to use macro to associate a GUID with a type?
A: There is no C++ standard way to assign a GUID attribute to a type. Any solution that we provide at this point
A: There is no C++ standard way to assign a GUID attribute to a type. Any solution that we provide at this point
is a workaround to this limitation. Macro can hide any such platform specific workarounds.
Q: How does it work?
@ -63,7 +62,8 @@ A: For Visual C++ we use the __declspec(uuid) attribute.
For Clang we use an overload of a function MsoGetGuid(T*).
This function is used to initialize GuidOf<T>::Value static field returned by __uuidof() macro.
The main benefit of using function is that it allows us to associate GUID with a type in the type's namespace.
The function is discovered with help of C++ argument-dependent name lookup http://en.wikipedia.org/wiki/Argument_dependent_name_lookup .
The function is discovered with help of C++ argument-dependent name lookup
http://en.wikipedia.org/wiki/Argument_dependent_name_lookup .
Q: Why not to use a template specialization for GUID association?
A: This is what we tried first, but a template cannot be specialized in a different namespace. In our case we want to
@ -74,49 +74,51 @@ A: See the msoGuidDetails.h
*/
namespace Mso
{
namespace Mso {
OACR_WARNING_PUSH
OACR_WARNING_DISABLE(VAR_IN_HEADER, "False Positive for variable in header with template. (see Bug 1689514) ")
/// To return false in TypeHasGuid<T>::Value if type has no GUID defined by MSO_STRUCT_GUID/MSO_CLASS_GUID
template <typename T> ::Mso::Details::GuidUtils::FalseType MsoTypeHasGuid(T*);
template <typename T>
::Mso::Details::GuidUtils::FalseType MsoTypeHasGuid(T*);
/// Type traits to check if type has a GUID defined by MSO_STRUCT_GUID/MSO_CLASS_GUID
template <typename T>
struct TypeHasGuid
{
typedef decltype(MsoTypeHasGuid(static_cast<T*>(nullptr))) Type;
enum { Value = Type::Value };
typedef decltype(MsoTypeHasGuid(static_cast<T*>(nullptr))) Type;
enum
{
Value = Type::Value
};
};
/**
This template is to address an issue with NDK linker which cannot properly compile
a template that uses a pointer to GUID as a template parameter.
E.g. the " struct TCntQIPtr<T, const GUID* piid = &__uuidof(T)> " will fail to compile
because linker cannot find a static field which we use for __uuidof(T) implementation.
Instead, this line must be changed to " struct TCntQIPtr<T, const GUID* piid = nullptr> "
and we should use Mso::ResolveGuidPtr<T, piid>::Guid instead of piid inside of the template.
The Mso::ResolveGuidPtr has a specialization for nullptr that does all the "magic".
This template is to address an issue with NDK linker which cannot properly compile
a template that uses a pointer to GUID as a template parameter.
E.g. the " struct TCntQIPtr<T, const GUID* piid = &__uuidof(T)> " will fail to compile
because linker cannot find a static field which we use for __uuidof(T) implementation.
Instead, this line must be changed to " struct TCntQIPtr<T, const GUID* piid = nullptr> "
and we should use Mso::ResolveGuidPtr<T, piid>::Guid instead of piid inside of the template.
The Mso::ResolveGuidPtr has a specialization for nullptr that does all the "magic".
*/
template <typename T, const GUID* guidPtr>
struct ResolveGuidPtr
{
static const GUID* Guid;
static const GUID* Guid;
};
template <typename T, const GUID* guidPtr>
const GUID* ResolveGuidPtr<T, guidPtr>::Guid = guidPtr;
template <typename T>
struct ResolveGuidPtr<T, static_cast<const GUID *>(nullptr)>
struct ResolveGuidPtr<T, static_cast<const GUID*>(nullptr)>
{
static const GUID* Guid;
static const GUID* Guid;
};
template <typename T>
const GUID* ResolveGuidPtr<T, static_cast<const GUID *>(nullptr)>::Guid = &__uuidof(T);
const GUID* ResolveGuidPtr<T, static_cast<const GUID*>(nullptr)>::Guid = &__uuidof(T);
OACR_WARNING_POP
} // namespace Mso

Просмотреть файл

@ -20,32 +20,36 @@ See the msoGuid.h for the usage guidelines.
#include <compilerAdapters/compilerFeatures.h>
#if MS_TARGET_POSIX
# include <guiddef.h>
#include <guiddef.h>
#endif // MS_TARGET_POSIX
// Private macro for MSO_STRUCT_GUID/MSO_CLASS_GUID macro implementations.
#if COMPILER_SUPPORTS_UUID // For Visual C++
# define MSO_GUID_IMPL(keyword, type, guidString) \
static_assert(sizeof(guidString) == 37, "GUID string must have the following format: \"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\""); \
keyword __declspec(uuid(guidString)) type; \
__pragma(warning(suppress:25352)) \
extern "C++" ::Mso::Details::GuidUtils::TrueType MsoTypeHasGuid(type*);
#define MSO_GUID_IMPL(keyword, type, guidString) \
static_assert( \
sizeof(guidString) == 37, \
"GUID string must have the following format: \"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\""); \
keyword __declspec(uuid(guidString)) type; \
__pragma(warning(suppress : 25352)) extern "C++" ::Mso::Details::GuidUtils::TrueType MsoTypeHasGuid(type*);
#else // For Clang
# define MSO_GUID_IMPL(keyword, type, guidString) \
keyword type; \
extern "C++" inline constexpr GUID MsoGetGuid(type*) noexcept { return ::Mso::Details::GuidUtils::StringToGuid(guidString); } \
extern "C++" ::Mso::Details::GuidUtils::TrueType MsoTypeHasGuid(type*);
#define MSO_GUID_IMPL(keyword, type, guidString) \
keyword type; \
extern "C++" inline constexpr GUID MsoGetGuid(type*) noexcept \
{ \
return ::Mso::Details::GuidUtils::StringToGuid(guidString); \
} \
extern "C++" ::Mso::Details::GuidUtils::TrueType MsoTypeHasGuid(type*);
#endif // COMPILER_SUPPORTS_UUID
/// Associates type with a GUID. To be used before type declaration.
#define MSO_STRUCT_GUID(type, guidString) MSO_GUID_IMPL(struct, type, guidString)
#define MSO_CLASS_GUID( type, guidString) MSO_GUID_IMPL(class, type, guidString)
#define MSO_CLASS_GUID(type, guidString) MSO_GUID_IMPL(class, type, guidString)
#define MSO_GUID(type, guidString) MSO_STRUCT_GUID(type, guidString)
//==========================================================================================================================
// GUID token is a special type that can be used to define and access GUIDs using only header files.
// For example, to define a GUID in a header file without declaring a type, you can write:
//
//
// MSO_DEFINE_GUID_TOKEN(MyToken, "d807b970-b875-4491-a88e-99038236d60f")
//
// Then to access the GUID:
@ -74,29 +78,26 @@ See the msoGuid.h for the usage guidelines.
//
// Each alias will have its own unique GUID associated with it.
// To get GUID of an alias:
//
//
// const GUID& intGuid = __uuidof(MyIntTemplate::GuidType);
// const GUID& floatGuid = __uuidof(MyFloatTemplate::GuidType);
//
/// Gets type from the GUID token.
#define MSO_GET_GUID_TOKEN_TYPE(guidToken) \
guidToken##_GuidToken
#define MSO_GET_GUID_TOKEN_TYPE(guidToken) guidToken##_GuidToken
/// Defines a GUID token type.
#define MSO_DEFINE_GUID_TOKEN(guidToken, guidString) \
MSO_STRUCT_GUID(MSO_GET_GUID_TOKEN_TYPE(guidToken), guidString)
/// Defines a GUID token type.
#define MSO_DEFINE_GUID_TOKEN(guidToken, guidString) MSO_STRUCT_GUID(MSO_GET_GUID_TOKEN_TYPE(guidToken), guidString)
/// A macro to access GUID by a token defined by MSO_DEFINE_GUID_TOKEN
#define __uuidof_token(guidToken) \
__uuidof(MSO_GET_GUID_TOKEN_TYPE(guidToken))
#define __uuidof_token(guidToken) __uuidof(MSO_GET_GUID_TOKEN_TYPE(guidToken))
//==========================================================================================================================
/// Replacement for the MIDL_INTERFACE based on MSO_STRUCT_GUID. To be used in MIDL generated files.
#define MIDL_INTERFACE2(type, guidString) \
MSO_STRUCT_GUID(type, guidString) \
struct DECLSPEC_NOVTABLE
MSO_STRUCT_GUID(type, guidString) \
struct DECLSPEC_NOVTABLE
// __uuidof(type) implementation for Clang. In VC++ we use the native __uuidof() operator.
#if !COMPILER_SUPPORTS_UUID
@ -105,64 +106,64 @@ See the msoGuid.h for the usage guidelines.
#endif
/// A macro to be used instead of __uuidof(expr). For types use __uuidof(type). E.g. __uuidof_expr(this).
#define __uuidof_expr(expr) \
__uuidof(typename std::remove_pointer<typename std::decay<decltype(expr)>::type>::type)
#define __uuidof_expr(expr) __uuidof(typename std::remove_pointer<typename std::decay<decltype(expr)>::type>::type)
// We must explicitly set the C++ extern context for the MIDL generated files where it is set to "C".
extern "C++"
{
namespace Mso { namespace Details { namespace GuidUtils {
// To indicate that type has or does not have GUID. We do not want to add dependency on "type_traits"
struct TrueType { enum { Value = true }; };
struct FalseType { enum { Value = false }; };
namespace Mso { namespace Details { namespace GuidUtils {
// To indicate that type has or does not have GUID. We do not want to add dependency on "type_traits"
struct TrueType
{
enum
{
Value = true
};
};
struct FalseType
{
enum
{
Value = false
};
};
#if !COMPILER_SUPPORTS_UUID
/// Default implementation of the MsoGetGuid. It is used when we cannot find type specific implementation
/// provided by MSO_STRUCT_GUID/MSO_CLASS_GUID macro.
template <typename T>
inline GUID MsoGetGuid(T*) noexcept
{
static_assert(sizeof(T) == 0, "GUID is undefined for the type T");
return {};
}
/// Default implementation of the MsoGetGuid. It is used when we cannot find type specific implementation
/// provided by MSO_STRUCT_GUID/MSO_CLASS_GUID macro.
template <typename T>
inline GUID MsoGetGuid(T*) noexcept
{
static_assert(sizeof(T) == 0, "GUID is undefined for the type T");
return {};
}
/// Statically associates a GUID with a type. It is used by __uuidof() macro implementation.
template <typename T>
struct GuidOf
{
static const GUID Value;
};
/// Statically associates a GUID with a type. It is used by __uuidof() macro implementation.
template <typename T>
struct GuidOf
{
static const GUID Value;
};
template <typename T>
const GUID GuidOf<T>::Value = MsoGetGuid(static_cast<T*>(nullptr));
template <typename T>
const GUID GuidOf<T>::Value = MsoGetGuid(static_cast<T*>(nullptr));
/// To represent a GUID string without curly braces: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX"
typedef char GuidString[37];
/// To represent a GUID string without curly braces: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX"
typedef char GuidString[37];
/// Converts a hexadecimal ASCII character to an unsigned char.
constexpr const unsigned char H2U[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
/// Converts a hexadecimal ASCII character to an unsigned char.
constexpr const unsigned char H2U[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
#if __clang__
#pragma clang diagnostic push
@ -170,26 +171,24 @@ constexpr const unsigned char H2U[256] = {
#pragma clang diagnostic ignored "-Wchar-subscripts"
#endif // __clang__
/// Converts string to a GUID at compile time. Expected format: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX"
constexpr GUID StringToGuid(const GuidString& g) noexcept
{
return
{
static_cast<unsigned int>((H2U[g[0]] << 28) | (H2U[g[1]] << 24) | (H2U[g[2]] << 20) | (H2U[g[3]] << 16) | (H2U[g[4]] << 12) | (H2U[g[5]] << 8) | (H2U[g[6]] << 4) | H2U[g[7]]),
static_cast<unsigned short>((H2U[g[9]] << 12) | (H2U[g[10]] << 8) | (H2U[g[11]] << 4) | H2U[g[12]]),
static_cast<unsigned short>((H2U[g[14]] << 12) | (H2U[g[15]] << 8) | (H2U[g[16]] << 4) | H2U[g[17]]),
{
static_cast<unsigned char>((H2U[g[19]] << 4) | H2U[g[20]]),
static_cast<unsigned char>((H2U[g[21]] << 4) | H2U[g[22]]),
static_cast<unsigned char>((H2U[g[24]] << 4) | H2U[g[25]]),
static_cast<unsigned char>((H2U[g[26]] << 4) | H2U[g[27]]),
static_cast<unsigned char>((H2U[g[28]] << 4) | H2U[g[29]]),
static_cast<unsigned char>((H2U[g[30]] << 4) | H2U[g[31]]),
static_cast<unsigned char>((H2U[g[32]] << 4) | H2U[g[33]]),
static_cast<unsigned char>((H2U[g[34]] << 4) | H2U[g[35]])
}
};
}
/// Converts string to a GUID at compile time. Expected format: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX"
constexpr GUID StringToGuid(const GuidString& g) noexcept
{
return {
static_cast<unsigned int>(
(H2U[g[0]] << 28) | (H2U[g[1]] << 24) | (H2U[g[2]] << 20) | (H2U[g[3]] << 16) | (H2U[g[4]] << 12)
| (H2U[g[5]] << 8) | (H2U[g[6]] << 4) | H2U[g[7]]),
static_cast<unsigned short>((H2U[g[9]] << 12) | (H2U[g[10]] << 8) | (H2U[g[11]] << 4) | H2U[g[12]]),
static_cast<unsigned short>((H2U[g[14]] << 12) | (H2U[g[15]] << 8) | (H2U[g[16]] << 4) | H2U[g[17]]),
{static_cast<unsigned char>((H2U[g[19]] << 4) | H2U[g[20]]),
static_cast<unsigned char>((H2U[g[21]] << 4) | H2U[g[22]]),
static_cast<unsigned char>((H2U[g[24]] << 4) | H2U[g[25]]),
static_cast<unsigned char>((H2U[g[26]] << 4) | H2U[g[27]]),
static_cast<unsigned char>((H2U[g[28]] << 4) | H2U[g[29]]),
static_cast<unsigned char>((H2U[g[30]] << 4) | H2U[g[31]]),
static_cast<unsigned char>((H2U[g[32]] << 4) | H2U[g[33]]),
static_cast<unsigned char>((H2U[g[34]] << 4) | H2U[g[35]])}};
}
#if __clang__
#pragma clang diagnostic pop
@ -197,7 +196,7 @@ constexpr GUID StringToGuid(const GuidString& g) noexcept
#endif // !COMPILER_SUPPORTS_UUID
} } } // namespace Mso::Details::GuidUtils
}}} // namespace Mso::Details::GuidUtils
} // extern "C++"
#endif // LIBLET_PLATFORMADAPTERS_MSOGUIDDETAILS_H

Просмотреть файл

@ -19,7 +19,7 @@
#ifndef _BYTE_DEFINED
#define _BYTE_DEFINED
typedef unsigned char BYTE;//__clang__ : conflict with libc++17 byte definition
typedef unsigned char BYTE; //__clang__ : conflict with libc++17 byte definition
#endif // !_BYTE_DEFINED
#ifndef _WORD_DEFINED
@ -39,7 +39,7 @@ typedef unsigned int UINT;
#ifndef _LONG_DEFINED
#define _LONG_DEFINED
typedef int32_t LONG; //MS_TARGET_APPLE LONG as a Windows type must stay 32-bit even in 64-bit code
typedef int32_t LONG; // MS_TARGET_APPLE LONG as a Windows type must stay 32-bit even in 64-bit code
#endif // !_LONG_DEFINED
#ifndef _ULONG_DEFINED
@ -49,7 +49,7 @@ typedef uint32_t ULONG;
#ifndef _BOOL_DEFINED
#define _BOOL_DEFINED
typedef int32_t BOOL; //MS_TARGET_APPLE
typedef int32_t BOOL; // MS_TARGET_APPLE
#define TRUE 1
#define FALSE 0
#endif // !_BOOL_DEFINED
@ -71,7 +71,7 @@ typedef UINT_PTR WPARAM;
#ifndef _DWORD_DEFINED
#define _DWORD_DEFINED
typedef uint32_t DWORD; //MS_TARGET_APPLE DWORD as a Windows type must stay 32-bit even in 64-bit code
typedef uint32_t DWORD; // MS_TARGET_APPLE DWORD as a Windows type must stay 32-bit even in 64-bit code
#endif // !_DWORD_DEFINED
#ifndef _LPARAM_DEFINED

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше