/*
 * Copyright (c) 2003 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef SCHED_LIST_HH
#define SCHED_LIST_HH

#include <list>
#include "base/misc.hh"

//  Any types you use this class for must be covered here...
namespace {
    void ClearEntry(int &i) { i = 0; };
    void ClearEntry(unsigned &i) { i = 0; };
    void ClearEntry(double &i) { i = 0; };
    template <class T> void ClearEntry(std::list<T> &l) { l.clear(); };
};


//
//  this is a special list type that allows the user to insert elements at a
//  specified positive offset from the "current" element, but only allow them
//  be extracted from the "current" element
//


template <class T>
class SchedList
{
    T *data_array;
    unsigned position;
    unsigned size;
    unsigned mask;

  public:
    SchedList(unsigned size);
    SchedList(void);

    void init(unsigned size);

    T &operator[](unsigned offset);

    void advance(void);

    void clear(void);
};



//
//  Constructor
//
template<class T>
SchedList<T>::SchedList(unsigned _size)
{
    size = _size;

    //  size must be a power of two
    if (size & (size-1)) {
        panic("SchedList: size must be a power of two");
    }

    if (size < 2) {
        panic("SchedList: you don't want a list that small");
    }

    //  calculate the bit mask for the modulo operation
    mask = size - 1;

    data_array = new T[size];

    if (!data_array) {
        panic("SchedList: could not allocate memory");
    }

    clear();
}

template<class T>
SchedList<T>::SchedList(void)
{
    data_array = 0;
    size = 0;
}


template<class T> void
SchedList<T>::init(unsigned _size)
{
    size = _size;

    if (!data_array) {
        //  size must be a power of two
        if (size & (size-1)) {
            panic("SchedList: size must be a power of two");
        }

        if (size < 2) {
            panic("SchedList: you don't want a list that small");
        }

        //  calculate the bit mask for the modulo operation
        mask = size - 1;

        data_array = new T[size];

        if (!data_array) {
            panic("SchedList: could not allocate memory");
        }

        clear();
    }
}


template<class T> void
SchedList<T>::advance(void)
{
    ClearEntry(data_array[position]);

    //    position = (++position % size);
    position = ++position & mask;
}


template<class T> void
SchedList<T>::clear(void)
{
    for (unsigned i=0; i<size; ++i) {
        ClearEntry(data_array[i]);
    }

    position = 0;
}


template<class T>  T&
SchedList<T>::operator[](unsigned offset)
{
    if (offset >= size) {
        panic("SchedList: can't access element beyond current pointer");
    }

    //    unsigned p = (position + offset) % size;
    unsigned p = (position + offset) & mask;

    return data_array[p];
}



#endif