OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 // --- |
| 6 // Author: Simon Que |
| 7 |
| 8 #ifndef _RANKED_LIST_H_ |
| 9 #define _RANKED_LIST_H_ |
| 10 |
| 11 #include <cstdio> |
| 12 #include <cstring> |
| 13 |
| 14 #include "base/basictypes.h" |
| 15 |
| 16 // RankedList lets you add entries and automatically sorts them internally, so |
| 17 // they can be accessed in sorted order. The entries are stored as a vector |
| 18 // array. |
| 19 |
| 20 namespace leak_detector { |
| 21 |
| 22 template <typename T> |
| 23 class RankedList { |
| 24 public: |
| 25 typedef void* (*Allocator)(size_t size); |
| 26 typedef void (*DeAllocator)(void* ptr); |
| 27 |
| 28 // A single entry in the RankedList. The RankedList sorts entries by |count|. |
| 29 struct Entry { |
| 30 int count; |
| 31 T value; |
| 32 }; |
| 33 |
| 34 RankedList(int max_size, Allocator alloc, DeAllocator dealloc); |
| 35 ~RankedList(); |
| 36 |
| 37 RankedList& operator=(const RankedList& other); |
| 38 |
| 39 // Access the array of entries. |
| 40 const Entry* entries() const { |
| 41 return entries_; |
| 42 } |
| 43 // Access individual element. Does not do boundary checking. |
| 44 const Entry& entry(int index) const { |
| 45 return entries_[index]; |
| 46 } |
| 47 const int size() const { |
| 48 return size_; |
| 49 } |
| 50 |
| 51 // Add a new value-count pair to the list. Does not check for existing entries |
| 52 // with the same value. |
| 53 void Add(const T& value, int count); |
| 54 |
| 55 private: |
| 56 // Returns the position to insert a new value. Returns -1 if it cannot be |
| 57 // inserted. |
| 58 int GetInsertionIndex(int count) const; |
| 59 |
| 60 // Max and min counts. |
| 61 const int max_count() const { |
| 62 if (size_ == 0) |
| 63 return 0; |
| 64 return entries_[0].count; |
| 65 } |
| 66 const int min_count() const { |
| 67 if (size_ == 0) |
| 68 return 0; |
| 69 return entries_[size_ - 1].count; |
| 70 } |
| 71 |
| 72 // For memory allocation. |
| 73 Allocator alloc_; |
| 74 DeAllocator dealloc_; |
| 75 |
| 76 // Max items in the list. |
| 77 int max_size_; |
| 78 |
| 79 // The current number of items in the list. |
| 80 int size_; |
| 81 |
| 82 // Points to the array of entries. |
| 83 Entry* entries_; |
| 84 }; |
| 85 |
| 86 template <typename T> |
| 87 RankedList<T>::RankedList(int max_size, Allocator alloc, DeAllocator dealloc) |
| 88 : alloc_(alloc), |
| 89 dealloc_(dealloc), |
| 90 max_size_(max_size), |
| 91 size_(0) { |
| 92 // Allocate array of elements, with an extra element at end as an overflow |
| 93 // bucket. |
| 94 size_t entries_size = sizeof(Entry) * (max_size + 1); |
| 95 entries_ = static_cast<Entry*>(alloc_(entries_size)); |
| 96 memset(entries_, 0, entries_size); |
| 97 } |
| 98 |
| 99 template <typename T> |
| 100 RankedList<T>::~RankedList() { |
| 101 dealloc_(entries_); |
| 102 entries_ = NULL; |
| 103 } |
| 104 |
| 105 template <typename T> |
| 106 RankedList<T>& RankedList<T>::operator=(const RankedList<T>& other) { |
| 107 // Delete currently allocated memory. |
| 108 dealloc_(entries_); |
| 109 entries_ = NULL; |
| 110 |
| 111 // Allocate the space for the new data. |
| 112 max_size_ = other.max_size_; |
| 113 size_t entries_size = sizeof(Entry) * (max_size_ + 1); |
| 114 entries_ = static_cast<Entry*>(alloc_(entries_size)); |
| 115 memset(entries_, 0, entries_size); |
| 116 |
| 117 // Copy over the new data. |
| 118 size_ = other.size_; |
| 119 memcpy(entries_, other.entries_, sizeof(Entry) * size_); |
| 120 } |
| 121 |
| 122 template <typename T> |
| 123 void RankedList<T>::Add(const T& value, int count) { |
| 124 // Determine where to insert the value. |
| 125 int index = GetInsertionIndex(count); |
| 126 if (index == -1) |
| 127 return; |
| 128 // Shift the other elements down. Use memmove to deal with source/dest |
| 129 // overlaps. |
| 130 memmove(&entries_[index + 1], &entries_[index], |
| 131 (size_ - index) * sizeof(Entry)); |
| 132 // Finally, insert the new entry. |
| 133 entries_[index].count = count; |
| 134 entries_[index].value = value; |
| 135 // Update size. |
| 136 if (size_ < max_size_) |
| 137 ++size_; |
| 138 } |
| 139 |
| 140 template <typename T> |
| 141 int RankedList<T>::GetInsertionIndex(int count) const { |
| 142 // If the list is full, do not add any entry with |count| if does not exceed |
| 143 // the lowest count of the entries in the list. |
| 144 if (size_ == max_size_ && count <= min_count()) |
| 145 return -1; |
| 146 // If larger than the current largest item, insert it before. |
| 147 if (count >= max_count()) |
| 148 return 0; |
| 149 // If smaller than the current smallest item, but the list is not full, |
| 150 // insert it after. |
| 151 if (count <= min_count()) |
| 152 return size_; |
| 153 |
| 154 // Otherwise it's somewhere in the middle, so look for it there. |
| 155 int min_pos = 0; |
| 156 int max_pos = size_ - 1; |
| 157 while (max_pos >= min_pos) { |
| 158 int midpoint = (max_pos + min_pos) / 2; |
| 159 if (count >= entries_[midpoint].count && |
| 160 count <= entries_[midpoint - 1].count) { |
| 161 return midpoint; |
| 162 } |
| 163 // The list is reverse sorted. |
| 164 if (entries_[midpoint].count >= count) |
| 165 min_pos = midpoint + 1; |
| 166 else |
| 167 max_pos = midpoint - 1; |
| 168 } |
| 169 return max_pos; |
| 170 } |
| 171 |
| 172 } // namespace leak_detector |
| 173 |
| 174 #endif // _RANKED_LIST_H_ |
OLD | NEW |