rankedset.h

Back to Ranked set

pastel/sys/rankedset/

// Description: Ranked set

#ifndef PASTELSYS_RANKEDSET_H
#define PASTELSYS_RANKEDSET_H

#include "pastel/sys/mytypes.h"
#include "pastel/sys/ensure.h"

#include <vector>
#include <algorithm>

namespace Pastel
{

    //! A ranked set
    /*!
   Maintains the k smallest elements stored in the set;
   a bounded priority queue. The k is called the capacity 
   of the set.
   */
    template <typename Type, typename Less = LessThan>
    class RankedSet
    {
    public:
        using DataSet = std::vector<Type>;
        using Iterator = typename DataSet::iterator;
        using ConstIterator = typename DataSet::const_iterator;
        using iterator = Iterator;
        using const_iterator = ConstIterator;

        //! Constructs a set.
        RankedSet(
            integer capacity = 0,
            Less less = Less())
            : dataSet_()
            , less_(std::move(less))
        {
            ENSURE_OP(capacity, >= , 0);
            reserve(capacity);
        }

        //! Inserts an element into the set.
        Iterator push(const Type& that)
        {
            if (capacity() == 0)
            {
                return end();
            }

            if (size() == capacity())
            {
                if (!less_(that, top()))
                {
                    return end();
                }

                pop();
            }

            dataSet_.push_back(that);
            std::push_heap(begin(), end(), less_);
            return std::prev(end());
        }

        //! Releases the underlying data-set.
        /*!
       Post-conditions:
       capacity() == 0
       size() == 0

       sorted (bool):
       Whether to sort the data-set in 
       increasing order using heap-sort.

       returns:
       The underlying data-set moved out
       of the ranked-set.
       */
        DataSet release(bool sorted = true)
        {
            if (sorted)
            {
                for (auto i = end(); i != begin();--i)
                {
                    std::pop_heap(begin(), i, less_);
                }
            }
            return std::move(dataSet_);
        }

        //! Removes the maximum element.
        void pop()
        {
            ENSURE(!empty());
            std::pop_heap(begin(), end(), less_);
            dataSet_.pop_back();
        }

        //! Removes all elements.
        void clear()
        {
            integer k = capacity();
            dataSet_.clear();
            // The implementation of std::vector 
            // may or may not change the capacity 
            // of the vector. Restore capacity to 
            // be sure.
            dataSet_.reserve(k);
        }

        //! Returns an iterator to the first element.
        PASTEL_ITERATOR_FUNCTIONS(begin, dataSet_.begin());

        //! Returns an iterator to the one-past-end element.
        PASTEL_ITERATOR_FUNCTIONS(end, dataSet_.end());

        //! Returns whether the set is full.
        bool full() const
        {
            return size() == capacity();
        }

        //! Returns whether the set is empty.
        bool empty() const
        {
            return dataSet_.empty();
        }

        //! Swaps two sets.
        void swap(RankedSet& that)
        {
            using std::swap;

            dataSet_.swap(that.dataSet_);
            swap(less_, that.less_);
        }

        //! Returns the maximum element.
        Type& top()
        {
            ENSURE(!empty());
            return dataSet_.front();
        }

        //! Returns the maximum element.
        const Type& top() const
        {
            ENSURE(!empty());
            return dataSet_.front();
        }

        //! Returns the size of the set.
        integer size() const
        {
            return dataSet_.size();
        }

        //! Sets the capacity of the set.
        /*!
       Preconditions:
       capacity >= 0
       */
        void reserve(integer capacity)
        {
            ENSURE_OP(capacity, >=, 0);

            while(size() > capacity)
            {
                pop();
            }

            dataSet_.reserve(capacity);
        }

        //! Returns the capacity of the set.
        integer capacity() const
        {
            return dataSet_.capacity();
        }

    private:
        DataSet dataSet_;
        Less less_;
    };

}

#endif