c++カスタムダイナミック配列テンプレート

9354 ワード

本明細書では、連続する空間を必要とするコンテナをカスタマイズし、割り当てられた空間を有効に利用し、より効率的な配列オブジェクト操作を提供し、参照カウントを使用してメモリコピーを低減する動的配列テンプレートクラス(Array)について説明します.メモリヘッドには、記述ブロック、有効なデータオブジェクト数、および合計メモリオブジェクトサイズが記録されます.特徴は以下の通りである:(1)Arrayとstd::vectorまたはstd::arrayは異なる.Arrayは連続するオブジェクトを格納し、オブジェクトメモリの前に配列記述ブロックを開いて配列を記述する.(2)Arrayに格納されているデータ数は動的であり,setLengthで調整できるとともに,+=演算子を用いて配列にデータを追加できる.(3)複数の配列インスタンスは、同一のデータコンテンツを使用することが可能であり、重複してコンテンツを作成しないことが、配列クラスの最も重要な特性であり、主な目的である.すなわち、1つのArrayオブジェクトから新しいArrayオブジェクトを構築したり、他のArrayに値を付与したりした場合、新しいメモリ申請およびコピーは生成されない.複数のArrayのデータは同じメモリ領域を指し、共通のメモリ領域は参照カウントによって管理される.(4)メモリ領域を指すArrayオブジェクトがすべて破棄されると、メモリは解放される.(5)空のArrayにコンテンツを追加すると,新しいデータを格納するために自動的に新しいメモリ領域を開く.(6)既に含まれているArrayに対して追加または書き換え([]下付き演算)を行うと、配列に含まれる内領域が他の配列によっても参照されると、自動的に元のメモリ領域への参照が解除され、新しいメモリ領域が作成されて新しいデータが格納される.使用上の注意:頻繁にデータを追加する操作は非常に非効率であり、追加する数量が確定した場合はsetLengthまたはsetCapacityを呼び出して最終長さまたは容量を設定してから追加すると性能が向上します.使用上の注意:Array設計はデータアクセスのみを提供するため、配列に格納されているコンテンツはコンストラクション関数とコンストラクション関数を呼び出すことはありません.具体的なコードは以下のように実現される.
template 
class Array
{
public:
	typedef T TYPE;
	struct ArrayDesc //      
	{
		volatile int refer;//    
		volatile unsigned int capacity;//      
		volatile unsigned int length;//        
	};
protected:
	T* m_ptr;
public:
	Array()
	{
		m_ptr = NULL;
	}
	Array(const Array &another)
	{
		m_ptr = NULL;
		operator = (another);
	}
	Array(const T* ptr, size_t length)
	{
		m_ptr = NULL;
		setLength(length);
		memcpy(m_ptr, ptr, length * sizeof(*ptr));
	}
	Array(size_t length)
	{
		m_ptr = NULL;
		setLength(length);
	}
	~Array()
	{
		setLength(0);
	}


	//   =               (           ,        1 ,          ,       )
	inline Array& operator =(const Array &another)
	{
		if (m_ptr != another.m_ptr)//         
		{
			setLength(0);
			//        
			if (another.m_ptr)
			{
				ArrayDesc *pDesc = ((ArrayDesc*) another.m_ptr) - 1;//           
				lock_inc(pDesc->refer);//               
				m_ptr = (T*) (pDesc + 1);//                     
			}
		}
		return *this;
	}

	inline Array operator +(const Array &another)
	{
		Array < T > result;
		if (m_ptr || another.m_ptr)
		{
			size_t myCount = length();
			size_t anotherCount = another.length();
			result.setLength(myCount + anotherCount);//         
			T* destPtr = result.m_ptr;
			if (myCount > 0)
			{
				memcpy(destPtr, m_ptr, myCount * sizeof(*m_ptr));//          
				destPtr += myCount;
			}
			if (anotherCount > 0)
			{
				memcpy(destPtr, another.m_ptr, anotherCount * sizeof(*m_ptr));//            
				destPtr += myCount;
			}
		}
		return result;//        
	}

	//        ,             
	inline Array operator +(const T &another)
	{
		size_t myCount = length();
		Array < T > result(myCount + 1);//           
		if (myCount > 0) memcpy(result.m_ptr, m_ptr, myCount * sizeof(*m_ptr));//             
		result.m_ptr[myCount] = another;//         
		return result;
	}
	//          
	inline Array& operator +=(const Array &another)
	{
		size_t len = another.length();
		if (len > 0) cat(another.m_ptr, another.length());
		return *this;
	}
	//        ,       
	inline Array& operator +=(const T &another)
	{
		size_t myCount = length();
		setLength(myCount + 1);
		m_ptr[myCount] = another;
		return *this;
	}
	//                    
	inline T& operator [](size_t index)
	{
		if (!m_ptr) return *(T*) NULL;
		ArrayDesc *pDesc = ((ArrayDesc*) m_ptr) - 1;
		assert(index < pDesc->length);//                
		duplicate();
		return m_ptr[index];
	}
	//                    (cosnt  )
	inline const T& operator [](size_t index) const
	{
		if (!m_ptr) return *(T*) NULL;
		ArrayDesc * const pDesc = ((ArrayDesc* const ) m_ptr) - 1;
		assert(index < pDesc->length);//                
		return m_ptr[index];
	}
	//              
	inline bool operator ==(const Array &another) const
	{
		return m_ptr == another.m_ptr;
	}
	//               
	inline bool operator !=(const Array &another) const
	{
		return m_ptr != another.m_ptr;
	}
	//           
	inline const T* ptr() const
	{
		return m_ptr;
	}
	//           
	inline T* own_ptr()
	{
		duplicate();//                  ,            ,                 
		return m_ptr;
	}
	//            
	inline size_t length() const
	{
		if (!m_ptr) return 0;
		ArrayDesc * const pDesc = ((ArrayDesc* const ) m_ptr) - 1;
		return pDesc->length;
	}
	//                       
	inline Array& cat(const T* ptr, size_t count)
	{
		return insert(length(), ptr, count);
	}

	//                      
	inline Array& insert(size_t index, const T* ptr, size_t count)
	{
		if (count > 0)
		{
			ArrayDesc *pMyDesc = m_ptr ? ((ArrayDesc*) m_ptr) - 1 : NULL;
			size_t myCount = pMyDesc ? pMyDesc->length : 0;
			//         
			assert(index <= myCount);
			//                  ,            ,    
			// setLength ptr    ,        ptr   。
			bool isMySelf = false;
			size_t inMyPos = 0;
			if (pMyDesc && (ptr >= m_ptr) && (ptr <= (m_ptr + pMyDesc->capacity)))
			{
				isMySelf = true;//                     
				inMyPos = ptr - m_ptr;//          
				if (inMyPos >= index) inMyPos += count;//                ptr( setLength     )
			}
			setLength(myCount + count);//            

			//              (            ,memmove           ,memcpy           )
			if (index < myCount) memmove(&m_ptr[index + count], &m_ptr[index], sizeof(*ptr) * (myCount - index));
			//                 
			if (isMySelf)  memcpy(&m_ptr[index], &m_ptr[inMyPos], count * sizeof(*m_ptr));
			else memcpy(&m_ptr[index], ptr, count * sizeof(*m_ptr));
		}
		return *this;
	}

	inline Array& remove(size_t index, size_t count)
	{
		if (count > 0)
		{
			duplicate();//            (      1       ,             )
			ArrayDesc *pMyDesc = m_ptr ? ((ArrayDesc*) m_ptr) - 1 : NULL;
			size_t myCount = pMyDesc ? pMyDesc->length : 0;
			assert(index < myCount);
			if (count > myCount - index) count = myCount - index;
			size_t copyCount = myCount - index - count;
			if (copyCount > 0) memcpy(&m_ptr[index], &m_ptr[index + count], sizeof(*m_ptr) * copyCount);
			setLength(myCount - count);
		}
		return *this;
	}

	inline Array& setLength(const size_t length)
	{
		assert(length >= 0);
		ArrayDesc *pDesc = NULL;
		if (m_ptr) pDesc = ((ArrayDesc*) m_ptr) - 1;
		if (length == 0)//       
		{
			if (pDesc)
			{
				if (lock_dec(pDesc->refer) <= 0) //     0,          
				    free(pDesc);
				m_ptr = NULL;
			}
		}
		else if (pDesc)
		{
			if (length != pDesc->length)
			{
				//      1              (          )
				if (pDesc->refer > 1)
				{
					lock_dec(pDesc->refer);//          
					ArrayDesc *pNewDesc = (ArrayDesc*) calloc(1, sizeof(*pDesc) + sizeof(*m_ptr)
							* (length + 1));//        ,calloc      ,          0,    
					pNewDesc->capacity = (unsigned int) length;
					pNewDesc->length = (unsigned int) length;
					pNewDesc->refer = 1;
					m_ptr = (T*) (pNewDesc + 1);//                   
					size_t lengthMin = pDesc->length < length ? pDesc->length : length;
					memcpy(m_ptr, pDesc + 1, lengthMin * sizeof(*m_ptr));//                 
				}
				else //     1         ,               
				{
					if (length >= pDesc->capacity)//                      
					{
						pDesc = (ArrayDesc*) realloc(pDesc, sizeof(*pDesc) + sizeof(*m_ptr) * (length + 1));
						//                     
						m_ptr = (T*) (pDesc + 1);
						//               
						memset(&m_ptr[pDesc->length], 0, sizeof(*m_ptr) * (length - pDesc->capacity + 1));
						pDesc->capacity = (unsigned int) length;//    
						pDesc->length = (unsigned int) length;//    
					}
					else pDesc->length = (unsigned int) length;//            
				}
				memset(&m_ptr[length], 0, sizeof(*m_ptr));//                 0(             )
			}
		}
		else //            ,                            
		{
			ArrayDesc *pNewDesc =
			(ArrayDesc*) calloc(1, sizeof(*pDesc) + sizeof(*m_ptr) * (length + 1));
			pNewDesc->capacity = (unsigned int) length;
			pNewDesc->length = (unsigned int) length;
			pNewDesc->refer = 1;
			m_ptr = (T*) (pNewDesc + 1);
		}
		return *this;
	}
	inline size_t capacity() const
	{
		if (m_ptr)
		{
			ArrayDesc *pDesc = ((ArrayDesc*) m_ptr) - 1;
			return pDesc->capacity;
		}
		return 0;
	}
	inline Array& setCapacity(size_t capacity)
	{
		size_t myCount = length();//        。         ,    setLength(0)
		if (capacity > myCount)
		{
			setLength(capacity);
			ArrayDesc *pDesc = ((ArrayDesc*) m_ptr) - 1;
			pDesc->length = myCount;
		}
		return *this;
	}
protected:
	inline void duplicate()//              
	{
		if (m_ptr)
		{
			ArrayDesc *pDesc = ((ArrayDesc*)m_ptr) - 1;//             
			if (pDesc->refer > 1)
			{
				ArrayDesc *pNewDesc = (ArrayDesc*)malloc(sizeof(*pDesc) + sizeof(*m_ptr) * (pDesc->capacity + 1));//             
				pNewDesc->capacity = pDesc->capacity;
				pNewDesc->length = pDesc->length;
				pNewDesc->refer = 1;
				m_ptr = (T*)(pNewDesc + 1);//               
				memcpy( m_ptr,pDesc + 1, (pDesc->length + 1) * sizeof(*m_ptr));//                        
				lock_dec(pDesc->refer);//           
			}
		}
	}
};