Skip to content

Commit e0337b0

Browse files
committed
Avoid instantiating hash-based containers with non-hashable key types
1 parent 1311cd4 commit e0337b0

File tree

1 file changed

+48
-16
lines changed

1 file changed

+48
-16
lines changed

source/bounded/std_iterator.cpp

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55

66
export module bounded.std_iterator;
77

8-
import bounded.character;
98
import bounded.bounded_integer;
9+
import bounded.character;
10+
import bounded.concepts;
1011
import bounded.declval;
1112
import bounded.integer;
1213

@@ -33,9 +34,28 @@ concept std_random_access_iterator =
3334
))
3435
);
3536

37+
template<typename T>
38+
concept hashable = default_constructible<std::hash<T>>;
39+
40+
template<typename T, typename Key, typename Mapped>
41+
concept std_ordered_map_iterator =
42+
std::same_as<T, typename std::map<Key, Mapped>::iterator> or
43+
std::same_as<T, typename std::map<Key, Mapped>::const_iterator> or
44+
std::same_as<T, typename std::multimap<Key, Mapped>::iterator> or
45+
std::same_as<T, typename std::multimap<Key, Mapped>::const_iterator>;
46+
47+
template<typename T, typename Key, typename Mapped>
48+
concept std_unordered_map_iterator =
49+
hashable<Key> and (
50+
std::same_as<T, typename std::unordered_map<Key, Mapped>::iterator> or
51+
std::same_as<T, typename std::unordered_map<Key, Mapped>::const_iterator> or
52+
std::same_as<T, typename std::unordered_multimap<Key, Mapped>::iterator> or
53+
std::same_as<T, typename std::unordered_multimap<Key, Mapped>::const_iterator>
54+
);
55+
3656
template<
3757
typename T,
38-
typename value_type = std::remove_cvref_t<decltype(*declval<T>())>,
58+
typename value_type,
3959
typename key_type = typename value_type::first_type,
4060
typename mapped_type = typename value_type::second_type
4161
>
@@ -44,31 +64,31 @@ concept std_map_bidirectional_iterator =
4464
!std::is_reference_v<key_type> and !std::is_const_v<key_type> and
4565
!std::is_reference_v<mapped_type> and !std::is_const_v<mapped_type> and
4666
(
47-
std::same_as<T, typename std::map<key_type, mapped_type>::iterator> or
48-
std::same_as<T, typename std::map<key_type, mapped_type>::const_iterator> or
49-
std::same_as<T, typename std::multimap<key_type, mapped_type>::iterator> or
50-
std::same_as<T, typename std::multimap<key_type, mapped_type>::const_iterator> or
51-
std::same_as<T, typename std::unordered_map<key_type, mapped_type>::iterator> or
52-
std::same_as<T, typename std::unordered_map<key_type, mapped_type>::const_iterator> or
53-
std::same_as<T, typename std::unordered_multimap<key_type, mapped_type>::iterator> or
54-
std::same_as<T, typename std::unordered_multimap<key_type, mapped_type>::const_iterator>
67+
std_ordered_map_iterator<T, key_type, mapped_type> or
68+
std_unordered_map_iterator<T, key_type, mapped_type>
69+
);
70+
71+
template<typename T, typename value_type>
72+
concept std_unordered_set_iterator =
73+
hashable<value_type> and (
74+
std::same_as<T, typename std::unordered_set<value_type>::iterator> or
75+
std::same_as<T, typename std::unordered_set<value_type>::const_iterator> or
76+
std::same_as<T, typename std::unordered_multiset<value_type>::iterator> or
77+
std::same_as<T, typename std::unordered_multiset<value_type>::const_iterator>
5578
);
5679

5780
template<typename T, typename value_type = std::remove_cvref_t<decltype(*declval<T>())>>
5881
concept std_bidirectional_iterator =
5982
!std::is_void_v<value_type> and !std::is_reference_v<value_type> and !std::is_const_v<value_type> and (
6083
std_random_access_iterator<T> or
61-
std_map_bidirectional_iterator<T> or
84+
std_map_bidirectional_iterator<T, value_type> or
85+
std_unordered_set_iterator<T, value_type> or
6286
std::same_as<T, typename std::list<value_type>::iterator> or
6387
std::same_as<T, typename std::list<value_type>::const_iterator> or
6488
std::same_as<T, typename std::set<value_type>::iterator> or
6589
std::same_as<T, typename std::set<value_type>::const_iterator> or
6690
std::same_as<T, typename std::multiset<value_type>::iterator> or
67-
std::same_as<T, typename std::multiset<value_type>::const_iterator> or
68-
std::same_as<T, typename std::unordered_set<value_type>::iterator> or
69-
std::same_as<T, typename std::unordered_set<value_type>::const_iterator> or
70-
std::same_as<T, typename std::unordered_multiset<value_type>::iterator> or
71-
std::same_as<T, typename std::unordered_multiset<value_type>::const_iterator>
91+
std::same_as<T, typename std::multiset<value_type>::const_iterator>
7292
);
7393

7494
template<typename T, typename value_type = std::remove_cvref_t<decltype(*declval<T>())>>
@@ -117,4 +137,16 @@ static_assert(bounded::std_iterator<std::vector<int>::iterator>);
117137

118138
static_assert(std::same_as<decltype(std::vector<int>::iterator() + bounded::constant<1>), std::vector<int>::iterator>);
119139

140+
struct iterator {
141+
struct value_type {
142+
};
143+
constexpr auto operator*() const -> value_type {
144+
return value_type();
145+
}
146+
constexpr auto operator++() & -> iterator & {
147+
return *this;
148+
}
149+
};
150+
static_assert(!bounded::std_iterator<iterator>);
151+
120152
} // namespace

0 commit comments

Comments
 (0)