From 5dfe25c4f4997da2d7a23bdc80c2438e72d9813a Mon Sep 17 00:00:00 2001 From: Zihan Chen Date: Tue, 17 Dec 2019 05:18:04 -0800 Subject: [PATCH] Update release --- Import/GacUI.h | 4 +- Import/Vlpp.cpp | 275 ++++++++++-- Import/Vlpp.h | 960 +++++++++++++++++++++++----------------- Import/VlppReflection.h | 4 +- 4 files changed, 793 insertions(+), 450 deletions(-) diff --git a/Import/GacUI.h b/Import/GacUI.h index a0613fe3..d67a155d 100644 --- a/Import/GacUI.h +++ b/Import/GacUI.h @@ -8279,7 +8279,7 @@ namespace vl struct QueryServiceHelper; template - struct QueryServiceHelper::YesNoType> + struct QueryServiceHelper::YesNoType> { static WString GetIdentifier() { @@ -8288,7 +8288,7 @@ namespace vl }; template - struct QueryServiceHelper::YesNoType> + struct QueryServiceHelper::YesNoType> { static WString GetIdentifier() { diff --git a/Import/Vlpp.cpp b/Import/Vlpp.cpp index 75569cb9..fe92a47a 100644 --- a/Import/Vlpp.cpp +++ b/Import/Vlpp.cpp @@ -1189,6 +1189,8 @@ PartialOrderingProcessor /*********************************************************************** .\UNITTEST\UNITTEST.CPP ***********************************************************************/ +#ifdef VCZH_MSVC +#endif namespace vl { @@ -1200,56 +1202,269 @@ namespace vl UnitTest ***********************************************************************/ - void UnitTest::PrintMessage(const WString& string) + namespace execution_impl { - Console::SetColor(false, true, false, true); - Console::WriteLine(string); - Console::SetColor(true, true, true, false); - } + struct UnitTestLink + { + const char* fileName; + UnitTestFileProc testProc = nullptr; + UnitTestLink* next = nullptr; + }; + UnitTestLink* testHead = nullptr; + UnitTestLink** testTail = &testHead; + + enum class UnitTestContextKind + { + File, + Category, + Case, + }; - void UnitTest::PrintInfo(const WString& string) - { - Console::SetColor(true, true, true, true); - Console::WriteLine(string); - Console::SetColor(true, true, true, false); + struct UnitTestContext + { + UnitTestContext* parent = nullptr; + WString indentation; + UnitTestContextKind kind = UnitTestContextKind::File; + bool failed = false; + }; + + UnitTestContext* testContext = nullptr; + vint totalFiles = 0; + vint passedFiles = 0; + vint totalCases = 0; + vint passedCases = 0; + bool suppressFailure = false; + + template + void RecordFailure(TMessage errorMessage) + { + UnitTest::PrintMessage(errorMessage, UnitTest::MessageKind::Error); + auto current = testContext; + while (current) + { + current->failed = true; + current = current->parent; + } + } + + template + void SuppressCppFailure(TCallback&& callback) + { + try + { + callback(); + } + catch (const UnitTestAssertError& e) + { + RecordFailure(e.message); + } + catch (const UnitTestConfigError& e) + { + RecordFailure(e.message); + } + catch (const Error& e) + { + RecordFailure(e.Description()); + } + catch (const Exception& e) + { + RecordFailure(e.Message()); + } + catch (...) + { + RecordFailure(L"Unknown exception occurred!"); + } + } + + template + void SuppressCFailure(TCallback&& callback) + { +#ifdef VCZH_MSVC + __try + { + SuppressCppFailure(ForwardValue(callback)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + RecordFailure(L"Runtime exception occurred!"); + } +#else + SuppressCppFailure(callback); +#endif + } + + template + void ExecuteAndSuppressFailure(TCallback&& callback) + { + if (suppressFailure) + { + SuppressCFailure(ForwardValue(callback)); + } + else + { + callback(); + } + } } + using namespace execution_impl; - void UnitTest::PrintError(const WString& string) + void UnitTest::PrintMessage(const WString& string, MessageKind kind) { - Console::SetColor(true, false, false, true); - Console::WriteLine(string); + if (kind != MessageKind::Error && !testContext) + { + throw UnitTestConfigError(L"Cannot print message when unit test is not running."); + } + + switch (kind) + { + case MessageKind::Error: + Console::SetColor(true, false, false, true); + break; + case MessageKind::Info: + Console::SetColor(true, true, true, true); + break; + case MessageKind::File: + Console::SetColor(true, false, true, true); + break; + case MessageKind::Category: + Console::SetColor(true, true, false, true); + break; + case MessageKind::Case: + Console::SetColor(false, true, false, true); + break; + } + Console::WriteLine((testContext ? testContext->indentation : L"") + string); Console::SetColor(true, true, true, false); } - struct UnitTestLink +#ifdef VCZH_MSVC + int UnitTest::RunAndDisposeTests(int argc, wchar_t* argv[]) +#else + int UnitTest::RunAndDisposeTests(int argc, char* argv[]) +#endif { - UnitTest::TestProc testProc = nullptr; - UnitTestLink* next = nullptr; - }; - UnitTestLink* testHead = nullptr; - UnitTestLink** testTail = &testHead; + if (argc < 3) + { + if (argc == 2) + { +#ifdef VCZH_MSVC + WString option = argv[1]; +#else + WString option = atow(argv[1]); +#endif + if (option == L"/D") + { + suppressFailure = false; + } + else if (option == L"/R") + { + suppressFailure = true; + } + else + { + goto PRINT_USAGE; + } + } + else + { +#ifdef VCZH_MSVC + if (IsDebuggerPresent()) + { + suppressFailure = false; + } + else + { + suppressFailure = true; + } +#else + suppressFailure = true; +#endif + } + + auto current = testHead; + testHead = nullptr; + testTail = nullptr; + + UnitTestContext context; + testContext = &context; + totalFiles = 0; + passedFiles = 0; + totalCases = 0; + passedCases = 0; + + if (suppressFailure) + { + PrintMessage(L"Failures are suppressed.", MessageKind::Info); + } + else + { + PrintMessage(L"Failures are not suppressed.", MessageKind::Info); + } + + while (current) + { + context.failed = false; + PrintMessage(atow(current->fileName), MessageKind::File); + context.indentation = L" "; + ExecuteAndSuppressFailure(current->testProc); + if (!testContext->failed) passedFiles++; + totalFiles++; + context.indentation = L""; + auto temp = current; + current = current->next; + delete temp; + } - void UnitTest::PushTest(TestProc testProc) + bool passed = totalFiles == passedFiles; + auto messageKind = passed ? MessageKind::Case : MessageKind::Error; + PrintMessage(L"Passed test files: " + itow(passedFiles) + L"/" + itow(totalFiles), messageKind); + PrintMessage(L"Passed test cases: " + itow(passedCases) + L"/" + itow(totalCases), messageKind); + testContext = nullptr; + return passed ? 0 : 1; + } + PRINT_USAGE: + PrintMessage(L"Usage: [/D | /R]", MessageKind::Error); + return 1; + } + + void UnitTest::RegisterTestFile(const char* fileName, UnitTestFileProc testProc) { auto link = new UnitTestLink; + link->fileName = fileName; link->testProc = testProc; *testTail = link; testTail = &link->next; } - void UnitTest::RunAndDisposeTests() + void UnitTest::RunCategoryOrCase(const WString& description, bool isCategory, Func&& callback) { - auto current = testHead; - testHead = nullptr; - testTail = nullptr; - - while (current) + if (!testContext) throw UnitTestConfigError(L"TEST_CATEGORY is not allowed to execute outside of TEST_FILE."); + if (testContext->kind == UnitTestContextKind::Case) throw UnitTestConfigError( + isCategory ? + L"TEST_CATEGORY is not allowed to execute inside TEST_CASE" : + L"TEST_CASE is not allowed to execute inside TEST_CASE"); + + PrintMessage(description, (isCategory ? MessageKind::Category : MessageKind::Case)); + + UnitTestContext context; + context.parent = testContext; + context.indentation = testContext->indentation + L" "; + context.kind = isCategory ? UnitTestContextKind::Category : UnitTestContextKind::Case; + + testContext = &context; + ExecuteAndSuppressFailure(callback); + if (!isCategory) { - current->testProc(); - auto temp = current; - current = current->next; - delete temp; + if (!testContext->failed) passedCases++; + totalCases++; } + testContext = context.parent; + } + + void UnitTest::EnsureLegalToAssert() + { + if (!testContext) throw UnitTestConfigError(L"Assertion is not allowed to execute outside of TEST_CASE."); + if (testContext->kind != UnitTestContextKind::Case) throw UnitTestConfigError(L"Assertion is not allowed to execute outside of TEST_CASE."); } } } diff --git a/Import/Vlpp.h b/Import/Vlpp.h index 00615f00..ade8edd5 100644 --- a/Import/Vlpp.h +++ b/Import/Vlpp.h @@ -84,9 +84,9 @@ Framework::Basic namespace vl { -/*********************************************************************** -x86 and x64 Compatbility -***********************************************************************/ + /*********************************************************************** + x86 and x64 Compatbility + ***********************************************************************/ #if defined VCZH_MSVC /// 1-byte signed integer. @@ -168,9 +168,9 @@ x86 and x64 Compatbility #endif #endif -/*********************************************************************** -Basic Types -***********************************************************************/ + /*********************************************************************** + Basic Types + ***********************************************************************/ class NotCopyable { @@ -180,7 +180,7 @@ Basic Types public: NotCopyable(); }; - + /// Base type of all errors. An error is an exception that you are not allowed to catch. Raising it means there is a fatal error in the code. class Error { @@ -193,9 +193,9 @@ Basic Types }; #if defined VCZH_MSVC || defined VCZH_GCC || defined _DEBUG - #define CHECK_ERROR(CONDITION,DESCRIPTION) do{if(!(CONDITION))throw Error(DESCRIPTION);}while(0) +#define CHECK_ERROR(CONDITION,DESCRIPTION) do{if(!(CONDITION))throw Error(DESCRIPTION);}while(0) #elif defined NDEBUG - #define CHECK_ERROR(CONDITION,DESCRIPTION) +#define CHECK_ERROR(CONDITION,DESCRIPTION) #endif #define CHECK_FAIL(DESCRIPTION) do{throw Error(DESCRIPTION);}while(0) @@ -204,10 +204,10 @@ Basic Types if(bool __scope_variable_flag__=true)\ for(TYPE VARIABLE = VALUE;__scope_variable_flag__;__scope_variable_flag__=false) -/*********************************************************************** -Type Traits -***********************************************************************/ - + /*********************************************************************** + Type Traits + ***********************************************************************/ + template struct RemoveReference { @@ -303,9 +303,9 @@ Type Traits { }; -/*********************************************************************** -Basic Types -***********************************************************************/ + /*********************************************************************** + Basic Types + ***********************************************************************/ /// Base type of all classes. class Object @@ -313,7 +313,7 @@ Basic Types public: virtual ~Object(); }; - + /// Type for storing a value to wherever requiring a [T:vl.Ptr`1] to [T:vl.Object]. /// Type of the value. template @@ -328,52 +328,52 @@ Basic Types :object(_object) { } - + /// Box a movable value. /// The value to box. ObjectBox(T&& _object) :object(MoveValue(_object)) { } - + /// Copy a box. /// The box. ObjectBox(const ObjectBox& value) :object(value.object) { } - + /// Move a box. /// The box. ObjectBox(ObjectBox&& value) :object(MoveValue(value.object)) { } - + /// Box a value. /// The boxed value. /// The value to box. ObjectBox& operator=(const T& _object) { - object=_object; + object = _object; return *this; } - + /// Copy a box. /// The boxed value. /// The box. ObjectBox& operator=(const ObjectBox& value) { - object=value.object; + object = value.object; return *this; } - + /// Move a box. /// The boxed value. /// The box. ObjectBox& operator=(ObjectBox&& value) { - object=MoveValue(value.object); + object = MoveValue(value.object); return *this; } @@ -405,7 +405,7 @@ Basic Types :object(new T(value)) { } - + /// Create a non-null value. /// The value to move. Nullable(T&& value) @@ -416,75 +416,75 @@ Basic Types /// Copy a nullable value. /// The nullable value to copy. Nullable(const Nullable& nullable) - :object(nullable.object?new T(*nullable.object):0) + :object(nullable.object ? new T(*nullable.object) : 0) { } - + /// Move a nullable value. /// The nullable value to move. Nullable(Nullable&& nullable) :object(nullable.object) { - nullable.object=0; + nullable.object = 0; } ~Nullable() { - if(object) + if (object) { delete object; - object=0; + object = 0; } } - + /// Create a non-null value. /// The created nullable value. /// The value to copy. Nullable& operator=(const T& value) { - if(object) + if (object) { delete object; - object=0; + object = 0; } - object=new T(value); + object = new T(value); return *this; } - + /// Copy a nullable value. /// The created nullable value. /// The nullable value to copy. Nullable& operator=(const Nullable& nullable) { - if(this!=&nullable) + if (this != &nullable) { - if(object) + if (object) { delete object; - object=0; + object = 0; } - if(nullable.object) + if (nullable.object) { - object=new T(*nullable.object); + object = new T(*nullable.object); } } return *this; } - + /// Move a nullable value. /// The created nullable value. /// The nullable value to move. Nullable& operator=(Nullable&& nullable) { - if(this!=&nullable) + if (this != &nullable) { - if(object) + if (object) { delete object; - object=0; + object = 0; } - object=nullable.object; - nullable.object=0; + object = nullable.object; + nullable.object = 0; } return *this; } @@ -493,24 +493,24 @@ Basic Types { return a.object - ?b.object - ?*a.object==*b.object - :false - :b.object - ?false - :true; + ? b.object + ? *a.object == *b.object + : false + : b.object + ? false + : true; } static vint Compare(const Nullable& a, const Nullable& b) { return a.object - ?b.object - ?(*a.object==*b.object?0:*a.object<*b.object?-1:1) - :1 - :b.object - ?-1 - :0; + ? b.object + ? (*a.object == *b.object ? 0 : *a.object < *b.object ? -1 : 1) + : 1 + : b.object + ? -1 + : 0; } bool operator==(const Nullable& nullable)const @@ -525,31 +525,31 @@ Basic Types bool operator<(const Nullable& nullable)const { - return Compare(*this, nullable)<0; + return Compare(*this, nullable) < 0; } bool operator<=(const Nullable& nullable)const { - return Compare(*this, nullable)<=0; + return Compare(*this, nullable) <= 0; } bool operator>(const Nullable& nullable)const { - return Compare(*this, nullable)>0; + return Compare(*this, nullable) > 0; } bool operator>=(const Nullable& nullable)const { - return Compare(*this, nullable)>=0; + return Compare(*this, nullable) >= 0; } /// Convert the nullable value to a bool value. /// Returns true if it is not null. operator bool()const { - return object!=0; + return object != 0; } - + /// Unbox the value. This operation will cause an access violation of it is null. /// The original value. const T& Value()const @@ -562,12 +562,12 @@ Basic Types union BinaryRetriver { T t; - char binary[sizeof(T)>minSize?sizeof(T):minSize]; + char binary[sizeof(T) > minSize ? sizeof(T) : minSize]; }; -/*********************************************************************** -Type Traits -***********************************************************************/ + /*********************************************************************** + Type Traits + ***********************************************************************/ /// Get the index type of a value for containers. /// Type of the value. @@ -593,31 +593,32 @@ Type Traits struct POD { /// Returns true if the type is a Plain-Old-Data type. - static const bool Result=false; + static const bool Result = false; }; - template<>struct POD{static const bool Result=true;}; - template<>struct POD{static const bool Result=true;}; - template<>struct POD{static const bool Result=true;}; - template<>struct POD{static const bool Result=true;}; - template<>struct POD{static const bool Result=true;}; - template<>struct POD{static const bool Result=true;}; - template<>struct POD{static const bool Result=true;}; - template<>struct POD{static const bool Result=true;}; - template<>struct POD{static const bool Result=true;}; - template<>struct POD{static const bool Result=true;}; - template<>struct POD{static const bool Result=true;}; - templatestruct POD{static const bool Result=true;}; - templatestruct POD{static const bool Result=true;}; - templatestruct POD{static const bool Result=true;}; - templatestruct POD{static const bool Result=POD::Result;}; - templatestruct POD{static const bool Result=POD::Result;}; - templatestruct POD{static const bool Result=POD::Result;}; - templatestruct POD{static const bool Result=POD::Result;}; - -/*********************************************************************** -Date and Time -***********************************************************************/ + template<>struct POD { static const bool Result = true; }; + template<>struct POD { static const bool Result = true; }; + template<>struct POD { static const bool Result = true; }; + template<>struct POD { static const bool Result = true; }; + template<>struct POD { static const bool Result = true; }; + template<>struct POD { static const bool Result = true; }; + template<>struct POD { static const bool Result = true; }; + template<>struct POD { static const bool Result = true; }; + template<>struct POD { static const bool Result = true; }; + template<>struct POD { static const bool Result = true; }; + template<>struct POD { static const bool Result = true; }; + templatestruct POD { static const bool Result = true; }; + templatestruct POD { static const bool Result = true; }; + templatestruct POD { static const bool Result = true; }; + templatestruct POD { static const bool Result = true; }; + templatestruct POD { static const bool Result = POD::Result; }; + templatestruct POD { static const bool Result = POD::Result; }; + templatestruct POD { static const bool Result = POD::Result; }; + templatestruct POD { static const bool Result = POD::Result; }; + + /*********************************************************************** + Date and Time + ***********************************************************************/ /// A type representing the combination of date and time. struct DateTime @@ -632,7 +633,7 @@ Date and Time vint milliseconds; vuint64_t totalMilliseconds; - + // in gcc, this will be mktime(t) * 1000 + gettimeofday().tv_usec / 1000 vuint64_t filetime; @@ -653,8 +654,8 @@ Date and Time /// The minute. /// The second. /// The millisecond. - static DateTime FromDateTime(vint _year, vint _month, vint _day, vint _hour=0, vint _minute=0, vint _second=0, vint _milliseconds=0); - + static DateTime FromDateTime(vint _year, vint _month, vint _day, vint _hour = 0, vint _minute = 0, vint _second = 0, vint _milliseconds = 0); + static DateTime FromFileTime(vuint64_t filetime); /// Create an empty date time value. @@ -675,18 +676,18 @@ Date and Time /// The delta in milliseconds. DateTime Backward(vuint64_t milliseconds); - bool operator==(const DateTime& value)const { return filetime==value.filetime; } - bool operator!=(const DateTime& value)const { return filetime!=value.filetime; } - bool operator<(const DateTime& value)const { return filetime(const DateTime& value)const { return filetime>value.filetime; } - bool operator>=(const DateTime& value)const { return filetime>=value.filetime; } + bool operator==(const DateTime& value)const { return filetime == value.filetime; } + bool operator!=(const DateTime& value)const { return filetime != value.filetime; } + bool operator<(const DateTime& value)const { return filetime < value.filetime; } + bool operator<=(const DateTime& value)const { return filetime <= value.filetime; } + bool operator>(const DateTime& value)const { return filetime > value.filetime; } + bool operator>=(const DateTime& value)const { return filetime >= value.filetime; } }; -/*********************************************************************** -Interface -***********************************************************************/ - + /*********************************************************************** + Interface + ***********************************************************************/ + /// Base type of all interfaces. All interface types are encouraged to be virtual inherited. class Interface : private NotCopyable { @@ -694,12 +695,12 @@ Interface virtual ~Interface(); }; -/*********************************************************************** -Type Traits -***********************************************************************/ + /*********************************************************************** + Type Traits + ***********************************************************************/ - struct YesType{}; - struct NoType{}; + struct YesType {}; + struct NoType {}; template struct AcceptType @@ -712,25 +713,79 @@ Type Traits typedef T Type; }; + template + struct YesNoAnd + { + typedef NoType Type; + }; + + template<> + struct YesNoAnd + { + typedef YesType Type; + }; + + template + struct YesNoOr + { + typedef YesType Type; + }; + + template<> + struct YesNoOr + { + typedef NoType Type; + }; + template struct AcceptValue { - static const bool Result=false; + static const bool Result = false; }; template<> struct AcceptValue { - static const bool Result=true; + static const bool Result = true; }; + template + T ValueOf(); + template - struct RequiresConvertable + struct PointerConvertable { static YesType Test(TTo* value); static NoType Test(void* value); - - typedef decltype(Test((TFrom*)0)) YesNoType; + + typedef decltype(Test(ValueOf())) YesNoType; + }; + + template + struct ReturnConvertable + { + static YesType Test(TTo&& value); + static NoType Test(...); + + typedef decltype(Test(ValueOf())) YesNoType; + }; + + template + struct ReturnConvertable + { + typedef YesType YesNoType; + }; + + template + struct ReturnConvertable + { + typedef NoType YesNoType; + }; + + template<> + struct ReturnConvertable + { + typedef YesType YesNoType; }; template @@ -1489,19 +1544,27 @@ Ptr template class Ptr { - template - friend class Ptr; + template + friend class Ptr; protected: - typedef void (*Destructor)(volatile vint*, void*); + typedef void(*Destructor)(volatile vint*, void*); - volatile vint* counter; - T* reference; - void* originalReference; - Destructor originalDestructor; + volatile vint* counter = nullptr; + T* reference = nullptr; + void* originalReference = nullptr; + Destructor originalDestructor = nullptr; + + void SetEmptyNoIncDec() + { + counter = nullptr; + reference = nullptr; + originalReference = nullptr; + originalDestructor = nullptr; + } void Inc() { - if(counter) + if (counter) { INCRC(counter); } @@ -1509,18 +1572,15 @@ Ptr void Dec(bool deleteIfZero = true) { - if(counter) + if (counter) { - if(DECRC(counter)==0) + if (DECRC(counter) == 0) { if (deleteIfZero) { originalDestructor(counter, originalReference); } - counter=nullptr; - reference=nullptr; - originalReference=nullptr; - originalDestructor=nullptr; + SetEmptyNoIncDec(); } } } @@ -1532,9 +1592,9 @@ Ptr Ptr(volatile vint* _counter, T* _reference, void* _originalReference, Destructor _originalDestructor) :counter(_counter) - ,reference(_reference) - ,originalReference(_originalReference) - ,originalDestructor(_originalDestructor) + , reference(_reference) + , originalReference(_originalReference) + , originalDestructor(_originalDestructor) { Inc(); } @@ -1542,82 +1602,82 @@ Ptr /// Create a null pointer. Ptr() - :counter(0) - ,reference(0) - ,originalReference(0) - ,originalDestructor(0) { } - + /// Convert a pointer to an object to a smart pointer. /// The pointer to the object. Ptr(T* pointer) - :counter(0) - ,reference(0) - ,originalReference(0) - ,originalDestructor(0) { - if(pointer) + if (pointer) { - counter=ReferenceCounterOperator::CreateCounter(pointer); - reference=pointer; - originalReference=pointer; - originalDestructor=&ReferenceCounterOperator::DeleteReference; + counter = ReferenceCounterOperator::CreateCounter(pointer); + reference = pointer; + originalReference = pointer; + originalDestructor = &ReferenceCounterOperator::DeleteReference; Inc(); } } - + /// Copy a smart pointer. /// The smart pointer to copy. Ptr(const Ptr& pointer) :counter(pointer.counter) - ,reference(pointer.reference) - ,originalReference(pointer.originalReference) - ,originalDestructor(pointer.originalDestructor) + , reference(pointer.reference) + , originalReference(pointer.originalReference) + , originalDestructor(pointer.originalDestructor) { Inc(); } - + /// Move a smart pointer. /// The smart pointer to Move. Ptr(Ptr&& pointer) :counter(pointer.counter) - ,reference(pointer.reference) - ,originalReference(pointer.originalReference) - ,originalDestructor(pointer.originalDestructor) + , reference(pointer.reference) + , originalReference(pointer.originalReference) + , originalDestructor(pointer.originalDestructor) { - pointer.counter=0; - pointer.reference=0; - pointer.originalReference=0; - pointer.originalDestructor=0; + pointer.SetEmptyNoIncDec(); } - + /// Cast a smart pointer. /// The type of the object before casting. /// The smart pointer to cast. - template + template::YesNoType>::Type> Ptr(const Ptr& pointer) - :counter(0) - ,reference(0) - ,originalReference(0) - ,originalDestructor(0) - { - T* converted=pointer.Obj(); - if(converted) - { - counter=pointer.Counter(); - reference=converted; - originalReference=pointer.originalReference; - originalDestructor=pointer.originalDestructor; + { + if (auto converted = pointer.Obj()) + { + counter = pointer.Counter(); + reference = converted; + originalReference = pointer.originalReference; + originalDestructor = pointer.originalDestructor; Inc(); } } + /// Cast a smart pointer. + /// The type of the object before casting. + /// The smart pointer to cast. + template::YesNoType>::Type> + Ptr(Ptr&& pointer) + { + if (auto converted = pointer.Obj()) + { + counter = pointer.Counter(); + reference = converted; + originalReference = pointer.originalReference; + originalDestructor = pointer.originalDestructor; + pointer.SetEmptyNoIncDec(); + } + } + ~Ptr() { Dec(); } - + /// Detach the contained object from this smart pointer. /// The detached object. Returns null if this smart pointer is empty. T* Detach() @@ -1626,171 +1686,137 @@ Ptr Dec(false); return detached; } - + /// Cast a smart pointer. /// The type of the object after casting. /// The casted smart pointer. Returns null if failed. template Ptr Cast()const { - C* converted=dynamic_cast(reference); - return Ptr((converted?counter:0), converted, originalReference, originalDestructor); + C* converted = dynamic_cast(reference); + return Ptr((converted ? counter : 0), converted, originalReference, originalDestructor); } - + /// Convert a pointer to an object to a smart pointer. /// The converted smart pointer. /// The pointer to the object. Ptr& operator=(T* pointer) { Dec(); - if(pointer) + if (pointer) { - counter=ReferenceCounterOperator::CreateCounter(pointer); - reference=pointer; - originalReference=pointer; - originalDestructor=&ReferenceCounterOperator::DeleteReference; + counter = ReferenceCounterOperator::CreateCounter(pointer); + reference = pointer; + originalReference = pointer; + originalDestructor = &ReferenceCounterOperator::DeleteReference; Inc(); } else { - counter=0; - reference=0; - originalReference=0; - originalDestructor=0; + SetEmptyNoIncDec(); } return *this; } - + /// Copy a smart pointer. /// The copied smart pointer. /// The smart pointer to copy. Ptr& operator=(const Ptr& pointer) { - if(this!=&pointer) + if (this != &pointer) { Dec(); - counter=pointer.counter; - reference=pointer.reference; - originalReference=pointer.originalReference; - originalDestructor=pointer.originalDestructor; + counter = pointer.counter; + reference = pointer.reference; + originalReference = pointer.originalReference; + originalDestructor = pointer.originalDestructor; Inc(); } return *this; } - + /// Move a smart pointer. /// The moved smart pointer. /// The smart pointer to Move. Ptr& operator=(Ptr&& pointer) { - if(this!=&pointer) + if (this != &pointer) { Dec(); - counter=pointer.counter; - reference=pointer.reference; - originalReference=pointer.originalReference; - originalDestructor=pointer.originalDestructor; - - pointer.counter=0; - pointer.reference=0; - pointer.originalReference=0; - pointer.originalDestructor=0; - } - return *this; - } - - /// Cast a smart pointer. - /// The type of the object before casting. - /// The smart pointer after casting. - /// The smart pointer to cast. - template - Ptr& operator=(const Ptr& pointer) - { - T* converted=pointer.Obj(); - Dec(); - if(converted) - { - counter=pointer.counter; - reference=converted; - originalReference=pointer.originalReference; - originalDestructor=pointer.originalDestructor; - Inc(); - } - else - { - counter=0; - reference=0; - originalReference=0; - originalDestructor=0; + counter = pointer.counter; + reference = pointer.reference; + originalReference = pointer.originalReference; + originalDestructor = pointer.originalDestructor; + pointer.SetEmptyNoIncDec(); } return *this; } bool operator==(const T* pointer)const { - return reference==pointer; + return reference == pointer; } bool operator!=(const T* pointer)const { - return reference!=pointer; + return reference != pointer; } bool operator>(const T* pointer)const { - return reference>pointer; + return reference > pointer; } bool operator>=(const T* pointer)const { - return reference>=pointer; + return reference >= pointer; } bool operator<(const T* pointer)const { - return reference& pointer)const { - return reference==pointer.reference; + return reference == pointer.reference; } bool operator!=(const Ptr& pointer)const { - return reference!=pointer.reference; + return reference != pointer.reference; } bool operator>(const Ptr& pointer)const { - return reference>pointer.reference; + return reference > pointer.reference; } bool operator>=(const Ptr& pointer)const { - return reference>=pointer.reference; + return reference >= pointer.reference; } bool operator<(const Ptr& pointer)const { - return reference& pointer)const { - return reference<=pointer.reference; + return reference <= pointer.reference; } /// Test if it is a null pointer. /// Returns true if it is not null. operator bool()const { - return reference!=0; + return reference != 0; } /// Get the pointer to the object. @@ -1799,7 +1825,7 @@ Ptr { return reference; } - + /// Get the pointer to the object. /// The pointer to the object. T* operator->()const @@ -2079,15 +2105,63 @@ Framework::Function #define VCZH_FUNCTION namespace vl { - -/*********************************************************************** -vl::Func -***********************************************************************/ template class Func { }; + +/*********************************************************************** +vl::function_lambda::LambdaRetriveType +***********************************************************************/ + + namespace function_lambda + { + template + struct LambdaRetriveType + { + }; + + template + struct FunctionObjectRetriveType + { + typedef typename LambdaRetriveType::Type Type; + typedef typename LambdaRetriveType::FunctionType FunctionType; + typedef typename LambdaRetriveType::ResultType ResultType; + typedef typename LambdaRetriveType::ParameterTypes ParameterTypes; + }; + + template + struct LambdaRetriveType + { + typedef Func Type; + typedef R(FunctionType)(TArgs...); + typedef R ResultType; + typedef TypeTuple ParameterTypes; + }; + + template + struct LambdaRetriveType + { + typedef Func Type; + typedef R(FunctionType)(TArgs...); + typedef R ResultType; + typedef TypeTuple ParameterTypes; + }; + + template + struct FunctionObjectRetriveType + { + typedef Func Type; + typedef R(FunctionType)(TArgs...); + typedef R ResultType; + typedef TypeTuple ParameterTypes; + }; + } + +/*********************************************************************** +vl::Func +***********************************************************************/ namespace internal_invokers { @@ -2154,6 +2228,11 @@ vl::Func { } + ObjectInvoker(C&& _function) + :function(MoveValue(_function)) + { + } + R Invoke(TArgs&& ...args)override { return function(ForwardValue(args)...); @@ -2174,6 +2253,11 @@ vl::Func { } + ObjectInvoker(C&& _function) + :function(MoveValue(_function)) + { + } + void Invoke(TArgs&& ...args)override { function(ForwardValue(args)...); @@ -2190,6 +2274,23 @@ vl::Func protected: Ptr> invoker; + template + static bool IsEmptyFunc(const Func& function) + { + return !function; + } + + template + static bool IsEmptyFunc(Func& function) + { + return !function; + } + + template + static bool IsEmptyFunc(C&&) + { + return false; + } public: typedef R FunctionType(TArgs...); typedef R ResultType; @@ -2198,21 +2299,28 @@ vl::Func Func() { } - + /// Copy a function reference. /// The function reference to copy. Func(const Func& function) + :invoker(function.invoker) { - invoker=function.invoker; } - + + /// Move a function reference. + /// The function reference to move. + Func(Func&& function) + :invoker(MoveValue(function.invoker)) + { + } + /// Create a reference using a function pointer. /// The function pointer. Func(R(*function)(TArgs...)) { - invoker=new internal_invokers::StaticInvoker(function); + invoker = new internal_invokers::StaticInvoker(function); } - + /// Create a reference using a method. /// Type of the class that has the method. /// The object that has the method. @@ -2220,29 +2328,19 @@ vl::Func template Func(C* sender, R(C::*function)(TArgs...)) { - invoker=new internal_invokers::MemberInvoker(sender, function); + invoker = new internal_invokers::MemberInvoker(sender, function); } - /// Create a reference using a function object. - /// Return type of the function object. - /// Argument types of the function object. - /// The function object. - template - Func(const Func& function) - { - if (function) - { - invoker = new internal_invokers::ObjectInvoker, R, TArgs...>(function); - } - } - /// Create a reference using a function object. /// Type of the function object. /// The function object. It could be a lambda expression. - template - Func(const C& function) + template()(ValueOf()...)), R>::YesNoType>::Type> + Func(C&& function) { - invoker = new internal_invokers::ObjectInvoker(function); + if (!IsEmptyFunc(function)) + { + invoker = new internal_invokers::ObjectInvoker::Type, R, TArgs...>(ForwardValue(function)); + } } /// Invoke the function. @@ -2253,6 +2351,18 @@ vl::Func return invoker->Invoke(ForwardValue(args)...); } + Func& operator=(const Func& function) + { + invoker = function.invoker; + return *this; + } + + Func& operator=(const Func&& function) + { + invoker = MoveValue(function.invoker); + return *this; + } + bool operator==(const Func& function)const { return invoker == function.invoker; @@ -2272,51 +2382,11 @@ vl::Func }; /*********************************************************************** -vl::function_lambda::LambdaRetriveType +LAMBDA ***********************************************************************/ namespace function_lambda { - template - struct LambdaRetriveType - { - typedef vint Type; - typedef vint FunctionType; - typedef vint ResultType; - }; - - template - struct FunctionObjectRetriveType - { - typedef typename LambdaRetriveType::Type Type; - typedef typename LambdaRetriveType::FunctionType FunctionType; - typedef typename LambdaRetriveType::ResultType ResultType; - }; - - template - struct LambdaRetriveType - { - typedef Func Type; - typedef R(FunctionType)(TArgs...); - typedef R ResultType; - }; - - template - struct LambdaRetriveType - { - typedef Func Type; - typedef R(FunctionType)(TArgs...); - typedef R ResultType; - }; - - template - struct FunctionObjectRetriveType - { - typedef Func Type; - typedef R(FunctionType)(TArgs...); - typedef R ResultType; - }; - /// Create a function reference to a function object or a lambda expression, with all type information autotimatically inferred. You can use the macro called "LAMBDA" to refer to this function. /// Type of the function object or the lambda expression. /// The function reference. @@ -2326,7 +2396,7 @@ vl::function_lambda::LambdaRetriveType { return functionObject; } - + /// Create a function reference to a function pointer, with all type information autotimatically inferred. You can use the macro called "FUNCTION" to refer to this function. /// Type of the function pointer. /// The function reference. @@ -5300,6 +5370,7 @@ namespace vl > class Group : public Object, public virtual IEnumerable> { + public: typedef SortedList KeyContainer; typedef List ValueContainer; protected: @@ -5671,57 +5742,6 @@ Random Access #endif -/*********************************************************************** -.\CONSOLE.H -***********************************************************************/ -/*********************************************************************** -Vczh Library++ 3.0 -Developer: Zihan Chen(vczh) -UI::Console - -***********************************************************************/ - -#ifndef VCZH_CONSOLE -#define VCZH_CONSOLE - - -namespace vl -{ - namespace console - { - /// A Static class for command line window operations. - class Console abstract - { - public: - /// Write to the command line window. - /// Content to write. - /// Size of the content in wchar_t. The zero terminator is not included. - static void Write(const wchar_t* string, vint length); - - /// Write to the command line window. - /// Content to write. - static void Write(const wchar_t* string); - - /// Write to the command line window. - /// Content to write. - static void Write(const WString& string); - - /// Write to the command line window with a CRLF. - /// Content to write. - static void WriteLine(const WString& string); - - /// Read from the command line window. - /// The whole line read from the command line window. - static WString Read(); - - static void SetColor(bool red, bool green, bool blue, bool light); - static void SetTitle(const WString& string); - }; - } -} - -#endif - /*********************************************************************** .\EXCEPTION.H ***********************************************************************/ @@ -5781,6 +5801,57 @@ namespace vl #endif +/*********************************************************************** +.\CONSOLE.H +***********************************************************************/ +/*********************************************************************** +Vczh Library++ 3.0 +Developer: Zihan Chen(vczh) +UI::Console + +***********************************************************************/ + +#ifndef VCZH_CONSOLE +#define VCZH_CONSOLE + + +namespace vl +{ + namespace console + { + /// A Static class for command line window operations. + class Console abstract + { + public: + /// Write to the command line window. + /// Content to write. + /// Size of the content in wchar_t. The zero terminator is not included. + static void Write(const wchar_t* string, vint length); + + /// Write to the command line window. + /// Content to write. + static void Write(const wchar_t* string); + + /// Write to the command line window. + /// Content to write. + static void Write(const WString& string); + + /// Write to the command line window with a CRLF. + /// Content to write. + static void WriteLine(const WString& string); + + /// Read from the command line window. + /// The whole line read from the command line window. + static WString Read(); + + static void SetColor(bool red, bool green, bool blue, bool light); + static void SetTitle(const WString& string); + }; + } +} + +#endif + /*********************************************************************** .\GLOBALSTORAGE.H ***********************************************************************/ @@ -6122,73 +6193,130 @@ UI::Console #define VCZH_UNITTEST -class UnitTestError -{ -}; - namespace vl { namespace unittest { + using UnitTestFileProc = void(*)(); + /// ) - /// { - /// - /// - /// - /// - /// } - /// You should call [M:vl.unittest.UnitTest.RunAndDisposeTests] in your main function to run all test cases. + /// A static class containing all unit test operations. + /// 1) Writing test cases: + /// TEST_FILE + /// { + /// TEST_CATEGORY(L"Category Description"){ ... }); + /// TEST_CASE(L"Test Case Description"){ ... }); + /// } + /// A category could contains other categories and cases, but a case should only contain assertions. + /// 2) Writing asserts: + /// TEST_CASE_ASSERT(condition): An assertion that is also a test case, only legal to call inside a category, with a description equivalents to the condition. + /// TEST_ASSERT(condition); Only legal to call inside a case. It passes when condition evaluates to true. + /// TEST_ERROR(condition); Only legal to call inside a case. It passes when condition throws vl::Error + /// TEST_EXCEPTION(statement, exception, callback); Only legal to call inside a case. It passes when an exception of the expected type is thrown, and callback(exception) passes. + /// 3) Other functions + /// TEST_PRINT(message); Print neutral message. + /// 4) + /// You should call [M:vl.unittest.UnitTest.RunAndDisposeTests] in your main function to run all test cases, and return the value from this function. + /// When "/D" is provided, the test program crashes at any failed assertiong. + /// When "/R" is provided, the test program consumes all failed assertions and run all cases. A test case stopped at the first failed assertion. Exit code will be 1 when any case fails. + /// When no argument is provided + /// In Windows, it becomes "/D" only when a debugger is attached, in other cases it becomes "/R". + /// In other platforms, it becomes "/R" /// ]]> - class UnitTest abstract + class UnitTest { public: - typedef void(*TestProc)(); + UnitTest() = delete; - /// Print a green message. - /// The content. - static void PrintMessage(const WString& string); + enum class MessageKind + { + Info, + Error, + File, + Category, + Case, + }; - /// Print a white information. + /// Print a message with specified color. /// The content. - static void PrintInfo(const WString& string); + /// The kind of the content. + static void PrintMessage(const WString& string, MessageKind kind); - /// Print a red error. - /// The content. - static void PrintError(const WString& string); + /// Run all test cases. +#ifdef VCZH_MSVC + static int RunAndDisposeTests(int argc, wchar_t* argv[]); +#else + static int RunAndDisposeTests(int argc, char* argv[]); +#endif - static void PushTest(TestProc testProc); + static void RegisterTestFile(const char* fileName, UnitTestFileProc testProc); + static void RunCategoryOrCase(const WString& description, bool isCategory, Func&& callback); + static void EnsureLegalToAssert(); + }; - /// Run all test cases. - static void RunAndDisposeTests(); + class UnitTestFile + { + public: + UnitTestFile(const char* fileName, UnitTestFileProc testProc) + { + UnitTest::RegisterTestFile(fileName, testProc); + } }; -#define TEST_CHECK_ERROR(CONDITION,DESCRIPTION) do{if(!(CONDITION))throw Error(DESCRIPTION);}while(0) -#define TEST_ASSERT(CONDITION) do{TEST_CHECK_ERROR(CONDITION,L"");}while(0) -#define TEST_ERROR(CONDITION) do{try{CONDITION;throw UnitTestError();}catch(const Error&){}catch(const UnitTestError&){TEST_CHECK_ERROR(false,L"");}}while(0) -#define TEST_CASE(NAME)\ - extern void TESTCASE_##NAME(); \ - namespace vl_unittest_executors \ - { \ - class TESTCASE_RUNNER_##NAME \ - { \ - public: \ - static void RunUnitTest() \ - { \ - vl::unittest::UnitTest::PrintMessage(L_(#NAME)); \ - TESTCASE_##NAME(); \ - } \ - TESTCASE_RUNNER_##NAME() \ - { \ - vl::unittest::UnitTest::PushTest(&TESTCASE_RUNNER_##NAME::RunUnitTest); \ - } \ - } TESTCASE_RUNNER_##NAME##_INSTANCE; \ - } \ - void TESTCASE_##NAME() -#define TEST_PRINT(x) vl::unittest::UnitTest::PrintInfo(x) -#define TEST_EXCEPTION(STATEMENT,EXCEPTION,ASSERT_FUNCTION) try{STATEMENT; TEST_ASSERT(false);}catch(const EXCEPTION& e){ASSERT_FUNCTION(e);} + struct UnitTestAssertError + { + const wchar_t* message; + + UnitTestAssertError(const wchar_t* _message) :message(_message) {} + }; + + struct UnitTestConfigError + { + const wchar_t* message; + + UnitTestConfigError(const wchar_t* _message) :message(_message) {} + }; + +#define TEST_FILE\ + static void VLPPTEST_TESTFILE();\ + static ::vl::unittest::UnitTestFile VLPPTEST_TESTFILE_INSTANCE(__FILE__, &VLPPTEST_TESTFILE);\ + static void VLPPTEST_TESTFILE()\ + +#define TEST_CATEGORY(DESCRIPTION)\ + ::vl::unittest::UnitTest::RunCategoryOrCase((DESCRIPTION), true, [&]()\ + +#define TEST_CASE(DESCRIPTION)\ + ::vl::unittest::UnitTest::RunCategoryOrCase((DESCRIPTION), false, [&]()\ + +#define TEST_ASSERT(CONDITION)\ + do{\ + ::vl::unittest::UnitTest::EnsureLegalToAssert();\ + if(!(CONDITION))throw ::vl::unittest::UnitTestAssertError(L"Assertion failure: " #CONDITION);\ + }while(0)\ + +#define TEST_ERROR(STATEMENT)\ + do{\ + ::vl::unittest::UnitTest::EnsureLegalToAssert();\ + try{STATEMENT; throw ::vl::unittest::UnitTestAssertError(L"Expect an error but nothing occurred: " #STATEMENT);}\ + catch(const ::vl::Error&){}\ + catch(const ::vl::unittest::UnitTestAssertError&) { throw; }\ + catch (const ::vl::unittest::UnitTestConfigError&) { throw; }\ + }while(0)\ + +#define TEST_EXCEPTION(STATEMENT,EXCEPTION,ASSERT_FUNCTION)\ + do{\ + auto __ASSERT_FUNCTION__ = ASSERT_FUNCTION;\ + try{STATEMENT; throw ::vl::unittest::UnitTestAssertError(L"Expect [" #EXCEPTION "] but nothing occurred: " #STATEMENT);}\ + catch(const EXCEPTION& e){ __ASSERT_FUNCTION__(e); }\ + catch(...){ throw ::vl::unittest::UnitTestAssertError(L"Expect [" #EXCEPTION "] but get unexpected exception: " #STATEMENT); }\ + }while(0)\ + +#define TEST_PRINT(MESSAGE)\ + ::vl::unittest::UnitTest::PrintMessage((MESSAGE), ::vl::unittest::UnitTest::MessageKind::Info)\ + +#define TEST_CASE_ASSERT(CONDITION)\ + TEST_CASE(L ## # CONDITION) { TEST_ASSERT(CONDITION); })\ + } } @@ -6991,7 +7119,7 @@ LazyList template LazyList> FindType()const { - return Cast().Where([](T t){return t;}); + return Cast().Where([](Ptr t){return t;}); } /// Create a new lazy list with all elements sorted. diff --git a/Import/VlppReflection.h b/Import/VlppReflection.h index 6df1486f..0d7cfdcb 100644 --- a/Import/VlppReflection.h +++ b/Import/VlppReflection.h @@ -471,7 +471,7 @@ ReferenceCounterOperator } template - struct ReferenceCounterOperator::YesNoType> + struct ReferenceCounterOperator::YesNoType> { static __forceinline volatile vint* CreateCounter(T* reference) { @@ -4916,7 +4916,7 @@ Class protected:\ bool IsAggregatable()override\ {\ - return AcceptValue>::YesNoType>::Result;\ + return AcceptValue>::YesNoType>::Result;\ }\ void LoadInternal()override\ {