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