#ifndef _KILIB_KTL_GAP_H_ #define _KILIB_KTL_GAP_H_ #include "types.h" #include "memory.h" #ifndef __ccdoc__ namespace ki { #endif //========================================================================= //@{ @pkg ki.KTL //@} //@{ // 基本型専用ギャップバッファ // // 小耳に挟んだギャップバッファというもの。 // ものすごい勘違いをして別物ができているかもしれませんが、 // 細かいことはあまり気にしないでください。 // 配列のようにランダムアクセス可能で、 // 同一箇所への連続した挿入/削除が速いというデータ構造です。 // ( 下の図で言うと、gap_startへの挿入/削除にはデータの移動が必要ない ) //
//@@  D  <--0
//@@  D
//@@  |  <--gap_start
//@@  |
//@@  D  <--gap_end
//@@  D
//@@     <--array_end
//	
// メモリイメージをそのままコピーしてる実装なので、 // プリミティブ型以外では絶対に使わないこと。 //@} //========================================================================= template class gapbuf : public Object { public: //@{ // コンストラクタ // @param alloc_size // 最初に確保する"メモリの"サイズ。 // "配列の"サイズではないことに注意。 //@} explicit gapbuf( ulong alloc_size=40 ) : alen_( Max(alloc_size, 10UL) ) , gs_ ( 0 ) , ge_ ( alen_ ) , buf_ ( new T[alen_] ) {} ~gapbuf() { delete [] buf_; } //@{ 要素挿入 //@} void InsertAt( ulong i, const T& x ) { MakeGapAt( i ); buf_[gs_++] = x; if( gs_==ge_ ) Reallocate( alen_<<1 ); } //@{ 要素挿入(複数) //@} void InsertAt( ulong i, const T* x, ulong len ) { MakeGapAt( size() ); MakeGapAt( i ); if( ge_-gs_ <= len ) Reallocate( Max(alen_+len+1, alen_<<1) ); memmove( buf_+gs_, x, len*sizeof(T) ); gs_ += len; } //@{ 末尾に要素を追加 //@} void Add( const T& x ) { InsertAt( size(), x ); } //@{ 末尾に要素を追加(複数) //@} void Add( const T* x, ulong len ) { InsertAt( size(), x, len ); } //@{ 要素削除 //@} void RemoveAt( ulong i, ulong len=1 ) { if( i <= gs_ && gs_ <= i+len ) { // この場合はメモリ移動の必要がない // まず前半を削除 len -= (gs_-i); gs_ = i; } else { MakeGapAt( i ); } // 後半を削除 ge_ += len; } //@{ 要素削除(全部) //@} void RemoveAll() { RemoveAt( 0, size() ); } //@{ 要素削除(指定index以降全部) //@} void RemoveToTail( ulong i ) { RemoveAt( i, size()-i ); } //@{ 要素コピー(指定index以降全部) //@} ulong CopyToTail( ulong i, T* x ) { return CopyAt( i, size()-i, x ); } //@{ 要素コピー //@} ulong CopyAt( ulong i, ulong len, T* x ) { ulong copyed=0; if( i < gs_ ) { // 前半 copyed += Min( len, gs_-i ); memmove( x, buf_+i, copyed*sizeof(T) ); x += copyed; len -= copyed; i += copyed; } // 後半 memmove( x, buf_+(i-gs_)+ge_, len*sizeof(T) ); return copyed + len; } public: //@{ 要素数 //@} ulong size() const { return alen_ - (ge_-gs_); } //@{ 要素取得 //@} T& operator[]( ulong i ) { return buf_[ ( igs_ ) { int j = i+(ge_-gs_); memmove( buf_+gs_, buf_+ge_, (j-ge_)*sizeof(T) ); ge_ = j; } gs_ = i; } void Reallocate( ulong newalen ) { T *tmp = new T[newalen], *old=buf_; const ulong tail = alen_-ge_; memmove( tmp, old, gs_*sizeof(T) ); memmove( tmp+newalen-tail, old+ge_, tail*sizeof(T) ); delete [] old; buf_ = tmp; ge_ = newalen-tail; alen_ = newalen; } private: NOCOPY(gapbuf); }; //========================================================================= //@{ // gapbuf + smartptr のふり // // 要素削除時にdeleteを実行しっちゃったりするバージョン。 // 任意オブジェクトをギャップバッファで使いたいときは // これでてきとーに代用すべし。 //@} //========================================================================= template class gapbufobj : public gapbuf { public: explicit gapbufobj( ulong alloc_size=40 ) : gapbuf( alloc_size ) { } void RemoveAt( ulong i, ulong len=1 ) { ulong& gs_ = gapbuf::gs_; ulong& ge_ = gapbuf::ge_; T**& buf_= gapbuf::buf_; if( i <= gs_ && gs_ <= i+len ) { // 前半を削除 for( ulong j=i, ed=gs_; j::MakeGapAt( i ); } // 後半を削除 for( ulong j=ge_, ed=ge_+len; j::size() ); } void RemoveAll( ulong i ) { RemoveAt( 0, gapbuf::size() ); } void RemoveToTail( ulong i ) { RemoveAt( i, gapbuf::size()-i ); } public: T& operator[]( ulong i ) { return *gapbuf::operator[](i); } const T& operator[]( ulong i ) const { return *gapbuf::operator[](i); } private: NOCOPY(gapbufobj); }; //========================================================================= } // namespace ki #endif // _KILIB_KTL_GAP_H_