From 957fb0a20df2034974135349edfe8ac79f52ec71 Mon Sep 17 00:00:00 2001 From: Martok Date: Fri, 14 Apr 2017 22:38:40 +0200 Subject: [PATCH] * [uutlGenerics] TutlList: declare Sort() and required generics * [uutlAlgorithm] range errors in QuickSort, avoid double-free by using IutlArray.Exchange * [uutlComparer] TutlReverseComparer: invert an arbitrary IutlComparer --- uutlAlgorithm.pas | 22 ++++++++++------------ uutlComparer.pas | 38 ++++++++++++++++++++++++++++++++++++++ uutlGenerics.pas | 16 +++++++++++++++- uutlInterfaces.pas | 1 + 4 files changed, 64 insertions(+), 13 deletions(-) diff --git a/uutlAlgorithm.pas b/uutlAlgorithm.pas index d24fb80..3f2bbbb 100644 --- a/uutlAlgorithm.pas +++ b/uutlAlgorithm.pas @@ -180,21 +180,19 @@ class procedure TutlQuickSort.DoSort( aHigh: Integer); var lo, hi: Integer; - p, tmp: T; + p: T; begin - repeat + while (aLow < aHigh) do begin lo := aLow; hi := aHigh; p := aArray[(aLow + aHigh) div 2]; repeat - while (aComparer.Compare(p, aArray[lo]) > 0) do + while (aComparer.Compare(p, aArray[lo]) > 0) and (lo < aHigh) do lo := lo + 1; - while (aComparer.Compare(p, aArray[hi]) < 0) do + while (aComparer.Compare(p, aArray[hi]) < 0) and (hi > aLow) do hi := hi - 1; if (lo <= hi) then begin - tmp := aArray[lo]; - aArray[lo] := aArray[hi]; - aArray[hi] := tmp; + aArray.Exchange(lo, hi); lo := lo + 1; hi := hi - 1; end; @@ -209,7 +207,7 @@ begin DoSort(aArray, aComparer, lo, aHigh); aHigh := hi; end; - until (aLow >= aHigh); + end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -225,14 +223,14 @@ begin if not Assigned(aArray) then raise EArgumentNilException.Create('aArray'); - repeat + while (aLow < aHigh) do begin lo := aLow; hi := aHigh; p := aArray[(aLow + aHigh) div 2]; repeat - while (aComparer.Compare(p, aArray[lo]) > 0) do + while (aComparer.Compare(p, aArray[lo]) > 0) and (lo < aHigh) do lo := lo + 1; - while (aComparer.Compare(p, aArray[hi]) < 0) do + while (aComparer.Compare(p, aArray[hi]) < 0) and (hi > aLow) do hi := hi - 1; if (lo <= hi) then begin tmp := aArray[lo]; @@ -252,7 +250,7 @@ begin DoSort(aArray, aComparer, lo, aHigh); aHigh := hi; end; - until (aLow >= aHigh); + end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/uutlComparer.pas b/uutlComparer.pas index 91de2cd..0b19721 100644 --- a/uutlComparer.pas +++ b/uutlComparer.pas @@ -111,6 +111,25 @@ type {$ENDIF} end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + generic TutlReverseComparer = class( + TInterfacedObject, + specialize IutlEqualityComparer, + specialize IutlComparer) + + public type + IComparer = specialize IutlComparer; + + private + fComparer: IComparer; + + public + function EqualityCompare(constref i1, i2: T): Boolean; + function Compare(constref i1, i2: T): Integer; + + constructor Create(aComparer: IComparer); + end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// operator <(const i1, i2: TObject): Boolean; inline; operator >(const i1, i2: TObject): Boolean; inline; @@ -244,5 +263,24 @@ begin end; {$ENDIF} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlReverseComparer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TutlReverseComparer.EqualityCompare(constref i1, i2: T): Boolean; +begin + Result:= fComparer.EqualityCompare(i1, i2); +end; + +function TutlReverseComparer.Compare(constref i1, i2: T): Integer; +begin + Result:= - fComparer.Compare(i1, i2); +end; + +constructor TutlReverseComparer.Create(aComparer: IComparer); +begin + inherited Create; + fComparer:= aComparer; +end; + end. diff --git a/uutlGenerics.pas b/uutlGenerics.pas index cfa4448..832d4f9 100644 --- a/uutlGenerics.pas +++ b/uutlGenerics.pas @@ -207,10 +207,16 @@ type generic TutlList = class( specialize TutlCustomList) + private type + TQuickSortImpl = specialize TutlQuickSort; + IComparer = TQuickSortimpl.IComparer; + TReverseComp = specialize TutlReverseComparer; public type TEqualityComparer = specialize TutlEqualityComparer; public + procedure Sort(aComparer: IComparer; const aReverse: boolean = false); + constructor Create(const aOwnsItems: Boolean); end; @@ -1157,7 +1163,7 @@ begin System.Move(p1^, tmp{%H-}, SizeOf(T)); System.Move(p2^, p1^, SizeOf(T)); System.Move(tmp, p2^, SizeOf(T)); - FillByte(tmp, SizeOf(tmp), 0) + FillByte(tmp, SizeOf(tmp), 0); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1278,6 +1284,14 @@ end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TutlList.Sort(aComparer: IComparer; const aReverse: boolean); +begin + if aReverse then + aComparer:= TReverseComp.Create(aComparer); + TQuickSortImpl.Sort(Self, aComparer); +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlList.Create(const aOwnsItems: Boolean); begin diff --git a/uutlInterfaces.pas b/uutlInterfaces.pas index 6328a46..9eed030 100644 --- a/uutlInterfaces.pas +++ b/uutlInterfaces.pas @@ -92,6 +92,7 @@ type ['{D3618E88-3BF7-4E63-850F-6893A334564A}'] procedure SetCount(const aValue: Integer); procedure SetItem(const aIndex: Integer; aItem: T); + procedure Exchange(const aIndex1, aIndex2: Integer); property Count: Integer read GetCount write SetCount; property Items[const aIndex: Integer]: T read GetItem write SetItem; default;