

/*!
  @author d金魚
  @file buffer.hpp
  @brief bufferのクラス。std::vectorのpush_back()では挿入が遅い！と言う方に(クラス等は使えないけど^^;
  @since 2004/06/06
	@note
	licence:BSD Licence
*/


#ifndef DKUTIL_BUFFER_HPP
#define DKUTIL_BUFFER_HPP

#include <vector>
#include <dkutil/boost/parm_string.hpp>
#include <dkutil/serialize.hpp>
#include <dkutil/shared_buffer.hpp>

namespace dkutil{

namespace policy{

/*!
テンプレートの特殊化が出来ないVC6用
@note
POD; Plain Old Data = int などの基本型や，コンストラクタ・
デストラクタ・仮想関数などを持たない構造体/共用体など，C と互換
性のある型。
http://www.tietew.jp/cppll_novice/archive/394
より引用。//char_traits
*/
template<typename T>
class pod_traits{
public:
	typedef typename T value_type;
	typedef typename char char_type;
	typedef typename unsigned char byte_type;
	typedef typename size_t size_type;
	typedef typename size_type pos_type;
	static bool is_byte(){
		return 1==sizeof(value_type);
	}
	static void  assign(value_type& __c1, const value_type& c2) {
		c1 = c2; 
	}
	static value_type* assign(value_type* __s, size_t __n, value_type __c)
  { 
		if(is_byte())
		{
			memset(__s, __c,__n);
		}else{
			for(size_t i=0;i<__n;i++)
			{
				__s[i] = __c;
			}
		}
		return __s; 
	}
  static bool  eq(const value_type& c1, const value_type& c2) 
    { return c1 == c2; }
  static bool  lt(const value_type& c1, const value_type& c2) 
    { return c1 < c2; }

  static int  compare(const value_type* s1, const value_type* s2, size_t n) {
    for (size_t i = 0; i < n; ++i)
      if (!eq(s1[i], s2[i]))
        return s1[i] < s2[i] ? -1 : 1;
    return 0;
  }

  static size_t  length(const value_type* s) {
    const value_type _NullChar = _STLP_DEFAULT_CONSTRUCTED(value_type);
    size_t i;
    for (i = 0; !eq(s[i], _NullChar); ++i)
      {}
    return i;
  }

  static const value_type*  find(const value_type* s, size_t n, const value_type& c) {
    for ( ; n > 0 ; ++s, --n)
      if (eq(*s, c))
        return s;
    return 0;
  }

	static value_type *move(value_type *x,const value_type *y,size_type size)
	{
		
			return (size == 0 ? x : (value_type *)memmove(x,y, size * sizeof(value_type)));
  }
  
  static value_type*  copy(value_type* s1, const value_type* s2, size_t n)
	{
    return (n == 0 ? s1 :
	    (value_type*)memcpy(s1, s2, n * sizeof(value_type)));
  } 
	

};

}//end of policy
/**
@note
仕様：
	なるたけ例外を飛ばさない。
	引数のサイズ指定はバイト単位ではなく要素単位で行う。
	offset記憶のないstd::stringのような感じ

@todo
どこかでロジック的なエラーがあるかもしれない。
*/
template<typename T,class Traits,typename A>
class buffer_base{
public:
	typedef typename Traits traits_type;
	typedef typename Traits::pos_type size_type;
	typedef typename T *pointer;
	typedef typename T &reference;
	typedef const T &const_reference;
	typedef const T *const_pointer;
	typedef typename Traits::value_type value_type;
	typedef typename buffer_base<T,Traits,A> self_type;

	typedef A allocator_type;

	//BOOST_STATIC_CONSTANT(size_type,element_size = sizeof(T));
private:
	T *mP;
	size_type mSize;
	allocator_type mA;
	static void at_error(){
		DKUTIL_THROW_OR_NOTICE(std::range_error("buffer_base<>::at() range error"));
	}
public:

	buffer_base(const_reference x){
		mP = NULL;
		mSize = 0;
		copy(&x,element_size());
	}
	buffer_base(const_pointer p,size_type size){
		mP = NULL;
		mSize = 0;
		copy(p,size);
	}
	buffer_base(){
		mP = NULL;
		mSize = 0;
	}
	buffer_base(const self_type &x){
		mP = NULL;
		mSize = 0;
		operator=(x);
	}
	~buffer_base(){
		clear();
	}//char_traits

	///@return 今確保している要素数を返す。
	size_type size()const{
		return mSize / element_size();
	}
	size_type byte_size()const{
		return mSize;
	}
	size_type element_size()const{
		return sizeof(T);
	}
	value_type at(size_type n){
		if(size() <= n){
			at_error();
			return 0;
		}
		return operator[](n);
	}
	const value_type at(size_type n)const{
		if(size() <= n){
			at_error();
			return 0;
		}
		return operator[](n);
	}
	value_type operator[](size_type n){
		return mP[n];
	}
	const	value_type operator[](size_type n)const{
		return mP[n];
	}
	void clear(){
		if(mP){
			mA.deallocate(mP);
			mP = NULL;
		}
		mSize = 0;
	}
	/**

	@param siz[in] 確保したいsizeof(T)の数を入れる。
	すでに確保済みだったらそのまま返す処理はif_reserve()が行います。
	*/
	///	バッファ領域を確保する
	bool reserve(size_type siz){
		if(isValid())
		{//reallocみたいな処理
			//if(siz < size()){//すでに確保されていたらtrue	return true;}
			pointer pt = mA.allocate(siz);
			if(NULL==pt) return false;
			size_type ts = size();
			if(siz < ts){
				traits_type::copy(pt,mP,siz);
				//ts update
				ts = siz;
			}else{
				traits_type::copy(pt,mP,ts);
			}

			
			
			clear();
			
			mP = pt;
			mSize = siz;
			//mP = mA.allocate(siz);

			//traits_type::copy(mP,pt,ts);
		}else{
			mP = mA.allocate(siz);
		}
		mSize = siz;
		return NULL != mP;
	}
	/**
	中身をすべて破棄してから確保しなおす
	*/
	bool resize(size_type siz,const_reference x=value_type()){
		/*clear();
		if(false==reserve(siz)){
			return false;
		}*/
		return assign(siz,x);
	}
	/*bool valid()const{
		return NULL != mP;
	}*/
	bool isValid()const{
		//return valid();
		return NULL != mP && mSize != 0;
	}

	pointer get(){
		return mP;
	}
	const_pointer get()const{
		return mP;
	}

	/*
		bool copy(const value_type *x,size_t size){
		if(false==reset(size)) return false;
		memcpy(get(),x,size);
		return true;
	}*/
	bool copy(const_pointer p,size_type size){
		/*if(size >= mSize || false==isValid()){
			if(false==reserve(size)){
				return false;
			}
		}*/
		DKUTIL_RETURN_FALSE(reserve(size));
		traits_type::copy(mP,p,size);
		return true;
	}
	//bool assign(const reference x){
	//	traits_type::assing(
	//}
	bool assign(size_type n,const_reference x = value_type()){
	
		DKUTIL_RETURN_FALSE(reserve(n));
		
		traits_type::assign(mP,n,x);
		
		return true;
	}

	bool insertion_copy(size_type offset,const_pointer *p,size_type size){
		size_type maxv = std::numelic_limits<size_type>::max();
		//オーバフローするかどうかチェック
		if(maxv - size < offset){
			return false;
		}
		//確保分をオーバーフローするかどうかチェック
		if(offset + size >= mSize || false==isValid()){
			if(false==reserve(offset + size)){
				return false;
			}
		}
		size_type ts = mSize - offset;
		traits_type::copy(mP + ts,p,size);
		return true;
		
	}
	bool reset(size_type size){
		clear();
		
		return reserve(size);
	}
	/*value_type *get(){
		return mP.get();
	}
	const value_type *get()const{
		return mP.get();
	}*/

	///str分バッファを確保してコピーする
	bool copy_string(parm_string str){
		size_t len = str.size();
		//NULL文字分も
		if(false==reset(len + 1)) return false;	
		//memcpy(get(),str.c_str(),len);
		if(DKUTIL_FAILED(
			dkc_strcpy((char *)get(),byte_size(),str.c_str(),len)
			)){
			return false;
		}
		//get()[len] = '\0'; 
		return true;
	}

	///assign()のセキュア版 マルチスレッド対応
	void fill(value_type x){
		synchronized swimming;
		size_t len = byte_size();
		if(0==len) return;
		dkcSecureFillMemory(get(),len,x);
	}
	void fillzero(){
		fill(0);
	}
	bool to_string(std::string &dest)const{
		std::string s;
		if(get()[byte_size()-1] != '\0') return false;
		//if(strlen(get())!=size()-1) return false;
		for(size_t i=0;i<byte_size();i++){
			const char *p = (const char *)get();
			if('\0'==p[i]) break;
			s += p[i];
		}
		dest = s;
		return true;
	}
	///必要だったらresize()
	bool if_resize(size_type siz,value_type v = value_type())
	{
		bool r = true;
		if(size() < siz || false==isValid()){
			r = resize(siz,v);
		}
		return r;
	}
	///
	bool if_reserve(size_type siz){
		bool r = true;
		if(size() < siz || false==isValid()){
			r = reserve(siz);
		}
		return r;
	}
	
	self_type *self(){
		return this;
	}
	const self_type *self()const{
		return this;
	}
	void serialize(ISerializeStream *p)
	{
		uint32 t;
		if(p->is_read_mode())
		{
			*p << t;
			if(false==reset(t))
				throw serialize_error("buffer_base::serialize() read reset() error");
		}else{
			if(false==isValid())
				throw serialize_error("buffer_base::serialize() write false==isValid() error");
			t = size();
			*p << t;
		}
		p->serialize(get(),size());		
	}
	///@return シリアライズする時のファイルに出力するバイト単位のサイズを返す。
	size_t serialize_size()const{
		return byte_size() + sizeof(uint32);
	}
	friend bool operator==(const self_type &x,const self_type &y)
	{
		if(x.size() != y.size()) return false;
		bool r = 0==memcmp(x.get(),y.get(),x.byte_size());
		return r;
	}
	friend bool operator!=(const self_type &x,const self_type &y)
	{
		return !operator==(x,y);
	}
	self_type &operator=(const shared_buffer &x){
		if(element_size() != 1){
			DKUTIL_THROW_OR_NOTICE(
				std::runtime_error("buffer_base operator=(const shared_buffer &) element_size() != 1")
			);
			return *this;
		}
		if(false==copy(x.get_const(),x.size())){
			DKUTIL_THROW_OR_NOTICE(
				std::runtime_error("buffer_base operator=(const shared_buffer &) copy() error")
			);
		}
		return *this;
	}
	self_type &operator=(const self_type &x){
			
	if(false==copy(x.get(),x.size())){
			DKUTIL_THROW_OR_NOTICE(
				std::runtime_error("buffer_base operator=(const self_type &) copy() error")
			);
		}
		return *this;

	}
	friend bool operator<(const self_type &x,const self_type &y){
		if(x.byte_size() < y.byte_size()) return true;
		if(x.byte_size()== y.byte_size()) 
			return (memcmp(x.get(),y.get(),x.byte_size()) < 0);
		return false;
	}

			

};

typedef buffer_base<unsigned char,policy::pod_traits<unsigned char>,std::allocator<unsigned char> > byte_buffer;
typedef buffer_base<char,policy::pod_traits<char>,std::allocator<char> > char_buffer;
typedef buffer_base<uint32,policy::pod_traits<uint32>,std::allocator<uint32> > uint32_buffer;
#if 0
/**
@param POLICY_T bool is_read_mode() と store(uint8 *,size_t)を備えたクラス
*/
template<class POLICY_T>
class buffered_interface : public POLICY_T{
	
public:
	typedef typename POLICY_T policy_type;
	typedef typename POLICY_T base_type;
	buffered_interface(int EndianType,size_t inner_buffer_size = 1024 * 64) 
		: mS(inner_buffer_size)
	{
		reserve(ibs);
	}
	~buffered_interface(){
		clear();
	}
	void clear(){
		mBuff.clear();
	}
	///内部メモリバッファのサイズを変更する
	bool reserve(size_t ibs){
		clear();
		
		if(0==ibs){
			ibs = inner_buffer_size;
		}
		if(ibs % 64){//64byteで割り切れなかったら。
			ibs += (ibs % 64);
		}
		return mBuff.reset(ibs);
	}
	bool need_update(size_t size){
		return (size < mOffset + size);
	}
	bool update_action(){
		if(base_type::is_read_mode())
		{
			size_t rs = base_type::read(mBuff.data(),mBuff.size());
			mOffset= 0;
			mLimit = rs;
			
		}else{
			size_t ws = base_type::write(mBuff.get(),mOffset);
			if(ws != mOffset) return false;
			mOffset = 0;
			mLimit = mBuff.size();
		}
	}
	virtual bool write(const void *buff,size_t size,size_t *write_size){
		if(need_update(size)){
			update_action();
		}
		if(mBuff.size() > size){

		}
	}
	
protected:
	policy_type mP;
	byte_buffer mBuff;
	size_t mLimit,mOffset;
	int mEndianMode
public:

};
#endif

/*
template
class exception_buffer_base : public buffer_base<T,Traits,A>{
	
	static void error_throw__(const char *s)const{
		char str[256]="buffer_base | ";
		dkc_strcat(str,sizeof(str),strlen(str),s,strlen(s));
		DKUTIL_THROW_OR_NOTICE(std::runtime_error(str));
	}
public:
};
*/

}//end of dkutil namepsace

#endif //end of include once

