// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Copyright (C) 2016 Red Hat Inc. */ #pragma once #include #include #include "assert.h" namespace crimson { /* * T : type of data held in the heap. * * C : class that implements operator() with two arguments and * returns a boolean when the first argument is greater than (higher * in priority than) the second. */ template class Heap { public: class iterator { friend Heap; Heap& heap; int index; iterator(Heap& _heap, int _index) : heap(_heap), index(_index) { // empty } public: iterator(iterator&& other) : heap(other.heap), index(other.index) { // empty } iterator& operator++() { ++index; return *this; } bool operator==(const iterator& other) const { return index == other.index; } bool operator!=(const iterator& other) const { return !(*this == other); } T& operator*() { return heap.data[index]; } // the item this iterator refers to void increase() { heap.siftUp(index); } }; // class iterator friend iterator; protected: std::vector data; int count; C comparator; // parent(0) should be a negative value, which it is due to // truncating towards negative infinity static inline int parent(int i) { return (i - 1) / 2; } static inline int lhs(int i) { return 2*i + 1; } static inline int rhs(int i) { return 2*i + 2; } void siftUp(int i) { assert(i < count); while (i > 0) { int pi = parent(i); if (!comparator(data[i], data[pi])) { break; } std::swap(data[i], data[pi]); i = pi; } } void siftDown(int i) { while (i < count) { int li = lhs(i); int ri = rhs(i); if (li < count) { if (comparator(data[li], data[i])) { if (ri < count && comparator(data[ri], data[li])) { std::swap(data[i], data[ri]); i = ri; } else { std::swap(data[i], data[li]); i = li; } } else if (ri < count && comparator(data[ri], data[i])) { std::swap(data[i], data[ri]); i = ri; } else { break; } } else { break; } } } public: Heap() : count(0) { // empty } Heap(const Heap& other) { data.resize(other.data.size()); for (int i = 0; i < other.count; ++i) { data[i] = other.data[i]; } count = other.count; } const Heap& operator=(const Heap& other) { data.resize(other.data.size()); for (int i = 0; i < other.count; ++i) { data[i] = other.data[i]; } count = other.count; return *this; } bool empty() const { return 0 == count; } T& top() { return data[0]; } void push(T item) { int i = count++; data.push_back(item); siftUp(i); } void pop() { data[0] = data[--count]; data.resize(count); siftDown(0); } void updateTop() { siftDown(0); } void clear() { count = 0; data.resize(0); } iterator begin() { return iterator(*this, 0); } iterator end() { return iterator(*this, count); } std::ostream& displaySorted(std::ostream& out, std::function filter, bool insert_line_breaks = true) const { Heap temp = *this; bool first = true; out << "[ "; while(!temp.empty()) { const T& top = temp.top(); if (filter(top)) { if (!first) { out << ", "; } if (insert_line_breaks) { out << std::endl << " "; } out << temp.top(); first = false; } temp.pop(); } out << " ]"; if (insert_line_breaks) { out << std::endl; } return out; } template friend std::ostream& operator<<(std::ostream&, const Heap&); }; // class Heap template std::ostream& operator<<(std::ostream& out, const Heap& h) { out << "[ "; if (h.count) { out << h.data[0]; } for (int i = 1; i < h.count; i++) { out << ", " << h.data[i]; } out << " ]"; return out; } } // namespace