Skip to content

Commit 4e6971e

Browse files
committed
[libc++] Optimize {set,map}::{lower,upper}_bound
1 parent 1098a5c commit 4e6971e

File tree

3 files changed

+145
-54
lines changed

3 files changed

+145
-54
lines changed

libcxx/include/__tree

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

1168+
template <bool _LowerBound, class _Key>
1169+
_LIBCPP_HIDE_FROM_ABI __end_node_pointer __lower_upper_bound_unique_impl(const _Key& __v) const {
1170+
auto __rt = __root();
1171+
auto __result = __end_node();
1172+
auto __comp = __lazy_synth_three_way_comparator<_Compare, _Key, value_type>(value_comp());
1173+
while (__rt != nullptr) {
1174+
auto __comp_res = __comp(__v, __rt->__get_value());
1175+
1176+
if (__comp_res.__less()) {
1177+
__result = static_cast<__end_node_pointer>(__rt);
1178+
__rt = static_cast<__node_pointer>(__rt->__left_);
1179+
} else if (__comp_res.__greater()) {
1180+
__rt = static_cast<__node_pointer>(__rt->__right_);
1181+
} else if _LIBCPP_CONSTEXPR (_LowerBound) {
1182+
return static_cast<__end_node_pointer>(__rt);
1183+
} else {
1184+
return __rt->__right_ ? static_cast<__end_node_pointer>(std::__tree_min(__rt->__right_)) : __result;
1185+
}
1186+
}
1187+
return __result;
1188+
}
1189+
1190+
template <class _Key>
1191+
_LIBCPP_HIDE_FROM_ABI iterator __lower_bound_unique(const _Key& __v) {
1192+
return iterator(__lower_upper_bound_unique_impl<true>(__v));
1193+
}
1194+
11681195
template <class _Key>
1169-
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Key& __v) {
1170-
return __lower_bound(__v, __root(), __end_node());
1196+
_LIBCPP_HIDE_FROM_ABI const_iterator __lower_bound_unique(const _Key& __v) const {
1197+
return const_iterator(__lower_upper_bound_unique_impl<true>(__v));
11711198
}
1199+
11721200
template <class _Key>
1173-
_LIBCPP_HIDE_FROM_ABI iterator __lower_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result);
1201+
_LIBCPP_HIDE_FROM_ABI iterator __upper_bound_unique(const _Key& __v) {
1202+
return iterator(__lower_upper_bound_unique_impl<false>(__v));
1203+
}
1204+
11741205
template <class _Key>
1175-
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Key& __v) const {
1176-
return __lower_bound(__v, __root(), __end_node());
1206+
_LIBCPP_HIDE_FROM_ABI const_iterator __upper_bound_unique(const _Key& __v) const {
1207+
return iterator(__lower_upper_bound_unique_impl<false>(__v));
11771208
}
1209+
1210+
private:
1211+
template <class _Key>
1212+
_LIBCPP_HIDE_FROM_ABI iterator
1213+
__lower_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result);
1214+
11781215
template <class _Key>
11791216
_LIBCPP_HIDE_FROM_ABI const_iterator
1180-
__lower_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const;
1217+
__lower_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const;
1218+
1219+
public:
11811220
template <class _Key>
1182-
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Key& __v) {
1183-
return __upper_bound(__v, __root(), __end_node());
1221+
_LIBCPP_HIDE_FROM_ABI iterator __lower_bound_multi(const _Key& __v) {
1222+
return __lower_bound_multi(__v, __root(), __end_node());
11841223
}
11851224
template <class _Key>
1186-
_LIBCPP_HIDE_FROM_ABI iterator __upper_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result);
1225+
_LIBCPP_HIDE_FROM_ABI const_iterator __lower_bound_multi(const _Key& __v) const {
1226+
return __lower_bound_multi(__v, __root(), __end_node());
1227+
}
1228+
1229+
template <class _Key>
1230+
_LIBCPP_HIDE_FROM_ABI iterator __upper_bound_multi(const _Key& __v) {
1231+
return __upper_bound_multi(__v, __root(), __end_node());
1232+
}
1233+
11871234
template <class _Key>
1188-
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Key& __v) const {
1189-
return __upper_bound(__v, __root(), __end_node());
1235+
_LIBCPP_HIDE_FROM_ABI const_iterator __upper_bound_multi(const _Key& __v) const {
1236+
return __upper_bound_multi(__v, __root(), __end_node());
11901237
}
1238+
1239+
private:
1240+
template <class _Key>
1241+
_LIBCPP_HIDE_FROM_ABI iterator
1242+
__upper_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result);
1243+
11911244
template <class _Key>
11921245
_LIBCPP_HIDE_FROM_ABI const_iterator
1193-
__upper_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const;
1246+
__upper_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const;
1247+
1248+
public:
11941249
template <class _Key>
11951250
_LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> __equal_range_unique(const _Key& __k);
11961251
template <class _Key>
@@ -2098,16 +2153,16 @@ __tree<_Tp, _Compare, _Allocator>::__count_multi(const _Key& __k) const {
20982153
__rt = static_cast<__node_pointer>(__rt->__right_);
20992154
else
21002155
return std::distance(
2101-
__lower_bound(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2102-
__upper_bound(__k, static_cast<__node_pointer>(__rt->__right_), __result));
2156+
__lower_bound_multi(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2157+
__upper_bound_multi(__k, static_cast<__node_pointer>(__rt->__right_), __result));
21032158
}
21042159
return 0;
21052160
}
21062161

21072162
template <class _Tp, class _Compare, class _Allocator>
21082163
template <class _Key>
21092164
typename __tree<_Tp, _Compare, _Allocator>::iterator
2110-
__tree<_Tp, _Compare, _Allocator>::__lower_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) {
2165+
__tree<_Tp, _Compare, _Allocator>::__lower_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result) {
21112166
while (__root != nullptr) {
21122167
if (!value_comp()(__root->__get_value(), __v)) {
21132168
__result = static_cast<__end_node_pointer>(__root);
@@ -2120,7 +2175,7 @@ __tree<_Tp, _Compare, _Allocator>::__lower_bound(const _Key& __v, __node_pointer
21202175

21212176
template <class _Tp, class _Compare, class _Allocator>
21222177
template <class _Key>
2123-
typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__lower_bound(
2178+
typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__lower_bound_multi(
21242179
const _Key& __v, __node_pointer __root, __end_node_pointer __result) const {
21252180
while (__root != nullptr) {
21262181
if (!value_comp()(__root->__get_value(), __v)) {
@@ -2135,7 +2190,7 @@ typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare,
21352190
template <class _Tp, class _Compare, class _Allocator>
21362191
template <class _Key>
21372192
typename __tree<_Tp, _Compare, _Allocator>::iterator
2138-
__tree<_Tp, _Compare, _Allocator>::__upper_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) {
2193+
__tree<_Tp, _Compare, _Allocator>::__upper_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result) {
21392194
while (__root != nullptr) {
21402195
if (value_comp()(__v, __root->__get_value())) {
21412196
__result = static_cast<__end_node_pointer>(__root);
@@ -2148,7 +2203,7 @@ __tree<_Tp, _Compare, _Allocator>::__upper_bound(const _Key& __v, __node_pointer
21482203

21492204
template <class _Tp, class _Compare, class _Allocator>
21502205
template <class _Key>
2151-
typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__upper_bound(
2206+
typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__upper_bound_multi(
21522207
const _Key& __v, __node_pointer __root, __end_node_pointer __result) const {
21532208
while (__root != nullptr) {
21542209
if (value_comp()(__v, __root->__get_value())) {
@@ -2224,8 +2279,8 @@ __tree<_Tp, _Compare, _Allocator>::__equal_range_multi(const _Key& __k) {
22242279
} else if (__comp_res.__greater())
22252280
__rt = static_cast<__node_pointer>(__rt->__right_);
22262281
else
2227-
return _Pp(__lower_bound(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2228-
__upper_bound(__k, static_cast<__node_pointer>(__rt->__right_), __result));
2282+
return _Pp(__lower_bound_multi(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2283+
__upper_bound_multi(__k, static_cast<__node_pointer>(__rt->__right_), __result));
22292284
}
22302285
return _Pp(iterator(__result), iterator(__result));
22312286
}
@@ -2247,8 +2302,8 @@ __tree<_Tp, _Compare, _Allocator>::__equal_range_multi(const _Key& __k) const {
22472302
} else if (__comp_res.__greater())
22482303
__rt = static_cast<__node_pointer>(__rt->__right_);
22492304
else
2250-
return _Pp(__lower_bound(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2251-
__upper_bound(__k, static_cast<__node_pointer>(__rt->__right_), __result));
2305+
return _Pp(__lower_bound_multi(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)),
2306+
__upper_bound_multi(__k, static_cast<__node_pointer>(__rt->__right_), __result));
22522307
}
22532308
return _Pp(const_iterator(__result), const_iterator(__result));
22542309
}

libcxx/include/map

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,30 +1268,40 @@ public:
12681268
}
12691269
# endif // _LIBCPP_STD_VER >= 20
12701270

1271-
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.lower_bound(__k); }
1272-
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { return __tree_.lower_bound(__k); }
1271+
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.__lower_bound_unique(__k); }
1272+
1273+
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const {
1274+
return __tree_.__lower_bound_unique(__k);
1275+
}
1276+
1277+
// The transparent versions of the lookup functions use the _multi version, since a non-element key is allowed to
1278+
// match multiple elements.
12731279
# if _LIBCPP_STD_VER >= 14
12741280
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
12751281
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) {
1276-
return __tree_.lower_bound(__k);
1282+
return __tree_.__lower_bound_multi(__k);
12771283
}
12781284

12791285
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
12801286
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const {
1281-
return __tree_.lower_bound(__k);
1287+
return __tree_.__lower_bound_multi(__k);
12821288
}
12831289
# endif
12841290

1285-
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.upper_bound(__k); }
1286-
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { return __tree_.upper_bound(__k); }
1291+
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.__upper_bound_unique(__k); }
1292+
1293+
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const {
1294+
return __tree_.__upper_bound_unique(__k);
1295+
}
1296+
12871297
# if _LIBCPP_STD_VER >= 14
12881298
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
12891299
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) {
1290-
return __tree_.upper_bound(__k);
1300+
return __tree_.__upper_bound_multi(__k);
12911301
}
12921302
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
12931303
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const {
1294-
return __tree_.upper_bound(__k);
1304+
return __tree_.__upper_bound_multi(__k);
12951305
}
12961306
# endif
12971307

@@ -1831,30 +1841,38 @@ public:
18311841
}
18321842
# endif // _LIBCPP_STD_VER >= 20
18331843

1834-
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.lower_bound(__k); }
1835-
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { return __tree_.lower_bound(__k); }
1844+
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.__lower_bound_multi(__k); }
1845+
1846+
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const {
1847+
return __tree_.__lower_bound_multi(__k);
1848+
}
1849+
18361850
# if _LIBCPP_STD_VER >= 14
18371851
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
18381852
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) {
1839-
return __tree_.lower_bound(__k);
1853+
return __tree_.__lower_bound_multi(__k);
18401854
}
18411855

18421856
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
18431857
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const {
1844-
return __tree_.lower_bound(__k);
1858+
return __tree_.__lower_bound_multi(__k);
18451859
}
18461860
# endif
18471861

1848-
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.upper_bound(__k); }
1849-
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { return __tree_.upper_bound(__k); }
1862+
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.__upper_bound_multi(__k); }
1863+
1864+
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const {
1865+
return __tree_.__upper_bound_multi(__k);
1866+
}
1867+
18501868
# if _LIBCPP_STD_VER >= 14
18511869
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
18521870
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) {
1853-
return __tree_.upper_bound(__k);
1871+
return __tree_.__upper_bound_multi(__k);
18541872
}
18551873
template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0>
18561874
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const {
1857-
return __tree_.upper_bound(__k);
1875+
return __tree_.__upper_bound_multi(__k);
18581876
}
18591877
# endif
18601878

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)