/*
 * Copyright 2015 - 2025 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#if __has_include(<utility>)
#include <utility>
#include "typetraits.hpp"
#else
#include "typetraits.hpp"
namespace std {

template<typename T>
constexpr ox::remove_reference_t<T> &&move(T &&t) noexcept {
	return static_cast<ox::remove_reference_t<T>&&>(t);
}

template<typename T>
constexpr void swap(T &a, T &b) noexcept {
	auto temp = std::move(a);
	a = std::move(b);
	b = std::move(temp);
}

template<typename T, typename U>
constexpr bool cmp_equal(T const t, U const u) noexcept {
	if constexpr(ox::is_signed_v<T> == ox::is_signed_v<U>) {
		return t == u;
	} else if constexpr(ox::is_signed_v<T>) {
		return t >= 0 && static_cast<ox::Unsigned<T>>(t) == u;
	} else {
		return u >= 0 && t == static_cast<ox::Unsigned<U>>(u);
	}
}

template<typename T, typename U>
constexpr bool cmp_less(T const t, U const u) noexcept {
	if constexpr(ox::is_signed_v<T> == ox::is_signed_v<U>) {
		return t < u;
	} else if constexpr(ox::is_signed_v<T>) {
		return t < 0 || static_cast<ox::Unsigned<T>>(t) < u;
	} else {
		return u >= 0 && t < static_cast<ox::Unsigned<U>>(u);
	}
}

template<typename T, typename U>
constexpr bool cmp_not_equal(T const t, U const u) noexcept {
	return !std::cmp_equal(t, u);
}

template<typename T, typename U>
constexpr bool cmp_greater(T const t, U const u) noexcept {
	return std::cmp_less(u, t);
}

template<typename T, typename U>
constexpr bool cmp_less_equal(T const t, U const u) noexcept {
	return !std::cmp_less(u, t);
}

template<typename T, typename U>
constexpr bool cmp_greater_equal(T const t, U const u) noexcept {
	return !std::cmp_less(t, u);
}

static_assert(cmp_less(-1, 5u));
static_assert(!cmp_less(5u, -1));
static_assert(cmp_equal(5u, 5));
static_assert(cmp_equal(5, 5u));
static_assert(!cmp_equal(-5, 5u));
static_assert(!cmp_equal(4u, 5u));

}
#endif

namespace ox {

struct in_place_t {
	explicit constexpr in_place_t() = default;
};

inline constexpr ox::in_place_t in_place;

template<class T>
constexpr T &&forward(remove_reference_t<T> &t) noexcept {
	return static_cast<T&&>(t);
}

template<class T>
constexpr T &&forward(remove_reference_t<T> &&t) noexcept {
	return static_cast<T&&>(t);
}

}

