#pragma once #include "CoreTypes.h" #include "Ranges/View.h" #include "Ranges/Utility.h" #include "Ranges/AllView.h" #include "Templates/Utility.h" #include "Ranges/TransformView.h" #include "TypeTraits/TypeTraits.h" NAMESPACE_REDCRAFT_BEGIN NAMESPACE_MODULE_BEGIN(Redcraft) NAMESPACE_MODULE_BEGIN(Utility) // NOTE: In the STL, use std::from_range_t as a disambiguation tag that resolves ambiguity // introduced by the list-initialization. For example, for the following code: // // R RangeOfInts = /* ... */; // static_assert(CRange and CSameAs, int>); // // TArray Arr(RangeOfInts); // TArray Brr{RangeOfInts}; // // If R is TArray than decltype(Arr) is TArray and decltype(Brr) is TArray, // otherwise, decltype(Arr) is TArray and decltype(Brr) is TArray. // // But Redcraft can't use the std::from_range_t tag because list-initialization is discouraged. /** A concept specifies a container that can reserve size. */ template concept CReservableContainer = CSizedRange && requires (C& Container, size_t N) { Container.Reserve(N); { Container.Max() } -> CSameAs; }; /** A concept specifies a container that can append elements. */ template concept CAppendableContainer = requires (C& Container, Ref&& Reference) { requires ( requires { Container.EmplaceBack (Forward(Reference)); } || requires { Container.PushBack (Forward(Reference)); } || requires { Container.Emplace(Container.End(), Forward(Reference)); } || requires { Container.Insert (Container.End(), Forward(Reference)); } ); }; NAMESPACE_BEGIN(Range) /** Constructs a non-view object from the elements of the range. */ template requires (!CView) NODISCARD FORCEINLINE constexpr auto To(R&& Range, Ts&&... Args) { if constexpr (!CInputRange || CConvertibleTo, TRangeElement>) { if constexpr (CConstructibleFrom) { return C(Forward(Range), Forward(Args)...); } else if constexpr (CCommonRange && CInputRange && CConstructibleFrom, TRangeSentinel, Ts...>) { return C(Range::Begin(Range), Range::End(Range), Forward(Args)...); } else if constexpr (CConstructibleFrom && CAppendableContainer>) { C Result(Forward(Args)...); if constexpr (CSizedRange && CReservableContainer) { Result.Reserve(Range::Num(Range)); } for (TRangeReference Element : Range) { if constexpr (requires { Result.EmplaceBack(DeclVal>()); }) { Result.EmplaceBack(Forward>(Element)); } else if constexpr (requires { Result.PushBack(DeclVal>()); }) { Result.PushBack(Forward>(Element)); } else if constexpr (requires { Result.Emplace(Result.End(), DeclVal>()); }) { Result.Emplace(Result.End(), Forward>(Element)); } else /* if constexpr (requires { Result.Insert(Result.End(), DeclVal>()); }) */ { Result.Insert(Result.End(), Forward>(Element)); } } return Result; } else static_assert(sizeof(R) == -1, "The container type is not constructible from a range"); } else { if constexpr (CInputRange>) { return Range::To(Range::All(Range) | Range::Transform([](T&& Element) { return Range::To>(Forward(Element)); }), Forward(Args)...); } else static_assert(sizeof(R) == -1, "The container type is not constructible from a range"); } } /** Constructs a non-view object from the elements of the range. */ template