/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <folly/Poly.h>
namespace folly {
namespace poly {
/**
* A `Poly` interface for types that are equality comparable.
*/
struct IEqualityComparable : PolyExtends<> {
template <class T>
static auto isEqual_(T const& _this, T const& that)
-> decltype(std::declval<bool (&)(bool)>()(_this == that)) {
return _this == that;
}
template <class T>
using Members = FOLLY_POLY_MEMBERS(&isEqual_<T>);
};
/**
* A `Poly` interface for types that are strictly orderable.
*/
struct IStrictlyOrderable : PolyExtends<> {
template <class T>
static auto isLess_(T const& _this, T const& that)
-> decltype(std::declval<bool (&)(bool)>()(_this < that)) {
return _this < that;
}
template <class T>
using Members = FOLLY_POLY_MEMBERS(&isLess_<T>);
};
} // namespace poly
/// \cond
namespace detail {
template <class I1, class I2>
using Comparable = Conjunction<
std::is_same<std::decay_t<I1>, std::decay_t<I2>>,
std::is_base_of<poly::IEqualityComparable, std::decay_t<I1>>>;
template <class I1, class I2>
using Orderable = Conjunction<
std::is_same<std::decay_t<I1>, std::decay_t<I2>>,
std::is_base_of<poly::IStrictlyOrderable, std::decay_t<I1>>>;
} // namespace detail
/// \endcond
template <
class I1,
class I2,
std::enable_if_t<detail::Comparable<I1, I2>::value, int> = 0>
bool operator==(Poly<I1> const& _this, Poly<I2> const& that) {
if (poly_empty(_this) != poly_empty(that)) {
return false;
} else if (poly_empty(_this)) {
return true;
} else if (poly_type(_this) != poly_type(that)) {
throw BadPolyCast();
}
return ::folly::poly_call<0, poly::IEqualityComparable>(_this, that);
}
template <
class I1,
class I2,
std::enable_if_t<detail::Comparable<I1, I2>::value, int> = 0>
bool operator!=(Poly<I1> const& _this, Poly<I2> const& that) {
return !(_this == that);
}
template <
class I1,
class I2,
std::enable_if_t<detail::Orderable<I1, I2>::value, int> = 0>
bool operator<(Poly<I1> const& _this, Poly<I2> const& that) {
if (poly_empty(that)) {
return false;
} else if (poly_empty(_this)) {
return true;
} else if (poly_type(_this) != poly_type(that)) {
throw BadPolyCast{};
}
return ::folly::poly_call<0, poly::IStrictlyOrderable>(_this, that);
}
template <
class I1,
class I2,
std::enable_if_t<detail::Orderable<I1, I2>::value, int> = 0>
bool operator>(Poly<I1> const& _this, Poly<I2> const& that) {
return that < _this;
}
template <
class I1,
class I2,
std::enable_if_t<detail::Orderable<I1, I2>::value, int> = 0>
bool operator<=(Poly<I1> const& _this, Poly<I2> const& that) {
return !(that < _this);
}
template <
class I1,
class I2,
std::enable_if_t<detail::Orderable<I1, I2>::value, int> = 0>
bool operator>=(Poly<I1> const& _this, Poly<I2> const& that) {
return !(_this < that);
}
namespace poly {
/**
* A `Poly` interface for types that are move-only.
*/
struct IMoveOnly : PolyExtends<> {
template <class Base>
struct Interface : Base {
Interface() = default;
Interface(Interface const&) = delete;
Interface(Interface&&) = default;
Interface& operator=(Interface const&) = delete;
Interface& operator=(Interface&&) = default;
using Base::Base;
};
};
/**
* A `Poly` interface for types that are copyable and movable.
*/
struct ISemiRegular : PolyExtends<> {};
/**
* A `Poly` interface for types that are copyable, movable, and equality
* comparable.
*/
struct IRegular : PolyExtends<ISemiRegular, IEqualityComparable> {};
} // namespace poly
} // namespace folly