Блог человека, который 18-ть лет программирует на Delphi. И 25 лет программирует вообще. VCL, UML, MDA, тесты. Это не "учебник", это - "заметки на полях".
суббота, 28 февраля 2015 г.
четверг, 26 февраля 2015 г.
Containers 10. About patterns and mixins
Original in Russian: http://18delphi.blogspot.ru/2013/03/blog-post_29.html
About containers. Table of contents
Now let’s talk about mixins a bit.
The theory can be read here:
https://en.wikipedia.org/wiki/Mixin
Instead, we’ll go in for practice.
Let’s look at the definition:
In object-oriented programming languages, a mixin is a class that contains a combination of methods from other classes. How such a combination is done depends on the language, but it is not by inheritance. If a combination contains all methods of combined classes, it is equivalent tomultiple inheritance.
Mixins encourage code reuse and can be used to avoid the inheritance ambiguity that multiple inheritance can cause (the "diamond problem"), or to work around lack of support for multiple inheritance in a language.
A mixin can also be viewed as an interface with implemented methods. When a class includes a mixin, the class implements the interface and includes, rather than inherits, all the mixin's attributes (fields, properties) and methods. They become part of the class during compilation.
A mixin can defer definition and binding of methods untilruntime, though attributes and instantiation parameters are still defined at compile time. This differs from the most widely used approach (which originated in the programming language Simula) of defining all attributes, methods and initialization at compile time.
Those who code on C++ are lucky, because they have multiple inheritance and the question “how to add mixin to the existing class hierarchy” does not arise. Delphi programmers are not lucky. There is no multiple inheritance. Actually, thank God – mixins are far more highly specialized tool then multiple inheritance.
I will write separately about the particular examples of using the mixins in life. And now let’s consider a purely abstract example illustrating only the technique of embedding the mixin class to the hierarchy of inheritance of designed classes.
In the previous article we had an example:
Let’s redraw the diagram in this way:
We can see that functionality of Stack'а has completely moved to StackPrim.
And two more classes have appeared – TintStackFromPersisten, inherited from TPersistent and StackPrim, and class TIntStackFromComponent, inherited from TComponent and StackPrim.
Multiple inheritance – you’d ask. Logically – yes. At the level of the diagrams arrows.
Let’s see how it all looks on Delphi:
StackPrim.imp.pas:
---------------------------------------------
Stack.imp.pas:
---------------------------------------------
StringStack.pas:
---------------------------------------------
IntStack.pas:
---------------------------------------------
!!! And there are two NEW classes:
---------------------------------------------
IntStackFromPersistent.pas:
---------------------------------------------
IntStackFromComponent.pas:
---------------------------------------------
As for me, it is fun :-) There is only ONE mixin, but it is added to FOUR different classes and even different places in the hierarchy of the inheritance.
Try it. May be you will like it.
In the next series I will try to tell WHY do I use it.
About containers. Table of contents
Now let’s talk about mixins a bit.
The theory can be read here:
https://en.wikipedia.org/wiki/Mixin
Instead, we’ll go in for practice.
Let’s look at the definition:
In object-oriented programming languages, a mixin is a class that contains a combination of methods from other classes. How such a combination is done depends on the language, but it is not by inheritance. If a combination contains all methods of combined classes, it is equivalent tomultiple inheritance.
Mixins encourage code reuse and can be used to avoid the inheritance ambiguity that multiple inheritance can cause (the "diamond problem"), or to work around lack of support for multiple inheritance in a language.
A mixin can also be viewed as an interface with implemented methods. When a class includes a mixin, the class implements the interface and includes, rather than inherits, all the mixin's attributes (fields, properties) and methods. They become part of the class during compilation.
A mixin can defer definition and binding of methods untilruntime, though attributes and instantiation parameters are still defined at compile time. This differs from the most widely used approach (which originated in the programming language Simula) of defining all attributes, methods and initialization at compile time.
Those who code on C++ are lucky, because they have multiple inheritance and the question “how to add mixin to the existing class hierarchy” does not arise. Delphi programmers are not lucky. There is no multiple inheritance. Actually, thank God – mixins are far more highly specialized tool then multiple inheritance.
I will write separately about the particular examples of using the mixins in life. And now let’s consider a purely abstract example illustrating only the technique of embedding the mixin class to the hierarchy of inheritance of designed classes.
In the previous article we had an example:
Let’s redraw the diagram in this way:
We can see that functionality of Stack'а has completely moved to StackPrim.
And two more classes have appeared – TintStackFromPersisten, inherited from TPersistent and StackPrim, and class TIntStackFromComponent, inherited from TComponent and StackPrim.
Multiple inheritance – you’d ask. Logically – yes. At the level of the diagrams arrows.
Let’s see how it all looks on Delphi:
StackPrim.imp.pas:
{$IfNDef StackPrim_imp}
{$Define StackPrim_imp}
ItemsHolder = array of _ItemType_;
_StackPrim_ = {mixin} class(_StackPrim_Parent_)
private
// private fields
f_Items : ItemsHolder;
public
// public methods
procedure Push(const anItem: _ItemType_);
function Pop: _ItemType_;
end;//_StackPrim_
{$Else StackPrim_imp}
// start class _StackPrim_
procedure _StackPrim_.Push(const anItem: _ItemType_);
var
l_L : Integer;
begin
l_L := Length(f_Items);
SetLength(f_Items, l_L + 1);
f_Items[l_L] := anItem;
end;//_StackPrim_.Push
function _StackPrim_.Pop: _ItemType_;
var
l_L : Integer;
begin
l_L := Length(f_Items) - 1;
Result := f_Items[l_L];
SetLength(f_Items, l_L);
end;//_StackPrim_.Pop
{$EndIf StackPrim_imp}
---------------------------------------------
Stack.imp.pas:
{$IfNDef Stack_imp}
{$Define Stack_imp}
_StackPrim_Parent_ = TObject;
{$Include StackPrim.imp.pas}
_Stack_ = {mixin} class(_StackPrim_)
end;//_Stack_
{$Else Stack_imp}
{$Include StackPrim.imp.pas}
{$EndIf Stack_imp}
---------------------------------------------
StringStack.pas:
unit StringStack;
interface
type
_ItemType_ = AnsiString;
{$Include Stack.imp.pas}
TStringStack = class(_Stack_)
end;//TStringStack
implementation
{$Include Stack.imp.pas}
end.
---------------------------------------------
IntStack.pas:
unit IntStack;
interface
type
_ItemType_ = Integer;
{$Include Stack.imp.pas}
TIntStack = class(_Stack_)
end;//TIntStack
implementation
{$Include Stack.imp.pas}
end
---------------------------------------------
!!! And there are two NEW classes:
---------------------------------------------
IntStackFromPersistent.pas:
unit IntStackFromPersistent;
interface
uses
Classes
;
type
_ItemType_ = Integer;
_StackPrim_Parent_ = TPersistent;
{$Include StackPrim.imp.pas}
TIntStackFromPersistent = class(_StackPrim_)
end;//TIntStackFromPersistent
implementation
{$Include StackPrim.imp.pas}
end.
---------------------------------------------
IntStackFromComponent.pas:
unit IntStackFromComponent;
interface
uses
Classes
;
type
_ItemType_ = Integer;
_StackPrim_Parent_ = TComponent;
{$Include StackPrim.imp.pas}
TIntStackFromComponent = class(_StackPrim_)
end;//TIntStackFromComponent
implementation
{$Include StackPrim.imp.pas}
end.
---------------------------------------------
As for me, it is fun :-) There is only ONE mixin, but it is added to FOUR different classes and even different places in the hierarchy of the inheritance.
Try it. May be you will like it.
In the next series I will try to tell WHY do I use it.
Containers 9. Special containers. Part 2
Original in Russian: http://18delphi.blogspot.ru/2013/07/2_18.html
About containers. Table of contents
The previous series was here - http://18delphi.blogspot.com/2015/02/containers-8-deriving-of-specific.html
And here - http://18delphi.blogspot.com/2015/02/containers-7-abstract-containers-part-2.html
Now let’s look how special containers have changed.
The model:
The code:
StandardAtomicList.imp.pas:
IUnknownRefListTest.pas:
About containers. Table of contents
The previous series was here - http://18delphi.blogspot.com/2015/02/containers-8-deriving-of-specific.html
And here - http://18delphi.blogspot.com/2015/02/containers-7-abstract-containers-part-2.html
Now let’s look how special containers have changed.
The model:
The code:
StandardAtomicList.imp.pas:
StandardAtomicList.imp.pas:
{$IfNDef StandardAtomicList_imp}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBox"
// The unit: "StandardAtomicList.imp.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: Impurity::Class Shared Delphi Sand Box::SandBox::FinalContainers::StandardAtomicList
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$Define StandardAtomicList_imp}
_AtomicList_Parent_ = TRefcounted;
{$Include ..\SandBox\AtomicList.imp.pas}
_StandardAtomicList_ = {mixin} class(_AtomicList_)
end;//_StandardAtomicList_
{$Else StandardAtomicList_imp}
{$Include ..\SandBox\AtomicList.imp.pas}
{$EndIf StandardAtomicList_imp}
IntegerList.pas:
unit IntegerList;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBox"
// The unit: "IntegerList.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TIntegerList
//
// The list of Integer's
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$Include ..\SandBox\sbDefine.inc}
interface
uses
Refcounted,
Classes,
l3PtrLoc
;
type
_ItemType_ = Integer;
{$Include ..\SandBox\StandardAtomicList.imp.pas}
TIntegerList = class(_StandardAtomicList_)
{* The list of Integer's }
end;//TIntegerList
implementation
uses
RTLConsts,
l3MemorySizeUtils
;
{$Include ..\SandBox\StandardAtomicList.imp.pas}
end.
Int64List.pas:
unit Int64List;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBox"
// The unit: "Int64List.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TInt64List
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$Include ..\SandBox\sbDefine.inc}
interface
uses
Refcounted,
Classes,
l3PtrLoc
;
type
_ItemType_ = Int64;
{$Include ..\SandBox\StandardAtomicList.imp.pas}
TInt64List = class(_StandardAtomicList_)
end;//TInt64List
implementation
uses
RTLConsts,
l3MemorySizeUtils
;
{$Include ..\SandBox\StandardAtomicList.imp.pas}
end.
ByteList.pas:
unit ByteList;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBox"
// The unit: "ByteList.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TByteList
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$Include ..\SandBox\sbDefine.inc}
interface
uses
Refcounted,
Classes,
l3PtrLoc
;
type
_ItemType_ = Byte;
{$Include ..\SandBox\StandardAtomicList.imp.pas}
TByteList = class(_StandardAtomicList_)
end;//TByteList
implementation
uses
RTLConsts,
l3MemorySizeUtils
;
{$Include ..\SandBox\StandardAtomicList.imp.pas}
end.
IUnknownRefList.pas:
unit IUnknownRefList;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBox"
// The unit: "IUnknownRefList.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TIUnknownRefList
//
// The list of the REFERENCES to IUnknown
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$Include ..\SandBox\sbDefine.inc}
interface
uses
Refcounted,
Classes,
l3PtrLoc
;
type
_ItemType_ = IUnknown;
_InterfaceRefList_Parent_ = TRefcounted;
{$Include ..\SandBox\InterfaceRefList.imp.pas}
TIUnknownRefList = class(_InterfaceRefList_)
{* The list of the REFERENCES to IUnknown }
end;//TIUnknownRefList
implementation
uses
RTLConsts,
l3MemorySizeUtils
;
{$Include ..\SandBox\InterfaceRefList.imp.pas}
end.
IUnknownPtrList.pas:
unit IUnknownPtrList;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBox"
// The unit: "IUnknownPtrList.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TIUnknownPtrList
//
// The list of the POINTERS to IUnknown
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$Include ..\SandBox\sbDefine.inc}
interface
uses
Refcounted,
Classes,
l3PtrLoc
;
type
_ItemType_ = IUnknown;
_InterfacePtrList_Parent_ = TRefcounted;
{$Include ..\SandBox\InterfacePtrList.imp.pas}
TIUnknownPtrList = class(_InterfacePtrList_)
{* The list of the POINTERS to IUnknown }
end;//TIUnknownPtrList
implementation
uses
RTLConsts,
l3MemorySizeUtils
;
{$Include ..\SandBox\InterfacePtrList.imp.pas}
end.
And the tests.
The model:
pic2
pic3
The code:
ListTest.imp.pas:
{$IfNDef ListTest_imp}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBoxTest"
// The unit: "ListTest.imp.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: TestCaseMixIn::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::ListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$Define ListTest_imp}
{$If defined(nsTest)}
_ListTest_ = class(TTestCase)
protected
// protected methods
function CreateList: _ListType_;
{* Creates the list for testing }
end;//_ListTest_
{$IfEnd} //nsTest
{$Else ListTest_imp}
{$If defined(nsTest)}
// start class _ListTest_
function _ListTest_.CreateList: _ListType_;
//#UC START# *51E80E0D030D_51E80DD30125_var*
//#UC END# *51E80E0D030D_51E80DD30125_var*
begin
//#UC START# *51E80E0D030D_51E80DD30125_impl*
Result := _ListType_.Create;
//#UC END# *51E80E0D030D_51E80DD30125_impl*
end;//_ListTest_.CreateList
{$IfEnd} //nsTest
{$EndIf ListTest_imp}
AtomicListTest.imp.pas:
{$IfNDef AtomicListTest_imp}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBoxTest"
// The unit: "AtomicListTest.imp.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: TestCaseMixIn::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::AtomicListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$Define AtomicListTest_imp}
{$If defined(nsTest)}
{$Include ..\SandBox\ListTest.imp.pas}
_AtomicListTest_ = class(_ListTest_)
private
// private methods
function RandomItem: _ItemType_;
published
// published methods
procedure DoIt;
procedure TestTwoLists;
procedure TestInsert;
procedure TestInsertAt0;
procedure DeleteTest;
{* The test of item deleting }
procedure AddTest;
{* The test of item adding }
procedure RemoveTest;
{* The test of item deleting by the value }
end;//_AtomicListTest_
{$IfEnd} //nsTest
{$Else AtomicListTest_imp}
{$If defined(nsTest)}
{$Include ..\SandBox\ListTest.imp.pas}
// start class _AtomicListTest_
function _AtomicListTest_.RandomItem: _ItemType_;
//#UC START# *51E6ADE0016E_51E03FC80111_var*
var
l_V : Cardinal;
//#UC END# *51E6ADE0016E_51E03FC80111_var*
begin
//#UC START# *51E6ADE0016E_51E03FC80111_impl*
l_V := Random(1000);
if (l_V > High(_ItemType_)) then
Result := High(_ItemType_)
else
Result := l_V;
//#UC END# *51E6ADE0016E_51E03FC80111_impl*
end;//_AtomicListTest_.RandomItem
procedure _AtomicListTest_.DoIt;
//#UC START# *51DEB319037C_51E03FC80111_var*
const
cCount = 1000;
var
l_List : _ListType_;
l_Count : IndexType;
l_Index : IndexType;
//#UC END# *51DEB319037C_51E03FC80111_var*
begin
//#UC START# *51DEB319037C_51E03FC80111_impl*
l_List := CreateList;
try
l_List.Count := cCount;
Check(l_List.Count = cCount);
Check(l_List.Capacity >= cCount);
for l_Index := 0 to l_List.Count - 1 do
Check(l_List[l_Index] = 0);
l_Count := Random(cCount);
l_List.Count := l_Count;
Check(l_List.Count = l_Count, Format('We’ve allocated %d items. Count = %d', [l_Count, l_List.Count]));
Check(l_List.Capacity >= l_Count, Format('We’ve allocated %d items. Capacity = %d', [l_Count, l_List.Capacity]));
for l_Index := 0 to l_List.Count - 1 do
Check(l_List[l_Index] = 0);
finally
FreeAndNil(l_List);
end;//try..finally
//#UC END# *51DEB319037C_51E03FC80111_impl*
end;//_AtomicListTest_.DoIt
procedure _AtomicListTest_.TestTwoLists;
//#UC START# *51DED6FC03C1_51E03FC80111_var*
const
cCount = 1000;
var
l_A : _ListType_;
l_B : _ListType_;
l_Index : IndexType;
l_Value : _ItemType_;
//#UC END# *51DED6FC03C1_51E03FC80111_var*
begin
//#UC START# *51DED6FC03C1_51E03FC80111_impl*
l_A := CreateList;
try
l_B := CreateList;
try
l_A.Count := cCount;
for l_Index := 0 to l_A.Count - 1 do
begin
l_Value := RandomItem;
l_A[l_Index] := l_Value;
Check(l_A[l_Index] = l_Value);
end;//for l_Index
l_B.Count := l_A.Count;
for l_Index := 0 to l_A.Count - 1 do
begin
l_B[l_Index] := l_A[l_Index];
end;//for l_Index
for l_Index := 0 to l_A.Count - 1 do
begin
Check(l_B[l_Index] = l_A[l_Index]);
end;//for l_Index
finally
FreeAndNil(l_B);
end;//try..finally
finally
FreeAndNil(l_A);
end;//try..finally
//#UC END# *51DED6FC03C1_51E03FC80111_impl*
end;//_AtomicListTest_.TestTwoLists
procedure _AtomicListTest_.TestInsert;
//#UC START# *51E6AC74038B_51E03FC80111_var*
const
cCount = 1000;
var
l_List : _ListType_;
l_Value : _ItemType_;
l_Index : IndexType;
//#UC END# *51E6AC74038B_51E03FC80111_var*
begin
//#UC START# *51E6AC74038B_51E03FC80111_impl*
l_List := CreateList;
try
for l_Index := 0 to cCount do
begin
l_Value := RandomItem;
l_List.Insert(l_Index, l_Value);
Check(l_List.Count = l_Index + 1);
Check(l_List[l_Index] = l_Value);
end;//for l_Index
finally
FreeAndNil(l_List);
end;//try..finally
//#UC END# *51E6AC74038B_51E03FC80111_impl*
end;//_AtomicListTest_.TestInsert
procedure _AtomicListTest_.TestInsertAt0;
//#UC START# *51E6B4260008_51E03FC80111_var*
const
cCount = 1000;
var
l_List : _ListType_;
l_Value : _ItemType_;
l_Index : IndexType;
//#UC END# *51E6B4260008_51E03FC80111_var*
begin
//#UC START# *51E6B4260008_51E03FC80111_impl*
l_List := CreateList;
try
for l_Index := 0 to cCount do
begin
l_Value := RandomItem;
l_List.Insert(0, l_Value);
Check(l_List.Count = l_Index + 1);
Check(l_List[0] = l_Value);
end;//for l_Index
finally
FreeAndNil(l_List);
end;//try..finally
//#UC END# *51E6B4260008_51E03FC80111_impl*
end;//_AtomicListTest_.TestInsertAt0
procedure _AtomicListTest_.DeleteTest;
//#UC START# *51E7F6EF0285_51E03FC80111_var*
const
cCount = 1000;
var
l_List : _ListType_;
l_Value : _ItemType_;
l_Index : IndexType;
l_Prev : _ItemType_;
//#UC END# *51E7F6EF0285_51E03FC80111_var*
begin
//#UC START# *51E7F6EF0285_51E03FC80111_impl*
l_List := CreateList;
try
for l_Index := 0 to cCount do
begin
l_Value := RandomItem;
l_List.Insert(l_Index, l_Value);
Check(l_List.Count = l_Index + 1);
Check(l_List[l_Index] = l_Value);
end;//for l_Index
while not l_List.Empty do
begin
l_Index := Random(l_List.Count - 1);
if (l_Index < l_List.Count - 1) then
begin
l_Prev := l_List[l_Index + 1];
l_List.Delete(l_Index);
if l_List.Empty then
break;
Check(l_List[l_Index] = l_Prev);
end//l_Index < l_List.Count - 1
else
begin
if (l_Index = 0) then
l_List.Delete(l_Index)
else
begin
l_Prev := l_List[l_Index - 1];
l_List.Delete(l_Index);
if l_List.Empty then
break;
Check(l_List[l_Index - 1] = l_Prev);
end;//l_Index = 0
end;//l_Index < l_List.Count - 1
end;//while l_List.Count
finally
FreeAndNil(l_List);
end;//try..finally
//#UC END# *51E7F6EF0285_51E03FC80111_impl*
end;//_AtomicListTest_.DeleteTest
procedure _AtomicListTest_.AddTest;
//#UC START# *51E80DC50154_51E03FC80111_var*
const
cCount = 1000;
var
l_List : _ListType_;
l_Value : _ItemType_;
l_Index : IndexType;
//#UC END# *51E80DC50154_51E03FC80111_var*
begin
//#UC START# *51E80DC50154_51E03FC80111_impl*
l_List := CreateList;
try
for l_Index := 0 to cCount do
begin
l_Value := RandomItem;
l_List.Add(l_Value);
Check(l_List.Last = l_Value);
end;//for l_Index
finally
FreeAndNil(l_List);
end;//try..finally
//#UC END# *51E80DC50154_51E03FC80111_impl*
end;//_AtomicListTest_.AddTest
procedure _AtomicListTest_.RemoveTest;
//#UC START# *51E8127802AF_51E03FC80111_var*
const
cCount = 1000;
var
l_List : _ListType_;
l_Value : _ItemType_;
l_Index : IndexType;
//#UC END# *51E8127802AF_51E03FC80111_var*
begin
//#UC START# *51E8127802AF_51E03FC80111_impl*
l_List := CreateList;
try
for l_Index := 0 to cCount do
begin
l_Value := RandomItem;
l_List.Add(l_Value);
Check(l_List.Last = l_Value);
end;//for l_Index
while not l_List.Empty do
begin
l_Value := RandomItem;
l_List.Remove(l_Value);
end;//while not
finally
FreeAndNil(l_List);
end;//try..finally
//#UC END# *51E8127802AF_51E03FC80111_impl*
end;//_AtomicListTest_.RemoveTest
{$IfEnd} //nsTest
{$EndIf AtomicListTest_imp}
IUnknownRefListTest.pas:
unit IUnknownRefListTest;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBoxTest"
// The unit: "IUnknownRefListTest.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: TestCase::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::IUnknownRefListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$Include ..\SandBox\sbtDefine.inc}
interface
{$If defined(nsTest)}
uses
TestFrameWork,
IUnknownRefList
;
{$IfEnd} //nsTest
{$If defined(nsTest)}
type
_ListType_ = TIUnknownRefList;
{$Include ..\SandBox\ListTest.imp.pas}
TIUnknownRefListTest = class(_ListTest_)
published
// published methods
procedure DoIt;
end;//TIUnknownRefListTest
{$IfEnd} //nsTest
implementation
{$If defined(nsTest)}
uses
SysUtils
;
{$IfEnd} //nsTest
{$If defined(nsTest)}
{$Include ..\SandBox\ListTest.imp.pas}
// start class TIUnknownRefListTest
procedure TIUnknownRefListTest.DoIt;
//#UC START# *51E80B2F02CF_51E80B08039E_var*
var
l_List : _ListType_;
//#UC END# *51E80B2F02CF_51E80B08039E_var*
begin
//#UC START# *51E80B2F02CF_51E80B08039E_impl*
l_List := CreateList;
try
// - For now we do nothing
finally
FreeAndNil(l_List);
end;//try..finally
//#UC END# *51E80B2F02CF_51E80B08039E_impl*
end;//TIUnknownRefListTest.DoIt
{$IfEnd} //nsTest
initialization
TestFramework.RegisterTest(TIUnknownRefListTest.Suite);
end.
Containers 8. Deriving of specific atomic containers from abstract ones
Original in Russian: http://18delphi.blogspot.ru/2013/07/blog-post_8789.html
About containers. Table of contents
The previous series was here - http://18delphi.blogspot.com/2015/02/containers-7-abstract-containers-part-2.html
Now let us derive from abstract containers of the previous series – the specific ones. As yet – atomic ones.
So. As usual.
The model:
The code:
IntegerList.pas:
The tests (picked out of the thin air, nevertheless they have the right to live).
The model of the tests:
The code of the tests:
IntegerListTest.pas:
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
About containers. Table of contents
The previous series was here - http://18delphi.blogspot.com/2015/02/containers-7-abstract-containers-part-2.html
Now let us derive from abstract containers of the previous series – the specific ones. As yet – atomic ones.
So. As usual.
The model:
The code:
IntegerList.pas:
unit IntegerList;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBox"
// The unit: "IntegerList.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TIntegerList
//
// The list of Integer's
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ! Fully generated from the model. It is not allowed to edit manually. !
interface
uses
Refcounted,
Classes,
l3PtrLoc
;
type
_ItemType_ = Integer;
_AtomicList_Parent_ = TRefcounted;
{$Include AtomicList.imp.pas}
TIntegerList = class(_AtomicList_)
{* The list of Integer's }
end;//TIntegerList
implementation
uses
RTLConsts,
l3MemorySizeUtils
;
type _Instance_R_ = TIntegerList;
type _AtomicList_R_ = TIntegerList;
{$Include AtomicList.imp.pas}
end.
ByteList.pas:
unit ByteList;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBox"
// The unit: "ByteList.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TByteList
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ! Fully generated from the model. It is not allowed to edit manually. !
interface
uses
Refcounted,
Classes,
l3PtrLoc
;
type
_ItemType_ = Byte;
_AtomicList_Parent_ = TRefcounted;
{$Include AtomicList.imp.pas}
TByteList = class(_AtomicList_)
end;//TByteList
implementation
uses
RTLConsts,
l3MemorySizeUtils
;
type _Instance_R_ = TByteList;
type _AtomicList_R_ = TByteList;
{$Include AtomicList.imp.pas}
end.
Int64List.pas:
unit Int64List;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBox"
// The unit: "Int64List.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Sand Box::SandBox::FinalContainers::TInt64List
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ! Fully generated from the model. It is not allowed to edit manually. !
interface
uses
Refcounted,
Classes,
l3PtrLoc
;
type
_ItemType_ = Int64;
_AtomicList_Parent_ = TRefcounted;
{$Include AtomicList.imp.pas}
TInt64List = class(_AtomicList_)
end;//TInt64List
implementation
uses
RTLConsts,
l3MemorySizeUtils
;
type _Instance_R_ = TInt64List;
type _AtomicList_R_ = TInt64List;
{$Include AtomicList.imp.pas}
end.
The tests (picked out of the thin air, nevertheless they have the right to live).
The model of the tests:
The code of the tests:
IntegerListTest.pas:
unit IntegerListTest;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBoxTest"
// The unit: "IntegerListTest.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: TestCase::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::IntegerListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ! Fully generated from the model. It is not allowed to edit manually. !
interface
uses
TestFrameWork
;
type
TIntegerListTest = class(TTestCase)
published
// published methods
procedure DoIt;
procedure TestTwoLists;
end;//TIntegerListTest
implementation
uses
IntegerList,
SysUtils
;
// start class TIntegerListTest
procedure TIntegerListTest.DoIt;
//#UC START# *51DEB319037C_51DEB2FA00B0_var*
const
cCount = 1000;
var
l_List : TIntegerList;
l_Count : IndexType;
l_Index : IndexType;
//#UC END# *51DEB319037C_51DEB2FA00B0_var*
begin
//#UC START# *51DEB319037C_51DEB2FA00B0_impl*
l_List := TIntegerList.Create;
try
l_List.Count := cCount;
Check(l_List.Count = cCount);
Check(l_List.Capacity >= cCount);
for l_Index := 0 to l_List.Count - 1 do
Check(l_List[l_Index] = 0);
l_Count := Random(cCount);
l_List.Count := l_Count;
Check(l_List.Count = l_Count, Format('We’ve allocated %d items. Count = %d', [l_Count, l_List.Count]));
Check(l_List.Capacity >= l_Count, Format('We’ve allocated %d items. Capacity = %d', [l_Count, l_List.Capacity]));
for l_Index := 0 to l_List.Count - 1 do
Check(l_List[l_Index] = 0);
finally
FreeAndNil(l_List);
end;//try..finally
//#UC END# *51DEB319037C_51DEB2FA00B0_impl*
end;//TIntegerListTest.DoIt
procedure TIntegerListTest.TestTwoLists;
//#UC START# *51DED6FC03C1_51DEB2FA00B0_var*
const
cCount = 1000;
var
l_A : TIntegerList;
l_B : TIntegerList;
l_Index : IndexType;
l_Value : Integer;
//#UC END# *51DED6FC03C1_51DEB2FA00B0_var*
begin
//#UC START# *51DED6FC03C1_51DEB2FA00B0_impl*
l_A := TIntegerList.Create;
try
l_B := TIntegerList.Create;
try
l_A.Count := cCount;
for l_Index := 0 to l_A.Count - 1 do
begin
l_Value := Random(1000);
l_A[l_Index] := l_Value;
Check(l_A[l_Index] = l_Value);
end;//for l_Index
l_B.Count := l_A.Count;
for l_Index := 0 to l_A.Count - 1 do
begin
l_B[l_Index] := l_A[l_Index];
end;//for l_Index
for l_Index := 0 to l_A.Count - 1 do
begin
Check(l_B[l_Index] = l_A[l_Index]);
end;//for l_Index
finally
FreeAndNil(l_B);
end;//try..finally
finally
FreeAndNil(l_A);
end;//try..finally
//#UC END# *51DED6FC03C1_51DEB2FA00B0_impl*
end;//TIntegerListTest.TestTwoLists
initialization
TestFramework.RegisterTest(TIntegerListTest.Suite);
end.
ByteListTest.pas:
unit ByteListTest;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBoxTest"
// The unit: "ByteListTest.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: TestCase::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::ByteListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ! Fully generated from the model. It is not allowed to edit manually. !
interface
uses
TestFrameWork
;
type
TByteListTest = class(TTestCase)
published
// published methods
procedure DoIt;
end;//TByteListTest
implementation
uses
ByteList,
SysUtils
;
// start class TByteListTest
procedure TByteListTest.DoIt;
//#UC START# *51DEE6960378_51DEE67C003A_var*
const
cCount = 1000;
var
l_List : TByteList;
l_Count : IndexType;
l_Index : IndexType;
//#UC END# *51DEE6960378_51DEE67C003A_var*
begin
//#UC START# *51DEE6960378_51DEE67C003A_impl*
l_List := TByteList.Create;
try
l_List.Count := cCount;
Check(l_List.Count = cCount);
Check(l_List.Capacity >= cCount);
for l_Index := 0 to l_List.Count - 1 do
Check(l_List[l_Index] = 0);
l_Count := Random(cCount);
l_List.Count := l_Count;
Check(l_List.Count = l_Count, Format('We’ve allocated %d items. Count = %d', [l_Count, l_List.Count]));
Check(l_List.Capacity >= l_Count, Format('We’ve allocated %d items. Capacity = %d', [l_Count, l_List.Capacity]));
for l_Index := 0 to l_List.Count - 1 do
Check(l_List[l_Index] = 0);
finally
FreeAndNil(l_List);
end;//try..finally
//#UC END# *51DEE6960378_51DEE67C003A_impl*
end;//TByteListTest.DoIt
initialization
TestFramework.RegisterTest(TByteListTest.Suite);
end.
Int64ListTest.pas:
unit Int64ListTest;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBoxTest"
// The unit: "Int64ListTest.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: TestCase::Class Shared Delphi Sand Box::SandBoxTest::FinalContainersTests::Int64ListTest
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ! Fully generated from the model. It is not allowed to edit manually. !
interface
uses
TestFrameWork
;
type
TInt64ListTest = class(TTestCase)
published
// published methods
procedure DoIt;
end;//TInt64ListTest
implementation
uses
Int64List,
SysUtils
;
// start class TInt64ListTest
procedure TInt64ListTest.DoIt;
//#UC START# *51DEE90202A8_51DEE8E9025A_var*
const
cCount = 1000;
var
l_List : TInt64List;
l_Count : IndexType;
l_Index : IndexType;
//#UC END# *51DEE90202A8_51DEE8E9025A_var*
begin
//#UC START# *51DEE90202A8_51DEE8E9025A_impl*
l_List := TInt64List.Create;
try
l_List.Count := cCount;
Check(l_List.Count = cCount);
Check(l_List.Capacity >= cCount);
for l_Index := 0 to l_List.Count - 1 do
Check(l_List[l_Index] = 0);
l_Count := Random(cCount);
l_List.Count := l_Count;
Check(l_List.Count = l_Count, Format('We’ve allocated %d items. Count = %d', [l_Count, l_List.Count]));
Check(l_List.Capacity >= l_Count, Format('We’ve allocated %d items. Capacity = %d', [l_Count, l_List.Capacity]));
for l_Index := 0 to l_List.Count - 1 do
Check(l_List[l_Index] = 0);
finally
FreeAndNil(l_List);
end;//try..finally
//#UC END# *51DEE90202A8_51DEE8E9025A_impl*
end;//TInt64ListTest.DoIt
initialization
TestFramework.RegisterTest(TInt64ListTest.Suite);
end.
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
Containers 7. Abstract containers. Part 2
Original in Russian: http://18delphi.blogspot.ru/2013/07/2.html
About containers. Table of contents
The previous series was here - http://18delphi.blogspot.com/2015/02/containers-6-abstract-containers.html
Let’s extend the functionality of the container by adding the “standard” container operations.
As usual we’ll start with the model:
And the code:
List.imp.pas:
InterfacePtrList.imp.pas:
InterfaceRefList.imp.pas:
About containers. Table of contents
The previous series was here - http://18delphi.blogspot.com/2015/02/containers-6-abstract-containers.html
Let’s extend the functionality of the container by adding the “standard” container operations.
As usual we’ll start with the model:
And 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;
{* That is actually the place to store data }
f_Count : IndexType;
{* 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 }
procedure DirectInsert(anIndex: IndexType;
const anItem: _ItemType_);
{* Direct adding of the item. Without checking the validity of the index }
procedure MoveItems(aDst: IndexType;
aSrc: IndexType;
aSize: Cardinal);
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_);
function pm_GetEmpty: Boolean;
function pm_GetFirst: _ItemType_;
function pm_GetLast: _ItemType_;
protected
// overridden protected methods
procedure Cleanup; override;
{* The function of object fields cleaning. }
public
// public methods
procedure Delete(anIndex: IndexType); // can raise EListError
{* delete the item with index anIndex }
procedure Insert(anIndex: IndexType;
const anItem: _ItemType_); // can raise EListError
{* Adding of the item }
procedure Add(const anItem: _ItemType_);
{* Adds an item of the list }
function IndexOf(const anItem: _ItemType_): IndexType;
{* Returns the index of the list item or -1, if there is no item in the list }
procedure Remove(const anIndex: _ItemType_);
{* Deletes an item from the list }
procedure Clear;
{* Clears the list }
public
// public properties
property Count: IndexType
read f_Count
write pm_SetCount;
{* The number of items in the list }
property Capacity: IndexType
read pm_GetCapacity
write pm_SetCapacity;
{* The capacity of the list }
property Items[anIndex: IndexType]: _ItemType_
read pm_GetItems
write pm_SetItems;
default;
{* The items of the list. }
property Empty: Boolean
read pm_GetEmpty;
{* The list is empty }
property First: _ItemType_
read pm_GetFirst;
{* The first item of the list }
property Last: _ItemType_
read pm_GetLast;
{* The last item 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_.DirectInsert(anIndex: IndexType;
const anItem: _ItemType_);
//#UC START# *51E6A2AA02E4_51DEB07E03E4_var*
var
l_Cap : Integer;
l_Count : Integer;
//#UC END# *51E6A2AA02E4_51DEB07E03E4_var*
begin
//#UC START# *51E6A2AA02E4_51DEB07E03E4_impl*
l_Count := f_Count;
l_Cap := Self.Capacity;
if (l_Count >= l_Cap) then
ReAllocList(ExpandSize(l_Cap + 1));
{ Make room for the inserted item. }
Dec(l_Count, anIndex);
if (l_Count > 0) then
begin
MoveItems(anIndex + 1, anIndex + 0, l_Count);
{$If not defined(l3Items_IsAtomic)}
FillChar(PMem(ItemSlot(anIndex))^, cItemSize, 0);
// - To ensure that there is no odd reference to the lines and/or the interfaces
{$IfEnd}
end;//l_Count > 0
FillItem(ItemSlot(anIndex)^, anItem);
Inc(f_Count);
{$IfDef l3Items_IsAtomic}
Assert(ItemSlot(anIndex)^ = anItem);
{$Else l3Items_IsAtomic}
{$If (SizeOf(_ItemType_) <= 4) AND not Defined(l3Items_IsProcedured)}
Assert(ItemSlot(anIndex)^ = anItem);
{$IfEnd}
{$EndIf l3Items_IsAtomic}
//#UC END# *51E6A2AA02E4_51DEB07E03E4_impl*
end;//_List_.DirectInsert
procedure _List_.MoveItems(aDst: IndexType;
aSrc: IndexType;
aSize: Cardinal);
//#UC START# *51E6A8190252_51DEB07E03E4_var*
type
PInteger = ^Integer;
var
l_Sz : Integer;
l_S : Integer;
l_D : Integer;
l_B : PMem;
//#UC END# *51E6A8190252_51DEB07E03E4_var*
begin
//#UC START# *51E6A8190252_51DEB07E03E4_impl*
if (aSize > 0) then
begin
l_B := f_Data.AsPointer;
l_S := aSrc * cItemSize;
l_D := aDst * cItemSize;
l_Sz := aSize * cItemSize;
if (l_Sz = SizeOf(Integer)) then
begin
PInteger(l_B + l_D)^ := PInteger(l_B + l_S)^;
Exit;
end//l_Sz = SizeOf(Integer)
else
Move((l_B + l_S)^, (l_B + l_D)^, l_Sz);
end;//aSize > 0
//#UC END# *51E6A8190252_51DEB07E03E4_impl*
end;//_List_.MoveItems
procedure _List_.Delete(anIndex: IndexType); // can raise EListError
//#UC START# *51E6A2660270_51DEB07E03E4_var*
var
l_P : PItemType;
//#UC END# *51E6A2660270_51DEB07E03E4_var*
begin
//#UC START# *51E6A2660270_51DEB07E03E4_impl*
CheckIndex(anIndex);
l_P := ItemSlot(anIndex);
Dec(f_Count);
FreeItem(l_P^);
if (anIndex <> f_Count) then
MoveItems(anIndex, Succ(anIndex), f_Count-anIndex);
//#UC END# *51E6A2660270_51DEB07E03E4_impl*
end;//_List_.Delete
procedure _List_.Insert(anIndex: IndexType;
const anItem: _ItemType_); // can raise EListError
//#UC START# *51E6A3140016_51DEB07E03E4_var*
procedure _Error;
begin
raise EListError.CreateFmt(SListIndexError, [anIndex]);
end;
//#UC END# *51E6A3140016_51DEB07E03E4_var*
begin
//#UC START# *51E6A3140016_51DEB07E03E4_impl*
if (anIndex < 0) or (anIndex > f_Count) then
_Error;
DirectInsert(anIndex, anItem)
//#UC END# *51E6A3140016_51DEB07E03E4_impl*
end;//_List_.Insert
procedure _List_.Add(const anItem: _ItemType_);
//#UC START# *51E80192036C_51DEB07E03E4_var*
//#UC END# *51E80192036C_51DEB07E03E4_var*
begin
//#UC START# *51E80192036C_51DEB07E03E4_impl*
DirectInsert(f_Count, anItem);
//#UC END# *51E80192036C_51DEB07E03E4_impl*
end;//_List_.Add
function _List_.IndexOf(const anItem: _ItemType_): IndexType;
//#UC START# *51E801D503C5_51DEB07E03E4_var*
var
l_Index : IndexType;
//#UC END# *51E801D503C5_51DEB07E03E4_var*
begin
//#UC START# *51E801D503C5_51DEB07E03E4_impl*
Result := -1;
// - let’s be pessimistic
for l_Index := 0 to f_Count - 1 do
begin
if IsSame(ItemSlot(l_Index)^, anItem) then
begin
Result := l_Index;
break;
end;//IsSame(ItemSlot(l_Index)^, anItem)
end;//for l_Index
//#UC END# *51E801D503C5_51DEB07E03E4_impl*
end;//_List_.IndexOf
procedure _List_.Remove(const anIndex: _ItemType_);
//#UC START# *51E802290167_51DEB07E03E4_var*
var
l_Index : IndexType;
//#UC END# *51E802290167_51DEB07E03E4_var*
begin
//#UC START# *51E802290167_51DEB07E03E4_impl*
l_Index := IndexOf(anIndex);
if (l_Index >= 0) then
Delete(l_Index);
//#UC END# *51E802290167_51DEB07E03E4_impl*
end;//_List_.Remove
procedure _List_.Clear;
//#UC START# *51E8026302B4_51DEB07E03E4_var*
//#UC END# *51E8026302B4_51DEB07E03E4_var*
begin
//#UC START# *51E8026302B4_51DEB07E03E4_impl*
Count := 0;
//#UC END# *51E8026302B4_51DEB07E03E4_impl*
end;//_List_.Clear
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
function _List_.pm_GetEmpty: Boolean;
//#UC START# *51E7FDAC023D_51DEB07E03E4get_var*
//#UC END# *51E7FDAC023D_51DEB07E03E4get_var*
begin
//#UC START# *51E7FDAC023D_51DEB07E03E4get_impl*
Result := (Count = 0);
//#UC END# *51E7FDAC023D_51DEB07E03E4get_impl*
end;//_List_.pm_GetEmpty
function _List_.pm_GetFirst: _ItemType_;
//#UC START# *51E8070603AC_51DEB07E03E4get_var*
//#UC END# *51E8070603AC_51DEB07E03E4get_var*
begin
//#UC START# *51E8070603AC_51DEB07E03E4get_impl*
Result := Items[0];
//#UC END# *51E8070603AC_51DEB07E03E4get_impl*
end;//_List_.pm_GetFirst
function _List_.pm_GetLast: _ItemType_;
//#UC START# *51E8074101B5_51DEB07E03E4get_var*
//#UC END# *51E8074101B5_51DEB07E03E4get_var*
begin
//#UC START# *51E8074101B5_51DEB07E03E4get_impl*
Result := Items[f_Count - 1];
//#UC END# *51E8074101B5_51DEB07E03E4get_impl*
end;//_List_.pm_GetLast
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}
InterfacePtrList.imp.pas:
{$IfNDef InterfacePtrList_imp}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBox"
// The unit: "InterfacePtrList.imp.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: Impurity::Class Shared Delphi Sand Box::SandBox::STLLike::InterfacePtrList
//
// The list of the pointers to the interfaces. Does not have its items
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$Define InterfacePtrList_imp}
_List_Parent_ = _InterfacePtrList_Parent_;
{$Include ..\SandBox\List.imp.pas}
_InterfacePtrList_ = {mixin} class(_List_)
{* The list of the pointers to the interfaces. Does not have its items }
end;//_InterfacePtrList_
{$Else InterfacePtrList_imp}
// start class _InterfacePtrList_
procedure FillItem(var thePlace: _ItemType_;
const aFrom: _ItemType_); forward;
function IsSame(const A: _ItemType_;
const B: _ItemType_): Boolean; forward;
procedure FreeItem(var thePlace: _ItemType_);
//#UC START# *51DEC20B01D7_51E8098001DC_var*
//#UC END# *51DEC20B01D7_51E8098001DC_var*
begin
//#UC START# *51DEC20B01D7_51E8098001DC_impl*
!!! Needs to be implemented !!!
//#UC END# *51DEC20B01D7_51E8098001DC_impl*
end;//FreeItem
procedure FillItem(var thePlace: _ItemType_;
const aFrom: _ItemType_);
//#UC START# *51DECB440087_51E8098001DC_var*
//#UC END# *51DECB440087_51E8098001DC_var*
begin
//#UC START# *51DECB440087_51E8098001DC_impl*
!!! Needs to be implemented !!!
//#UC END# *51DECB440087_51E8098001DC_impl*
end;//FillItem
function IsSame(const A: _ItemType_;
const B: _ItemType_): Boolean;
//#UC START# *51DECB820261_51E8098001DC_var*
//#UC END# *51DECB820261_51E8098001DC_var*
begin
//#UC START# *51DECB820261_51E8098001DC_impl*
!!! Needs to be implemented !!!
//#UC END# *51DECB820261_51E8098001DC_impl*
end;//IsSame
{$Include ..\SandBox\List.imp.pas}
{$EndIf InterfacePtrList_imp}
InterfaceRefList.imp.pas:
{$IfNDef InterfaceRefList_imp}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBox"
// The unit: "InterfaceRefList.imp.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: Impurity::Class Shared Delphi Sand Box::SandBox::STLLike::InterfaceRefList
//
// The list of the references to the interfaces. It has its items
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$Define InterfaceRefList_imp}
_List_Parent_ = _InterfaceRefList_Parent_;
{$Include ..\SandBox\List.imp.pas}
_InterfaceRefList_ = {mixin} class(_List_)
{* The list of the references to the interfaces. It has its items }
end;//_InterfaceRefList_
{$Else InterfaceRefList_imp}
// start class _InterfaceRefList_
procedure FillItem(var thePlace: _ItemType_;
const aFrom: _ItemType_); forward;
function IsSame(const A: _ItemType_;
const B: _ItemType_): Boolean; forward;
procedure FreeItem(var thePlace: _ItemType_);
//#UC START# *51DEC20B01D7_51E809AD001D_var*
//#UC END# *51DEC20B01D7_51E809AD001D_var*
begin
//#UC START# *51DEC20B01D7_51E809AD001D_impl*
thePlace := nil;
//#UC END# *51DEC20B01D7_51E809AD001D_impl*
end;//FreeItem
procedure FillItem(var thePlace: _ItemType_;
const aFrom: _ItemType_);
//#UC START# *51DECB440087_51E809AD001D_var*
//#UC END# *51DECB440087_51E809AD001D_var*
begin
//#UC START# *51DECB440087_51E809AD001D_impl*
thePlace := afrom;
//#UC END# *51DECB440087_51E809AD001D_impl*
end;//FillItem
function IsSame(const A: _ItemType_;
const B: _ItemType_): Boolean;
//#UC START# *51DECB820261_51E809AD001D_var*
//#UC END# *51DECB820261_51E809AD001D_var*
begin
//#UC START# *51DECB820261_51E809AD001D_impl*
Result := (A = B);
//#UC END# *51DECB820261_51E809AD001D_impl*
end;//IsSame
{$Include ..\SandBox\List.imp.pas}
{$EndIf InterfaceRefList_imp}
Containers 6. Abstract containers
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
Containers 5. Encapsulation of the work with the memory. Part 1
Original in Russian: http://18delphi.blogspot.ru/2013/07/1.html
About containers. Table of contents
Now we shall allocate the work with the memory to a separate object - Tl3PtrLoc.
The model:
l3MemUtils.pas:
l3PtrLoc.pas:
The source code - https://sourceforge.net/p/rumtmarc/code-0/17/tree/trunk/Blogger/STL.2/
About containers. Table of contents
Now we shall allocate the work with the memory to a separate object - Tl3PtrLoc.
The model:
The code:
unit l3MemUtils;
//
// The library "L3$Basic Concepts"
// Generated from UML model, root element: SimpleClass::Class Shared Delphi Requirements to the low-level libraries::L3$Basic Concepts::MemoryUtils::Tl3MemUtils
//
interface
uses
Refcounted
;
type
Rl3MemUtils = class of Tl3MemUtils;
Tl3MemUtils = class(TRefcounted)
protected
// protected methods
class procedure CheckMaxes; virtual;
{* The signature of the method CheckMaxes }
class procedure StatMemAlloc(aSize: Integer;
aL3: Boolean); virtual;
public
// public methods
class procedure ReallocLocalMem(var P;
NewSize: Cardinal);
{* reallocate the piece of the local memory }
class procedure FreeLocalMem(var P);
{* free the piece of the local memory }
end;//Tl3MemUtils
var
l3MemU : Rl3MemUtils = Tl3MemUtils;
var
f_LocalMemUsed : Integer;
implementation
uses
l3MemorySizeUtils
;
// start class Tl3MemUtils
class procedure Tl3MemUtils.ReallocLocalMem(var P;
NewSize: Cardinal);
//#UC START# *51DD561502D9_51DD554C0205_var*
//#UC END# *51DD561502D9_51DD554C0205_var*
begin
//#UC START# *51DD561502D9_51DD554C0205_impl*
Dec(f_LocalMemUsed, l3MemorySize(Pointer(P)));
{$IfDef l3DirectUseSystemMemManager}
if (Pointer(P) = nil) then
begin
l3MemU.StatMemAlloc(NewSize, true);
Pointer(P) := SysGetMem(NewSize)
end//Pointer(P) = nil
else
if (NewSize > 0) then
begin
l3MemU.StatMemAlloc(NewSize, true);
Pointer(P) := SysReallocMem(Pointer(P), NewSize);
end//NewSize > 0
else
begin
SysFreeMem(Pointer(P));
Pointer(P) := nil;
end;//NewSize > 0
{$Else l3DirectUseSystemMemManager}
System.ReallocMem(Pointer(P), NewSize);
{$EndIf l3DirectUseSystemMemManager}
Inc(f_LocalMemUsed, l3MemorySize(Pointer(P)));
l3MemU.CheckMaxes;
//#UC END# *51DD561502D9_51DD554C0205_impl*
end;//Tl3MemUtils.ReallocLocalMem
class procedure Tl3MemUtils.FreeLocalMem(var P);
//#UC START# *51DD62110253_51DD554C0205_var*
//#UC END# *51DD62110253_51DD554C0205_var*
begin
//#UC START# *51DD62110253_51DD554C0205_impl*
if (Pointer(P) <> nil) then
begin
Dec(f_LocalMemUsed, l3MemorySize(Pointer(P)));
{$IfDef l3DirectUseSystemMemManager}
SysFreeMem(Pointer(P));
{$Else l3DirectUseSystemMemManager}
System.FreeMem(Pointer(P));
{$EndIf l3DirectUseSystemMemManager}
end;//Pointer(P) <> nil
Pointer(P) := nil;
//#UC END# *51DD62110253_51DD554C0205_impl*
end;//Tl3MemUtils.FreeLocalMem
class procedure Tl3MemUtils.CheckMaxes;
//#UC START# *51DD686A03A3_51DD554C0205_var*
//#UC END# *51DD686A03A3_51DD554C0205_var*
begin
//#UC START# *51DD686A03A3_51DD554C0205_impl*
// - for now we do nothing
//#UC END# *51DD686A03A3_51DD554C0205_impl*
end;//Tl3MemUtils.CheckMaxes
class procedure Tl3MemUtils.StatMemAlloc(aSize: Integer;
aL3: Boolean);
//#UC START# *51DD6DCE00DF_51DD554C0205_var*
//#UC END# *51DD6DCE00DF_51DD554C0205_var*
begin
//#UC START# *51DD6DCE00DF_51DD554C0205_impl*
// - or now we do nothing
//#UC END# *51DD6DCE00DF_51DD554C0205_impl*
end;//Tl3MemUtils.StatMemAlloc
end.
l3PtrLoc.pas:
unit l3PtrLoc;
//
// The library "L3$Basic Concepts"
// Generated from UML model, root element: UtilityPack::Class Shared Delphi Requirements to the low-level libraries::L3$Basic Concepts::MemoryUtils::l3PtrLoc
//
interface
uses
l3MemorySizeUtils
;
type
Tl3PtrLoc = {$IfDef XE4}record{$Else}object{$EndIf}
private
f_AsPointer : PMem;
public
function Init(aSize: Integer): Boolean;
function GetSize: Integer;
procedure SetSize(aSize: Integer);
procedure Clear;
function Read(anOfs: Integer;
aBuf: PMem;
aBufSize: Integer): Integer;
function Write(anOfs: Integer;
aBuf: PMem;
aBufSize: Integer): Integer;
public
property AsPointer: PMem
read f_AsPointer;
end;//Tl3PtrLoc
implementation
uses
l3MemUtils
;
// start class Tl3PtrLoc
function Tl3PtrLoc.Init(aSize: Integer): Boolean;
//#UC START# *51DD5D1903C3_51DD567A01B5_var*
//#UC END# *51DD5D1903C3_51DD567A01B5_var*
begin
//#UC START# *51DD5D1903C3_51DD567A01B5_impl*
f_AsPointer := nil;
SetSize(aSize);
Result := (f_AsPointer <> nil);
//#UC END# *51DD5D1903C3_51DD567A01B5_impl*
end;//Tl3PtrLoc.Init
function Tl3PtrLoc.GetSize: Integer;
//#UC START# *51DD5D3800F3_51DD567A01B5_var*
//#UC END# *51DD5D3800F3_51DD567A01B5_var*
begin
//#UC START# *51DD5D3800F3_51DD567A01B5_impl*
Result := l3MemorySize(f_AsPointer);
//#UC END# *51DD5D3800F3_51DD567A01B5_impl*
end;//Tl3PtrLoc.GetSize
procedure Tl3PtrLoc.SetSize(aSize: Integer);
//#UC START# *51DD5D4F004A_51DD567A01B5_var*
//#UC END# *51DD5D4F004A_51DD567A01B5_var*
begin
//#UC START# *51DD5D4F004A_51DD567A01B5_impl*
if (aSize = 0) then
l3MemU.FreeLocalMem(f_AsPointer)
else
if (GetSize < aSize) then
begin
// - previously it was <> - now I’ve decided to try not to reduce the size of the memory
// so that not to produce defragmentation.
if (aSize < 10) then
l3MemU.ReallocLocalMem(f_AsPointer, aSize)
else
l3MemU.ReallocLocalMem(f_AsPointer, (aSize + $F) and $FFFFFFF0);
end;//GetSize < aSize
//#UC END# *51DD5D4F004A_51DD567A01B5_impl*
end;//Tl3PtrLoc.SetSize
procedure Tl3PtrLoc.Clear;
//#UC START# *51DD5D6F0304_51DD567A01B5_var*
//#UC END# *51DD5D6F0304_51DD567A01B5_var*
begin
//#UC START# *51DD5D6F0304_51DD567A01B5_impl*
SetSize(0);
//#UC END# *51DD5D6F0304_51DD567A01B5_impl*
end;//Tl3PtrLoc.Clear
function Tl3PtrLoc.Read(anOfs: Integer;
aBuf: PMem;
aBufSize: Integer): Integer;
//#UC START# *51DD5E2203B0_51DD567A01B5_var*
//#UC END# *51DD5E2203B0_51DD567A01B5_var*
begin
//#UC START# *51DD5E2203B0_51DD567A01B5_impl*
Result := 0;
Assert(false, 'Not implemented yet');
(* Result := Min(GetSize - anOfs, aBufSize);
if (Result > 0) then
l3Move((P + anOfs)^, aBuf^, Result)
else
Result := 0;*)
//#UC END# *51DD5E2203B0_51DD567A01B5_impl*
end;//Tl3PtrLoc.Read
function Tl3PtrLoc.Write(anOfs: Integer;
aBuf: PMem;
aBufSize: Integer): Integer;
//#UC START# *51DD5E5F02E1_51DD567A01B5_var*
(*var
OldSize : Integer;
NewSize : Integer;*)
//#UC END# *51DD5E5F02E1_51DD567A01B5_var*
begin
//#UC START# *51DD5E5F02E1_51DD567A01B5_impl*
Result := 0;
Assert(false, 'Not implemented yet');
(* OldSize := GetSize;
NewSize := Ofs + BufSize;
if (NewSize > OldSize) then SetSize(NewSize);
Result := BufSize;
l3Move(Buf^, (P + Ofs)^, Result);*)
//#UC END# *51DD5E5F02E1_51DD567A01B5_impl*
end;//Tl3PtrLoc.Write
end.
The source code - https://sourceforge.net/p/rumtmarc/code-0/17/tree/trunk/Blogger/STL.2/
Containers 4. Encapsulation of the work with the memory. Part 0
Original in Russian: http://18delphi.blogspot.ru/2013/07/0.html
About containers. Table of contents
I’d like to continue describing the containers in “STL style”.
Tthere I have used dynamic arrays.
In my REAL “micro-STL” I use direct work with the memory - GetMem/FreeMem.
That is why I want to start with how I work with the memory directly. Or rather how I’ve encapsulated the work with the memory in different facade functions/objects.
The first example is receiving the size of the memory piece. I have already told a bit here - http://18delphi.blogspot.ru/2015/02/how-to-find-out-true-size-of-memory.html
And now I want to show how it is drawn on UML and how it is encapsulated in a separate unit.
So.
At first – the model:
And the test.
The model:
The code:
Next, I hope, I’ll tell about the encapsulation GetMem/FreeMem/ReallocMem in "object" Tl3Ptr.
All sources are here - https://sourceforge.net/p/rumtmarc/code-0/15/tree/trunk/Blogger/STL.1/
About containers. Table of contents
I’d like to continue describing the containers in “STL style”.
Tthere I have used dynamic arrays.
In my REAL “micro-STL” I use direct work with the memory - GetMem/FreeMem.
That is why I want to start with how I work with the memory directly. Or rather how I’ve encapsulated the work with the memory in different facade functions/objects.
The first example is receiving the size of the memory piece. I have already told a bit here - http://18delphi.blogspot.ru/2015/02/how-to-find-out-true-size-of-memory.html
And now I want to show how it is drawn on UML and how it is encapsulated in a separate unit.
So.
At first – the model:
And the code:
l3MemorySizeUtilsPrim.pas:
unit l3MemorySizeUtilsPrim;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "L3$Basic Concepts"
// The unit: "w:/common/components/rtl/L3/l3MemorySizeUtilsPrim.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: UtilityPack::Class Shared Delphi Requirements to the low-level libraries::L3$Basic Concepts::MemoryUtils::l3MemorySizeUtilsPrim
//
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ! Fully generated from the model. It is not allowed to edit manually. !
interface
type
Tl3MemorySizeFunc = function (aPtr: Pointer): Integer;
{$If not defined(XE)}
function L3MemorySizeDelphi7(aPtr: Pointer): Integer;
{* function to get the size of the memory piece }
{$IfEnd} //not XE
{$If defined(XE)}
function L3MemorySizeXE(aPtr: Pointer): Integer;
{* function to get the size of the memory piece }
{$IfEnd} //XE
implementation
uses
l3MemorySizeUtils
;
// unit methods
{$If not defined(XE)}
function L3MemorySizeDelphi7(aPtr: Pointer): Integer;
//#UC START# *51DAD8DC00B2_51DADE55035E_var*
const
cThisUsedFlag = 2;
cPrevFreeFlag = 1;
cFillerFlag = Integer($80000000);
cFlags = cThisUsedFlag or cPrevFreeFlag or cFillerFlag;
type
PUsed = ^TUsed;
TUsed = packed record
sizeFlags: Integer;
end;//TUsed
//#UC END# *51DAD8DC00B2_51DADE55035E_var*
begin
//#UC START# *51DAD8DC00B2_51DADE55035E_impl*
if (aPtr = nil) then
Result := 0
else
Result := PUsed(PMem(aPtr)-SizeOf(TUsed)).sizeFlags and not cFlags - sizeof(TUsed);
// Result := (PLong(Long(aP) - 4)^ AND not cFlags) - 4;
//#UC END# *51DAD8DC00B2_51DADE55035E_impl*
end;//L3MemorySizeDelphi7
{$IfEnd} //not XE
{$If defined(XE)}
function L3MemorySizeXE(aPtr: Pointer): Integer;
//#UC START# *51DADA9600F9_51DADE55035E_var*
const
{----------------------------Block type flags---------------------------}
{The lower 3 bits in the dword header of small blocks (4 bits in medium and
large blocks) are used as flags to indicate the state of the block}
{Set if the block is not in use}
IsFreeBlockFlag = 1;
{Set if this is a medium block}
IsMediumBlockFlag = 2;
{Set if it is a medium block being used as a small block pool. Only valid if
IsMediumBlockFlag is set.}
IsSmallBlockPoolInUseFlag = 4;
{Set if it is a large block. Only valid if IsMediumBlockFlag is not set.}
IsLargeBlockFlag = 4;
{Is the medium block preceding this block available?}
PreviousMediumBlockIsFreeFlag = 8;
{Is this large block segmented? I.e. is it actually built up from more than
one chunk allocated through VirtualAlloc? (Only used by large blocks.)}
LargeBlockIsSegmented = 8;
{The flags masks for small blocks}
DropSmallFlagsMask = -8;
ExtractSmallFlagsMask = 7;
{The flags masks for medium and large blocks}
DropMediumAndLargeFlagsMask = -16;
ExtractMediumAndLargeFlagsMask = 15;
{------------------------------Private types------------------------------}
type
{Move procedure type}
TMoveProc = procedure(const ASource; var ADest; ACount: NativeInt);
{-----------------------Small block structures--------------------------}
{Pointer to the header of a small block pool}
PSmallBlockPoolHeader = ^TSmallBlockPoolHeader;
{Small block type (Size = 32 bytes for 32-bit, 64 bytes for 64-bit).}
PSmallBlockType = ^TSmallBlockType;
TSmallBlockType = record
{True = Block type is locked}
BlockTypeLocked: Boolean;
{Bitmap indicating which of the first 8 medium block groups contain blocks
of a suitable size for a block pool.}
AllowedGroupsForBlockPoolBitmap: Byte;
{The block size for this block type}
BlockSize: Word;
{The minimum and optimal size of a small block pool for this block type}
MinimumBlockPoolSize: Word;
OptimalBlockPoolSize: Word;
{The first partially free pool for the given small block. This field must
be at the same offset as TSmallBlockPoolHeader.NextPartiallyFreePool.}
NextPartiallyFreePool: PSmallBlockPoolHeader;
{The last partially free pool for the small block type. This field must
be at the same offset as TSmallBlockPoolHeader.PreviousPartiallyFreePool.}
PreviousPartiallyFreePool: PSmallBlockPoolHeader;
{The offset of the last block that was served sequentially. The field must
be at the same offset as TSmallBlockPoolHeader.FirstFreeBlock.}
NextSequentialFeedBlockAddress: Pointer;
{The last block that can be served sequentially.}
MaxSequentialFeedBlockAddress: Pointer;
{The pool that is current being used to serve blocks in sequential order}
CurrentSequentialFeedPool: PSmallBlockPoolHeader;
{$ifdef UseCustomFixedSizeMoveRoutines}
{The fixed size move procedure used to move data for this block size when
it is upsized. When a block is downsized (which usually does not occur
that often) the variable size move routine is used.}
UpsizeMoveProcedure: TMoveProc;
{$else}
Reserved1: Pointer;
{$endif}
{$if SizeOf(Pointer) = 8}
{Pad to 64 bytes for 64-bit}
Reserved2: Pointer;
{$ifend}
end;
{Small block pool (Size = 32 bytes for 32-bit, 48 bytes for 64-bit).}
TSmallBlockPoolHeader = record
{BlockType}
BlockType: PSmallBlockType;
{$if SizeOf(Pointer) <> 8}
{Align the next fields to the same fields in TSmallBlockType and pad this
structure to 32 bytes for 32-bit}
Reserved1: Cardinal;
{$ifend}
{The next and previous pool that has free blocks of this size. Do not
change the position of these two fields: They must be at the same offsets
as the fields in TSmallBlockType of the same name.}
NextPartiallyFreePool: PSmallBlockPoolHeader;
PreviousPartiallyFreePool: PSmallBlockPoolHeader;
{Pointer to the first free block inside this pool. This field must be at
the same offset as TSmallBlockType.NextSequentialFeedBlockAddress.}
FirstFreeBlock: Pointer;
{The number of blocks allocated in this pool.}
BlocksInUse: Cardinal;
{Small block pool signature. Used by the leak checking mechanism to
determine whether a medium block is a small block pool or a regular medium
block.}
SmallBlockPoolSignature: Cardinal;
{The pool pointer and flags of the first block}
FirstBlockPoolPointerAndFlags: NativeUInt;
end;
{Small block layout:
At offset -SizeOf(Pointer) = Flags + address of the small block pool.
At offset BlockSize - SizeOf(Pointer) = Flags + address of the small block
pool for the next small block.
}
{------------------------Medium block structures------------------------}
{The medium block pool from which medium blocks are drawn. Size = 16 bytes
for 32-bit and 32 bytes for 64-bit.}
PMediumBlockPoolHeader = ^TMediumBlockPoolHeader;
TMediumBlockPoolHeader = record
{Points to the previous and next medium block pools. This circular linked
list is used to track memory leaks on program shutdown.}
PreviousMediumBlockPoolHeader: PMediumBlockPoolHeader;
NextMediumBlockPoolHeader: PMediumBlockPoolHeader;
{Padding}
Reserved1: NativeUInt;
{The block size and flags of the first medium block in the block pool}
FirstMediumBlockSizeAndFlags: NativeUInt;
end;
{Medium block layout:
Offset: -2 * SizeOf(Pointer) = Previous Block Size (only if the previous block is free)
Offset: -SizeOf(Pointer) = This block size and flags
Offset: 0 = User data / Previous Free Block (if this block is free)
Offset: SizeOf(Pointer) = Next Free Block (if this block is free)
Offset: BlockSize - 2*SizeOf(Pointer) = Size of this block (if this block is free)
Offset: BlockSize - SizeOf(Pointer) = Size of the next block and flags
{A medium block that is unused}
PMediumFreeBlock = ^TMediumFreeBlock;
TMediumFreeBlock = record
PreviousFreeBlock: PMediumFreeBlock;
NextFreeBlock: PMediumFreeBlock;
end;
{-------------------------Large block structures------------------------}
{Large block header record (Size = 16 for 32-bit, 32 for 64-bit)}
PLargeBlockHeader = ^TLargeBlockHeader;
TLargeBlockHeader = record
{Points to the previous and next large blocks. This circular linked
list is used to track memory leaks on program shutdown.}
PreviousLargeBlockHeader: PLargeBlockHeader;
NextLargeBlockHeader: PLargeBlockHeader;
{The user allocated size of the Large block}
UserAllocatedSize: NativeUInt;
{The size of this block plus the flags}
BlockSizeAndFlags: NativeUInt;
end;
{---------------------------Private constants-----------------------------}
const
{The size of the block header in front of small and medium blocks}
BlockHeaderSize = SizeOf(Pointer);
{The size of a small block pool header}
SmallBlockPoolHeaderSize = SizeOf(TSmallBlockPoolHeader);
{The size of a medium block pool header}
MediumBlockPoolHeaderSize = SizeOf(TMediumBlockPoolHeader);
{The size of the header in front of Large blocks}
LargeBlockHeaderSize = SizeOf(TLargeBlockHeader);
(*
{This memory manager}
ThisMemoryManager: TMemoryManagerEx = (
GetMem: SysGetMem;
FreeMem: SysFreeMem;
ReallocMem: SysReallocMem;
AllocMem: SysAllocMem;
RegisterExpectedMemoryLeak: SysRegisterExpectedMemoryLeak;
UnregisterExpectedMemoryLeak: SysUnregisterExpectedMemoryLeak);
*)
var
lBlockHeader: Cardinal;
LPSmallBlockType: PSmallBlockType;
LOldAvailableSize: Cardinal;
//#UC END# *51DADA9600F9_51DADE55035E_var*
begin
//#UC START# *51DADA9600F9_51DADE55035E_impl*
if (aPtr = nil) then
Result := 0
else
begin
{Get the block header: Is it actually a small block?}
LBlockHeader := PNativeUInt(PByte(aPtr) - BlockHeaderSize)^;
{Is it a small block that is in use?}
if LBlockHeader and (IsFreeBlockFlag or IsMediumBlockFlag or IsLargeBlockFlag) = 0 then
begin
{----------------------------Small block------------------------------}
{The block header is a pointer to the block pool: Get the block type}
LPSmallBlockType := PSmallBlockPoolHeader(LBlockHeader).BlockType;
{Get the available size inside blocks of this type.}
Result := LPSmallBlockType.BlockSize - BlockHeaderSize;
end
else
begin
{Is this a medium block or a large block?}
if LBlockHeader and (IsFreeBlockFlag or IsLargeBlockFlag) = 0 then
begin
Result:= (LBlockHeader and DropMediumAndLargeFlagsMask) - BlockHeaderSize;
end
else
begin
{Is this a valid large block?}
if LBlockHeader and (IsFreeBlockFlag or IsMediumBlockFlag) = 0 then
begin
{-----------------------Large block------------------------------}
{Get the block header}
//LBlockHeader := PNativeUInt(PByte(aP) - BlockHeaderSize)^;
{Subtract the overhead to determine the useable size in the large block.}
Result := (LBlockHeader and DropMediumAndLargeFlagsMask) - (LargeBlockHeaderSize + BlockHeaderSize);
end
else
begin
{-----------------------Invalid block------------------------------}
{Bad pointer: probably an attempt to reallocate a free memory block.}
Result := 0;
assert(false);
end;
end;
end;
end;
//#UC END# *51DADA9600F9_51DADE55035E_impl*
end;//L3MemorySizeXE
{$IfEnd} //XE
end.
------
l3MemorySizeUtils.pas:
unit l3MemorySizeUtils;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "L3$Basic Concepts"
// The unit: "w:/common/components/rtl/L3/l3MemorySizeUtils.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: UtilityPack::Class Shared Delphi Requirements to the low-level libraries::L3$Basic Concepts::MemoryUtils::l3MemorySizeUtils
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ! Fully generated from the model. It is not allowed to edit manually. !
interface
uses
l3MemorySizeUtilsPrim
;
type
PMem = System.PANSIChar;
{$If not defined(XE)}
var l3MemorySize : Tl3MemorySizeFunc = L3MemorySizeDelphi7;
{* function to get the size of the memory piece}
{$IfEnd} //not XE
{$If defined(XE)}
var l3MemorySize : Tl3MemorySizeFunc = L3MemorySizeXE;
{* function to get the size of the memory piece}
{$IfEnd} //XE
implementation
end.
And the test.
The model:
The code:
unit MemorySizeTest;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// The library "SandBoxTest"
// The unit: "w:/common/components/rtl/SandBox/MemorySizeTest.pas"
// Native Delphi interfaces (.pas)
// Generated from UML model, root element: TestCase::Class Shared Delphi Sand Box::SandBoxTest::Memory::MemorySizeTest
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ! Fully generated from the model. It is not allowed to edit manually. !
interface
{$If defined(nsTest)}
uses
BaseTest
;
{$IfEnd} //nsTest
{$If defined(nsTest)}
type
TMemorySizeTest = class(TBaseTest)
protected
// overridden protected methods
function GetFolder: AnsiString; override;
{* The folder containing the test }
function GetModelElementGUID: AnsiString; override;
{* The model element identifier that describes the test }
published
// published methods
procedure DoIt;
end;//TMemorySizeTest
{$IfEnd} //nsTest
implementation
{$If defined(nsTest)}
uses
l3MemorySizeUtils,
SysUtils,
TestFrameWork
;
{$IfEnd} //nsTest
{$If defined(nsTest)}
// start class TMemorySizeTest
procedure TMemorySizeTest.DoIt;
//#UC START# *51DAE7030012_51DAE6E20300_var*
var
l_Index : Integer;
l_Size : Integer;
l_RealSize : Integer;
l_P : Pointer;
//#UC END# *51DAE7030012_51DAE6E20300_var*
begin
//#UC START# *51DAE7030012_51DAE6E20300_impl*
for l_Index := 1 to 4 * 1024 do
begin
l_Size := l_Index * 2;
System.GetMem(l_P, l_Size);
try
l_RealSize := l3MemorySize(l_P);
Check(l_RealSize >= l_Size, Format('We have allocated %d. It has been allocated %d.', [l_Size, l_RealSize]));
finally
System.FreeMem(l_P);
end;//try..finally
end;//form l_Index
//#UC END# *51DAE7030012_51DAE6E20300_impl*
end;//TMemorySizeTest.DoIt
function TMemorySizeTest.GetFolder: AnsiString;
{-}
begin
Result := 'Memory';
end;//TMemorySizeTest.GetFolder
function TMemorySizeTest.GetModelElementGUID: AnsiString;
{-}
begin
Result := '51DAE6E20300';
end;//TMemorySizeTest.GetModelElementGUID
{$IfEnd} //nsTest
initialization
TestFramework.RegisterTest(TMemorySizeTest.Suite);
end.
Next, I hope, I’ll tell about the encapsulation GetMem/FreeMem/ReallocMem in "object" Tl3Ptr.
All sources are here - https://sourceforge.net/p/rumtmarc/code-0/15/tree/trunk/Blogger/STL.1/
Подписаться на:
Комментарии (Atom)
















