Skip to content

Commit 8f9cce0

Browse files
authored
[libc++] Add container_traits (prework for std::flat_map) (#109578)
This PR is extracted from #98643, as per code review request #98643 (comment)
1 parent a3bad9a commit 8f9cce0

File tree

12 files changed

+337
-0
lines changed

12 files changed

+337
-0
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,7 @@ set(files
747747
__type_traits/common_type.h
748748
__type_traits/conditional.h
749749
__type_traits/conjunction.h
750+
__type_traits/container_traits.h
750751
__type_traits/copy_cv.h
751752
__type_traits/copy_cvref.h
752753
__type_traits/datasizeof.h
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___TYPE_TRAITS_CONTAINER_TRAITS_H
11+
#define _LIBCPP___TYPE_TRAITS_CONTAINER_TRAITS_H
12+
13+
#include <__config>
14+
15+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
16+
# pragma GCC system_header
17+
#endif
18+
19+
_LIBCPP_BEGIN_NAMESPACE_STD
20+
21+
// // __container_traits is a general purpose utility containing traits describing various containers operations.
22+
// It currently only has one trait: `__emplacement_has_strong_exception_safety_guarantee`, but it's
23+
// intended to be extended in the future.
24+
//
25+
// These traits should only be used for optimization or QoI purposes. In particular, since this is a libc++ internal
26+
// mechanism, no user-defined containers should be expected to specialize these traits (in fact it would be illegal for
27+
// them to do so). Hence, when using these traits to implement something, make sure that a container that fails to
28+
// specialize these traits does not result in non-conforming code.
29+
//
30+
// When a trait is nonsensical for a type, this class still provides a fallback value for that trait.
31+
// For example, `std::array` does not support `insert` or `emplace`, so
32+
// `__emplacement_has_strong_exception_safety_guarantee` is false for such types.
33+
template <class _Container>
34+
struct __container_traits {
35+
// A trait that tells whether a single element insertion/emplacement via member function
36+
// `insert(...)` or `emplace(...)` has strong exception guarantee, that is, if the function
37+
// exits via an exception, the original container is unaffected
38+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee = false;
39+
};
40+
41+
_LIBCPP_END_NAMESPACE_STD
42+
43+
#endif // _LIBCPP___TYPE_TRAITS_CONTAINER_TRAITS_H

libcxx/include/deque

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ template <class T, class Allocator, class Predicate>
220220
#include <__ranges/size.h>
221221
#include <__split_buffer>
222222
#include <__type_traits/conditional.h>
223+
#include <__type_traits/container_traits.h>
224+
#include <__type_traits/disjunction.h>
223225
#include <__type_traits/enable_if.h>
224226
#include <__type_traits/is_allocator.h>
225227
#include <__type_traits/is_convertible.h>
@@ -2609,6 +2611,17 @@ inline constexpr bool __format::__enable_insertable<std::deque<wchar_t>> = true;
26092611

26102612
#endif // _LIBCPP_STD_VER >= 20
26112613

2614+
template <class _Tp, class _Allocator>
2615+
struct __container_traits<deque<_Tp, _Allocator> > {
2616+
// http://eel.is/c++draft/deque.modifiers#3
2617+
// If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move
2618+
// assignment operator of T, there are no effects. If an exception is thrown while inserting a single element at
2619+
// either end, there are no effects. Otherwise, if an exception is thrown by the move constructor of a
2620+
// non-Cpp17CopyInsertable T, the effects are unspecified.
2621+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee =
2622+
_Or<is_nothrow_move_constructible<_Tp>, __is_cpp17_copy_insertable<_Allocator> >::value;
2623+
};
2624+
26122625
_LIBCPP_END_NAMESPACE_STD
26132626

26142627
#if _LIBCPP_STD_VER >= 17

libcxx/include/forward_list

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ template <class T, class Allocator, class Predicate>
218218
#include <__ranges/container_compatible_range.h>
219219
#include <__ranges/from_range.h>
220220
#include <__type_traits/conditional.h>
221+
#include <__type_traits/container_traits.h>
221222
#include <__type_traits/enable_if.h>
222223
#include <__type_traits/is_allocator.h>
223224
#include <__type_traits/is_const.h>
@@ -1544,6 +1545,17 @@ erase(forward_list<_Tp, _Allocator>& __c, const _Up& __v) {
15441545
}
15451546
#endif
15461547

1548+
template <class _Tp, class _Allocator>
1549+
struct __container_traits<forward_list<_Tp, _Allocator> > {
1550+
// http://eel.is/c++draft/container.reqmts
1551+
// Unless otherwise specified (see [associative.reqmts.except], [unord.req.except], [deque.modifiers],
1552+
// [inplace.vector.modifiers], and [vector.modifiers]) all container types defined in this Clause meet the following
1553+
// additional requirements:
1554+
// - If an exception is thrown by an insert() or emplace() function while inserting a single element, that
1555+
// function has no effects.
1556+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee = true;
1557+
};
1558+
15471559
_LIBCPP_END_NAMESPACE_STD
15481560

15491561
#if _LIBCPP_STD_VER >= 17

libcxx/include/list

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ template <class T, class Allocator, class Predicate>
225225
#include <__ranges/container_compatible_range.h>
226226
#include <__ranges/from_range.h>
227227
#include <__type_traits/conditional.h>
228+
#include <__type_traits/container_traits.h>
228229
#include <__type_traits/enable_if.h>
229230
#include <__type_traits/is_allocator.h>
230231
#include <__type_traits/is_nothrow_assignable.h>
@@ -1715,6 +1716,17 @@ inline constexpr bool __format::__enable_insertable<std::list<wchar_t>> = true;
17151716

17161717
#endif // _LIBCPP_STD_VER >= 20
17171718

1719+
template <class _Tp, class _Allocator>
1720+
struct __container_traits<list<_Tp, _Allocator> > {
1721+
// http://eel.is/c++draft/container.reqmts
1722+
// Unless otherwise specified (see [associative.reqmts.except], [unord.req.except], [deque.modifiers],
1723+
// [inplace.vector.modifiers], and [vector.modifiers]) all container types defined in this Clause meet the following
1724+
// additional requirements:
1725+
// - If an exception is thrown by an insert() or emplace() function while inserting a single element, that
1726+
// function has no effects.
1727+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee = true;
1728+
};
1729+
17181730
_LIBCPP_END_NAMESPACE_STD
17191731

17201732
#if _LIBCPP_STD_VER >= 17

libcxx/include/map

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20
594594
#include <__ranges/container_compatible_range.h>
595595
#include <__ranges/from_range.h>
596596
#include <__tree>
597+
#include <__type_traits/container_traits.h>
597598
#include <__type_traits/is_allocator.h>
598599
#include <__type_traits/remove_const.h>
599600
#include <__type_traits/type_identity.h>
@@ -1644,6 +1645,14 @@ erase_if(map<_Key, _Tp, _Compare, _Allocator>& __c, _Predicate __pred) {
16441645
}
16451646
#endif
16461647

1648+
template <class _Key, class _Tp, class _Compare, class _Allocator>
1649+
struct __container_traits<map<_Key, _Tp, _Compare, _Allocator> > {
1650+
// http://eel.is/c++draft/associative.reqmts.except#2
1651+
// For associative containers, if an exception is thrown by any operation from within
1652+
// an insert or emplace function inserting a single element, the insertion has no effect.
1653+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee = true;
1654+
};
1655+
16471656
template <class _Key, class _Tp, class _Compare = less<_Key>, class _Allocator = allocator<pair<const _Key, _Tp> > >
16481657
class _LIBCPP_TEMPLATE_VIS multimap {
16491658
public:
@@ -2158,6 +2167,14 @@ erase_if(multimap<_Key, _Tp, _Compare, _Allocator>& __c, _Predicate __pred) {
21582167
}
21592168
#endif
21602169

2170+
template <class _Key, class _Tp, class _Compare, class _Allocator>
2171+
struct __container_traits<multimap<_Key, _Tp, _Compare, _Allocator> > {
2172+
// http://eel.is/c++draft/associative.reqmts.except#2
2173+
// For associative containers, if an exception is thrown by any operation from within
2174+
// an insert or emplace function inserting a single element, the insertion has no effect.
2175+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee = true;
2176+
};
2177+
21612178
_LIBCPP_END_NAMESPACE_STD
21622179

21632180
#if _LIBCPP_STD_VER >= 17

libcxx/include/module.modulemap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ module std_core [system] {
7979
}
8080
module conditional { header "__type_traits/conditional.h" }
8181
module conjunction { header "__type_traits/conjunction.h" }
82+
module container_traits { header "__type_traits/container_traits.h" }
8283
module copy_cv { header "__type_traits/copy_cv.h" }
8384
module copy_cvref { header "__type_traits/copy_cvref.h" }
8485
module datasizeof { header "__type_traits/datasizeof.h" }

libcxx/include/set

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ erase_if(multiset<Key, Compare, Allocator>& c, Predicate pred); // C++20
531531
#include <__ranges/container_compatible_range.h>
532532
#include <__ranges/from_range.h>
533533
#include <__tree>
534+
#include <__type_traits/container_traits.h>
534535
#include <__type_traits/enable_if.h>
535536
#include <__type_traits/is_allocator.h>
536537
#include <__type_traits/is_nothrow_assignable.h>
@@ -1022,6 +1023,14 @@ erase_if(set<_Key, _Compare, _Allocator>& __c, _Predicate __pred) {
10221023
}
10231024
#endif
10241025

1026+
template <class _Key, class _Compare, class _Allocator>
1027+
struct __container_traits<set<_Key, _Compare, _Allocator> > {
1028+
// http://eel.is/c++draft/associative.reqmts.except#2
1029+
// For associative containers, if an exception is thrown by any operation from within
1030+
// an insert or emplace function inserting a single element, the insertion has no effect.
1031+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee = true;
1032+
};
1033+
10251034
template <class _Key, class _Compare = less<_Key>, class _Allocator = allocator<_Key> >
10261035
class _LIBCPP_TEMPLATE_VIS multiset {
10271036
public:
@@ -1481,6 +1490,14 @@ erase_if(multiset<_Key, _Compare, _Allocator>& __c, _Predicate __pred) {
14811490
}
14821491
#endif
14831492

1493+
template <class _Key, class _Compare, class _Allocator>
1494+
struct __container_traits<multiset<_Key, _Compare, _Allocator> > {
1495+
// http://eel.is/c++draft/associative.reqmts.except#2
1496+
// For associative containers, if an exception is thrown by any operation from within
1497+
// an insert or emplace function inserting a single element, the insertion has no effect.
1498+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee = true;
1499+
};
1500+
14841501
_LIBCPP_END_NAMESPACE_STD
14851502

14861503
#if _LIBCPP_STD_VER >= 17

libcxx/include/unordered_map

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,9 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
604604
#include <__ranges/concepts.h>
605605
#include <__ranges/container_compatible_range.h>
606606
#include <__ranges/from_range.h>
607+
#include <__type_traits/container_traits.h>
607608
#include <__type_traits/enable_if.h>
609+
#include <__type_traits/invoke.h>
608610
#include <__type_traits/is_allocator.h>
609611
#include <__type_traits/is_integral.h>
610612
#include <__type_traits/remove_const.h>
@@ -1830,6 +1832,16 @@ inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const unordered_map<_Key, _Tp, _Has
18301832

18311833
#endif
18321834

1835+
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
1836+
struct __container_traits<unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc> > {
1837+
// http://eel.is/c++draft/unord.req.except#2
1838+
// For unordered associative containers, if an exception is thrown by any operation
1839+
// other than the container's hash function from within an insert or emplace function
1840+
// inserting a single element, the insertion has no effect.
1841+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee =
1842+
__nothrow_invokable<_Hash, const _Key&>::value;
1843+
};
1844+
18331845
template <class _Key,
18341846
class _Tp,
18351847
class _Hash = hash<_Key>,
@@ -2520,6 +2532,16 @@ inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const unordered_multimap<_Key, _Tp,
25202532

25212533
#endif
25222534

2535+
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
2536+
struct __container_traits<unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc> > {
2537+
// http://eel.is/c++draft/unord.req.except#2
2538+
// For unordered associative containers, if an exception is thrown by any operation
2539+
// other than the container's hash function from within an insert or emplace function
2540+
// inserting a single element, the insertion has no effect.
2541+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee =
2542+
__nothrow_invokable<_Hash, const _Key&>::value;
2543+
};
2544+
25232545
_LIBCPP_END_NAMESPACE_STD
25242546

25252547
#if _LIBCPP_STD_VER >= 17

libcxx/include/unordered_set

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,9 @@ template <class Value, class Hash, class Pred, class Alloc>
550550
#include <__ranges/concepts.h>
551551
#include <__ranges/container_compatible_range.h>
552552
#include <__ranges/from_range.h>
553+
#include <__type_traits/container_traits.h>
553554
#include <__type_traits/enable_if.h>
555+
#include <__type_traits/invoke.h>
554556
#include <__type_traits/is_allocator.h>
555557
#include <__type_traits/is_integral.h>
556558
#include <__type_traits/is_nothrow_assignable.h>
@@ -1183,6 +1185,16 @@ inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const unordered_set<_Value, _Hash,
11831185

11841186
#endif
11851187

1188+
template <class _Value, class _Hash, class _Pred, class _Alloc>
1189+
struct __container_traits<unordered_set<_Value, _Hash, _Pred, _Alloc> > {
1190+
// http://eel.is/c++draft/unord.req.except#2
1191+
// For unordered associative containers, if an exception is thrown by any operation
1192+
// other than the container's hash function from within an insert or emplace function
1193+
// inserting a single element, the insertion has no effect.
1194+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee =
1195+
__nothrow_invokable<_Hash, const _Value&>::value;
1196+
};
1197+
11861198
template <class _Value, class _Hash = hash<_Value>, class _Pred = equal_to<_Value>, class _Alloc = allocator<_Value> >
11871199
class _LIBCPP_TEMPLATE_VIS unordered_multiset {
11881200
public:
@@ -1793,6 +1805,16 @@ inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const unordered_multiset<_Value, _H
17931805

17941806
#endif
17951807

1808+
template <class _Value, class _Hash, class _Pred, class _Alloc>
1809+
struct __container_traits<unordered_multiset<_Value, _Hash, _Pred, _Alloc> > {
1810+
// http://eel.is/c++draft/unord.req.except#2
1811+
// For unordered associative containers, if an exception is thrown by any operation
1812+
// other than the container's hash function from within an insert or emplace function
1813+
// inserting a single element, the insertion has no effect.
1814+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee =
1815+
__nothrow_invokable<_Hash, const _Value&>::value;
1816+
};
1817+
17961818
_LIBCPP_END_NAMESPACE_STD
17971819

17981820
#if _LIBCPP_STD_VER >= 17

libcxx/include/vector

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ template<class T, class charT> requires is-vector-bool-reference<T> // Since C++
356356
#include <__ranges/size.h>
357357
#include <__split_buffer>
358358
#include <__type_traits/conditional.h>
359+
#include <__type_traits/container_traits.h>
360+
#include <__type_traits/disjunction.h>
359361
#include <__type_traits/enable_if.h>
360362
#include <__type_traits/is_allocator.h>
361363
#include <__type_traits/is_constructible.h>
@@ -3005,6 +3007,18 @@ public:
30053007
};
30063008
#endif // _LIBCPP_STD_VER >= 23
30073009

3010+
template <class _Tp, class _Allocator>
3011+
struct __container_traits<vector<_Tp, _Allocator> > {
3012+
// http://eel.is/c++draft/vector.modifiers#2
3013+
// If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move
3014+
// assignment operator of T or by any InputIterator operation, there are no effects. If an exception is thrown while
3015+
// inserting a single element at the end and T is Cpp17CopyInsertable or is_nothrow_move_constructible_v<T> is true,
3016+
// there are no effects. Otherwise, if an exception is thrown by the move constructor of a non-Cpp17CopyInsertable T,
3017+
// the effects are unspecified.
3018+
static _LIBCPP_CONSTEXPR const bool __emplacement_has_strong_exception_safety_guarantee =
3019+
_Or<is_nothrow_move_constructible<_Tp>, __is_cpp17_copy_insertable<_Allocator> >::value;
3020+
};
3021+
30083022
_LIBCPP_END_NAMESPACE_STD
30093023

30103024
#if _LIBCPP_STD_VER >= 17

0 commit comments

Comments
 (0)