// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_UTILITY_H_
#define CTL_UTILITY_H_
#include "remove_reference.h"

namespace ctl {

namespace __ {

template<typename T>
struct no_infer_
{
    typedef T type;
};

template<typename T>
using no_infer = typename no_infer_<T>::type;

} // namespace __

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

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

template<typename T>
constexpr T&&
forward(__::no_infer<T>& t) noexcept
{
    return static_cast<T&&>(t);
}

template<typename T>
// TODO(mrdomino): requires move_constructible<T> && move_assignable<T>
constexpr void
swap(T& a, T& b) noexcept
{
    T t(ctl::move(a));
    a = ctl::move(b);
    b = ctl::move(t);
}

template<typename T, size_t N>
// TODO(mrdomino): requires is_swappable
constexpr void
swap(T (&a)[N], T (&b)[N]) noexcept
{
    for (size_t i = 0; i < N; ++i)
        swap(a[i], b[i]);
}

template<typename T>
T&&
declval() noexcept;

} // namespace ctl

#endif // CTL_UTILITY_H_