// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#pragma once

#include "codegen/impala-ir.h"

namespace impala {

template <typename T, typename C>
class PriorityQueue;

// A simple iterator for PriorityQueue
template <typename T, typename C>
class PriorityQueueIterator {
 public:
  PriorityQueueIterator(PriorityQueue<T, C>* queue, int index)
    : queue_(queue), index_(index) {}
  ~PriorityQueueIterator() {}

  PriorityQueue<T, C>* GetPriorityQueue() { return queue_; }
  // The operator to cast 'this' to int
  operator int() { return index_; }
  // The dereference operator
  T& operator*() { return queue_->elements_[index_]; }
  // The prefix increment operator ++itor
  PriorityQueueIterator<T, C>& operator++() {
    index_++;
    return *this;
  }
  // The Less operator
  bool operator<(PriorityQueueIterator& other) { return index_ < other.index_; }

 private:
  // The priority queue.
  PriorityQueue<T, C>* queue_;
  // The index to the element that this iterator is pointing at.
  int index_;
};

// A priority queue template based on the array implementation of a binary search tree.
// The first type T is the type of the elements of the queue while the second type C
// is the comparator to compare elements during the heapification operations.
//
// Within the template, the array elements_ (represented by std::vector<T>) holds the
// elements of the queue.
//
// This class calls C.Less(const T& x, const T& y) to compare elements and expects a
// 'true' return when x < y. Since any node in the binary search tree is larger than
// any of its two children, this class implements a max heap.
//
// The grow and shrink of the array is maintained automatically by std::vector<T> and
// the array is destroyed upon the destruction of the queue.
//
// To add to the queue, call Push(). To remove the top element, call Pop(). To look at
// the top element without removal, call Top().
//
// The priority queue is not thread safe.
//
template <typename T, typename C>
class PriorityQueue {
 public:
  PriorityQueue(const C& c) : elements_(), comparator_(c) {}

  ~PriorityQueue() {}

  // Clear all elements
  void Clear() { elements_.clear(); }

  // The top element
  T& IR_ALWAYS_INLINE Top() { return elements_[0]; }

  // The ith element
  T& operator[](int i) { return elements_[i]; }

  void Reserve(int64_t capacity) { elements_.reserve(capacity); }

  // The size f the heap
  int64_t IR_ALWAYS_INLINE Size() const { return elements_.size(); }

  // Check if the heap is empty
  bool IR_ALWAYS_INLINE Empty() const { return elements_.empty(); }

  // Get the begin iterator.
  PriorityQueueIterator<T, C> Begin() { return PriorityQueueIterator<T, C>(this, 0); }

  // Get the end iterator.
  PriorityQueueIterator<T, C> End() { return PriorityQueueIterator<T, C>(this, Size()); }

  // Add a new element to the end of the array and then heapify. This is an
  // O(log n) operation.
  void IR_ALWAYS_INLINE Push(const T& v) {
    // Insert the new element v at the end.
    elements_.emplace_back(v);
    // Move up the new element and its ancestors if necessary (all the way to the
    // element at index 0) to maintain the heap property.
    HeapifySubtreeUp(0, Size() - 1);
  }

  // Remove the top element from the priority queue and then heapify affected
  // elements. This is an O(log n) operation. Must not be called when the queue
  // is empty.
  T IR_ALWAYS_INLINE Pop() {
    if (Size() > 0) {
      int last = Size() - 1;
      T top_element = Top();
      // Swap the top element from 0 to index 'last'.
      Swap(elements_[0], elements_[last]);
      // Heapify from index 0 and down.
      HeapifySubtreeDown(0, last);
      elements_.pop_back();
      // Return the original top element.
      return top_element;
    }
    DCHECK(false);
    return T();
  }

  // Heapify from top element at index 0 in O(log n) complexity. It is
  // assumed that the elements in [1, size_-1] are already arranged as a heap.
  void IR_ALWAYS_INLINE HeapifyFromTop() { HeapifySubtreeDown(0, Size()); }

 protected:
  // Move up elements starting at index i to maintain the heap property.
  // The operation stops when the element at index low_bound has been reached.
  // It is assumed that the elements in [low_bound, i-1] are already arranged
  // as a heap. This is an O(log n) algorithm.
  void IR_ALWAYS_INLINE HeapifySubtreeUp(int low_bound, int i) {
    while (i > low_bound) {
      // parent = (i-2)/2            when i is even, or
      //        = (i-1)/2 = (i)/2    when i is odd.
      int parent = (i & 1) ? (i >> 1) : ((i - 2) >> 1);
      if (comparator_.Less(elements_[i], elements_[parent])) {
        break;
      } else {
        Swap(elements_[parent], elements_[i]);
      }
      // Continue to heapify the affected sub-tree at root 'parent'.
      i = parent;
    }
  }

  // Heapify a sub-tree rooted at index i, all the way to the element at index
  // high_bound-1. It is assumed that the elements in [i, high_bound-1] are already
  // arranged as a heap. This is an O(log n) algorithm.
  void IR_ALWAYS_INLINE HeapifySubtreeDown(int i, int high_bound) {
    while (i < high_bound) {
      int largest = i; // Initialize largest as the root
      int left = (i << 1) + 1; // left  = 2*i + 1
      int right = left + 1; // right = 2*i + 2
      // If the left child is larger than the root
      if (left < high_bound && comparator_.Less(elements_[largest], elements_[left])) {
        largest = left;
      }
      // If the right child is larger than the largest
      if (right < high_bound && comparator_.Less(elements_[largest], elements_[right])) {
        largest = right;
      }
      // If the largest is not the root
      if (largest != i) {
        Swap(elements_[i], elements_[largest]);
        // Continue to heapify the affected sub-tree at root largest.
        i = largest;
      } else {
        break;
      }
    }
  }

  // Swap two elements of type T.
  void IR_ALWAYS_INLINE Swap(T& x, T& y) {
    T t = x;
    x = y;
    y = t;
  }

 private:
  // The array holding the elements.
  std::vector<T> elements_;
  // The comparator
  const C& comparator_;

  friend class PriorityQueueIterator<T, C>;
};

} // namespace impala

