Orange/include/Orange/Core/Traits.h

283 lines
8.2 KiB
C++

#pragma once
#include <Orange/Core/Types.h>
// Needed for placement new/delete.
#include <new>
#include <initializer_list>
#include <functional>
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; }
}
}