#pragma once #include // Needed for placement new/delete. #include #include #include #ifndef offsetof2 #define offsetof2(type, member) size_t(uintptr_t(&((type*)0)->member)) #endif namespace orange { template using Function = std::function; struct FalseType { static constexpr bool Value = false; }; struct TrueType { static constexpr bool Value = true; }; template struct IsLValueReference : FalseType {}; template struct IsLValueReference : TrueType {}; template struct RemoveReference_ { using Type = T; }; template struct RemoveReference_ { using Type = T; }; template struct RemoveReference_ { using Type = T; }; template using RemoveReference = typename RemoveReference_::Type; template constexpr T&& Forward(RemoveReference& t) { return static_cast(t); } template constexpr T&& Forward(RemoveReference&& t) { static_assert(!IsLValueReference::Value, "Can not forward an rvalue as an lvalue."); return static_cast(t); } template constexpr RemoveReference&& Move(T&& arg) { return static_cast&&>(arg); } template [[nodiscard]] constexpr ForwardIt MinElement(ForwardIt first, ForwardIt last) { if (first == last) return last; ForwardIt smallest = first; ++first; for (; first != last; ++first) { if (*first < *smallest) smallest = first; } return smallest; } template [[nodiscard]] constexpr ForwardIt MinElement(ForwardIt first, ForwardIt last, Compare comp) { if (first == last) return last; ForwardIt smallest = first; ++first; for (; first != last; ++first) { if (comp(*first, *smallest)) smallest = first; } return smallest; } template [[nodiscard]] constexpr ForwardIt MaxElement(ForwardIt first, ForwardIt last) { if (first == last) return last; ForwardIt largest = first; ++first; for (; first != last; ++first) { if (*largest < *first) largest = first; } return largest; } template [[nodiscard]] constexpr ForwardIt MaxElement(ForwardIt first, ForwardIt last, Compare comp) { if (first == last) return last; ForwardIt largest = first; ++first; for (; first != last; ++first) { if (comp(*largest, *first)) largest = first; } return largest; } template [[nodiscard]] constexpr size_t Size(const T (&array)[N]) noexcept { (void)array; return N; } template [[nodiscard]] constexpr T Min(const T& valMin, const T& valMax) { return valMin < valMax ? valMin : valMax; } template [[nodiscard]] constexpr T Min(std::initializer_list ilist) { return *MinElement(ilist.begin(), ilist.end()); } template [[nodiscard]] constexpr T Min(std::initializer_list ilist, Compare comp) { return *MinElement(ilist.begin(), ilist.end(), comp); } template [[nodiscard]] constexpr T Max(const T& valMin, const T& valMax) { return valMin > valMax ? valMin : valMax; } template [[nodiscard]] constexpr T Max(std::initializer_list ilist) { return *MaxElement(ilist.begin(), ilist.end()); } template [[nodiscard]] constexpr T Max(std::initializer_list ilist, Compare comp) { return *MaxElement(ilist.begin(), ilist.end(), comp); } template [[nodiscard]] constexpr T Clamp( const T& val, const T& minVal, const T& maxVal ) { return Min( Max( val, minVal ), maxVal ); } template [[nodiscard]] constexpr T Align(T what, U to) { return (what + to - 1) & ~(to - 1); } // Transformations namespace Util { template OutputIt Transform(InputIt inFirst, InputIt inLast, OutputIt outFirst, UnaryOperation unaryOp) { while (inFirst != inLast) *outFirst++ = unaryOp(*inFirst++); return outFirst; } template OutputIt Transform(InputIt1 first1, InputIt1 last1, InputIt2 first2, OutputIt outFirst, BinaryOperation binOp) { while (first1 != last1) *outFirst++ = binOp(*first1++, *first2++); return outFirst; } template T TransformResult(InputIt first, InputIt last, UnaryOperation op) { T result; Transform(first, last, result.begin(), op); return result; } template T TransformResult(InputIt1 first1, InputIt1 last1, InputIt2 first2, BinaryOperation op) { T result; Transform(first1, last1, first2, result.begin(), op); return result; } } template constexpr T Accumulate(InputIt first, InputIt last, T init) { for (; first != last; ++first) init = Move(init) + *first; return init; } template constexpr T Accumulate(InputIt first, InputIt last, T init, BinaryOperation op) { for (; first != last; ++first) init = op(Move(init), *first); return init; } template bool Equal(InputIt1 first1, InputIt1 last1, InputIt2 first2) { for (; first1 != last1; ++first1, ++first2) { if (!(*first1 == *first2)) return false; } return true; } template bool Equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, BinaryPredicate p) { for (; first1 != last1; ++first1, ++first2) { if (!p(*first1, *first2)) return false; } return true; } template OutputIt Copy(InputIt first, InputIt last, OutputIt d_first) { for (; first != last; (void)++first, (void)++d_first) *d_first = *first; return d_first; } template OutputIt CopyIf(InputIt first, InputIt last, OutputIt d_first, UnaryPredicate pred) { for (; first != last; ++first) { if (pred(*first)) { *d_first = *first; ++d_first; } } return d_first; } template void Fill(ForwardIt first, ForwardIt last, const T& value) { for (; first != last; ++first) *first = value; } // Math ops namespace Math { template T Negate(const T& x) { return -x; } template T Add (const T& x, const T& y) { return x + y; } template T Subtract (const T& x, const T& y) { return x - y; } template T Multiply (const T& x, const T& y) { return x * y; } template T Divide (const T& x, const T& y) { return x / y; } template T Modulo (const T& x, const T& y) { return x % y; } } }