1// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#ifndef QDUPLICATETRACKER_P_H
4#define QDUPLICATETRACKER_P_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include <private/qglobal_p.h>
18
19#ifdef __cpp_lib_memory_resource
20# include <unordered_set>
21# include <memory_resource>
22# include <qhash.h> // for the hashing helpers
23#else
24# include <qset.h>
25#endif
26
27QT_BEGIN_NAMESPACE
28
29template <typename T, size_t Prealloc = 32>
30class QDuplicateTracker {
31#ifdef __cpp_lib_memory_resource
32 template <typename HT>
33 struct QHasher {
34 size_t storedSeed = QHashSeed::globalSeed();
35 size_t operator()(const HT &t) const {
36 return QHashPrivate::calculateHash(t, storedSeed);
37 }
38 };
39
40 struct node_guesstimate { void *next; size_t hash; T value; };
41 static constexpr size_t bufferSize(size_t N) {
42 return N * sizeof(void*) // bucket list
43 + N * sizeof(node_guesstimate); // nodes
44 }
45
46 char buffer[bufferSize(N: Prealloc)];
47 std::pmr::monotonic_buffer_resource res{buffer, sizeof buffer};
48 std::pmr::unordered_set<T, QHasher<T>> set{Prealloc, &res};
49#else
50 class Set : public QSet<T> {
51 qsizetype setSize = 0;
52 public:
53 explicit Set(qsizetype n) : QSet<T>{}
54 { this->reserve(n); }
55
56 auto insert(const T &e) {
57 auto it = QSet<T>::insert(e);
58 const auto n = this->size();
59 return std::pair{it, std::exchange(setSize, n) != n};
60 }
61
62 auto insert(T &&e) {
63 auto it = QSet<T>::insert(std::move(e));
64 const auto n = this->size();
65 return std::pair{it, std::exchange(setSize, n) != n};
66 }
67 };
68 Set set{Prealloc};
69#endif
70 Q_DISABLE_COPY_MOVE(QDuplicateTracker);
71public:
72 static constexpr inline bool uses_pmr =
73 #ifdef __cpp_lib_memory_resource
74 true
75 #else
76 false
77 #endif
78 ;
79 QDuplicateTracker() = default;
80 explicit QDuplicateTracker(qsizetype n)
81#ifdef __cpp_lib_memory_resource
82 : set{size_t(n), &res}
83#else
84 : set{n}
85#endif
86 {}
87 Q_DECL_DEPRECATED_X("Pass the capacity to reserve() to the ctor instead.")
88 void reserve(qsizetype n) { set.reserve(n); }
89 [[nodiscard]] bool hasSeen(const T &s)
90 {
91 return !set.insert(s).second;
92 }
93 [[nodiscard]] bool hasSeen(T &&s)
94 {
95 return !set.insert(std::move(s)).second;
96 }
97
98 template <typename C>
99 void appendTo(C &c) const &
100 {
101 for (const auto &e : set)
102 c.push_back(e);
103 }
104
105 template <typename C>
106 void appendTo(C &c) &&
107 {
108 if constexpr (uses_pmr) {
109 while (!set.empty())
110 c.push_back(std::move(set.extract(set.begin()).value()));
111 } else {
112 return appendTo(c); // lvalue version
113 }
114 }
115
116 void clear()
117 {
118 set.clear();
119 }
120};
121
122QT_END_NAMESPACE
123
124#endif /* QDUPLICATETRACKER_P_H */
125

source code of qtbase/src/corelib/tools/qduplicatetracker_p.h