Original in Russian: http://18delphi.blogspot.ru/2013/07/blog-post_3683.html
About containers. Table of contents
Now I want to tell about the practice of creating “pattern” container in “STL style”.
FOR NOW – WITHOUT the “true” Generics (http://18delphi.blogspot.com/2015/02/containers-3-generics-and-without.html). They ALSO can be used. But FOR NOW – there is a NUMBER OF UNCLOSED errors, which for some reason Embarcadero does not hurry to close. That is a weak point. What to say. Even my error (http://qc.embarcadero.com/wc/qcmain.aspx?d=116040 http://18delphi.blogspot.com/2013/05/xe4.html) - has been "kind of corrected", but not closed. Even so that was a minor matter. If I get it my way right...
One remark. Despite the fact that in STL such containers are called vector, I’ve decided to keep continuity with Delphi and name it List.
So. As usual.
The model:
The code:
List.imp.pas:
{$IfNDef List_imp} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // The library "SandBox" // The unit: "List.imp.pas" // Native Delphi interfaces (.pas) // Generated from UML model, root element: Impurity::Class Shared Delphi Sand Box::SandBox::STLLike::List // // The abstract list of values // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {$Define List_imp} PItemType = ^_ItemType_; const { Sizes } cItemSize = SizeOf(_ItemType_); type IndexType = System.Integer; _List_ = {mixin} class(_List_Parent_) {* The abstract list of values } private // private fields f_Data : Tl3PtrLoc; f_Count : IndexType; {* The field for the property Count} private // private methods procedure ReAllocList(aNewCapacity: IndexType); procedure CheckIndex(anIndex: IndexType); // can raise EListError {* checks the validity of the index and raises an exception if it is incorrect } function ItemSlot(anIndex: IndexType): PItemType; function ExpandSize(aTargetSize: IndexType): Cardinal; procedure CheckSetItem(anIndex: IndexType); // can raise EListError {* Checks the validity of the index upon insert } protected // property methods procedure pm_SetCount(aValue: IndexType); function pm_GetCapacity: IndexType; procedure pm_SetCapacity(aValue: IndexType); function pm_GetItems(anIndex: IndexType): _ItemType_; procedure pm_SetItems(anIndex: IndexType; const aValue: _ItemType_); protected // overridden protected methods procedure Cleanup; override; {* The function of object fields cleaning. } public // public properties property Count: IndexType read f_Count write pm_SetCount; property Capacity: IndexType read pm_GetCapacity write pm_SetCapacity; property Items[anIndex: IndexType]: _ItemType_ read pm_GetItems write pm_SetItems; default; {* The items of the list. } end;//_List_ {$Else List_imp} // start class _List_ procedure _List_.ReAllocList(aNewCapacity: IndexType); //#UC START# *51DEB8770017_51DEB07E03E4_var* var l_Cap : Integer; l_Cnt : Integer; //#UC END# *51DEB8770017_51DEB07E03E4_var* begin //#UC START# *51DEB8770017_51DEB07E03E4_impl* f_Data.SetSize(aNewCapacity * cItemSize); l_Cap := Self.Capacity; Assert(l_Cap >= aNewCapacity); l_Cnt := f_Count; if (l_Cap > l_Cnt) then System.FillChar(ItemSlot(l_Cnt)^, (l_Cap - l_Cnt) * cItemSize, 0); //#UC END# *51DEB8770017_51DEB07E03E4_impl* end;//_List_.ReAllocList procedure _List_.CheckIndex(anIndex: IndexType); // can raise EListError //#UC START# *51DEB95E00BD_51DEB07E03E4_var* procedure _Error; begin raise EListError.CreateFmt(SListIndexError + ' from (%d)', [anIndex, f_Count]) end; //#UC END# *51DEB95E00BD_51DEB07E03E4_var* begin //#UC START# *51DEB95E00BD_51DEB07E03E4_impl* if (anIndex < 0) or (anIndex >= f_Count) then _Error; //#UC END# *51DEB95E00BD_51DEB07E03E4_impl* end;//_List_.CheckIndex function _List_.ItemSlot(anIndex: IndexType): PItemType; //#UC START# *51DEBE2D008A_51DEB07E03E4_var* //#UC END# *51DEBE2D008A_51DEB07E03E4_var* begin //#UC START# *51DEBE2D008A_51DEB07E03E4_impl* Result := PItemType(f_Data.AsPointer + anIndex * cItemSize); assert(Result <> nil); //#UC END# *51DEBE2D008A_51DEB07E03E4_impl* end;//_List_.ItemSlot function _List_.ExpandSize(aTargetSize: IndexType): Cardinal; //#UC START# *51DEC11F0058_51DEB07E03E4_var* const cIncrArray : array [0..3] of Integer = (64 * 1024, 1024, 128, 4); cMaxForTwice : Integer = 1 * 1024 * 1024; var I : Integer; //#UC END# *51DEC11F0058_51DEB07E03E4_var* begin //#UC START# *51DEC11F0058_51DEB07E03E4_impl* Assert(aTargetSize > 0); Result := aTargetSize; if (Result > cMaxForTwice) then // we do not double large arrays, but even them to 1 Mb Result := (aTargetSize div cMaxForTwice + 1) * cMaxForTwice else begin for I := 0 to High(cIncrArray) do if (aTargetSize > cIncrArray[I]) then begin Result := (aTargetSize div cIncrArray[I]) * cIncrArray[I] * 2; Break; end;//aTargetSize > cIncrArray[I] end;//Result > cMaxForTwic //#UC END# *51DEC11F0058_51DEB07E03E4_impl* end;//_List_.ExpandSize procedure _List_.CheckSetItem(anIndex: IndexType); // can raise EListError //#UC START# *51DECAA8035E_51DEB07E03E4_var* //#UC END# *51DECAA8035E_51DEB07E03E4_var* begin //#UC START# *51DECAA8035E_51DEB07E03E4_impl* CheckIndex(anIndex); //#UC END# *51DECAA8035E_51DEB07E03E4_impl* end;//_List_.CheckSetItem procedure _List_.pm_SetCount(aValue: IndexType); //#UC START# *51DEB1ED0017_51DEB07E03E4set_var* procedure SayBadCount(aNewCount: LongInt); begin raise EListError.CreateFmt(sListIndexError, [aNewCount]); end; var l_Ptr : PItemType; {$IfNDef l3Items_IsUnrefcounted} l_Index : Integer; {$EndIf l3Items_IsUnrefcounted} //#UC END# *51DEB1ED0017_51DEB07E03E4set_var* begin //#UC START# *51DEB1ED0017_51DEB07E03E4set_impl* if (aValue < 0) then SayBadCount(aValue); if (aValue < f_Count) then begin l_Ptr := ItemSlot(aValue); {$IfDef l3Items_IsUnrefcounted} System.FillChar(l_Ptr^, (f_Count - 1 - aValue) * cItemSize, 0); {$Else l3Items_IsUnrefcounted} for l_Index := aValue to f_Count - 1 do begin FreeItem(l_Ptr^); Inc(PMem(l_Ptr), cItemSize); end;//for i {$EndIf l3Items_IsUnrefcounted} end//aValue < f_Count else if (aValue > Self.Capacity) then ReAllocList(ExpandSize(aValue)); if (f_Count < aValue) then System.FillChar(ItemSlot(f_Count)^, (aValue - f_Count) * cItemSize, 0); f_Count := aValue; //#UC END# *51DEB1ED0017_51DEB07E03E4set_impl* end;//_List_.pm_SetCount function _List_.pm_GetCapacity: IndexType; //#UC START# *51DEB20E0130_51DEB07E03E4get_var* //#UC END# *51DEB20E0130_51DEB07E03E4get_var* begin //#UC START# *51DEB20E0130_51DEB07E03E4get_impl* Result := f_Data.GetSize div cItemSize; //#UC END# *51DEB20E0130_51DEB07E03E4get_impl* end;//_List_.pm_GetCapacity procedure _List_.pm_SetCapacity(aValue: IndexType); //#UC START# *51DEB20E0130_51DEB07E03E4set_var* procedure SayBadCap(aNewCapacity: IndexType); begin raise EListError.CreateFmt(sListIndexError, [aNewCapacity]); end; //#UC END# *51DEB20E0130_51DEB07E03E4set_var* begin //#UC START# *51DEB20E0130_51DEB07E03E4set_impl* if (aValue < 0) then SayBadCap(aValue); if (pm_GetCapacity <> aValue) then begin { If the list is shrinking, then update _Count for the smaller size. } if (aValue < f_Count) then Count := aValue; ReAllocList(aValue); end;//GetCapacity(Self) <> aValue //#UC END# *51DEB20E0130_51DEB07E03E4set_impl* end;//_List_.pm_SetCapacity function _List_.pm_GetItems(anIndex: IndexType): _ItemType_; //#UC START# *51DECA1202C5_51DEB07E03E4get_var* //#UC END# *51DECA1202C5_51DEB07E03E4get_var* begin //#UC START# *51DECA1202C5_51DEB07E03E4get_impl* CheckIndex(anIndex); Result := ItemSlot(anIndex)^; //#UC END# *51DECA1202C5_51DEB07E03E4get_impl* end;//_List_.pm_GetItems procedure _List_.pm_SetItems(anIndex: IndexType; const aValue: _ItemType_); //#UC START# *51DECA1202C5_51DEB07E03E4set_var* {$IfNDef l3Items_IsAtomic} var l_P : PItemType; {$EndIf l3Items_IsAtomic} //#UC END# *51DECA1202C5_51DEB07E03E4set_var* begin //#UC START# *51DECA1202C5_51DEB07E03E4set_impl* CheckSetItem(anIndex); {$IfDef l3Items_IsAtomic} PItemType(ItemSlot(anIndex))^ := aValue; {$Else l3Items_IsAtomic} l_P := PItemType(ItemSlot(anIndex)); if not IsSame(l_P^, aValue) then begin FreeItem(l_P^); FillItem(l_P^, aValue); end;//not IsSame(l_P^, anItem) {$EndIf l3Items_IsAtomic} //#UC END# *51DECA1202C5_51DEB07E03E4set_impl* end;//_List_.pm_SetItems procedure _List_.Cleanup; //#UC START# *479731C50290_51DEB07E03E4_var* //#UC END# *479731C50290_51DEB07E03E4_var* begin //#UC START# *479731C50290_51DEB07E03E4_impl* Count := 0; f_Data.SetSize(0); inherited; //#UC END# *479731C50290_51DEB07E03E4_impl* end;//_List_.Cleanup {$EndIf List_imp}
UnrefcountedListPrim.imp.pas:
{$IfNDef UnrefcountedListPrim_imp} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // The library "SandBox" // The unit: "UnrefcountedListPrim.imp.pas" // Native Delphi interfaces (.pas) // Generated from UML model, root element: Impurity::Class Shared Delphi Sand Box::SandBox::STLLike::UnrefcountedListPrim // // The list of values without any reference counting // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {$Define UnrefcountedListPrim_imp} {$Define l3Items_IsUnrefcounted} _List_Parent_ = _UnrefcountedListPrim_Parent_; {$Include List.imp.pas} _UnrefcountedListPrim_ = {mixin} class(_List_) {* The list of values without any reference counting } end;//_UnrefcountedListPrim_ {$Else UnrefcountedListPrim_imp} // start class _UnrefcountedListPrim_ function IsSame(const A: _ItemType_; const B: _ItemType_): Boolean; //#UC START# *51DECB820261_51DED02E0163_var* //#UC END# *51DECB820261_51DED02E0163_var* begin //#UC START# *51DECB820261_51DED02E0163_impl* Result := (A = B); //#UC END# *51DECB820261_51DED02E0163_impl* end;//IsSame type _List_R_ = _UnrefcountedListPrim_; {$Include List.imp.pas} {$EndIf UnrefcountedListPrim_imp}
AtomicList.imp.pas:
{$IfNDef AtomicList_imp} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // The library "SandBox" // The unit: "AtomicList.imp.pas" // Native Delphi interfaces (.pas) // Generated from UML model, root element: Impurity::Class Shared Delphi Sand Box::SandBox::STLLike::AtomicList // // The list of atomic values // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {$Define AtomicList_imp} {$Define l3Items_IsAtomic} _UnrefcountedListPrim_Parent_ = _AtomicList_Parent_; {$Include UnrefcountedListPrim.imp.pas} _AtomicList_ = {mixin} class(_UnrefcountedListPrim_) {* The list of atomic values } end;//_AtomicList_ {$Else AtomicList_imp} // start class _AtomicList_ procedure FillItem(var thePlace: _ItemType_; const aFrom: _ItemType_); forward; procedure FreeItem(var thePlace: _ItemType_); //#UC START# *51DEC20B01D7_51DED48301D9_var* //#UC END# *51DEC20B01D7_51DED48301D9_var* begin //#UC START# *51DEC20B01D7_51DED48301D9_impl* thePlace := _ItemType_(0); //#UC END# *51DEC20B01D7_51DED48301D9_impl* end;//FreeItem procedure FillItem(var thePlace: _ItemType_; const aFrom: _ItemType_); //#UC START# *51DECB440087_51DED48301D9_var* //#UC END# *51DECB440087_51DED48301D9_var* begin //#UC START# *51DECB440087_51DED48301D9_impl* thePlace := aFrom; //#UC END# *51DECB440087_51DED48301D9_impl* end;//FillItem type _UnrefcountedListPrim_R_ = _AtomicList_; {$Include UnrefcountedListPrim.imp.pas} {$EndIf AtomicList_imp}
The code is here - http://sourceforge.net/p/rumtmarc/code-0/19/tree/trunk/Blogger/SandBox and http://sourceforge.net/p/rumtmarc/code-0/19/tree/trunk/Blogger/SandBoxTest
Комментариев нет:
Отправить комментарий