Skip to content

Commit 053a947

Browse files
committed
[flat_set] C++14 style transparent lookups
1 parent 15c721a commit 053a947

File tree

2 files changed

+32
-75
lines changed

2 files changed

+32
-75
lines changed

include/itlib/flat_set.hpp

+31-74
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
//
2929
// VERSION HISTORY
3030
//
31+
// 1.04 (2022-06-23) Transparent lookups (C++14 style)
3132
// 1.03 (2022-04-14) Noxcept move construct and assign
3233
// 1.02 (2021-09-28) Fixed construction from std::initializer_list which
3334
// allowed duplicate elements to find their wey in the set
@@ -68,21 +69,6 @@
6869
// > myset
6970
//
7071
//
71-
// Configuration
72-
//
73-
// itlib::flat_set has a single configurable setting:
74-
//
75-
// const char* overloads
76-
// By default itlib::flat_set provides overloads for the access methods
77-
// (find, lower_bound, count) for const char* for cases when
78-
// std::string is the key, so that no allocations happen when accessing with
79-
// a C-string of a string literal.
80-
// However if const char* or any other class with implicit conversion from
81-
// const char* is the key, they won't compile.
82-
// If you plan on using flat_set with such keys, you'll need to define
83-
// ITLIB_FLAT_SET_NO_CONST_CHAR_OVERLOADS before including the header
84-
//
85-
//
8672
// TESTS
8773
//
8874
// You can find unit tests for static_vector in its official repo:
@@ -94,14 +80,22 @@
9480
#include <algorithm>
9581
#include <type_traits>
9682

97-
#if !defined(ITLIB_FLAT_SET_NO_CONST_CHAR_OVERLOADS)
98-
#include <cstring>
99-
#endif
100-
10183
namespace itlib
10284
{
10385

104-
template <typename Key, typename Compare = std::less<Key>, typename Container = std::vector<Key>>
86+
namespace impl
87+
{
88+
struct less
89+
{
90+
template <typename T, typename U>
91+
auto operator()(const T& t, const U& u) const -> decltype(t < u)
92+
{
93+
return t < u;
94+
}
95+
};
96+
}
97+
98+
template <typename Key, typename Compare = impl::less, typename Container = std::vector<Key>>
10599
class flat_set
106100
{
107101
public:
@@ -172,17 +166,20 @@ class flat_set
172166

173167
void clear() noexcept { m_container.clear(); }
174168

175-
iterator lower_bound(const key_type& k)
169+
template <typename F>
170+
iterator lower_bound(const F& k)
176171
{
177172
return std::lower_bound(m_container.begin(), m_container.end(), k, m_cmp);
178173
}
179174

180-
const_iterator lower_bound(const key_type& k) const
175+
template <typename F>
176+
const_iterator lower_bound(const F& k) const
181177
{
182178
return std::lower_bound(m_container.begin(), m_container.end(), k, m_cmp);
183179
}
184180

185-
iterator find(const key_type& k)
181+
template <typename F>
182+
iterator find(const F& k)
186183
{
187184
auto i = lower_bound(k);
188185
if (i != end() && !m_cmp(k, *i))
@@ -191,7 +188,8 @@ class flat_set
191188
return end();
192189
}
193190

194-
const_iterator find(const key_type& k) const
191+
template <typename F>
192+
const_iterator find(const F& k) const
195193
{
196194
auto i = lower_bound(k);
197195
if (i != end() && !m_cmp(k, *i))
@@ -200,7 +198,8 @@ class flat_set
200198
return end();
201199
}
202200

203-
size_t count(const key_type& k) const
201+
template <typename F>
202+
size_t count(const F& k) const
204203
{
205204
return find(k) == end() ? 0 : 1;
206205
}
@@ -240,7 +239,13 @@ class flat_set
240239
return m_container.erase(pos);
241240
}
242241

243-
size_type erase(const key_type& k)
242+
iterator erase(iterator pos)
243+
{
244+
return erase(const_iterator(pos));
245+
}
246+
247+
template <typename F>
248+
size_type erase(const F& k)
244249
{
245250
auto i = find(k);
246251
if (i == end())
@@ -269,54 +274,6 @@ class flat_set
269274
return m_container;
270275
}
271276

272-
#if !defined(ITLIB_FLAT_SET_NO_CONST_CHAR_OVERLOADS)
273-
///////////////////////////////////////////////////////////////////////////////////
274-
// const char* overloads for sets with an std::string key to avoid allocs
275-
iterator lower_bound(const char* k)
276-
{
277-
static_assert(std::is_same<std::string, key_type>::value, "flat_set::lower_bound(const char*) works only for std::strings");
278-
static_assert(std::is_same<std::less<std::string>, key_compare>::value, "flat_set::lower_bound(const char*) works only for std::string-s, compared with std::less<std::string>");
279-
return std::lower_bound(m_container.begin(), m_container.end(), k, [](const value_type& a, const char* b) -> bool
280-
{
281-
return strcmp(a.c_str(), b) < 0;
282-
});
283-
}
284-
285-
const_iterator lower_bound(const char* k) const
286-
{
287-
static_assert(std::is_same<std::string, key_type>::value, "flat_set::lower_bound(const char*) works only for std::strings");
288-
static_assert(std::is_same<std::less<std::string>, key_compare>::value, "flat_set::lower_bound(const char*) works only for std::string-s, compared with std::less<std::string>");
289-
return std::lower_bound(m_container.begin(), m_container.end(), k, [](const value_type& a, const char* b) -> bool
290-
{
291-
return strcmp(a.c_str(), b) < 0;
292-
});
293-
}
294-
295-
iterator find(const char* k)
296-
{
297-
auto i = lower_bound(k);
298-
if (i != end() && *i == k)
299-
return i;
300-
301-
return end();
302-
}
303-
304-
const_iterator find(const char* k) const
305-
{
306-
auto i = lower_bound(k);
307-
if (i != end() && *i == k)
308-
return i;
309-
310-
return end();
311-
}
312-
313-
size_t count(const char* k) const
314-
{
315-
return find(k) == end() ? 0 : 1;
316-
}
317-
318-
#endif // !defined(ITLIB_FLAT_SET_NO_CONST_CHAR_OVERLOADS)
319-
320277
private:
321278
key_compare m_cmp;
322279
container_type m_container;

test/t-flat_set-11.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ TEST_CASE("[flat_set] test")
166166
CHECK(m2.capacity() == m1c);
167167
}
168168

169-
TEST_CASE("[flat_map] initialize")
169+
TEST_CASE("[flat_set] initialize")
170170
{
171171
using namespace itlib;
172172
flat_set<int> m1 = {5, 3, 23};

0 commit comments

Comments
 (0)