/*-
 * Copyright (c) 2000 Qube Software, Ltd.
 * All rights reserved.
 * 
 * 	$Id: vector.h,v 1.8 2000/06/29 17:15:03 hugh Exp $
 */

#ifndef __vector_h__
#define __vector_h__

#include        "xdecl.h"
#include        <iostream>

template<class T> struct Vector
{
    /* Constraints on T:
     *
     *
     *  T::T();
     *  int T::operator==(const T&) const
     *  T& T::operator=(const T&)
     *  std::ostream& operator<<(std::ostream&, const T&)
     *
     */

    // Constructors
                                Vector() { init(); }
                                Vector(const Vector<T>&);
                                Vector(unsigned int n)
                                   { init(); resizeFor(n); }

    // Destructor
				~Vector() { purge(); }

    // Accessors
    unsigned int                size() const { return size_; }
    unsigned int                space() const { return space_; }

    // Operators
    T&                          operator[](unsigned int i) { return v_[i]; }
    const T&                    operator[](unsigned int i) const
                                   { return v_[i]; }
    
    // Features

    unsigned int		add(const T&);
    void                        add(const Vector<T>&);
    bool			locate(const T&, unsigned int&) const;
    bool			locateFirst(const T& t, unsigned int& n) const
                                        { return locate(t, n); }
    bool			locateLast(const T& t, unsigned int& n) const
                                        { return locate(t, n); }
    bool			intern(const T&, unsigned int&);
    void			insert(const T&, unsigned int);
    void                        insert(const Vector<T>&, unsigned int);
    bool			removeAt(unsigned int);
    bool			removeAt(unsigned int, unsigned int);
    bool			remove(const T&);
    bool			remove(const Vector<T>&);
    bool                        member(const T& t) const;
    void			empty() { resizeFor(0); }
    int                         compare(const Vector<T>&) const;
    void			consume(Vector<T>&);
    Vector<T>*			intersect(const Vector<T>&) const;
    Vector<T>&                  operator+=(const Vector<T>& v) 
                                { add(v); return *this; }
    Vector<T>&                  operator-=(const Vector<T>& v)
                                { remove(v); return *this; }

    int                         operator==(const Vector<T>& v) const
                                   { return !compare(v); }
    const T&                    first() const { return v_[0]; }
    const T&                    last() const { return v_[size_ - 1]; }

    const T&                    at(unsigned int i) const { return v_[i]; }
    void                        at(unsigned int i, const T& t) { v_[i] = t; }
    void                        sizeTo(unsigned int n);
    void			spaceTo(unsigned int n) { resizeFor(n); }
    Vector<T>&                  operator=(const Vector<T>&);
    Vector<T>*                  slice(unsigned int start,
                                      unsigned int end) const;
    unsigned int                instanceSize() const;

protected:

    void                        init();
    void                        size(unsigned int s) { size_ = s; }
    void                        resizeFor(unsigned int);
    void                        purge();



protected:

    unsigned int                size_;
    unsigned int                space_;
    T* XDECL(space_)            v_;
};

template<class T> struct OrderedVector: public Vector<T>
{

    typedef int (*compareFn)(const T* a, const T* b);

    /* Constraints on T:
     *
     *
     *  T::T();
     *  int T::operator==(const T&) const;
     *  T& T::operator=(const T&)
     *  std::ostream<<(std::ostream&, const T&)
     *
     *  int T::operator<=(const T&) const;
     *
     */

                                OrderedVector() { init(); }
                                OrderedVector(unsigned int n)
                                    : Vector<T>(n) { init(); }
                                    
                                OrderedVector(const Vector<T>&);
                                OrderedVector(const OrderedVector<T>&);

    // Accessors
    compareFn                   cFn() const { return cFn_; }

    // Modifiers
    void                        cFn(compareFn f) { cFn_ = f; }

    // Overrides
    unsigned int                add(const T&);
    bool                        locate(const T&, unsigned int&) const;
    bool                        locateFirst(const T&, unsigned int&) const;
    bool                        locateLast(const T&, unsigned int&) const;

    void			add(const Vector<T>&);
    bool			intern(const T&, unsigned int&);
    bool			remove(const T&);
    bool			member(const T&) const;
    
    int                         compare(const OrderedVector<T>&) const;

    int                         operator==(const OrderedVector<T>& v) const
                                   { return !compare(v); }
    int                         operator<=(const OrderedVector<T>& v) const
                                   { return compare(v) <= 0; }
#if 0
    // Overrides, Vector<T>
    void                        consume(Vector<T>&);
#endif

    // Features
    void                        consume(OrderedVector<T>& v)
                                {
                                    Vector<T>::consume(v);
                                }
    OrderedVector<T>&           operator=(const OrderedVector<T>&);
    OrderedVector<T>*		intersect(const OrderedVector<T>&) const;
    // NS - made this public as we no longer support operator()
    OrderedVector<T>*           slice(unsigned int start,
                                      unsigned int end) const;
    
protected:

    void                        init() { initCfn(); }
    void                        initCfn() const 
                                {
                                    const_cast<OrderedVector<T>*>(this)->cFn_
                                        = defaultCompareFn; 
                                }

private:

    TRANSIENT compareFn         cFn_;
    static int                  defaultCompareFn(const T*, const T*);
};

template<class T> std::ostream& operator<<(std::ostream& os, const Vector<T>& v)
{
    os << '[';
    for (unsigned int i = 0; i < v.size(); ++i) {
        os << v[i];
        if (i < v.size() - 1) os << ' ';
    }
    os << ']';
    return os;
}


/***************** Vector<T>, methods for ******************************/

template<class T> Vector<T>::Vector(const Vector<T>& v)
{
    init();
    *this = v;
}

template<class T> unsigned int Vector<T>::add(const T& t)
{
    resizeFor(size_ + 1);
    v_[size_++] = t;
    return size_ - 1;
}

template<class T> void Vector<T>::init()
{
    v_ = 0;
    size_ = 0;
    space_ = 0;
}

template<class T> void Vector<T>::purge()
{
    delete [] v_;
    init();
}

template<class T> void Vector<T>::resizeFor(unsigned int n)
{
    if (!n) purge();
    else {
        if (n > space_) {
            /* Need more space */
            unsigned int newSpace = space_;
            if (!newSpace) newSpace = 4;
            while (newSpace < n) newSpace *= 2;

            T* newV = new T[newSpace];
            for (unsigned int i = 0; i < size_; ++i) newV[i] = v_[i];

            space_ = newSpace;

            delete [] v_;
            v_ = newV;
        }
    }
}

template<class T>
bool Vector<T>::locate(const T& t, unsigned int& atIndex) const
{
    bool found = false;
    unsigned int i;
    for (i = 0; i < size_; ++i) {
        if (v_[i] == t) { found = true; break; }
    }

    atIndex = i;
    return found;
}


template<class T> void Vector<T>::insert(const T& t, unsigned int atIndex)
{
    resizeFor(size() + 1);

    for (unsigned int i = size(); i > atIndex; --i) at(i, at(i-1));
    size(size() + 1);
    at(atIndex, t);
}

template<class T> void Vector<T>::insert(const Vector<T>& v,
                                         unsigned int atIndex)
{
    /* Insert the given vector, `v' at `atIndex' */
    unsigned int n = size() + v.size();
    resizeFor(n);
    unsigned int i, j;

    for (i = n, j = size(); j > atIndex; --j, --i) at(i-1, at(j-1));
    for (j = 0; j < v.size(); ++j, ++atIndex) at(atIndex, v[j]);
    size_ += v.size();
}

template<class T> bool Vector<T>::intern(const T& t, unsigned int& atIndex)
{
    bool found = locate(t, atIndex);
    if (!found) {
        insert(t, atIndex);
    }
    return bool(!found);
}

template <class T> int Vector<T>::compare(const Vector<T>& v) const
{
    int val = 0;

    if (size_ != v.size())
	return 1;
    
    for (unsigned int i = 0; i < size_; ++i) {

        if (v[i] == v_[i]) val = 0;
        else {
            val = 1;
            break;
        }
    }
    return val;
}

template <class T> bool Vector<T>::removeAt(unsigned int i)
{
    if (i < size_) {
        if (--size_) {
            for (unsigned j = i; j < size_; ++j) v_[j] = v_[j+1];
            v_[size_] = T();
        }
        resizeFor(size_);
        return true;
    }
    return false;
}

template <class T> bool Vector<T>::removeAt(unsigned int start,
					    unsigned int end)
{
    /* Remove the range [start, end)
     */
    if (start < end) {
        unsigned int i, j;
        for (i = end, j = start; i < size_; ++i, ++j) v_[j] = v_[i];
        while (j < size_) {
            v_[j] = T();
            ++j;
        }
        size_ -= end - start;
        resizeFor(size_);
    }
    return true;
}

template <class T> bool Vector<T>::remove(const T& t)
{
    unsigned int at;
    if (locate(t, at)) return removeAt(at);
    return false;
}

template<class T>
Vector<T>* Vector<T>::slice(unsigned int start, unsigned int end) const
{
    if (end > size()) end = size();
    if (start >= end) return new Vector<T>;   // empty vector.

    Vector<T>* vp = new Vector<T>(end - start);
    for (unsigned int i = start; i < end; ++i) {
        (*vp)[i - start] = v_[i];
    }
    vp->size_ = end - start;

    return vp;
}

template<class T> void Vector<T>::consume(Vector<T>& v)
{
    if (this != &v) {
        /* Steal the contents of V, leaving v empty */
        purge();

        v_ = v.v_;
        size_ = v.size_;
        space_ = v.space_;

        v.init();
    }
}

template<class T> bool Vector<T>::member(const T& t) const
{
    unsigned int atIndex;
    return locate(t, atIndex);
}

template<class T> void Vector<T>::sizeTo(unsigned int n) 
{
    /* Change the size of the vector to `n'. 
     * If shrinking do not change the space allocated.
     */
    if (n < size_) {
        /* When shrinking need to nullify the ragged edge
         * so remenant object references do not exist.
         */
        for (unsigned int i = n; i < space_; ++i) v_[i] = T();
    }
    else resizeFor(n);

    size_ = n;
}

template<class T> Vector<T>& Vector<T>::operator=(const Vector<T>& v)
{
    if (this != &v) {
        purge();

        resizeFor(v.size());
        unsigned int i;
        for (i = 0; i < v.size(); ++i) v_[i] = v[i];
        size_ = i;        
    }
    return *this;
}

template<class T> void Vector<T>::add(const Vector<T>& v)
{
    for (unsigned int i = 0; i < v.size(); ++i) {
        add(v[i]);
    }
}

template<class T> bool Vector<T>::remove(const Vector<T>& v)
{
    /* Return true iff all elements of `v' removed.
     */
    bool result = true;
    for (unsigned int i = 0; i < v.size(); ++i) {
        bool s = remove(v[i]);
        if (!s) result = false;
    }
    return result;
}

template<class T> Vector<T>*
Vector<T>::intersect(const Vector<T>& v1) const
{
    Vector<T>* v = new Vector<T>();
    for (unsigned int i = 0; i < size(); ++i) {
        if (v1.member(v_[i])) v->add(v_[i]);
    }
    return v;
}

template<class T> unsigned int Vector<T>::instanceSize() const
{
    return sizeof(*this) + space_*sizeof(T);
}

/*********** OrderedVector<T>, methods for ****************************/

template<class T> OrderedVector<T>::OrderedVector(const Vector<T>& v)
{
    init();
    resizeFor(v.size());

    for (unsigned int i = 0; i < v.size(); ++i) add(v[i]);
}

template<class T> OrderedVector<T>::OrderedVector(const OrderedVector<T>& v)
{
    init();
    *this = v;
}

template<class T>
OrderedVector<T>& OrderedVector<T>::operator=(const OrderedVector<T>& v)
{
    if (this != &v) {
        purge();
        Vector<T>::operator=(v);
        cFn_ = v.cFn_;
    }
    return *this;
}

template<class T>
bool OrderedVector<T>::locate(const T& t, unsigned int& atIndex) const
{
    if (!cFn_) initCfn();

    unsigned int lo = (unsigned int)-1;
    unsigned int hi = size();

    bool found = false;
    unsigned int probe;
    while (hi - lo > 1) {
        probe = (lo + hi) / 2;
        int v = (*cFn_)(v_ + probe, &t);
        if (!v) {
            hi = probe;
            found = true;
            break;
        }
        else if (v < 0) {
            lo = probe;
        }
        else hi = probe;
    }

    atIndex = hi;
    return found;
}

template<class T>
bool OrderedVector<T>::locateFirst(const T& t, unsigned int& atIndex) const
{
    /* Find the first match in the ordered vector not just any match.
     */

    bool found = locate(t, atIndex);
    if (found && atIndex > 0) {
        /* We have a match, but it might not be the first.
         * step back until we have the first match.
         */
        unsigned int i = atIndex;
        do {
            --i;
            int v = (*cFn_)(v_ + i, &t);
            if (!v) atIndex = i;
            else break;
        } while (i > 0);
    }
    return found;
}

template<class T>
bool OrderedVector<T>::locateLast(const T& t, unsigned int& atIndex) const
{
    /* Find the last match in the ordered vector not just any match.
     */

    bool found = locate(t, atIndex);
    if (found) {
        /* We have a match, but it might not be the last.
         * step forwards until we have the last match.
         */
        unsigned int i = atIndex + 1;
        while (i < size()) {
            int v = (*cFn_)(v_ + i, &t);
            if (!v) atIndex = i;
            else break;
            ++i;
        };
    }
    return found;
}

template<class T> unsigned int OrderedVector<T>::add(const T& t)
{
    unsigned int atIndex;
    locate(t, atIndex);         // &atIndex
    insert(t, atIndex);
    return atIndex;
}

template<class T> void OrderedVector<T>::add(const Vector<T>& v)
{
    for (unsigned int i = 0; i < v.size(); ++i) {
        add(v[i]);
    }
}

template<class T> bool OrderedVector<T>::intern(const T& t,
						unsigned int& atIndex)
{
    bool found = locate(t, atIndex);
    if (!found) {
        insert(t, atIndex);
    }
    return bool(!found);
}

template <class T> bool OrderedVector<T>::remove(const T& t)
{
    unsigned int at;
    if (locate(t, at)) return removeAt(at);
    return false;
}

template<class T> bool OrderedVector<T>::member(const T& t) const
{
    unsigned int atIndex;
    return locate(t, atIndex);
}

template<class T> int OrderedVector<T>::defaultCompareFn(const T* a,
                                                         const T* b)
{
    if (*a == *b) return 0;
    if (*a <= *b) return -1;
    return 1;
}

#if 0
template<class T> void OrderedVector<T>::consume(Vector<T>& v)
{
    /* Steal the guts of `v' and in-place sort the data.
     * NOTE: `v' is empty after.
     *       Our old content is lost.
     */
    if (!cFn_) initCfn();

    extern int quicksort(void*, size_t, size_t, int (*)(const void*,
                                                        const void*));
    Vector<T>::consume(v);
    quicksort((void*) v_, (size_t) size_, (size_t) sizeof(T), 
              (int (*)(const void*, const void*))cFn_);
}
#endif

template<class T>
int OrderedVector<T>::compare(const OrderedVector<T>& v) const
{
    if (!cFn_) initCfn();

    int val = 0;

    if (size_ != v.size())
	return 1;
    
    for (unsigned int i = 0; i < size_; ++i) {

        val = (*cFn_)(v.v_ + i, v_ + i);
        if (val) break;
    }
    return val;
}

template<class T> OrderedVector<T>*
OrderedVector<T>::slice(unsigned int start, unsigned int end) const
{
    if (end > size()) end = size();
    if (start >= end) return new OrderedVector<T>;   // empty vector.

    OrderedVector<T>* vp = new OrderedVector<T>(end - start);
    for (unsigned int i = start; i < end; ++i) {
        (*vp)[i - start] = v_[i];
    }
    vp->size_ = end - start;

    return vp;
}

// NS - changed the return type as we can no longer have
// AP<> in the utils SDK.
template<class T>
OrderedVector<T>* operator-(const OrderedVector<T>& v1,
			    const OrderedVector<T>& v2)
{
    OrderedVector<T>* v = new OrderedVector<T>();
    for (unsigned int i = 0; i < v1.size(); ++i) {
        if (!v2.member(v1[i])) v->add(v1[i]);
    }
    return v;
}

template<class T> OrderedVector<T>*
OrderedVector<T>::intersect(const OrderedVector<T>& v1) const
{
    OrderedVector<T>* v = new OrderedVector<T>();
    for (unsigned int i = 0; i < size(); ++i) {
        if (v1.member(v_[i])) v->add(v_[i]);
    }
    return v;
}

#endif /* __vector_h__ */

