52template <
class T,
class Cmp = std::greater<T> >
78 enum State { UNORDERED, BOTTOM_KNOWN, HEAP_SORTED };
79 using UnsortedIterator =
typename std::vector<T>::const_iterator;
81 explicit TopN(
size_t limit) :
TopN(limit, Cmp()) {}
82 TopN(
size_t limit,
const Cmp& cmp) :
limit_(limit), cmp_(cmp) {}
83 size_t limit()
const {
return limit_; }
86 size_t size()
const {
return std::min(elements_.size(),
limit_); }
87 bool empty()
const {
return size() == 0; }
91 void reserve(
size_t n) { elements_.reserve(std::min(n,
limit_ + 1)); }
97 void push(
const T& v) { push(v,
nullptr); }
98 void push(
const T& v, T* dropped) { PushInternal(v, dropped); }
102 push(std::move(v),
nullptr);
104 void push(T&& v, T* dropped) {
105 PushInternal(std::move(v), dropped);
108 const T& peek_bottom();
113 std::vector<T>* Extract();
118 std::vector<T>* ExtractUnsorted();
123 std::vector<T>* ExtractNondestructive()
const;
132 void ExtractNondestructive(std::vector<T>* output)
const;
138 std::vector<T>* ExtractUnsortedNondestructive()
const;
148 void ExtractUnsortedNondestructive(std::vector<T>* output)
const;
152 UnsortedIterator unsorted_begin()
const {
return elements_.begin(); }
153 UnsortedIterator unsorted_end()
const {
return elements_.begin() +
size(); }
155 Cmp* comparator() {
return &cmp_; }
161 template <
typename U>
177 std::vector<T> elements_;
180 State state_ = UNORDERED;
184template <
class T,
class Cmp>
188 if (dropped) *dropped = std::forward<U>(v);
191 if (state_ != HEAP_SORTED) {
192 elements_.push_back(std::forward<U>(v));
193 if (state_ == UNORDERED || cmp_(elements_.back(), elements_.front())) {
202 swap(elements_.front(), elements_.back());
204 if (elements_.size() ==
limit_ + 1) {
206 std::make_heap(elements_.begin(), elements_.end(), cmp_);
207 if (dropped) *dropped = std::move(elements_.front());
208 std::pop_heap(elements_.begin(), elements_.end(), cmp_);
209 state_ = HEAP_SORTED;
213 if (cmp_(v, elements_.front())) {
217 elements_.back() = std::forward<U>(
225 std::pop_heap(elements_.begin(), elements_.end(), cmp_);
226 if (dropped) *dropped = std::move(elements_.back());
228 if (dropped) *dropped = std::forward<U>(v);
232template <
class T,
class Cmp>
233const T& TopN<T, Cmp>::peek_bottom() {
235 if (state_ == UNORDERED) {
237 int min_candidate = 0;
238 for (
size_t i = 1;
i < elements_.size(); ++
i) {
239 if (cmp_(elements_[min_candidate], elements_[i])) {
245 if (min_candidate != 0) {
247 swap(elements_[0], elements_[min_candidate]);
249 state_ = BOTTOM_KNOWN;
251 return elements_.front();
253template <
class T,
class Cmp>
254std::vector<T>* TopN<T, Cmp>::Extract() {
255 auto out =
new std::vector<T>;
256 out->swap(elements_);
257 if (state_ != HEAP_SORTED) {
258 std::sort(out->begin(), out->end(), cmp_);
261 std::sort_heap(out->begin(), out->end(), cmp_);
265template <
class T,
class Cmp>
266std::vector<T>* TopN<T, Cmp>::ExtractUnsorted() {
267 auto out =
new std::vector<T>;
268 out->swap(elements_);
269 if (state_ == HEAP_SORTED) {
275template <
class T,
class Cmp>
276std::vector<T>* TopN<T, Cmp>::ExtractNondestructive()
const {
277 auto out =
new std::vector<T>;
278 ExtractNondestructive(out);
281template <
class T,
class Cmp>
282void TopN<T, Cmp>::ExtractNondestructive(std::vector<T>* output)
const {
285 if (state_ != HEAP_SORTED) {
286 std::sort(output->begin(), output->end(), cmp_);
289 std::sort_heap(output->begin(), output->end(), cmp_);
292template <
class T,
class Cmp>
293std::vector<T>* TopN<T, Cmp>::ExtractUnsortedNondestructive()
const {
294 auto elements =
new std::vector<T>;
295 ExtractUnsortedNondestructive(elements);
298template <
class T,
class Cmp>
299void TopN<T, Cmp>::ExtractUnsortedNondestructive(std::vector<T>* output)
const {
302 if (state_ == HEAP_SORTED) {
307template <
class T,
class Cmp>
308void TopN<T, Cmp>::Reset() {