//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___UTILITY_DEFAULT_THREE_WAY_COMPARATOR_H
#define _LIBCPP___UTILITY_DEFAULT_THREE_WAY_COMPARATOR_H

#include <__config>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_arithmetic.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#  pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

// This struct can be specialized to provide a three way comparator between _LHS and _RHS.
// The return value should be
// - less than zero if (lhs_val < rhs_val)
// - greater than zero if (rhs_val < lhs_val)
// - zero otherwise
template <class _LHS, class _RHS, class = void>
struct __default_three_way_comparator;

template <class _LHS, class _RHS>
struct __default_three_way_comparator<_LHS,
                                      _RHS,
                                      __enable_if_t<is_arithmetic<_LHS>::value && is_arithmetic<_RHS>::value> > {
  _LIBCPP_HIDE_FROM_ABI static int operator()(_LHS __lhs, _RHS __rhs) {
    if (__lhs < __rhs)
      return -1;
    if (__lhs > __rhs)
      return 1;
    return 0;
  }
};

#if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_lt_synthesizes_from_spaceship)
template <class _LHS, class _RHS>
struct __default_three_way_comparator<
    _LHS,
    _RHS,
    __enable_if_t<!(is_arithmetic<_LHS>::value && is_arithmetic<_RHS>::value) &&
                  __builtin_lt_synthesizes_from_spaceship(const _LHS&, const _RHS&)>> {
  _LIBCPP_HIDE_FROM_ABI static int operator()(const _LHS& __lhs, const _RHS& __rhs) {
    auto __res = __lhs <=> __rhs;
    if (__res < 0)
      return -1;
    if (__res > 0)
      return 1;
    return 0;
  }
};
#endif

template <class _LHS, class _RHS, bool = true>
struct __has_default_three_way_comparator : false_type {};

template <class _LHS, class _RHS>
struct __has_default_three_way_comparator<_LHS, _RHS, sizeof(__default_three_way_comparator<_LHS, _RHS>) >= 0>
    : true_type {};

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___UTILITY_DEFAULT_THREE_WAY_COMPARATOR_H
