#pragma once

/*
Referenced from libstdc++
https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/include/bits/move.h
*/
/*
C++ freestanding does not provide ::std::addressof, ::std::move and ::std::forward. We need to define them by ourselves.
*/

namespace fast_io::freestanding
{

template <typename T>
#if __has_cpp_attribute(__gnu__::__always_inline__)
[[__gnu__::__always_inline__]]
#elif __has_cpp_attribute(msvc::forceinline)
[[msvc::forceinline]]
#endif
[[nodiscard]] inline constexpr T *
addressof(T &r) noexcept
{
	return __builtin_addressof(r); // death to compilers which do not support __builtin_addressof
}

template <typename T>
T const *addressof(T const &&) = delete;

template <typename T>
#if __has_cpp_attribute(__gnu__::__always_inline__)
[[__gnu__::__always_inline__]]
#elif __has_cpp_attribute(msvc::forceinline)
[[msvc::forceinline]]
#endif
[[nodiscard]] inline constexpr T &&
forward(::std::remove_reference_t<T> &t) noexcept
{
	return static_cast<T &&>(t);
}

template <typename T>
#if __has_cpp_attribute(__gnu__::__always_inline__)
[[__gnu__::__always_inline__]]
#elif __has_cpp_attribute(msvc::forceinline)
[[msvc::forceinline]]
#endif
[[nodiscard]] inline constexpr typename ::std::remove_reference<T>::type &&
move(T &&t) noexcept
{
	return static_cast<typename ::std::remove_reference<T>::type &&>(t);
}

} // namespace fast_io::freestanding
