Skip to content

Commit 54e10de

Browse files
philnik777clingfei
authored andcommitted
[libc++] Optimize {set,map}::{lower,upper}_bound (llvm#161366)
Apple M4: ``` Benchmark Baseline Candidate Difference % Difference --------------------------------------------------------------------------------------------- ---------- ----------- ------------ -------------- std::map<int,_int>::lower_bound(key)_(existent)/0 0.01 0.01 -0.00 -25.78 std::map<int,_int>::lower_bound(key)_(existent)/1024 7.94 4.28 -3.66 -46.09 std::map<int,_int>::lower_bound(key)_(existent)/32 2.73 1.69 -1.03 -37.89 std::map<int,_int>::lower_bound(key)_(existent)/8192 11.63 5.52 -6.11 -52.55 std::map<int,_int>::lower_bound(key)_(non-existent)/0 0.28 0.28 -0.00 -1.35 std::map<int,_int>::lower_bound(key)_(non-existent)/1024 17.21 7.63 -9.58 -55.67 std::map<int,_int>::lower_bound(key)_(non-existent)/32 4.71 3.26 -1.45 -30.71 std::map<int,_int>::lower_bound(key)_(non-existent)/8192 26.82 10.58 -16.24 -60.55 std::map<int,_int>::upper_bound(key)_(existent)/0 0.01 0.01 0.00 20.62 std::map<int,_int>::upper_bound(key)_(existent)/1024 7.93 3.61 -4.32 -54.49 std::map<int,_int>::upper_bound(key)_(existent)/32 2.83 1.98 -0.85 -30.01 std::map<int,_int>::upper_bound(key)_(existent)/8192 11.69 5.72 -5.97 -51.06 std::map<int,_int>::upper_bound(key)_(non-existent)/0 0.28 0.28 -0.00 -1.36 std::map<int,_int>::upper_bound(key)_(non-existent)/1024 17.21 8.00 -9.21 -53.53 std::map<int,_int>::upper_bound(key)_(non-existent)/32 4.70 2.93 -1.78 -37.76 std::map<int,_int>::upper_bound(key)_(non-existent)/8192 26.54 11.18 -15.36 -57.89 std::map<std::string,_int>::lower_bound(key)_(existent)/0 0.04 0.04 -0.00 -3.26 std::map<std::string,_int>::lower_bound(key)_(existent)/1024 27.46 26.25 -1.22 -4.43 std::map<std::string,_int>::lower_bound(key)_(existent)/32 19.17 15.71 -3.46 -18.07 std::map<std::string,_int>::lower_bound(key)_(existent)/8192 35.33 35.03 -0.30 -0.84 std::map<std::string,_int>::lower_bound(key)_(non-existent)/0 0.27 0.27 -0.00 -1.45 std::map<std::string,_int>::lower_bound(key)_(non-existent)/1024 24.88 24.17 -0.70 -2.83 std::map<std::string,_int>::lower_bound(key)_(non-existent)/32 11.67 11.63 -0.04 -0.32 std::map<std::string,_int>::lower_bound(key)_(non-existent)/8192 31.81 32.33 0.52 1.64 std::map<std::string,_int>::upper_bound(key)_(existent)/0 0.04 0.04 -0.00 -2.22 std::map<std::string,_int>::upper_bound(key)_(existent)/1024 29.91 26.51 -3.40 -11.38 std::map<std::string,_int>::upper_bound(key)_(existent)/32 19.69 17.74 -1.95 -9.92 std::map<std::string,_int>::upper_bound(key)_(existent)/8192 32.55 35.24 2.69 8.25 std::map<std::string,_int>::upper_bound(key)_(non-existent)/0 0.27 0.27 -0.00 -1.74 std::map<std::string,_int>::upper_bound(key)_(non-existent)/1024 23.87 26.77 2.91 12.18 std::map<std::string,_int>::upper_bound(key)_(non-existent)/32 11.44 11.81 0.37 3.24 std::map<std::string,_int>::upper_bound(key)_(non-existent)/8192 33.02 32.59 -0.43 -1.29 std::set<int>::lower_bound(key)_(existent)/0 0.01 0.01 0.00 0.48 std::set<int>::lower_bound(key)_(existent)/1024 7.83 4.21 -3.62 -46.23 std::set<int>::lower_bound(key)_(existent)/32 2.74 1.68 -1.06 -38.81 std::set<int>::lower_bound(key)_(existent)/8192 22.75 11.12 -11.63 -51.12 std::set<int>::lower_bound(key)_(non-existent)/0 0.28 0.27 -0.01 -3.52 std::set<int>::lower_bound(key)_(non-existent)/1024 17.15 8.40 -8.75 -51.03 std::set<int>::lower_bound(key)_(non-existent)/32 4.63 2.50 -2.13 -46.03 std::set<int>::lower_bound(key)_(non-existent)/8192 28.88 11.05 -17.82 -61.72 std::set<int>::upper_bound(key)_(existent)/0 0.01 0.01 -0.00 -7.79 std::set<int>::upper_bound(key)_(existent)/1024 7.80 3.63 -4.16 -53.42 std::set<int>::upper_bound(key)_(existent)/32 2.81 1.90 -0.91 -32.44 std::set<int>::upper_bound(key)_(existent)/8192 21.93 11.35 -10.58 -48.26 std::set<int>::upper_bound(key)_(non-existent)/0 0.28 0.27 -0.01 -3.81 std::set<int>::upper_bound(key)_(non-existent)/1024 16.76 7.38 -9.38 -55.98 std::set<int>::upper_bound(key)_(non-existent)/32 4.58 3.10 -1.48 -32.31 std::set<int>::upper_bound(key)_(non-existent)/8192 26.95 10.70 -16.25 -60.29 std::set<std::string>::lower_bound(key)_(existent)/0 0.04 0.04 0.00 0.02 std::set<std::string>::lower_bound(key)_(existent)/1024 28.08 27.04 -1.04 -3.71 std::set<std::string>::lower_bound(key)_(existent)/32 17.53 16.94 -0.58 -3.34 std::set<std::string>::lower_bound(key)_(existent)/8192 32.79 33.28 0.49 1.49 std::set<std::string>::lower_bound(key)_(non-existent)/0 0.28 0.28 -0.00 -0.06 std::set<std::string>::lower_bound(key)_(non-existent)/1024 25.23 24.38 -0.85 -3.38 std::set<std::string>::lower_bound(key)_(non-existent)/32 11.45 11.68 0.24 2.07 std::set<std::string>::lower_bound(key)_(non-existent)/8192 32.30 36.80 4.50 13.95 std::set<std::string>::upper_bound(key)_(existent)/0 0.04 0.04 -0.00 -0.14 std::set<std::string>::upper_bound(key)_(existent)/1024 26.71 26.37 -0.34 -1.27 std::set<std::string>::upper_bound(key)_(existent)/32 20.07 19.06 -1.02 -5.06 std::set<std::string>::upper_bound(key)_(existent)/8192 36.69 35.50 -1.19 -3.25 std::set<std::string>::upper_bound(key)_(non-existent)/0 0.28 0.28 -0.00 -0.16 std::set<std::string>::upper_bound(key)_(non-existent)/1024 24.48 24.90 0.42 1.73 std::set<std::string>::upper_bound(key)_(non-existent)/32 11.68 11.77 0.09 0.77 std::set<std::string>::upper_bound(key)_(non-existent)/8192 33.16 34.12 0.96 2.89 ```
1 parent e442141 commit 54e10de

File tree

3 files changed

+149
-56
lines changed

3 files changed

+149
-56
lines changed

libcxx/include/__tree

Lines changed: 81 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,32 +1166,87 @@ public:
11661166
template <class _Key>
11671167
_LIBCPP_HIDE_FROM_ABI size_type __count_multi(const _Key& __k) const;
11681168

1169+
template <bool _LowerBound, class _Key>
1170+
_LIBCPP_HIDE_FROM_ABI __end_node_pointer __lower_upper_bound_unique_impl(const _Key& __v) const {
1171+
auto __rt = __root();
1172+
auto __result = __end_node();
1173+
auto __comp = __lazy_synth_three_way_comparator<_Compare, _Key, value_type>(value_comp());
1174+
while (__rt != nullptr) {
1175+
auto __comp_res = __comp(__v, __rt->__get_value());
1176+
1177+
if (__comp_res.__less()) {
1178+
__result = static_cast<__end_node_pointer>(__rt);
1179+
__rt = static_cast<__node_pointer>(__rt->__left_);
1180+
} else if (__comp_res.__greater()) {
1181+
__rt = static_cast<__node_pointer>(__rt->__right_);
1182+
} else if _LIBCPP_CONSTEXPR (_LowerBound) {
1183+
return static_cast<__end_node_pointer>(__rt);
1184+
} else {
1185+
return __rt->__right_ ? static_cast<__end_node_pointer>(std::__tree_min(__rt->__right_)) : __result;
1186+
}
1187+
}
1188+
return __result;
1189+
}
1190+
1191+
template <class _Key>
1192+
_LIBCPP_HIDE_FROM_ABI iterator __lower_bound_unique(const _Key& __v) {
1193+
return iterator(__lower_upper_bound_unique_impl<true>(__v));
1194+
}
1195+
11691196
template <class _Key>
1170-
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Key& __v) {
1171-
return __lower_bound(__v, __root(), __end_node());
1197+
_LIBCPP_HIDE_FROM_ABI const_iterator __lower_bound_unique(const _Key& __v) const {
1198+
return const_iterator(__lower_upper_bound_unique_impl<true>(__v));
11721199
}
1200+
11731201
template <class _Key>
1174-
_LIBCPP_HIDE_FROM_ABI iterator __lower_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result);
1202+
_LIBCPP_HIDE_FROM_ABI iterator __upper_bound_unique(const _Key& __v) {
1203+
return iterator(__lower_upper_bound_unique_impl<false>(__v));
1204+
}
1205+
11751206
template <class _Key>
1176-
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Key& __v) const {
1177-
return __lower_bound(__v, __root(), __end_node());
1207+
_LIBCPP_HIDE_FROM_ABI const_iterator __upper_bound_unique(const _Key& __v) const {
1208+
return iterator(__lower_upper_bound_unique_impl<false>(__v));
11781209
}
1210+
1211+
private:
1212+
template <class _Key>
1213+
_LIBCPP_HIDE_FROM_ABI iterator
1214+
__lower_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result);
1215+
11791216
template <class _Key>
11801217
_LIBCPP_HIDE_FROM_ABI const_iterator
1181-
__lower_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const;
1218+
__lower_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const;
1219+
1220+
public:
1221+
template <class _Key>
1222+
_LIBCPP_HIDE_FROM_ABI iterator __lower_bound_multi(const _Key& __v) {
1223+
return __lower_bound_multi(__v, __root(), __end_node());
1224+
}
11821225
template <class _Key>
1183-
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Key& __v) {
1184-
return __upper_bound(__v, __root(), __end_node());
1226+
_LIBCPP_HIDE_FROM_ABI const_iterator __lower_bound_multi(const _Key& __v) const {
1227+
return __lower_bound_multi(__v, __root(), __end_node());
11851228
}
1229+
11861230
template <class _Key>
1187-
_LIBCPP_HIDE_FROM_ABI iterator __upper_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result);
1231+
_LIBCPP_HIDE_FROM_ABI iterator __upper_bound_multi(const _Key& __v) {
1232+
return __upper_bound_multi(__v, __root(), __end_node());
1233+
}
1234+
11881235
template <class _Key>
1189-
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Key& __v) const {
1190-
return __upper_bound(__v, __root(), __end_node());
1236+
_LIBCPP_HIDE_FROM_ABI const_iterator __upper_bound_multi(const _Key& __v) const {
1237+
return __upper_bound_multi(__v, __root(), __end_node());
11911238
}
1239+
1240+
private:
1241+
template <class _Key>
1242+
_LIBCPP_HIDE_FROM_ABI iterator
1243+
__upper_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result);
1244+
11921245
template <class _Key>
11931246
_LIBCPP_HIDE_FROM_ABI const_iterator
1194-
__upper_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const;
1247+
__upper_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const;
1248+
1249+
public:
11951250
template <class _Key>
11961251
_LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> __equal_range_unique(const _Key& __k);
11971252
template <class _Key>
@@ -2100,16 +2155,16 @@ __tree<_Tp, _Compare, _Allocator>::__count_multi(const _Key& __k) const {
21002155
__rt = static_cast<__node_pointer>(__rt->__right_);
21012156
else
21022157
return std::distance(
2103-
__lower_bound(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2104-
__upper_bound(__k, static_cast<__node_pointer>(__rt->__right_), __result));
2158+
__lower_bound_multi(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2159+
__upper_bound_multi(__k, static_cast<__node_pointer>(__rt->__right_), __result));
21052160
}
21062161
return 0;
21072162
}
21082163

21092164
template <class _Tp, class _Compare, class _Allocator>
21102165
template <class _Key>
2111-
typename __tree<_Tp, _Compare, _Allocator>::iterator
2112-
__tree<_Tp, _Compare, _Allocator>::__lower_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) {
2166+
typename __tree<_Tp, _Compare, _Allocator>::iterator __tree<_Tp, _Compare, _Allocator>::__lower_bound_multi(
2167+
const _Key& __v, __node_pointer __root, __end_node_pointer __result) {
21132168
while (__root != nullptr) {
21142169
if (!value_comp()(__root->__get_value(), __v)) {
21152170
__result = static_cast<__end_node_pointer>(__root);
@@ -2122,7 +2177,7 @@ __tree<_Tp, _Compare, _Allocator>::__lower_bound(const _Key& __v, __node_pointer
21222177

21232178
template <class _Tp, class _Compare, class _Allocator>
21242179
template <class _Key>
2125-
typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__lower_bound(
2180+
typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__lower_bound_multi(
21262181
const _Key& __v, __node_pointer __root, __end_node_pointer __result) const {
21272182
while (__root != nullptr) {
21282183
if (!value_comp()(__root->__get_value(), __v)) {
@@ -2136,8 +2191,8 @@ typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare,
21362191

21372192
template <class _Tp, class _Compare, class _Allocator>
21382193
template <class _Key>
2139-
typename __tree<_Tp, _Compare, _Allocator>::iterator
2140-
__tree<_Tp, _Compare, _Allocator>::__upper_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) {
2194+
typename __tree<_Tp, _Compare, _Allocator>::iterator __tree<_Tp, _Compare, _Allocator>::__upper_bound_multi(
2195+
const _Key& __v, __node_pointer __root, __end_node_pointer __result) {
21412196
while (__root != nullptr) {
21422197
if (value_comp()(__v, __root->__get_value())) {
21432198
__result = static_cast<__end_node_pointer>(__root);
@@ -2150,7 +2205,7 @@ __tree<_Tp, _Compare, _Allocator>::__upper_bound(const _Key& __v, __node_pointer
21502205

21512206
template <class _Tp, class _Compare, class _Allocator>
21522207
template <class _Key>
2153-
typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__upper_bound(
2208+
typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__upper_bound_multi(
21542209
const _Key& __v, __node_pointer __root, __end_node_pointer __result) const {
21552210
while (__root != nullptr) {
21562211
if (value_comp()(__v, __root->__get_value())) {
@@ -2226,8 +2281,9 @@ __tree<_Tp, _Compare, _Allocator>::__equal_range_multi(const _Key& __k) {
22262281
} else if (__comp_res.__greater())
22272282
__rt = static_cast<__node_pointer>(__rt->__right_);
22282283
else
2229-
return _Pp(__lower_bound(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2230-
__upper_bound(__k, static_cast<__node_pointer>(__rt->__right_), __result));
2284+
return _Pp(
2285+
__lower_bound_multi(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2286+
__upper_bound_multi(__k, static_cast<__node_pointer>(__rt->__right_), __result));
22312287
}
22322288
return _Pp(iterator(__result), iterator(__result));
22332289
}
@@ -2249,8 +2305,9 @@ __tree<_Tp, _Compare, _Allocator>::__equal_range_multi(const _Key& __k) const {
22492305
} else if (__comp_res.__greater())
22502306
__rt = static_cast<__node_pointer>(__rt->__right_);
22512307
else
2252-
return _Pp(__lower_bound(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2253-
__upper_bound(__k, static_cast<__node_pointer>(__rt->__right_), __result));
2308+
return _Pp(
2309+
__lower_bound_multi(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2310+
__upper_bound_multi(__k, static_cast<__node_pointer>(__rt->__right_), __result));
22542311
}
22552312
return _Pp(const_iterator(__result), const_iterator(__result));
22562313
}

libcxx/include/map

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,38 +1300,48 @@ public:
13001300
}
13011301
# endif // _LIBCPP_STD_VER >= 20
13021302

1303-
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.lower_bound(__k); }
1304-
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { return __tree_.lower_bound(__k); }
1303+
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.__lower_bound_unique(__k); }
1304+
1305+
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const {
1306+
return __tree_.__lower_bound_unique(__k);
1307+
}
1308+
1309+
// The transparent versions of the lookup functions use the _multi version, since a non-element key is allowed to
1310+
// match multiple elements.
13051311
# if _LIBCPP_STD_VER >= 14
13061312
template <typename _K2,
13071313
enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>,
13081314
int> = 0>
13091315
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) {
1310-
return __tree_.lower_bound(__k);
1316+
return __tree_.__lower_bound_multi(__k);
13111317
}
13121318

13131319
template <typename _K2,
13141320
enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>,
13151321
int> = 0>
13161322
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const {
1317-
return __tree_.lower_bound(__k);
1323+
return __tree_.__lower_bound_multi(__k);
13181324
}
13191325
# endif
13201326

1321-
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.upper_bound(__k); }
1322-
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { return __tree_.upper_bound(__k); }
1327+
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.__upper_bound_unique(__k); }
1328+
1329+
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const {
1330+
return __tree_.__upper_bound_unique(__k);
1331+
}
1332+
13231333
# if _LIBCPP_STD_VER >= 14
13241334
template <typename _K2,
13251335
enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>,
13261336
int> = 0>
13271337
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) {
1328-
return __tree_.upper_bound(__k);
1338+
return __tree_.__upper_bound_multi(__k);
13291339
}
13301340
template <typename _K2,
13311341
enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>,
13321342
int> = 0>
13331343
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const {
1334-
return __tree_.upper_bound(__k);
1344+
return __tree_.__upper_bound_multi(__k);
13351345
}
13361346
# endif
13371347

@@ -1871,30 +1881,38 @@ public:
18711881
}
18721882
# endif // _LIBCPP_STD_VER >= 20
18731883

1874-
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.lower_bound(__k); }
1875-
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { return __tree_.lower_bound(__k); }
1884+
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.__lower_bound_multi(__k); }
1885+
1886+
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const {
1887+
return __tree_.__lower_bound_multi(__k);
1888+
}
1889+
18761890
# if _LIBCPP_STD_VER >= 14
18771891
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
18781892
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) {
1879-
return __tree_.lower_bound(__k);
1893+
return __tree_.__lower_bound_multi(__k);
18801894
}
18811895

18821896
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
18831897
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const {
1884-
return __tree_.lower_bound(__k);
1898+
return __tree_.__lower_bound_multi(__k);
18851899
}
18861900
# endif
18871901

1888-
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.upper_bound(__k); }
1889-
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { return __tree_.upper_bound(__k); }
1902+
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.__upper_bound_multi(__k); }
1903+
1904+
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const {
1905+
return __tree_.__upper_bound_multi(__k);
1906+
}
1907+
18901908
# if _LIBCPP_STD_VER >= 14
18911909
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
18921910
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) {
1893-
return __tree_.upper_bound(__k);
1911+
return __tree_.__upper_bound_multi(__k);
18941912
}
18951913
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
18961914
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const {
1897-
return __tree_.upper_bound(__k);
1915+
return __tree_.__upper_bound_multi(__k);
18981916
}
18991917
# endif
19001918

libcxx/include/set

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -849,30 +849,40 @@ public:
849849
}
850850
# endif // _LIBCPP_STD_VER >= 20
851851

852-
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.lower_bound(__k); }
853-
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { return __tree_.lower_bound(__k); }
852+
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.__lower_bound_unique(__k); }
853+
854+
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const {
855+
return __tree_.__lower_bound_unique(__k);
856+
}
857+
858+
// The transparent versions of the lookup functions use the _multi version, since a non-element key is allowed to
859+
// match multiple elements.
854860
# if _LIBCPP_STD_VER >= 14
855861
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
856862
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) {
857-
return __tree_.lower_bound(__k);
863+
return __tree_.__lower_bound_multi(__k);
858864
}
859865

860866
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
861867
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const {
862-
return __tree_.lower_bound(__k);
868+
return __tree_.__lower_bound_multi(__k);
863869
}
864870
# endif
865871

866-
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.upper_bound(__k); }
867-
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { return __tree_.upper_bound(__k); }
872+
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.__upper_bound_unique(__k); }
873+
874+
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const {
875+
return __tree_.__upper_bound_unique(__k);
876+
}
877+
868878
# if _LIBCPP_STD_VER >= 14
869879
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
870880
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) {
871-
return __tree_.upper_bound(__k);
881+
return __tree_.__upper_bound_multi(__k);
872882
}
873883
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
874884
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const {
875-
return __tree_.upper_bound(__k);
885+
return __tree_.__upper_bound_multi(__k);
876886
}
877887
# endif
878888

@@ -1301,30 +1311,38 @@ public:
13011311
}
13021312
# endif // _LIBCPP_STD_VER >= 20
13031313

1304-
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.lower_bound(__k); }
1305-
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { return __tree_.lower_bound(__k); }
1314+
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.__lower_bound_multi(__k); }
1315+
1316+
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const {
1317+
return __tree_.__lower_bound_multi(__k);
1318+
}
1319+
13061320
# if _LIBCPP_STD_VER >= 14
13071321
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
13081322
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) {
1309-
return __tree_.lower_bound(__k);
1323+
return __tree_.__lower_bound_multi(__k);
13101324
}
13111325

13121326
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
13131327
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const {
1314-
return __tree_.lower_bound(__k);
1328+
return __tree_.__lower_bound_multi(__k);
13151329
}
13161330
# endif
13171331

1318-
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.upper_bound(__k); }
1319-
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { return __tree_.upper_bound(__k); }
1332+
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.__upper_bound_multi(__k); }
1333+
1334+
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const {
1335+
return __tree_.__upper_bound_multi(__k);
1336+
}
1337+
13201338
# if _LIBCPP_STD_VER >= 14
13211339
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
13221340
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) {
1323-
return __tree_.upper_bound(__k);
1341+
return __tree_.__upper_bound_multi(__k);
13241342
}
13251343
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
13261344
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const {
1327-
return __tree_.upper_bound(__k);
1345+
return __tree_.__upper_bound_multi(__k);
13281346
}
13291347
# endif
13301348

0 commit comments

Comments
 (0)