#ifndef _ZLIST_HPP_
#define _ZLIST_HPP_
#include <assert.h>
#include <array>
template<typename T,int SIZE>
struct zlist
{
	std::array<T,SIZE>*buf;
	uint32_t 		  bpos;
	uint32_t          epos;
    uint32_t          len;
	zlist()
		:buf(nullptr)
		,bpos(0)
		,epos(0)
        ,len(1)
	{
		buf=new std::array<T,SIZE>();
        len = 1;
        while(len < SIZE)
          len <<= 1;
	}

	~zlist()
	{
		delete buf;
	}

	void clear()
	{
		bpos=epos;
	}

	int index(uint32_t p)const
	{
        int l =  p&(len-1);
        return l - len + SIZE;
        //return p&(SIZE-1);
	}

	void push(const T&o)
	{
		if(size()>=SIZE) skip(1);

		buf->at(index(epos++))=o;
	}

	void rpush(const T&o)
	{
		if(size()>=SIZE) rskip(1);

		buf->at(index(--bpos))=o;
	}

	T& grow()
	{
		if(size()>=SIZE) skip(1);
		++epos;
		return rat(0);
	}

	T& rgrow()
	{
		if(size()>=SIZE) rskip(1);
		--bpos;
		return at(0);
	}

	template<typename Pred>
	int find_if(const Pred&p)const
	{
		for(int i=0,len=size();i<len;i++)
		{
			if(p((*this)[i]))
				return i;
		}

		return -1;
	}
	template<typename Pred>
	int find_last_if(const Pred&p)const
	{
		for(int i=0,len=size();i<len;i++)
		{
			if(p((*this)(i)))
			{
				return len-i-1;
			}
		}

		return -1;
	}

	template<typename Pred>
	void skip_if(const Pred&p)
	{
		while(!empty())
		{
			if(!p(at(0)))
				break;
			skip(1);
		}
	}

	template<typename Pred>
	void for_each(const Pred&p)
	{
		for(unsigned i=bpos;i<epos;i++)
			p(buf->at(index(i)));
	}

	void skip(int count)
	{
		assert(count<=(int)size());
		bpos+=count;
	}

	void rskip(int count)
	{
		assert(count<=(int)size());
		epos-=count;
	}

	bool empty()const
	{
		return epos==bpos;
	}

	int size()const
	{
		return epos-bpos;
	}

	T&at(int i) 
	{ 
		assert(i<(int)size());
		return buf->at(index(bpos+i)); 
	}

	const T&at(int i) const
	{ 
		assert(i<(int)size());
		return buf->at(index(bpos+i)); 
	}

	T&rat(int i) 
	{ 
		assert(i<(int)size());
		return buf->at(index(epos-i-1)); 
	}

	const T&rat(int i) const
	{ 
		assert(i<(int)size());
		return buf->at(index(epos-i-1)); 
	}
	T&operator[](int i) 
	{ 
		return at(i);
	}

	const T&operator[](int i) const
	{ 
		return at(i);
	}

	T&operator()(int i) 
	{ 
		return rat(i);
	}

	const T&operator()(int i) const
	{ 
		return rat(i);
	}
};
#endif