Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qduplicatetracker_p.h
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
5#ifndef QDUPLICATETRACKER_P_H
6#define QDUPLICATETRACKER_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <private/qglobal_p.h>
20
21#ifdef __cpp_lib_memory_resource
22# include <unordered_set>
23# include <memory_resource>
24# include <qhash.h> // for the hashing helpers
25#else
26# include <qset.h>
27#endif
28
30
31template <typename T, size_t Prealloc = 32>
32class QDuplicateTracker {
33#ifdef __cpp_lib_memory_resource
34 template <typename HT>
35 struct QHasher {
36 size_t storedSeed = QHashSeed::globalSeed();
37 size_t operator()(const HT &t) const {
38 return QHashPrivate::calculateHash(t, storedSeed);
39 }
40 };
41
42 struct node_guesstimate { void *next; size_t hash; T value; };
43 static constexpr size_t bufferSize(size_t N) {
44 return N * sizeof(void*) // bucket list
45 + N * sizeof(node_guesstimate); // nodes
46 }
47
48 char buffer[bufferSize(Prealloc)];
49 std::pmr::monotonic_buffer_resource res{buffer, sizeof buffer};
50 using Set = std::pmr::unordered_set<T, QHasher<T>>;
51 Set set{Prealloc, &res};
52#else
53 class Set : public QSet<T> {
54 qsizetype setSize = 0;
55 public:
56 explicit Set(qsizetype n) : QSet<T>{}
57 { this->reserve(n); }
58
59 auto insert(const T &e) {
60 auto it = QSet<T>::insert(e);
61 const auto n = this->size();
62 return std::pair{it, std::exchange(setSize, n) != n};
63 }
64
65 auto insert(T &&e) {
66 auto it = QSet<T>::insert(std::move(e));
67 const auto n = this->size();
68 return std::pair{it, std::exchange(setSize, n) != n};
69 }
70 };
71 Set set{Prealloc};
72#endif
73 Q_DISABLE_COPY_MOVE(QDuplicateTracker)
74public:
75 static constexpr inline bool uses_pmr =
76 #ifdef __cpp_lib_memory_resource
77 true
78 #else
79 false
80 #endif
81 ;
82 QDuplicateTracker() {} // don't `= default`, lest we value-initialize `buffer`
83 explicit QDuplicateTracker(qsizetype n)
84#ifdef __cpp_lib_memory_resource
85 : set{size_t(n), &res}
86#else
87 : set{n}
88#endif
89 {}
90 Q_DECL_DEPRECATED_X("Pass the capacity to reserve() to the ctor instead.")
91 void reserve(qsizetype n) { set.reserve(n); }
92 [[nodiscard]] bool hasSeen(const T &s)
93 {
94 return !set.insert(s).second;
95 }
96 [[nodiscard]] bool hasSeen(T &&s)
97 {
98 return !set.insert(std::move(s)).second;
99 }
100 // For when you want to know, but aren't *yet* sure you'll add it:
101 [[nodiscard]] bool contains(const T &s) const
102 {
103 return set.find(s) != set.end(); // TODO C++20: can use set.contains()
104 }
105
106 template <typename C>
107 void appendTo(C &c) const &
108 {
109 for (const auto &e : set)
110 c.push_back(e);
111 }
112
113 template <typename C>
114 void appendTo(C &c) &&
115 {
116 if constexpr (uses_pmr) {
117 while (!set.empty())
118 c.push_back(std::move(set.extract(set.begin()).value()));
119 } else {
120 return appendTo(c); // lvalue version
121 }
122 }
123
124 void clear()
125 {
126#ifdef __cpp_lib_memory_resource
127 // The birth defect of std::unordered_set is that both the nodes as
128 // well as the bucket array are allocated from the same allocator, so
129 // if we want to reclaim memory from the freed nodes, we also need to
130 // reclaim the memory for the bucket array.
131
132 set = Set(); // release all memory in `res` (clear() doesn't, and swap() is UB!)
133 res.release(); // restore to initial state (buffer, sizeof buffer)
134 // m_b_r can't reuse buffers, anyway
135 // now that `res` is reset to the initial state, also reset `set`:
136 set = Set{Prealloc, &res};
137#else
138 set.clear();
139#endif // __cpp_lib_memory_resource
140 }
141
142 using const_iterator = typename Set::const_iterator;
143 const_iterator begin() const { return set.cbegin(); }
144 const_iterator end() const { return set.cend(); }
145 const_iterator cbegin() const { return begin(); }
146 const_iterator cend() const { return end(); }
147};
148
149QT_END_NAMESPACE
150
151#endif /* QDUPLICATETRACKER_P_H */
Combined button and popup list for selecting options.