/*********************************************************************** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY DEVELOPER: Zihan Chen(vczh) ***********************************************************************/ /*********************************************************************** .\BASIC.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_BASIC #define VCZH_BASIC #ifdef VCZH_CHECK_MEMORY_LEAKS #define _CRTDBG_MAP_ALLOC #include #include #define VCZH_CHECK_MEMORY_LEAKS_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) #define new VCZH_CHECK_MEMORY_LEAKS_NEW #endif #if defined _WIN64 || defined __x86_64 || defined __LP64__ || defined __aarch64__ || defined _M_ARM64 #define VCZH_64 #endif #if defined _MSC_VER #define VCZH_MSVC #else #define VCZH_GCC #if defined(__APPLE__) #define VCZH_APPLE #endif #endif #if defined __arm__ || defined __aarch64__ || defined _M_ARM || defined _M_ARM64 #define VCZH_ARM #endif #if defined VCZH_MSVC #define VCZH_WCHAR_UTF16 #elif defined VCZH_GCC #define VCZH_WCHAR_UTF32 #endif #if defined VCZH_WCHAR_UTF16 static_assert(sizeof(wchar_t) == sizeof(char16_t), "wchar_t is not UTF-16."); #elif defined VCZH_WCHAR_UTF32 static_assert(sizeof(wchar_t) == sizeof(char32_t), "wchar_t is not UTF-32."); #else static_assert(false, "wchar_t configuration is not right."); #endif #if defined VCZH_ARM #elif defined VCZH_MSVC #include #elif defined VCZH_GCC #include #endif #if defined VCZH_GCC #include #include #include #define abstract #define __thiscall #define __forceinline inline #define _I8_MIN ((vint8_t)0x80) #define _I8_MAX ((vint8_t)0x7F) #define _UI8_MAX ((vuint8_t)0xFF) #define _I16_MIN ((vint16_t)0x8000) #define _I16_MAX ((vint16_t)0x7FFF) #define _UI16_MAX ((vuint16_t)0xFFFF) #define _I32_MIN ((vint32_t)0x80000000) #define _I32_MAX ((vint32_t)0x7FFFFFFF) #define _UI32_MAX ((vuint32_t)0xFFFFFFFF) #define _I64_MIN ((vint64_t)0x8000000000000000L) #define _I64_MAX ((vint64_t)0x7FFFFFFFFFFFFFFFL) #define _UI64_MAX ((vuint64_t)0xFFFFFFFFFFFFFFFFL) #endif #include #include #define L_(x) L__(x) #define L__(x) L ## x namespace vl { /*********************************************************************** x86 and x64 Compatbility ***********************************************************************/ #if defined VCZH_MSVC /// 1-byte signed integer. typedef signed __int8 vint8_t; /// 1-byte unsigned integer. typedef unsigned __int8 vuint8_t; /// 2-bytes signed integer. typedef signed __int16 vint16_t; /// 2-bytes unsigned integer. typedef unsigned __int16 vuint16_t; /// 4-bytes signed integer. typedef signed __int32 vint32_t; /// 4-bytes unsigned integer. typedef unsigned __int32 vuint32_t; /// 8-bytes signed integer. typedef signed __int64 vint64_t; /// 8-bytes unsigned integer. typedef unsigned __int64 vuint64_t; #elif defined VCZH_GCC typedef int8_t vint8_t; typedef uint8_t vuint8_t; typedef int16_t vint16_t; typedef uint16_t vuint16_t; typedef int32_t vint32_t; typedef uint32_t vuint32_t; typedef int64_t vint64_t; typedef uint64_t vuint64_t; #endif #ifdef VCZH_64 /// Signed interface whose size equals to sizeof(void*). typedef vint64_t vint; /// Signed interface whose size equals to sizeof(void*). typedef vint64_t vsint; /// Unsigned interface whose size equals to sizeof(void*). typedef vuint64_t vuint; #else /// Signed interface whose size equals to sizeof(void*). typedef vint32_t vint; /// Signed interface whose size equals to sizeof(void*). typedef vint32_t vsint; /// Unsigned interface whose size equals to sizeof(void*). typedef vuint32_t vuint; #endif /// Signed interger representing position. typedef vint64_t pos_t; #ifdef VCZH_64 #define ITOA_S _i64toa_s #define ITOW_S _i64tow_s #define I64TOA_S _i64toa_s #define I64TOW_S _i64tow_s #define UITOA_S _ui64toa_s #define UITOW_S _ui64tow_s #define UI64TOA_S _ui64toa_s #define UI64TOW_S _ui64tow_s #if defined VCZH_MSVC #define INCRC(x) (_InterlockedIncrement64(x)) #define DECRC(x) (_InterlockedDecrement64(x)) #elif defined VCZH_ARM #define INCRC(x) (__atomic_add_fetch(x, 1, __ATOMIC_SEQ_CST)) #define DECRC(x) (__atomic_sub_fetch(x, 1, __ATOMIC_SEQ_CST)) #elif defined VCZH_GCC #define INCRC(x) (__sync_add_and_fetch(x, 1)) #define DECRC(x) (__sync_sub_and_fetch(x, 1)) #endif #else #define ITOA_S _itoa_s #define ITOW_S _itow_s #define I64TOA_S _i64toa_s #define I64TOW_S _i64tow_s #define UITOA_S _ui64toa_s #define UITOW_S _ui64tow_s #define UI64TOA_S _ui64toa_s #define UI64TOW_S _ui64tow_s #if defined VCZH_MSVC #define INCRC(x) (_InterlockedIncrement((volatile long*)(x))) #define DECRC(x) (_InterlockedDecrement((volatile long*)(x))) #elif defined VCZH_ARM #define INCRC(x) (__atomic_add_fetch(x, 1, __ATOMIC_SEQ_CST)) #define DECRC(x) (__atomic_sub_fetch(x, 1, __ATOMIC_SEQ_CST)) #elif defined VCZH_GCC #define INCRC(x) (__sync_add_and_fetch(x, 1)) #define DECRC(x) (__sync_sub_and_fetch(x, 1)) #endif #endif /*********************************************************************** Basic Types ***********************************************************************/ /// Base type of all errors. An error is an exception that is not recommended to catch. Raising it means there is a mistake in the code. class Error { private: const wchar_t* description; public: Error(const wchar_t* _description); const wchar_t* Description()const; }; #if defined VCZH_MSVC || defined VCZH_GCC || defined _DEBUG #define CHECK_ERROR(CONDITION,DESCRIPTION) do{if(!(CONDITION))throw Error(DESCRIPTION);}while(0) #elif defined NDEBUG #define CHECK_ERROR(CONDITION,DESCRIPTION) #endif #define CHECK_FAIL(DESCRIPTION) do{throw Error(DESCRIPTION);}while(0) #define SCOPE_VARIABLE(TYPE, VARIABLE, VALUE)\ if(bool __scope_variable_flag__=true)\ for(TYPE VARIABLE = VALUE;__scope_variable_flag__;__scope_variable_flag__=false) template struct TypeTuple { }; /// /// Base type of all classes. /// This type has a virtual destructor, making all derived classes destructors virtual. /// In this way an object is allowed to be deleted using a pointer of a qualified base type pointing to this object. /// class Object { public: virtual ~Object() = default; }; /// Type for representing nullable data. /// Type of the data, typically it is a value type, or [T:vl.Ptr`1] could be used here. template class Nullable { private: T* object = nullptr; public: /// Create a null value. Nullable() = default; /// Create a non-null value by copying data. /// The data to copy. Nullable(const T& value) :object(new T(value)) { } /// Create a non-null value by moving data. /// The data to move. Nullable(T&& value) :object(new T(std::move(value))) { } /// Create a nullable value by copying from another nullable value. /// The nullable value to copy. Nullable(const Nullable& nullable) :object(nullable.object ? new T(*nullable.object) : nullptr) { } /// Create a nullable value by moving from another nullable value. /// The nullable value to move. Nullable(Nullable&& nullable) :object(nullable.object) { nullable.object = nullptr; } ~Nullable() { if (object) delete object; } /// Replace the data inside this nullable value by copying from data. /// The nullable value itself. /// The data to copy. Nullable& operator=(const T& value) { if (object) delete object; object = new T(value); return *this; } /// Replace the data inside this nullable value by copying from another nullable value. /// The nullable value itself. /// The nullable value to copy. Nullable& operator=(const Nullable& nullable) { if (this != &nullable) { if (object) delete object; if (nullable.object) { object = new T(*nullable.object); } else { object = nullptr; } } return *this; } /// Replace the data inside this nullable value by moving from another nullable value. /// The nullable value itself. /// The nullable value to move. Nullable& operator=(Nullable&& nullable) { if (this != &nullable) { if (object) delete object; object = nullable.object; nullable.object = nullptr; } return *this; } /// Comparing two nullable values. /// Returns true when these nullable values are all null, or the data inside them equals. /// The first nullable value to compare. /// The second nullable value to compare. static bool Equals(const Nullable& a, const Nullable& b) { if (!a.object && !b.object) return true; if (a.object && b.object) return *a.object == *b.object; return false; } /// Comparing two nullable values. /// /// Returns a positive value when the first value is greater than the second value. /// Returns a negative value when the first value is lesser than the second value. /// Returns zero when the two values equal. /// When one is null and another one is not, the non-null one is greater. /// /// The first nullable value to compare. /// The second nullable value to compare. static vint Compare(const Nullable& a, const Nullable& b) { if (a.object && b.object) { if (*a.object > *b.object) return 1; if (*a.object < *b.object) return -1; return 0; } if (a.object) return 1; if (b.object) return -1; return 0; } bool operator==(const Nullable& nullable)const { return Equals(*this, nullable); } bool operator!=(const Nullable& nullable)const { return !Equals(*this, nullable); } bool operator<(const Nullable& nullable)const { return Compare(*this, nullable) < 0; } bool operator<=(const Nullable& nullable)const { return Compare(*this, nullable) <= 0; } bool operator>(const Nullable& nullable)const { return Compare(*this, nullable) > 0; } bool operator>=(const Nullable& nullable)const { return Compare(*this, nullable) >= 0; } /// Test if this nullable value is non-null. /// Returns true if it is non-null. operator bool()const { return object != nullptr; } /// Return the data inside this nullable value /// The data inside this nullable value. It crashes when it is null. const T& Value()const { if (!object) throw Error(L"Nullable::Value()#Cannot unbox from null."); return *object; } }; template union BinaryRetriver { T t; char binary[sizeof(T) > minSize ? sizeof(T) : minSize]; }; /*********************************************************************** Type Traits ***********************************************************************/ /// Type for specify and create a representative value for comparing another value of a specific type for containers. /// The element type for containers. template struct KeyType { public: /// The type of the representative value. typedef T Type; /// Convert a value in a container to its representative value. /// The representative value. /// The value in a container. static const T& GetKeyValue(const T& value) { return value; } }; /*********************************************************************** Interface ***********************************************************************/ #define NOT_COPYABLE(TYPE)\ TYPE(const TYPE&) = delete;\ TYPE(TYPE&&) = delete;\ TYPE& operator=(const TYPE&) = delete;\ TYPE& operator=(TYPE&&) = delete /// Base type of all interfaces. All interface types are encouraged to be virtual inherited. class Interface { public: NOT_COPYABLE(Interface); Interface() = default; virtual ~Interface() = default; }; } #endif /*********************************************************************** .\COLLECTIONS\PAIR.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_PAIR #define VCZH_COLLECTIONS_PAIR namespace vl { namespace collections { template class Pair; /// A type representing a pair of key and value. /// Type of the key. /// Type of the value. template class Pair { public: /// The key. K key; /// The value. V value; Pair() = default; template Pair(TKey&& _key, TValue&& _value) : key(std::forward(_key)) , value(std::forward(_value)) { } Pair(const K& _key, const V& _value) : key(_key) , value(_value) { } Pair(const K& _key, V&& _value) : key(_key) , value(std::move(_value)) { } Pair(K&& _key, const V& _value) : key(std::move(_key)) , value(_value) { } Pair(K&& _key, V&& _value) : key(std::move(_key)) , value(std::move(_value)) { } Pair(const Pair& pair) : key(pair.key) , value(pair.value) { } Pair(const Pair& pair) : key(pair.key) , value(pair.value) { } Pair(Pair&& pair) : key(std::move(pair.key)) , value(std::move(pair.value)) { } Pair& operator=(const Pair& pair) { key = pair.key; value = pair.value; return *this; } Pair& operator=(Pair&& pair) { key = std::move(pair.key); value = std::move(pair.value); return *this; } template auto CompareTo(const Pair& pair) const -> vint requires ( std::is_same_v, std::remove_cvref_t>&& std::is_same_v, std::remove_cvref_t> ) { if (key < pair.key) { return -1; } else if (key > pair.key) { return 1; } else if (value < pair.value) { return -1; } else if (value > pair.value) { return 1; } else { return 0; } } template bool operator==(TPair&& pair)const { return CompareTo(std::forward(pair)) == 0; } template bool operator!=(TPair&& pair)const { return CompareTo(std::forward(pair)) != 0; } template bool operator<(TPair&& pair)const { return CompareTo(std::forward(pair)) < 0; } template bool operator<=(TPair&& pair)const { return CompareTo(std::forward(pair)) <= 0; } template bool operator>(TPair&& pair)const { return CompareTo(std::forward(pair)) > 0; } template bool operator>=(TPair&& pair)const { return CompareTo(std::forward(pair)) >= 0; } }; template class Pair { public: const K& key; const V& value; #if defined(__clang__) #pragma clang dignostic push #pragma clang diagnostic ignored "-Wnull-dereference" #elif defined(__GNUC__) #pragma GCC dignostic push #pragma GCC diagnostic ignored "-Wnull-dereference" #endif Pair() : key(*(const K*)nullptr) , value(*(const V*)nullptr) { } #if defined(__clang__) #pragma clang dignostic pop #elif defined(__GNUC__) #pragma GCC dignostic popd #endif Pair(const K& _key, const V& _value) : key(_key) , value(_value) { } Pair(const Pair& pair) : key(pair.key) , value(pair.value) { } Pair& operator=(const Pair& pair) { #ifdef VCZH_CHECK_MEMORY_LEAKS_NEW #undef new #endif this->~Pair(); new(this) Pair(pair); return *this; #ifdef VCZH_CHECK_MEMORY_LEAKS_NEW #define new VCZH_CHECK_MEMORY_LEAKS_NEW #endif } template auto CompareTo(const Pair& pair) const -> vint requires ( std::is_same_v, std::remove_cvref_t>&& std::is_same_v, std::remove_cvref_t> ) { if (key < pair.key) { return -1; } else if (key > pair.key) { return 1; } else if (value < pair.value) { return -1; } else if (value > pair.value) { return 1; } else { return 0; } } template bool operator==(TPair&& pair)const { return CompareTo(std::forward(pair)) == 0; } template bool operator!=(TPair&& pair)const { return CompareTo(std::forward(pair)) != 0; } template bool operator<(TPair&& pair)const { return CompareTo(std::forward(pair)) < 0; } template bool operator<=(TPair&& pair)const { return CompareTo(std::forward(pair)) <= 0; } template bool operator>(TPair&& pair)const { return CompareTo(std::forward(pair)) > 0; } template bool operator>=(TPair&& pair)const { return CompareTo(std::forward(pair)) >= 0; } }; } } #endif /*********************************************************************** .\PRIMITIVES\DATETIME.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_DATETIME #define VCZH_DATETIME namespace vl { /*********************************************************************** Date and Time ***********************************************************************/ /// A type representing the combination of date and time. struct DateTime { /// The year. vint year = 0; /// The month, from 1 to 12. vint month = 0; /// The day, from 1 to 31. vint day = 0; /// The hour, from 0 to 23. vint hour = 0; /// The minute, from 0 to 59. vint minute = 0; /// The second, from 0 to 60. vint second = 0; /// The milliseconds, from 0 to 999. vint milliseconds = 0; /// /// The calculated total milliseconds. It is OS dependent because the start time is different. /// It is from 0 to 6, representing Sunday to Saturday. /// vint dayOfWeek = 0; /// /// The calculated total milliseconds. It is OS dependent because the start time is different. /// You should not rely on the fact about how this value is created. /// The only invariant thing is that, when an date time is earlier than another, the totalMilliseconds is lesser. /// vuint64_t totalMilliseconds = 0; /// /// The calculated file time for the date and time. It is OS dependent. /// You should not rely on the fact about how this value is created. /// The only invariant thing is that, when an date time is earlier than another, the filetime is lesser. /// vuint64_t filetime = 0; /// Get the current local time. /// The current local time. static DateTime LocalTime(); /// Get the current UTC time. /// The current UTC time. static DateTime UtcTime(); /// Create a date time value. /// The created date time value. /// The year. /// The month. /// The day. /// The hour. /// 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); /// Create a date time value from a file time. /// The created date time value. /// The file time. static DateTime FromFileTime(vuint64_t filetime); /// Create an empty date time value that is not meaningful. DateTime() = default; /// Convert the UTC time to the local time. /// The UTC time. DateTime ToLocalTime(); /// Convert the local time to the UTC time. /// The local time. DateTime ToUtcTime(); /// Move forward. /// The moved time. /// The delta in milliseconds. DateTime Forward(vuint64_t milliseconds); /// Move Backward. /// The moved 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 < 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; } }; } #endif /*********************************************************************** .\PRIMITIVES\POINTER.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_POINTER #define VCZH_POINTER namespace vl { /*********************************************************************** ReferenceCounterOperator ***********************************************************************/ /// /// The strategy class to create and delete the reference counter of an object. /// For any object inherits from [T:vl.reflection.DescriptableObject], the reference counter is stored inside the object. /// For any other object, the reference counter is allocated separately. /// You can create your own strategy by adding a new partial specialization to this class. /// /// /// The type of the object. /// /// /// [T:vl.Ptr`1] will always use [T:vl.YesType] as the second type parameter. /// This parameter is useful when you want to do partial specialization in the SFINAE way. /// template struct ReferenceCounterOperator { /// Create the reference counter of an object. /// The pointer to the reference counter. /// The object. static __forceinline volatile vint* CreateCounter(T* reference) { return new vint(0); } /// Delete the reference counter from an object. /// The pointer to the reference counter. /// The object. static __forceinline void DeleteReference(volatile vint* counter, void* reference) { delete counter; delete (T*)reference; } }; /*********************************************************************** Ptr ***********************************************************************/ /// /// A shared pointer. /// It maintains a reference counter to the object. /// When no [T:vl.Ptr`1] is referencing the object, the object will be deleted automatically. /// /// /// It is safe to convert the same pointer to an object to a shared pointer once. /// If you do it multiple times, it depends on [T:vl.ReferenceCounterOperator`2]. /// For built-in strategies, only pointer to [T:vl.reflection.DescriptableObject] or its derived classes can be safely converted to a shared pointer for multiple times. /// For any other object, it will crash on the destructor of [T:vl.Ptr`1]. /// /// The type of the object. template class Ptr { template friend class Ptr; protected: typedef void(*Destructor)(volatile vint*, void*); 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) { INCRC(counter); } } void Dec(bool deleteIfZero = true) { if (counter) { if (DECRC(counter) == 0) { if (deleteIfZero) { originalDestructor(counter, originalReference); } SetEmptyNoIncDec(); } } } volatile vint* Counter()const { return counter; } Ptr(volatile vint* _counter, T* _reference, void* _originalReference, Destructor _originalDestructor) :counter(_counter) , reference(_reference) , originalReference(_originalReference) , originalDestructor(_originalDestructor) { Inc(); } public: /// Create a null pointer. Ptr() = default; /// Create a null pointer. Ptr(std::nullptr_t) {}; /// Convert a pointer to an object to a shared pointer. /// The pointer to the object. explicit Ptr(T* pointer) { if (pointer) { counter = ReferenceCounterOperator::CreateCounter(pointer); reference = pointer; originalReference = pointer; originalDestructor = &ReferenceCounterOperator::DeleteReference; Inc(); } } /// Copy a shared pointer. /// The shared pointer to copy. Ptr(const Ptr& pointer) :counter(pointer.counter) , reference(pointer.reference) , originalReference(pointer.originalReference) , originalDestructor(pointer.originalDestructor) { Inc(); } /// Move a shared pointer. /// The shared pointer to Move. Ptr(Ptr&& pointer) :counter(pointer.counter) , reference(pointer.reference) , originalReference(pointer.originalReference) , originalDestructor(pointer.originalDestructor) { pointer.SetEmptyNoIncDec(); } /// Cast a shared pointer implicitly by copying another shared pointer. /// The type of the object before casting. /// The shared pointer to cast. template Ptr(const Ptr& pointer) requires (std::is_convertible_v) { if (auto converted = pointer.Obj()) { counter = pointer.Counter(); reference = converted; originalReference = pointer.originalReference; originalDestructor = pointer.originalDestructor; Inc(); } } /// Cast a shared pointer implicitly by moving another shared pointer. /// The type of the object before casting. /// The shared pointer to cast. template Ptr(Ptr&& pointer) requires (std::is_convertible_v) { 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 shared pointer. /// When no [T:vl.Ptr`1] is referencing to the object because of a call to Detach, the object will not be deleted. /// /// The detached object. Returns null if this shared pointer is empty. T* Detach() { auto detached = reference; Dec(false); return detached; } /// Cast a shared pointer explicitly. /// The type of the object after casting. /// The casted shared pointer. Returns null for empty shared pointer or a failed cast. template Ptr Cast()const { C* converted = dynamic_cast(reference); return Ptr((converted ? counter : 0), converted, originalReference, originalDestructor); } /// Replace by nullptr. /// The shared pointer itself. /// The nullptr. Ptr& operator=(std::nullptr_t) { Dec(); SetEmptyNoIncDec(); return *this; } /// Replace by copying another shared pointer. /// The shared pointer itself. /// The shared pointer to copy. Ptr& operator=(const Ptr& pointer) { if (this != &pointer) { Dec(); counter = pointer.counter; reference = pointer.reference; originalReference = pointer.originalReference; originalDestructor = pointer.originalDestructor; Inc(); } return *this; } /// Replace by moving another shared pointer. /// The shared pointer itself. /// The shared pointer to copy. Ptr& operator=(Ptr&& pointer) { if (this != &pointer) { Dec(); 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; } bool operator!=(const T* pointer)const { return reference != pointer; } bool operator>(const T* pointer)const { return reference > pointer; } bool operator>=(const T* pointer)const { return reference >= pointer; } bool operator<(const T* pointer)const { return reference < pointer; } bool operator<=(const T* pointer)const { return reference <= pointer; } bool operator==(const Ptr& pointer)const { return reference == pointer.reference; } bool operator!=(const Ptr& pointer)const { return reference != pointer.reference; } bool operator>(const Ptr& pointer)const { return reference > pointer.reference; } bool operator>=(const Ptr& pointer)const { return reference >= pointer.reference; } bool operator<(const Ptr& pointer)const { return reference < pointer.reference; } bool operator<=(const Ptr& pointer)const { return reference <= pointer.reference; } /// Test if it is an empty shared pointer. /// Returns true if it is non-null. operator bool()const { return reference != 0; } /// Get the pointer to the contained object. /// The pointer to the contained object. Returns null for an empty shared pointer. T* Obj()const { return reference; } /// Get the pointer to the contained object. /// The pointer to the contained object. Returns null for an empty shared pointer. T* operator->()const { return reference; } }; template Ptr(C*) -> Ptr; /*********************************************************************** ComPtr ***********************************************************************/ template class ComPtr { protected: volatile vint* counter = nullptr; T* reference = nullptr; void SetEmpty() { counter = nullptr; reference = nullptr; } void Inc() { if (counter) { INCRC(counter); } } void Dec() { if (counter) { if (DECRC(counter) == 0) { delete counter; reference->Release(); SetEmpty(); } } } volatile vint* Counter()const { return counter; } ComPtr(volatile vint* _counter, T* _reference) :counter(_counter) , reference(_reference) { Inc(); } public: ComPtr() = default; ComPtr(std::nullptr_t) {} ComPtr(T* pointer) { if (pointer) { counter = new volatile vint(1); reference = pointer; } else { SetEmpty(); } } ComPtr(const ComPtr& pointer) { counter = pointer.counter; reference = pointer.reference; Inc(); } ComPtr(ComPtr&& pointer) { counter = pointer.counter; reference = pointer.reference; pointer.SetEmpty(); } ~ComPtr() { Dec(); } ComPtr& operator=(std::nullptr_t) { Dec(); SetEmpty(); return *this; } ComPtr& operator=(T* pointer) { Dec(); if (pointer) { counter = new vint(1); reference = pointer; } else { SetEmpty(); } return *this; } ComPtr& operator=(const ComPtr& pointer) { if (this != &pointer) { Dec(); counter = pointer.counter; reference = pointer.reference; Inc(); } return *this; } ComPtr& operator=(ComPtr&& pointer) { if (this != &pointer) { Dec(); counter = pointer.counter; reference = pointer.reference; pointer.SetEmpty(); } return *this; } bool operator==(const T* pointer)const { return reference == pointer; } bool operator!=(const T* pointer)const { return reference != pointer; } bool operator>(const T* pointer)const { return reference > pointer; } bool operator>=(const T* pointer)const { return reference >= pointer; } bool operator<(const T* pointer)const { return reference < pointer; } bool operator<=(const T* pointer)const { return reference <= pointer; } bool operator==(const ComPtr& pointer)const { return reference == pointer.reference; } bool operator!=(const ComPtr& pointer)const { return reference != pointer.reference; } bool operator>(const ComPtr& pointer)const { return reference > pointer.reference; } bool operator>=(const ComPtr& pointer)const { return reference >= pointer.reference; } bool operator<(const ComPtr& pointer)const { return reference < pointer.reference; } bool operator<=(const ComPtr& pointer)const { return reference <= pointer.reference; } operator bool()const { return reference != nullptr; } T* Obj()const { return reference; } T* operator->()const { return reference; } }; template ComPtr(C*) ->ComPtr; /*********************************************************************** Traits ***********************************************************************/ template struct KeyType> { typedef T* Type; static T* GetKeyValue(const Ptr& key) { return key.Obj(); } }; template struct KeyType> { typedef T* Type; static T* GetKeyValue(const ComPtr& key) { return key.Obj(); } }; } #endif /*********************************************************************** .\COLLECTIONS\INTERFACES.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_INTERFACES #define VCZH_COLLECTIONS_INTERFACES namespace vl { namespace collections { /*********************************************************************** Reflection ***********************************************************************/ class ICollectionReference : public virtual Interface { public: virtual void OnDisposed() = 0; }; /*********************************************************************** Interfaces ***********************************************************************/ /// An enumerator interface for receiving values without going back. /// Type of the values returned from the enumerator. template class IEnumerator : public virtual Interface { public: typedef T ElementType; /// Copy the enumerator with the current state. /// The copied enumerator. virtual IEnumerator* Clone()const=0; /// Get the reference to the current value in the enumerator. /// The reference to the current value. /// /// After calling , need to be called to make the first value available. /// Return value of will be changed after each time is called. /// If returns false, the behavior of is undefined. /// virtual const T& Current()const=0; /// Get the position of the current value in the enumerator. /// The position of the current value. /// /// After calling , need to be called to make the first value available. /// Index will be increased after each time is called with true returned. /// virtual vint Index()const=0; /// Prepare for the next value. /// Returns false if there is no more value. virtual bool Next()=0; /// Reset the enumerator. virtual void Reset()=0; /// Test if all values of this enumerator have been evaluated. /// Returns true if all values have been evaluated. /// An evaluated enumerator typically means, there will be no more calculation happens in regardless if all values have been read or not. virtual bool Evaluated()const{return false;} }; /// /// An enumerable interface representing all types that provide multiple values in order. /// range-based for-loop is available on enumerable yet. /// by applying the indexed function on the collection, a tuple of value and index is returned, structured binding could apply. /// functions work for all enumerable implementation. /// provides high-level operations for enumerables, you can create a lazy list by calling on any enumerables. /// /// xs; /// for (vint i = 0; i < 10; i++) /// xs.Add(i); /// List ys; /// /// // replace values in ys using xs, it could also be appending instead of replacing, which is controlled by the third argument /// CopyFrom(ys, xs); /// /// // print ys /// for (auto y : ys) /// Console::Write(itow(y) + L" "); /// Console::WriteLine(L""); /// /// // print ys, added by the position /// for (auto [y, i] : indexed(ys)) /// Console::Write(itow(y + i) + L" "); /// Console::WriteLine(L""); /// /// // print all odd numbers in ys /// for (auto y : From(ys).Where([](int a){return a % 2 == 1;})) /// Console::Write(itow(y) + L" "); /// Console::WriteLine(L""); /// } /// ]]> /// Type of the values in the enumerable. template class IEnumerable : public virtual Interface { public: typedef T ElementType; /// /// Create an enumerator. [M:vl.collections.IEnumerator`1.Next] should be called before reading the first value. /// /// /// In most of the cases, you do not need to call this function. /// "for (auto x : xs);", "for (auto [x, i] : indexed(xs));", and do all the jobs for you. /// /// The enumerator. virtual IEnumerator* CreateEnumerator() const = 0; /// Get the underlying collection object. /// The underlying collection object, could be nullptr. virtual const Object* GetCollectionObject() const = 0; /// Get the associated collection reference. /// The associated collection reference. virtual Ptr GetCollectionReference() const = 0; /// /// Associate a collection reference to this collection. /// It will crash if one has been associated. /// will be called when this collection is no longer available. /// /// The associated collection reference. virtual void SetCollectionReference(Ptr ref) const = 0; /// /// Get the strong-typed associated collection reference. /// It returns nullptr when none has been associated. /// It throws when one has been associated but the type is unexpected. /// /// The expected type of the associated collection reference. /// The strong-typed associated collection reference. template Ptr TryGetCollectionReference() { auto ref = GetCollectionReference(); if (!ref) return nullptr; auto sref = ref.template Cast(); CHECK_ERROR(sref, L"IEnumerable::TryGetCollectionReference()#The associated collection reference has an unexpected type."); return sref; } }; template class EnumerableBase : public Object, public virtual IEnumerable { private: mutable Ptr colref; public: ~EnumerableBase() { if (colref) colref->OnDisposed(); } const Object* GetCollectionObject() const override { return this; } Ptr GetCollectionReference() const override { return colref; } void SetCollectionReference(Ptr ref) const override { CHECK_ERROR(!colref, L"EnumerableBase::SetCollectionReference(Ptr)#Cannot associate another collection reference to this collection."); colref = ref; } }; /*********************************************************************** Random Access ***********************************************************************/ namespace randomaccess_internal { template struct RandomAccessable { static const bool CanRead = false; static const bool CanResize = false; }; template struct RandomAccess { static vint GetCount(const T& t) { return t.Count(); } static const typename T::ElementType& GetValue(const T& t, vint index) { return t.Get(index); } static void SetCount(T& t, vint count) { t.Resize(count); } static void SetValue(T& t, vint index, const typename T::ElementType& value) { t.Set(index, value); } template static void AppendValue(T& t, V&& value) { t.Add(value); } }; } } } #endif /*********************************************************************** .\COLLECTIONS\LIST.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_LIST #define VCZH_COLLECTIONS_LIST #include #ifdef VCZH_CHECK_MEMORY_LEAKS_NEW #undef new #endif #include namespace vl { namespace collections { /*********************************************************************** Memory Management ***********************************************************************/ namespace memory_management { template void CallDefaultCtors(T* items, vint count) { if constexpr (!std::is_trivially_constructible_v) { for (vint i = 0; i < count; i++) { new(&items[i])T(); } } } template void CallCopyCtors(T* items, const T* source, vint count) { if constexpr (!std::is_trivially_copy_constructible_v) { for (vint i = 0; i < count; i++) { new(&items[i])T(source[i]); } } else { memcpy(items, source, sizeof(T) * count); } } template void CallMoveCtors(T* items, T* source, vint count) { if constexpr (!std::is_trivially_move_constructible_v) { for (vint i = 0; i < count; i++) { new(&items[i])T(std::move(source[i])); } } else { memcpy(items, source, sizeof(T) * count); } } template void CallMoveAssignmentsOverlapped(T* items, T* source, vint count) { if constexpr (!std::is_trivially_move_assignable_v) { if (items < source) { for (vint i = 0; i < count; i++) { items[i] = std::move(source[i]); } } else if (items > source) { for (vint i = count - 1; i >= 0; i--) { items[i] = std::move(source[i]); } } } else { memmove(items, source, sizeof(T) * count); } } template void CallDtors(T* items, vint count) { if constexpr (!std::is_trivially_destructible_v) { for (vint i = 0; i < count; i++) { items[i].~T(); } } } template T* AllocateBuffer(vint size) { if (size <= 0) return nullptr; return (T*)malloc(sizeof(T) * size); } template void DeallocateBuffer(T* buffer) { if (buffer == nullptr) return; free(buffer); } template void ReleaseUnnecessaryBuffer(T*& items, vint& capacity, vint oldCount, vint newCount) { if (!items) return; if(newCount < oldCount) { CallDtors(&items[newCount], oldCount - newCount); } if (newCount <= capacity / 2 && newCount <= 8) { vint newCapacity = capacity * 5 / 8; if (newCount < newCapacity) { T* newBuffer = AllocateBuffer(newCapacity); CallMoveCtors(newBuffer, items, newCount); CallDtors(items, newCount); DeallocateBuffer(items); capacity = newCapacity; items = newBuffer; } } } template void InsertUninitializedItems(T*& items, vint& capacity, vint& count, vint index, vint insertCount) { vint newCount = count + insertCount; if (newCount > capacity) { vint newCapacity = newCount < capacity ? capacity : (newCount * 5 / 4 + 1); T* newBuffer = AllocateBuffer(newCapacity); CallMoveCtors(newBuffer, items, index); CallMoveCtors(&newBuffer[index + insertCount], &items[index], count - index); CallDtors(items, count); DeallocateBuffer(items); capacity = newCapacity; items = newBuffer; } else if (index < count) { if (insertCount >= (count - index)) { CallMoveCtors(&items[index + insertCount], &items[index], count - index); CallDtors(&items[index], count - index); } else { CallMoveCtors(&items[count], &items[count - insertCount], insertCount); CallMoveAssignmentsOverlapped(&items[index + insertCount], &items[index], count - index - insertCount); CallDtors(&items[index], insertCount); } } count = newCount; } template, std::remove_cvref_t>> struct Accept_; template struct Accept_ { using TAccept = TArg; using TForward = TArg; }; template struct Accept_ { using TAccept = TItem; using TForward = TItem&&; }; template using AcceptType = typename Accept_::TAccept; template using ForwardType = typename Accept_::TForward; template AcceptType RefOrConvert(TArg&& arg) { return std::forward(arg); } } /*********************************************************************** ArrayBase ***********************************************************************/ /// Base type of all linear container. /// Type of elements. template class ArrayBase abstract : public EnumerableBase { protected: class Enumerator : public Object, public virtual IEnumerator { private: const ArrayBase* container; vint index; public: Enumerator(const ArrayBase* _container, vint _index = -1) { container = _container; index = _index; } IEnumerator* Clone()const override { return new Enumerator(container, index); } const T& Current()const override { return container->Get(index); } vint Index()const override { return index; } bool Next() override { index++; return index >= 0 && index < container->Count(); } void Reset() override { index = -1; } bool Evaluated()const override { return true; } }; T* buffer = nullptr; vint count = 0; ArrayBase() = default; public: IEnumerator* CreateEnumerator()const { return new Enumerator(this); } /// Get the number of elements in the container. /// The number of elements. vint Count()const { return count; } /// Get the reference to the specified element. /// The reference to the specified element. It will crash when the index is out of range. /// The index of the element. const T& Get(vint index)const { CHECK_ERROR(index >= 0 && index < this->count, L"ArrayBase::Get(vint)#Argument index not in range."); return this->buffer[index]; } /// Get the reference to the specified element. /// The reference to the specified element. It will crash when the index is out of range. /// The index of the element. const T& operator[](vint index)const { CHECK_ERROR(index >= 0 && index < this->count, L"ArrayBase::operator[](vint)#Argument index not in range."); return this->buffer[index]; } }; /*********************************************************************** Array ***********************************************************************/ /// Array: linear container with fixed size in runtime. All elements are contiguous in memory. /// Type of elements. template class Array : public ArrayBase { using K = typename KeyType::Type; public: /// Create an array. /// The size of the array. /// /// The default value is zero. can be called to determine the size later. /// It will crash when the size is a negative number. /// Array(vint size = 0) { CHECK_ERROR(size >= 0, L"Array::Array(vint)#Size should not be negative."); this->buffer = memory_management::AllocateBuffer(size); memory_management::CallDefaultCtors(this->buffer, size); this->count = size; } /// Create an array with elements provided. /// Pointer to values to copy. /// The number of values to copy. /// It will crash when the size is a negative number. Array(const T* _buffer, vint size) { CHECK_ERROR(size >= 0, L"Array::Array(const T*, vint)#Size should not be negative."); this->buffer = memory_management::AllocateBuffer(size); memory_management::CallCopyCtors(this->buffer, _buffer, size); this->count = size; } ~Array() { if (this->buffer) { memory_management::CallDtors(this->buffer, this->count); memory_management::DeallocateBuffer(this->buffer); } } Array(const Array&) = delete; Array(Array&& _move) { this->buffer = _move.buffer; this->count = _move.count; _move.buffer = nullptr; _move.count = 0; } Array& operator=(const Array&) = delete; Array& operator=(Array&& _move) { if (this->buffer) { memory_management::CallDtors(this->buffer, this->count); memory_management::DeallocateBuffer(this->buffer); } this->buffer = _move.buffer; this->count = _move.count; _move.buffer = nullptr; _move.count = 0; return *this; } /// Test does the array contain a value or not. /// Returns true if the array contains the specified value. /// The value to test. bool Contains(const K& item)const { return IndexOf(item) != -1; } /// Get the position of a value in this array. /// Returns the position of first element that equals to the specified value. Returns -1 if failed to find. /// The value to find. vint IndexOf(const K& item)const { for (vint i = 0; i < this->count; i++) { if (this->buffer[i] == item) { return i; } } return -1; } /// Replace an element in the specified position. /// The type of the new value. /// Returns true if this operation succeeded. It will crash when the index is out of range /// The position of the element to replace. /// The new value to replace. template bool Set(vint index, TItem&& item) { CHECK_ERROR(index >= 0 && index < this->count, L"Array::Set(vint)#Argument index not in range."); this->buffer[index] = std::forward(item); return true; } bool Set(vint index, T&& item) { return Set(index, std::move(item)); } using ArrayBase::operator[]; /// Get the reference to the specified element. /// The reference to the specified element. It will crash when the index is out of range. /// The index of the element. T& operator[](vint index) { CHECK_ERROR(index >= 0 && index < this->count, L"Array::operator[](vint)#Argument index not in range."); return this->buffer[index]; } /// Change the size of the array. This function can be called multiple times to change the size. /// The new size of the array. /// It will crash when the size is a negative number. void Resize(vint size) { CHECK_ERROR(size >= 0, L"Array::Resize(vint)#Size should not be negative."); T* newBuffer = memory_management::AllocateBuffer(size); if (size < this->count) { memory_management::CallMoveCtors(newBuffer, this->buffer, size); } else { memory_management::CallMoveCtors(newBuffer, this->buffer, this->count); memory_management::CallDefaultCtors(&newBuffer[this->count], size - this->count); } memory_management::CallDtors(this->buffer, this->count); memory_management::DeallocateBuffer(this->buffer); this->buffer = newBuffer; this->count = size; } }; /*********************************************************************** ListBase ***********************************************************************/ /// Base type for all list containers. /// Type of elements. template class ListBase abstract : public ArrayBase { using K = typename KeyType::Type; protected: vint capacity = 0; public: ListBase() = default; ~ListBase() { if (this->buffer) { memory_management::CallDtors(this->buffer, this->count); memory_management::DeallocateBuffer(this->buffer); } } ListBase(const ListBase&) = delete; ListBase(ListBase&& _move) { this->buffer = _move.buffer; this->count = _move.count; this->capacity = _move.capacity; _move.buffer = nullptr; _move.count = 0; _move.capacity = 0; } ListBase& operator=(const ListBase&) = delete; ListBase& operator=(ListBase&& _move) { if (this->buffer) { memory_management::CallDtors(this->buffer, this->count); memory_management::DeallocateBuffer(this->buffer); } this->buffer = _move.buffer; this->count = _move.count; this->capacity = _move.capacity; _move.buffer = nullptr; _move.count = 0; _move.capacity = 0; return *this; } /// Remove an element at a specified position. /// Returns true if the element is removed. It will crash when the index is out of range. /// The index of the element to remove. bool RemoveAt(vint index) { vint previousCount = this->count; CHECK_ERROR(index >= 0 && index < this->count, L"ListBase::RemoveAt(vint)#Argument index not in range."); memory_management::CallMoveAssignmentsOverlapped(&this->buffer[index], &this->buffer[index + 1], this->count - index - 1); this->count--; memory_management::ReleaseUnnecessaryBuffer(this->buffer, this->capacity, previousCount, this->count); return true; } /// Remove contiguous elements at a specified psition. /// Returns true if elements are removed. It will crash when the index or the size is out of range. /// The index of the first element to remove. /// The number of elements to remove. bool RemoveRange(vint index, vint _count) { vint previousCount = this->count; CHECK_ERROR(index >= 0 && index <= this->count, L"ListBase::RemoveRange(vint, vint)#Argument index not in range."); CHECK_ERROR(index + _count >= 0 && index + _count <= this->count, L"ListBase::RemoveRange(vint, vint)#Argument _count not in range."); memory_management::CallMoveAssignmentsOverlapped(&this->buffer[index], &this->buffer[index + _count], this->count - index - _count); this->count -= _count; memory_management::ReleaseUnnecessaryBuffer(this->buffer, this->capacity, previousCount, this->count); return true; } /// Remove all elements. /// Returns true if all elements are removed. bool Clear() { vint previousCount = this->count; this->count = 0; this->capacity = 0; memory_management::CallDtors(this->buffer, previousCount); memory_management::DeallocateBuffer(this->buffer); this->buffer = nullptr; return true; } }; /*********************************************************************** List ***********************************************************************/ /// List: linear container with dynamic size in runtime for unordered values. All elements are contiguous in memory. /// Type of elements. template class List : public ListBase { using K = typename KeyType::Type; public: /// Create an empty list. List() = default; List(List&& container) : ListBase(std::move(container)) {} List& operator=(List&& _move) = default; /// Test does the list contain a value or not. /// Returns true if the list contains the specified value. /// The value to test. bool Contains(const K& item)const { return IndexOf(item) != -1; } /// Get the position of a value in this list. /// Returns the position of first element that equals to the specified value. Returns -1 if failed to find. /// The value to find. vint IndexOf(const K& item)const { for (vint i = 0; i < this->count; i++) { if (this->buffer[i] == item) { return i; } } return -1; } /// Append a value at the end of the list. /// The type of the new value. /// The index of the added item. /// The value to add. template vint Add(TItem&& item) { return Insert(this->count, std::forward(item)); } vint Add(T&& item) { return Add(std::move(item)); } /// Insert a value at the specified position. /// The index of the added item. It will crash if the index is out of range /// The position to insert the value. /// The value to add. vint Insert(vint index, const T& item) { CHECK_ERROR(index >= 0 && index <= this->count, L"List::Insert(vint, const T&)#Argument index not in range."); memory_management::InsertUninitializedItems(this->buffer, this->capacity, this->count, index, 1); memory_management::CallCopyCtors(&this->buffer[index], &item, 1); return index; } /// Insert a value at the specified position. /// The index of the added item. It will crash if the index is out of range /// The position to insert the value. /// The value to add. vint Insert(vint index, T&& item) { CHECK_ERROR(index >= 0 && index <= this->count, L"List::Insert(vint, const T&)#Argument index not in range."); memory_management::InsertUninitializedItems(this->buffer, this->capacity, this->count, index, 1); memory_management::CallMoveCtors(&this->buffer[index], &item, 1); return index; } /// Remove an element from the list. If multiple elements equal to the specified value, only the first one will be removed /// Returns true if the element is removed. /// The item to remove. bool Remove(const K& item) { vint index = IndexOf(item); if (index >= 0 && index < this->count) { this->RemoveAt(index); return true; } else { return false; } } /// Replace an element in the specified position. /// The type of the new value. /// Returns true if this operation succeeded. It will crash when the index is out of range /// The position of the element to replace. /// The new value to replace. template bool Set(vint index, TItem&& item) { CHECK_ERROR(index >= 0 && index < this->count, L"List::Set(vint)#Argument index not in range."); this->buffer[index] = std::forward(item); return true; } bool Set(vint index, T&& item) { return Set(index, std::move(item)); } using ListBase::operator[]; /// Get the reference to the specified element. /// The reference to the specified element. It will crash when the index is out of range. /// The index of the element. T& operator[](vint index) { CHECK_ERROR(index >= 0 && index < this->count, L"List::operator[](vint)#Argument index not in range."); return this->buffer[index]; } }; /*********************************************************************** SortedList ***********************************************************************/ /// SortedList: linear container with dynamic size in runtime for ordered values. All elements are kept in order, and are contiguous in memory. /// Type of elements. template class SortedList : public ListBase { using K = typename KeyType::Type; protected: /// Get the position of an element in this list by performing binary search. /// Type of the element to find. /// Returns the position. Returns -1 if it does not exist. /// The element to find. /// /// If the element exist, this argument returns one of the element that equals to the specified value. /// If the element doesn not exist, /// this argument returns either the greatest element that less than the specified value, /// or the lest element that greater than the specified value. /// template vint IndexOfInternal(const Key& item, vint& index)const { vint start = 0; vint end = this->count - 1; index = -1; while (start <= end) { index = start + (end - start) / 2; if (this->buffer[index] == item) { return index; } else if (this->buffer[index] > item) { end = index - 1; } else { start = index + 1; } } return -1; } vint Insert(vint index, const T& item) { bool uninitialized = false; memory_management::InsertUninitializedItems(this->buffer, this->capacity, this->count, index, 1); memory_management::CallCopyCtors(&this->buffer[index], &item, 1); return index; } vint Insert(vint index, T&& item) { bool uninitialized = false; memory_management::InsertUninitializedItems(this->buffer, this->capacity, this->count, index, 1); memory_management::CallMoveCtors(&this->buffer[index], &item, 1); return index; } public: /// Create an empty list. SortedList() = default; SortedList(SortedList&& container) : ListBase(std::move(container)) {} SortedList& operator=(SortedList && _move) = default; SortedList(const SortedList&xs) : ListBase(std::move(const_cast&>(static_cast&>(xs)))) { } /// Test does the list contain a value or not. /// Returns true if the list contains the specified value. /// The value to test. bool Contains(const K& item)const { return IndexOf(item) != -1; } /// Get the position of a value in this list. /// Returns the position of first element that equals to the specified value. Returns -1 if failed to find. /// The value to find. vint IndexOf(const K& item)const { vint outputIndex = -1; return IndexOfInternal(item, outputIndex); } /// Add a value at the correct position, all elements will be kept in order. /// The type of the new value. /// The index of the added item. /// The value to add. template vint Add(TItem&& item) { if (ArrayBase::count == 0) { return Insert(0, std::forward(item)); } else { vint outputIndex = -1; if constexpr (std::is_same_v, std::remove_cvref_t>) { IndexOfInternal(item, outputIndex); } else if constexpr (std::is_same_v, std::remove_cvref_t>) { IndexOfInternal(item, outputIndex); } else { IndexOfInternal(KeyType::GetKeyValue(item), outputIndex); } CHECK_ERROR(outputIndex >= 0 && outputIndex < this->count, L"SortedList::Add(const T&)#Internal error, index not in range."); if (this->buffer[outputIndex] < item) { outputIndex++; } return Insert(outputIndex, std::forward(item)); } } vint Add(T&& item) { return Add(std::move(item)); } /// Remove an element from the list. If multiple elements equal to the specified value, only the first one will be removed /// Returns true if the element is removed. /// The item to remove. bool Remove(const K& item) { vint index = IndexOf(item); if (index >= 0 && index < ArrayBase::count) { this->RemoveAt(index); return true; } else { return false; } } }; /*********************************************************************** Special Containers ***********************************************************************/ template class PushOnlyAllocator : public Object { protected: vint blockSize; vint allocatedSize; List blocks; public: NOT_COPYABLE(PushOnlyAllocator); PushOnlyAllocator(vint _blockSize = 65536) :blockSize(_blockSize) , allocatedSize(0) { } ~PushOnlyAllocator() { for (vint i = 0; i < blocks.Count(); i++) { delete[] blocks[i]; } } T* Get(vint index) { if (index >= allocatedSize) { return 0; } vint row = index / blockSize; vint column = index % blockSize; return &blocks[row][column]; } T* Create() { if (allocatedSize == blocks.Count()*blockSize) { blocks.Add(new T[blockSize]); } vint index = allocatedSize++; return Get(index); } }; namespace bom_helper { struct TreeNode { TreeNode* nodes[4]; }; template struct Accessor { static __forceinline void* Get(TreeNode* root, vuint8_t index) { if (!root) { return nullptr; } vint fragmentIndex = (index >> (2 * (Index - 1))) % 4; TreeNode* fragmentRoot = root->nodes[fragmentIndex]; return fragmentRoot ? Accessor::Get(fragmentRoot, index) : 0; } static __forceinline void Set(TreeNode*& root, vuint8_t index, void* value, PushOnlyAllocator& allocator) { if (!root) { root = allocator.Create(); memset(root->nodes, 0, sizeof(root->nodes)); } vint fragmentIndex = (index >> (2 * (Index - 1))) % 4; TreeNode*& fragmentRoot = root->nodes[fragmentIndex]; Accessor::Set(fragmentRoot, index, value, allocator); } }; template<> struct Accessor<0> { static __forceinline void* Get(TreeNode* root, vuint8_t index) { return (void*)root; } static __forceinline void Set(TreeNode*& root, vuint8_t index, void* value, PushOnlyAllocator& allocator) { ((void*&)root) = value; } }; } template class ByteObjectMap : public Object { public: typedef PushOnlyAllocator Allocator; protected: bom_helper::TreeNode* root = nullptr; public: NOT_COPYABLE(ByteObjectMap); ByteObjectMap() = default; ~ByteObjectMap() = default; T* Get(vuint8_t index) { return (T*)bom_helper::Accessor<>::Get(root, index); } void Set(vuint8_t index, T* value, Allocator& allocator) { bom_helper::Accessor<>::Set(root, index, value, allocator); } }; /*********************************************************************** Random Access ***********************************************************************/ namespace randomaccess_internal { template struct RandomAccessable> { static const bool CanRead = true; static const bool CanResize = true; }; template struct RandomAccessable> { static const bool CanRead = true; static const bool CanResize = false; }; template struct RandomAccessable> { static const bool CanRead = true; static const bool CanResize = false; }; } } } #ifdef VCZH_CHECK_MEMORY_LEAKS_NEW #define new VCZH_CHECK_MEMORY_LEAKS_NEW #endif #endif /*********************************************************************** .\COLLECTIONS\DICTIONARY.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_DICTIONARY #define VCZH_COLLECTIONS_DICTIONARY namespace vl { namespace collections { /// Dictionary: one to one map container. /// Type of keys. /// Type of values. template class Dictionary : public EnumerableBase> { using KK = typename KeyType::Type; using VK = typename KeyType::Type; using KVPair = Pair; public: typedef SortedList KeyContainer; typedef List ValueContainer; protected: class Enumerator : public Object, public virtual IEnumerator { private: const Dictionary* container; vint index; KVPair current; void UpdateCurrent() { if(indexCount()) { current = { container->Keys().Get(index),container->Values().Get(index) }; } } public: Enumerator(const Dictionary* _container, vint _index=-1) { container=_container; index=_index; } IEnumerator* Clone()const override { return new Enumerator(container, index); } const KVPair& Current()const override { return current; } vint Index()const override { return index; } bool Next() override { index++; UpdateCurrent(); return index>=0 && indexCount(); } void Reset() override { index=-1; UpdateCurrent(); } bool Evaluated()const override { return true; } }; KeyContainer keys; ValueContainer values; public: /// Create an empty dictionary. Dictionary() = default; ~Dictionary() = default; Dictionary(const Dictionary&) = delete; Dictionary(Dictionary&& _move) : keys(std::move(_move.keys)) , values(std::move(_move.values)) { } Dictionary& operator=(const Dictionary&) = delete; Dictionary& operator=(Dictionary && _move) { keys = std::move(_move.keys); values = std::move(_move.values); return* this; } IEnumerator* CreateEnumerator()const { return new Enumerator(this); } /// Get all keys. /// All keys. const KeyContainer& Keys()const { return keys; } /// Get all values. /// All values. const ValueContainer& Values()const { return values; } /// Get the number of keys. /// The number of keys. It is also the number of values. vint Count()const { return keys.Count(); } /// Get the reference to the value associated to a specified key. /// The reference to the value. It will crash if the key does not exist. /// The key to find. const VT& Get(const KK& key)const { return values.Get(keys.IndexOf(key)); } /// Get the reference to the value associated to a specified key. /// The reference to the value. It will crash if the key does not exist. /// The key to find. const VT& operator[](const KK& key)const { return values.Get(keys.IndexOf(key)); } /// Replace the value associated to a specified key. /// The type of the new key. /// The type of the new value. /// Returns true if the value is replaced. /// The key to find. If the key does not exist, it will be added to the dictionary. /// The associated value to replace. template bool Set(TKeyItem&& key, TValueItem&& value) { using TKeyAccept = memory_management::AcceptType; using TKeyForward = memory_management::ForwardType; TKeyAccept keyAccept = memory_management::RefOrConvert(std::forward(key)); vint index = keys.IndexOf(KeyType::GetKeyValue(keyAccept)); if (index == -1) { index = keys.Add(std::forward(keyAccept)); values.Insert(index, std::forward(value)); } else { values[index] = std::forward(value); } return true; } bool Set(const KT& key, const VT& value) { return Set(key, value); } bool Set(const KT& key, VT&& value) { return Set(key, std::move(value)); } bool Set(KT&& key, const VT& value) { return Set(std::move(key), value); } bool Set(KT&& key, VT&& value) { return Set(std::move(key), std::move(value)); } /// Add a key with an associated value. /// Returns true if the pair is added. If will crash if the key exists. /// The pair of key and value. bool Add(const Pair& value) { return Add(value.key, value.value); } /// Add a key with an associated value. /// Returns true if the pair is added. If will crash if the key exists. /// The pair of key and value. bool Add(Pair&& value) { return Add(std::move(value.key), std::move(value.value)); } /// Add a key with an associated value. /// The type of the new key. /// The type of the new value. /// Returns true if the pair is added. If will crash if the key exists. /// The key to add. /// The value to add. template bool Add(TKeyItem&& key, TValueItem&& value) { using TKeyAccept = memory_management::AcceptType; using TKeyForward = memory_management::ForwardType; TKeyAccept keyAccept = memory_management::RefOrConvert(std::forward(key)); CHECK_ERROR(!keys.Contains(KeyType::GetKeyValue(keyAccept)), L"Dictionary::Add(const KT&, const VT&)#Key already exists."); vint index = keys.Add(std::forward(keyAccept)); values.Insert(index, std::forward(value)); return true; } bool Add(const KT& key, const VT& value) { return Add(key, value); } bool Add(const KT& key, VT&& value) { return Add(key, std::move(value)); } bool Add(KT&& key, const VT& value) { return Add(std::move(key), value); } bool Add(KT&& key, VT&& value) { return Add(std::move(key), std::move(value)); } /// Remove a key with the associated value. /// Returns true if the key and the value is removed. /// The key to find. bool Remove(const KK& key) { vint index=keys.IndexOf(key); if(index!=-1) { keys.RemoveAt(index); values.RemoveAt(index); return true; } else { return false; } } /// Remove all elements. /// Returns true if all elements are removed. bool Clear() { keys.Clear(); values.Clear(); return true; } }; /// Group: one to many map container. /// Type of keys. /// Type of values. template class Group : public EnumerableBase> { using KK = typename KeyType::Type; using VK = typename KeyType::Type; using KVPair = Pair; public: typedef SortedList KeyContainer; typedef List ValueContainer; protected: class Enumerator : public Object, public virtual IEnumerator { private: const Group* container; vint keyIndex; vint valueIndex; KVPair current; void UpdateCurrent() { if (keyIndex < container->Count()) { const ValueContainer& values = container->GetByIndex(keyIndex); if (valueIndex < values.Count()) { current = { container->Keys().Get(keyIndex) ,values.Get(valueIndex) }; } } } public: Enumerator(const Group* _container, vint _keyIndex=-1, vint _valueIndex=-1) { container=_container; keyIndex=_keyIndex; valueIndex=_valueIndex; } IEnumerator* Clone()const override { return new Enumerator(container, keyIndex, valueIndex); } const KVPair& Current()const override { return current; } vint Index()const override { if(0<=keyIndex && keyIndexCount()) { vint index=0; for(vint i=0;iGetByIndex(i).Count(); } return index+valueIndex; } else { return -1; } } bool Next() override { if(keyIndex==-1) { keyIndex=0; } while(keyIndexCount()) { valueIndex++; const ValueContainer& values=container->GetByIndex(keyIndex); if(valueIndex values; public: /// Create an empty group. Group() = default; ~Group() { Clear(); } Group(const Group&) = delete; Group(Group&& _move) : keys(std::move(_move.keys)) , values(std::move(_move.values)) { } Group& operator=(const Group&) = delete; Group& operator=(Group && _move) { Clear(); keys = std::move(_move.keys); values = std::move(_move.values); return*this; } IEnumerator* CreateEnumerator()const { return new Enumerator(this); } /// Get all keys. /// All keys. const KeyContainer& Keys()const { return keys; } /// Get the number of keys. /// The number of keys. vint Count()const { return keys.Count(); } /// Get all values associated to a specified key. /// All associated values. It will crash if the key does not exist. /// The key to find. const ValueContainer& Get(const KK& key)const { return *values.Get(keys.IndexOf(key)); } /// Get all values associated to a key at a specified index in . /// All associaged values. It will crash if the index is out of range. /// The position of the key. const ValueContainer& GetByIndex(vint index)const { return *values.Get(index); } /// Get all values associated to a specified key. /// All associated values. It will crash if the key does not exist. /// The key to find. const ValueContainer& operator[](const KK& key)const { return *values.Get(keys.IndexOf(key)); } /// Test if there is any value associated to a specified key or not. /// Returns true there is at least one value associated to this key. /// The key to find. bool Contains(const KK& key)const { return keys.Contains(key); } /// Test if a value is associated to a specified key or not. /// Returns true if the specified value is associated to the specified key. /// The key to find. /// The value to find. bool Contains(const KK& key, const VK& value)const { vint index=keys.IndexOf(key); if(index!=-1) { return values.Get(index)->Contains(value); } else { return false; } } /// /// Add a key with an associated value. /// If the key already exists, the value will be associated to the key with other values. /// If this value has already been associated to the key, it will still be duplicated. /// /// Returns true if the pair is added. /// The pair of key and value to add. bool Add(const Pair& value) { return Add(value.key, value.value); } /// /// Add a key with an associated value. /// If the key already exists, the value will be associated to the key with other values. /// If this value has already been associated to the key, it will still be duplicated. /// /// Returns true if the pair is added. /// The pair of key and value to add. bool Add(Pair&& value) { return Add(std::move(value.key), std::move(value.value)); } /// /// Add a key with an associated value. /// If the key already exists, the value will be associated to the key with other values. /// If this value has already been associated to the key, it will still be duplicated. /// /// The type of the new key. /// The type of the new value. /// Returns true if the key and the value are added. /// The key to add. /// The value to add. template bool Add(TKeyItem&& key, TValueItem&& value) { using TKeyAccept = memory_management::AcceptType; using TKeyForward = memory_management::ForwardType; TKeyAccept keyAccept = memory_management::RefOrConvert(std::forward(key)); ValueContainer* target = nullptr; vint index = keys.IndexOf(KeyType::GetKeyValue(keyAccept)); if (index == -1) { target = new ValueContainer; values.Insert(keys.Add(std::forward(keyAccept)), target); } else { target = values[index]; } target->Add(std::forward(value)); return true; } bool Add(const KT& key, const VT& value) { return Add(key, value); } bool Add(const KT& key, VT&& value) { return Add(key, std::move(value)); } bool Add(KT&& key, const VT& value) { return Add(std::move(key), value); } bool Add(KT&& key, VT&& value) { return Add(std::move(key), std::move(value)); } /// Remove a key with all associated values. /// Returns true if the key and all associated values are removed. /// The key to find. bool Remove(const KK& key) { vint index=keys.IndexOf(key); if(index!=-1) { keys.RemoveAt(index); auto target=values[index]; values.RemoveAt(index); delete target; return true; } else { return false; } } /// Remove a value associated to a specified key. /// /// Returns true if the value is removed. /// If this value is associated to the key for jultiple times, only the first one will be removed. /// If this value is associated to the key for jultiple times, only the first one will be removed. /// /// The key to find. /// The value to remove. bool Remove(const KK& key, const VK& value) { vint index=keys.IndexOf(key); if(index!=-1) { auto target=values[index]; target->Remove(value); if(target->Count()==0) { keys.RemoveAt(index); values.RemoveAt(index); delete target; } return true; } else { return false; } } /// Remove everything. /// Returns true if all keys and values are removed. bool Clear() { for(vint i=0;iPerform inner join on two groups. /// The type of keys in two groups. /// The type of values in the first group. /// The type of values in the second group. /// The type of the first callback. /// The type of the second callback. /// The type of the third callback. /// The first group. /// The second group. /// /// Callback that is called when a value in the first group is discarded. /// This happens for values associated to a key in the first group, that no value is assocated to the same key in the second group. /// The first argument is the key, the second argument is the discarded value list in the first group. /// /// /// Callback that is called when a value in the second group is discarded. /// This happens for values associated to a key in the second group, that no value is assocated to the same key in the first group. /// The first argument is the key, the second argument is the discarded value list in the first group. /// /// /// Callback that is called when a match of values in both groups are found. /// This happens for any key that, values are associated to this key in both group. /// The first argument is the key, the second argument is the associated value list in the first group, the third argument list is the associated value in the second group. /// /// /// This function does not change data in provided groups. /// /// & values) /// { /// return L"[" + From(values).Aggregate([](const WString& a, const WString& b) { return a + L", " + b; }) + L"]"; /// }; /// /// Group as, bs; /// as.Add(1 ,L"A"); as.Add(1 ,L"B"); as.Add(2 ,L"C"); as.Add(2 ,L"D"); /// bs.Add(1 ,L"X"); bs.Add(1 ,L"Y"); bs.Add(3 ,L"Z"); bs.Add(3 ,L"W"); /// GroupInnerJoin( /// as, /// bs, /// [&](vint key, const List& values) { Console::WriteLine(L"Discarded in as: " + itow(key) + printList(values)); }, /// [&](vint key, const List& values) { Console::WriteLine(L"Discarded in bs: " + itow(key) + printList(values)); }, /// [&](vint key, const List& values1, const List& values2) { Console::WriteLine(L"Accepted: " + itow(key) + printList(values1) + printList(values2)); } /// ); /// } /// ]]> template< typename TKey, typename TValueFirst, typename TValueSecond, typename TDiscardFirst, // TKey * [TValueFirst] -> void typename TDiscardSecond, // TKey * [TValueSecond] -> void typename TAccept // TKey * [TValueFirst] * [TValueSecond] -> void > void GroupInnerJoin( const Group& first, const Group& second, const TDiscardFirst& discardFirst, const TDiscardSecond& discardSecond, const TAccept& accept ) { vint firstIndex = 0; vint secondIndex = 0; vint firstCount = first.Keys().Count(); vint secondCount = second.Keys().Count(); while (true) { if (firstIndex < firstCount) { auto firstKey = first.Keys()[firstIndex]; const List& firstValues = first.GetByIndex(firstIndex); if (secondIndex < secondCount) { auto secondKey = second.Keys()[secondIndex]; const List& secondValues = second.GetByIndex(secondIndex); if (firstKey < secondKey) { discardFirst(firstKey, firstValues); firstIndex++; } else if (firstKey > secondKey) { discardSecond(secondKey, secondValues); secondIndex++; } else { accept(firstKey, firstValues, secondValues); firstIndex++; secondIndex++; } } else { discardFirst(firstKey, firstValues); firstIndex++; } } else { if (secondIndex < secondCount) { auto secondKey = second.Keys()[secondIndex]; const List& secondValues = second.GetByIndex(secondIndex); discardSecond(secondKey, secondValues); secondIndex++; } else { break; } } } } /*********************************************************************** Random Access ***********************************************************************/ namespace randomaccess_internal { template struct RandomAccessable> { static const bool CanRead = true; static const bool CanResize = false; }; template struct RandomAccess> { static vint GetCount(const Dictionary& t) { return t.Count(); } static Pair GetValue(const Dictionary& t, vint index) { return Pair(t.Keys().Get(index), t.Values().Get(index)); } static void AppendValue(Dictionary& t, const Pair& value) { t.Set(value.key, value.value); } static void AppendValue(Dictionary& t, const Pair& value) { t.Set(value.key, value.value); } }; } } } #endif /*********************************************************************** .\COLLECTIONS\OPERATIONCOPYFROM.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_OPERATIONCOPYFROM #define VCZH_COLLECTIONS_OPERATIONCOPYFROM namespace vl { namespace collections { /*********************************************************************** Copy Functions for Containers ***********************************************************************/ namespace copyfrom_internal { using namespace randomaccess_internal; template struct CopyFromAlgorithm { }; template struct CopyFromAlgorithm { static void Perform(Ds& ds, const Ss& ss, bool append) { vint copyCount=RandomAccess::GetCount(ss); vint index=(append?RandomAccess::GetCount(ds):0); vint resizeCount=index+copyCount; RandomAccess::SetCount(ds, resizeCount); for(vint i=0;i::SetValue(ds, index+i, RandomAccess::GetValue(ss, i)); } } }; template struct CopyFromAlgorithm { static void Perform(Ds& ds, const Ss& ss, bool append) { if(!append) { ds.Clear(); } vint copyCount=RandomAccess::GetCount(ss); for(vint i=0;i::AppendValue(ds, RandomAccess::GetValue(ss, i)); } } }; template struct CopyFromAlgorithm { static void Perform(Ds& ds, const Ss& ss, bool append) { Ptr> enumerator; vint copyCount=0; enumerator = Ptr(ss.CreateEnumerator()); while(enumerator->Next()) { copyCount++; } vint index=(append?RandomAccess::GetCount(ds):0); vint resizeCount=index+copyCount; RandomAccess::SetCount(ds, resizeCount); enumerator = Ptr(ss.CreateEnumerator()); while(enumerator->Next()) { RandomAccess::SetValue(ds, index++, enumerator->Current()); } } }; template struct CopyFromAlgorithm { static void Perform(Ds& ds, const Ss& ss, bool append) { if (!append) { ds.Clear(); } auto enumerator = Ptr(ss.CreateEnumerator()); while (enumerator->Next()) { RandomAccess::AppendValue(ds, enumerator->Current()); } } }; template struct Slice { const T* items; vint count; }; } namespace randomaccess_internal { template struct RandomAccessable> { static const bool CanRead = true; static const bool CanResize = true; }; template struct RandomAccess> { static vint GetCount(const copyfrom_internal::Slice& t) { return t.count; } static const T& GetValue(const copyfrom_internal::Slice& t, vint index) { return t.items[index]; } }; } /// Copy containers. /// Type of the target container. /// Type of the source container. /// The target container. /// The source container. /// Set to true to perform appending instead of replacing. template void CopyFrom(Ds& ds, const Ss& ss, bool append = false) { copyfrom_internal::CopyFromAlgorithm::CanResize, randomaccess_internal::RandomAccessable::CanRead>::Perform(ds, ss, append); } /// Copy containers. /// Type of the target container. /// Type of values in the source container. /// The target container. /// Pointer to source values. /// The number of values to copy. /// Set to true to perform appending instead of replacing. template void CopyFrom(Ds& ds, const S* buffer, vint count, bool append = false) { copyfrom_internal::Slice slice = { buffer, count }; CopyFrom(ds, slice, append); } /// Copy containers. /// Type of the target container. /// Type of values in the source container. /// The target container. /// Pointer to the first source value. /// Pointer to the value after the last source value. /// Set to true to perform appending instead of replacing. template void CopyFrom(Ds& ds, const S* begin, const S* end, bool append = false) { copyfrom_internal::Slice slice = { begin, end - begin }; CopyFrom(ds, slice, append); } } } #endif /*********************************************************************** .\COLLECTIONS\OPERATIONENUMERABLE.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_OPERATIONENUMERABLE #define VCZH_COLLECTIONS_OPERATIONENUMERABLE namespace vl { namespace collections { /*********************************************************************** EmptyEnumerable ***********************************************************************/ template class EmptyEnumerator : public Object, public virtual IEnumerator { IEnumerator* Clone()const override { return new EmptyEnumerator(); } const T& Current()const override { CHECK_FAIL(L"EmptyEnumerable::Enumerator::Current()#This collection is empty."); } vint Index()const override { return -1; } bool Next()override { return false; } void Reset()override { } bool Evaluated()const override { return true; } }; /*********************************************************************** RangeEnumerator ***********************************************************************/ template class RangeEnumerator : public Object, public virtual IEnumerator { protected: T start; T count; T current; public: RangeEnumerator(T _start, T _count, T _current) :start(_start) ,count(_count) ,current(_current) { } RangeEnumerator(T _start, T _count) :start(_start) ,count(_count) ,current(_start-1) { } IEnumerator* Clone()const override { return new RangeEnumerator(start, count, current); } const T& Current()const override { return current; } T Index()const override { return current-start; } bool Next()override { if(start-1<=current && current class ContainerEnumerator : public Object, public virtual IEnumerator { private: Ptr container; vint index; public: ContainerEnumerator(Ptr _container, vint _index=-1) { container=_container; index=_index; } IEnumerator* Clone()const override { return new ContainerEnumerator(container, index); } const T& Current()const override { return container->Get(index); } vint Index()const override { return index; } bool Next()override { index++; return index>=0 && indexCount(); } void Reset()override { index=-1; } bool Evaluated()const override { return true; } }; /*********************************************************************** CompareEnumerable ***********************************************************************/ /// Compare two enumerables. /// Type of elements in the first enumerable. /// Type of elements in the second enumerable. /// /// Returns a positive value when the first enumerable is greater than the second enumerable. /// Returns a negative value when the first enumerable is lesser than the second enumerable. /// Returns zero when the two enumerables equal. /// /// The first enumerable to compare. /// The second enumerable to compare. /// /// The comparison result is similar to comparing two strings. /// When an enumerable contains no value but another one does, the empty one is lesser. /// When an enumerable is the prefix of another one, the prefix is lesser. /// When two enumerable contain the same values in the same order, they equals. /// In other cases, the results represents the comparison result of the first pair of inequal values in enumerables. /// template vint CompareEnumerable(const IEnumerable& a, const IEnumerable& b) { auto ator = Ptr(a.CreateEnumerator()); auto btor = Ptr(b.CreateEnumerator()); while (true) { bool a = ator->Next(); bool b = btor->Next(); if (a && !b) return 1; if (!a&&b) return -1; if (!a && !b) break; const T& ac = ator->Current(); const U& bc = btor->Current(); if (ac < bc) { return -1; } else if (ac > bc) { return 1; } } return 0; } template struct SortedListOperations { static bool Contains(const SortedList& items, const T& item) { return items.Contains(item); } }; template struct SortedListOperations> { static bool Contains(const SortedList>& items, const Ptr& item) { return items.Contains(item.Obj()); } }; } } #endif /*********************************************************************** .\COLLECTIONS\OPERATIONCONCAT.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_OPERATIONCONCAT #define VCZH_COLLECTIONS_OPERATIONCONCAT namespace vl { namespace collections { /*********************************************************************** Concat ***********************************************************************/ template class ConcatEnumerator : public virtual IEnumerator { protected: IEnumerator* enumerator1; IEnumerator* enumerator2; vint index; bool turned; public: ConcatEnumerator(IEnumerator* _enumerator1, IEnumerator* _enumerator2, vint _index=-1, bool _turned=false) :enumerator1(_enumerator1) ,enumerator2(_enumerator2) ,index(_index) ,turned(_turned) { } ~ConcatEnumerator() { delete enumerator1; delete enumerator2; } IEnumerator* Clone()const override { return new ConcatEnumerator(enumerator1->Clone(), enumerator2->Clone(), index, turned); } const T& Current()const override { if(turned) { return enumerator2->Current(); } else { return enumerator1->Current(); } } vint Index()const override { return index; } bool Next()override { index++; if(turned) { return enumerator2->Next(); } else { if(enumerator1->Next()) { return true; } else { turned=true; return enumerator2->Next(); } } } void Reset()override { enumerator1->Reset(); enumerator2->Reset(); index=-1; turned=false; } bool Evaluated()const override { return enumerator1->Evaluated() && enumerator2->Evaluated(); } }; } } #endif /*********************************************************************** .\COLLECTIONS\OPERATIONFOREACH.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_FOREACH #define VCZH_COLLECTIONS_FOREACH namespace vl { namespace collections { struct RangeBasedForLoopEnding { }; /*********************************************************************** Range-Based For-Loop Iterator ***********************************************************************/ template struct RangeBasedForLoopIterator { private: IEnumerator* iterator; public: RangeBasedForLoopIterator(const IEnumerable& enumerable) : iterator(enumerable.CreateEnumerator()) { operator++(); } ~RangeBasedForLoopIterator() { if (iterator) delete iterator; } void operator++() { if (!iterator->Next()) { delete iterator; iterator = nullptr; } } const T& operator*() const { return iterator->Current(); } bool operator==(RangeBasedForLoopEnding) const { return iterator == nullptr; } }; template RangeBasedForLoopIterator begin(const IEnumerable& enumerable) { return { enumerable }; } template RangeBasedForLoopEnding end(const IEnumerable& enumerable) { return {}; } /*********************************************************************** Range-Based For-Loop Iterator with Index ***********************************************************************/ template struct RangeBasedForLoopIteratorWithIndex { struct Tuple { const T& value; vint index; Tuple(const T& _value, vint _index) : value(_value) , index(_index) { } }; private: IEnumerator* iterator; vint index; public: RangeBasedForLoopIteratorWithIndex(const IEnumerable& enumerable) : iterator(enumerable.CreateEnumerator()) , index(-1) { operator++(); } ~RangeBasedForLoopIteratorWithIndex() { if (iterator) delete iterator; } void operator++() { if (!iterator->Next()) { delete iterator; iterator = nullptr; } index++; } Tuple operator*() const { return { iterator->Current(),index }; } bool operator==(RangeBasedForLoopEnding) const { return iterator == nullptr; } }; template struct EnumerableWithIndex { const IEnumerable& enumerable; EnumerableWithIndex(const IEnumerable& _enumerable) : enumerable(_enumerable) { } }; template EnumerableWithIndex indexed(const IEnumerable& enumerable) { return { enumerable }; } template RangeBasedForLoopIteratorWithIndex begin(const EnumerableWithIndex& enumerable) { return { enumerable.enumerable }; } template RangeBasedForLoopEnding end(const EnumerableWithIndex& enumerable) { return {}; } } } #endif /*********************************************************************** .\COLLECTIONS\OPERATIONPAIR.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_OPERATIONPAIR #define VCZH_COLLECTIONS_OPERATIONPAIR namespace vl { namespace collections { /*********************************************************************** Pairwise ***********************************************************************/ template class PairwiseEnumerator : public virtual IEnumerator> { protected: IEnumerator* enumerator1; IEnumerator* enumerator2; Nullable> current; public: PairwiseEnumerator(IEnumerator* _enumerator1, IEnumerator* _enumerator2, Nullable> _current = {}) :enumerator1(_enumerator1) ,enumerator2(_enumerator2) ,current(_current) { } ~PairwiseEnumerator() { delete enumerator1; delete enumerator2; } IEnumerator>* Clone()const override { return new PairwiseEnumerator(enumerator1->Clone(), enumerator2->Clone(), current); } const Pair& Current()const override { return current.Value(); } vint Index()const override { return enumerator1->Index(); } bool Next()override { if (enumerator1->Next() && enumerator2->Next()) { current = Pair(enumerator1->Current(), enumerator2->Current()); return true; } else { return false; } } void Reset()override { enumerator1->Reset(); enumerator2->Reset(); } bool Evaluated()const override { return enumerator1->Evaluated() && enumerator2->Evaluated(); } }; } } #endif /*********************************************************************** .\COLLECTIONS\OPERATIONSEQUENCE.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_OPERATIONSEQUENCE #define VCZH_COLLECTIONS_OPERATIONSEQUENCE namespace vl { namespace collections { /*********************************************************************** Take ***********************************************************************/ template class TakeEnumerator : public virtual IEnumerator { protected: IEnumerator* enumerator; vint count; public: TakeEnumerator(IEnumerator* _enumerator, vint _count) :enumerator(_enumerator) ,count(_count) { } ~TakeEnumerator() { delete enumerator; } IEnumerator* Clone()const override { return new TakeEnumerator(enumerator->Clone(), count); } const T& Current()const override { return enumerator->Current(); } vint Index()const override { return enumerator->Index(); } bool Next()override { if(enumerator->Index()>=count-1) return false; return enumerator->Next(); } void Reset()override { enumerator->Reset(); } bool Evaluated()const override { return enumerator->Evaluated(); } }; /*********************************************************************** Skip ***********************************************************************/ template class SkipEnumerator : public virtual IEnumerator { protected: IEnumerator* enumerator; vint count; bool skipped; public: SkipEnumerator(IEnumerator* _enumerator, vint _count, bool _skipped=false) :enumerator(_enumerator) ,count(_count) ,skipped(_skipped) { } ~SkipEnumerator() { delete enumerator; } IEnumerator* Clone()const override { return new SkipEnumerator(enumerator->Clone(), count, skipped); } const T& Current()const override { return enumerator->Current(); } vint Index()const override { return enumerator->Index()-count; } bool Next()override { if(!skipped) { skipped=true; for(vint i=0;iNext()) { return false; } } } return enumerator->Next(); } void Reset()override { enumerator->Reset(); skipped=false; } bool Evaluated()const override { return enumerator->Evaluated(); } }; /*********************************************************************** Repeat ***********************************************************************/ template class RepeatEnumerator : public virtual IEnumerator { protected: IEnumerator* enumerator; vint count; vint index; vint repeatedCount; public: RepeatEnumerator(IEnumerator* _enumerator, vint _count, vint _index=-1, vint _repeatedCount=0) :enumerator(_enumerator) ,count(_count) ,index(_index) ,repeatedCount(_repeatedCount) { } ~RepeatEnumerator() { delete enumerator; } IEnumerator* Clone()const override { return new RepeatEnumerator(enumerator->Clone(), count, index, repeatedCount); } const T& Current()const override { return enumerator->Current(); } vint Index()const override { return index; } bool Next()override { while(repeatedCountNext()) { index++; return true; } repeatedCount++; enumerator->Reset(); } return false; } void Reset()override { enumerator->Reset(); index=-1; repeatedCount=0; } bool Evaluated()const override { return enumerator->Evaluated(); } }; /*********************************************************************** Distinct ***********************************************************************/ template class DistinctEnumerator : public virtual IEnumerator { protected: IEnumerator* enumerator; SortedList distinct; Nullable lastValue; public: DistinctEnumerator(IEnumerator* _enumerator) :enumerator(_enumerator) { } DistinctEnumerator(const DistinctEnumerator& _enumerator) :lastValue(_enumerator.lastValue) { enumerator = _enumerator.enumerator->Clone(); CopyFrom(distinct, _enumerator.distinct); } ~DistinctEnumerator() { delete enumerator; } IEnumerator* Clone()const override { return new DistinctEnumerator(*this); } const T& Current()const override { return lastValue.Value(); } vint Index()const override { return distinct.Count()-1; } bool Next()override { while (enumerator->Next()) { const T& current = enumerator->Current(); if (!SortedListOperations::Contains(distinct, current)) { lastValue = current; distinct.Add(current); return true; } } return false; } void Reset()override { enumerator->Reset(); distinct.Clear(); } }; /*********************************************************************** Reverse ***********************************************************************/ template class ReverseEnumerator : public virtual IEnumerator { protected: List cache; vint index; public: ReverseEnumerator(const IEnumerable& enumerable) :index(-1) { CopyFrom(cache, enumerable); } ReverseEnumerator(const ReverseEnumerator& _enumerator) :index(_enumerator.index) { CopyFrom(cache, _enumerator.cache); } ~ReverseEnumerator() { } IEnumerator* Clone()const override { return new ReverseEnumerator(*this); } const T& Current()const override { return cache.Get(cache.Count()-1-index); } vint Index()const override { return index; } bool Next()override { index++; return index class FromIteratorEnumerable : public EnumerableBase { private: class Enumerator : public Object, public IEnumerator { private: I begin; I end; I current; public: Enumerator(I _begin, I _end, I _current) :begin(_begin) ,end(_end) ,current(_current) { } IEnumerator* Clone()const override { return new Enumerator(begin, end, current); } const T& Current()const override { return *current; } vint Index()const override { return current-begin; } bool Next()override { current++; return begin<=current && current* CreateEnumerator()const { return new Enumerator(begin, end, begin - 1); } FromIteratorEnumerable(I _begin, I _end) :begin(_begin) ,end(_end) { } FromIteratorEnumerable(const FromIteratorEnumerable& enumerable) :begin(enumerable.begin) ,end(enumerable.end) { } }; template class FromIterator { public: template static FromIteratorEnumerable Wrap(I begin, I end) { return FromIteratorEnumerable(begin, end); } }; template FromIteratorEnumerable FromPointer(const T* begin, const T* end) { return FromIteratorEnumerable(begin, end); } template FromIteratorEnumerable FromArray(T (&items)[size]) { return FromIteratorEnumerable(&items[0], &items[size]); } } } #endif /*********************************************************************** .\COLLECTIONS\OPERATIONSET.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_OPERATIONSET #define VCZH_COLLECTIONS_OPERATIONSET namespace vl { namespace collections { /*********************************************************************** Intersect/Except ***********************************************************************/ template class IntersectExceptEnumerator : public virtual IEnumerator { protected: IEnumerator* enumerator; SortedList reference; vint index; public: IntersectExceptEnumerator(IEnumerator* _enumerator, const IEnumerable& _reference) :enumerator(_enumerator) ,index(-1) { CopyFrom(reference, _reference); } IntersectExceptEnumerator(const IntersectExceptEnumerator& _enumerator) { enumerator=_enumerator.enumerator->Clone(); CopyFrom(reference, _enumerator.reference); index=_enumerator.index; } ~IntersectExceptEnumerator() { delete enumerator; } IEnumerator* Clone()const override { return new IntersectExceptEnumerator(*this); } const T& Current()const override { return enumerator->Current(); } vint Index()const override { return index; } bool Next()override { while(enumerator->Next()) { if(SortedListOperations::Contains(reference, enumerator->Current())==Intersect) { index++; return true; } } return false; } void Reset()override { enumerator->Reset(); index=-1; } }; } } #endif /*********************************************************************** .\COLLECTIONS\PARTIALORDERING.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_PARTIALORDERING #define VCZH_COLLECTIONS_PARTIALORDERING namespace vl { namespace collections { /*********************************************************************** Partial Ordering ***********************************************************************/ namespace po { /// /// Node contains extra information for sorted objects. /// struct Node { bool visited = false; /// The index used in [F:vl.collections.PartialOrderingProcessor.components], specifying the component that contain this node. vint component = -1; /// All nodes that this node depends on. const List* ins = nullptr; /// All nodes that this node is depended by. const List* outs = nullptr; /// /// If [M:vl.collections.PartialOrderingProcessor.InitWithSubClass`2] is used, /// a node becomes a sub class representing objects. /// An object will not be shared by different sub classes. /// In this case, this field is a pointer to an array of indexes of objects. /// The index is used in "items" argument in [M:vl.collections.PartialOrderingProcessor.InitWithSubClass`2] /// const vint* firstSubClassItem = nullptr; /// /// When is available, /// this field is the number of indexes in the array. /// vint subClassItemCount = 0; }; /// /// Component is a unit in sorting result. /// If a component contains more than one node, /// it means that nodes in this component depend on each other by the given relationship. /// It is not possible to tell which node should be place before others for all nodes in this component. /// If all nodes are completely partial ordered, /// there should be only one node in all components. /// struct Component { /// /// Pointer to the array of all indexes of nodes in this component. /// Index is used in [F:vl.collections.PartialOrderingProcessor.nodes]. /// const vint* firstNode = nullptr; /// The number of nodes in this component. vint nodeCount = 0; }; } } namespace collections { /// /// PartialOrderingProcessor is used to sort objects by given relationships among them. /// The relationship is defined by dependance. /// If A depends on B, then B will be place before A after sorting. /// If a group of objects depends on each other by the given relationship, /// they will be grouped together in the sorting result. /// class PartialOrderingProcessor : public Object { template using GroupOf = Group; protected: List emptyList; // make a pointer to an empty list available Group ins; // if a depends on b, ins.Contains(a, b) Group outs; // if a depends on b, outs.Contains(b, a) Array firstNodesBuffer; // one buffer for all Component::firstNode Array subClassItemsBuffer; // one buffer for all Node::firstSubClassItem void InitNodes(vint itemCount); void VisitUnvisitedNode(po::Node& node, Array& reversedOrder, vint& used); void AssignUnassignedNode(po::Node& node, vint componentIndex, vint& used); public: /// After is called, this field stores all nodes referenced by sorted components. /// /// The same order is kept as the "items" argument in , and . /// If sub classing is enabled by calling , /// a node represents a sub class of objects. /// In this case, the order in this field does not matter, /// [F:vl.collections.po.Node.firstSubClassItem] stores indexes of objects in this sub class. /// Array nodes; /// After is called, this field stores all sorted components in order. List components; /// /// Sort objects by given relationships. It will crash if this method is called for more than once. /// /// /// One and only one of , or must be called to set data for sorting. /// And then call to sort objects and store the result in . /// void Sort(); /// Set data for sorting, by providing a list for objects, and a group for their relationship. /// Type of the list for objects. , or are recommended. /// List of objects for sorting. /// Relationship of objects for sorting in . Both keys and values are elements in "items". To say that a depends on b, do depGroup.Add(a, b). /// items; /// items.Add(L"elephant"); /// items.Add(L"fish"); /// items.Add(L"ball"); /// items.Add(L"cat"); /// items.Add(L"dog"); /// items.Add(L"apple"); /// /// Group depGroup; /// depGroup.Add(L"ball", L"apple"); /// depGroup.Add(L"cat", L"ball"); /// depGroup.Add(L"ball", L"dog"); /// depGroup.Add(L"dog", L"cat"); /// depGroup.Add(L"elephant", L"cat"); /// depGroup.Add(L"fish", L"dog"); /// /// PartialOrderingProcessor pop; /// pop.InitWithGroup(items, depGroup); /// pop.Sort(); /// /// for (vint i = 0; i < pop.components.Count(); i++) /// { /// auto& c = pop.components[i]; /// Console::WriteLine( /// L"Component " + itow(i) + L": " + /// Range(0, c.nodeCount) /// .Select([&](vint ni){ return items[c.firstNode[ni]]; }) /// .Aggregate([](const WString& a, const WString& b){ return a + L" " + b; }) /// ); /// } /// /// for (vint i = 0; i < pop.nodes.Count(); i++) /// { /// auto& n = pop.nodes[i]; /// if(n.outs->Count() > 0) /// { /// Console::WriteLine( /// L"Node " + items[i] + L" <- " + /// From(*n.outs) /// .Select([&](vint ni){ return items[ni]; }) /// .Aggregate([](const WString& a, const WString& b){ return a + L" " + b; }) /// ); /// } /// } /// } /// ]]> template void InitWithGroup(const TList& items, const GroupOf& depGroup) { CHECK_ERROR(nodes.Count() == 0, L"PartialOrdering::InitWithGroup(items, depGroup)#Initializing twice is not allowed."); for (vint i = 0; i < depGroup.Count(); i++) { vint fromNode = items.IndexOf(KeyType::GetKeyValue(depGroup.Keys()[i])); CHECK_ERROR(fromNode != -1, L"PartialOrdering::InitWithGroup(items, depGroup)#The key in outsGroup does not exist in items."); auto& edges = depGroup.GetByIndex(i); for (vint j = 0; j < edges.Count(); j++) { vint toNode = items.IndexOf(KeyType::GetKeyValue(edges[j])); CHECK_ERROR(toNode != -1, L"PartialOrdering::InitWithGroup(items, depGroup)#The value in outsGroup does not exist in items."); ins.Add(fromNode, toNode); outs.Add(toNode, fromNode); } } InitNodes(items.Count()); } /// Set data for sorting, by providing a list for objects, and a function for their relationship. /// Type of the list for objects. , or are recommended. /// Type of the function that defines relationships of objects. /// List of objects for sorting. /// Relationship of objects for sorting, both arguments are elements in "items". To say that a depends on b, depFunc(a, b) must returns true. /// items; /// items.Add(L"elephant"); /// items.Add(L"fish"); /// items.Add(L"ball"); /// items.Add(L"cat"); /// items.Add(L"dog"); /// items.Add(L"apple"); /// /// auto depFunc = [](const WString& a, const WString& b) /// { /// return /// (a == L"ball" && b == L"apple") || /// (a == L"cat" && b == L"ball") || /// (a == L"ball" && b == L"dog") || /// (a == L"dog" && b == L"cat") || /// (a == L"elephant" && b == L"cat") || /// (a == L"fish" && b == L"dog") /// ; /// }; /// /// PartialOrderingProcessor pop; /// pop.InitWithFunc(items, depFunc); /// pop.Sort(); /// /// for (vint i = 0; i < pop.components.Count(); i++) /// { /// auto& c = pop.components[i]; /// Console::WriteLine( /// L"Component " + itow(i) + L": " + /// Range(0, c.nodeCount) /// .Select([&](vint ni){ return items[c.firstNode[ni]]; }) /// .Aggregate([](const WString& a, const WString& b){ return a + L" " + b; }) /// ); /// } /// /// for (vint i = 0; i < pop.nodes.Count(); i++) /// { /// auto& n = pop.nodes[i]; /// if(n.outs->Count() > 0) /// { /// Console::WriteLine( /// L"Node " + items[i] + L" <- " + /// From(*n.outs) /// .Select([&](vint ni){ return items[ni]; }) /// .Aggregate([](const WString& a, const WString& b){ return a + L" " + b; }) /// ); /// } /// } /// } /// ]]> template void InitWithFunc(const TList& items, TFunc&& depFunc) { GroupOf depGroup; for (vint i = 0; i < items.Count(); i++) { for (vint j = 0; j < items.Count(); j++) { if (depFunc(items[i], items[j])) { depGroup.Add(items[i], items[j]); } } } InitWithGroup(items, depGroup); } /// Set data for sorting, by providing a list for objects, and a group for their relationship, and a dictionary for sub classing objects. /// Type of the list for objects. , or are recommended. /// Type of a sub class. /// List of objects for sorting. /// Relationship of objects for sorting in . Both keys and values are elements in "items". To say that a depends on b, do depGroup.Add(a, b). /// Sub classing objects. Keys are elements in "items". If multiple keys have the same value in this dictionary, then these objects are in the same sub class. /// /// Relationships are defined on objects. /// By sub classing objects, /// relationships of sub classes are calculated from "depGroup". /// If object A in sub class X depends on object B in sub class Y, then sub class X depends on sub class Y. /// It is allowed that relatipnships on sub classes are not completely partial ordered, /// in this case, some components may contain multiple sub classes. /// /// items; /// for (vint i = 1; i <= 2; i++) /// { /// items.Add(L"apple_" + itow(i)); /// items.Add(L"ball_" + itow(i)); /// items.Add(L"cat_" + itow(i)); /// items.Add(L"dog_" + itow(i)); /// items.Add(L"elephant_" + itow(i)); /// items.Add(L"fish_" + itow(i)); /// } /// /// Group depGroup; /// depGroup.Add(L"ball_2", L"apple_1"); /// depGroup.Add(L"cat_2", L"ball_1"); /// depGroup.Add(L"ball_2", L"dog_1"); /// depGroup.Add(L"dog_2", L"cat_1"); /// depGroup.Add(L"elephant_2", L"cat_1"); /// depGroup.Add(L"fish_2", L"dog_1"); /// /// Dictionary subClass; /// for (vint i = 1; i <= 2; i++) /// { /// subClass.Add(L"apple_" + itow(i), 1); /// subClass.Add(L"ball_" + itow(i), 2); /// subClass.Add(L"cat_" + itow(i), 3); /// subClass.Add(L"dog_" + itow(i), 4); /// subClass.Add(L"elephant_" + itow(i), 5); /// subClass.Add(L"fish_" + itow(i), 6); /// } /// /// PartialOrderingProcessor pop; /// pop.InitWithSubClass(items, depGroup, subClass); /// pop.Sort(); /// /// for (vint i = 0; i < pop.components.Count(); i++) /// { /// auto& c = pop.components[i]; /// Console::WriteLine( /// L"Component " + itow(i) + L": sub classes" + /// Range(0, c.nodeCount) /// .Select([&](vint ni) { return c.firstNode[ni]; }) /// .Aggregate(L"", [](const WString& a, vint b) { return a + L" " + itow(b); }) /// ); /// } /// /// for (vint i = 0; i < pop.nodes.Count(); i++) /// { /// auto& n = pop.nodes[i]; /// Console::WriteLine(L"Sub class " + itow(i)); /// /// Console::WriteLine( /// Range(0, n.subClassItemCount) /// .Select([&](vint si) { return n.firstSubClassItem[si]; }) /// .Aggregate(L" :", [&](const WString& a, vint b) { return a + L" " + items[b]; }) /// ); /// /// if (n.outs->Count() > 0) /// { /// Console::WriteLine( /// From(*n.outs) /// .Aggregate(L" <- sub classes", [](const WString& a, vint b) { return a + L" " + itow(b); }) /// ); /// } /// } /// } /// ]]> template void InitWithSubClass(const TList& items, const GroupOf& depGroup, const Dictionary& subClasses) { CHECK_ERROR(nodes.Count() == 0, L"PartialOrdering::InitWithSubClass(items, degGroup, subClasses)#Initializing twice is not allowed."); using ElementType = typename TList::ElementType; using ElementKeyType = KeyType; Group scItems; SortedList singleItems; for (vint i = 0; i < subClasses.Count(); i++) { const auto& key = subClasses.Keys()[i]; const auto& value = subClasses.Values()[i]; scItems.Add(value, key); } for (vint i = 0; i < items.Count(); i++) { const auto& item = items[i]; if (!subClasses.Keys().Contains(ElementKeyType::GetKeyValue(item))) { singleItems.Add(item); } } auto getSubClass = [&](const ElementType& item) { vint index = subClasses.Keys().IndexOf(ElementKeyType::GetKeyValue(item)); if (index != -1) { index = scItems.Keys().IndexOf(KeyType::GetKeyValue(subClasses.Values()[index])); CHECK_ERROR(index != -1, L"PartialOrdering::InitWithSubClass(items, degGroup, subClasses)#Internal Error."); return index; } else { index = singleItems.IndexOf(ElementKeyType::GetKeyValue(item)); CHECK_ERROR(index != -1, L"PartialOrdering::InitWithSubClass(items, degGroup, subClasses)#Internal Error."); return scItems.Count() + index; } }; for (vint i = 0; i < depGroup.Count(); i++) { const auto& key = depGroup.Keys()[i]; vint keyIndex = getSubClass(key); const auto& values = depGroup.GetByIndex(i); for (vint j = 0; j < values.Count(); j++) { const auto& value = values[j]; vint valueIndex = getSubClass(value); if (!ins.Contains(keyIndex, valueIndex)) { ins.Add(keyIndex, valueIndex); } } } for (vint i = 0; i < ins.Count(); i++) { vint key = ins.Keys()[i]; const auto& values = ins.GetByIndex(i); for (vint j = 0; j < values.Count(); j++) { outs.Add(values[j], key); } } InitNodes(scItems.Count() + singleItems.Count()); subClassItemsBuffer.Resize(items.Count()); vint used = 0; vint scItemCount = scItems.Keys().Count(); for (vint i = 0; i < nodes.Count(); i++) { auto& node = nodes[i]; node.firstSubClassItem = &subClassItemsBuffer[used]; if (i < scItemCount) { const auto& values = scItems.GetByIndex(i); for (vint j = 0; j < values.Count(); j++) { subClassItemsBuffer[used++] = items.IndexOf(ElementKeyType::GetKeyValue(values[j])); } node.subClassItemCount = values.Count(); } else { subClassItemsBuffer[used++] = items.IndexOf(ElementKeyType::GetKeyValue(singleItems[i - scItemCount])); node.subClassItemCount = 1; } } } }; } } #endif /*********************************************************************** .\PRIMITIVES\FUNCTION.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_FUNCTION #define VCZH_FUNCTION #include namespace vl { template class Func; /*********************************************************************** vl::Func ***********************************************************************/ namespace internal_invokers { template class Invoker : public Object { public: virtual R Invoke(TArgs&& ...args) = 0; }; //------------------------------------------------------ template class StaticInvoker : public Invoker { protected: R(*function)(TArgs ...args); public: StaticInvoker(R(*_function)(TArgs...)) :function(_function) { } R Invoke(TArgs&& ...args)override { return function(std::forward(args)...); } }; //------------------------------------------------------ template class MemberInvoker : public Invoker { protected: C* sender; R(C::*function)(TArgs ...args); public: MemberInvoker(C* _sender, R(C::*_function)(TArgs ...args)) :sender(_sender) ,function(_function) { } R Invoke(TArgs&& ...args)override { return (sender->*function)(std::forward(args)...); } }; //------------------------------------------------------ template class ObjectInvoker : public Invoker { protected: C function; public: ObjectInvoker(const C& _function) :function(_function) { } ObjectInvoker(C&& _function) :function(std::move(_function)) { } R Invoke(TArgs&& ...args)override { return function(std::forward(args)...); } }; //------------------------------------------------------ template class ObjectInvoker : public Invoker { protected: C function; public: ObjectInvoker(const C& _function) :function(_function) { } ObjectInvoker(C&& _function) :function(std::move(_function)) { } void Invoke(TArgs&& ...args)override { function(std::forward(args)...); } }; } /// A type for functors. /// The return type. /// Types of parameters. template class Func : public Object { 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; /// Create a null functor. Func() = default; /// Copy a functor. /// The functor to copy. Func(const Func& function) = default; /// Move a functor. /// The functor to move. Func(Func&& function) = default; /// Create a functor from a function pointer. /// The function pointer. Func(R(*function)(TArgs...)) { invoker = Ptr(new internal_invokers::StaticInvoker(function)); } /// Create a functor from a method. /// Type of the class that this method belongs to. /// The object that this method belongs to. /// The method pointer. template Func(C* sender, R(C::*function)(TArgs...)) { invoker = Ptr(new internal_invokers::MemberInvoker(sender, function)); } /// Create a functor from another compatible functor. /// Type of the functor to copy. /// The functor to copy. It could be a lambda expression, or any types that has operator() members. template Func(C&& function) requires ( std::is_invocable_v ) && ( std::is_same_v || std::is_convertible_v()(std::declval()...)), R> ) { if (!IsEmptyFunc(function)) { invoker = Ptr(new internal_invokers::ObjectInvoker, R, TArgs...>(std::forward(function))); } } /// Invoke the function. /// Returns the function result. It crashes when the functor is null. /// Arguments to invoke the function. R operator()(TArgs ...args)const { return invoker->Invoke(std::forward(args)...); } Func& operator=(const Func& function) { invoker = function.invoker; return *this; } Func& operator=(const Func&& function) { invoker = std::move(function.invoker); return *this; } bool operator==(const Func& function)const { return invoker == function.invoker; } bool operator!=(const Func& function)const { return invoker != function.invoker; } /// Test is the functor is non-null. /// Returns true if the functor is non-null. operator bool()const { return invoker; } }; /*********************************************************************** vl::function_lambda::LambdaRetriveType ***********************************************************************/ namespace function_lambda { template struct LambdaRetriveType { }; template struct LambdaRetriveType { typedef R(FunctionType)(TArgs...); typedef R ResultType; typedef TypeTuple ParameterTypes; }; template struct LambdaRetriveType { typedef R(FunctionType)(TArgs...); typedef R ResultType; typedef TypeTuple ParameterTypes; }; #define LAMBDA vl::function_lambda::Lambda } template Func(C&&) -> Func::FunctionType>; template Func(R(*)(TArgs...)) -> Func; template Func(C*, R(C::*)(TArgs...)) -> Func; } #endif /*********************************************************************** .\COLLECTIONS\OPERATIONSELECT.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_OPERATIONSELECT #define VCZH_COLLECTIONS_OPERATIONSELECT namespace vl { namespace collections { /*********************************************************************** Select ***********************************************************************/ template class SelectEnumerator : public virtual IEnumerator { protected: IEnumerator* enumerator; Func selector; Nullable current; public: SelectEnumerator(IEnumerator* _enumerator, const Func& _selector, Nullable _current = {}) :enumerator(_enumerator) ,selector(_selector) ,current(_current) { } ~SelectEnumerator() { delete enumerator; } IEnumerator* Clone()const override { return new SelectEnumerator(enumerator->Clone(), selector, current); } const K& Current()const override { return current.Value(); } vint Index()const override { return enumerator->Index(); } bool Next()override { if (enumerator->Next()) { current = selector(enumerator->Current()); return true; } else { return false; } } void Reset()override { enumerator->Reset(); } }; } } #endif /*********************************************************************** .\COLLECTIONS\OPERATIONWHERE.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_OPERATIONWHERE #define VCZH_COLLECTIONS_OPERATIONWHERE namespace vl { namespace collections { /*********************************************************************** Where ***********************************************************************/ template class WhereEnumerator : public virtual IEnumerator { protected: IEnumerator* enumerator; Func selector; vint index; public: WhereEnumerator(IEnumerator* _enumerator, const Func& _selector, vint _index=-1) :enumerator(_enumerator) ,selector(_selector) ,index(_index) { } ~WhereEnumerator() { delete enumerator; } IEnumerator* Clone()const override { return new WhereEnumerator(enumerator->Clone(), selector, index); } const T& Current()const override { return enumerator->Current(); } vint Index()const override { return index; } bool Next()override { while(enumerator->Next()) { if(selector(enumerator->Current())) { index++; return true; } } return false; } void Reset()override { enumerator->Reset(); index=-1; } }; } } #endif /*********************************************************************** .\PRIMITIVES\EVENT.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_EVENT #define VCZH_EVENT namespace vl { template class Event; class EventHandler : public Object { public: virtual bool IsAttached() = 0; }; /// An event for being subscribed using multiple callbacks. A callback is any functor that returns void. /// Types of callback parameters. template class Event : public Object { protected: class EventHandlerImpl : public EventHandler { public: bool attached; Func function; EventHandlerImpl(const Func& _function) :attached(true) , function(_function) { } bool IsAttached()override { return attached; } }; collections::SortedList> handlers; public: NOT_COPYABLE(Event); Event() = default; /// Add a callback to the event. /// The event handler representing the callback. /// The callback. Ptr Add(const Func& function) { auto handler = Ptr(new EventHandlerImpl(function)); handlers.Add(handler); return handler; } /// Add a callback to the event. /// The event handler representing the callback. /// The callback. Ptr Add(void(*function)(TArgs...)) { return Add(Func(function)); } /// Add a method callback to the event. /// Type of the class that the callback belongs to. /// The event handler representing the callback. /// The object that the callback belongs to. /// The method callback. template Ptr Add(C* sender, void(C::*function)(TArgs...)) { return Add(Func(sender, function)); } /// Remove a callback by an event handler returns from . /// Returns true if this operation succeeded. /// The event handler representing the callback. bool Remove(Ptr handler) { auto impl = handler.Cast(); if (!impl) return false; vint index = handlers.IndexOf(impl.Obj()); if (index == -1) return false; impl->attached = false; handlers.RemoveAt(index); return true; } /// Invoke all callbacks in the event. /// Arguments to invoke all callbacks. template void operator()(TArgs2&& ...args)const { for(vint i = 0; i < handlers.Count(); i++) { handlers[i]->function(std::forward(args)...); } } }; } #endif /*********************************************************************** .\PRIMITIVES\LAZY.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_LAZY #define VCZH_LAZY namespace vl { /// A type representing a lazy evaluation. /// The type of the evaluation result. template class Lazy : public Object { protected: class Internal { public: Func evaluator; T value; bool evaluated; }; Ptr internalValue; public: /// Create an empty evaluation. Lazy() = default; /// Create an evaluation using a function, which produces the evaluation result. /// The function. Lazy(const Func& evaluator) { internalValue = Ptr(new Internal); internalValue->evaluated=false; internalValue->evaluator=evaluator; } /// Create an evaluation with the immediate result. /// The result.0 Lazy(const T& value) { internalValue = Ptr(new Internal); internalValue->evaluated=true; internalValue->value=value; } /// Create an evaluation by copying another one. /// The evaluation to copy. Lazy(const Lazy& lazy) = default; /// Create an evaluation by moving another one. /// The evaluation to move. Lazy(Lazy&& lazy) = default; Lazy& operator=(const Func& evaluator) { internalValue = Ptr(new Internal); internalValue->evaluated=false; internalValue->evaluator=evaluator; return *this; } Lazy& operator=(const T& value) { internalValue = Ptr(new Internal); internalValue->evaluated=true; internalValue->value=value; return *this; } Lazy& operator=(const Lazy& lazy) { internalValue=lazy.internalValue; return *this; } /// Get the evaluation result. If the evaluation has not been performed, it will run the evaluation function and cache the result. /// The evaluation result. const T& Value()const { if(!internalValue->evaluated) { internalValue->evaluated=true; internalValue->value=internalValue->evaluator(); internalValue->evaluator=Func(); } return internalValue->value; } /// Test if it has already been evaluated or not. /// Returns true if it has already been evaluated. bool IsEvaluated()const { return internalValue->evaluated; } /// Test if it is an empty evaluation or not. /// Returns true if it is not empty. operator bool()const { return internalValue; } }; } #endif /*********************************************************************** .\PRIMITIVES\TUPLE.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License This file is generated by: Vczh Functional Macro ***********************************************************************/ #ifndef VCZH_TUPLE #define VCZH_TUPLE namespace vl { class TupleNullItem { }; template class Tuple { }; /*********************************************************************** vl::Tuple ***********************************************************************/ template class Tuple : public Object { public: T0 f0; Tuple() { } Tuple(T0 p0) :f0(p0) { } static int Compare(const Tuple& a, const Tuple& b) { if (a.f0 < b.f0) return -1; else if (a.f0 > b.f0) return 1; return 0; } bool operator==(const Tuple& value)const{ return Compare(*this, value) == 0; } bool operator!=(const Tuple& value)const{ return Compare(*this, value) != 0; } bool operator< (const Tuple& value)const{ return Compare(*this, value) < 0; } bool operator<=(const Tuple& value)const{ return Compare(*this, value) <= 0; } bool operator> (const Tuple& value)const{ return Compare(*this, value) > 0; } bool operator>=(const Tuple& value)const{ return Compare(*this, value) >= 0; } }; /*********************************************************************** vl::Tuple ***********************************************************************/ template class Tuple : public Object { public: T0 f0;T1 f1; Tuple() { } Tuple(T0 p0,T1 p1) :f0(p0),f1(p1) { } static int Compare(const Tuple& a, const Tuple& b) { if (a.f0 < b.f0) return -1; else if (a.f0 > b.f0) return 1;if (a.f1 < b.f1) return -1; else if (a.f1 > b.f1) return 1; return 0; } bool operator==(const Tuple& value)const{ return Compare(*this, value) == 0; } bool operator!=(const Tuple& value)const{ return Compare(*this, value) != 0; } bool operator< (const Tuple& value)const{ return Compare(*this, value) < 0; } bool operator<=(const Tuple& value)const{ return Compare(*this, value) <= 0; } bool operator> (const Tuple& value)const{ return Compare(*this, value) > 0; } bool operator>=(const Tuple& value)const{ return Compare(*this, value) >= 0; } }; /*********************************************************************** vl::Tuple ***********************************************************************/ template class Tuple : public Object { public: T0 f0;T1 f1;T2 f2; Tuple() { } Tuple(T0 p0,T1 p1,T2 p2) :f0(p0),f1(p1),f2(p2) { } static int Compare(const Tuple& a, const Tuple& b) { if (a.f0 < b.f0) return -1; else if (a.f0 > b.f0) return 1;if (a.f1 < b.f1) return -1; else if (a.f1 > b.f1) return 1;if (a.f2 < b.f2) return -1; else if (a.f2 > b.f2) return 1; return 0; } bool operator==(const Tuple& value)const{ return Compare(*this, value) == 0; } bool operator!=(const Tuple& value)const{ return Compare(*this, value) != 0; } bool operator< (const Tuple& value)const{ return Compare(*this, value) < 0; } bool operator<=(const Tuple& value)const{ return Compare(*this, value) <= 0; } bool operator> (const Tuple& value)const{ return Compare(*this, value) > 0; } bool operator>=(const Tuple& value)const{ return Compare(*this, value) >= 0; } }; /*********************************************************************** vl::Tuple ***********************************************************************/ template class Tuple : public Object { public: T0 f0;T1 f1;T2 f2;T3 f3; Tuple() { } Tuple(T0 p0,T1 p1,T2 p2,T3 p3) :f0(p0),f1(p1),f2(p2),f3(p3) { } static int Compare(const Tuple& a, const Tuple& b) { if (a.f0 < b.f0) return -1; else if (a.f0 > b.f0) return 1;if (a.f1 < b.f1) return -1; else if (a.f1 > b.f1) return 1;if (a.f2 < b.f2) return -1; else if (a.f2 > b.f2) return 1;if (a.f3 < b.f3) return -1; else if (a.f3 > b.f3) return 1; return 0; } bool operator==(const Tuple& value)const{ return Compare(*this, value) == 0; } bool operator!=(const Tuple& value)const{ return Compare(*this, value) != 0; } bool operator< (const Tuple& value)const{ return Compare(*this, value) < 0; } bool operator<=(const Tuple& value)const{ return Compare(*this, value) <= 0; } bool operator> (const Tuple& value)const{ return Compare(*this, value) > 0; } bool operator>=(const Tuple& value)const{ return Compare(*this, value) >= 0; } }; /*********************************************************************** vl::Tuple ***********************************************************************/ template class Tuple : public Object { public: T0 f0;T1 f1;T2 f2;T3 f3;T4 f4; Tuple() { } Tuple(T0 p0,T1 p1,T2 p2,T3 p3,T4 p4) :f0(p0),f1(p1),f2(p2),f3(p3),f4(p4) { } static int Compare(const Tuple& a, const Tuple& b) { if (a.f0 < b.f0) return -1; else if (a.f0 > b.f0) return 1;if (a.f1 < b.f1) return -1; else if (a.f1 > b.f1) return 1;if (a.f2 < b.f2) return -1; else if (a.f2 > b.f2) return 1;if (a.f3 < b.f3) return -1; else if (a.f3 > b.f3) return 1;if (a.f4 < b.f4) return -1; else if (a.f4 > b.f4) return 1; return 0; } bool operator==(const Tuple& value)const{ return Compare(*this, value) == 0; } bool operator!=(const Tuple& value)const{ return Compare(*this, value) != 0; } bool operator< (const Tuple& value)const{ return Compare(*this, value) < 0; } bool operator<=(const Tuple& value)const{ return Compare(*this, value) <= 0; } bool operator> (const Tuple& value)const{ return Compare(*this, value) > 0; } bool operator>=(const Tuple& value)const{ return Compare(*this, value) >= 0; } }; /*********************************************************************** vl::Tuple ***********************************************************************/ template class Tuple : public Object { public: T0 f0;T1 f1;T2 f2;T3 f3;T4 f4;T5 f5; Tuple() { } Tuple(T0 p0,T1 p1,T2 p2,T3 p3,T4 p4,T5 p5) :f0(p0),f1(p1),f2(p2),f3(p3),f4(p4),f5(p5) { } static int Compare(const Tuple& a, const Tuple& b) { if (a.f0 < b.f0) return -1; else if (a.f0 > b.f0) return 1;if (a.f1 < b.f1) return -1; else if (a.f1 > b.f1) return 1;if (a.f2 < b.f2) return -1; else if (a.f2 > b.f2) return 1;if (a.f3 < b.f3) return -1; else if (a.f3 > b.f3) return 1;if (a.f4 < b.f4) return -1; else if (a.f4 > b.f4) return 1;if (a.f5 < b.f5) return -1; else if (a.f5 > b.f5) return 1; return 0; } bool operator==(const Tuple& value)const{ return Compare(*this, value) == 0; } bool operator!=(const Tuple& value)const{ return Compare(*this, value) != 0; } bool operator< (const Tuple& value)const{ return Compare(*this, value) < 0; } bool operator<=(const Tuple& value)const{ return Compare(*this, value) <= 0; } bool operator> (const Tuple& value)const{ return Compare(*this, value) > 0; } bool operator>=(const Tuple& value)const{ return Compare(*this, value) >= 0; } }; /*********************************************************************** vl::Tuple ***********************************************************************/ template class Tuple : public Object { public: T0 f0;T1 f1;T2 f2;T3 f3;T4 f4;T5 f5;T6 f6; Tuple() { } Tuple(T0 p0,T1 p1,T2 p2,T3 p3,T4 p4,T5 p5,T6 p6) :f0(p0),f1(p1),f2(p2),f3(p3),f4(p4),f5(p5),f6(p6) { } static int Compare(const Tuple& a, const Tuple& b) { if (a.f0 < b.f0) return -1; else if (a.f0 > b.f0) return 1;if (a.f1 < b.f1) return -1; else if (a.f1 > b.f1) return 1;if (a.f2 < b.f2) return -1; else if (a.f2 > b.f2) return 1;if (a.f3 < b.f3) return -1; else if (a.f3 > b.f3) return 1;if (a.f4 < b.f4) return -1; else if (a.f4 > b.f4) return 1;if (a.f5 < b.f5) return -1; else if (a.f5 > b.f5) return 1;if (a.f6 < b.f6) return -1; else if (a.f6 > b.f6) return 1; return 0; } bool operator==(const Tuple& value)const{ return Compare(*this, value) == 0; } bool operator!=(const Tuple& value)const{ return Compare(*this, value) != 0; } bool operator< (const Tuple& value)const{ return Compare(*this, value) < 0; } bool operator<=(const Tuple& value)const{ return Compare(*this, value) <= 0; } bool operator> (const Tuple& value)const{ return Compare(*this, value) > 0; } bool operator>=(const Tuple& value)const{ return Compare(*this, value) >= 0; } }; /*********************************************************************** vl::Tuple ***********************************************************************/ template class Tuple : public Object { public: T0 f0;T1 f1;T2 f2;T3 f3;T4 f4;T5 f5;T6 f6;T7 f7; Tuple() { } Tuple(T0 p0,T1 p1,T2 p2,T3 p3,T4 p4,T5 p5,T6 p6,T7 p7) :f0(p0),f1(p1),f2(p2),f3(p3),f4(p4),f5(p5),f6(p6),f7(p7) { } static int Compare(const Tuple& a, const Tuple& b) { if (a.f0 < b.f0) return -1; else if (a.f0 > b.f0) return 1;if (a.f1 < b.f1) return -1; else if (a.f1 > b.f1) return 1;if (a.f2 < b.f2) return -1; else if (a.f2 > b.f2) return 1;if (a.f3 < b.f3) return -1; else if (a.f3 > b.f3) return 1;if (a.f4 < b.f4) return -1; else if (a.f4 > b.f4) return 1;if (a.f5 < b.f5) return -1; else if (a.f5 > b.f5) return 1;if (a.f6 < b.f6) return -1; else if (a.f6 > b.f6) return 1;if (a.f7 < b.f7) return -1; else if (a.f7 > b.f7) return 1; return 0; } bool operator==(const Tuple& value)const{ return Compare(*this, value) == 0; } bool operator!=(const Tuple& value)const{ return Compare(*this, value) != 0; } bool operator< (const Tuple& value)const{ return Compare(*this, value) < 0; } bool operator<=(const Tuple& value)const{ return Compare(*this, value) <= 0; } bool operator> (const Tuple& value)const{ return Compare(*this, value) > 0; } bool operator>=(const Tuple& value)const{ return Compare(*this, value) >= 0; } }; /*********************************************************************** vl::Tuple ***********************************************************************/ template class Tuple : public Object { public: T0 f0;T1 f1;T2 f2;T3 f3;T4 f4;T5 f5;T6 f6;T7 f7;T8 f8; Tuple() { } Tuple(T0 p0,T1 p1,T2 p2,T3 p3,T4 p4,T5 p5,T6 p6,T7 p7,T8 p8) :f0(p0),f1(p1),f2(p2),f3(p3),f4(p4),f5(p5),f6(p6),f7(p7),f8(p8) { } static int Compare(const Tuple& a, const Tuple& b) { if (a.f0 < b.f0) return -1; else if (a.f0 > b.f0) return 1;if (a.f1 < b.f1) return -1; else if (a.f1 > b.f1) return 1;if (a.f2 < b.f2) return -1; else if (a.f2 > b.f2) return 1;if (a.f3 < b.f3) return -1; else if (a.f3 > b.f3) return 1;if (a.f4 < b.f4) return -1; else if (a.f4 > b.f4) return 1;if (a.f5 < b.f5) return -1; else if (a.f5 > b.f5) return 1;if (a.f6 < b.f6) return -1; else if (a.f6 > b.f6) return 1;if (a.f7 < b.f7) return -1; else if (a.f7 > b.f7) return 1;if (a.f8 < b.f8) return -1; else if (a.f8 > b.f8) return 1; return 0; } bool operator==(const Tuple& value)const{ return Compare(*this, value) == 0; } bool operator!=(const Tuple& value)const{ return Compare(*this, value) != 0; } bool operator< (const Tuple& value)const{ return Compare(*this, value) < 0; } bool operator<=(const Tuple& value)const{ return Compare(*this, value) <= 0; } bool operator> (const Tuple& value)const{ return Compare(*this, value) > 0; } bool operator>=(const Tuple& value)const{ return Compare(*this, value) >= 0; } }; /*********************************************************************** vl::Tuple ***********************************************************************/ template class Tuple : public Object { public: T0 f0;T1 f1;T2 f2;T3 f3;T4 f4;T5 f5;T6 f6;T7 f7;T8 f8;T9 f9; Tuple() { } Tuple(T0 p0,T1 p1,T2 p2,T3 p3,T4 p4,T5 p5,T6 p6,T7 p7,T8 p8,T9 p9) :f0(p0),f1(p1),f2(p2),f3(p3),f4(p4),f5(p5),f6(p6),f7(p7),f8(p8),f9(p9) { } static int Compare(const Tuple& a, const Tuple& b) { if (a.f0 < b.f0) return -1; else if (a.f0 > b.f0) return 1;if (a.f1 < b.f1) return -1; else if (a.f1 > b.f1) return 1;if (a.f2 < b.f2) return -1; else if (a.f2 > b.f2) return 1;if (a.f3 < b.f3) return -1; else if (a.f3 > b.f3) return 1;if (a.f4 < b.f4) return -1; else if (a.f4 > b.f4) return 1;if (a.f5 < b.f5) return -1; else if (a.f5 > b.f5) return 1;if (a.f6 < b.f6) return -1; else if (a.f6 > b.f6) return 1;if (a.f7 < b.f7) return -1; else if (a.f7 > b.f7) return 1;if (a.f8 < b.f8) return -1; else if (a.f8 > b.f8) return 1;if (a.f9 < b.f9) return -1; else if (a.f9 > b.f9) return 1; return 0; } bool operator==(const Tuple& value)const{ return Compare(*this, value) == 0; } bool operator!=(const Tuple& value)const{ return Compare(*this, value) != 0; } bool operator< (const Tuple& value)const{ return Compare(*this, value) < 0; } bool operator<=(const Tuple& value)const{ return Compare(*this, value) <= 0; } bool operator> (const Tuple& value)const{ return Compare(*this, value) > 0; } bool operator>=(const Tuple& value)const{ return Compare(*this, value) >= 0; } }; } #endif /*********************************************************************** .\STRINGS\STRING.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_STRINGS_STRING #define VCZH_STRINGS_STRING namespace vl { /// /// Immutable string. and is recommended instead. /// Locale awared operations are in [T:vl.Locale], typically by using the "INVLOC" macro. /// /// Type of code points. template class ObjectString : public Object { template friend class ObjectString; private: static const T zero; mutable T* buffer = (T*)&zero; mutable volatile vint* counter = nullptr; mutable vint start = 0; mutable vint length = 0; mutable vint realLength = 0; static vint CalculateLength(const T* buffer) { vint result=0; while(*buffer++)result++; return result; } static vint64_t Compare(const T* bufA, const ObjectString& strB) { const T* bufB = strB.buffer + strB.start; const T* bufAOld = bufA; vint length = strB.length; while (true) { if (*bufA && length) { length--; vint64_t diff = (vint64_t)(*bufA++) - (vint64_t)(*bufB++); if (diff != 0) { return diff; } } else if (*bufA) { return CalculateLength(bufA); } else if (length) { return -length; } else { return 0; } }; } public: static vint64_t Compare(const ObjectString& strA, const ObjectString& strB) { const T* bufA = strA.buffer + strA.start; const T* bufB = strB.buffer + strB.start; vint length = strA.length < strB.length ? strA.length : strB.length; while (length--) { vint64_t diff = (vint64_t)(*bufA++) - (vint64_t)(*bufB++); if (diff != 0) { return diff; } }; return strA.length - strB.length; } private: void Inc()const { if(counter) { INCRC(counter); } } void Dec()const { if(counter) { if(DECRC(counter)==0) { delete[] buffer; delete counter; } } } ObjectString SubUnsafe(vint _start, vint _length)const { if (_length <= 0) return {}; ObjectString str; str.buffer = buffer; str.counter = counter; str.start = start + _start; str.length = _length; str.realLength = realLength; Inc(); return std::move(str); } ObjectString ReplaceUnsafe(const ObjectString& source, vint index, vint count)const { if (source.length == 0 && count == 0) return *this; if (index == 0 && count == length) return source; ObjectString str; str.counter = new vint(1); str.start = 0; str.length = length - count + source.length; str.realLength = str.length; str.buffer = new T[str.length + 1]; memcpy(str.buffer, buffer + start, sizeof(T) * index); memcpy(str.buffer + index, source.buffer + source.start, sizeof(T) * source.length); memcpy(str.buffer + index + source.length, (buffer + start + index + count), sizeof(T) * (length - index - count)); str.buffer[str.length] = 0; return std::move(str); } public: static ObjectString Empty; /// Create an empty string. ObjectString() = default; /// Copy a string. /// The string to copy. ObjectString(const ObjectString&string) { buffer = string.buffer; counter = string.counter; start = string.start; length = string.length; realLength = string.realLength; Inc(); } /// Move a string. /// The string to move. ObjectString(ObjectString && string) { buffer = string.buffer; counter = string.counter; start = string.start; length = string.length; realLength = string.realLength; string.buffer = (T*)&zero; string.counter = nullptr; string.start = 0; string.length = 0; string.realLength = 0; } ~ObjectString() { Dec(); } /// Copy a string. /// Memory to copy. It must be zero terminated. ObjectString(const T* _buffer) { CHECK_ERROR(_buffer != 0, L"ObjectString::ObjectString(const T*)#Cannot construct a string from nullptr."); counter = new vint(1); start = 0; length = CalculateLength(_buffer); buffer = new T[length + 1]; memcpy(buffer, _buffer, sizeof(T) * (length + 1)); realLength = length; } /// Take over a character pointer with known length. /// The created string. /// The zero-terminated character buffer which should be created using the global operator new[]. /// The number of available characters in the buffer. static ObjectString TakeOver(T* _buffer, vint _length) { CHECK_ERROR(_length >= 0, L"ObjectString::TakeOver(T*, vint)#Length should not be negative."); CHECK_ERROR(_buffer[_length] == 0, L"ObjectString::TakeOver(T*, vint)#Buffer is not properly zero-terminated."); ObjectString str; str.counter = new vint(1); str.length = _length; str.realLength = _length; str.buffer = _buffer; return std::move(str); } /// Create a string continaing one code point. /// The created string. /// The code point. static ObjectString FromChar(const T& _char) { T buffer[2]; buffer[0] = _char; buffer[1] = 0; return buffer; } /// Copy a string. /// Memory to copy. It is not required to be zero terminated. /// The created string. /// Size of the content in code points. static ObjectString CopyFrom(const T* _buffer, vint _length) { CHECK_ERROR(_length >= 0, L"ObjectString::CopyFrom(const T*, vint)#Length should not be negative."); if (_length > 0) { ObjectString str; str.buffer = new T[_length + 1]; memcpy(str.buffer, _buffer, _length * sizeof(T)); str.buffer[_length] = 0; str.counter = new vint(1); str.start = 0; str.length = _length; str.realLength = _length; return std::move(str); } return {}; } /// /// Create an unmanaged string. /// Such string uses a piece of unmanaged memory, /// hereby it doesn't release the memory when the string is destroyed. /// /// The created string. /// Unmanaged memory. It must be zero terminated. static ObjectString Unmanaged(const T* _buffer) { CHECK_ERROR(_buffer != 0, L"ObjectString::Unmanaged(const T*)#Cannot construct a string from nullptr."); ObjectString str; str.buffer = (T*)_buffer; str.length = CalculateLength(_buffer); str.realLength = str.length; return std::move(str); } /// /// Unsafe convert one string to another if their character components are in the same size. /// /// The type of the character component of the string to cast. /// The created string /// The string to cast template static ObjectString UnsafeCastFrom(const ObjectString& _string) { static_assert(sizeof(T) == sizeof(T2), "ObjectString::UnsafeCastFrom cannot be used on a string with a different size of the character component."); if (_string.Length() == 0) return {}; ObjectString str; str.buffer = (T*)_string.buffer; str.counter = _string.counter; str.start = _string.start; str.length = _string.length; str.realLength = _string.realLength; str.Inc(); return std::move(str); } /// /// Get the zero terminated buffer in the string. /// Copying parts of a string does not necessarily create a new buffer, /// so in some situation the string will not actually points to a zero terminated buffer. /// In this case, this function will copy the content to a new buffer with a zero terminator and return. /// /// The zero terminated buffer. const T* Buffer()const { if(start+length!=realLength) { T* newBuffer=new T[length+1]; memcpy(newBuffer, buffer+start, sizeof(T)*length); newBuffer[length]=0; Dec(); buffer=newBuffer; counter=new vint(1); start=0; realLength=length; } return buffer+start; } /// Replace the string by copying another string. /// The string itself. /// The string to copy. ObjectString& operator=(const ObjectString& string) { if(this!=&string) { Dec(); buffer=string.buffer; counter=string.counter; start=string.start; length=string.length; realLength=string.realLength; Inc(); } return *this; } /// Replace the string by moving another string. /// The string itself. /// The string to move. ObjectString& operator=(ObjectString&& string) { if(this!=&string) { Dec(); buffer=string.buffer; counter=string.counter; start=string.start; length=string.length; realLength=string.realLength; string.buffer=(T*)&zero; string.counter=0; string.start=0; string.length=0; string.realLength=0; } return *this; } /// Replace the string by appending another string. /// The string itself. /// The string to append. ObjectString& operator+=(const ObjectString& string) { return *this=*this+string; } /// Create a new string by concatenating two strings. /// The new string. /// The string to append. ObjectString operator+(const ObjectString& string)const { return ReplaceUnsafe(string, length, 0); } bool operator==(const ObjectString& string)const { return Compare(*this, string)==0; } bool operator!=(const ObjectString& string)const { return Compare(*this, string)!=0; } bool operator>(const ObjectString& string)const { return Compare(*this, string)>0; } bool operator>=(const ObjectString& string)const { return Compare(*this, string)>=0; } bool operator<(const ObjectString& string)const { return Compare(*this, string)<0; } bool operator<=(const ObjectString& string)const { return Compare(*this, string)<=0; } bool operator==(const T* buffer)const { return Compare(buffer, *this)==0; } bool operator!=(const T* buffer)const { return Compare(buffer, *this)!=0; } bool operator>(const T* buffer)const { return Compare(buffer, *this)<0; } bool operator>=(const T* buffer)const { return Compare(buffer, *this)<=0; } bool operator<(const T* buffer)const { return Compare(buffer, *this)>0; } bool operator<=(const T* buffer)const { return Compare(buffer, *this)>=0; } /// Get a code point in the specified position. /// Returns the code point. It will crash when the specified position is out of range. /// T operator[](vint index)const { CHECK_ERROR(index>=0 && index:operator[](vint)#Argument index not in range."); return buffer[start+index]; } /// Get the size of the string in code points. /// The size, not including the zero terminator. vint Length()const { return length; } /// Find a code point. /// The position of the code point. Returns -1 if it does not exist. /// The code point to find. vint IndexOf(T c)const { const T* reading=buffer+start; for(vint i=0;iGet the prefix of the string. /// The prefix. It will crash when the specified size is out of range. /// Size of the prefix. /// ObjectString Left(vint count)const { CHECK_ERROR(count>=0 && count<=length, L"ObjectString::Left(vint)#Argument count not in range."); return SubUnsafe(0, count); } /// Get the postfix of the string. /// The postfix. It will crash when the specified size is out of range. /// Size of the prefix. /// ObjectString Right(vint count)const { CHECK_ERROR(count>=0 && count<=length, L"ObjectString::Right(vint)#Argument count not in range."); return SubUnsafe(length-count, count); } /// Get a sub string. /// The sub string. It will crash when the specified position or size is out of range. /// The position of the first code point of the sub string. /// The size of the sub string. /// ObjectString Sub(vint index, vint count)const { CHECK_ERROR(index>=0 && index<=length, L"ObjectString::Sub(vint, vint)#Argument index not in range."); CHECK_ERROR(index+count>=0 && index+count<=length, L"ObjectString::Sub(vint, vint)#Argument count not in range."); return SubUnsafe(index, count); } /// Get a string by removing a sub string. /// The string without the sub string. It will crash when the specified position or size is out of range. /// The position of the first code point of the sub string. /// The size of the sub string. /// ObjectString Remove(vint index, vint count)const { CHECK_ERROR(index>=0 && index::Remove(vint, vint)#Argument index not in range."); CHECK_ERROR(index+count>=0 && index+count<=length, L"ObjectString::Remove(vint, vint)#Argument count not in range."); return ReplaceUnsafe(ObjectString(), index, count); } /// Get a string by inserting another string. /// The string with another string inserted. It will crash when the specified position is out of range. /// The position to insert. /// The string to insert. /// ObjectString Insert(vint index, const ObjectString& string)const { CHECK_ERROR(index>=0 && index<=length, L"ObjectString::Insert(vint)#Argument count not in range."); return ReplaceUnsafe(string, index, 0); } friend bool operator<(const T* left, const ObjectString& right) { return Compare(left, right)<0; } friend bool operator<=(const T* left, const ObjectString& right) { return Compare(left, right)<=0; } friend bool operator>(const T* left, const ObjectString& right) { return Compare(left, right)>0; } friend bool operator>=(const T* left, const ObjectString& right) { return Compare(left, right)>=0; } friend bool operator==(const T* left, const ObjectString& right) { return Compare(left, right)==0; } friend bool operator!=(const T* left, const ObjectString& right) { return Compare(left, right)!=0; } friend ObjectString operator+(const T* left, const ObjectString& right) { return ObjectString::Unmanaged(left)+right; } }; template ObjectString ObjectString::Empty=ObjectString(); template const T ObjectString::zero=0; /// Ansi string in local code page. typedef ObjectString AString; /// Unicode string, UTF-16 on Windows, UTF-32 on Linux and macOS. typedef ObjectString WString; /// Utf-8 String. typedef ObjectString U8String; /// Utf-16 String. typedef ObjectString U16String; /// Utf-32 String. typedef ObjectString U32String; /// Convert a string to a signed integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// Returns true if this operation succeeded. extern vint atoi_test(const AString& string, bool& success); /// Convert a string to a signed integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// Returns true if this operation succeeded. extern vint wtoi_test(const WString& string, bool& success); /// Convert a string to a signed 64-bits integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// Returns true if this operation succeeded. extern vint64_t atoi64_test(const AString& string, bool& success); /// Convert a string to a signed 64-bits integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// Returns true if this operation succeeded. extern vint64_t wtoi64_test(const WString& string, bool& success); /// Convert a string to an unsigned integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// Returns true if this operation succeeded. extern vuint atou_test(const AString& string, bool& success); /// Convert a string to an unsigned integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// Returns true if this operation succeeded. extern vuint wtou_test(const WString& string, bool& success); /// Convert a string to an unsigned 64-bits integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// Returns true if this operation succeeded. extern vuint64_t atou64_test(const AString& string, bool& success); /// Convert a string to an unsigned 64-bits integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// Returns true if this operation succeeded. extern vuint64_t wtou64_test(const WString& string, bool& success); /// Convert a string to a 64-bits floating point number. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// Returns true if this operation succeeded. extern double atof_test(const AString& string, bool& success); /// Convert a string to a 64-bits floating point number. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// Returns true if this operation succeeded. extern double wtof_test(const WString& string, bool& success); /// Convert a string to a signed integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// If you need to know whether the conversion is succeeded or not, please use instead. extern vint atoi(const AString& string); /// Convert a string to a signed integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// If you need to know whether the conversion is succeeded or not, please use instead. extern vint wtoi(const WString& string); /// Convert a string to a signed 64-bits integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// If you need to know whether the conversion is succeeded or not, please use instead. extern vint64_t atoi64(const AString& string); /// Convert a string to a signed 64-bits integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// If you need to know whether the conversion is succeeded or not, please use instead. extern vint64_t wtoi64(const WString& string); /// Convert a string to an usigned integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// If you need to know whether the conversion is succeeded or not, please use instead. extern vuint atou(const AString& string); /// Convert a string to an usigned integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// If you need to know whether the conversion is succeeded or not, please use instead. extern vuint wtou(const WString& string); /// Convert a string to an usigned 64-bits integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// If you need to know whether the conversion is succeeded or not, please use instead. extern vuint64_t atou64(const AString& string); /// Convert a string to an usigned 64-bits integer. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// If you need to know whether the conversion is succeeded or not, please use instead. extern vuint64_t wtou64(const WString& string); /// Convert a string to a 64-bits floating point number. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// If you need to know whether the conversion is succeeded or not, please use instead. extern double atof(const AString& string); /// Convert a string to a 64-bits floating point number. /// The converted number. If the conversion failed, the result is undefined. /// The string to convert. /// If you need to know whether the conversion is succeeded or not, please use instead. extern double wtof(const WString& string); /// Convert a signed interger to a string. /// The converted string. /// The number to convert. extern AString itoa(vint number); /// Convert a signed interger to a string. /// The converted string. /// The number to convert. extern WString itow(vint number); /// Convert a signed 64-bits interger to a string. /// The converted string. /// The number to convert. extern AString i64toa(vint64_t number); /// Convert a signed 64-bits interger to a string. /// The converted string. /// The number to convert. extern WString i64tow(vint64_t number); /// Convert an unsigned interger to a string. /// The converted string. /// The number to convert. extern AString utoa(vuint number); /// Convert an unsigned interger to a string. /// The converted string. /// The number to convert. extern WString utow(vuint number); /// Convert an unsigned 64-bits interger to a string. /// The converted string. /// The number to convert. extern AString u64toa(vuint64_t number); /// Convert an unsigned 64-bits interger to a string. /// The converted string. /// The number to convert. extern WString u64tow(vuint64_t number); /// Convert a 64-bits floating pointer number to a string. /// The converted string. /// The number to convert. extern AString ftoa(double number); /// Convert a 64-bits floating pointer number to a string. /// The converted string. /// The number to convert. extern WString ftow(double number); /// Convert all letters to lower case letters. /// The converted string. /// The string to convert. extern AString alower(const AString& string); /// Convert all letters to lower case letters. /// The converted string. /// The string to convert. extern WString wlower(const WString& string); /// Convert all letters to upper case letters. /// The converted string. /// The string to convert. extern AString aupper(const AString& string); /// Convert all letters to upper case letters. /// The converted string. /// The string to convert. extern WString wupper(const WString& string); #if defined VCZH_GCC extern void _itoa_s(vint32_t value, char* buffer, size_t size, vint radix); extern void _itow_s(vint32_t value, wchar_t* buffer, size_t size, vint radix); extern void _i64toa_s(vint64_t value, char* buffer, size_t size, vint radix); extern void _i64tow_s(vint64_t value, wchar_t* buffer, size_t size, vint radix); extern void _uitoa_s(vuint32_t value, char* buffer, size_t size, vint radix); extern void _uitow_s(vuint32_t value, wchar_t* buffer, size_t size, vint radix); extern void _ui64toa_s(vuint64_t value, char* buffer, size_t size, vint radix); extern void _ui64tow_s(vuint64_t value, wchar_t* buffer, size_t size, vint radix); extern void _gcvt_s(char* buffer, size_t size, double value, vint numberOfDigits); extern void _strlwr_s(char* buffer, size_t size); extern void _strupr_s(char* buffer, size_t size); extern void _wcslwr_s(wchar_t* buffer, size_t size); extern void _wcsupr_s(wchar_t* buffer, size_t size); extern void wcscpy_s(wchar_t* buffer, size_t size, const wchar_t* text); #endif } #endif /*********************************************************************** .\COLLECTIONS\OPERATIONSTRING.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_COLLECTIONS_OPERATIONSTRING #define VCZH_COLLECTIONS_OPERATIONSTRING namespace vl { namespace collections { /// Copy containers. /// Type of the target container. /// Type of code points in the source string. /// The target container. /// The source string. /// Set to true to perform appending instead of replacing. template void CopyFrom(Ds& ds, const ObjectString& ss, bool append = false) { const S* buffer = ss.Buffer(); vint count = ss.Length(); CopyFrom(ds, buffer, count, append); } /// Copy containers. /// Type of code points in the target string. /// Type of the source container. /// The target string. /// The source container. /// Set to true to perform appending instead of replacing. template void CopyFrom(ObjectString& ds, const Ss& ss, bool append = false) { Array da(ds.Buffer(), ds.Length()); CopyFrom(da, ss, append); if (da.Count() == 0) { ds = {}; } else { ds = ObjectString::CopyFrom(&da[0], da.Count()); } } } } #endif /*********************************************************************** .\COLLECTIONS\OPERATION.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License Functions: CopyFrom(TargetContainer, SourceContainer) [T] .Select(T->K) => [K] [T] .Where(T->bool) => [T] [Ptr] .Cast() => [Ptr] [Ptr] .FindType() => [Ptr] [T] .OrderBy(T->T->int) => [T] [T] .Aggregate(T->T->T) => T [T] .Aggregate(T->T->T, T) => T [T] .All(T->bool) => bool [T] .Any(T->bool) => bool [T] .Max() => T [T] .Min() => T [T] .First() => T [T] .FirstOrDefault(T) => T [T] .Last() => T [T] .LastOrDefault(T) => T [T] .Count() => vint [T] .IsEmpty() => bool [T] .Concat([T]) => [T] (evaluated) [T] .Take(vint) => [T] (evaluated) [T] .Skip(vint) => [T] (evaluated) [T] .Repeat(vint) => [T] (evaluated) [T] .Distinct() => [T] [T] .Reverse() => [T] (evaluated) [T] .Pairwise([K]) => [(T,K)] (evaluated) [T] .Intersect([T]) => [T] [T] .Except([T]) => [T] [T] .Union([T]) => [T] [T] .Evaluate() => [T] [T] .SelectMany(T->[K]) => [K] [T] .GroupBy(T->K) => [(K, [T])] (evaluated) means the lazy list is evaluated when all sources are evaluated From(begin, end) => [T] From(array) => [T] Range(start, count) => [vint] for (auto x : xs); for (auto [x, i] : indexed(xs)); ***********************************************************************/ #ifndef VCZH_COLLECTIONS_OPERATION #define VCZH_COLLECTIONS_OPERATION namespace vl { namespace collections { /*********************************************************************** Quick Sort ***********************************************************************/ /// Quick sort. /// Type of elements. /// Type of the comparer. /// Pointer to element array to sort. /// The number of elements to sort. /// /// The comparar for two elements. /// Both arguments are elements to compare. /// Returns a positive number when the first argument is greater. /// Returns a negative number when the second argument is greater. /// Returns zero when two arguments equal. /// template void SortLambda(T* items, vint length, F orderer) { while (true) { if (length == 0) return; vint pivot = 0; vint left = 0; vint right = 0; { bool flag = false; while (left + right + 1 != length) { vint& mine = (flag ? left : right); vint& theirs = (flag ? right : left); vint candidate = (flag ? left : length - right - 1); vint factor = (flag ? -1 : 1); if (orderer(items[pivot], items[candidate]) * factor <= 0) { mine++; } else { theirs++; T temp = items[pivot]; items[pivot] = items[candidate]; items[candidate] = temp; pivot = candidate; flag = !flag; } } } { vint reading = left - 1; vint writing = reading; while (reading >= 0) { if (orderer(items[pivot], items[reading]) == 0) { if (reading != writing) { T temp = items[reading]; items[reading] = items[writing]; items[writing] = temp; } writing--; } reading--; } left = writing + 1; } { vint reading = length - right; vint writing = reading; while (reading < length) { if (orderer(items[pivot], items[reading]) == 0) { if (reading != writing) { T temp = items[reading]; items[reading] = items[writing]; items[writing] = temp; } writing++; } reading++; } right = length - writing; } if (left < right) { SortLambda(items, left, orderer); items += length - right; length = right; } else { SortLambda(items + length - right, right, orderer); length = left; } } } /// Quick sort. /// Type of elements. /// Pointer to element array to sort. /// The number of elements to sort. /// /// The comparar for two elements. /// Both arguments are elements to compare. /// Returns a positive number when the first argument is greater. /// Returns a negative number when the second argument is greater. /// Returns zero when two arguments equal. /// template void Sort(T* items, vint length, const Func& orderer) { SortLambda>(items, length, orderer); } /*********************************************************************** LazyList ***********************************************************************/ /// A lazy evaluated container with rich operations. is useful to create lazy list from arrays or containers. /// The type of elements. /// ///

A lazy list is usually created directly from a container source, or from a calculation on a source.

///

Typically the lazy list cannot be used after the source is deleted.

///

/// If this lazy list needs to be used after the source is deleted, /// you are recommended to use [F:vl.collections.LazyList`1.Evaluate], with forceCopy set to true. ///

///

In this way you get a lazy list with all values copied, they do not rely on other objects.

///
template class LazyList : public EnumerableBase { protected: Ptr> enumeratorPrototype; IEnumerator* xs()const { return enumeratorPrototype->Clone(); } using TInput = decltype(std::declval>().Current()); public: /// Create a lazy list from an enumerator. This enumerator will be deleted when this lazy list is deleted. /// The enumerator. LazyList(IEnumerator* enumerator) :enumeratorPrototype(enumerator) { } /// Create a lazy list from an enumerator. /// The enumerator. LazyList(Ptr> enumerator) :enumeratorPrototype(enumerator) { } /// Create a lazy list from an enumerable. /// The enumerable. LazyList(const IEnumerable& enumerable) :enumeratorPrototype(enumerable.CreateEnumerator()) { } /// Create a lazy list from another lazy list. /// The lazy list. LazyList(const LazyList& lazyList) :enumeratorPrototype(lazyList.enumeratorPrototype) { // no need to clone enumeratorPrototype as it will never be iterated } /// Create a lazy list from another lazy list. /// The lazy list. LazyList(LazyList&& lazyList) :enumeratorPrototype(lazyList.enumeratorPrototype) { lazyList.enumeratorPrototype = nullptr; } /// Create a lazy list from a container. It is very useful to a container as an intermediate result and then put in a lazy list. /// Type of the container. /// The container. template LazyList(Ptr container) :enumeratorPrototype(new ContainerEnumerator(container)) { } /// Create an empty lazy list. LazyList() :enumeratorPrototype(new EmptyEnumerator()) { } LazyList& operator=(const LazyList& lazyList) { // no need to clone enumeratorPrototype as it will never be iterated enumeratorPrototype = lazyList.enumeratorPrototype; return *this; } LazyList& operator=(LazyList&& lazyList) { enumeratorPrototype = lazyList.enumeratorPrototype; lazyList.enumeratorPrototype = nullptr; return *this; } IEnumerator* CreateEnumerator()const { return enumeratorPrototype->Clone(); } //------------------------------------------------------- /// Create a new lazy list with all elements transformed. /// Type of the transformer. /// The created lazy list. /// The transformer. /// template auto Select(F f) const -> LazyList()))> { return new SelectEnumerator()))>(xs(), f); } /// Create a new lazy list with all elements filtered. /// Type of the filter. /// The created lazy list. /// The filter. /// template LazyList Where(F f)const { return new WhereEnumerator(xs(), f); } /// Create a new lazy list with all elements casted to a new type. /// The new type. /// The created lazy list. /// /// The lazy list being casted contains elements of type [T:vl.Ptr`1]. /// [F:vl.Ptr`1.Cast`1] is called on each elements. /// If some elements fail to cast, they become empty shared pointers. /// template LazyList> Cast()const { Func(T)> f = [](T t)->Ptr {return t.template Cast(); }; return new SelectEnumerator>(xs(), f); } /// Create a new lazy list with only elements that successfully casted to a new type. /// The new type. /// The created lazy list. /// /// The lazy list being casted contains elements of type [T:vl.Ptr`1]. /// [F:vl.Ptr`1.Cast`1] is called on each elements. /// If some elements fail to cast, they are eliminated from the result. /// template LazyList> FindType()const { return Cast().Where([](Ptr t) {return t; }); } /// Create a new lazy list with all elements sorted. /// Type of the comparer. /// The created lazy list. /// /// The comparar for two elements. /// Both arguments are elements to compare. /// Returns a positive number when the first argument is greater. /// Returns a negative number when the second argument is greater. /// Returns zero when two arguments equal. /// /// template LazyList OrderBy(F f)const { auto sorted = Ptr(new List); CopyFrom(*sorted.Obj(), *this); if (sorted->Count() > 0) { SortLambda(&sorted->operator[](0), sorted->Count(), f); } return sorted; } //------------------------------------------------------- /// Aggregate a lazy list. It will crash if the lazy list is empty. /// Type of the aggregator. /// The aggregated value. /// /// The aggregator. /// The first argument is the aggregated value of any prefix. /// The second argument is the element right after a prefix. /// Returns the aggregated value of the new prefix. /// For the first call, the first argument is the first element in the lazy list. /// /// template T Aggregate(F f)const { auto enumerator = Ptr(CreateEnumerator()); if (!enumerator->Next()) { throw Error(L"LazyList::Aggregate(F)#Aggregate failed to calculate from an empty container."); } T result = enumerator->Current(); while (enumerator->Next()) { result = f(result, enumerator->Current()); } return result; } /// Aggregate a lazy list. /// Type of the initial value. /// Type of the aggregator. /// The aggregated value. /// The aggregated value defined for the empty prefix. /// /// The aggregator. /// The first argument is the aggregated value of any prefix. /// The second argument is the element right after a prefix. /// Returns the aggregated value of the new prefix. /// /// template I Aggregate(I init, F f)const { for (auto& t : *this) { init = f(init, t); } return init; } /// Test if all elements in the lazy list satisfy a filter. /// Type of the filter. /// Returns true if all elements satisfy the filter. /// The filter. /// template bool All(F f)const { return Select(f).Aggregate(true, [](bool a, bool b) { return a && b; }); } /// Test if any elements in the lazy list satisfy a filter. /// Type of the filter. /// Returns true if there is at least one element satisfies the filter. /// The filter. /// template bool Any(F f)const { return Select(f).Aggregate(false, [](bool a, bool b) { return a || b; }); } /// Get the maximum value in the lazy list. It will crash if the lazy list is empty. /// The maximum value. /// T Max()const { return Aggregate([](T a, T b) { return a > b ? a : b; }); } /// Get the minimum value in the lazy list. It will crash if the lazy list is empty. /// The minimum value. /// T Min()const { return Aggregate([](T a, T b) { return a < b ? a : b; }); } /// Get the first value in the lazy list. It will crash if the lazy list is empty. /// The first value. T First()const { auto enumerator = Ptr(CreateEnumerator()); if (!enumerator->Next()) { throw Error(L"LazyList::First(F)#First failed to calculate from an empty container."); } return enumerator->Current(); } /// Get the first value in the lazy list. /// The first value. If the lazy list is empty, the argument is returned. /// The argument to return if the lazy list is empty. T First(T defaultValue)const { auto enumerator = Ptr(CreateEnumerator()); if (!enumerator->Next()) { return defaultValue; } return enumerator->Current(); } /// Get the last value in the lazy list. It will crash if the lazy list is empty. /// The last value. T Last()const { auto enumerator = Ptr(CreateEnumerator()); if (!enumerator->Next()) { throw Error(L"LazyList::Last(F)#Last failed to calculate from an empty container."); } else { T value = enumerator->Current(); while (enumerator->Next()) { value = enumerator->Current(); } return value; } } /// Get the last value in the lazy list. /// The last value. If the lazy list is empty, the argument is returned. /// The argument to return if the lazy list is empty. T Last(T defaultValue)const { auto enumerator = Ptr(CreateEnumerator()); while (enumerator->Next()) { defaultValue = enumerator->Current(); } return defaultValue; } /// Get the number of elements in the lazy list. /// The number of elements. vint Count()const { vint result = 0; auto enumerator = Ptr(CreateEnumerator()); while (enumerator->Next()) { result++; } return result; } /// Test if the lazy list is empty. /// Returns true if the lazy list is empty. bool IsEmpty()const { auto enumerator = Ptr(CreateEnumerator()); return !enumerator->Next(); } //------------------------------------------------------- /// Create a new lazy list containing elements of the two container in order. /// The created lazy list. /// Elements to be appended. /// LazyList Concat(const IEnumerable& remains)const { return new ConcatEnumerator(xs(), remains.CreateEnumerator()); } /// Create a new lazy list with a prefix of the lazy list. /// The created lazy list. /// The size of the prefix. /// LazyList Take(vint count)const { return new TakeEnumerator(xs(), count); } /// Create a new lazy list with a postfix of the lazy list. /// The created lazy list. /// The number of elements to skip. /// LazyList Skip(vint count)const { return new SkipEnumerator(xs(), count); } /// Create a new lazy list with several copies of the lazy list in order. /// The created lazy list. /// The numbers of copies. /// LazyList Repeat(vint count)const { return new RepeatEnumerator(xs(), count); } /// Create a new lazy list with duplicated elements removed in this lazy list. /// The created lazy list. /// LazyList Distinct()const { return new DistinctEnumerator(xs()); } /// Create a new lazy list with all elements in this lazy list in a reverse order. /// The created lazy list. /// LazyList Reverse()const { return new ReverseEnumerator(*this); } //------------------------------------------------------- /// Create a new lazy list of pairs from elements from two containers. /// Type of all elements in the second container. /// /// The created lazy list, which contains pairs of elements from two containers at the same position. /// If the two container have different sizes, the created lazy list has the size of the shorter one. /// /// The second container. /// p){ return p.key + p.value; }); /// for (auto z : zs) Console::Write(itow(z) + L" "); /// } /// ]]> template LazyList> Pairwise(const IEnumerable& remains)const { return new PairwiseEnumerator(xs(), remains.CreateEnumerator()); } /// Create a new lazy list with elements from the lazy list, which also appear in the second container. /// The created lazy list. Elements in the create lazy list is in the same order as in this lazy list. /// The second container. /// LazyList Intersect(const IEnumerable& remains)const { return LazyList(new IntersectExceptEnumerator(xs(), remains)).Distinct(); } /// Create a new lazy list with elements from the lazy list, which do not appear in the second container. /// The created lazy list. Elements in the create lazy list is in the same order as in this lazy list. /// The second container. /// LazyList Except(const IEnumerable& remains)const { return LazyList(new IntersectExceptEnumerator(xs(), remains)).Distinct(); } /// Create a new lazy list with elements in two containers. Duplicated elements will be removed. /// The created lazy list. /// The second container. /// LazyList Union(const IEnumerable& remains)const { return Concat(remains).Distinct(); } //------------------------------------------------------- /// Get an evaluated copy of this lazy list. /// /// The created lazy list. /// If this lazy list has been evaluated before, it returns a reference to this lazy list. /// If this lazy list has not been evaluated before, it go through this lazy list and copy all values. /// /// Set to true to force copying values, regardless of whether this lazy list is evaluated or not. /// ///

"Evaluated" means reading from this lazy list cause no extra calculation.

///

In most of the cases, the created lazy list relies on its source.

///

For example, a lazy list can be created from a reference to a , or from an array on stack.

///

If this list or array is deleted, then iterating the created lazy list will crash.

///

By calling the Evaluate function with forceCopy set to true, a new lazy list is created, with all values cached in it.

///

Its connection to the source list or array is removed, and can then be passed to everywhere.

///
LazyList Evaluate(bool forceCopy = false)const { if (!forceCopy && enumeratorPrototype->Evaluated()) { return *this; } else { auto xs = Ptr(new List); CopyFrom(*xs.Obj(), *this); return xs; } } /// Create a new lazy list, whose elements are from transformed elements in this lazy list. /// Type of the transformer. /// The created lazy list. /// /// The transformer. /// The first argument is any element in this lazy list. /// Returns the transformed lazy list from this argument. /// /// template auto SelectMany(F f)const -> LazyList()))::ElementType> { using U = typename decltype(f(std::declval()))::ElementType; return Select(f).Aggregate(LazyList(), [](const LazyList& a, const IEnumerable& b)->LazyList {return a.Concat(b); }); } /// Create a new lazy list, with elements from this lazy list grouped by a key function. /// Type of the key function. /// The created lazy list. /// /// The key function. /// The first argument is any element in this lazy list. /// Returns a key calculated from this argument. /// Elements that have the same key will be grouped together. /// /// >; /// for (auto y : ys) /// { /// Console::Write(itow(y.key) + L":"); /// for (auto z : y.value) Console::Write(L" " + itow(z)); /// Console::WriteLine(L""); /// } /// } /// ]]> template auto GroupBy(F f)const -> LazyList())), LazyList>> { using K = decltype(f(std::declval())); auto self = *this; return Select(f) .Distinct() .Select([=](K k) { return Pair>( k, self.Where([=](T t) {return k == f(t); }) ); }); } }; /// Create a lazy list with a series of increasing number. /// Type of elements. /// A lazy list of increasing numbers. /// The first number. /// Total amount of increasing numbers. template LazyList Range(T start, T count) { return new RangeEnumerator(start, count); } /// Create a lazy list from an enumerable. /// Type of elements. /// The created lazy list. /// The enumerable. template LazyList From(const IEnumerable& enumerable) { return enumerable; } /// Create a lazy list from another lazy list. /// Type of elements. /// The created lazy list. /// The lazy list to copy. template LazyList From(const LazyList& enumerable) { return enumerable; } /// Create a lazy list from an array. /// Type of elements. /// The created lazy list. /// Pointer to the first element in the array. /// Pointer to the element after the last element in the array. template LazyList From(const T* begin, const T* end) { return FromPointer(begin, end); } /// Create a lazy list from an array. /// Type of elements. /// Size of the array. /// The created lazy list. /// The array. template LazyList From(T (&items)[size]) { return FromArray(items); } /// Create a lazy list from an array. /// Type of elements. /// Size of the array. /// The created lazy list. /// The array. template LazyList From(const T (&items)[size]) { return FromArray(items); } /*********************************************************************** Range-Based For-Loop Iterator with Index for LazyList ***********************************************************************/ template struct LazyListWithIndex { LazyList lazyList; LazyListWithIndex(const LazyList& _lazyList) : lazyList(_lazyList) { } }; template LazyListWithIndex indexed(const LazyList& lazyList) { return { lazyList }; } template RangeBasedForLoopIteratorWithIndex begin(const LazyListWithIndex& enumerable) { return { enumerable.lazyList }; } template RangeBasedForLoopEnding end(const LazyListWithIndex& enumerable) { return {}; } } } #endif /*********************************************************************** .\CONSOLE.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_CONSOLE #define VCZH_CONSOLE namespace vl { namespace console { /// Basic I/O for command-line applications. class Console abstract { public: /// Write a string to the command-line window. /// Content to write. /// Size of the content in wchar_t, not including the zero terminator. static void Write(const wchar_t* string, vint length); /// Write a string to the command-line window. /// Content to write, must be zero terminated. static void Write(const wchar_t* string); /// Write a string to the command-line window. /// Content to write. static void Write(const WString& string); /// Write to the command-line window, following CR/LF characters. /// Content to write. static void WriteLine(const WString& string); /// Read a string 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 ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_EXCEPTION #define VCZH_EXCEPTION namespace vl { /// Base type of all exceptions. class Exception : public Object { protected: WString message; public: Exception(const WString& _message=WString::Empty); const WString& Message()const; }; class ArgumentException : public Exception { protected: WString function; WString name; public: ArgumentException(const WString& _message=WString::Empty, const WString& _function=WString::Empty, const WString& _name=WString::Empty); const WString& GetFunction()const; const WString& GetName()const; }; } #endif /*********************************************************************** .\GLOBALSTORAGE.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_GLOBALSTORAGE #define VCZH_GLOBALSTORAGE namespace vl { /// /// Base type of all global storages. /// A global storage stores multiple values using a name. /// The "BEGIN_GLOBAL_STOREGE_CLASS" macro is recommended to create a global storage. /// /// /// All values are shared like global variables, but they are created at the first time when they need to be accessed. /// is recommended after you don't need any global storages any more, it frees memory. /// /// data; /// INITIALIZE_GLOBAL_STORAGE_CLASS /// data = new vint(100); /// FINALIZE_GLOBAL_STORAGE_CLASS /// data = nullptr; /// END_GLOBAL_STORAGE_CLASS(MyStorage) /// /// int main() /// { /// // GetMyStorage is generated by defining MyStorage /// Console::WriteLine(itow(*GetMyStorage().data.Obj())); /// FinalizeGlobalStorage(); /// } /// ]]> class GlobalStorage : public Object { private: bool initialized = false; protected: virtual void InitializeResource() = 0; virtual void FinalizeResource() = 0; public: NOT_COPYABLE(GlobalStorage); GlobalStorage(); ~GlobalStorage(); bool IsInitialized(); void EnsureInitialized(); void EnsureFinalized(); }; struct GlobalStorageDescriptor { GlobalStorage* globalStorage = nullptr; GlobalStorageDescriptor* next = nullptr; }; extern void RegisterStorageDescriptor(GlobalStorageDescriptor* globalStorageDescriptor); /// Free all memories used by global storages. extern void FinalizeGlobalStorage(); } #define BEGIN_GLOBAL_STORAGE_CLASS(NAME) \ class NAME \ : public vl::GlobalStorage \ , private vl::GlobalStorageDescriptor \ { \ public: \ NAME() \ { \ globalStorage = this; \ vl::RegisterStorageDescriptor(this); \ } \ ~NAME() \ { \ EnsureFinalized(); \ } \ #define INITIALIZE_GLOBAL_STORAGE_CLASS \ protected: \ void InitializeResource() \ { \ #define FINALIZE_GLOBAL_STORAGE_CLASS \ } \ protected: \ void FinalizeResource() \ { \ #define END_GLOBAL_STORAGE_CLASS(NAME) \ } \ }; \ NAME& Get##NAME() \ { \ static NAME __global_storage_##NAME; \ __global_storage_##NAME.EnsureInitialized(); \ return __global_storage_##NAME; \ } \ #define EXTERN_GLOBAL_STORAGE_CLASS(NAME)\ class NAME;\ extern NAME& Get##NAME();\ #endif /*********************************************************************** .\STRINGS\CONVERSION.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_STRINGS_CONVERSION #define VCZH_STRINGS_CONVERSION namespace vl { namespace encoding { /*********************************************************************** UtfConversion ***********************************************************************/ template struct UtfConversion; template<> struct UtfConversion { #if defined VCZH_WCHAR_UTF16 static const vint BufferLength = 2; #elif defined VCZH_WCHAR_UTF32 static const vint BufferLength = 1; #endif static vint From32(char32_t source, wchar_t(&dest)[BufferLength]); static vint To32(const wchar_t* source, vint sourceLength, char32_t& dest); }; template<> struct UtfConversion { static const vint BufferLength = 6; static vint From32(char32_t source, char8_t(&dest)[BufferLength]); static vint To32(const char8_t* source, vint sourceLength, char32_t& dest); }; template<> struct UtfConversion { static const vint BufferLength = 2; static vint From32(char32_t source, char16_t(&dest)[BufferLength]); static vint To32(const char16_t* source, vint sourceLength, char32_t& dest); }; /*********************************************************************** Utfto32ReaderBase and UtfFrom32ReaerBase ***********************************************************************/ struct UtfCharCluster { vint index; vint size; }; template class UtfFrom32ReaderBase : public Object { static const vint BufferLength = UtfConversion::BufferLength; vint read = 0; vint available = 0; T buffer[BufferLength]; UtfCharCluster sourceCluster = { 0,0 }; vint readCounter = -1; bool error = false; public: T Read() { if (available == -1) return 0; if (read == available) { char32_t c = static_cast(this)->Consume(); if (c) { available = UtfConversion::From32(c, buffer); if (available == -1) return 0; sourceCluster.index += sourceCluster.size; sourceCluster.size = 1; } else { available = -1; readCounter++; sourceCluster.index += sourceCluster.size; sourceCluster.size = 0; return 0; } read = 0; } readCounter++; return buffer[read++]; } vint ReadingIndex() const { return readCounter; } UtfCharCluster SourceCluster() const { return sourceCluster; } bool HasIllegalChar() const { return error; } }; template class UtfTo32ReaderBase : public Object { static const vint BufferLength = UtfConversion::BufferLength; vint available = 0; T buffer[BufferLength]; UtfCharCluster sourceCluster = { 0,0 }; vint readCounter = -1; bool error = false; public: char32_t Read() { if (available == -1) return 0; while (available < BufferLength) { T c = static_cast(this)->Consume(); if (c) { buffer[available++] = c; } else { if (available == 0) { available = -1; readCounter++; sourceCluster.index += sourceCluster.size; sourceCluster.size = 0; return 0; } break; } } char32_t dest = 0; vint result = UtfConversion::To32(buffer, available, dest); if (result == -1) { available = -1; return 0; } available -= result; for (vint i = 0; i < available; i++) { buffer[i] = buffer[i + result]; } readCounter++; sourceCluster.index += sourceCluster.size; sourceCluster.size = result; return dest; } vint ReadingIndex() const { return readCounter; } UtfCharCluster SourceCluster() const { return sourceCluster; } bool HasIllegalChar() const { return error; } }; /*********************************************************************** UtfStringTo32Reader and UtfStringFrom32Reader ***********************************************************************/ template class UtfStringConsumer : public TBase { protected: const T* starting = nullptr; const T* consuming = nullptr; T Consume() { T c = *consuming; if (c) consuming++; return c; } public: UtfStringConsumer(const T* _starting) : starting(_starting) , consuming(_starting) { } }; template class UtfStringFrom32Reader : public UtfStringConsumer>> { template friend class UtfFrom32ReaderBase; public: UtfStringFrom32Reader(const char32_t* _starting) : UtfStringConsumer>>(_starting) { } }; template class UtfStringTo32Reader : public UtfStringConsumer>> { template friend class UtfTo32ReaderBase; public: UtfStringTo32Reader(const T* _starting) : UtfStringConsumer>>(_starting) { } }; template class UtfStringToStringReader : public UtfFrom32ReaderBase> { template friend class UtfFrom32ReaderBase; protected: UtfStringTo32Reader internalReader; char32_t Consume() { return internalReader.Read(); } public: UtfStringToStringReader(const TFrom* _starting) : internalReader(_starting) { } UtfCharCluster SourceCluster() const { return internalReader.SourceCluster(); } bool HasIllegalChar() const { return UtfFrom32ReaderBase>::HasIllegalChar() || internalReader.HasIllegalChar(); } }; } /*********************************************************************** String Conversions (buffer walkthrough) ***********************************************************************/ extern vint _wtoa(const wchar_t* w, char* a, vint chars); extern vint _atow(const char* a, wchar_t* w, vint chars); template vint _utftou32(const T* s, char32_t* d, vint chars); template vint _u32toutf(const char32_t* s, T* d, vint chars); extern template vint _utftou32(const wchar_t* s, char32_t* d, vint chars); extern template vint _utftou32(const char8_t* s, char32_t* d, vint chars); extern template vint _utftou32(const char16_t* s, char32_t* d, vint chars); extern template vint _u32toutf(const char32_t* s, wchar_t* d, vint chars); extern template vint _u32toutf(const char32_t* s, char8_t* d, vint chars); extern template vint _u32toutf(const char32_t* s, char16_t* d, vint chars); /*********************************************************************** String Conversions (direct) ***********************************************************************/ extern AString wtoa (const WString& source); extern WString atow (const AString& source); extern U32String wtou32 (const WString& source); extern WString u32tow (const U32String& source); extern U32String u8tou32 (const U8String& source); extern U8String u32tou8 (const U32String& source); extern U32String u16tou32(const U16String& source); extern U16String u32tou16(const U32String& source); /*********************************************************************** String Conversions (buffer walkthrough indirect) ***********************************************************************/ template vint _utftoutf(const TFrom* s, TTo* d, vint chars); extern template vint _utftoutf(const wchar_t* s, char8_t* d, vint chars); extern template vint _utftoutf(const wchar_t* s, char16_t* d, vint chars); extern template vint _utftoutf(const char8_t* s, wchar_t* d, vint chars); extern template vint _utftoutf(const char8_t* s, char16_t* d, vint chars); extern template vint _utftoutf(const char16_t* s, wchar_t* d, vint chars); extern template vint _utftoutf(const char16_t* s, char8_t* d, vint chars); /*********************************************************************** String Conversions (unicode indirect) ***********************************************************************/ extern U8String wtou8 (const WString& source); extern WString u8tow (const U8String& source); extern U16String wtou16 (const WString& source); extern WString u16tow (const U16String& source); extern U16String u8tou16 (const U8String& source); extern U8String u16tou8 (const U16String& source); /*********************************************************************** String Conversions (ansi indirect) ***********************************************************************/ inline U8String atou8 (const AString& source) { return wtou8(atow(source)); } inline U16String atou16 (const AString& source) { return wtou16(atow(source)); } inline U32String atou32 (const AString& source) { return wtou32(atow(source)); } inline AString u8toa (const U8String& source) { return wtoa(u8tow(source)); } inline AString u16toa (const U16String& source) { return wtoa(u16tow(source)); } inline AString u32toa (const U32String& source) { return wtoa(u32tow(source)); } } #endif /*********************************************************************** .\STRINGS\LOREMIPSUM.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_STRINGS_LOREMIPSUM #define VCZH_STRINGS_LOREMIPSUM namespace vl { /// Style of the random text. enum class LoremIpsumCasing { /// First letters of all words are lower cased. AllWordsLowerCase, /// first letters of first words of all sentences are upper cased. FirstWordUpperCase, /// First letters of all words are upper cased. AllWordsUpperCase, }; /// Get some random text. /// The generated random text. It may not exactly in the expected size. /// The expected size. /// The expected casing. extern WString LoremIpsum(vint bestLength, LoremIpsumCasing casing); /// Get some random text for a title, first letters of all words are upper cased. /// The generated random text. It may not be exactly in the expected size. /// The expected size. extern WString LoremIpsumTitle(vint bestLength); /// Get some random sentences. The first letter of the first word is uppder cased. /// The generated random text with a period character ".". It may not be exactly in the expected size. /// The expected size. extern WString LoremIpsumSentence(vint bestLength); /// Get some random paragraphs. First letters of first words of all sentences are upper cased. /// The generated random text with multiple sentences ending with period characters ".". It may not be exactly in the expected size. /// The expected size. extern WString LoremIpsumParagraph(vint bestLength); } #endif /*********************************************************************** .\UNITTEST\UNITTEST.H ***********************************************************************/ /*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/ #ifndef VCZH_UNITTEST #define VCZH_UNITTEST namespace vl { namespace unittest { using UnitTestFileProc = void(*)(); struct UnitTestLink { const char* fileName = nullptr; UnitTestFileProc testProc = nullptr; UnitTestLink* next = nullptr; }; /// ///

Unit test framework.

///

/// Test cases could be defined in multiple cpp files. In each cpp file, there can be one TEST_FILE call. /// ///

///

/// Both TEST_CATEGORY could be used inside TEST_FILE, or nested inside another TEST_CATEGORY. /// TEST_CASE could be used inside TEST_FILE or TEST_CATEGORY. ///

///

/// TEST_ASSERT is used to verify a boolean expression. /// It could only be used in TEST_CASE. /// TEST_ASSERT could not be used in TEST_FILE or TEST_CATEGORY. ///

///

/// When the test program is started in debug mode (Windows only), or by command line options "/D", /// A TEST_ASSERT failure will trigger a break point, it could be catched by any debugger. ///

///

/// When the test program is started in release mode, or by command line options "/R", or without command line options, /// A TEST_ASSERT failure will report an error and skip rest of the current TEST_CASE, the execution will continue. ///

///

/// TEST_ERROR execute one statement, it fails when no [T:vl.Error] is thrown. ///

///

/// TEST_EXCEPTION execute one statement, it fails when the specified exception type is not thrown. /// Another callback will be called when the exception is thrown, given a chance to check data in the exception. ///

///

/// TEST_CASE_ASSERT is an abbreviation of TEST_CASE + TEST_ASSERT. /// It is very common that are multiple independent assertions. ///

///

/// TEST_CASE_ASSERT is a test case, it can be used in TEST_CATEGORY or TEST_FILE. /// In release mode, by failing this assertion, the execution does not stop. ///

///

/// TEST_CATEGORY is very useful when multiple assertions do not have dependencies. /// During the execution of the test program, TEST_FILE, TEST_CATEGORY, TEST_CASE and failed TEST_ASSERT will be rendered with indentation and different colors. ///

///

/// is needed in the main function to execute test cases. /// TEST_PRINT could be used during test cases to print debug information to a command-line application. ///

///
/// class UnitTest { protected: static bool IsDebuggerAttached(); static int PrintUsages(); static int RunAndDisposeTests(Nullable option); public: UnitTest() = delete; enum class MessageKind { Info, Error, File, Category, Case, }; static void PrintMessage(const WString& string, MessageKind kind); /// Run all test cases. /// The return value for the main function. If any assertion fails, it is non-zero. /// Accept the first argument of the main function. /// Accept the second argument of the main function. static int RunAndDisposeTests(int argc, wchar_t* argv[]); /// Run all test cases. /// The return value for the main function. If any assertion fails, it is non-zero. /// Accept the first argument of the main function. /// Accept the second argument of the main function. static int RunAndDisposeTests(int argc, char* argv[]); static void RegisterTestFile(UnitTestLink* link); static void RunCategoryOrCase(const WString& description, bool isCategory, Func&& callback); static void EnsureLegalToAssert(); }; class UnitTestFile { protected: UnitTestLink link; public: UnitTestFile(const char* fileName, UnitTestFileProc testProc) { link.fileName = fileName; link.testProc = testProc; UnitTest::RegisterTestFile(&link); } }; 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); })\ } } #endif