86 std::vector<std::pair<T, int64_t>>
GetMostFrequent(
int num_samples)
const;
102 Bucket* absl_nonnull bucket;
103 Item* absl_nullable next =
nullptr;
104 Item* absl_nullable prev =
nullptr;
113 Bucket* absl_nullable next =
nullptr;
114 Bucket* absl_nullable prev =
nullptr;
118 void RemoveIfEmpty(Bucket* absl_nonnull bucket) {
119 if (bucket->items.empty()) {
120 bucket_alloc_.Return(buckets_.erase(bucket));
124 void RemoveFromLinkedList(Item* absl_nonnull item) {
125 Bucket* absl_nonnull bucket = item->bucket;
126 item_alloc_.Return(bucket->items.erase(item));
127 RemoveIfEmpty(bucket);
130 Bucket* absl_nonnull GetBucketForCountOne() {
131 if (!buckets_.empty() && buckets_.back()->count == 1) {
132 return buckets_.back();
135 Bucket* absl_nonnull bucket = buckets_.insert_back(bucket_alloc_.New());
140 const int storage_size_;
146 using is_transparent = void;
147 size_t operator()(
const Item* absl_nonnull value)
const {
148 return Hash()(value->value);
150 size_t operator()(
const T& value)
const {
return Hash()(value); }
154 using is_transparent = void;
155 bool operator()(
const Item* absl_nonnull a,
156 const Item* absl_nonnull b)
const {
157 return Eq()(a->value, b->value);
159 bool operator()(
const Item* absl_nonnull a,
const T& b)
const {
160 return Eq()(a->value, b);
162 bool operator()(
const T& a,
const Item* absl_nonnull b)
const {
163 return Eq()(a, b->value);
166 absl::flat_hash_set<Item* absl_nonnull, HashItemPtr, EqItemPtr> item_ptr_set_;
198 if (buckets_.empty()) {
200 DCHECK(item_alloc_.empty());
201 DCHECK(item_ptr_set_.empty());
202 Bucket* absl_nonnull bucket = buckets_.insert_back(bucket_alloc_.New());
203 Item* absl_nonnull
const item =
204 bucket->items.insert_front(item_alloc_.New());
205 item->bucket = bucket;
206 item->value = std::move(value);
208 item_ptr_set_.emplace(item);
212 DCHECK(!buckets_.empty());
214 auto it = item_ptr_set_.find(value);
215 if (it == item_ptr_set_.end()) {
218 if (item_alloc_.full()) {
220 Bucket* absl_nonnull
const last_bucket = buckets_.back();
223 Item* absl_nonnull recycled_item = last_bucket->items.front();
225 item_ptr_set_.erase(recycled_item);
226 item_alloc_.Return(last_bucket->items.pop_front());
227 RemoveIfEmpty(last_bucket);
229 Bucket* absl_nonnull bucket = GetBucketForCountOne();
230 DCHECK_EQ(bucket->count, 1);
231 Item* absl_nonnull item = bucket->items.insert_back(item_alloc_.New());
232 item->value = std::move(value);
233 item->bucket = bucket;
234 item_ptr_set_.emplace_hint(it, item);
236 Item* absl_nonnull item = *it;
237 Bucket* absl_nonnull bucket = item->bucket;
238 ItemList& current_bucket_items = bucket->items;
239 const int64_t new_count = bucket->count + 1;
240 const bool no_bucket_for_new_count =
241 (bucket->prev ==
nullptr) || (bucket->prev->count > new_count);
242 if (no_bucket_for_new_count && current_bucket_items.
single()) {
246 bucket->count = new_count;
250 auto dangling_item = current_bucket_items.
erase(item);
252 Bucket* new_bucket =
nullptr;
253 if (bucket->prev && bucket->prev->count == new_count) {
254 new_bucket = bucket->prev;
257 new_bucket = buckets_.insert_before(bucket, bucket_alloc_.New());
258 new_bucket->count = new_count;
261 dangling_item->bucket = new_bucket;
262 new_bucket->items.
insert_back(std::move(dangling_item));
265 RemoveIfEmpty(bucket);
279 std::vector<std::pair<T, int64_t>> result;
280 result.reserve(num_samples);
281 if (!buckets_.empty()) {
282 for (Bucket* bucket = buckets_.front(); bucket; bucket = bucket->next) {
283 const int64_t count = bucket->count;
284 DCHECK(!bucket->items.empty());
285 for (Item* item = bucket->items.back(); item; item = item->prev) {
286 if (result.size() == num_samples)
return result;
287 result.emplace_back(item->value, count);