From 5e64450bce5122d29e74919e936223e822c4b608 Mon Sep 17 00:00:00 2001 From: _Redstone_c_ Date: Sun, 19 Feb 2023 19:00:57 +0800 Subject: [PATCH] feat(containers): add TFunctionalOutputIterator and operations support --- .../Source/Public/Containers/Iterator.h | 126 ++++++++++++++++-- 1 file changed, 117 insertions(+), 9 deletions(-) diff --git a/Redcraft.Utility/Source/Public/Containers/Iterator.h b/Redcraft.Utility/Source/Public/Containers/Iterator.h index 99f3280..5ecd7f4 100644 --- a/Redcraft.Utility/Source/Public/Containers/Iterator.h +++ b/Redcraft.Utility/Source/Public/Containers/Iterator.h @@ -65,8 +65,8 @@ concept CIndirectlyWritable = { *Iter = Forward(A); *Forward(Iter) = Forward(A); - const_cast&&>(*Iter) = Forward(A); - const_cast&&>(*Forward(Iter)) = Forward(A); + const_cast&&>(*Iter) = Forward(A); + const_cast&&>(*Forward(Iter)) = Forward(A); }; template @@ -340,9 +340,9 @@ public: using ElementType = TIteratorElementType; # if DO_CHECK - FORCEINLINE constexpr TCountedIterator() requires CDefaultConstructible : Length(1), MaxLength(0) { }; + FORCEINLINE constexpr TCountedIterator() requires (CDefaultConstructible) : Length(1), MaxLength(0) { }; # else - FORCEINLINE constexpr TCountedIterator() requires CDefaultConstructible = default; + FORCEINLINE constexpr TCountedIterator() requires (CDefaultConstructible) = default; # endif FORCEINLINE constexpr TCountedIterator(const TCountedIterator&) = default; @@ -426,7 +426,7 @@ static_assert(CSizedSentinelFor>); template TCountedIterator(I, ptrdiff) -> TCountedIterator; -template requires (CReferenceable> && CBooleanTestable> && CMovable && CMovable) +template requires (CReferenceable> && CMovable && CMovable) class TFunctionalInputIterator final : private FNoncopyable { public: @@ -436,10 +436,7 @@ public: using ElementType = TRemoveReference>; - FORCEINLINE constexpr TFunctionalInputIterator() = default; - - FORCEINLINE constexpr TFunctionalInputIterator(TFunctionalInputIterator&&) = default; - FORCEINLINE constexpr TFunctionalInputIterator& operator=(TFunctionalInputIterator&&) = default; + FORCEINLINE constexpr TFunctionalInputIterator() requires (CDefaultConstructible && CDefaultConstructible) : bIsConsumed(false) { }; template requires (CConvertibleTo && CConvertibleTo) FORCEINLINE constexpr TFunctionalInputIterator(T&& InInputer, U&& InSentinel) : InputerStorage(Forward(InInputer)), SentinelStorage(Forward(InSentinel)), bIsConsumed(false) { } @@ -474,6 +471,117 @@ static_assert(CInputIterator>); template TFunctionalInputIterator(F, G) -> TFunctionalInputIterator; +template +class TFunctionalOutputIterator final : private FNoncopyable +{ +public: + + using Outputer = F; + +private: + + class FIndirectionProxy : private FSingleton + { + public: + + FORCEINLINE constexpr FIndirectionProxy(const TFunctionalOutputIterator& InIter) : Iter(InIter) { check_code({ bIsProduced = false; }); } + +# if DO_CHECK + FORCEINLINE ~FIndirectionProxy() + { + checkf(bIsProduced, TEXT("Exception output, Ensures that the value is assigned to the output iterator.")); + } +# endif + + template requires (CInvocable) + FORCEINLINE constexpr void operator=(T&& InValue) const + { + checkf(!bIsProduced, TEXT("Exception output, Ensure that no multiple values are assigned to the output iterator.")); + Invoke(Iter.OutputerStorage, Forward(InValue)); + check_code({ bIsProduced = true; }); + } + + private: + + const TFunctionalOutputIterator& Iter; + +# if DO_CHECK + mutable bool bIsProduced; +# endif + + }; + + class FPostIncrementProxy : private FSingleton + { + public: + + FORCEINLINE constexpr FPostIncrementProxy(const TFunctionalOutputIterator& InIter) : Iter(InIter) { check_code({ bIsProduced = false; }); } + +# if DO_CHECK + FORCEINLINE ~FPostIncrementProxy() + { + checkf(bIsProduced, TEXT("Exception output, Ensures that the value is assigned to the output iterator.")); + } +# endif + + NODISCARD FORCEINLINE constexpr FIndirectionProxy operator*() const + { + checkf(!bIsProduced, TEXT("Exception output, Ensure that no multiple values are assigned to the output iterator.")); + check_code({ bIsProduced = true; }); + return FIndirectionProxy(Iter); + } + + private: + + const TFunctionalOutputIterator& Iter; + +# if DO_CHECK + mutable bool bIsProduced; +# endif + + }; + +public: + + FORCEINLINE constexpr TFunctionalOutputIterator() requires (CDefaultConstructible) { check_code({ bIsProduced = false; }); } + + template requires (CConvertibleTo) + FORCEINLINE constexpr TFunctionalOutputIterator(T&& InOutputer) : OutputerStorage(Forward(InOutputer)) { check_code({ bIsProduced = false; }); } + + NODISCARD FORCEINLINE constexpr FIndirectionProxy operator*() const + { + checkf(!bIsProduced, TEXT("Exception output, Ensure that no multiple values are assigned to the output iterator.")); + check_code({ bIsProduced = true; }); + return FIndirectionProxy(*this); + } + + FORCEINLINE constexpr TFunctionalOutputIterator& operator++() { check_code({ bIsProduced = false; }); return *this; } + + FORCEINLINE constexpr FPostIncrementProxy operator++(int) + { + checkf(!bIsProduced, TEXT("Exception output, Ensure that no multiple values are assigned to the output iterator.")); + return FPostIncrementProxy(*this); + } + + NODISCARD FORCEINLINE constexpr const Outputer& GetOutputer() const& { return OutputerStorage; } + NODISCARD FORCEINLINE constexpr Outputer GetOutputer() && { return OutputerStorage; } + +private: + + Outputer OutputerStorage; + +# if DO_CHECK + mutable bool bIsProduced; +# endif + +}; + +static_assert(CIndirectlyWritable, int32>); +static_assert(COutputIterator, int32>); + +template +TFunctionalOutputIterator(F) -> TFunctionalOutputIterator; + NAMESPACE_BEGIN(Iteration) /** Increments given iterator 'Iter' by 'N' elements. */