/*
 * Copyright 2002 Lite Speed Technologies Inc, All Rights Reserved.
 * LITE SPEED PROPRIETARY/CONFIDENTIAL.
 */


#ifndef GPOINTERLIST_H
#define GPOINTERLIST_H


/**
  *@author George Wang
  */


#include <stddef.h>
#include <string.h>
#include <sys/types.h>

typedef int (*gpl_for_each_fn)(void *);
typedef int (*gpl_for_each_fn2)(void *, void *);

class GPointerList
{
    void **m_pStore;
    void **m_pStoreEnd;
    void **m_pEnd;

    int allocate(int capacity);
    GPointerList(const GPointerList &rhs);
    void operator=(const GPointerList &rhs);
public:
    typedef void **iterator;
    typedef void *const *const_iterator;
    GPointerList();
    explicit GPointerList(size_t initSize);
    ~GPointerList();
    ssize_t size() const    {   return m_pEnd - m_pStore;   }
    bool empty() const      {   return m_pEnd == m_pStore;  }
    bool full() const       {   return m_pEnd == m_pStoreEnd;   }
    size_t capacity() const {   return m_pStoreEnd - m_pStore;  }
    void clear()            {   m_pEnd = m_pStore;          }
    iterator begin()        {   return m_pStore;            }
    iterator end()          {   return m_pEnd;              }
    const_iterator begin() const    {   return m_pStore;    }
    const_iterator end() const      {   return m_pEnd;      }
    void *back() const             {   return *(m_pEnd - 1);   }
    int reserve(size_t sz)        {   return allocate(sz);  }
    int resize(size_t sz);
    int grow(size_t sz)   {   return allocate(sz + capacity()); }

    iterator erase(iterator iter)
    {   *iter = *(--m_pEnd);  return iter; }
    void safe_push_back(void *pPointer)   {   *m_pEnd++ = pPointer;   }
    void safe_push_back(void **pPointer, int n);
    void safe_pop_back(void **pPointer, int n);
    int  push_back(void *pPointer);
    int  push_back(const void *pPointer)
    {   return push_back((void *)pPointer);    }
    int  push_back(const GPointerList &list);
    void *pop_back()                        {   return *(--m_pEnd);         }

    int push_front(void **pPointer, int n);

    int pop_front(int n)
    {
        if (n >= size())
        {
            n = size();
            clear();
        }
        else
        {
            memmove(m_pStore, m_pStore + n, sizeof(void *) * (m_pEnd - m_pStore - n));
            m_pEnd -= n;
        }
        return n;
    }

    int pop_front(void **pPointer, int n)
    {
        if (n > size())
            n = size();
        memmove(pPointer, m_pStore, n * sizeof(void *));
        if (n >= size())
            clear();
        else
        {
            memmove(m_pStore, m_pStore + n, sizeof(void *) * (m_pEnd - m_pStore - n));
            m_pEnd -= n;
        }
        return n;
    }
    void *&operator[](size_t off)        {   return *(m_pStore + off);   }
    void *&operator[](size_t off) const  {   return *(m_pStore + off);   }
    void sort(int(*compare)(const void *, const void *));
    void swap(GPointerList &rhs);

    const_iterator lower_bound(const void *pKey,
                               int(*compare)(const void *, const void *)) const ;
    const_iterator bfind(const void *pKey,
                         int(*compare)(const void *, const void *)) const;
                         
    const_iterator find(const void *obj) const
    {
        for (const_iterator iter = begin(); iter < end(); ++iter)
            if (*iter == obj)
                return iter;
        return end();
    }
                     
    int for_each(iterator beg, iterator end, gpl_for_each_fn fn);
    int for_each2(iterator beg, iterator end, gpl_for_each_fn2 fn,
                  void *param);

};

template< typename T >
class TPointerList : public GPointerList
{
    void operator=(const TPointerList &rhs);
    TPointerList(const TPointerList &rhs);
public:
    typedef T **iterator;
    typedef T *const *const_iterator;
    TPointerList() {}

    explicit TPointerList(size_t initSize)
        : GPointerList(initSize)
    {}
    iterator begin()        {   return (iterator)GPointerList::begin();   }
    iterator end()          {   return (iterator)GPointerList::end();    }
    const_iterator begin() const
    {   return (const_iterator)GPointerList::begin();    }
    const_iterator end() const
    {   return (const_iterator)GPointerList::end();      }

    T *pop_back()
    {   return (T *)GPointerList::pop_back();   }
    T *&operator[](size_t off)
    {   return (T *&)GPointerList::operator[](off); }

    T *&operator[](size_t off) const
    {   return (T *&)GPointerList::operator[](off); }

    T *back() const
    {   return (T *)GPointerList::back();    }

    iterator erase(iterator iter)
    {   return (iterator)GPointerList::erase((GPointerList::iterator)iter);    }

    void release_objects()
    {
        for (iterator iter = begin(); iter < end(); ++iter)
            if (*iter) delete *iter;
        GPointerList::clear();
    }

    int copy(const TPointerList &rhs)
    {
        release_objects();
        for (const_iterator iter = rhs.begin(); iter < rhs.end(); ++iter)
            push_back(new T(**iter));
        return size();
    }

    int append(const TPointerList &rhs)
    {
        for (const_iterator iter = rhs.begin(); iter < rhs.end(); ++iter)
            if (find(*iter) == end())
                push_back(new T(**iter));
        return size();
    }

    int push_front(const TPointerList &rhs)
    {
        return GPointerList::push_front((void **)rhs.begin(), rhs.size());
    }

    const_iterator find(const T *obj) const
    {
        for (const_iterator iter = begin(); iter < end(); ++iter)
            if (**iter == *obj)
                return iter;
        return end();
    }

    const_iterator find(const void *obj, int (*compare)(const T *, const void *)) const
    {
        for (const_iterator iter = begin(); iter < end(); ++iter)
            if ((*compare)(*iter, obj) == 0)
                return iter;
        return end();
    }
    

    iterator lower_bound(const void *pKey,
                         int(*compare)(const void *, const void *)) const
    {   return (iterator)GPointerList::lower_bound(pKey, compare);   }

    iterator bfind(const void *pKey,
                   int(*compare)(const void *, const void *)) const
    {   return (iterator)GPointerList::bfind(pKey, compare);  }

    int for_each(iterator beg, iterator end, gpl_for_each_fn fn)
    {   return GPointerList::for_each((void **)beg, (void **)end, fn);    }

    int for_each2(iterator beg, iterator end, gpl_for_each_fn2 fn, void *param)
    {   return GPointerList::for_each2((void **)beg, (void **)end, fn, param);    }
};


#endif
