tvl-depot/absl/types/compare.h
Abseil Team 0e7afdcbd2 Export of internal Abseil changes
--
62058c9c008e23c787f35c1a5fe05851046a71f1 by Abseil Team <absl-team@google.com>:

Fix some strange usage of INSTANTIATE_TEST_SUITE_P

PiperOrigin-RevId: 264185105

--
4400d84027d86415a2f9b81996ff22e7fd7aa30f by Derek Mauro <dmauro@google.com>:

Disable testing std::string_view from nullptr on GCC >= GCC9.

PiperOrigin-RevId: 264150587

--
656d5a742ba48d025589709fad33ddae4b02c620 by Matt Calabrese <calabrese@google.com>:

Fix `absl::any_cast` such that it properly works with qualifications.

PiperOrigin-RevId: 263843429

--
6ec89214a4ef2170bf069623a56ffd22863b748d by Abseil Team <absl-team@google.com>:

Use macros to enable inline constexpr variables in compare.h when the compiler supports the feature.

PiperOrigin-RevId: 263790677

--
a5171e0897195a0367fc08abce9504f813d027ff by Derek Mauro <dmauro@google.com>:

Add the Apache License to files that are missing it.

PiperOrigin-RevId: 263774164

--
19e09a7ce8a0aac0a7d534e1799e4d73b63a1bb5 by Abseil Team <absl-team@google.com>:

Update iter.position when moving up the tree in rebalance_after_delete.

This field isn't read after the first iteration in rebalance_after_delete, and I think it's not a correctness issue, but it is read in try_merge_or_rebalance and potentially affects rebalancing decisions so it can affect performance. There's also an extremely unlikely potential for undefined behavior due to signed integer overflow since this field is only ever incremented in try_merge_or_rebalance (and position is an int). Basically though, I just don't think it makes sense to have this invalid iterator floating around here.

PiperOrigin-RevId: 263770305
GitOrigin-RevId: 62058c9c008e23c787f35c1a5fe05851046a71f1
Change-Id: I1e2fb7cbfac7507dddedd181414ee35a5778f8f5
2019-08-19 15:34:07 -04:00

556 lines
21 KiB
C++

// Copyright 2018 The Abseil Authors.
//
// 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
//
// https://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.
//
// -----------------------------------------------------------------------------
// compare.h
// -----------------------------------------------------------------------------
//
// This header file defines the `absl::weak_equality`, `absl::strong_equality`,
// `absl::partial_ordering`, `absl::weak_ordering`, and `absl::strong_ordering`
// types for storing the results of three way comparisons.
//
// Example:
// absl::weak_ordering compare(const std::string& a, const std::string& b);
//
// These are C++11 compatible versions of the C++20 corresponding types
// (`std::weak_equality`, etc.) and are designed to be drop-in replacements
// for code compliant with C++20.
#ifndef ABSL_TYPES_COMPARE_H_
#define ABSL_TYPES_COMPARE_H_
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <type_traits>
#include "absl/base/attributes.h"
#include "absl/meta/type_traits.h"
namespace absl {
namespace compare_internal {
using value_type = int8_t;
template <typename T>
struct Fail {
static_assert(sizeof(T) < 0, "Only literal `0` is allowed.");
};
// We need the NullPtrT template to avoid triggering the modernize-use-nullptr
// ClangTidy warning in user code.
template <typename NullPtrT = std::nullptr_t>
struct OnlyLiteralZero {
constexpr OnlyLiteralZero(NullPtrT) noexcept {} // NOLINT
// Fails compilation when `nullptr` or integral type arguments other than
// `int` are passed. This constructor doesn't accept `int` because literal `0`
// has type `int`. Literal `0` arguments will be implicitly converted to
// `std::nullptr_t` and accepted by the above constructor, while other `int`
// arguments will fail to be converted and cause compilation failure.
template <
typename T,
typename = typename std::enable_if<
std::is_same<T, std::nullptr_t>::value ||
(std::is_integral<T>::value && !std::is_same<T, int>::value)>::type,
typename = typename Fail<T>::type>
OnlyLiteralZero(T); // NOLINT
};
enum class eq : value_type {
equal = 0,
equivalent = equal,
nonequal = 1,
nonequivalent = nonequal,
};
enum class ord : value_type { less = -1, greater = 1 };
enum class ncmp : value_type { unordered = -127 };
// Define macros to allow for creation or emulation of C++17 inline variables
// based on whether the feature is supported. Note: we can't use
// ABSL_INTERNAL_INLINE_CONSTEXPR here because the variables here are of
// incomplete types so they need to be defined after the types are complete.
#ifdef __cpp_inline_variables
#define ABSL_COMPARE_INLINE_BASECLASS_DECL(name)
#define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) \
static const type name
#define ABSL_COMPARE_INLINE_INIT(type, name, init) \
inline constexpr type type::name(init)
#else // __cpp_inline_variables
#define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) \
ABSL_CONST_INIT static const T name
#define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name)
#define ABSL_COMPARE_INLINE_INIT(type, name, init) \
template <typename T> \
const T compare_internal::type##_base<T>::name(init)
#endif // __cpp_inline_variables
// These template base classes allow for defining the values of the constants
// in the header file (for performance) without using inline variables (which
// aren't available in C++11).
template <typename T>
struct weak_equality_base {
ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequivalent);
};
template <typename T>
struct strong_equality_base {
ABSL_COMPARE_INLINE_BASECLASS_DECL(equal);
ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequal);
ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequivalent);
};
template <typename T>
struct partial_ordering_base {
ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
ABSL_COMPARE_INLINE_BASECLASS_DECL(unordered);
};
template <typename T>
struct weak_ordering_base {
ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
};
template <typename T>
struct strong_ordering_base {
ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
ABSL_COMPARE_INLINE_BASECLASS_DECL(equal);
ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
};
} // namespace compare_internal
class weak_equality
: public compare_internal::weak_equality_base<weak_equality> {
explicit constexpr weak_equality(compare_internal::eq v) noexcept
: value_(static_cast<compare_internal::value_type>(v)) {}
friend struct compare_internal::weak_equality_base<weak_equality>;
public:
ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_equality, equivalent);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_equality, nonequivalent);
// Comparisons
friend constexpr bool operator==(
weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ == 0;
}
friend constexpr bool operator!=(
weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ != 0;
}
friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
weak_equality v) noexcept {
return 0 == v.value_;
}
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
weak_equality v) noexcept {
return 0 != v.value_;
}
private:
compare_internal::value_type value_;
};
ABSL_COMPARE_INLINE_INIT(weak_equality, equivalent,
compare_internal::eq::equivalent);
ABSL_COMPARE_INLINE_INIT(weak_equality, nonequivalent,
compare_internal::eq::nonequivalent);
class strong_equality
: public compare_internal::strong_equality_base<strong_equality> {
explicit constexpr strong_equality(compare_internal::eq v) noexcept
: value_(static_cast<compare_internal::value_type>(v)) {}
friend struct compare_internal::strong_equality_base<strong_equality>;
public:
ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, equal);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, nonequal);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, equivalent);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, nonequivalent);
// Conversion
constexpr operator weak_equality() const noexcept { // NOLINT
return value_ == 0 ? weak_equality::equivalent
: weak_equality::nonequivalent;
}
// Comparisons
friend constexpr bool operator==(
strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ == 0;
}
friend constexpr bool operator!=(
strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ != 0;
}
friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
strong_equality v) noexcept {
return 0 == v.value_;
}
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
strong_equality v) noexcept {
return 0 != v.value_;
}
private:
compare_internal::value_type value_;
};
ABSL_COMPARE_INLINE_INIT(strong_equality, equal, compare_internal::eq::equal);
ABSL_COMPARE_INLINE_INIT(strong_equality, nonequal,
compare_internal::eq::nonequal);
ABSL_COMPARE_INLINE_INIT(strong_equality, equivalent,
compare_internal::eq::equivalent);
ABSL_COMPARE_INLINE_INIT(strong_equality, nonequivalent,
compare_internal::eq::nonequivalent);
class partial_ordering
: public compare_internal::partial_ordering_base<partial_ordering> {
explicit constexpr partial_ordering(compare_internal::eq v) noexcept
: value_(static_cast<compare_internal::value_type>(v)) {}
explicit constexpr partial_ordering(compare_internal::ord v) noexcept
: value_(static_cast<compare_internal::value_type>(v)) {}
explicit constexpr partial_ordering(compare_internal::ncmp v) noexcept
: value_(static_cast<compare_internal::value_type>(v)) {}
friend struct compare_internal::partial_ordering_base<partial_ordering>;
constexpr bool is_ordered() const noexcept {
return value_ !=
compare_internal::value_type(compare_internal::ncmp::unordered);
}
public:
ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, less);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, equivalent);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, greater);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, unordered);
// Conversion
constexpr operator weak_equality() const noexcept { // NOLINT
return value_ == 0 ? weak_equality::equivalent
: weak_equality::nonequivalent;
}
// Comparisons
friend constexpr bool operator==(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.is_ordered() && v.value_ == 0;
}
friend constexpr bool operator!=(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return !v.is_ordered() || v.value_ != 0;
}
friend constexpr bool operator<(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.is_ordered() && v.value_ < 0;
}
friend constexpr bool operator<=(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.is_ordered() && v.value_ <= 0;
}
friend constexpr bool operator>(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.is_ordered() && v.value_ > 0;
}
friend constexpr bool operator>=(
partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.is_ordered() && v.value_ >= 0;
}
friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
partial_ordering v) noexcept {
return v.is_ordered() && 0 == v.value_;
}
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
partial_ordering v) noexcept {
return !v.is_ordered() || 0 != v.value_;
}
friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
partial_ordering v) noexcept {
return v.is_ordered() && 0 < v.value_;
}
friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
partial_ordering v) noexcept {
return v.is_ordered() && 0 <= v.value_;
}
friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
partial_ordering v) noexcept {
return v.is_ordered() && 0 > v.value_;
}
friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
partial_ordering v) noexcept {
return v.is_ordered() && 0 >= v.value_;
}
private:
compare_internal::value_type value_;
};
ABSL_COMPARE_INLINE_INIT(partial_ordering, less, compare_internal::ord::less);
ABSL_COMPARE_INLINE_INIT(partial_ordering, equivalent,
compare_internal::eq::equivalent);
ABSL_COMPARE_INLINE_INIT(partial_ordering, greater,
compare_internal::ord::greater);
ABSL_COMPARE_INLINE_INIT(partial_ordering, unordered,
compare_internal::ncmp::unordered);
class weak_ordering
: public compare_internal::weak_ordering_base<weak_ordering> {
explicit constexpr weak_ordering(compare_internal::eq v) noexcept
: value_(static_cast<compare_internal::value_type>(v)) {}
explicit constexpr weak_ordering(compare_internal::ord v) noexcept
: value_(static_cast<compare_internal::value_type>(v)) {}
friend struct compare_internal::weak_ordering_base<weak_ordering>;
public:
ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, less);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, equivalent);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, greater);
// Conversions
constexpr operator weak_equality() const noexcept { // NOLINT
return value_ == 0 ? weak_equality::equivalent
: weak_equality::nonequivalent;
}
constexpr operator partial_ordering() const noexcept { // NOLINT
return value_ == 0 ? partial_ordering::equivalent
: (value_ < 0 ? partial_ordering::less
: partial_ordering::greater);
}
// Comparisons
friend constexpr bool operator==(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ == 0;
}
friend constexpr bool operator!=(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ != 0;
}
friend constexpr bool operator<(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ < 0;
}
friend constexpr bool operator<=(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ <= 0;
}
friend constexpr bool operator>(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ > 0;
}
friend constexpr bool operator>=(
weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ >= 0;
}
friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
weak_ordering v) noexcept {
return 0 == v.value_;
}
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
weak_ordering v) noexcept {
return 0 != v.value_;
}
friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
weak_ordering v) noexcept {
return 0 < v.value_;
}
friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
weak_ordering v) noexcept {
return 0 <= v.value_;
}
friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
weak_ordering v) noexcept {
return 0 > v.value_;
}
friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
weak_ordering v) noexcept {
return 0 >= v.value_;
}
private:
compare_internal::value_type value_;
};
ABSL_COMPARE_INLINE_INIT(weak_ordering, less, compare_internal::ord::less);
ABSL_COMPARE_INLINE_INIT(weak_ordering, equivalent,
compare_internal::eq::equivalent);
ABSL_COMPARE_INLINE_INIT(weak_ordering, greater,
compare_internal::ord::greater);
class strong_ordering
: public compare_internal::strong_ordering_base<strong_ordering> {
explicit constexpr strong_ordering(compare_internal::eq v) noexcept
: value_(static_cast<compare_internal::value_type>(v)) {}
explicit constexpr strong_ordering(compare_internal::ord v) noexcept
: value_(static_cast<compare_internal::value_type>(v)) {}
friend struct compare_internal::strong_ordering_base<strong_ordering>;
public:
ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, less);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equal);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equivalent);
ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, greater);
// Conversions
constexpr operator weak_equality() const noexcept { // NOLINT
return value_ == 0 ? weak_equality::equivalent
: weak_equality::nonequivalent;
}
constexpr operator strong_equality() const noexcept { // NOLINT
return value_ == 0 ? strong_equality::equal : strong_equality::nonequal;
}
constexpr operator partial_ordering() const noexcept { // NOLINT
return value_ == 0 ? partial_ordering::equivalent
: (value_ < 0 ? partial_ordering::less
: partial_ordering::greater);
}
constexpr operator weak_ordering() const noexcept { // NOLINT
return value_ == 0
? weak_ordering::equivalent
: (value_ < 0 ? weak_ordering::less : weak_ordering::greater);
}
// Comparisons
friend constexpr bool operator==(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ == 0;
}
friend constexpr bool operator!=(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ != 0;
}
friend constexpr bool operator<(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ < 0;
}
friend constexpr bool operator<=(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ <= 0;
}
friend constexpr bool operator>(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ > 0;
}
friend constexpr bool operator>=(
strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
return v.value_ >= 0;
}
friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
strong_ordering v) noexcept {
return 0 == v.value_;
}
friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
strong_ordering v) noexcept {
return 0 != v.value_;
}
friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
strong_ordering v) noexcept {
return 0 < v.value_;
}
friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
strong_ordering v) noexcept {
return 0 <= v.value_;
}
friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
strong_ordering v) noexcept {
return 0 > v.value_;
}
friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
strong_ordering v) noexcept {
return 0 >= v.value_;
}
private:
compare_internal::value_type value_;
};
ABSL_COMPARE_INLINE_INIT(strong_ordering, less, compare_internal::ord::less);
ABSL_COMPARE_INLINE_INIT(strong_ordering, equal, compare_internal::eq::equal);
ABSL_COMPARE_INLINE_INIT(strong_ordering, equivalent,
compare_internal::eq::equivalent);
ABSL_COMPARE_INLINE_INIT(strong_ordering, greater,
compare_internal::ord::greater);
#undef ABSL_COMPARE_INLINE_BASECLASS_DECL
#undef ABSL_COMPARE_INLINE_SUBCLASS_DECL
#undef ABSL_COMPARE_INLINE_INIT
namespace compare_internal {
// We also provide these comparator adapter functions for internal absl use.
// Helper functions to do a boolean comparison of two keys given a boolean
// or three-way comparator.
// SFINAE prevents implicit conversions to bool (such as from int).
template <typename Bool,
absl::enable_if_t<std::is_same<bool, Bool>::value, int> = 0>
constexpr bool compare_result_as_less_than(const Bool r) { return r; }
constexpr bool compare_result_as_less_than(const absl::weak_ordering r) {
return r < 0;
}
template <typename Compare, typename K, typename LK>
constexpr bool do_less_than_comparison(const Compare &compare, const K &x,
const LK &y) {
return compare_result_as_less_than(compare(x, y));
}
// Helper functions to do a three-way comparison of two keys given a boolean or
// three-way comparator.
// SFINAE prevents implicit conversions to int (such as from bool).
template <typename Int,
absl::enable_if_t<std::is_same<int, Int>::value, int> = 0>
constexpr absl::weak_ordering compare_result_as_ordering(const Int c) {
return c < 0 ? absl::weak_ordering::less
: c == 0 ? absl::weak_ordering::equivalent
: absl::weak_ordering::greater;
}
constexpr absl::weak_ordering compare_result_as_ordering(
const absl::weak_ordering c) {
return c;
}
template <
typename Compare, typename K, typename LK,
absl::enable_if_t<!std::is_same<bool, absl::result_of_t<Compare(
const K &, const LK &)>>::value,
int> = 0>
constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
const K &x, const LK &y) {
return compare_result_as_ordering(compare(x, y));
}
template <
typename Compare, typename K, typename LK,
absl::enable_if_t<std::is_same<bool, absl::result_of_t<Compare(
const K &, const LK &)>>::value,
int> = 0>
constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
const K &x, const LK &y) {
return compare(x, y) ? absl::weak_ordering::less
: compare(y, x) ? absl::weak_ordering::greater
: absl::weak_ordering::equivalent;
}
} // namespace compare_internal
} // namespace absl
#endif // ABSL_TYPES_COMPARE_H_