1/* Fast open-addressing concurrent hashset.
2 *
3 * Copyright 2023 Christian Mazakas.
4 * Copyright 2023 Joaquin M Lopez Munoz.
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE_1_0.txt or copy at
7 * http://www.boost.org/LICENSE_1_0.txt)
8 *
9 * See https://www.boost.org/libs/unordered for library home page.
10 */
11
12#ifndef BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP
13#define BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP
14
15#include <boost/unordered/concurrent_flat_set_fwd.hpp>
16#include <boost/unordered/detail/concurrent_static_asserts.hpp>
17#include <boost/unordered/detail/foa/concurrent_table.hpp>
18#include <boost/unordered/detail/foa/flat_set_types.hpp>
19#include <boost/unordered/detail/type_traits.hpp>
20#include <boost/unordered/unordered_flat_set_fwd.hpp>
21
22#include <boost/container_hash/hash.hpp>
23#include <boost/core/allocator_access.hpp>
24#include <boost/core/serialization.hpp>
25
26#include <utility>
27
28namespace boost {
29 namespace unordered {
30 template <class Key, class Hash, class Pred, class Allocator>
31 class concurrent_flat_set
32 {
33 private:
34 template <class Key2, class Hash2, class Pred2, class Allocator2>
35 friend class concurrent_flat_set;
36 template <class Key2, class Hash2, class Pred2, class Allocator2>
37 friend class unordered_flat_set;
38
39 using type_policy = detail::foa::flat_set_types<Key>;
40
41 using table_type =
42 detail::foa::concurrent_table<type_policy, Hash, Pred, Allocator>;
43
44 table_type table_;
45
46 template <class K, class H, class KE, class A>
47 bool friend operator==(concurrent_flat_set<K, H, KE, A> const& lhs,
48 concurrent_flat_set<K, H, KE, A> const& rhs);
49
50 template <class K, class H, class KE, class A, class Predicate>
51 friend typename concurrent_flat_set<K, H, KE, A>::size_type erase_if(
52 concurrent_flat_set<K, H, KE, A>& set, Predicate pred);
53
54 template<class Archive, class K, class H, class KE, class A>
55 friend void serialize(
56 Archive& ar, concurrent_flat_set<K, H, KE, A>& c,
57 unsigned int version);
58
59 public:
60 using key_type = Key;
61 using value_type = typename type_policy::value_type;
62 using init_type = typename type_policy::init_type;
63 using size_type = std::size_t;
64 using difference_type = std::ptrdiff_t;
65 using hasher = typename boost::unordered::detail::type_identity<Hash>::type;
66 using key_equal = typename boost::unordered::detail::type_identity<Pred>::type;
67 using allocator_type = typename boost::unordered::detail::type_identity<Allocator>::type;
68 using reference = value_type&;
69 using const_reference = value_type const&;
70 using pointer = typename boost::allocator_pointer<allocator_type>::type;
71 using const_pointer =
72 typename boost::allocator_const_pointer<allocator_type>::type;
73 static constexpr size_type bulk_visit_size = table_type::bulk_visit_size;
74
75 concurrent_flat_set()
76 : concurrent_flat_set(detail::foa::default_bucket_count)
77 {
78 }
79
80 explicit concurrent_flat_set(size_type n, const hasher& hf = hasher(),
81 const key_equal& eql = key_equal(),
82 const allocator_type& a = allocator_type())
83 : table_(n, hf, eql, a)
84 {
85 }
86
87 template <class InputIterator>
88 concurrent_flat_set(InputIterator f, InputIterator l,
89 size_type n = detail::foa::default_bucket_count,
90 const hasher& hf = hasher(), const key_equal& eql = key_equal(),
91 const allocator_type& a = allocator_type())
92 : table_(n, hf, eql, a)
93 {
94 this->insert(f, l);
95 }
96
97 concurrent_flat_set(concurrent_flat_set const& rhs)
98 : table_(rhs.table_,
99 boost::allocator_select_on_container_copy_construction(
100 rhs.get_allocator()))
101 {
102 }
103
104 concurrent_flat_set(concurrent_flat_set&& rhs)
105 : table_(std::move(rhs.table_))
106 {
107 }
108
109 template <class InputIterator>
110 concurrent_flat_set(
111 InputIterator f, InputIterator l, allocator_type const& a)
112 : concurrent_flat_set(f, l, 0, hasher(), key_equal(), a)
113 {
114 }
115
116 explicit concurrent_flat_set(allocator_type const& a)
117 : table_(detail::foa::default_bucket_count, hasher(), key_equal(), a)
118 {
119 }
120
121 concurrent_flat_set(
122 concurrent_flat_set const& rhs, allocator_type const& a)
123 : table_(rhs.table_, a)
124 {
125 }
126
127 concurrent_flat_set(concurrent_flat_set&& rhs, allocator_type const& a)
128 : table_(std::move(rhs.table_), a)
129 {
130 }
131
132 concurrent_flat_set(std::initializer_list<value_type> il,
133 size_type n = detail::foa::default_bucket_count,
134 const hasher& hf = hasher(), const key_equal& eql = key_equal(),
135 const allocator_type& a = allocator_type())
136 : concurrent_flat_set(n, hf, eql, a)
137 {
138 this->insert(il.begin(), il.end());
139 }
140
141 concurrent_flat_set(size_type n, const allocator_type& a)
142 : concurrent_flat_set(n, hasher(), key_equal(), a)
143 {
144 }
145
146 concurrent_flat_set(
147 size_type n, const hasher& hf, const allocator_type& a)
148 : concurrent_flat_set(n, hf, key_equal(), a)
149 {
150 }
151
152 template <typename InputIterator>
153 concurrent_flat_set(
154 InputIterator f, InputIterator l, size_type n, const allocator_type& a)
155 : concurrent_flat_set(f, l, n, hasher(), key_equal(), a)
156 {
157 }
158
159 template <typename InputIterator>
160 concurrent_flat_set(InputIterator f, InputIterator l, size_type n,
161 const hasher& hf, const allocator_type& a)
162 : concurrent_flat_set(f, l, n, hf, key_equal(), a)
163 {
164 }
165
166 concurrent_flat_set(
167 std::initializer_list<value_type> il, const allocator_type& a)
168 : concurrent_flat_set(
169 il, detail::foa::default_bucket_count, hasher(), key_equal(), a)
170 {
171 }
172
173 concurrent_flat_set(std::initializer_list<value_type> il, size_type n,
174 const allocator_type& a)
175 : concurrent_flat_set(il, n, hasher(), key_equal(), a)
176 {
177 }
178
179 concurrent_flat_set(std::initializer_list<value_type> il, size_type n,
180 const hasher& hf, const allocator_type& a)
181 : concurrent_flat_set(il, n, hf, key_equal(), a)
182 {
183 }
184
185
186 concurrent_flat_set(
187 unordered_flat_set<Key, Hash, Pred, Allocator>&& other)
188 : table_(std::move(other.table_))
189 {
190 }
191
192 ~concurrent_flat_set() = default;
193
194 concurrent_flat_set& operator=(concurrent_flat_set const& rhs)
195 {
196 table_ = rhs.table_;
197 return *this;
198 }
199
200 concurrent_flat_set& operator=(concurrent_flat_set&& rhs)
201 noexcept(boost::allocator_is_always_equal<Allocator>::type::value ||
202 boost::allocator_propagate_on_container_move_assignment<
203 Allocator>::type::value)
204 {
205 table_ = std::move(rhs.table_);
206 return *this;
207 }
208
209 concurrent_flat_set& operator=(std::initializer_list<value_type> ilist)
210 {
211 table_ = ilist;
212 return *this;
213 }
214
215 /// Capacity
216 ///
217
218 size_type size() const noexcept { return table_.size(); }
219 size_type max_size() const noexcept { return table_.max_size(); }
220
221 BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
222 {
223 return size() == 0;
224 }
225
226 template <class F>
227 BOOST_FORCEINLINE size_type visit(key_type const& k, F f) const
228 {
229 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
230 return table_.visit(k, f);
231 }
232
233 template <class F>
234 BOOST_FORCEINLINE size_type cvisit(key_type const& k, F f) const
235 {
236 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
237 return table_.visit(k, f);
238 }
239
240 template <class K, class F>
241 BOOST_FORCEINLINE typename std::enable_if<
242 detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
243 visit(K&& k, F f) const
244 {
245 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
246 return table_.visit(std::forward<K>(k), f);
247 }
248
249 template <class K, class F>
250 BOOST_FORCEINLINE typename std::enable_if<
251 detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
252 cvisit(K&& k, F f) const
253 {
254 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
255 return table_.visit(std::forward<K>(k), f);
256 }
257
258 template<class FwdIterator, class F>
259 BOOST_FORCEINLINE
260 size_t visit(FwdIterator first, FwdIterator last, F f) const
261 {
262 BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
263 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
264 return table_.visit(first, last, f);
265 }
266
267 template<class FwdIterator, class F>
268 BOOST_FORCEINLINE
269 size_t cvisit(FwdIterator first, FwdIterator last, F f) const
270 {
271 BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
272 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
273 return table_.visit(first, last, f);
274 }
275
276 template <class F> size_type visit_all(F f) const
277 {
278 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
279 return table_.visit_all(f);
280 }
281
282 template <class F> size_type cvisit_all(F f) const
283 {
284 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
285 return table_.cvisit_all(f);
286 }
287
288#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
289 template <class ExecPolicy, class F>
290 typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
291 void>::type
292 visit_all(ExecPolicy&& p, F f) const
293 {
294 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
295 BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
296 table_.visit_all(p, f);
297 }
298
299 template <class ExecPolicy, class F>
300 typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
301 void>::type
302 cvisit_all(ExecPolicy&& p, F f) const
303 {
304 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
305 BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
306 table_.cvisit_all(p, f);
307 }
308#endif
309
310 template <class F> bool visit_while(F f) const
311 {
312 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
313 return table_.visit_while(f);
314 }
315
316 template <class F> bool cvisit_while(F f) const
317 {
318 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
319 return table_.cvisit_while(f);
320 }
321
322#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
323 template <class ExecPolicy, class F>
324 typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
325 bool>::type
326 visit_while(ExecPolicy&& p, F f) const
327 {
328 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
329 BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
330 return table_.visit_while(p, f);
331 }
332
333 template <class ExecPolicy, class F>
334 typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
335 bool>::type
336 cvisit_while(ExecPolicy&& p, F f) const
337 {
338 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
339 BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
340 return table_.cvisit_while(p, f);
341 }
342#endif
343
344 /// Modifiers
345 ///
346
347 BOOST_FORCEINLINE bool insert(value_type const& obj)
348 {
349 return table_.insert(obj);
350 }
351
352 BOOST_FORCEINLINE bool insert(value_type&& obj)
353 {
354 return table_.insert(std::move(obj));
355 }
356
357 template <class K>
358 BOOST_FORCEINLINE typename std::enable_if<
359 detail::are_transparent<K, hasher, key_equal>::value,
360 bool >::type
361 insert(K&& k)
362 {
363 return table_.try_emplace(std::forward<K>(k));
364 }
365
366 template <class InputIterator>
367 void insert(InputIterator begin, InputIterator end)
368 {
369 for (auto pos = begin; pos != end; ++pos) {
370 table_.emplace(*pos);
371 }
372 }
373
374 void insert(std::initializer_list<value_type> ilist)
375 {
376 this->insert(ilist.begin(), ilist.end());
377 }
378
379 template <class F>
380 BOOST_FORCEINLINE bool insert_or_visit(value_type const& obj, F f)
381 {
382 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
383 return table_.insert_or_cvisit(obj, f);
384 }
385
386 template <class F>
387 BOOST_FORCEINLINE bool insert_or_visit(value_type&& obj, F f)
388 {
389 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
390 return table_.insert_or_cvisit(std::move(obj), f);
391 }
392
393 template <class K, class F>
394 BOOST_FORCEINLINE typename std::enable_if<
395 detail::are_transparent<K, hasher, key_equal>::value,
396 bool >::type
397 insert_or_visit(K&& k, F f)
398 {
399 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
400 return table_.try_emplace_or_cvisit(std::forward<K>(k), f);
401 }
402
403 template <class InputIterator, class F>
404 void insert_or_visit(InputIterator first, InputIterator last, F f)
405 {
406 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
407 for (; first != last; ++first) {
408 table_.emplace_or_cvisit(*first, f);
409 }
410 }
411
412 template <class F>
413 void insert_or_visit(std::initializer_list<value_type> ilist, F f)
414 {
415 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
416 this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
417 }
418
419 template <class F>
420 BOOST_FORCEINLINE bool insert_or_cvisit(value_type const& obj, F f)
421 {
422 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
423 return table_.insert_or_cvisit(obj, f);
424 }
425
426 template <class F>
427 BOOST_FORCEINLINE bool insert_or_cvisit(value_type&& obj, F f)
428 {
429 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
430 return table_.insert_or_cvisit(std::move(obj), f);
431 }
432
433 template <class K, class F>
434 BOOST_FORCEINLINE typename std::enable_if<
435 detail::are_transparent<K, hasher, key_equal>::value,
436 bool >::type
437 insert_or_cvisit(K&& k, F f)
438 {
439 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
440 return table_.try_emplace_or_cvisit(std::forward<K>(k), f);
441 }
442
443 template <class InputIterator, class F>
444 void insert_or_cvisit(InputIterator first, InputIterator last, F f)
445 {
446 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
447 for (; first != last; ++first) {
448 table_.emplace_or_cvisit(*first, f);
449 }
450 }
451
452 template <class F>
453 void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
454 {
455 BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
456 this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
457 }
458
459 template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
460 {
461 return table_.emplace(std::forward<Args>(args)...);
462 }
463
464 template <class Arg, class... Args>
465 BOOST_FORCEINLINE bool emplace_or_visit(Arg&& arg, Args&&... args)
466 {
467 BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
468 return table_.emplace_or_cvisit(
469 std::forward<Arg>(arg), std::forward<Args>(args)...);
470 }
471
472 template <class Arg, class... Args>
473 BOOST_FORCEINLINE bool emplace_or_cvisit(Arg&& arg, Args&&... args)
474 {
475 BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
476 return table_.emplace_or_cvisit(
477 std::forward<Arg>(arg), std::forward<Args>(args)...);
478 }
479
480 BOOST_FORCEINLINE size_type erase(key_type const& k)
481 {
482 return table_.erase(k);
483 }
484
485 template <class K>
486 BOOST_FORCEINLINE typename std::enable_if<
487 detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
488 erase(K&& k)
489 {
490 return table_.erase(std::forward<K>(k));
491 }
492
493 template <class F>
494 BOOST_FORCEINLINE size_type erase_if(key_type const& k, F f)
495 {
496 return table_.erase_if(k, f);
497 }
498
499 template <class K, class F>
500 BOOST_FORCEINLINE typename std::enable_if<
501 detail::are_transparent<K, hasher, key_equal>::value &&
502 !detail::is_execution_policy<K>::value,
503 size_type>::type
504 erase_if(K&& k, F f)
505 {
506 return table_.erase_if(std::forward<K>(k), f);
507 }
508
509#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
510 template <class ExecPolicy, class F>
511 typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
512 void>::type
513 erase_if(ExecPolicy&& p, F f)
514 {
515 BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
516 table_.erase_if(p, f);
517 }
518#endif
519
520 template <class F> size_type erase_if(F f) { return table_.erase_if(f); }
521
522 void swap(concurrent_flat_set& other) noexcept(
523 boost::allocator_is_always_equal<Allocator>::type::value ||
524 boost::allocator_propagate_on_container_swap<Allocator>::type::value)
525 {
526 return table_.swap(other.table_);
527 }
528
529 void clear() noexcept { table_.clear(); }
530
531 template <typename H2, typename P2>
532 size_type merge(concurrent_flat_set<Key, H2, P2, Allocator>& x)
533 {
534 BOOST_ASSERT(get_allocator() == x.get_allocator());
535 return table_.merge(x.table_);
536 }
537
538 template <typename H2, typename P2>
539 size_type merge(concurrent_flat_set<Key, H2, P2, Allocator>&& x)
540 {
541 return merge(x);
542 }
543
544 BOOST_FORCEINLINE size_type count(key_type const& k) const
545 {
546 return table_.count(k);
547 }
548
549 template <class K>
550 BOOST_FORCEINLINE typename std::enable_if<
551 detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
552 count(K const& k)
553 {
554 return table_.count(k);
555 }
556
557 BOOST_FORCEINLINE bool contains(key_type const& k) const
558 {
559 return table_.contains(k);
560 }
561
562 template <class K>
563 BOOST_FORCEINLINE typename std::enable_if<
564 detail::are_transparent<K, hasher, key_equal>::value, bool>::type
565 contains(K const& k) const
566 {
567 return table_.contains(k);
568 }
569
570 /// Hash Policy
571 ///
572 size_type bucket_count() const noexcept { return table_.capacity(); }
573
574 float load_factor() const noexcept { return table_.load_factor(); }
575 float max_load_factor() const noexcept
576 {
577 return table_.max_load_factor();
578 }
579 void max_load_factor(float) {}
580 size_type max_load() const noexcept { return table_.max_load(); }
581
582 void rehash(size_type n) { table_.rehash(n); }
583 void reserve(size_type n) { table_.reserve(n); }
584
585 /// Observers
586 ///
587 allocator_type get_allocator() const noexcept
588 {
589 return table_.get_allocator();
590 }
591
592 hasher hash_function() const { return table_.hash_function(); }
593 key_equal key_eq() const { return table_.key_eq(); }
594 };
595
596 template <class Key, class Hash, class KeyEqual, class Allocator>
597 bool operator==(
598 concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
599 concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
600 {
601 return lhs.table_ == rhs.table_;
602 }
603
604 template <class Key, class Hash, class KeyEqual, class Allocator>
605 bool operator!=(
606 concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
607 concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
608 {
609 return !(lhs == rhs);
610 }
611
612 template <class Key, class Hash, class Pred, class Alloc>
613 void swap(concurrent_flat_set<Key, Hash, Pred, Alloc>& x,
614 concurrent_flat_set<Key, Hash, Pred, Alloc>& y)
615 noexcept(noexcept(x.swap(y)))
616 {
617 x.swap(y);
618 }
619
620 template <class K, class H, class P, class A, class Predicate>
621 typename concurrent_flat_set<K, H, P, A>::size_type erase_if(
622 concurrent_flat_set<K, H, P, A>& c, Predicate pred)
623 {
624 return c.table_.erase_if(pred);
625 }
626
627 template<class Archive, class K, class H, class KE, class A>
628 void serialize(
629 Archive& ar, concurrent_flat_set<K, H, KE, A>& c, unsigned int)
630 {
631 ar & core::make_nvp("table",c.table_);
632 }
633
634#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
635
636 template <class InputIterator,
637 class Hash =
638 boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
639 class Pred =
640 std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
641 class Allocator = std::allocator<
642 typename std::iterator_traits<InputIterator>::value_type>,
643 class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
644 class = std::enable_if_t<detail::is_hash_v<Hash> >,
645 class = std::enable_if_t<detail::is_pred_v<Pred> >,
646 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
647 concurrent_flat_set(InputIterator, InputIterator,
648 std::size_t = boost::unordered::detail::foa::default_bucket_count,
649 Hash = Hash(), Pred = Pred(), Allocator = Allocator())
650 -> concurrent_flat_set<
651 typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
652 Allocator>;
653
654 template <class T, class Hash = boost::hash<T>,
655 class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
656 class = std::enable_if_t<detail::is_hash_v<Hash> >,
657 class = std::enable_if_t<detail::is_pred_v<Pred> >,
658 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
659 concurrent_flat_set(std::initializer_list<T>,
660 std::size_t = boost::unordered::detail::foa::default_bucket_count,
661 Hash = Hash(), Pred = Pred(), Allocator = Allocator())
662 -> concurrent_flat_set< T, Hash, Pred, Allocator>;
663
664 template <class InputIterator, class Allocator,
665 class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
666 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
667 concurrent_flat_set(InputIterator, InputIterator, std::size_t, Allocator)
668 -> concurrent_flat_set<
669 typename std::iterator_traits<InputIterator>::value_type,
670 boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
671 std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
672 Allocator>;
673
674 template <class InputIterator, class Allocator,
675 class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
676 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
677 concurrent_flat_set(InputIterator, InputIterator, Allocator)
678 -> concurrent_flat_set<
679 typename std::iterator_traits<InputIterator>::value_type,
680 boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
681 std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
682 Allocator>;
683
684 template <class InputIterator, class Hash, class Allocator,
685 class = std::enable_if_t<detail::is_hash_v<Hash> >,
686 class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
687 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
688 concurrent_flat_set(
689 InputIterator, InputIterator, std::size_t, Hash, Allocator)
690 -> concurrent_flat_set<
691 typename std::iterator_traits<InputIterator>::value_type, Hash,
692 std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
693 Allocator>;
694
695 template <class T, class Allocator,
696 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
697 concurrent_flat_set(std::initializer_list<T>, std::size_t, Allocator)
698 -> concurrent_flat_set<T, boost::hash<T>,std::equal_to<T>, Allocator>;
699
700 template <class T, class Allocator,
701 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
702 concurrent_flat_set(std::initializer_list<T >, Allocator)
703 -> concurrent_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
704
705 template <class T, class Hash, class Allocator,
706 class = std::enable_if_t<detail::is_hash_v<Hash> >,
707 class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
708 concurrent_flat_set(std::initializer_list<T >, std::size_t,Hash, Allocator)
709 -> concurrent_flat_set<T, Hash, std::equal_to<T>, Allocator>;
710
711#endif
712
713 } // namespace unordered
714} // namespace boost
715
716#endif // BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP
717

source code of boost/libs/unordered/include/boost/unordered/concurrent_flat_set.hpp