Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,7 @@ set(files
__utility/cmp.h
__utility/convert_to_integral.h
__utility/declval.h
__utility/default_three_way_comparator.h
__utility/element_count.h
__utility/empty.h
__utility/exception_guard.h
Expand All @@ -921,6 +922,7 @@ set(files
__utility/integer_sequence.h
__utility/is_pointer_in_range.h
__utility/is_valid_range.h
__utility/lazy_synth_three_way_comparator.h
__utility/move.h
__utility/no_destroy.h
__utility/pair.h
Expand Down
7 changes: 7 additions & 0 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,13 @@ typedef __char32_t char32_t;
# define _LIBCPP_LIFETIMEBOUND
# endif

// This is to work around https://llvm.org/PR156809
# ifndef _LIBCPP_CXX03_LANG
# define _LIBCPP_CTOR_LIFETIMEBOUND _LIBCPP_LIFETIMEBOUND
# else
# define _LIBCPP_CTOR_LIFETIMEBOUND
# endif

# if __has_cpp_attribute(_Clang::__noescape__)
# define _LIBCPP_NOESCAPE [[_Clang::__noescape__]]
# else
Expand Down
49 changes: 33 additions & 16 deletions libcxx/include/__tree
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <__type_traits/is_swappable.h>
#include <__type_traits/remove_const.h>
#include <__utility/forward.h>
#include <__utility/lazy_synth_three_way_comparator.h>
#include <__utility/move.h>
#include <__utility/pair.h>
#include <__utility/swap.h>
Expand Down Expand Up @@ -1749,14 +1750,18 @@ __tree<_Tp, _Compare, _Allocator>::__find_equal(const _Key& __v) {
}

__node_base_pointer* __node_ptr = __root_ptr();
auto __comp = __lazy_synth_three_way_comparator<_Compare, _Key, value_type>(value_comp());

while (true) {
if (value_comp()(__v, __nd->__get_value())) {
auto __comp_res = __comp(__v, __nd->__get_value());

if (__comp_res.__less()) {
if (__nd->__left_ == nullptr)
return _Pair(static_cast<__end_node_pointer>(__nd), __nd->__left_);

__node_ptr = std::addressof(__nd->__left_);
__nd = static_cast<__node_pointer>(__nd->__left_);
} else if (value_comp()(__nd->__get_value(), __v)) {
} else if (__comp_res.__greater()) {
if (__nd->__right_ == nullptr)
return _Pair(static_cast<__end_node_pointer>(__nd), __nd->__right_);

Expand Down Expand Up @@ -2065,10 +2070,12 @@ template <class _Key>
typename __tree<_Tp, _Compare, _Allocator>::size_type
__tree<_Tp, _Compare, _Allocator>::__count_unique(const _Key& __k) const {
__node_pointer __rt = __root();
auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp());
while (__rt != nullptr) {
if (value_comp()(__k, __rt->__get_value())) {
auto __comp_res = __comp(__k, __rt->__get_value());
if (__comp_res.__less()) {
__rt = static_cast<__node_pointer>(__rt->__left_);
} else if (value_comp()(__rt->__get_value(), __k))
} else if (__comp_res.__greater())
__rt = static_cast<__node_pointer>(__rt->__right_);
else
return 1;
Expand All @@ -2082,11 +2089,13 @@ typename __tree<_Tp, _Compare, _Allocator>::size_type
__tree<_Tp, _Compare, _Allocator>::__count_multi(const _Key& __k) const {
__end_node_pointer __result = __end_node();
__node_pointer __rt = __root();
auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp());
while (__rt != nullptr) {
if (value_comp()(__k, __rt->__get_value())) {
auto __comp_res = __comp(__k, __rt->__get_value());
if (__comp_res.__less()) {
__result = static_cast<__end_node_pointer>(__rt);
__rt = static_cast<__node_pointer>(__rt->__left_);
} else if (value_comp()(__rt->__get_value(), __k))
} else if (__comp_res.__greater())
__rt = static_cast<__node_pointer>(__rt->__right_);
else
return std::distance(
Expand Down Expand Up @@ -2159,11 +2168,13 @@ __tree<_Tp, _Compare, _Allocator>::__equal_range_unique(const _Key& __k) {
using _Pp = pair<iterator, iterator>;
__end_node_pointer __result = __end_node();
__node_pointer __rt = __root();
auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp());
while (__rt != nullptr) {
if (value_comp()(__k, __rt->__get_value())) {
auto __comp_res = __comp(__k, __rt->__get_value());
if (__comp_res.__less()) {
__result = static_cast<__end_node_pointer>(__rt);
__rt = static_cast<__node_pointer>(__rt->__left_);
} else if (value_comp()(__rt->__get_value(), __k))
} else if (__comp_res.__greater())
__rt = static_cast<__node_pointer>(__rt->__right_);
else
return _Pp(iterator(__rt),
Expand All @@ -2181,11 +2192,13 @@ __tree<_Tp, _Compare, _Allocator>::__equal_range_unique(const _Key& __k) const {
using _Pp = pair<const_iterator, const_iterator>;
__end_node_pointer __result = __end_node();
__node_pointer __rt = __root();
auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp());
while (__rt != nullptr) {
if (value_comp()(__k, __rt->__get_value())) {
auto __comp_res = __comp(__k, __rt->__get_value());
if (__comp_res.__less()) {
__result = static_cast<__end_node_pointer>(__rt);
__rt = static_cast<__node_pointer>(__rt->__left_);
} else if (value_comp()(__rt->__get_value(), __k))
} else if (__comp_res.__greater())
__rt = static_cast<__node_pointer>(__rt->__right_);
else
return _Pp(
Expand All @@ -2202,12 +2215,14 @@ pair<typename __tree<_Tp, _Compare, _Allocator>::iterator, typename __tree<_Tp,
__tree<_Tp, _Compare, _Allocator>::__equal_range_multi(const _Key& __k) {
using _Pp = pair<iterator, iterator>;
__end_node_pointer __result = __end_node();
__node_pointer __rt = __root();
__node_pointer __rt = __root();
auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp());
while (__rt != nullptr) {
if (value_comp()(__k, __rt->__get_value())) {
auto __comp_res = __comp(__k, __rt->__get_value());
if (__comp_res.__less()) {
__result = static_cast<__end_node_pointer>(__rt);
__rt = static_cast<__node_pointer>(__rt->__left_);
} else if (value_comp()(__rt->__get_value(), __k))
} else if (__comp_res.__greater())
__rt = static_cast<__node_pointer>(__rt->__right_);
else
return _Pp(__lower_bound(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
Expand All @@ -2223,12 +2238,14 @@ pair<typename __tree<_Tp, _Compare, _Allocator>::const_iterator,
__tree<_Tp, _Compare, _Allocator>::__equal_range_multi(const _Key& __k) const {
using _Pp = pair<const_iterator, const_iterator>;
__end_node_pointer __result = __end_node();
__node_pointer __rt = __root();
__node_pointer __rt = __root();
auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp());
while (__rt != nullptr) {
if (value_comp()(__k, __rt->__get_value())) {
auto __comp_res = __comp(__k, __rt->__get_value());
if (__comp_res.__less()) {
__result = static_cast<__end_node_pointer>(__rt);
__rt = static_cast<__node_pointer>(__rt->__left_);
} else if (value_comp()(__rt->__get_value(), __k))
} else if (__comp_res.__greater())
__rt = static_cast<__node_pointer>(__rt->__right_);
else
return _Pp(__lower_bound(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
Expand Down
50 changes: 50 additions & 0 deletions libcxx/include/__utility/default_three_way_comparator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// 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 _Tp>
struct __default_three_way_comparator<_Tp, _Tp, __enable_if_t<is_arithmetic<_Tp>::value> > {
_LIBCPP_HIDE_FROM_ABI static int operator()(_Tp __lhs, _Tp __rhs) {
if (__lhs < __rhs)
return -1;
if (__lhs > __rhs)
return 1;
return 0;
}
};

template <class _LHS, class _RHS, bool = true>
inline const bool __has_default_three_way_comparator_v = false;

template <class _LHS, class _RHS>
inline const bool
__has_default_three_way_comparator_v< _LHS, _RHS, sizeof(__default_three_way_comparator<_LHS, _RHS>) >= 0> = true;

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___UTILITY_DEFAULT_THREE_WAY_COMPARATOR_H
90 changes: 90 additions & 0 deletions libcxx/include/__utility/lazy_synth_three_way_comparator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//===----------------------------------------------------------------------===//
//
// 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_LAZY_SYNTH_THREE_WAY_COMPARATOR_H
#define _LIBCPP___UTILITY_LAZY_SYNTH_THREE_WAY_COMPARATOR_H

#include <__config>
#include <__type_traits/desugars_to.h>
#include <__type_traits/enable_if.h>
#include <__utility/default_three_way_comparator.h>

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

// This file implements a __lazy_synth_three_way_comparator, which tries to build an efficient three way comparison from
// a binary comparator. That is done in multiple steps:
// 1) Check whether the comparator desugars to a less-than operator
// If that is the case, check whether there exists a specialization of `__default_three_way_comparator`, which
// can be specialized to implement a three way comparator for the specific types.
// 2) Fall back to doing a lazy less than/greater than comparison

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Comparator, class _LHS, class _RHS>
struct __lazy_compare_result {
const _Comparator& __comp_;
const _LHS& __lhs_;
const _RHS& __rhs_;

_LIBCPP_HIDE_FROM_ABI
__lazy_compare_result(_LIBCPP_CTOR_LIFETIMEBOUND const _Comparator& __comp,
_LIBCPP_CTOR_LIFETIMEBOUND const _LHS& __lhs,
_LIBCPP_CTOR_LIFETIMEBOUND const _RHS& __rhs)
: __comp_(__comp), __lhs_(__lhs), __rhs_(__rhs) {}

_LIBCPP_HIDE_FROM_ABI bool __less() const { return __comp_(__lhs_, __rhs_); }
_LIBCPP_HIDE_FROM_ABI bool __greater() const { return __comp_(__rhs_, __lhs_); }
};

// This class provides three way comparison between _LHS and _RHS as efficiently as possible. This can be specialized if
// a comparator only compares part of the object, potentially allowing an efficient three way comparison between the
// subobjects. The specialization should use the __lazy_synth_three_way_comparator for the subobjects to achieve this.
template <class _Comparator, class _LHS, class _RHS, class = void>
struct __lazy_synth_three_way_comparator {
const _Comparator& __comp_;

_LIBCPP_HIDE_FROM_ABI __lazy_synth_three_way_comparator(_LIBCPP_CTOR_LIFETIMEBOUND const _Comparator& __comp)
: __comp_(__comp) {}

_LIBCPP_HIDE_FROM_ABI __lazy_compare_result<_Comparator, _LHS, _RHS>
operator()(_LIBCPP_LIFETIMEBOUND const _LHS& __lhs, _LIBCPP_LIFETIMEBOUND const _RHS& __rhs) const {
return __lazy_compare_result<_Comparator, _LHS, _RHS>(__comp_, __lhs, __rhs);
}
};

struct __eager_compare_result {
int __res_;

_LIBCPP_HIDE_FROM_ABI explicit __eager_compare_result(int __res) : __res_(__res) {}

_LIBCPP_HIDE_FROM_ABI bool __less() const { return __res_ < 0; }
_LIBCPP_HIDE_FROM_ABI bool __greater() const { return __res_ > 0; }
};

template <class _Comparator, class _LHS, class _RHS>
struct __lazy_synth_three_way_comparator<_Comparator,
_LHS,
_RHS,
__enable_if_t<__desugars_to_v<__less_tag, _Comparator, _LHS, _RHS> &&
__has_default_three_way_comparator_v<_LHS, _RHS> > > {
// This lifetimebound annotation is technically incorrect, but other specializations actually capture the lifetime of
// the comparator.
_LIBCPP_HIDE_FROM_ABI __lazy_synth_three_way_comparator(_LIBCPP_CTOR_LIFETIMEBOUND const _Comparator&) {}

// Same comment as above.
_LIBCPP_HIDE_FROM_ABI static __eager_compare_result
operator()(_LIBCPP_LIFETIMEBOUND const _LHS& __lhs, _LIBCPP_LIFETIMEBOUND const _RHS& __rhs) {
return __eager_compare_result(__default_three_way_comparator<_LHS, _RHS>()(__lhs, __rhs));
}
};

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___UTILITY_LAZY_SYNTH_THREE_WAY_COMPARATOR_H
45 changes: 45 additions & 0 deletions libcxx/include/map
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20
# include <__type_traits/remove_const.h>
# include <__type_traits/type_identity.h>
# include <__utility/forward.h>
# include <__utility/lazy_synth_three_way_comparator.h>
# include <__utility/pair.h>
# include <__utility/piecewise_construct.h>
# include <__utility/swap.h>
Expand Down Expand Up @@ -702,6 +703,50 @@ public:
# endif
};

# if _LIBCPP_STD_VER >= 14
template <class _MapValueT, class _Key, class _Compare>
struct __lazy_synth_three_way_comparator<__map_value_compare<_Key, _MapValueT, _Compare>, _MapValueT, _MapValueT> {
__lazy_synth_three_way_comparator<_Compare, _Key, _Key> __comp_;

__lazy_synth_three_way_comparator(
_LIBCPP_CTOR_LIFETIMEBOUND const __map_value_compare<_Key, _MapValueT, _Compare>& __comp)
: __comp_(__comp.key_comp()) {}

_LIBCPP_HIDE_FROM_ABI auto
operator()(_LIBCPP_LIFETIMEBOUND const _MapValueT& __lhs, _LIBCPP_LIFETIMEBOUND const _MapValueT& __rhs) const {
return __comp_(__lhs.first, __rhs.first);
}
};

template <class _MapValueT, class _Key, class _TransparentKey, class _Compare>
struct __lazy_synth_three_way_comparator<__map_value_compare<_Key, _MapValueT, _Compare>, _TransparentKey, _MapValueT> {
__lazy_synth_three_way_comparator<_Compare, _TransparentKey, _Key> __comp_;

__lazy_synth_three_way_comparator(
_LIBCPP_CTOR_LIFETIMEBOUND const __map_value_compare<_Key, _MapValueT, _Compare>& __comp)
: __comp_(__comp.key_comp()) {}

_LIBCPP_HIDE_FROM_ABI auto
operator()(_LIBCPP_LIFETIMEBOUND const _TransparentKey& __lhs, _LIBCPP_LIFETIMEBOUND const _MapValueT& __rhs) const {
return __comp_(__lhs, __rhs.first);
}
};

template <class _MapValueT, class _Key, class _TransparentKey, class _Compare>
struct __lazy_synth_three_way_comparator<__map_value_compare<_Key, _MapValueT, _Compare>, _MapValueT, _TransparentKey> {
__lazy_synth_three_way_comparator<_Compare, _Key, _TransparentKey> __comp_;

__lazy_synth_three_way_comparator(
_LIBCPP_CTOR_LIFETIMEBOUND const __map_value_compare<_Key, _MapValueT, _Compare>& __comp)
: __comp_(__comp.key_comp()) {}

_LIBCPP_HIDE_FROM_ABI auto
operator()(_LIBCPP_LIFETIMEBOUND const _MapValueT& __lhs, _LIBCPP_LIFETIMEBOUND const _TransparentKey& __rhs) const {
return __comp_(__lhs.first, __rhs);
}
};
# endif // _LIBCPP_STD_VER >= 14

template <class _Key, class _CP, class _Compare, bool __b>
inline _LIBCPP_HIDE_FROM_ABI void
swap(__map_value_compare<_Key, _CP, _Compare, __b>& __x, __map_value_compare<_Key, _CP, _Compare, __b>& __y)
Expand Down
Loading
Loading