Skip to content

Commit 7ee59ec

Browse files
committed
[libc++] Optimize {set,map}::{lower,upper}_bound
1 parent 4154c18 commit 7ee59ec

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)