git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.jcl@20 c37d764d-f447-7644-a108-883140d013fb
30419 lines
776 KiB
ObjectPascal
30419 lines
776 KiB
ObjectPascal
{**************************************************************************************************}
|
|
{ WARNING: JEDI preprocessor generated unit. Do not edit. }
|
|
{**************************************************************************************************}
|
|
|
|
{**************************************************************************************************}
|
|
{ }
|
|
{ Project JEDI Code Library (JCL) }
|
|
{ }
|
|
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
|
|
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
|
|
{ License at http://www.mozilla.org/MPL/ }
|
|
{ }
|
|
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
|
|
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
|
|
{ and limitations under the License. }
|
|
{ }
|
|
{ The Original Code is JclSortedMaps.pas. }
|
|
{ }
|
|
{ The Initial Developer of the Original Code is Florent Ouchet. Portions created by }
|
|
{ Florent Ouchet are Copyright (C) Florent Ouchet <outchy att users dott sourceforge dott net }
|
|
{ All rights reserved. }
|
|
{ }
|
|
{ Contributors: }
|
|
{ }
|
|
{**************************************************************************************************}
|
|
{ }
|
|
{ The Delphi Container Library }
|
|
{ }
|
|
{**************************************************************************************************}
|
|
{ }
|
|
{ Last modified: $Date:: 2009-09-12 14:21:23 +0200 (sam., 12 sept. 2009) $ }
|
|
{ Revision: $Rev:: 2997 $ }
|
|
{ Author: $Author:: outchy $ }
|
|
{ }
|
|
{**************************************************************************************************}
|
|
|
|
unit JclSortedMaps;
|
|
|
|
interface
|
|
|
|
{$I jcl.inc}
|
|
|
|
uses
|
|
Classes,
|
|
{$IFDEF UNITVERSIONING}
|
|
JclUnitVersioning,
|
|
{$ENDIF UNITVERSIONING}
|
|
{$IFDEF SUPPORTS_GENERICS}
|
|
JclAlgorithms,
|
|
{$ENDIF SUPPORTS_GENERICS}
|
|
JclBase, JclSynch,
|
|
JclAbstractContainers, JclContainerIntf, JclArrayLists, JclArraySets;
|
|
|
|
type
|
|
TJclIntfIntfSortedEntry = record
|
|
Key: IInterface;
|
|
Value: IInterface;
|
|
end;
|
|
|
|
TJclIntfIntfSortedMap = class(TJclIntfAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclIntfIntfMap, IJclIntfIntfSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function FreeValue(var Value: IInterface): IInterface;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(const A, B: IInterface): Integer;
|
|
private
|
|
FEntries: array of TJclIntfIntfSortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfIntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(const Value: IInterface): Boolean;
|
|
function Extract(const Key: IInterface): IInterface;
|
|
function GetValue(const Key: IInterface): IInterface;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: IInterface): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfIntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfIntfMap);
|
|
procedure PutValue(const Key: IInterface; const Value: IInterface);
|
|
function Remove(const Key: IInterface): IInterface;
|
|
function Size: Integer;
|
|
function Values: IJclIntfCollection;
|
|
{ IJclIntfIntfSortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfIntfSortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfIntfSortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfIntfSortedMap;
|
|
end;
|
|
|
|
TJclAnsiStrIntfSortedEntry = record
|
|
Key: AnsiString;
|
|
Value: IInterface;
|
|
end;
|
|
|
|
TJclAnsiStrIntfSortedMap = class(TJclAnsiStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclAnsiStrContainer,
|
|
IJclAnsiStrIntfMap, IJclAnsiStrIntfSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: AnsiString): AnsiString;
|
|
function FreeValue(var Value: IInterface): IInterface;
|
|
function KeysCompare(const A, B: AnsiString): Integer;
|
|
function ValuesCompare(const A, B: IInterface): Integer;
|
|
private
|
|
FEntries: array of TJclAnsiStrIntfSortedEntry;
|
|
function BinarySearch(const Key: AnsiString): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclAnsiStrIntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: AnsiString): Boolean;
|
|
function ContainsValue(const Value: IInterface): Boolean;
|
|
function Extract(const Key: AnsiString): IInterface;
|
|
function GetValue(const Key: AnsiString): IInterface;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: IInterface): AnsiString;
|
|
function KeySet: IJclAnsiStrSet;
|
|
function MapEquals(const AMap: IJclAnsiStrIntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclAnsiStrIntfMap);
|
|
procedure PutValue(const Key: AnsiString; const Value: IInterface);
|
|
function Remove(const Key: AnsiString): IInterface;
|
|
function Size: Integer;
|
|
function Values: IJclIntfCollection;
|
|
{ IJclAnsiStrIntfSortedMap }
|
|
function FirstKey: AnsiString;
|
|
function HeadMap(const ToKey: AnsiString): IJclAnsiStrIntfSortedMap;
|
|
function LastKey: AnsiString;
|
|
function SubMap(const FromKey, ToKey: AnsiString): IJclAnsiStrIntfSortedMap;
|
|
function TailMap(const FromKey: AnsiString): IJclAnsiStrIntfSortedMap;
|
|
end;
|
|
|
|
TJclIntfAnsiStrSortedEntry = record
|
|
Key: IInterface;
|
|
Value: AnsiString;
|
|
end;
|
|
|
|
TJclIntfAnsiStrSortedMap = class(TJclAnsiStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclAnsiStrContainer,
|
|
IJclIntfAnsiStrMap, IJclIntfAnsiStrSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function FreeValue(var Value: AnsiString): AnsiString;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(const A, B: AnsiString): Integer;
|
|
private
|
|
FEntries: array of TJclIntfAnsiStrSortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfAnsiStrMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(const Value: AnsiString): Boolean;
|
|
function Extract(const Key: IInterface): AnsiString;
|
|
function GetValue(const Key: IInterface): AnsiString;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: AnsiString): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfAnsiStrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfAnsiStrMap);
|
|
procedure PutValue(const Key: IInterface; const Value: AnsiString);
|
|
function Remove(const Key: IInterface): AnsiString;
|
|
function Size: Integer;
|
|
function Values: IJclAnsiStrCollection;
|
|
{ IJclIntfAnsiStrSortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfAnsiStrSortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfAnsiStrSortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfAnsiStrSortedMap;
|
|
end;
|
|
|
|
TJclAnsiStrAnsiStrSortedEntry = record
|
|
Key: AnsiString;
|
|
Value: AnsiString;
|
|
end;
|
|
|
|
TJclAnsiStrAnsiStrSortedMap = class(TJclAnsiStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclAnsiStrContainer,
|
|
IJclAnsiStrAnsiStrMap, IJclAnsiStrAnsiStrSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: AnsiString): AnsiString;
|
|
function FreeValue(var Value: AnsiString): AnsiString;
|
|
function KeysCompare(const A, B: AnsiString): Integer;
|
|
function ValuesCompare(const A, B: AnsiString): Integer;
|
|
private
|
|
FEntries: array of TJclAnsiStrAnsiStrSortedEntry;
|
|
function BinarySearch(const Key: AnsiString): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclAnsiStrAnsiStrMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: AnsiString): Boolean;
|
|
function ContainsValue(const Value: AnsiString): Boolean;
|
|
function Extract(const Key: AnsiString): AnsiString;
|
|
function GetValue(const Key: AnsiString): AnsiString;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: AnsiString): AnsiString;
|
|
function KeySet: IJclAnsiStrSet;
|
|
function MapEquals(const AMap: IJclAnsiStrAnsiStrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclAnsiStrAnsiStrMap);
|
|
procedure PutValue(const Key: AnsiString; const Value: AnsiString);
|
|
function Remove(const Key: AnsiString): AnsiString;
|
|
function Size: Integer;
|
|
function Values: IJclAnsiStrCollection;
|
|
{ IJclAnsiStrAnsiStrSortedMap }
|
|
function FirstKey: AnsiString;
|
|
function HeadMap(const ToKey: AnsiString): IJclAnsiStrAnsiStrSortedMap;
|
|
function LastKey: AnsiString;
|
|
function SubMap(const FromKey, ToKey: AnsiString): IJclAnsiStrAnsiStrSortedMap;
|
|
function TailMap(const FromKey: AnsiString): IJclAnsiStrAnsiStrSortedMap;
|
|
end;
|
|
|
|
TJclWideStrIntfSortedEntry = record
|
|
Key: WideString;
|
|
Value: IInterface;
|
|
end;
|
|
|
|
TJclWideStrIntfSortedMap = class(TJclWideStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclWideStrContainer,
|
|
IJclWideStrIntfMap, IJclWideStrIntfSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: WideString): WideString;
|
|
function FreeValue(var Value: IInterface): IInterface;
|
|
function KeysCompare(const A, B: WideString): Integer;
|
|
function ValuesCompare(const A, B: IInterface): Integer;
|
|
private
|
|
FEntries: array of TJclWideStrIntfSortedEntry;
|
|
function BinarySearch(const Key: WideString): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclWideStrIntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: WideString): Boolean;
|
|
function ContainsValue(const Value: IInterface): Boolean;
|
|
function Extract(const Key: WideString): IInterface;
|
|
function GetValue(const Key: WideString): IInterface;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: IInterface): WideString;
|
|
function KeySet: IJclWideStrSet;
|
|
function MapEquals(const AMap: IJclWideStrIntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclWideStrIntfMap);
|
|
procedure PutValue(const Key: WideString; const Value: IInterface);
|
|
function Remove(const Key: WideString): IInterface;
|
|
function Size: Integer;
|
|
function Values: IJclIntfCollection;
|
|
{ IJclWideStrIntfSortedMap }
|
|
function FirstKey: WideString;
|
|
function HeadMap(const ToKey: WideString): IJclWideStrIntfSortedMap;
|
|
function LastKey: WideString;
|
|
function SubMap(const FromKey, ToKey: WideString): IJclWideStrIntfSortedMap;
|
|
function TailMap(const FromKey: WideString): IJclWideStrIntfSortedMap;
|
|
end;
|
|
|
|
TJclIntfWideStrSortedEntry = record
|
|
Key: IInterface;
|
|
Value: WideString;
|
|
end;
|
|
|
|
TJclIntfWideStrSortedMap = class(TJclWideStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclWideStrContainer,
|
|
IJclIntfWideStrMap, IJclIntfWideStrSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function FreeValue(var Value: WideString): WideString;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(const A, B: WideString): Integer;
|
|
private
|
|
FEntries: array of TJclIntfWideStrSortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfWideStrMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(const Value: WideString): Boolean;
|
|
function Extract(const Key: IInterface): WideString;
|
|
function GetValue(const Key: IInterface): WideString;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: WideString): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfWideStrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfWideStrMap);
|
|
procedure PutValue(const Key: IInterface; const Value: WideString);
|
|
function Remove(const Key: IInterface): WideString;
|
|
function Size: Integer;
|
|
function Values: IJclWideStrCollection;
|
|
{ IJclIntfWideStrSortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfWideStrSortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfWideStrSortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfWideStrSortedMap;
|
|
end;
|
|
|
|
TJclWideStrWideStrSortedEntry = record
|
|
Key: WideString;
|
|
Value: WideString;
|
|
end;
|
|
|
|
TJclWideStrWideStrSortedMap = class(TJclWideStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclWideStrContainer,
|
|
IJclWideStrWideStrMap, IJclWideStrWideStrSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: WideString): WideString;
|
|
function FreeValue(var Value: WideString): WideString;
|
|
function KeysCompare(const A, B: WideString): Integer;
|
|
function ValuesCompare(const A, B: WideString): Integer;
|
|
private
|
|
FEntries: array of TJclWideStrWideStrSortedEntry;
|
|
function BinarySearch(const Key: WideString): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclWideStrWideStrMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: WideString): Boolean;
|
|
function ContainsValue(const Value: WideString): Boolean;
|
|
function Extract(const Key: WideString): WideString;
|
|
function GetValue(const Key: WideString): WideString;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: WideString): WideString;
|
|
function KeySet: IJclWideStrSet;
|
|
function MapEquals(const AMap: IJclWideStrWideStrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclWideStrWideStrMap);
|
|
procedure PutValue(const Key: WideString; const Value: WideString);
|
|
function Remove(const Key: WideString): WideString;
|
|
function Size: Integer;
|
|
function Values: IJclWideStrCollection;
|
|
{ IJclWideStrWideStrSortedMap }
|
|
function FirstKey: WideString;
|
|
function HeadMap(const ToKey: WideString): IJclWideStrWideStrSortedMap;
|
|
function LastKey: WideString;
|
|
function SubMap(const FromKey, ToKey: WideString): IJclWideStrWideStrSortedMap;
|
|
function TailMap(const FromKey: WideString): IJclWideStrWideStrSortedMap;
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_UNICODE_STRING}
|
|
TJclUnicodeStrIntfSortedEntry = record
|
|
Key: UnicodeString;
|
|
Value: IInterface;
|
|
end;
|
|
|
|
TJclUnicodeStrIntfSortedMap = class(TJclUnicodeStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclUnicodeStrContainer,
|
|
IJclUnicodeStrIntfMap, IJclUnicodeStrIntfSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: UnicodeString): UnicodeString;
|
|
function FreeValue(var Value: IInterface): IInterface;
|
|
function KeysCompare(const A, B: UnicodeString): Integer;
|
|
function ValuesCompare(const A, B: IInterface): Integer;
|
|
private
|
|
FEntries: array of TJclUnicodeStrIntfSortedEntry;
|
|
function BinarySearch(const Key: UnicodeString): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclUnicodeStrIntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: UnicodeString): Boolean;
|
|
function ContainsValue(const Value: IInterface): Boolean;
|
|
function Extract(const Key: UnicodeString): IInterface;
|
|
function GetValue(const Key: UnicodeString): IInterface;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: IInterface): UnicodeString;
|
|
function KeySet: IJclUnicodeStrSet;
|
|
function MapEquals(const AMap: IJclUnicodeStrIntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclUnicodeStrIntfMap);
|
|
procedure PutValue(const Key: UnicodeString; const Value: IInterface);
|
|
function Remove(const Key: UnicodeString): IInterface;
|
|
function Size: Integer;
|
|
function Values: IJclIntfCollection;
|
|
{ IJclUnicodeStrIntfSortedMap }
|
|
function FirstKey: UnicodeString;
|
|
function HeadMap(const ToKey: UnicodeString): IJclUnicodeStrIntfSortedMap;
|
|
function LastKey: UnicodeString;
|
|
function SubMap(const FromKey, ToKey: UnicodeString): IJclUnicodeStrIntfSortedMap;
|
|
function TailMap(const FromKey: UnicodeString): IJclUnicodeStrIntfSortedMap;
|
|
end;
|
|
|
|
TJclIntfUnicodeStrSortedEntry = record
|
|
Key: IInterface;
|
|
Value: UnicodeString;
|
|
end;
|
|
|
|
TJclIntfUnicodeStrSortedMap = class(TJclUnicodeStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclUnicodeStrContainer,
|
|
IJclIntfUnicodeStrMap, IJclIntfUnicodeStrSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function FreeValue(var Value: UnicodeString): UnicodeString;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(const A, B: UnicodeString): Integer;
|
|
private
|
|
FEntries: array of TJclIntfUnicodeStrSortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfUnicodeStrMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(const Value: UnicodeString): Boolean;
|
|
function Extract(const Key: IInterface): UnicodeString;
|
|
function GetValue(const Key: IInterface): UnicodeString;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: UnicodeString): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfUnicodeStrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfUnicodeStrMap);
|
|
procedure PutValue(const Key: IInterface; const Value: UnicodeString);
|
|
function Remove(const Key: IInterface): UnicodeString;
|
|
function Size: Integer;
|
|
function Values: IJclUnicodeStrCollection;
|
|
{ IJclIntfUnicodeStrSortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfUnicodeStrSortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfUnicodeStrSortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfUnicodeStrSortedMap;
|
|
end;
|
|
|
|
TJclUnicodeStrUnicodeStrSortedEntry = record
|
|
Key: UnicodeString;
|
|
Value: UnicodeString;
|
|
end;
|
|
|
|
TJclUnicodeStrUnicodeStrSortedMap = class(TJclUnicodeStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclUnicodeStrContainer,
|
|
IJclUnicodeStrUnicodeStrMap, IJclUnicodeStrUnicodeStrSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: UnicodeString): UnicodeString;
|
|
function FreeValue(var Value: UnicodeString): UnicodeString;
|
|
function KeysCompare(const A, B: UnicodeString): Integer;
|
|
function ValuesCompare(const A, B: UnicodeString): Integer;
|
|
private
|
|
FEntries: array of TJclUnicodeStrUnicodeStrSortedEntry;
|
|
function BinarySearch(const Key: UnicodeString): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclUnicodeStrUnicodeStrMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: UnicodeString): Boolean;
|
|
function ContainsValue(const Value: UnicodeString): Boolean;
|
|
function Extract(const Key: UnicodeString): UnicodeString;
|
|
function GetValue(const Key: UnicodeString): UnicodeString;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: UnicodeString): UnicodeString;
|
|
function KeySet: IJclUnicodeStrSet;
|
|
function MapEquals(const AMap: IJclUnicodeStrUnicodeStrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclUnicodeStrUnicodeStrMap);
|
|
procedure PutValue(const Key: UnicodeString; const Value: UnicodeString);
|
|
function Remove(const Key: UnicodeString): UnicodeString;
|
|
function Size: Integer;
|
|
function Values: IJclUnicodeStrCollection;
|
|
{ IJclUnicodeStrUnicodeStrSortedMap }
|
|
function FirstKey: UnicodeString;
|
|
function HeadMap(const ToKey: UnicodeString): IJclUnicodeStrUnicodeStrSortedMap;
|
|
function LastKey: UnicodeString;
|
|
function SubMap(const FromKey, ToKey: UnicodeString): IJclUnicodeStrUnicodeStrSortedMap;
|
|
function TailMap(const FromKey: UnicodeString): IJclUnicodeStrUnicodeStrSortedMap;
|
|
end;
|
|
{$ENDIF SUPPORTS_UNICODE_STRING}
|
|
|
|
{$IFDEF CONTAINER_ANSISTR}
|
|
TJclStrIntfSortedMap = TJclAnsiStrIntfSortedMap;
|
|
TJclIntfStrSortedMap = TJclIntfAnsiStrSortedMap;
|
|
TJclStrStrSortedMap = TJclAnsiStrAnsiStrSortedMap;
|
|
{$ENDIF CONTAINER_ANSISTR}
|
|
{$IFDEF CONTAINER_WIDESTR}
|
|
TJclStrIntfSortedMap = TJclWideStrIntfSortedMap;
|
|
TJclIntfStrSortedMap = TJclIntfWideStrSortedMap;
|
|
TJclStrStrSortedMap = TJclWideStrWideStrSortedMap;
|
|
{$ENDIF CONTAINER_WIDESTR}
|
|
{$IFDEF CONTAINER_UNICODESTR}
|
|
TJclStrIntfSortedMap = TJclUnicodeStrIntfSortedMap;
|
|
TJclIntfStrSortedMap = TJclIntfUnicodeStrSortedMap;
|
|
TJclStrStrSortedMap = TJclUnicodeStrUnicodeStrSortedMap;
|
|
{$ENDIF CONTAINER_UNICODESTR}
|
|
|
|
TJclSingleIntfSortedEntry = record
|
|
Key: Single;
|
|
Value: IInterface;
|
|
end;
|
|
|
|
TJclSingleIntfSortedMap = class(TJclSingleAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclSingleContainer,
|
|
IJclSingleIntfMap, IJclSingleIntfSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Single): Single;
|
|
function FreeValue(var Value: IInterface): IInterface;
|
|
function KeysCompare(const A, B: Single): Integer;
|
|
function ValuesCompare(const A, B: IInterface): Integer;
|
|
private
|
|
FEntries: array of TJclSingleIntfSortedEntry;
|
|
function BinarySearch(const Key: Single): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclSingleIntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Single): Boolean;
|
|
function ContainsValue(const Value: IInterface): Boolean;
|
|
function Extract(const Key: Single): IInterface;
|
|
function GetValue(const Key: Single): IInterface;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: IInterface): Single;
|
|
function KeySet: IJclSingleSet;
|
|
function MapEquals(const AMap: IJclSingleIntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclSingleIntfMap);
|
|
procedure PutValue(const Key: Single; const Value: IInterface);
|
|
function Remove(const Key: Single): IInterface;
|
|
function Size: Integer;
|
|
function Values: IJclIntfCollection;
|
|
{ IJclSingleIntfSortedMap }
|
|
function FirstKey: Single;
|
|
function HeadMap(const ToKey: Single): IJclSingleIntfSortedMap;
|
|
function LastKey: Single;
|
|
function SubMap(const FromKey, ToKey: Single): IJclSingleIntfSortedMap;
|
|
function TailMap(const FromKey: Single): IJclSingleIntfSortedMap;
|
|
end;
|
|
|
|
TJclIntfSingleSortedEntry = record
|
|
Key: IInterface;
|
|
Value: Single;
|
|
end;
|
|
|
|
TJclIntfSingleSortedMap = class(TJclSingleAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclSingleContainer,
|
|
IJclIntfSingleMap, IJclIntfSingleSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function FreeValue(var Value: Single): Single;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(const A, B: Single): Integer;
|
|
private
|
|
FEntries: array of TJclIntfSingleSortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfSingleMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(const Value: Single): Boolean;
|
|
function Extract(const Key: IInterface): Single;
|
|
function GetValue(const Key: IInterface): Single;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: Single): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfSingleMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfSingleMap);
|
|
procedure PutValue(const Key: IInterface; const Value: Single);
|
|
function Remove(const Key: IInterface): Single;
|
|
function Size: Integer;
|
|
function Values: IJclSingleCollection;
|
|
{ IJclIntfSingleSortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfSingleSortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfSingleSortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfSingleSortedMap;
|
|
end;
|
|
|
|
TJclSingleSingleSortedEntry = record
|
|
Key: Single;
|
|
Value: Single;
|
|
end;
|
|
|
|
TJclSingleSingleSortedMap = class(TJclSingleAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclSingleContainer,
|
|
IJclSingleSingleMap, IJclSingleSingleSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Single): Single;
|
|
function FreeValue(var Value: Single): Single;
|
|
function KeysCompare(const A, B: Single): Integer;
|
|
function ValuesCompare(const A, B: Single): Integer;
|
|
private
|
|
FEntries: array of TJclSingleSingleSortedEntry;
|
|
function BinarySearch(const Key: Single): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclSingleSingleMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Single): Boolean;
|
|
function ContainsValue(const Value: Single): Boolean;
|
|
function Extract(const Key: Single): Single;
|
|
function GetValue(const Key: Single): Single;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: Single): Single;
|
|
function KeySet: IJclSingleSet;
|
|
function MapEquals(const AMap: IJclSingleSingleMap): Boolean;
|
|
procedure PutAll(const AMap: IJclSingleSingleMap);
|
|
procedure PutValue(const Key: Single; const Value: Single);
|
|
function Remove(const Key: Single): Single;
|
|
function Size: Integer;
|
|
function Values: IJclSingleCollection;
|
|
{ IJclSingleSingleSortedMap }
|
|
function FirstKey: Single;
|
|
function HeadMap(const ToKey: Single): IJclSingleSingleSortedMap;
|
|
function LastKey: Single;
|
|
function SubMap(const FromKey, ToKey: Single): IJclSingleSingleSortedMap;
|
|
function TailMap(const FromKey: Single): IJclSingleSingleSortedMap;
|
|
end;
|
|
|
|
TJclDoubleIntfSortedEntry = record
|
|
Key: Double;
|
|
Value: IInterface;
|
|
end;
|
|
|
|
TJclDoubleIntfSortedMap = class(TJclDoubleAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclDoubleContainer,
|
|
IJclDoubleIntfMap, IJclDoubleIntfSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Double): Double;
|
|
function FreeValue(var Value: IInterface): IInterface;
|
|
function KeysCompare(const A, B: Double): Integer;
|
|
function ValuesCompare(const A, B: IInterface): Integer;
|
|
private
|
|
FEntries: array of TJclDoubleIntfSortedEntry;
|
|
function BinarySearch(const Key: Double): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclDoubleIntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Double): Boolean;
|
|
function ContainsValue(const Value: IInterface): Boolean;
|
|
function Extract(const Key: Double): IInterface;
|
|
function GetValue(const Key: Double): IInterface;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: IInterface): Double;
|
|
function KeySet: IJclDoubleSet;
|
|
function MapEquals(const AMap: IJclDoubleIntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclDoubleIntfMap);
|
|
procedure PutValue(const Key: Double; const Value: IInterface);
|
|
function Remove(const Key: Double): IInterface;
|
|
function Size: Integer;
|
|
function Values: IJclIntfCollection;
|
|
{ IJclDoubleIntfSortedMap }
|
|
function FirstKey: Double;
|
|
function HeadMap(const ToKey: Double): IJclDoubleIntfSortedMap;
|
|
function LastKey: Double;
|
|
function SubMap(const FromKey, ToKey: Double): IJclDoubleIntfSortedMap;
|
|
function TailMap(const FromKey: Double): IJclDoubleIntfSortedMap;
|
|
end;
|
|
|
|
TJclIntfDoubleSortedEntry = record
|
|
Key: IInterface;
|
|
Value: Double;
|
|
end;
|
|
|
|
TJclIntfDoubleSortedMap = class(TJclDoubleAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclDoubleContainer,
|
|
IJclIntfDoubleMap, IJclIntfDoubleSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function FreeValue(var Value: Double): Double;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(const A, B: Double): Integer;
|
|
private
|
|
FEntries: array of TJclIntfDoubleSortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfDoubleMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(const Value: Double): Boolean;
|
|
function Extract(const Key: IInterface): Double;
|
|
function GetValue(const Key: IInterface): Double;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: Double): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfDoubleMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfDoubleMap);
|
|
procedure PutValue(const Key: IInterface; const Value: Double);
|
|
function Remove(const Key: IInterface): Double;
|
|
function Size: Integer;
|
|
function Values: IJclDoubleCollection;
|
|
{ IJclIntfDoubleSortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfDoubleSortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfDoubleSortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfDoubleSortedMap;
|
|
end;
|
|
|
|
TJclDoubleDoubleSortedEntry = record
|
|
Key: Double;
|
|
Value: Double;
|
|
end;
|
|
|
|
TJclDoubleDoubleSortedMap = class(TJclDoubleAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclDoubleContainer,
|
|
IJclDoubleDoubleMap, IJclDoubleDoubleSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Double): Double;
|
|
function FreeValue(var Value: Double): Double;
|
|
function KeysCompare(const A, B: Double): Integer;
|
|
function ValuesCompare(const A, B: Double): Integer;
|
|
private
|
|
FEntries: array of TJclDoubleDoubleSortedEntry;
|
|
function BinarySearch(const Key: Double): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclDoubleDoubleMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Double): Boolean;
|
|
function ContainsValue(const Value: Double): Boolean;
|
|
function Extract(const Key: Double): Double;
|
|
function GetValue(const Key: Double): Double;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: Double): Double;
|
|
function KeySet: IJclDoubleSet;
|
|
function MapEquals(const AMap: IJclDoubleDoubleMap): Boolean;
|
|
procedure PutAll(const AMap: IJclDoubleDoubleMap);
|
|
procedure PutValue(const Key: Double; const Value: Double);
|
|
function Remove(const Key: Double): Double;
|
|
function Size: Integer;
|
|
function Values: IJclDoubleCollection;
|
|
{ IJclDoubleDoubleSortedMap }
|
|
function FirstKey: Double;
|
|
function HeadMap(const ToKey: Double): IJclDoubleDoubleSortedMap;
|
|
function LastKey: Double;
|
|
function SubMap(const FromKey, ToKey: Double): IJclDoubleDoubleSortedMap;
|
|
function TailMap(const FromKey: Double): IJclDoubleDoubleSortedMap;
|
|
end;
|
|
|
|
TJclExtendedIntfSortedEntry = record
|
|
Key: Extended;
|
|
Value: IInterface;
|
|
end;
|
|
|
|
TJclExtendedIntfSortedMap = class(TJclExtendedAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclExtendedContainer,
|
|
IJclExtendedIntfMap, IJclExtendedIntfSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Extended): Extended;
|
|
function FreeValue(var Value: IInterface): IInterface;
|
|
function KeysCompare(const A, B: Extended): Integer;
|
|
function ValuesCompare(const A, B: IInterface): Integer;
|
|
private
|
|
FEntries: array of TJclExtendedIntfSortedEntry;
|
|
function BinarySearch(const Key: Extended): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclExtendedIntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Extended): Boolean;
|
|
function ContainsValue(const Value: IInterface): Boolean;
|
|
function Extract(const Key: Extended): IInterface;
|
|
function GetValue(const Key: Extended): IInterface;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: IInterface): Extended;
|
|
function KeySet: IJclExtendedSet;
|
|
function MapEquals(const AMap: IJclExtendedIntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclExtendedIntfMap);
|
|
procedure PutValue(const Key: Extended; const Value: IInterface);
|
|
function Remove(const Key: Extended): IInterface;
|
|
function Size: Integer;
|
|
function Values: IJclIntfCollection;
|
|
{ IJclExtendedIntfSortedMap }
|
|
function FirstKey: Extended;
|
|
function HeadMap(const ToKey: Extended): IJclExtendedIntfSortedMap;
|
|
function LastKey: Extended;
|
|
function SubMap(const FromKey, ToKey: Extended): IJclExtendedIntfSortedMap;
|
|
function TailMap(const FromKey: Extended): IJclExtendedIntfSortedMap;
|
|
end;
|
|
|
|
TJclIntfExtendedSortedEntry = record
|
|
Key: IInterface;
|
|
Value: Extended;
|
|
end;
|
|
|
|
TJclIntfExtendedSortedMap = class(TJclExtendedAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclExtendedContainer,
|
|
IJclIntfExtendedMap, IJclIntfExtendedSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function FreeValue(var Value: Extended): Extended;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(const A, B: Extended): Integer;
|
|
private
|
|
FEntries: array of TJclIntfExtendedSortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfExtendedMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(const Value: Extended): Boolean;
|
|
function Extract(const Key: IInterface): Extended;
|
|
function GetValue(const Key: IInterface): Extended;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: Extended): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfExtendedMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfExtendedMap);
|
|
procedure PutValue(const Key: IInterface; const Value: Extended);
|
|
function Remove(const Key: IInterface): Extended;
|
|
function Size: Integer;
|
|
function Values: IJclExtendedCollection;
|
|
{ IJclIntfExtendedSortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfExtendedSortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfExtendedSortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfExtendedSortedMap;
|
|
end;
|
|
|
|
TJclExtendedExtendedSortedEntry = record
|
|
Key: Extended;
|
|
Value: Extended;
|
|
end;
|
|
|
|
TJclExtendedExtendedSortedMap = class(TJclExtendedAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclExtendedContainer,
|
|
IJclExtendedExtendedMap, IJclExtendedExtendedSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Extended): Extended;
|
|
function FreeValue(var Value: Extended): Extended;
|
|
function KeysCompare(const A, B: Extended): Integer;
|
|
function ValuesCompare(const A, B: Extended): Integer;
|
|
private
|
|
FEntries: array of TJclExtendedExtendedSortedEntry;
|
|
function BinarySearch(const Key: Extended): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclExtendedExtendedMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Extended): Boolean;
|
|
function ContainsValue(const Value: Extended): Boolean;
|
|
function Extract(const Key: Extended): Extended;
|
|
function GetValue(const Key: Extended): Extended;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: Extended): Extended;
|
|
function KeySet: IJclExtendedSet;
|
|
function MapEquals(const AMap: IJclExtendedExtendedMap): Boolean;
|
|
procedure PutAll(const AMap: IJclExtendedExtendedMap);
|
|
procedure PutValue(const Key: Extended; const Value: Extended);
|
|
function Remove(const Key: Extended): Extended;
|
|
function Size: Integer;
|
|
function Values: IJclExtendedCollection;
|
|
{ IJclExtendedExtendedSortedMap }
|
|
function FirstKey: Extended;
|
|
function HeadMap(const ToKey: Extended): IJclExtendedExtendedSortedMap;
|
|
function LastKey: Extended;
|
|
function SubMap(const FromKey, ToKey: Extended): IJclExtendedExtendedSortedMap;
|
|
function TailMap(const FromKey: Extended): IJclExtendedExtendedSortedMap;
|
|
end;
|
|
|
|
{$IFDEF MATH_EXTENDED_PRECISION}
|
|
TJclFloatIntfSortedMap = TJclExtendedIntfSortedMap;
|
|
TJclIntfFloatSortedMap = TJclIntfExtendedSortedMap;
|
|
TJclFloatFloatSortedMap = TJclExtendedExtendedSortedMap;
|
|
{$ENDIF MATH_EXTENDED_PRECISION}
|
|
{$IFDEF MATH_DOUBLE_PRECISION}
|
|
TJclFloatIntfSortedMap = TJclDoubleIntfSortedMap;
|
|
TJclIntfFloatSortedMap = TJclIntfDoubleSortedMap;
|
|
TJclFloatFloatSortedMap = TJclDoubleDoubleSortedMap;
|
|
{$ENDIF MATH_DOUBLE_PRECISION}
|
|
{$IFDEF MATH_SINGLE_PRECISION}
|
|
TJclFloatIntfSortedMap = TJclSingleIntfSortedMap;
|
|
TJclIntfFloatSortedMap = TJclIntfSingleSortedMap;
|
|
TJclFloatFloatSortedMap = TJclSingleSingleSortedMap;
|
|
{$ENDIF MATH_SINGLE_PRECISION}
|
|
|
|
TJclIntegerIntfSortedEntry = record
|
|
Key: Integer;
|
|
Value: IInterface;
|
|
end;
|
|
|
|
TJclIntegerIntfSortedMap = class(TJclIntegerAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclIntegerIntfMap, IJclIntegerIntfSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Integer): Integer;
|
|
function FreeValue(var Value: IInterface): IInterface;
|
|
function KeysCompare(A, B: Integer): Integer;
|
|
function ValuesCompare(const A, B: IInterface): Integer;
|
|
private
|
|
FEntries: array of TJclIntegerIntfSortedEntry;
|
|
function BinarySearch(Key: Integer): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntegerIntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(Key: Integer): Boolean;
|
|
function ContainsValue(const Value: IInterface): Boolean;
|
|
function Extract(Key: Integer): IInterface;
|
|
function GetValue(Key: Integer): IInterface;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: IInterface): Integer;
|
|
function KeySet: IJclIntegerSet;
|
|
function MapEquals(const AMap: IJclIntegerIntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntegerIntfMap);
|
|
procedure PutValue(Key: Integer; const Value: IInterface);
|
|
function Remove(Key: Integer): IInterface;
|
|
function Size: Integer;
|
|
function Values: IJclIntfCollection;
|
|
{ IJclIntegerIntfSortedMap }
|
|
function FirstKey: Integer;
|
|
function HeadMap(ToKey: Integer): IJclIntegerIntfSortedMap;
|
|
function LastKey: Integer;
|
|
function SubMap(FromKey, ToKey: Integer): IJclIntegerIntfSortedMap;
|
|
function TailMap(FromKey: Integer): IJclIntegerIntfSortedMap;
|
|
end;
|
|
|
|
TJclIntfIntegerSortedEntry = record
|
|
Key: IInterface;
|
|
Value: Integer;
|
|
end;
|
|
|
|
TJclIntfIntegerSortedMap = class(TJclIntegerAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclIntfIntegerMap, IJclIntfIntegerSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function FreeValue(var Value: Integer): Integer;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(A, B: Integer): Integer;
|
|
private
|
|
FEntries: array of TJclIntfIntegerSortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfIntegerMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(Value: Integer): Boolean;
|
|
function Extract(const Key: IInterface): Integer;
|
|
function GetValue(const Key: IInterface): Integer;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: Integer): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfIntegerMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfIntegerMap);
|
|
procedure PutValue(const Key: IInterface; Value: Integer);
|
|
function Remove(const Key: IInterface): Integer;
|
|
function Size: Integer;
|
|
function Values: IJclIntegerCollection;
|
|
{ IJclIntfIntegerSortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfIntegerSortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfIntegerSortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfIntegerSortedMap;
|
|
end;
|
|
|
|
TJclIntegerIntegerSortedEntry = record
|
|
Key: Integer;
|
|
Value: Integer;
|
|
end;
|
|
|
|
TJclIntegerIntegerSortedMap = class(TJclIntegerAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclIntegerIntegerMap, IJclIntegerIntegerSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Integer): Integer;
|
|
function FreeValue(var Value: Integer): Integer;
|
|
function KeysCompare(A, B: Integer): Integer;
|
|
function ValuesCompare(A, B: Integer): Integer;
|
|
private
|
|
FEntries: array of TJclIntegerIntegerSortedEntry;
|
|
function BinarySearch(Key: Integer): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntegerIntegerMap }
|
|
procedure Clear;
|
|
function ContainsKey(Key: Integer): Boolean;
|
|
function ContainsValue(Value: Integer): Boolean;
|
|
function Extract(Key: Integer): Integer;
|
|
function GetValue(Key: Integer): Integer;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: Integer): Integer;
|
|
function KeySet: IJclIntegerSet;
|
|
function MapEquals(const AMap: IJclIntegerIntegerMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntegerIntegerMap);
|
|
procedure PutValue(Key: Integer; Value: Integer);
|
|
function Remove(Key: Integer): Integer;
|
|
function Size: Integer;
|
|
function Values: IJclIntegerCollection;
|
|
{ IJclIntegerIntegerSortedMap }
|
|
function FirstKey: Integer;
|
|
function HeadMap(ToKey: Integer): IJclIntegerIntegerSortedMap;
|
|
function LastKey: Integer;
|
|
function SubMap(FromKey, ToKey: Integer): IJclIntegerIntegerSortedMap;
|
|
function TailMap(FromKey: Integer): IJclIntegerIntegerSortedMap;
|
|
end;
|
|
|
|
TJclCardinalIntfSortedEntry = record
|
|
Key: Cardinal;
|
|
Value: IInterface;
|
|
end;
|
|
|
|
TJclCardinalIntfSortedMap = class(TJclCardinalAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclCardinalIntfMap, IJclCardinalIntfSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Cardinal): Cardinal;
|
|
function FreeValue(var Value: IInterface): IInterface;
|
|
function KeysCompare(A, B: Cardinal): Integer;
|
|
function ValuesCompare(const A, B: IInterface): Integer;
|
|
private
|
|
FEntries: array of TJclCardinalIntfSortedEntry;
|
|
function BinarySearch(Key: Cardinal): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclCardinalIntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(Key: Cardinal): Boolean;
|
|
function ContainsValue(const Value: IInterface): Boolean;
|
|
function Extract(Key: Cardinal): IInterface;
|
|
function GetValue(Key: Cardinal): IInterface;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: IInterface): Cardinal;
|
|
function KeySet: IJclCardinalSet;
|
|
function MapEquals(const AMap: IJclCardinalIntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclCardinalIntfMap);
|
|
procedure PutValue(Key: Cardinal; const Value: IInterface);
|
|
function Remove(Key: Cardinal): IInterface;
|
|
function Size: Integer;
|
|
function Values: IJclIntfCollection;
|
|
{ IJclCardinalIntfSortedMap }
|
|
function FirstKey: Cardinal;
|
|
function HeadMap(ToKey: Cardinal): IJclCardinalIntfSortedMap;
|
|
function LastKey: Cardinal;
|
|
function SubMap(FromKey, ToKey: Cardinal): IJclCardinalIntfSortedMap;
|
|
function TailMap(FromKey: Cardinal): IJclCardinalIntfSortedMap;
|
|
end;
|
|
|
|
TJclIntfCardinalSortedEntry = record
|
|
Key: IInterface;
|
|
Value: Cardinal;
|
|
end;
|
|
|
|
TJclIntfCardinalSortedMap = class(TJclCardinalAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclIntfCardinalMap, IJclIntfCardinalSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function FreeValue(var Value: Cardinal): Cardinal;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(A, B: Cardinal): Integer;
|
|
private
|
|
FEntries: array of TJclIntfCardinalSortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfCardinalMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(Value: Cardinal): Boolean;
|
|
function Extract(const Key: IInterface): Cardinal;
|
|
function GetValue(const Key: IInterface): Cardinal;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: Cardinal): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfCardinalMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfCardinalMap);
|
|
procedure PutValue(const Key: IInterface; Value: Cardinal);
|
|
function Remove(const Key: IInterface): Cardinal;
|
|
function Size: Integer;
|
|
function Values: IJclCardinalCollection;
|
|
{ IJclIntfCardinalSortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfCardinalSortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfCardinalSortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfCardinalSortedMap;
|
|
end;
|
|
|
|
TJclCardinalCardinalSortedEntry = record
|
|
Key: Cardinal;
|
|
Value: Cardinal;
|
|
end;
|
|
|
|
TJclCardinalCardinalSortedMap = class(TJclCardinalAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclCardinalCardinalMap, IJclCardinalCardinalSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Cardinal): Cardinal;
|
|
function FreeValue(var Value: Cardinal): Cardinal;
|
|
function KeysCompare(A, B: Cardinal): Integer;
|
|
function ValuesCompare(A, B: Cardinal): Integer;
|
|
private
|
|
FEntries: array of TJclCardinalCardinalSortedEntry;
|
|
function BinarySearch(Key: Cardinal): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclCardinalCardinalMap }
|
|
procedure Clear;
|
|
function ContainsKey(Key: Cardinal): Boolean;
|
|
function ContainsValue(Value: Cardinal): Boolean;
|
|
function Extract(Key: Cardinal): Cardinal;
|
|
function GetValue(Key: Cardinal): Cardinal;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: Cardinal): Cardinal;
|
|
function KeySet: IJclCardinalSet;
|
|
function MapEquals(const AMap: IJclCardinalCardinalMap): Boolean;
|
|
procedure PutAll(const AMap: IJclCardinalCardinalMap);
|
|
procedure PutValue(Key: Cardinal; Value: Cardinal);
|
|
function Remove(Key: Cardinal): Cardinal;
|
|
function Size: Integer;
|
|
function Values: IJclCardinalCollection;
|
|
{ IJclCardinalCardinalSortedMap }
|
|
function FirstKey: Cardinal;
|
|
function HeadMap(ToKey: Cardinal): IJclCardinalCardinalSortedMap;
|
|
function LastKey: Cardinal;
|
|
function SubMap(FromKey, ToKey: Cardinal): IJclCardinalCardinalSortedMap;
|
|
function TailMap(FromKey: Cardinal): IJclCardinalCardinalSortedMap;
|
|
end;
|
|
|
|
TJclInt64IntfSortedEntry = record
|
|
Key: Int64;
|
|
Value: IInterface;
|
|
end;
|
|
|
|
TJclInt64IntfSortedMap = class(TJclInt64AbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclInt64IntfMap, IJclInt64IntfSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Int64): Int64;
|
|
function FreeValue(var Value: IInterface): IInterface;
|
|
function KeysCompare(const A, B: Int64): Integer;
|
|
function ValuesCompare(const A, B: IInterface): Integer;
|
|
private
|
|
FEntries: array of TJclInt64IntfSortedEntry;
|
|
function BinarySearch(const Key: Int64): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclInt64IntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Int64): Boolean;
|
|
function ContainsValue(const Value: IInterface): Boolean;
|
|
function Extract(const Key: Int64): IInterface;
|
|
function GetValue(const Key: Int64): IInterface;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: IInterface): Int64;
|
|
function KeySet: IJclInt64Set;
|
|
function MapEquals(const AMap: IJclInt64IntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclInt64IntfMap);
|
|
procedure PutValue(const Key: Int64; const Value: IInterface);
|
|
function Remove(const Key: Int64): IInterface;
|
|
function Size: Integer;
|
|
function Values: IJclIntfCollection;
|
|
{ IJclInt64IntfSortedMap }
|
|
function FirstKey: Int64;
|
|
function HeadMap(const ToKey: Int64): IJclInt64IntfSortedMap;
|
|
function LastKey: Int64;
|
|
function SubMap(const FromKey, ToKey: Int64): IJclInt64IntfSortedMap;
|
|
function TailMap(const FromKey: Int64): IJclInt64IntfSortedMap;
|
|
end;
|
|
|
|
TJclIntfInt64SortedEntry = record
|
|
Key: IInterface;
|
|
Value: Int64;
|
|
end;
|
|
|
|
TJclIntfInt64SortedMap = class(TJclInt64AbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclIntfInt64Map, IJclIntfInt64SortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function FreeValue(var Value: Int64): Int64;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(const A, B: Int64): Integer;
|
|
private
|
|
FEntries: array of TJclIntfInt64SortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfInt64Map }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(const Value: Int64): Boolean;
|
|
function Extract(const Key: IInterface): Int64;
|
|
function GetValue(const Key: IInterface): Int64;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: Int64): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfInt64Map): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfInt64Map);
|
|
procedure PutValue(const Key: IInterface; const Value: Int64);
|
|
function Remove(const Key: IInterface): Int64;
|
|
function Size: Integer;
|
|
function Values: IJclInt64Collection;
|
|
{ IJclIntfInt64SortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfInt64SortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfInt64SortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfInt64SortedMap;
|
|
end;
|
|
|
|
TJclInt64Int64SortedEntry = record
|
|
Key: Int64;
|
|
Value: Int64;
|
|
end;
|
|
|
|
TJclInt64Int64SortedMap = class(TJclInt64AbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclInt64Int64Map, IJclInt64Int64SortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Int64): Int64;
|
|
function FreeValue(var Value: Int64): Int64;
|
|
function KeysCompare(const A, B: Int64): Integer;
|
|
function ValuesCompare(const A, B: Int64): Integer;
|
|
private
|
|
FEntries: array of TJclInt64Int64SortedEntry;
|
|
function BinarySearch(const Key: Int64): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclInt64Int64Map }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Int64): Boolean;
|
|
function ContainsValue(const Value: Int64): Boolean;
|
|
function Extract(const Key: Int64): Int64;
|
|
function GetValue(const Key: Int64): Int64;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: Int64): Int64;
|
|
function KeySet: IJclInt64Set;
|
|
function MapEquals(const AMap: IJclInt64Int64Map): Boolean;
|
|
procedure PutAll(const AMap: IJclInt64Int64Map);
|
|
procedure PutValue(const Key: Int64; const Value: Int64);
|
|
function Remove(const Key: Int64): Int64;
|
|
function Size: Integer;
|
|
function Values: IJclInt64Collection;
|
|
{ IJclInt64Int64SortedMap }
|
|
function FirstKey: Int64;
|
|
function HeadMap(const ToKey: Int64): IJclInt64Int64SortedMap;
|
|
function LastKey: Int64;
|
|
function SubMap(const FromKey, ToKey: Int64): IJclInt64Int64SortedMap;
|
|
function TailMap(const FromKey: Int64): IJclInt64Int64SortedMap;
|
|
end;
|
|
|
|
TJclPtrIntfSortedEntry = record
|
|
Key: Pointer;
|
|
Value: IInterface;
|
|
end;
|
|
|
|
TJclPtrIntfSortedMap = class(TJclPtrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclPtrIntfMap, IJclPtrIntfSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Pointer): Pointer;
|
|
function FreeValue(var Value: IInterface): IInterface;
|
|
function KeysCompare(A, B: Pointer): Integer;
|
|
function ValuesCompare(const A, B: IInterface): Integer;
|
|
private
|
|
FEntries: array of TJclPtrIntfSortedEntry;
|
|
function BinarySearch(Key: Pointer): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclPtrIntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(Key: Pointer): Boolean;
|
|
function ContainsValue(const Value: IInterface): Boolean;
|
|
function Extract(Key: Pointer): IInterface;
|
|
function GetValue(Key: Pointer): IInterface;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: IInterface): Pointer;
|
|
function KeySet: IJclPtrSet;
|
|
function MapEquals(const AMap: IJclPtrIntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclPtrIntfMap);
|
|
procedure PutValue(Key: Pointer; const Value: IInterface);
|
|
function Remove(Key: Pointer): IInterface;
|
|
function Size: Integer;
|
|
function Values: IJclIntfCollection;
|
|
{ IJclPtrIntfSortedMap }
|
|
function FirstKey: Pointer;
|
|
function HeadMap(ToKey: Pointer): IJclPtrIntfSortedMap;
|
|
function LastKey: Pointer;
|
|
function SubMap(FromKey, ToKey: Pointer): IJclPtrIntfSortedMap;
|
|
function TailMap(FromKey: Pointer): IJclPtrIntfSortedMap;
|
|
end;
|
|
|
|
TJclIntfPtrSortedEntry = record
|
|
Key: IInterface;
|
|
Value: Pointer;
|
|
end;
|
|
|
|
TJclIntfPtrSortedMap = class(TJclPtrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclIntfPtrMap, IJclIntfPtrSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function FreeValue(var Value: Pointer): Pointer;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(A, B: Pointer): Integer;
|
|
private
|
|
FEntries: array of TJclIntfPtrSortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfPtrMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(Value: Pointer): Boolean;
|
|
function Extract(const Key: IInterface): Pointer;
|
|
function GetValue(const Key: IInterface): Pointer;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: Pointer): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfPtrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfPtrMap);
|
|
procedure PutValue(const Key: IInterface; Value: Pointer);
|
|
function Remove(const Key: IInterface): Pointer;
|
|
function Size: Integer;
|
|
function Values: IJclPtrCollection;
|
|
{ IJclIntfPtrSortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfPtrSortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfPtrSortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfPtrSortedMap;
|
|
end;
|
|
|
|
TJclPtrPtrSortedEntry = record
|
|
Key: Pointer;
|
|
Value: Pointer;
|
|
end;
|
|
|
|
TJclPtrPtrSortedMap = class(TJclPtrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer,
|
|
IJclPtrPtrMap, IJclPtrPtrSortedMap)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Pointer): Pointer;
|
|
function FreeValue(var Value: Pointer): Pointer;
|
|
function KeysCompare(A, B: Pointer): Integer;
|
|
function ValuesCompare(A, B: Pointer): Integer;
|
|
private
|
|
FEntries: array of TJclPtrPtrSortedEntry;
|
|
function BinarySearch(Key: Pointer): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclPtrPtrMap }
|
|
procedure Clear;
|
|
function ContainsKey(Key: Pointer): Boolean;
|
|
function ContainsValue(Value: Pointer): Boolean;
|
|
function Extract(Key: Pointer): Pointer;
|
|
function GetValue(Key: Pointer): Pointer;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: Pointer): Pointer;
|
|
function KeySet: IJclPtrSet;
|
|
function MapEquals(const AMap: IJclPtrPtrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclPtrPtrMap);
|
|
procedure PutValue(Key: Pointer; Value: Pointer);
|
|
function Remove(Key: Pointer): Pointer;
|
|
function Size: Integer;
|
|
function Values: IJclPtrCollection;
|
|
{ IJclPtrPtrSortedMap }
|
|
function FirstKey: Pointer;
|
|
function HeadMap(ToKey: Pointer): IJclPtrPtrSortedMap;
|
|
function LastKey: Pointer;
|
|
function SubMap(FromKey, ToKey: Pointer): IJclPtrPtrSortedMap;
|
|
function TailMap(FromKey: Pointer): IJclPtrPtrSortedMap;
|
|
end;
|
|
|
|
TJclIntfSortedEntry = record
|
|
Key: IInterface;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclIntfSortedMap = class(TJclIntfAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclValueOwner,
|
|
IJclIntfMap, IJclIntfSortedMap)
|
|
private
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: IInterface): IInterface;
|
|
function KeysCompare(const A, B: IInterface): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclIntfSortedEntry;
|
|
function BinarySearch(const Key: IInterface): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: IInterface): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(const Key: IInterface): TObject;
|
|
function GetValue(const Key: IInterface): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): IInterface;
|
|
function KeySet: IJclIntfSet;
|
|
function MapEquals(const AMap: IJclIntfMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntfMap);
|
|
procedure PutValue(const Key: IInterface; Value: TObject);
|
|
function Remove(const Key: IInterface): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclIntfSortedMap }
|
|
function FirstKey: IInterface;
|
|
function HeadMap(const ToKey: IInterface): IJclIntfSortedMap;
|
|
function LastKey: IInterface;
|
|
function SubMap(const FromKey, ToKey: IInterface): IJclIntfSortedMap;
|
|
function TailMap(const FromKey: IInterface): IJclIntfSortedMap;
|
|
end;
|
|
|
|
TJclAnsiStrSortedEntry = record
|
|
Key: AnsiString;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclAnsiStrSortedMap = class(TJclAnsiStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclAnsiStrContainer, IJclValueOwner,
|
|
IJclAnsiStrMap, IJclAnsiStrSortedMap)
|
|
private
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: AnsiString): AnsiString;
|
|
function KeysCompare(const A, B: AnsiString): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclAnsiStrSortedEntry;
|
|
function BinarySearch(const Key: AnsiString): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclAnsiStrMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: AnsiString): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(const Key: AnsiString): TObject;
|
|
function GetValue(const Key: AnsiString): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): AnsiString;
|
|
function KeySet: IJclAnsiStrSet;
|
|
function MapEquals(const AMap: IJclAnsiStrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclAnsiStrMap);
|
|
procedure PutValue(const Key: AnsiString; Value: TObject);
|
|
function Remove(const Key: AnsiString): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclAnsiStrSortedMap }
|
|
function FirstKey: AnsiString;
|
|
function HeadMap(const ToKey: AnsiString): IJclAnsiStrSortedMap;
|
|
function LastKey: AnsiString;
|
|
function SubMap(const FromKey, ToKey: AnsiString): IJclAnsiStrSortedMap;
|
|
function TailMap(const FromKey: AnsiString): IJclAnsiStrSortedMap;
|
|
end;
|
|
|
|
TJclWideStrSortedEntry = record
|
|
Key: WideString;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclWideStrSortedMap = class(TJclWideStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclWideStrContainer, IJclValueOwner,
|
|
IJclWideStrMap, IJclWideStrSortedMap)
|
|
private
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: WideString): WideString;
|
|
function KeysCompare(const A, B: WideString): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclWideStrSortedEntry;
|
|
function BinarySearch(const Key: WideString): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclWideStrMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: WideString): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(const Key: WideString): TObject;
|
|
function GetValue(const Key: WideString): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): WideString;
|
|
function KeySet: IJclWideStrSet;
|
|
function MapEquals(const AMap: IJclWideStrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclWideStrMap);
|
|
procedure PutValue(const Key: WideString; Value: TObject);
|
|
function Remove(const Key: WideString): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclWideStrSortedMap }
|
|
function FirstKey: WideString;
|
|
function HeadMap(const ToKey: WideString): IJclWideStrSortedMap;
|
|
function LastKey: WideString;
|
|
function SubMap(const FromKey, ToKey: WideString): IJclWideStrSortedMap;
|
|
function TailMap(const FromKey: WideString): IJclWideStrSortedMap;
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_UNICODE_STRING}
|
|
TJclUnicodeStrSortedEntry = record
|
|
Key: UnicodeString;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclUnicodeStrSortedMap = class(TJclUnicodeStrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclStrContainer, IJclUnicodeStrContainer, IJclValueOwner,
|
|
IJclUnicodeStrMap, IJclUnicodeStrSortedMap)
|
|
private
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: UnicodeString): UnicodeString;
|
|
function KeysCompare(const A, B: UnicodeString): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclUnicodeStrSortedEntry;
|
|
function BinarySearch(const Key: UnicodeString): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclUnicodeStrMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: UnicodeString): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(const Key: UnicodeString): TObject;
|
|
function GetValue(const Key: UnicodeString): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): UnicodeString;
|
|
function KeySet: IJclUnicodeStrSet;
|
|
function MapEquals(const AMap: IJclUnicodeStrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclUnicodeStrMap);
|
|
procedure PutValue(const Key: UnicodeString; Value: TObject);
|
|
function Remove(const Key: UnicodeString): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclUnicodeStrSortedMap }
|
|
function FirstKey: UnicodeString;
|
|
function HeadMap(const ToKey: UnicodeString): IJclUnicodeStrSortedMap;
|
|
function LastKey: UnicodeString;
|
|
function SubMap(const FromKey, ToKey: UnicodeString): IJclUnicodeStrSortedMap;
|
|
function TailMap(const FromKey: UnicodeString): IJclUnicodeStrSortedMap;
|
|
end;
|
|
{$ENDIF SUPPORTS_UNICODE_STRING}
|
|
|
|
{$IFDEF CONTAINER_ANSISTR}
|
|
TJclStrSortedMap = TJclAnsiStrSortedMap;
|
|
{$ENDIF CONTAINER_ANSISTR}
|
|
{$IFDEF CONTAINER_WIDESTR}
|
|
TJclStrSortedMap = TJclWideStrSortedMap;
|
|
{$ENDIF CONTAINER_WIDESTR}
|
|
{$IFDEF CONTAINER_UNICODESTR}
|
|
TJclStrSortedMap = TJclUnicodeStrSortedMap;
|
|
{$ENDIF CONTAINER_UNICODESTR}
|
|
|
|
TJclSingleSortedEntry = record
|
|
Key: Single;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclSingleSortedMap = class(TJclSingleAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclSingleContainer, IJclValueOwner,
|
|
IJclSingleMap, IJclSingleSortedMap)
|
|
private
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Single): Single;
|
|
function KeysCompare(const A, B: Single): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclSingleSortedEntry;
|
|
function BinarySearch(const Key: Single): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclSingleMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Single): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(const Key: Single): TObject;
|
|
function GetValue(const Key: Single): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): Single;
|
|
function KeySet: IJclSingleSet;
|
|
function MapEquals(const AMap: IJclSingleMap): Boolean;
|
|
procedure PutAll(const AMap: IJclSingleMap);
|
|
procedure PutValue(const Key: Single; Value: TObject);
|
|
function Remove(const Key: Single): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclSingleSortedMap }
|
|
function FirstKey: Single;
|
|
function HeadMap(const ToKey: Single): IJclSingleSortedMap;
|
|
function LastKey: Single;
|
|
function SubMap(const FromKey, ToKey: Single): IJclSingleSortedMap;
|
|
function TailMap(const FromKey: Single): IJclSingleSortedMap;
|
|
end;
|
|
|
|
TJclDoubleSortedEntry = record
|
|
Key: Double;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclDoubleSortedMap = class(TJclDoubleAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclDoubleContainer, IJclValueOwner,
|
|
IJclDoubleMap, IJclDoubleSortedMap)
|
|
private
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Double): Double;
|
|
function KeysCompare(const A, B: Double): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclDoubleSortedEntry;
|
|
function BinarySearch(const Key: Double): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclDoubleMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Double): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(const Key: Double): TObject;
|
|
function GetValue(const Key: Double): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): Double;
|
|
function KeySet: IJclDoubleSet;
|
|
function MapEquals(const AMap: IJclDoubleMap): Boolean;
|
|
procedure PutAll(const AMap: IJclDoubleMap);
|
|
procedure PutValue(const Key: Double; Value: TObject);
|
|
function Remove(const Key: Double): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclDoubleSortedMap }
|
|
function FirstKey: Double;
|
|
function HeadMap(const ToKey: Double): IJclDoubleSortedMap;
|
|
function LastKey: Double;
|
|
function SubMap(const FromKey, ToKey: Double): IJclDoubleSortedMap;
|
|
function TailMap(const FromKey: Double): IJclDoubleSortedMap;
|
|
end;
|
|
|
|
TJclExtendedSortedEntry = record
|
|
Key: Extended;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclExtendedSortedMap = class(TJclExtendedAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclExtendedContainer, IJclValueOwner,
|
|
IJclExtendedMap, IJclExtendedSortedMap)
|
|
private
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Extended): Extended;
|
|
function KeysCompare(const A, B: Extended): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclExtendedSortedEntry;
|
|
function BinarySearch(const Key: Extended): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclExtendedMap }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Extended): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(const Key: Extended): TObject;
|
|
function GetValue(const Key: Extended): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): Extended;
|
|
function KeySet: IJclExtendedSet;
|
|
function MapEquals(const AMap: IJclExtendedMap): Boolean;
|
|
procedure PutAll(const AMap: IJclExtendedMap);
|
|
procedure PutValue(const Key: Extended; Value: TObject);
|
|
function Remove(const Key: Extended): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclExtendedSortedMap }
|
|
function FirstKey: Extended;
|
|
function HeadMap(const ToKey: Extended): IJclExtendedSortedMap;
|
|
function LastKey: Extended;
|
|
function SubMap(const FromKey, ToKey: Extended): IJclExtendedSortedMap;
|
|
function TailMap(const FromKey: Extended): IJclExtendedSortedMap;
|
|
end;
|
|
|
|
{$IFDEF MATH_EXTENDED_PRECISION}
|
|
TJclFloatSortedMap = TJclExtendedSortedMap;
|
|
{$ENDIF MATH_EXTENDED_PRECISION}
|
|
{$IFDEF MATH_DOUBLE_PRECISION}
|
|
TJclFloatSortedMap = TJclDoubleSortedMap;
|
|
{$ENDIF MATH_DOUBLE_PRECISION}
|
|
{$IFDEF MATH_SINGLE_PRECISION}
|
|
TJclFloatSortedMap = TJclSingleSortedMap;
|
|
{$ENDIF MATH_SINGLE_PRECISION}
|
|
|
|
TJclIntegerSortedEntry = record
|
|
Key: Integer;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclIntegerSortedMap = class(TJclIntegerAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclValueOwner,
|
|
IJclIntegerMap, IJclIntegerSortedMap)
|
|
private
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Integer): Integer;
|
|
function KeysCompare(A, B: Integer): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclIntegerSortedEntry;
|
|
function BinarySearch(Key: Integer): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntegerMap }
|
|
procedure Clear;
|
|
function ContainsKey(Key: Integer): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(Key: Integer): TObject;
|
|
function GetValue(Key: Integer): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): Integer;
|
|
function KeySet: IJclIntegerSet;
|
|
function MapEquals(const AMap: IJclIntegerMap): Boolean;
|
|
procedure PutAll(const AMap: IJclIntegerMap);
|
|
procedure PutValue(Key: Integer; Value: TObject);
|
|
function Remove(Key: Integer): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclIntegerSortedMap }
|
|
function FirstKey: Integer;
|
|
function HeadMap(ToKey: Integer): IJclIntegerSortedMap;
|
|
function LastKey: Integer;
|
|
function SubMap(FromKey, ToKey: Integer): IJclIntegerSortedMap;
|
|
function TailMap(FromKey: Integer): IJclIntegerSortedMap;
|
|
end;
|
|
|
|
TJclCardinalSortedEntry = record
|
|
Key: Cardinal;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclCardinalSortedMap = class(TJclCardinalAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclValueOwner,
|
|
IJclCardinalMap, IJclCardinalSortedMap)
|
|
private
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Cardinal): Cardinal;
|
|
function KeysCompare(A, B: Cardinal): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclCardinalSortedEntry;
|
|
function BinarySearch(Key: Cardinal): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclCardinalMap }
|
|
procedure Clear;
|
|
function ContainsKey(Key: Cardinal): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(Key: Cardinal): TObject;
|
|
function GetValue(Key: Cardinal): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): Cardinal;
|
|
function KeySet: IJclCardinalSet;
|
|
function MapEquals(const AMap: IJclCardinalMap): Boolean;
|
|
procedure PutAll(const AMap: IJclCardinalMap);
|
|
procedure PutValue(Key: Cardinal; Value: TObject);
|
|
function Remove(Key: Cardinal): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclCardinalSortedMap }
|
|
function FirstKey: Cardinal;
|
|
function HeadMap(ToKey: Cardinal): IJclCardinalSortedMap;
|
|
function LastKey: Cardinal;
|
|
function SubMap(FromKey, ToKey: Cardinal): IJclCardinalSortedMap;
|
|
function TailMap(FromKey: Cardinal): IJclCardinalSortedMap;
|
|
end;
|
|
|
|
TJclInt64SortedEntry = record
|
|
Key: Int64;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclInt64SortedMap = class(TJclInt64AbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclValueOwner,
|
|
IJclInt64Map, IJclInt64SortedMap)
|
|
private
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Int64): Int64;
|
|
function KeysCompare(const A, B: Int64): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclInt64SortedEntry;
|
|
function BinarySearch(const Key: Int64): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclInt64Map }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: Int64): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(const Key: Int64): TObject;
|
|
function GetValue(const Key: Int64): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): Int64;
|
|
function KeySet: IJclInt64Set;
|
|
function MapEquals(const AMap: IJclInt64Map): Boolean;
|
|
procedure PutAll(const AMap: IJclInt64Map);
|
|
procedure PutValue(const Key: Int64; Value: TObject);
|
|
function Remove(const Key: Int64): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclInt64SortedMap }
|
|
function FirstKey: Int64;
|
|
function HeadMap(const ToKey: Int64): IJclInt64SortedMap;
|
|
function LastKey: Int64;
|
|
function SubMap(const FromKey, ToKey: Int64): IJclInt64SortedMap;
|
|
function TailMap(const FromKey: Int64): IJclInt64SortedMap;
|
|
end;
|
|
|
|
TJclPtrSortedEntry = record
|
|
Key: Pointer;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclPtrSortedMap = class(TJclPtrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclValueOwner,
|
|
IJclPtrMap, IJclPtrSortedMap)
|
|
private
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function FreeKey(var Key: Pointer): Pointer;
|
|
function KeysCompare(A, B: Pointer): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclPtrSortedEntry;
|
|
function BinarySearch(Key: Pointer): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclPtrMap }
|
|
procedure Clear;
|
|
function ContainsKey(Key: Pointer): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(Key: Pointer): TObject;
|
|
function GetValue(Key: Pointer): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): Pointer;
|
|
function KeySet: IJclPtrSet;
|
|
function MapEquals(const AMap: IJclPtrMap): Boolean;
|
|
procedure PutAll(const AMap: IJclPtrMap);
|
|
procedure PutValue(Key: Pointer; Value: TObject);
|
|
function Remove(Key: Pointer): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclPtrSortedMap }
|
|
function FirstKey: Pointer;
|
|
function HeadMap(ToKey: Pointer): IJclPtrSortedMap;
|
|
function LastKey: Pointer;
|
|
function SubMap(FromKey, ToKey: Pointer): IJclPtrSortedMap;
|
|
function TailMap(FromKey: Pointer): IJclPtrSortedMap;
|
|
end;
|
|
|
|
TJclSortedEntry = record
|
|
Key: TObject;
|
|
Value: TObject;
|
|
end;
|
|
|
|
TJclSortedMap = class(TJclAbstractContainerBase, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclKeyOwner, IJclValueOwner,
|
|
IJclMap, IJclSortedMap)
|
|
private
|
|
FOwnsKeys: Boolean;
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function KeysCompare(A, B: TObject): Integer;
|
|
function ValuesCompare(A, B: TObject): Integer;
|
|
public
|
|
{ IJclKeyOwner }
|
|
function FreeKey(var Key: TObject): TObject;
|
|
function GetOwnsKeys: Boolean;
|
|
property OwnsKeys: Boolean read FOwnsKeys;
|
|
{ IJclValueOwner }
|
|
function FreeValue(var Value: TObject): TObject;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TJclSortedEntry;
|
|
function BinarySearch(Key: TObject): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean; AOwnsKeys: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclMap }
|
|
procedure Clear;
|
|
function ContainsKey(Key: TObject): Boolean;
|
|
function ContainsValue(Value: TObject): Boolean;
|
|
function Extract(Key: TObject): TObject;
|
|
function GetValue(Key: TObject): TObject;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(Value: TObject): TObject;
|
|
function KeySet: IJclSet;
|
|
function MapEquals(const AMap: IJclMap): Boolean;
|
|
procedure PutAll(const AMap: IJclMap);
|
|
procedure PutValue(Key: TObject; Value: TObject);
|
|
function Remove(Key: TObject): TObject;
|
|
function Size: Integer;
|
|
function Values: IJclCollection;
|
|
{ IJclSortedMap }
|
|
function FirstKey: TObject;
|
|
function HeadMap(ToKey: TObject): IJclSortedMap;
|
|
function LastKey: TObject;
|
|
function SubMap(FromKey, ToKey: TObject): IJclSortedMap;
|
|
function TailMap(FromKey: TObject): IJclSortedMap;
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_GENERICS}
|
|
TJclSortedEntry<TKey,TValue> = record
|
|
Key: TKey;
|
|
Value: TValue;
|
|
end;
|
|
|
|
TJclSortedMap<TKey,TValue> = class(TJclAbstractContainerBase, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclGrowable, IJclPackable, IJclContainer, IJclPairOwner<TKey,TValue>,
|
|
IJclMap<TKey,TValue>, IJclSortedMap<TKey,TValue>)
|
|
protected
|
|
type
|
|
TSortedEntry = TJclSortedEntry<TKey,TValue>;
|
|
private
|
|
FOwnsKeys: Boolean;
|
|
FOwnsValues: Boolean;
|
|
protected
|
|
function KeysCompare(const A, B: TKey): Integer; virtual; abstract;
|
|
function ValuesCompare(const A, B: TValue): Integer; virtual; abstract;
|
|
function CreateEmptyArrayList(ACapacity: Integer; AOwnsObjects: Boolean): IJclCollection<TValue>; virtual; abstract;
|
|
function CreateEmptyArraySet(ACapacity: Integer; AOwnsObjects: Boolean): IJclSet<TKey>; virtual; abstract;
|
|
public
|
|
{ IJclPairOwner }
|
|
function FreeKey(var Key: TKey): TKey;
|
|
function FreeValue(var Value: TValue): TValue;
|
|
function GetOwnsKeys: Boolean;
|
|
function GetOwnsValues: Boolean;
|
|
property OwnsKeys: Boolean read FOwnsKeys;
|
|
property OwnsValues: Boolean read FOwnsValues;
|
|
private
|
|
FEntries: array of TSortedEntry;
|
|
function BinarySearch(const Key: TKey): Integer;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
public
|
|
constructor Create(ACapacity: Integer; AOwnsValues: Boolean; AOwnsKeys: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclMap<TKey,TValue> }
|
|
procedure Clear;
|
|
function ContainsKey(const Key: TKey): Boolean;
|
|
function ContainsValue(const Value: TValue): Boolean;
|
|
function Extract(const Key: TKey): TValue;
|
|
function GetValue(const Key: TKey): TValue;
|
|
function IsEmpty: Boolean;
|
|
function KeyOfValue(const Value: TValue): TKey;
|
|
function KeySet: IJclSet<TKey>;
|
|
function MapEquals(const AMap: IJclMap<TKey,TValue>): Boolean;
|
|
procedure PutAll(const AMap: IJclMap<TKey,TValue>);
|
|
procedure PutValue(const Key: TKey; const Value: TValue);
|
|
function Remove(const Key: TKey): TValue;
|
|
function Size: Integer;
|
|
function Values: IJclCollection<TValue>;
|
|
{ IJclSortedMap<TKey,TValue> }
|
|
function FirstKey: TKey;
|
|
function HeadMap(const ToKey: TKey): IJclSortedMap<TKey,TValue>;
|
|
function LastKey: TKey;
|
|
function SubMap(const FromKey, ToKey: TKey): IJclSortedMap<TKey,TValue>;
|
|
function TailMap(const FromKey: TKey): IJclSortedMap<TKey,TValue>;
|
|
end;
|
|
|
|
// E = external helper to compare items
|
|
TJclSortedMapE<TKey, TValue> = class(TJclSortedMap<TKey,TValue>, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclMap<TKey,TValue>, IJclSortedMap<TKey,TValue>, IJclPairOwner<TKey,TValue>)
|
|
protected
|
|
type
|
|
TArrayList = TJclArrayListE<TValue>;
|
|
TArraySet = TJclArraySetE<TKey>;
|
|
private
|
|
FKeyComparer: IJclComparer<TKey>;
|
|
FValueComparer: IJclComparer<TValue>;
|
|
FValueEqualityComparer: IJclEqualityComparer<TValue>;
|
|
protected
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
function KeysCompare(const A, B: TKey): Integer; override;
|
|
function ValuesCompare(const A, B: TValue): Integer; override;
|
|
function CreateEmptyArrayList(ACapacity: Integer; AOwnsObjects: Boolean): IJclCollection<TValue>; override;
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function CreateEmptyArraySet(ACapacity: Integer; AOwnsObjects: Boolean): IJclSet<TKey>; override;
|
|
public
|
|
constructor Create(const AKeyComparer: IJclComparer<TKey>; const AValueComparer: IJclComparer<TValue>;
|
|
const AValueEqualityComparer: IJclEqualityComparer<TValue>; ACapacity: Integer; AOwnsValues: Boolean;
|
|
AOwnsKeys: Boolean);
|
|
|
|
property KeyComparer: IJclComparer<TKey> read FKeyComparer write FKeyComparer;
|
|
property ValueComparer: IJclComparer<TValue> read FValueComparer write FValueComparer;
|
|
property ValueEqualityComparer: IJclEqualityComparer<TValue> read FValueEqualityComparer write FValueEqualityComparer;
|
|
end;
|
|
|
|
// F = Functions to compare items
|
|
TJclSortedMapF<TKey, TValue> = class(TJclSortedMap<TKey, TValue>, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclMap<TKey,TValue>, IJclSortedMap<TKey,TValue>, IJclPairOwner<TKey, TValue>)
|
|
protected
|
|
type
|
|
TArrayList = TJclArrayListF<TValue>;
|
|
TArraySet = TJclArraySetF<TKey>;
|
|
private
|
|
FKeyCompare: TCompare<TKey>;
|
|
FValueCompare: TCompare<TValue>;
|
|
FValueEqualityCompare: TEqualityCompare<TValue>;
|
|
protected
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
function KeysCompare(const A, B: TKey): Integer; override;
|
|
function ValuesCompare(const A, B: TValue): Integer; override;
|
|
function CreateEmptyArrayList(ACapacity: Integer; AOwnsObjects: Boolean): IJclCollection<TValue>; override;
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function CreateEmptyArraySet(ACapacity: Integer; AOwnsObjects: Boolean): IJclSet<TKey>; override;
|
|
public
|
|
constructor Create(AKeyCompare: TCompare<TKey>; AValueCompare: TCompare<TValue>;
|
|
AValueEqualityCompare: TEqualityCompare<TValue>; ACapacity: Integer; AOwnsValues: Boolean; AOwnsKeys: Boolean);
|
|
|
|
property KeyCompare: TCompare<TKey> read FKeyCompare write FKeyCompare;
|
|
property ValueCompare: TCompare<TValue> read FValueCompare write FValueCompare;
|
|
property ValueEqualityCompare: TEqualityCompare<TValue> read FValueEqualityCompare write FValueEqualityCompare;
|
|
end;
|
|
|
|
// I = items can compare themselves to an other
|
|
TJclSortedMapI<TKey: IComparable<TKey>; TValue: IComparable<TValue>, IEquatable<TValue>> = class(TJclSortedMap<TKey, TValue>,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer,
|
|
IJclMap<TKey,TValue>, IJclSortedMap<TKey,TValue>, IJclPairOwner<TKey, TValue>)
|
|
protected
|
|
type
|
|
TArrayList = TJclArrayListI<TValue>;
|
|
TArraySet = TJclArraySetI<TKey>;
|
|
protected
|
|
function KeysCompare(const A, B: TKey): Integer; override;
|
|
function ValuesCompare(const A, B: TValue): Integer; override;
|
|
function CreateEmptyArrayList(ACapacity: Integer; AOwnsObjects: Boolean): IJclCollection<TValue>; override;
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
function CreateEmptyArraySet(ACapacity: Integer; AOwnsObjects: Boolean): IJclSet<TKey>; override;
|
|
end;
|
|
{$ENDIF SUPPORTS_GENERICS}
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
const
|
|
UnitVersioning: TUnitVersionInfo = (
|
|
RCSfile: '$URL: https://jcl.svn.sourceforge.net/svnroot/jcl/tags/JCL-2.1-Build3536/jcl/source/common/JclSortedMaps.pas $';
|
|
Revision: '$Revision: 2997 $';
|
|
Date: '$Date: 2009-09-12 14:21:23 +0200 (sam., 12 sept. 2009) $';
|
|
LogPath: 'JCL\source\common';
|
|
Extra: '';
|
|
Data: nil
|
|
);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils;
|
|
|
|
//=== { TJclIntfIntfSortedMap } ==============================================
|
|
|
|
constructor TJclIntfIntfSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfIntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfIntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfIntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfIntfSortedMap then
|
|
begin
|
|
MyDest := TJclIntfIntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfIntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.ContainsValue(const Value: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.Extract(const Key: IInterface): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.GetValue(const Key: IInterface): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.HeadMap(const ToKey: IInterface): IJclIntfIntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfIntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.KeyOfValue(const Value: IInterface): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.MapEquals(const AMap: IJclIntfIntfMap): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfIntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfIntfSortedMap.PutAll(const AMap: IJclIntfIntfMap);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfIntfSortedMap.PutValue(const Key: IInterface; const Value: IInterface);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.Remove(const Key: IInterface): IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfIntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfIntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.TailMap(const FromKey: IInterface): IJclIntfIntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.Values: IJclIntfCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfIntfSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.FreeValue(var Value: IInterface): IInterface;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclIntfIntfSortedMap.ValuesCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclAnsiStrIntfSortedMap } ==============================================
|
|
|
|
constructor TJclAnsiStrIntfSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclAnsiStrIntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclAnsiStrIntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclAnsiStrIntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclAnsiStrIntfSortedMap then
|
|
begin
|
|
MyDest := TJclAnsiStrIntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.BinarySearch(const Key: AnsiString): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrIntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.ContainsKey(const Key: AnsiString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.ContainsValue(const Value: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.FirstKey: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.Extract(const Key: AnsiString): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.GetValue(const Key: AnsiString): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.HeadMap(const ToKey: AnsiString): IJclAnsiStrIntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclAnsiStrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclAnsiStrIntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.KeyOfValue(const Value: IInterface): AnsiString;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := '';
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.KeySet: IJclAnsiStrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclAnsiStrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.LastKey: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.MapEquals(const AMap: IJclAnsiStrIntfMap): Boolean;
|
|
var
|
|
It: IJclAnsiStrIterator;
|
|
Index: Integer;
|
|
AKey: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrIntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclAnsiStrIntfSortedMap.PutAll(const AMap: IJclAnsiStrIntfMap);
|
|
var
|
|
It: IJclAnsiStrIterator;
|
|
Key: AnsiString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrIntfSortedMap.PutValue(const Key: AnsiString; const Value: IInterface);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, '') <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.Remove(const Key: AnsiString): IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrIntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.SubMap(const FromKey, ToKey: AnsiString): IJclAnsiStrIntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclAnsiStrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclAnsiStrIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.TailMap(const FromKey: AnsiString): IJclAnsiStrIntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclAnsiStrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclAnsiStrIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.Values: IJclIntfCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclAnsiStrIntfSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.FreeKey(var Key: AnsiString): AnsiString;
|
|
begin
|
|
Result := Key;
|
|
Key := '';
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.FreeValue(var Value: IInterface): IInterface;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.KeysCompare(const A, B: AnsiString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclAnsiStrIntfSortedMap.ValuesCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclIntfAnsiStrSortedMap } ==============================================
|
|
|
|
constructor TJclIntfAnsiStrSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfAnsiStrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfAnsiStrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfAnsiStrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfAnsiStrSortedMap then
|
|
begin
|
|
MyDest := TJclIntfAnsiStrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfAnsiStrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.ContainsValue(const Value: AnsiString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.Extract(const Key: IInterface): AnsiString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := '';
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := '';
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.GetValue(const Key: IInterface): AnsiString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := '';
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.HeadMap(const ToKey: IInterface): IJclIntfAnsiStrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfAnsiStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfAnsiStrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.KeyOfValue(const Value: AnsiString): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.MapEquals(const AMap: IJclIntfAnsiStrMap): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfAnsiStrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfAnsiStrSortedMap.PutAll(const AMap: IJclIntfAnsiStrMap);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfAnsiStrSortedMap.PutValue(const Key: IInterface; const Value: AnsiString);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, '') <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.Remove(const Key: IInterface): AnsiString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfAnsiStrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfAnsiStrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfAnsiStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfAnsiStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.TailMap(const FromKey: IInterface): IJclIntfAnsiStrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfAnsiStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfAnsiStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.Values: IJclAnsiStrCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclAnsiStrArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfAnsiStrSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.FreeValue(var Value: AnsiString): AnsiString;
|
|
begin
|
|
Result := Value;
|
|
Value := '';
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclIntfAnsiStrSortedMap.ValuesCompare(const A, B: AnsiString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclAnsiStrAnsiStrSortedMap } ==============================================
|
|
|
|
constructor TJclAnsiStrAnsiStrSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclAnsiStrAnsiStrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclAnsiStrAnsiStrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclAnsiStrAnsiStrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclAnsiStrAnsiStrSortedMap then
|
|
begin
|
|
MyDest := TJclAnsiStrAnsiStrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.BinarySearch(const Key: AnsiString): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrAnsiStrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.ContainsKey(const Key: AnsiString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.ContainsValue(const Value: AnsiString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.FirstKey: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.Extract(const Key: AnsiString): AnsiString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := '';
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := '';
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.GetValue(const Key: AnsiString): AnsiString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := '';
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.HeadMap(const ToKey: AnsiString): IJclAnsiStrAnsiStrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclAnsiStrAnsiStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclAnsiStrAnsiStrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.KeyOfValue(const Value: AnsiString): AnsiString;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := '';
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.KeySet: IJclAnsiStrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclAnsiStrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.LastKey: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.MapEquals(const AMap: IJclAnsiStrAnsiStrMap): Boolean;
|
|
var
|
|
It: IJclAnsiStrIterator;
|
|
Index: Integer;
|
|
AKey: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrAnsiStrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclAnsiStrAnsiStrSortedMap.PutAll(const AMap: IJclAnsiStrAnsiStrMap);
|
|
var
|
|
It: IJclAnsiStrIterator;
|
|
Key: AnsiString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrAnsiStrSortedMap.PutValue(const Key: AnsiString; const Value: AnsiString);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, '') <> 0) and (ValuesCompare(Value, '') <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.Remove(const Key: AnsiString): AnsiString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrAnsiStrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.SubMap(const FromKey, ToKey: AnsiString): IJclAnsiStrAnsiStrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclAnsiStrAnsiStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclAnsiStrAnsiStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.TailMap(const FromKey: AnsiString): IJclAnsiStrAnsiStrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclAnsiStrAnsiStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclAnsiStrAnsiStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.Values: IJclAnsiStrCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclAnsiStrArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclAnsiStrAnsiStrSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.FreeKey(var Key: AnsiString): AnsiString;
|
|
begin
|
|
Result := Key;
|
|
Key := '';
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.FreeValue(var Value: AnsiString): AnsiString;
|
|
begin
|
|
Result := Value;
|
|
Value := '';
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.KeysCompare(const A, B: AnsiString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclAnsiStrAnsiStrSortedMap.ValuesCompare(const A, B: AnsiString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclWideStrIntfSortedMap } ==============================================
|
|
|
|
constructor TJclWideStrIntfSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclWideStrIntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclWideStrIntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclWideStrIntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclWideStrIntfSortedMap then
|
|
begin
|
|
MyDest := TJclWideStrIntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.BinarySearch(const Key: WideString): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrIntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.ContainsKey(const Key: WideString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.ContainsValue(const Value: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.FirstKey: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.Extract(const Key: WideString): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.GetValue(const Key: WideString): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.HeadMap(const ToKey: WideString): IJclWideStrIntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclWideStrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclWideStrIntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.KeyOfValue(const Value: IInterface): WideString;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := '';
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.KeySet: IJclWideStrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclWideStrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.LastKey: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.MapEquals(const AMap: IJclWideStrIntfMap): Boolean;
|
|
var
|
|
It: IJclWideStrIterator;
|
|
Index: Integer;
|
|
AKey: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrIntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclWideStrIntfSortedMap.PutAll(const AMap: IJclWideStrIntfMap);
|
|
var
|
|
It: IJclWideStrIterator;
|
|
Key: WideString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrIntfSortedMap.PutValue(const Key: WideString; const Value: IInterface);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, '') <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.Remove(const Key: WideString): IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrIntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.SubMap(const FromKey, ToKey: WideString): IJclWideStrIntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclWideStrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclWideStrIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.TailMap(const FromKey: WideString): IJclWideStrIntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclWideStrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclWideStrIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.Values: IJclIntfCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclWideStrIntfSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.FreeKey(var Key: WideString): WideString;
|
|
begin
|
|
Result := Key;
|
|
Key := '';
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.FreeValue(var Value: IInterface): IInterface;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.KeysCompare(const A, B: WideString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclWideStrIntfSortedMap.ValuesCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclIntfWideStrSortedMap } ==============================================
|
|
|
|
constructor TJclIntfWideStrSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfWideStrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfWideStrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfWideStrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfWideStrSortedMap then
|
|
begin
|
|
MyDest := TJclIntfWideStrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfWideStrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.ContainsValue(const Value: WideString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.Extract(const Key: IInterface): WideString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := '';
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := '';
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.GetValue(const Key: IInterface): WideString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := '';
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.HeadMap(const ToKey: IInterface): IJclIntfWideStrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfWideStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfWideStrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.KeyOfValue(const Value: WideString): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.MapEquals(const AMap: IJclIntfWideStrMap): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfWideStrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfWideStrSortedMap.PutAll(const AMap: IJclIntfWideStrMap);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfWideStrSortedMap.PutValue(const Key: IInterface; const Value: WideString);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, '') <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.Remove(const Key: IInterface): WideString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfWideStrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfWideStrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfWideStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfWideStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.TailMap(const FromKey: IInterface): IJclIntfWideStrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfWideStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfWideStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.Values: IJclWideStrCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclWideStrArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfWideStrSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.FreeValue(var Value: WideString): WideString;
|
|
begin
|
|
Result := Value;
|
|
Value := '';
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclIntfWideStrSortedMap.ValuesCompare(const A, B: WideString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclWideStrWideStrSortedMap } ==============================================
|
|
|
|
constructor TJclWideStrWideStrSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclWideStrWideStrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclWideStrWideStrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclWideStrWideStrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclWideStrWideStrSortedMap then
|
|
begin
|
|
MyDest := TJclWideStrWideStrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.BinarySearch(const Key: WideString): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrWideStrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.ContainsKey(const Key: WideString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.ContainsValue(const Value: WideString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.FirstKey: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.Extract(const Key: WideString): WideString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := '';
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := '';
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.GetValue(const Key: WideString): WideString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := '';
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.HeadMap(const ToKey: WideString): IJclWideStrWideStrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclWideStrWideStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclWideStrWideStrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.KeyOfValue(const Value: WideString): WideString;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := '';
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.KeySet: IJclWideStrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclWideStrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.LastKey: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.MapEquals(const AMap: IJclWideStrWideStrMap): Boolean;
|
|
var
|
|
It: IJclWideStrIterator;
|
|
Index: Integer;
|
|
AKey: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrWideStrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclWideStrWideStrSortedMap.PutAll(const AMap: IJclWideStrWideStrMap);
|
|
var
|
|
It: IJclWideStrIterator;
|
|
Key: WideString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrWideStrSortedMap.PutValue(const Key: WideString; const Value: WideString);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, '') <> 0) and (ValuesCompare(Value, '') <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.Remove(const Key: WideString): WideString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrWideStrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.SubMap(const FromKey, ToKey: WideString): IJclWideStrWideStrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclWideStrWideStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclWideStrWideStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.TailMap(const FromKey: WideString): IJclWideStrWideStrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclWideStrWideStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclWideStrWideStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.Values: IJclWideStrCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclWideStrArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclWideStrWideStrSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.FreeKey(var Key: WideString): WideString;
|
|
begin
|
|
Result := Key;
|
|
Key := '';
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.FreeValue(var Value: WideString): WideString;
|
|
begin
|
|
Result := Value;
|
|
Value := '';
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.KeysCompare(const A, B: WideString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclWideStrWideStrSortedMap.ValuesCompare(const A, B: WideString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_UNICODE_STRING}
|
|
//=== { TJclUnicodeStrIntfSortedMap } ==============================================
|
|
|
|
constructor TJclUnicodeStrIntfSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclUnicodeStrIntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrIntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclUnicodeStrIntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclUnicodeStrIntfSortedMap then
|
|
begin
|
|
MyDest := TJclUnicodeStrIntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.BinarySearch(const Key: UnicodeString): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrIntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.ContainsKey(const Key: UnicodeString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.ContainsValue(const Value: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.FirstKey: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.Extract(const Key: UnicodeString): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.GetValue(const Key: UnicodeString): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.HeadMap(const ToKey: UnicodeString): IJclUnicodeStrIntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclUnicodeStrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclUnicodeStrIntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.KeyOfValue(const Value: IInterface): UnicodeString;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := '';
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.KeySet: IJclUnicodeStrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclUnicodeStrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.LastKey: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.MapEquals(const AMap: IJclUnicodeStrIntfMap): Boolean;
|
|
var
|
|
It: IJclUnicodeStrIterator;
|
|
Index: Integer;
|
|
AKey: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrIntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrIntfSortedMap.PutAll(const AMap: IJclUnicodeStrIntfMap);
|
|
var
|
|
It: IJclUnicodeStrIterator;
|
|
Key: UnicodeString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrIntfSortedMap.PutValue(const Key: UnicodeString; const Value: IInterface);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, '') <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.Remove(const Key: UnicodeString): IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrIntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.SubMap(const FromKey, ToKey: UnicodeString): IJclUnicodeStrIntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclUnicodeStrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclUnicodeStrIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.TailMap(const FromKey: UnicodeString): IJclUnicodeStrIntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclUnicodeStrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclUnicodeStrIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.Values: IJclIntfCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclUnicodeStrIntfSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.FreeKey(var Key: UnicodeString): UnicodeString;
|
|
begin
|
|
Result := Key;
|
|
Key := '';
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.FreeValue(var Value: IInterface): IInterface;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.KeysCompare(const A, B: UnicodeString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclUnicodeStrIntfSortedMap.ValuesCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclIntfUnicodeStrSortedMap } ==============================================
|
|
|
|
constructor TJclIntfUnicodeStrSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfUnicodeStrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfUnicodeStrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfUnicodeStrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfUnicodeStrSortedMap then
|
|
begin
|
|
MyDest := TJclIntfUnicodeStrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfUnicodeStrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.ContainsValue(const Value: UnicodeString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.Extract(const Key: IInterface): UnicodeString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := '';
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := '';
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.GetValue(const Key: IInterface): UnicodeString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := '';
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.HeadMap(const ToKey: IInterface): IJclIntfUnicodeStrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfUnicodeStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfUnicodeStrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.KeyOfValue(const Value: UnicodeString): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.MapEquals(const AMap: IJclIntfUnicodeStrMap): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfUnicodeStrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfUnicodeStrSortedMap.PutAll(const AMap: IJclIntfUnicodeStrMap);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfUnicodeStrSortedMap.PutValue(const Key: IInterface; const Value: UnicodeString);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, '') <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.Remove(const Key: IInterface): UnicodeString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfUnicodeStrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfUnicodeStrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfUnicodeStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfUnicodeStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.TailMap(const FromKey: IInterface): IJclIntfUnicodeStrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfUnicodeStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfUnicodeStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.Values: IJclUnicodeStrCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclUnicodeStrArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfUnicodeStrSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.FreeValue(var Value: UnicodeString): UnicodeString;
|
|
begin
|
|
Result := Value;
|
|
Value := '';
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclIntfUnicodeStrSortedMap.ValuesCompare(const A, B: UnicodeString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclUnicodeStrUnicodeStrSortedMap } ==============================================
|
|
|
|
constructor TJclUnicodeStrUnicodeStrSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclUnicodeStrUnicodeStrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrUnicodeStrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclUnicodeStrUnicodeStrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclUnicodeStrUnicodeStrSortedMap then
|
|
begin
|
|
MyDest := TJclUnicodeStrUnicodeStrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.BinarySearch(const Key: UnicodeString): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrUnicodeStrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.ContainsKey(const Key: UnicodeString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.ContainsValue(const Value: UnicodeString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.FirstKey: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.Extract(const Key: UnicodeString): UnicodeString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := '';
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := '';
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.GetValue(const Key: UnicodeString): UnicodeString;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := '';
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.HeadMap(const ToKey: UnicodeString): IJclUnicodeStrUnicodeStrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclUnicodeStrUnicodeStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclUnicodeStrUnicodeStrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.KeyOfValue(const Value: UnicodeString): UnicodeString;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := '';
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.KeySet: IJclUnicodeStrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclUnicodeStrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.LastKey: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.MapEquals(const AMap: IJclUnicodeStrUnicodeStrMap): Boolean;
|
|
var
|
|
It: IJclUnicodeStrIterator;
|
|
Index: Integer;
|
|
AKey: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrUnicodeStrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrUnicodeStrSortedMap.PutAll(const AMap: IJclUnicodeStrUnicodeStrMap);
|
|
var
|
|
It: IJclUnicodeStrIterator;
|
|
Key: UnicodeString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrUnicodeStrSortedMap.PutValue(const Key: UnicodeString; const Value: UnicodeString);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, '') <> 0) and (ValuesCompare(Value, '') <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.Remove(const Key: UnicodeString): UnicodeString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrUnicodeStrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.SubMap(const FromKey, ToKey: UnicodeString): IJclUnicodeStrUnicodeStrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclUnicodeStrUnicodeStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclUnicodeStrUnicodeStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.TailMap(const FromKey: UnicodeString): IJclUnicodeStrUnicodeStrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclUnicodeStrUnicodeStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclUnicodeStrUnicodeStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.Values: IJclUnicodeStrCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclUnicodeStrArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclUnicodeStrUnicodeStrSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.FreeKey(var Key: UnicodeString): UnicodeString;
|
|
begin
|
|
Result := Key;
|
|
Key := '';
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.FreeValue(var Value: UnicodeString): UnicodeString;
|
|
begin
|
|
Result := Value;
|
|
Value := '';
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.KeysCompare(const A, B: UnicodeString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclUnicodeStrUnicodeStrSortedMap.ValuesCompare(const A, B: UnicodeString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
{$ENDIF SUPPORTS_UNICODE_STRING}
|
|
|
|
//=== { TJclSingleIntfSortedMap } ==============================================
|
|
|
|
constructor TJclSingleIntfSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclSingleIntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclSingleIntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclSingleIntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclSingleIntfSortedMap then
|
|
begin
|
|
MyDest := TJclSingleIntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.BinarySearch(const Key: Single): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleIntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.ContainsKey(const Key: Single): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.ContainsValue(const Value: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.FirstKey: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.Extract(const Key: Single): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.GetValue(const Key: Single): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.HeadMap(const ToKey: Single): IJclSingleIntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclSingleIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSingleIntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.KeyOfValue(const Value: IInterface): Single;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0.0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.KeySet: IJclSingleSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclSingleArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.LastKey: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.MapEquals(const AMap: IJclSingleIntfMap): Boolean;
|
|
var
|
|
It: IJclSingleIterator;
|
|
Index: Integer;
|
|
AKey: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleIntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclSingleIntfSortedMap.PutAll(const AMap: IJclSingleIntfMap);
|
|
var
|
|
It: IJclSingleIterator;
|
|
Key: Single;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleIntfSortedMap.PutValue(const Key: Single; const Value: IInterface);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0.0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.Remove(const Key: Single): IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleIntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.SubMap(const FromKey, ToKey: Single): IJclSingleIntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclSingleIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSingleIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.TailMap(const FromKey: Single): IJclSingleIntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclSingleIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSingleIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.Values: IJclIntfCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclSingleIntfSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.FreeKey(var Key: Single): Single;
|
|
begin
|
|
Result := Key;
|
|
Key := 0.0;
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.FreeValue(var Value: IInterface): IInterface;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.KeysCompare(const A, B: Single): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclSingleIntfSortedMap.ValuesCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclIntfSingleSortedMap } ==============================================
|
|
|
|
constructor TJclIntfSingleSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfSingleSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfSingleSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfSingleSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfSingleSortedMap then
|
|
begin
|
|
MyDest := TJclIntfSingleSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfSingleSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.ContainsValue(const Value: Single): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.Extract(const Key: IInterface): Single;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0.0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0.0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.GetValue(const Key: IInterface): Single;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0.0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.HeadMap(const ToKey: IInterface): IJclIntfSingleSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfSingleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfSingleSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.KeyOfValue(const Value: Single): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.MapEquals(const AMap: IJclIntfSingleMap): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfSingleSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfSingleSortedMap.PutAll(const AMap: IJclIntfSingleMap);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfSingleSortedMap.PutValue(const Key: IInterface; const Value: Single);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, 0.0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.Remove(const Key: IInterface): Single;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfSingleSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfSingleSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfSingleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfSingleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.TailMap(const FromKey: IInterface): IJclIntfSingleSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfSingleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfSingleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.Values: IJclSingleCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclSingleArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfSingleSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.FreeValue(var Value: Single): Single;
|
|
begin
|
|
Result := Value;
|
|
Value := 0.0;
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclIntfSingleSortedMap.ValuesCompare(const A, B: Single): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclSingleSingleSortedMap } ==============================================
|
|
|
|
constructor TJclSingleSingleSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclSingleSingleSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclSingleSingleSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclSingleSingleSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclSingleSingleSortedMap then
|
|
begin
|
|
MyDest := TJclSingleSingleSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.BinarySearch(const Key: Single): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleSingleSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.ContainsKey(const Key: Single): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.ContainsValue(const Value: Single): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.FirstKey: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.Extract(const Key: Single): Single;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0.0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0.0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.GetValue(const Key: Single): Single;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0.0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.HeadMap(const ToKey: Single): IJclSingleSingleSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclSingleSingleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSingleSingleSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.KeyOfValue(const Value: Single): Single;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0.0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.KeySet: IJclSingleSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclSingleArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.LastKey: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.MapEquals(const AMap: IJclSingleSingleMap): Boolean;
|
|
var
|
|
It: IJclSingleIterator;
|
|
Index: Integer;
|
|
AKey: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleSingleSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclSingleSingleSortedMap.PutAll(const AMap: IJclSingleSingleMap);
|
|
var
|
|
It: IJclSingleIterator;
|
|
Key: Single;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleSingleSortedMap.PutValue(const Key: Single; const Value: Single);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0.0) <> 0) and (ValuesCompare(Value, 0.0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.Remove(const Key: Single): Single;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleSingleSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.SubMap(const FromKey, ToKey: Single): IJclSingleSingleSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclSingleSingleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSingleSingleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.TailMap(const FromKey: Single): IJclSingleSingleSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclSingleSingleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSingleSingleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.Values: IJclSingleCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclSingleArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclSingleSingleSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.FreeKey(var Key: Single): Single;
|
|
begin
|
|
Result := Key;
|
|
Key := 0.0;
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.FreeValue(var Value: Single): Single;
|
|
begin
|
|
Result := Value;
|
|
Value := 0.0;
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.KeysCompare(const A, B: Single): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclSingleSingleSortedMap.ValuesCompare(const A, B: Single): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclDoubleIntfSortedMap } ==============================================
|
|
|
|
constructor TJclDoubleIntfSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclDoubleIntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclDoubleIntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclDoubleIntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclDoubleIntfSortedMap then
|
|
begin
|
|
MyDest := TJclDoubleIntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.BinarySearch(const Key: Double): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleIntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.ContainsKey(const Key: Double): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.ContainsValue(const Value: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.FirstKey: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.Extract(const Key: Double): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.GetValue(const Key: Double): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.HeadMap(const ToKey: Double): IJclDoubleIntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclDoubleIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclDoubleIntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.KeyOfValue(const Value: IInterface): Double;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0.0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.KeySet: IJclDoubleSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclDoubleArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.LastKey: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.MapEquals(const AMap: IJclDoubleIntfMap): Boolean;
|
|
var
|
|
It: IJclDoubleIterator;
|
|
Index: Integer;
|
|
AKey: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleIntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclDoubleIntfSortedMap.PutAll(const AMap: IJclDoubleIntfMap);
|
|
var
|
|
It: IJclDoubleIterator;
|
|
Key: Double;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleIntfSortedMap.PutValue(const Key: Double; const Value: IInterface);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0.0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.Remove(const Key: Double): IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleIntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.SubMap(const FromKey, ToKey: Double): IJclDoubleIntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclDoubleIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclDoubleIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.TailMap(const FromKey: Double): IJclDoubleIntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclDoubleIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclDoubleIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.Values: IJclIntfCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclDoubleIntfSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.FreeKey(var Key: Double): Double;
|
|
begin
|
|
Result := Key;
|
|
Key := 0.0;
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.FreeValue(var Value: IInterface): IInterface;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.KeysCompare(const A, B: Double): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclDoubleIntfSortedMap.ValuesCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclIntfDoubleSortedMap } ==============================================
|
|
|
|
constructor TJclIntfDoubleSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfDoubleSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfDoubleSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfDoubleSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfDoubleSortedMap then
|
|
begin
|
|
MyDest := TJclIntfDoubleSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfDoubleSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.ContainsValue(const Value: Double): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.Extract(const Key: IInterface): Double;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0.0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0.0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.GetValue(const Key: IInterface): Double;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0.0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.HeadMap(const ToKey: IInterface): IJclIntfDoubleSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfDoubleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfDoubleSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.KeyOfValue(const Value: Double): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.MapEquals(const AMap: IJclIntfDoubleMap): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfDoubleSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfDoubleSortedMap.PutAll(const AMap: IJclIntfDoubleMap);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfDoubleSortedMap.PutValue(const Key: IInterface; const Value: Double);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, 0.0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.Remove(const Key: IInterface): Double;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfDoubleSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfDoubleSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfDoubleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfDoubleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.TailMap(const FromKey: IInterface): IJclIntfDoubleSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfDoubleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfDoubleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.Values: IJclDoubleCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclDoubleArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfDoubleSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.FreeValue(var Value: Double): Double;
|
|
begin
|
|
Result := Value;
|
|
Value := 0.0;
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclIntfDoubleSortedMap.ValuesCompare(const A, B: Double): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclDoubleDoubleSortedMap } ==============================================
|
|
|
|
constructor TJclDoubleDoubleSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclDoubleDoubleSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclDoubleDoubleSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclDoubleDoubleSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclDoubleDoubleSortedMap then
|
|
begin
|
|
MyDest := TJclDoubleDoubleSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.BinarySearch(const Key: Double): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleDoubleSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.ContainsKey(const Key: Double): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.ContainsValue(const Value: Double): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.FirstKey: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.Extract(const Key: Double): Double;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0.0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0.0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.GetValue(const Key: Double): Double;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0.0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.HeadMap(const ToKey: Double): IJclDoubleDoubleSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclDoubleDoubleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclDoubleDoubleSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.KeyOfValue(const Value: Double): Double;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0.0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.KeySet: IJclDoubleSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclDoubleArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.LastKey: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.MapEquals(const AMap: IJclDoubleDoubleMap): Boolean;
|
|
var
|
|
It: IJclDoubleIterator;
|
|
Index: Integer;
|
|
AKey: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleDoubleSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclDoubleDoubleSortedMap.PutAll(const AMap: IJclDoubleDoubleMap);
|
|
var
|
|
It: IJclDoubleIterator;
|
|
Key: Double;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleDoubleSortedMap.PutValue(const Key: Double; const Value: Double);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0.0) <> 0) and (ValuesCompare(Value, 0.0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.Remove(const Key: Double): Double;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleDoubleSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.SubMap(const FromKey, ToKey: Double): IJclDoubleDoubleSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclDoubleDoubleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclDoubleDoubleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.TailMap(const FromKey: Double): IJclDoubleDoubleSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclDoubleDoubleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclDoubleDoubleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.Values: IJclDoubleCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclDoubleArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclDoubleDoubleSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.FreeKey(var Key: Double): Double;
|
|
begin
|
|
Result := Key;
|
|
Key := 0.0;
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.FreeValue(var Value: Double): Double;
|
|
begin
|
|
Result := Value;
|
|
Value := 0.0;
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.KeysCompare(const A, B: Double): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclDoubleDoubleSortedMap.ValuesCompare(const A, B: Double): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclExtendedIntfSortedMap } ==============================================
|
|
|
|
constructor TJclExtendedIntfSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclExtendedIntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclExtendedIntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclExtendedIntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclExtendedIntfSortedMap then
|
|
begin
|
|
MyDest := TJclExtendedIntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.BinarySearch(const Key: Extended): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedIntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.ContainsKey(const Key: Extended): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.ContainsValue(const Value: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.FirstKey: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.Extract(const Key: Extended): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.GetValue(const Key: Extended): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.HeadMap(const ToKey: Extended): IJclExtendedIntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclExtendedIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclExtendedIntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.KeyOfValue(const Value: IInterface): Extended;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0.0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.KeySet: IJclExtendedSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclExtendedArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.LastKey: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.MapEquals(const AMap: IJclExtendedIntfMap): Boolean;
|
|
var
|
|
It: IJclExtendedIterator;
|
|
Index: Integer;
|
|
AKey: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedIntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclExtendedIntfSortedMap.PutAll(const AMap: IJclExtendedIntfMap);
|
|
var
|
|
It: IJclExtendedIterator;
|
|
Key: Extended;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedIntfSortedMap.PutValue(const Key: Extended; const Value: IInterface);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0.0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.Remove(const Key: Extended): IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedIntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.SubMap(const FromKey, ToKey: Extended): IJclExtendedIntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclExtendedIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclExtendedIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.TailMap(const FromKey: Extended): IJclExtendedIntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclExtendedIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclExtendedIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.Values: IJclIntfCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclExtendedIntfSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.FreeKey(var Key: Extended): Extended;
|
|
begin
|
|
Result := Key;
|
|
Key := 0.0;
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.FreeValue(var Value: IInterface): IInterface;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.KeysCompare(const A, B: Extended): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclExtendedIntfSortedMap.ValuesCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclIntfExtendedSortedMap } ==============================================
|
|
|
|
constructor TJclIntfExtendedSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfExtendedSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfExtendedSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfExtendedSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfExtendedSortedMap then
|
|
begin
|
|
MyDest := TJclIntfExtendedSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfExtendedSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.ContainsValue(const Value: Extended): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.Extract(const Key: IInterface): Extended;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0.0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0.0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.GetValue(const Key: IInterface): Extended;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0.0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.HeadMap(const ToKey: IInterface): IJclIntfExtendedSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfExtendedSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfExtendedSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.KeyOfValue(const Value: Extended): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.MapEquals(const AMap: IJclIntfExtendedMap): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfExtendedSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfExtendedSortedMap.PutAll(const AMap: IJclIntfExtendedMap);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfExtendedSortedMap.PutValue(const Key: IInterface; const Value: Extended);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, 0.0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.Remove(const Key: IInterface): Extended;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfExtendedSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfExtendedSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfExtendedSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfExtendedSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.TailMap(const FromKey: IInterface): IJclIntfExtendedSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfExtendedSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfExtendedSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.Values: IJclExtendedCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclExtendedArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfExtendedSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.FreeValue(var Value: Extended): Extended;
|
|
begin
|
|
Result := Value;
|
|
Value := 0.0;
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclIntfExtendedSortedMap.ValuesCompare(const A, B: Extended): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclExtendedExtendedSortedMap } ==============================================
|
|
|
|
constructor TJclExtendedExtendedSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclExtendedExtendedSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclExtendedExtendedSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclExtendedExtendedSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclExtendedExtendedSortedMap then
|
|
begin
|
|
MyDest := TJclExtendedExtendedSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.BinarySearch(const Key: Extended): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedExtendedSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.ContainsKey(const Key: Extended): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.ContainsValue(const Value: Extended): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.FirstKey: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.Extract(const Key: Extended): Extended;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0.0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0.0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.GetValue(const Key: Extended): Extended;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0.0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.HeadMap(const ToKey: Extended): IJclExtendedExtendedSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclExtendedExtendedSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclExtendedExtendedSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.KeyOfValue(const Value: Extended): Extended;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0.0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.KeySet: IJclExtendedSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclExtendedArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.LastKey: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.MapEquals(const AMap: IJclExtendedExtendedMap): Boolean;
|
|
var
|
|
It: IJclExtendedIterator;
|
|
Index: Integer;
|
|
AKey: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedExtendedSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclExtendedExtendedSortedMap.PutAll(const AMap: IJclExtendedExtendedMap);
|
|
var
|
|
It: IJclExtendedIterator;
|
|
Key: Extended;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedExtendedSortedMap.PutValue(const Key: Extended; const Value: Extended);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0.0) <> 0) and (ValuesCompare(Value, 0.0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.Remove(const Key: Extended): Extended;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedExtendedSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.SubMap(const FromKey, ToKey: Extended): IJclExtendedExtendedSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclExtendedExtendedSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclExtendedExtendedSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.TailMap(const FromKey: Extended): IJclExtendedExtendedSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclExtendedExtendedSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclExtendedExtendedSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.Values: IJclExtendedCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclExtendedArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclExtendedExtendedSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.FreeKey(var Key: Extended): Extended;
|
|
begin
|
|
Result := Key;
|
|
Key := 0.0;
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.FreeValue(var Value: Extended): Extended;
|
|
begin
|
|
Result := Value;
|
|
Value := 0.0;
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.KeysCompare(const A, B: Extended): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclExtendedExtendedSortedMap.ValuesCompare(const A, B: Extended): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclIntegerIntfSortedMap } ==============================================
|
|
|
|
constructor TJclIntegerIntfSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntegerIntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntegerIntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntegerIntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntegerIntfSortedMap then
|
|
begin
|
|
MyDest := TJclIntegerIntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.BinarySearch(Key: Integer): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerIntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.ContainsKey(Key: Integer): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.ContainsValue(const Value: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.FirstKey: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.Extract(Key: Integer): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.GetValue(Key: Integer): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.HeadMap(ToKey: Integer): IJclIntegerIntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntegerIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntegerIntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.KeyOfValue(const Value: IInterface): Integer;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.KeySet: IJclIntegerSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntegerArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.LastKey: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.MapEquals(const AMap: IJclIntegerIntfMap): Boolean;
|
|
var
|
|
It: IJclIntegerIterator;
|
|
Index: Integer;
|
|
AKey: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerIntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntegerIntfSortedMap.PutAll(const AMap: IJclIntegerIntfMap);
|
|
var
|
|
It: IJclIntegerIterator;
|
|
Key: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerIntfSortedMap.PutValue(Key: Integer; const Value: IInterface);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.Remove(Key: Integer): IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerIntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.SubMap(FromKey, ToKey: Integer): IJclIntegerIntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntegerIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntegerIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.TailMap(FromKey: Integer): IJclIntegerIntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntegerIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntegerIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.Values: IJclIntfCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntegerIntfSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.FreeKey(var Key: Integer): Integer;
|
|
begin
|
|
Result := Key;
|
|
Key := 0;
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.FreeValue(var Value: IInterface): IInterface;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.KeysCompare(A, B: Integer): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclIntegerIntfSortedMap.ValuesCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclIntfIntegerSortedMap } ==============================================
|
|
|
|
constructor TJclIntfIntegerSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfIntegerSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfIntegerSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfIntegerSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfIntegerSortedMap then
|
|
begin
|
|
MyDest := TJclIntfIntegerSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfIntegerSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.ContainsValue(Value: Integer): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.Extract(const Key: IInterface): Integer;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.GetValue(const Key: IInterface): Integer;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.HeadMap(const ToKey: IInterface): IJclIntfIntegerSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfIntegerSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfIntegerSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.KeyOfValue(Value: Integer): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.MapEquals(const AMap: IJclIntfIntegerMap): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfIntegerSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfIntegerSortedMap.PutAll(const AMap: IJclIntfIntegerMap);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfIntegerSortedMap.PutValue(const Key: IInterface; Value: Integer);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, 0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.Remove(const Key: IInterface): Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfIntegerSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfIntegerSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfIntegerSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfIntegerSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.TailMap(const FromKey: IInterface): IJclIntfIntegerSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfIntegerSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfIntegerSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.Values: IJclIntegerCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntegerArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfIntegerSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.FreeValue(var Value: Integer): Integer;
|
|
begin
|
|
Result := Value;
|
|
Value := 0;
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclIntfIntegerSortedMap.ValuesCompare(A, B: Integer): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclIntegerIntegerSortedMap } ==============================================
|
|
|
|
constructor TJclIntegerIntegerSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntegerIntegerSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntegerIntegerSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntegerIntegerSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntegerIntegerSortedMap then
|
|
begin
|
|
MyDest := TJclIntegerIntegerSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.BinarySearch(Key: Integer): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerIntegerSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.ContainsKey(Key: Integer): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.ContainsValue(Value: Integer): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.FirstKey: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.Extract(Key: Integer): Integer;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.GetValue(Key: Integer): Integer;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.HeadMap(ToKey: Integer): IJclIntegerIntegerSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntegerIntegerSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntegerIntegerSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.KeyOfValue(Value: Integer): Integer;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.KeySet: IJclIntegerSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntegerArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.LastKey: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.MapEquals(const AMap: IJclIntegerIntegerMap): Boolean;
|
|
var
|
|
It: IJclIntegerIterator;
|
|
Index: Integer;
|
|
AKey: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerIntegerSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntegerIntegerSortedMap.PutAll(const AMap: IJclIntegerIntegerMap);
|
|
var
|
|
It: IJclIntegerIterator;
|
|
Key: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerIntegerSortedMap.PutValue(Key: Integer; Value: Integer);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0) <> 0) and (ValuesCompare(Value, 0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.Remove(Key: Integer): Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerIntegerSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.SubMap(FromKey, ToKey: Integer): IJclIntegerIntegerSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntegerIntegerSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntegerIntegerSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.TailMap(FromKey: Integer): IJclIntegerIntegerSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntegerIntegerSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntegerIntegerSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.Values: IJclIntegerCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntegerArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntegerIntegerSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.FreeKey(var Key: Integer): Integer;
|
|
begin
|
|
Result := Key;
|
|
Key := 0;
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.FreeValue(var Value: Integer): Integer;
|
|
begin
|
|
Result := Value;
|
|
Value := 0;
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.KeysCompare(A, B: Integer): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclIntegerIntegerSortedMap.ValuesCompare(A, B: Integer): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclCardinalIntfSortedMap } ==============================================
|
|
|
|
constructor TJclCardinalIntfSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclCardinalIntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclCardinalIntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclCardinalIntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclCardinalIntfSortedMap then
|
|
begin
|
|
MyDest := TJclCardinalIntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.BinarySearch(Key: Cardinal): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalIntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.ContainsKey(Key: Cardinal): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.ContainsValue(const Value: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.FirstKey: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.Extract(Key: Cardinal): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.GetValue(Key: Cardinal): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.HeadMap(ToKey: Cardinal): IJclCardinalIntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclCardinalIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclCardinalIntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.KeyOfValue(const Value: IInterface): Cardinal;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.KeySet: IJclCardinalSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclCardinalArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.LastKey: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.MapEquals(const AMap: IJclCardinalIntfMap): Boolean;
|
|
var
|
|
It: IJclCardinalIterator;
|
|
Index: Integer;
|
|
AKey: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalIntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclCardinalIntfSortedMap.PutAll(const AMap: IJclCardinalIntfMap);
|
|
var
|
|
It: IJclCardinalIterator;
|
|
Key: Cardinal;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalIntfSortedMap.PutValue(Key: Cardinal; const Value: IInterface);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.Remove(Key: Cardinal): IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalIntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.SubMap(FromKey, ToKey: Cardinal): IJclCardinalIntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclCardinalIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclCardinalIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.TailMap(FromKey: Cardinal): IJclCardinalIntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclCardinalIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclCardinalIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.Values: IJclIntfCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclCardinalIntfSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.FreeKey(var Key: Cardinal): Cardinal;
|
|
begin
|
|
Result := Key;
|
|
Key := 0;
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.FreeValue(var Value: IInterface): IInterface;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.KeysCompare(A, B: Cardinal): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclCardinalIntfSortedMap.ValuesCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclIntfCardinalSortedMap } ==============================================
|
|
|
|
constructor TJclIntfCardinalSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfCardinalSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfCardinalSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfCardinalSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfCardinalSortedMap then
|
|
begin
|
|
MyDest := TJclIntfCardinalSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfCardinalSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.ContainsValue(Value: Cardinal): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.Extract(const Key: IInterface): Cardinal;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.GetValue(const Key: IInterface): Cardinal;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.HeadMap(const ToKey: IInterface): IJclIntfCardinalSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfCardinalSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfCardinalSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.KeyOfValue(Value: Cardinal): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.MapEquals(const AMap: IJclIntfCardinalMap): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfCardinalSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfCardinalSortedMap.PutAll(const AMap: IJclIntfCardinalMap);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfCardinalSortedMap.PutValue(const Key: IInterface; Value: Cardinal);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, 0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.Remove(const Key: IInterface): Cardinal;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfCardinalSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfCardinalSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfCardinalSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfCardinalSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.TailMap(const FromKey: IInterface): IJclIntfCardinalSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfCardinalSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfCardinalSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.Values: IJclCardinalCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclCardinalArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfCardinalSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.FreeValue(var Value: Cardinal): Cardinal;
|
|
begin
|
|
Result := Value;
|
|
Value := 0;
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclIntfCardinalSortedMap.ValuesCompare(A, B: Cardinal): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclCardinalCardinalSortedMap } ==============================================
|
|
|
|
constructor TJclCardinalCardinalSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclCardinalCardinalSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclCardinalCardinalSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclCardinalCardinalSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclCardinalCardinalSortedMap then
|
|
begin
|
|
MyDest := TJclCardinalCardinalSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.BinarySearch(Key: Cardinal): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalCardinalSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.ContainsKey(Key: Cardinal): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.ContainsValue(Value: Cardinal): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.FirstKey: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.Extract(Key: Cardinal): Cardinal;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.GetValue(Key: Cardinal): Cardinal;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.HeadMap(ToKey: Cardinal): IJclCardinalCardinalSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclCardinalCardinalSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclCardinalCardinalSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.KeyOfValue(Value: Cardinal): Cardinal;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.KeySet: IJclCardinalSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclCardinalArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.LastKey: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.MapEquals(const AMap: IJclCardinalCardinalMap): Boolean;
|
|
var
|
|
It: IJclCardinalIterator;
|
|
Index: Integer;
|
|
AKey: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalCardinalSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclCardinalCardinalSortedMap.PutAll(const AMap: IJclCardinalCardinalMap);
|
|
var
|
|
It: IJclCardinalIterator;
|
|
Key: Cardinal;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalCardinalSortedMap.PutValue(Key: Cardinal; Value: Cardinal);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0) <> 0) and (ValuesCompare(Value, 0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.Remove(Key: Cardinal): Cardinal;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalCardinalSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.SubMap(FromKey, ToKey: Cardinal): IJclCardinalCardinalSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclCardinalCardinalSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclCardinalCardinalSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.TailMap(FromKey: Cardinal): IJclCardinalCardinalSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclCardinalCardinalSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclCardinalCardinalSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.Values: IJclCardinalCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclCardinalArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclCardinalCardinalSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.FreeKey(var Key: Cardinal): Cardinal;
|
|
begin
|
|
Result := Key;
|
|
Key := 0;
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.FreeValue(var Value: Cardinal): Cardinal;
|
|
begin
|
|
Result := Value;
|
|
Value := 0;
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.KeysCompare(A, B: Cardinal): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclCardinalCardinalSortedMap.ValuesCompare(A, B: Cardinal): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclInt64IntfSortedMap } ==============================================
|
|
|
|
constructor TJclInt64IntfSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclInt64IntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclInt64IntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclInt64IntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclInt64IntfSortedMap then
|
|
begin
|
|
MyDest := TJclInt64IntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.BinarySearch(const Key: Int64): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64IntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.ContainsKey(const Key: Int64): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.ContainsValue(const Value: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.FirstKey: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.Extract(const Key: Int64): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.GetValue(const Key: Int64): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.HeadMap(const ToKey: Int64): IJclInt64IntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclInt64IntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclInt64IntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.KeyOfValue(const Value: IInterface): Int64;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.KeySet: IJclInt64Set;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclInt64ArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.LastKey: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.MapEquals(const AMap: IJclInt64IntfMap): Boolean;
|
|
var
|
|
It: IJclInt64Iterator;
|
|
Index: Integer;
|
|
AKey: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64IntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclInt64IntfSortedMap.PutAll(const AMap: IJclInt64IntfMap);
|
|
var
|
|
It: IJclInt64Iterator;
|
|
Key: Int64;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64IntfSortedMap.PutValue(const Key: Int64; const Value: IInterface);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.Remove(const Key: Int64): IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64IntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.SubMap(const FromKey, ToKey: Int64): IJclInt64IntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclInt64IntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclInt64IntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.TailMap(const FromKey: Int64): IJclInt64IntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclInt64IntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclInt64IntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.Values: IJclIntfCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclInt64IntfSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.FreeKey(var Key: Int64): Int64;
|
|
begin
|
|
Result := Key;
|
|
Key := 0;
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.FreeValue(var Value: IInterface): IInterface;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.KeysCompare(const A, B: Int64): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclInt64IntfSortedMap.ValuesCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclIntfInt64SortedMap } ==============================================
|
|
|
|
constructor TJclIntfInt64SortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfInt64SortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfInt64SortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfInt64SortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfInt64SortedMap then
|
|
begin
|
|
MyDest := TJclIntfInt64SortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfInt64SortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.ContainsValue(const Value: Int64): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.Extract(const Key: IInterface): Int64;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.GetValue(const Key: IInterface): Int64;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.HeadMap(const ToKey: IInterface): IJclIntfInt64SortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfInt64SortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfInt64SortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.KeyOfValue(const Value: Int64): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.MapEquals(const AMap: IJclIntfInt64Map): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfInt64SortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfInt64SortedMap.PutAll(const AMap: IJclIntfInt64Map);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfInt64SortedMap.PutValue(const Key: IInterface; const Value: Int64);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, 0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.Remove(const Key: IInterface): Int64;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfInt64SortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfInt64SortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfInt64SortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfInt64SortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.TailMap(const FromKey: IInterface): IJclIntfInt64SortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfInt64SortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfInt64SortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.Values: IJclInt64Collection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclInt64ArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfInt64SortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.FreeValue(var Value: Int64): Int64;
|
|
begin
|
|
Result := Value;
|
|
Value := 0;
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclIntfInt64SortedMap.ValuesCompare(const A, B: Int64): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclInt64Int64SortedMap } ==============================================
|
|
|
|
constructor TJclInt64Int64SortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclInt64Int64SortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclInt64Int64SortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclInt64Int64SortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclInt64Int64SortedMap then
|
|
begin
|
|
MyDest := TJclInt64Int64SortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.BinarySearch(const Key: Int64): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64Int64SortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.ContainsKey(const Key: Int64): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.ContainsValue(const Value: Int64): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.FirstKey: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.Extract(const Key: Int64): Int64;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := 0;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.GetValue(const Key: Int64): Int64;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := 0;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.HeadMap(const ToKey: Int64): IJclInt64Int64SortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclInt64Int64SortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclInt64Int64SortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.KeyOfValue(const Value: Int64): Int64;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.KeySet: IJclInt64Set;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclInt64ArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.LastKey: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.MapEquals(const AMap: IJclInt64Int64Map): Boolean;
|
|
var
|
|
It: IJclInt64Iterator;
|
|
Index: Integer;
|
|
AKey: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64Int64SortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclInt64Int64SortedMap.PutAll(const AMap: IJclInt64Int64Map);
|
|
var
|
|
It: IJclInt64Iterator;
|
|
Key: Int64;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64Int64SortedMap.PutValue(const Key: Int64; const Value: Int64);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0) <> 0) and (ValuesCompare(Value, 0) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.Remove(const Key: Int64): Int64;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64Int64SortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.SubMap(const FromKey, ToKey: Int64): IJclInt64Int64SortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclInt64Int64SortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclInt64Int64SortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.TailMap(const FromKey: Int64): IJclInt64Int64SortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclInt64Int64SortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclInt64Int64SortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.Values: IJclInt64Collection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclInt64ArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclInt64Int64SortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.FreeKey(var Key: Int64): Int64;
|
|
begin
|
|
Result := Key;
|
|
Key := 0;
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.FreeValue(var Value: Int64): Int64;
|
|
begin
|
|
Result := Value;
|
|
Value := 0;
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.KeysCompare(const A, B: Int64): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclInt64Int64SortedMap.ValuesCompare(const A, B: Int64): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclPtrIntfSortedMap } ==============================================
|
|
|
|
constructor TJclPtrIntfSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclPtrIntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclPtrIntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclPtrIntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclPtrIntfSortedMap then
|
|
begin
|
|
MyDest := TJclPtrIntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.BinarySearch(Key: Pointer): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrIntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.ContainsKey(Key: Pointer): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.ContainsValue(const Value: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.FirstKey: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.Extract(Key: Pointer): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.GetValue(Key: Pointer): IInterface;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.HeadMap(ToKey: Pointer): IJclPtrIntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclPtrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclPtrIntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.KeyOfValue(const Value: IInterface): Pointer;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.KeySet: IJclPtrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclPtrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.LastKey: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.MapEquals(const AMap: IJclPtrIntfMap): Boolean;
|
|
var
|
|
It: IJclPtrIterator;
|
|
Index: Integer;
|
|
AKey: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrIntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclPtrIntfSortedMap.PutAll(const AMap: IJclPtrIntfMap);
|
|
var
|
|
It: IJclPtrIterator;
|
|
Key: Pointer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrIntfSortedMap.PutValue(Key: Pointer; const Value: IInterface);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.Remove(Key: Pointer): IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrIntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.SubMap(FromKey, ToKey: Pointer): IJclPtrIntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclPtrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclPtrIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.TailMap(FromKey: Pointer): IJclPtrIntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclPtrIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclPtrIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.Values: IJclIntfCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclPtrIntfSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.FreeKey(var Key: Pointer): Pointer;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.FreeValue(var Value: IInterface): IInterface;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.KeysCompare(A, B: Pointer): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclPtrIntfSortedMap.ValuesCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclIntfPtrSortedMap } ==============================================
|
|
|
|
constructor TJclIntfPtrSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfPtrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfPtrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfPtrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfPtrSortedMap then
|
|
begin
|
|
MyDest := TJclIntfPtrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfPtrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.ContainsValue(Value: Pointer): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.Extract(const Key: IInterface): Pointer;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.GetValue(const Key: IInterface): Pointer;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.HeadMap(const ToKey: IInterface): IJclIntfPtrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfPtrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfPtrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.KeyOfValue(Value: Pointer): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.MapEquals(const AMap: IJclIntfPtrMap): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfPtrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfPtrSortedMap.PutAll(const AMap: IJclIntfPtrMap);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfPtrSortedMap.PutValue(const Key: IInterface; Value: Pointer);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.Remove(const Key: IInterface): Pointer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfPtrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfPtrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfPtrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfPtrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.TailMap(const FromKey: IInterface): IJclIntfPtrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfPtrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfPtrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.Values: IJclPtrCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclPtrArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfPtrSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.FreeValue(var Value: Pointer): Pointer;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclIntfPtrSortedMap.ValuesCompare(A, B: Pointer): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclPtrPtrSortedMap } ==============================================
|
|
|
|
constructor TJclPtrPtrSortedMap.Create(ACapacity: Integer);
|
|
begin
|
|
inherited Create();
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclPtrPtrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclPtrPtrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclPtrPtrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclPtrPtrSortedMap then
|
|
begin
|
|
MyDest := TJclPtrPtrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.BinarySearch(Key: Pointer): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrPtrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.ContainsKey(Key: Pointer): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.ContainsValue(Value: Pointer): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.FirstKey: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.Extract(Key: Pointer): Pointer;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.GetValue(Key: Pointer): Pointer;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.HeadMap(ToKey: Pointer): IJclPtrPtrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclPtrPtrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclPtrPtrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.KeyOfValue(Value: Pointer): Pointer;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.KeySet: IJclPtrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclPtrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.LastKey: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.MapEquals(const AMap: IJclPtrPtrMap): Boolean;
|
|
var
|
|
It: IJclPtrIterator;
|
|
Index: Integer;
|
|
AKey: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrPtrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclPtrPtrSortedMap.PutAll(const AMap: IJclPtrPtrMap);
|
|
var
|
|
It: IJclPtrIterator;
|
|
Key: Pointer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrPtrSortedMap.PutValue(Key: Pointer; Value: Pointer);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.Remove(Key: Pointer): Pointer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrPtrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.SubMap(FromKey, ToKey: Pointer): IJclPtrPtrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclPtrPtrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclPtrPtrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.TailMap(FromKey: Pointer): IJclPtrPtrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclPtrPtrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclPtrPtrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.Values: IJclPtrCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclPtrArrayList.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclPtrPtrSortedMap.Create(FSize);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.FreeKey(var Key: Pointer): Pointer;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.FreeValue(var Value: Pointer): Pointer;
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.KeysCompare(A, B: Pointer): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclPtrPtrSortedMap.ValuesCompare(A, B: Pointer): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclIntfSortedMap } ==============================================
|
|
|
|
constructor TJclIntfSortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntfSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntfSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntfSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfSortedMap then
|
|
begin
|
|
MyDest := TJclIntfSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfSortedMap.BinarySearch(const Key: IInterface): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.ContainsKey(const Key: IInterface): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.FirstKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.Extract(const Key: IInterface): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.GetValue(const Key: IInterface): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.HeadMap(const ToKey: IInterface): IJclIntfSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.KeyOfValue(Value: TObject): IInterface;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.KeySet: IJclIntfSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntfArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.LastKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.MapEquals(const AMap: IJclIntfMap): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
Index: Integer;
|
|
AKey: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfSortedMap.PutAll(const AMap: IJclIntfMap);
|
|
var
|
|
It: IJclIntfIterator;
|
|
Key: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfSortedMap.PutValue(const Key: IInterface; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.Remove(const Key: IInterface): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfSortedMap.SubMap(const FromKey, ToKey: IInterface): IJclIntfSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.TailMap(const FromKey: IInterface): IJclIntfSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntfSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntfSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfSortedMap.Create(FSize, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntfSortedMap.FreeKey(var Key: IInterface): IInterface;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclIntfSortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfSortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclIntfSortedMap.KeysCompare(const A, B: IInterface): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclIntfSortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclAnsiStrSortedMap } ==============================================
|
|
|
|
constructor TJclAnsiStrSortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclAnsiStrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclAnsiStrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclAnsiStrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclAnsiStrSortedMap then
|
|
begin
|
|
MyDest := TJclAnsiStrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.BinarySearch(const Key: AnsiString): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.ContainsKey(const Key: AnsiString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.FirstKey: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.Extract(const Key: AnsiString): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.GetValue(const Key: AnsiString): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.HeadMap(const ToKey: AnsiString): IJclAnsiStrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclAnsiStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclAnsiStrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.KeyOfValue(Value: TObject): AnsiString;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := '';
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.KeySet: IJclAnsiStrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclAnsiStrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.LastKey: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.MapEquals(const AMap: IJclAnsiStrMap): Boolean;
|
|
var
|
|
It: IJclAnsiStrIterator;
|
|
Index: Integer;
|
|
AKey: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclAnsiStrSortedMap.PutAll(const AMap: IJclAnsiStrMap);
|
|
var
|
|
It: IJclAnsiStrIterator;
|
|
Key: AnsiString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrSortedMap.PutValue(const Key: AnsiString; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, '') <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.Remove(const Key: AnsiString): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.SubMap(const FromKey, ToKey: AnsiString): IJclAnsiStrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclAnsiStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclAnsiStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.TailMap(const FromKey: AnsiString): IJclAnsiStrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclAnsiStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclAnsiStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclAnsiStrSortedMap.Create(FSize, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.FreeKey(var Key: AnsiString): AnsiString;
|
|
begin
|
|
Result := Key;
|
|
Key := '';
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.KeysCompare(const A, B: AnsiString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclAnsiStrSortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclWideStrSortedMap } ==============================================
|
|
|
|
constructor TJclWideStrSortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclWideStrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclWideStrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclWideStrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclWideStrSortedMap then
|
|
begin
|
|
MyDest := TJclWideStrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.BinarySearch(const Key: WideString): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.ContainsKey(const Key: WideString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.FirstKey: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.Extract(const Key: WideString): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.GetValue(const Key: WideString): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.HeadMap(const ToKey: WideString): IJclWideStrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclWideStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclWideStrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.KeyOfValue(Value: TObject): WideString;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := '';
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.KeySet: IJclWideStrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclWideStrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.LastKey: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.MapEquals(const AMap: IJclWideStrMap): Boolean;
|
|
var
|
|
It: IJclWideStrIterator;
|
|
Index: Integer;
|
|
AKey: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclWideStrSortedMap.PutAll(const AMap: IJclWideStrMap);
|
|
var
|
|
It: IJclWideStrIterator;
|
|
Key: WideString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrSortedMap.PutValue(const Key: WideString; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, '') <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.Remove(const Key: WideString): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.SubMap(const FromKey, ToKey: WideString): IJclWideStrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclWideStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclWideStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.TailMap(const FromKey: WideString): IJclWideStrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclWideStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclWideStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclWideStrSortedMap.Create(FSize, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.FreeKey(var Key: WideString): WideString;
|
|
begin
|
|
Result := Key;
|
|
Key := '';
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.KeysCompare(const A, B: WideString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclWideStrSortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_UNICODE_STRING}
|
|
//=== { TJclUnicodeStrSortedMap } ==============================================
|
|
|
|
constructor TJclUnicodeStrSortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclUnicodeStrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclUnicodeStrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclUnicodeStrSortedMap then
|
|
begin
|
|
MyDest := TJclUnicodeStrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.BinarySearch(const Key: UnicodeString): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.ContainsKey(const Key: UnicodeString): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.FirstKey: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.Extract(const Key: UnicodeString): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.GetValue(const Key: UnicodeString): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.HeadMap(const ToKey: UnicodeString): IJclUnicodeStrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclUnicodeStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclUnicodeStrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.KeyOfValue(Value: TObject): UnicodeString;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := '';
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.KeySet: IJclUnicodeStrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclUnicodeStrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.LastKey: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.MapEquals(const AMap: IJclUnicodeStrMap): Boolean;
|
|
var
|
|
It: IJclUnicodeStrIterator;
|
|
Index: Integer;
|
|
AKey: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrSortedMap.PutAll(const AMap: IJclUnicodeStrMap);
|
|
var
|
|
It: IJclUnicodeStrIterator;
|
|
Key: UnicodeString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrSortedMap.PutValue(const Key: UnicodeString; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, '') <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.Remove(const Key: UnicodeString): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.SubMap(const FromKey, ToKey: UnicodeString): IJclUnicodeStrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclUnicodeStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclUnicodeStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.TailMap(const FromKey: UnicodeString): IJclUnicodeStrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclUnicodeStrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclUnicodeStrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclUnicodeStrSortedMap.Create(FSize, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.FreeKey(var Key: UnicodeString): UnicodeString;
|
|
begin
|
|
Result := Key;
|
|
Key := '';
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.KeysCompare(const A, B: UnicodeString): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclUnicodeStrSortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
{$ENDIF SUPPORTS_UNICODE_STRING}
|
|
|
|
//=== { TJclSingleSortedMap } ==============================================
|
|
|
|
constructor TJclSingleSortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclSingleSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclSingleSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclSingleSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclSingleSortedMap then
|
|
begin
|
|
MyDest := TJclSingleSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclSingleSortedMap.BinarySearch(const Key: Single): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.ContainsKey(const Key: Single): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.FirstKey: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.Extract(const Key: Single): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.GetValue(const Key: Single): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.HeadMap(const ToKey: Single): IJclSingleSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclSingleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSingleSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.KeyOfValue(Value: TObject): Single;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0.0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.KeySet: IJclSingleSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclSingleArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.LastKey: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.MapEquals(const AMap: IJclSingleMap): Boolean;
|
|
var
|
|
It: IJclSingleIterator;
|
|
Index: Integer;
|
|
AKey: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclSingleSortedMap.PutAll(const AMap: IJclSingleMap);
|
|
var
|
|
It: IJclSingleIterator;
|
|
Key: Single;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleSortedMap.PutValue(const Key: Single; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0.0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.Remove(const Key: Single): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclSingleSortedMap.SubMap(const FromKey, ToKey: Single): IJclSingleSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclSingleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSingleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.TailMap(const FromKey: Single): IJclSingleSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclSingleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSingleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclSingleSortedMap.Create(FSize, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclSingleSortedMap.FreeKey(var Key: Single): Single;
|
|
begin
|
|
Result := Key;
|
|
Key := 0.0;
|
|
end;
|
|
|
|
function TJclSingleSortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclSingleSortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclSingleSortedMap.KeysCompare(const A, B: Single): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclSingleSortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclDoubleSortedMap } ==============================================
|
|
|
|
constructor TJclDoubleSortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclDoubleSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclDoubleSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclDoubleSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclDoubleSortedMap then
|
|
begin
|
|
MyDest := TJclDoubleSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.BinarySearch(const Key: Double): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.ContainsKey(const Key: Double): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.FirstKey: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.Extract(const Key: Double): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.GetValue(const Key: Double): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.HeadMap(const ToKey: Double): IJclDoubleSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclDoubleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclDoubleSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.KeyOfValue(Value: TObject): Double;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0.0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.KeySet: IJclDoubleSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclDoubleArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.LastKey: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.MapEquals(const AMap: IJclDoubleMap): Boolean;
|
|
var
|
|
It: IJclDoubleIterator;
|
|
Index: Integer;
|
|
AKey: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclDoubleSortedMap.PutAll(const AMap: IJclDoubleMap);
|
|
var
|
|
It: IJclDoubleIterator;
|
|
Key: Double;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleSortedMap.PutValue(const Key: Double; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0.0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.Remove(const Key: Double): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.SubMap(const FromKey, ToKey: Double): IJclDoubleSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclDoubleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclDoubleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.TailMap(const FromKey: Double): IJclDoubleSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclDoubleSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclDoubleSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclDoubleSortedMap.Create(FSize, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.FreeKey(var Key: Double): Double;
|
|
begin
|
|
Result := Key;
|
|
Key := 0.0;
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.KeysCompare(const A, B: Double): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclDoubleSortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclExtendedSortedMap } ==============================================
|
|
|
|
constructor TJclExtendedSortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclExtendedSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclExtendedSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclExtendedSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclExtendedSortedMap then
|
|
begin
|
|
MyDest := TJclExtendedSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.BinarySearch(const Key: Extended): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.ContainsKey(const Key: Extended): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.FirstKey: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.Extract(const Key: Extended): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.GetValue(const Key: Extended): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.HeadMap(const ToKey: Extended): IJclExtendedSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclExtendedSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclExtendedSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.KeyOfValue(Value: TObject): Extended;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0.0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.KeySet: IJclExtendedSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclExtendedArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.LastKey: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.MapEquals(const AMap: IJclExtendedMap): Boolean;
|
|
var
|
|
It: IJclExtendedIterator;
|
|
Index: Integer;
|
|
AKey: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclExtendedSortedMap.PutAll(const AMap: IJclExtendedMap);
|
|
var
|
|
It: IJclExtendedIterator;
|
|
Key: Extended;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedSortedMap.PutValue(const Key: Extended; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0.0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.Remove(const Key: Extended): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.SubMap(const FromKey, ToKey: Extended): IJclExtendedSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclExtendedSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclExtendedSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.TailMap(const FromKey: Extended): IJclExtendedSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclExtendedSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclExtendedSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclExtendedSortedMap.Create(FSize, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.FreeKey(var Key: Extended): Extended;
|
|
begin
|
|
Result := Key;
|
|
Key := 0.0;
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.KeysCompare(const A, B: Extended): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclExtendedSortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclIntegerSortedMap } ==============================================
|
|
|
|
constructor TJclIntegerSortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclIntegerSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclIntegerSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclIntegerSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntegerSortedMap then
|
|
begin
|
|
MyDest := TJclIntegerSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.BinarySearch(Key: Integer): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.ContainsKey(Key: Integer): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.FirstKey: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.Extract(Key: Integer): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.GetValue(Key: Integer): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.HeadMap(ToKey: Integer): IJclIntegerSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclIntegerSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntegerSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.KeyOfValue(Value: TObject): Integer;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.KeySet: IJclIntegerSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclIntegerArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.LastKey: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.MapEquals(const AMap: IJclIntegerMap): Boolean;
|
|
var
|
|
It: IJclIntegerIterator;
|
|
Index: Integer;
|
|
AKey: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntegerSortedMap.PutAll(const AMap: IJclIntegerMap);
|
|
var
|
|
It: IJclIntegerIterator;
|
|
Key: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerSortedMap.PutValue(Key: Integer; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.Remove(Key: Integer): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.SubMap(FromKey, ToKey: Integer): IJclIntegerSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclIntegerSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntegerSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.TailMap(FromKey: Integer): IJclIntegerSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclIntegerSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclIntegerSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntegerSortedMap.Create(FSize, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.FreeKey(var Key: Integer): Integer;
|
|
begin
|
|
Result := Key;
|
|
Key := 0;
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.KeysCompare(A, B: Integer): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclIntegerSortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclCardinalSortedMap } ==============================================
|
|
|
|
constructor TJclCardinalSortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclCardinalSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclCardinalSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclCardinalSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclCardinalSortedMap then
|
|
begin
|
|
MyDest := TJclCardinalSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.BinarySearch(Key: Cardinal): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.ContainsKey(Key: Cardinal): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.FirstKey: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.Extract(Key: Cardinal): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.GetValue(Key: Cardinal): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.HeadMap(ToKey: Cardinal): IJclCardinalSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclCardinalSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclCardinalSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.KeyOfValue(Value: TObject): Cardinal;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.KeySet: IJclCardinalSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclCardinalArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.LastKey: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.MapEquals(const AMap: IJclCardinalMap): Boolean;
|
|
var
|
|
It: IJclCardinalIterator;
|
|
Index: Integer;
|
|
AKey: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclCardinalSortedMap.PutAll(const AMap: IJclCardinalMap);
|
|
var
|
|
It: IJclCardinalIterator;
|
|
Key: Cardinal;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalSortedMap.PutValue(Key: Cardinal; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.Remove(Key: Cardinal): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.SubMap(FromKey, ToKey: Cardinal): IJclCardinalSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclCardinalSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclCardinalSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.TailMap(FromKey: Cardinal): IJclCardinalSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclCardinalSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclCardinalSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclCardinalSortedMap.Create(FSize, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.FreeKey(var Key: Cardinal): Cardinal;
|
|
begin
|
|
Result := Key;
|
|
Key := 0;
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.KeysCompare(A, B: Cardinal): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclCardinalSortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclInt64SortedMap } ==============================================
|
|
|
|
constructor TJclInt64SortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclInt64SortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclInt64SortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclInt64SortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclInt64SortedMap then
|
|
begin
|
|
MyDest := TJclInt64SortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclInt64SortedMap.BinarySearch(const Key: Int64): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64SortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.ContainsKey(const Key: Int64): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.FirstKey: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.Extract(const Key: Int64): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.GetValue(const Key: Int64): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.HeadMap(const ToKey: Int64): IJclInt64SortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclInt64SortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclInt64SortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.KeyOfValue(Value: TObject): Int64;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := 0;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.KeySet: IJclInt64Set;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclInt64ArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.LastKey: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.MapEquals(const AMap: IJclInt64Map): Boolean;
|
|
var
|
|
It: IJclInt64Iterator;
|
|
Index: Integer;
|
|
AKey: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64SortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclInt64SortedMap.PutAll(const AMap: IJclInt64Map);
|
|
var
|
|
It: IJclInt64Iterator;
|
|
Key: Int64;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64SortedMap.PutValue(const Key: Int64; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, 0) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.Remove(const Key: Int64): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64SortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclInt64SortedMap.SubMap(const FromKey, ToKey: Int64): IJclInt64SortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclInt64SortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclInt64SortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.TailMap(const FromKey: Int64): IJclInt64SortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclInt64SortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclInt64SortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64SortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclInt64SortedMap.Create(FSize, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclInt64SortedMap.FreeKey(var Key: Int64): Int64;
|
|
begin
|
|
Result := Key;
|
|
Key := 0;
|
|
end;
|
|
|
|
function TJclInt64SortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclInt64SortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclInt64SortedMap.KeysCompare(const A, B: Int64): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclInt64SortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclPtrSortedMap } ==============================================
|
|
|
|
constructor TJclPtrSortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclPtrSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclPtrSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclPtrSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclPtrSortedMap then
|
|
begin
|
|
MyDest := TJclPtrSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclPtrSortedMap.BinarySearch(Key: Pointer): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.ContainsKey(Key: Pointer): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.FirstKey: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.Extract(Key: Pointer): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.GetValue(Key: Pointer): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.HeadMap(ToKey: Pointer): IJclPtrSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclPtrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclPtrSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.KeyOfValue(Value: TObject): Pointer;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.KeySet: IJclPtrSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclPtrArraySet.Create(FSize);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.LastKey: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.MapEquals(const AMap: IJclPtrMap): Boolean;
|
|
var
|
|
It: IJclPtrIterator;
|
|
Index: Integer;
|
|
AKey: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclPtrSortedMap.PutAll(const AMap: IJclPtrMap);
|
|
var
|
|
It: IJclPtrIterator;
|
|
Key: Pointer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrSortedMap.PutValue(Key: Pointer; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.Remove(Key: Pointer): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclPtrSortedMap.SubMap(FromKey, ToKey: Pointer): IJclPtrSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclPtrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclPtrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.TailMap(FromKey: Pointer): IJclPtrSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclPtrSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclPtrSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclPtrSortedMap.Create(FSize, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclPtrSortedMap.FreeKey(var Key: Pointer): Pointer;
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
|
|
function TJclPtrSortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclPtrSortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclPtrSortedMap.KeysCompare(A, B: Pointer): Integer;
|
|
begin
|
|
Result := ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclPtrSortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
//=== { TJclSortedMap } ==============================================
|
|
|
|
constructor TJclSortedMap.Create(ACapacity: Integer; AOwnsValues: Boolean; AOwnsKeys: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsKeys := AOwnsKeys;
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclSortedMap.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclSortedMap.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclSortedMap;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclSortedMap then
|
|
begin
|
|
MyDest := TJclSortedMap(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclSortedMap.BinarySearch(Key: TObject): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSortedMap.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.ContainsKey(Key: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.ContainsValue(Value: TObject): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.FirstKey: TObject;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.Extract(Key: TObject): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := nil;
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.GetValue(Key: TObject): TObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := nil;
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.HeadMap(ToKey: TObject): IJclSortedMap;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSortedMap;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.KeyOfValue(Value: TObject): TObject;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := nil;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.KeySet: IJclSet;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArraySet.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.LastKey: TObject;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.MapEquals(const AMap: IJclMap): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
Index: Integer;
|
|
AKey: TObject;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSortedMap.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclSortedMap.PutAll(const AMap: IJclMap);
|
|
var
|
|
It: IJclIterator;
|
|
Key: TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSortedMap.PutValue(Key: TObject; Value: TObject);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, nil) <> 0) and (ValuesCompare(Value, nil) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.Remove(Key: TObject): TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSortedMap.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclSortedMap.SubMap(FromKey, ToKey: TObject): IJclSortedMap;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.TailMap(FromKey: TObject): IJclSortedMap;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclSortedMap;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSortedMap;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.Values: IJclCollection;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := TJclArrayList.Create(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclSortedMap.Create(FSize, False, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclSortedMap.FreeKey(var Key: TObject): TObject;
|
|
begin
|
|
if FOwnsKeys then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Key);
|
|
end
|
|
else
|
|
begin
|
|
Result := Key;
|
|
Key := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclSortedMap.FreeValue(var Value: TObject): TObject;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := nil;
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := nil;
|
|
end;
|
|
end;
|
|
|
|
function TJclSortedMap.GetOWnsKeys: Boolean;
|
|
begin
|
|
Result := FOwnsKeys;
|
|
end;
|
|
|
|
function TJclSortedMap.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
function TJclSortedMap.KeysCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TJclSortedMap.ValuesCompare(A, B: TObject): Integer;
|
|
begin
|
|
if Integer(A) > Integer(B) then
|
|
Result := 1
|
|
else
|
|
if Integer(A) < Integer(B) then
|
|
Result := -1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_GENERICS}
|
|
|
|
//=== { TJclSortedMap<TKey,TValue> } ==============================================
|
|
|
|
constructor TJclSortedMap<TKey,TValue>.Create(ACapacity: Integer; AOwnsValues: Boolean; AOwnsKeys: Boolean);
|
|
begin
|
|
inherited Create();
|
|
FOwnsKeys := AOwnsKeys;
|
|
FOwnsValues := AOwnsValues;
|
|
SetCapacity(ACapacity);
|
|
end;
|
|
|
|
destructor TJclSortedMap<TKey,TValue>.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJclSortedMap<TKey,TValue>.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
MyDest: TJclSortedMap<TKey,TValue>;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclSortedMap<TKey,TValue> then
|
|
begin
|
|
MyDest := TJclSortedMap<TKey,TValue>(Dest);
|
|
MyDest.SetCapacity(FSize);
|
|
MyDest.FEntries := FEntries;
|
|
MyDest.FSize := FSize;
|
|
end;
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.BinarySearch(const Key: TKey): Integer;
|
|
var
|
|
HiPos, LoPos, CompPos: Integer;
|
|
Comp: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
LoPos := 0;
|
|
HiPos := FSize - 1;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
while HiPos >= LoPos do
|
|
begin
|
|
Comp := KeysCompare(FEntries[CompPos].Key, Key);
|
|
if Comp < 0 then
|
|
LoPos := CompPos + 1
|
|
else
|
|
if Comp > 0 then
|
|
HiPos := CompPos - 1
|
|
else
|
|
begin
|
|
HiPos := CompPos;
|
|
LoPos := CompPos + 1;
|
|
end;
|
|
CompPos := (HiPos + LoPos) div 2;
|
|
end;
|
|
Result := HiPos;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSortedMap<TKey,TValue>.Clear;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
for Index := 0 to FSize - 1 do
|
|
begin
|
|
FreeKey(FEntries[Index].Key);
|
|
FreeValue(FEntries[Index].Value);
|
|
end;
|
|
FSize := 0;
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.ContainsKey(const Key: TKey): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.ContainsValue(const Value: TValue): Boolean;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.FirstKey: TKey;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Default(TKey);
|
|
if FSize > 0 then
|
|
Result := FEntries[0].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.Extract(const Key: TKey): TValue;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
Result := FEntries[Index].Value;
|
|
FEntries[Index].Value := Default(TValue);
|
|
FreeKey(FEntries[Index].Key);
|
|
if Index < (FSize - 1) then
|
|
MoveArray(Index + 1, Index, FSize - Index - 1);
|
|
Dec(FSize);
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := Default(TValue);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.GetValue(const Key: TKey): TValue;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Index := BinarySearch(Key);
|
|
Result := Default(TValue);
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
Result := FEntries[Index].Value
|
|
else if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.HeadMap(const ToKey: TKey): IJclSortedMap<TKey,TValue>;
|
|
var
|
|
ToIndex: Integer;
|
|
NewMap: TJclSortedMap<TKey,TValue>;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSortedMap<TKey,TValue>;
|
|
ToIndex := BinarySearch(ToKey);
|
|
if ToIndex >= 0 then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex + 1);
|
|
NewMap.FSize := ToIndex + 1;
|
|
while ToIndex >= 0 do
|
|
begin
|
|
NewMap.FEntries[ToIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.IsEmpty: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := FSize = 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.KeyOfValue(const Value: TValue): TKey;
|
|
var
|
|
Index: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Found := False;
|
|
Result := Default(TKey);
|
|
for Index := 0 to FSize - 1 do
|
|
if ValuesCompare(FEntries[Index].Value, Value) = 0 then
|
|
begin
|
|
Result := FEntries[Index].Key;
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
|
|
if (not Found) and (not FReturnDefaultElements) then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.KeySet: IJclSet<TKey>;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := CreateEmptyArraySet(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Key);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.LastKey: TKey;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Default(TKey);
|
|
if FSize > 0 then
|
|
Result := FEntries[FSize - 1].Key
|
|
else
|
|
if not FReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.MapEquals(const AMap: IJclMap<TKey,TValue>): Boolean;
|
|
var
|
|
It: IJclIterator<TKey>;
|
|
Index: Integer;
|
|
AKey: TKey;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AMap = nil then
|
|
Exit;
|
|
if FSize <> AMap.Size then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
Index := 0;
|
|
while It.HasNext do
|
|
begin
|
|
if Index >= FSize then
|
|
Exit;
|
|
AKey := It.Next;
|
|
if ValuesCompare(AMap.GetValue(AKey), FEntries[Index].Value) <> 0 then
|
|
Exit;
|
|
Inc(Index);
|
|
end;
|
|
Result := True;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSortedMap<TKey,TValue>.MoveArray(FromIndex, ToIndex, Count: Integer);
|
|
begin
|
|
if Count > 0 then
|
|
begin
|
|
Move(FEntries[FromIndex], FEntries[ToIndex], Count * SizeOf(FEntries[0]));
|
|
{ Keep reference counting working }
|
|
if FromIndex < ToIndex then
|
|
begin
|
|
if (ToIndex - FromIndex) < Count then
|
|
FillChar(FEntries[FromIndex], (ToIndex - FromIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end
|
|
else
|
|
if FromIndex > ToIndex then
|
|
begin
|
|
if (FromIndex - ToIndex) < Count then
|
|
FillChar(FEntries[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(FEntries[0]), 0)
|
|
else
|
|
FillChar(FEntries[FromIndex], Count * SizeOf(FEntries[0]), 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclSortedMap<TKey,TValue>.PutAll(const AMap: IJclMap<TKey,TValue>);
|
|
var
|
|
It: IJclIterator<TKey>;
|
|
Key: TKey;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if AMap = nil then
|
|
Exit;
|
|
It := AMap.KeySet.First;
|
|
while It.HasNext do
|
|
begin
|
|
Key := It.Next;
|
|
PutValue(Key, AMap.GetValue(Key));
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSortedMap<TKey,TValue>.PutValue(const Key: TKey; const Value: TValue);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FAllowDefaultElements or ((KeysCompare(Key, Default(TKey)) <> 0) and (ValuesCompare(Value, Default(TValue)) <> 0)) then
|
|
begin
|
|
Index := BinarySearch(Key);
|
|
|
|
if (Index >= 0) and (KeysCompare(FEntries[Index].Key, Key) = 0) then
|
|
begin
|
|
FreeValue(FEntries[Index].Value);
|
|
FEntries[Index].Value := Value;
|
|
end
|
|
else
|
|
begin
|
|
if FSize = FCapacity then
|
|
AutoGrow;
|
|
if FSize < FCapacity then
|
|
begin
|
|
Inc(Index);
|
|
if (Index < FSize) and (KeysCompare(FEntries[Index].Key, Key) <> 0) then
|
|
MoveArray(Index, Index + 1, FSize - Index);
|
|
FEntries[Index].Key := Key;
|
|
FEntries[Index].Value := Value;
|
|
Inc(FSize);
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.Remove(const Key: TKey): TValue;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(Key);
|
|
Result := FreeValue(Result);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSortedMap<TKey,TValue>.SetCapacity(Value: Integer);
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if FSize <= Value then
|
|
begin
|
|
SetLength(FEntries, Value);
|
|
inherited SetCapacity(Value);
|
|
end
|
|
else
|
|
raise EJclOperationNotSupportedError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.SubMap(const FromKey, ToKey: TKey): IJclSortedMap<TKey,TValue>;
|
|
var
|
|
FromIndex, ToIndex: Integer;
|
|
NewMap: TJclSortedMap<TKey,TValue>;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSortedMap<TKey,TValue>;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
ToIndex := BinarySearch(ToKey);
|
|
if (FromIndex >= 0) and (FromIndex <= ToIndex) then
|
|
begin
|
|
NewMap.SetCapacity(ToIndex - FromIndex + 1);
|
|
NewMap.FSize := ToIndex - FromIndex + 1;
|
|
while ToIndex >= FromIndex do
|
|
begin
|
|
NewMap.FEntries[ToIndex - FromIndex] := FEntries[ToIndex];
|
|
Dec(ToIndex);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.TailMap(const FromKey: TKey): IJclSortedMap<TKey,TValue>;
|
|
var
|
|
FromIndex, Index: Integer;
|
|
NewMap: TJclSortedMap<TKey,TValue>;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
NewMap := CreateEmptyContainer as TJclSortedMap<TKey,TValue>;
|
|
FromIndex := BinarySearch(FromKey);
|
|
if (FromIndex = -1) or (KeysCompare(FEntries[FromIndex].Key, FromKey) < 0) then
|
|
Inc(FromIndex);
|
|
if (FromIndex >= 0) and (FromIndex < FSize) then
|
|
begin
|
|
NewMap.SetCapacity(FSize - FromIndex);
|
|
NewMap.FSize := FSize - FromIndex;
|
|
Index := FromIndex;
|
|
while Index < FSize do
|
|
begin
|
|
NewMap.FEntries[Index - FromIndex] := FEntries[Index];
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
Result := NewMap;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.Values: IJclCollection<TValue>;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := CreateEmptyArrayList(FSize, False);
|
|
for Index := 0 to FSize - 1 do
|
|
Result.Add(FEntries[Index].Value);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.FreeKey(var Key: TKey): TKey;
|
|
begin
|
|
if FOwnsKeys then
|
|
begin
|
|
Result := Default(TKey);
|
|
FreeAndNil(Key);
|
|
end
|
|
else
|
|
begin
|
|
Result := Key;
|
|
Key := Default(TKey);
|
|
end;
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.FreeValue(var Value: TValue): TValue;
|
|
begin
|
|
if FOwnsValues then
|
|
begin
|
|
Result := Default(TValue);
|
|
FreeAndNil(Value);
|
|
end
|
|
else
|
|
begin
|
|
Result := Value;
|
|
Value := Default(TValue);
|
|
end;
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.GetOWnsKeys: Boolean;
|
|
begin
|
|
Result := FOwnsKeys;
|
|
end;
|
|
|
|
function TJclSortedMap<TKey,TValue>.GetOwnsValues: Boolean;
|
|
begin
|
|
Result := FOwnsValues;
|
|
end;
|
|
|
|
//=== { TJclSortedMapE<TKey, TValue> } =======================================
|
|
|
|
constructor TJclSortedMapE<TKey, TValue>.Create(const AKeyComparer: IJclComparer<TKey>;
|
|
const AValueComparer: IJclComparer<TValue>; const AValueEqualityComparer: IJclEqualityComparer<TValue>; ACapacity: Integer;
|
|
AOwnsValues: Boolean; AOwnsKeys: Boolean);
|
|
begin
|
|
inherited Create(ACapacity, AOwnsValues, AOwnsKeys);
|
|
FKeyComparer := AKeyComparer;
|
|
FValueComparer := AValueComparer;
|
|
FValueEqualityComparer := AValueEqualityComparer;
|
|
end;
|
|
|
|
procedure TJclSortedMapE<TKey, TValue>.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclSortedMapE<TKey, TValue>;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclSortedMapE<TKey, TValue> then
|
|
begin
|
|
ADest := TJclSortedMapE<TKey, TValue>(Dest);
|
|
ADest.FKeyComparer := FKeyComparer;
|
|
ADest.FValueComparer := FValueComparer;
|
|
end;
|
|
end;
|
|
|
|
function TJclSortedMapE<TKey, TValue>.CreateEmptyArrayList(ACapacity: Integer;
|
|
AOwnsObjects: Boolean): IJclCollection<TValue>;
|
|
begin
|
|
if FValueEqualityComparer = nil then
|
|
raise EJclNoEqualityComparerError.Create;
|
|
Result := TArrayList.Create(FValueEqualityComparer, ACapacity, AOwnsObjects);
|
|
end;
|
|
|
|
function TJclSortedMapE<TKey, TValue>.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclSortedMapE<TKey, TValue>.Create(FKeyComparer, FValueComparer, FValueEqualityComparer, FCapacity,
|
|
FOwnsValues, FOwnsKeys);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclSortedMapE<TKey, TValue>.CreateEmptyArraySet(ACapacity: Integer; AOwnsObjects: Boolean): IJclSet<TKey>;
|
|
begin
|
|
Result := TArraySet.Create(FKeyComparer, FCapacity, AOwnsObjects);
|
|
end;
|
|
|
|
function TJclSortedMapE<TKey, TValue>.KeysCompare(const A, B: TKey): Integer;
|
|
begin
|
|
if KeyComparer = nil then
|
|
raise EJclNoComparerError.Create;
|
|
Result := KeyComparer.Compare(A, B);
|
|
end;
|
|
|
|
function TJclSortedMapE<TKey, TValue>.ValuesCompare(const A, B: TValue): Integer;
|
|
begin
|
|
if ValueComparer = nil then
|
|
raise EJclNoComparerError.Create;
|
|
Result := ValueComparer.Compare(A, B);
|
|
end;
|
|
|
|
//=== { TJclSortedMapF<TKey, TValue> } =======================================
|
|
|
|
constructor TJclSortedMapF<TKey, TValue>.Create(AKeyCompare: TCompare<TKey>; AValueCompare: TCompare<TValue>;
|
|
AValueEqualityCompare: TEqualityCompare<TValue>; ACapacity: Integer; AOwnsValues: Boolean; AOwnsKeys: Boolean);
|
|
begin
|
|
inherited Create(ACapacity, AOwnsValues, AOwnsKeys);
|
|
FKeyCompare := AKeyCompare;
|
|
FValueCompare := AValueCompare;
|
|
FValueEqualityCompare := AValueEqualityCompare;
|
|
end;
|
|
|
|
procedure TJclSortedMapF<TKey, TValue>.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclSortedMapF<TKey, TValue>;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclSortedMapF<TKey, TValue> then
|
|
begin
|
|
ADest := TJclSortedMapF<TKey, TValue>(Dest);
|
|
ADest.FKeyCompare := FKeyCompare;
|
|
ADest.FValueCompare := FValueCompare;
|
|
end;
|
|
end;
|
|
|
|
function TJclSortedMapF<TKey, TValue>.CreateEmptyArrayList(ACapacity: Integer;
|
|
AOwnsObjects: Boolean): IJclCollection<TValue>;
|
|
begin
|
|
if not Assigned(FValueEqualityCompare) then
|
|
raise EJclNoEqualityComparerError.Create;
|
|
Result := TArrayList.Create(FValueEqualityCompare, ACapacity, AOwnsObjects);
|
|
end;
|
|
|
|
function TJclSortedMapF<TKey, TValue>.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclSortedMapF<TKey, TValue>.Create(FKeyCompare, FValueCompare, FValueEqualityCompare, FCapacity,
|
|
FOwnsValues, FOwnsKeys);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclSortedMapF<TKey, TValue>.CreateEmptyArraySet(ACapacity: Integer; AOwnsObjects: Boolean): IJclSet<TKey>;
|
|
begin
|
|
Result := TArraySet.Create(FKeyCompare, FCapacity, AOwnsObjects);
|
|
end;
|
|
|
|
function TJclSortedMapF<TKey, TValue>.KeysCompare(const A, B: TKey): Integer;
|
|
begin
|
|
if not Assigned(KeyCompare) then
|
|
raise EJclNoComparerError.Create;
|
|
Result := KeyCompare(A, B);
|
|
end;
|
|
|
|
function TJclSortedMapF<TKey, TValue>.ValuesCompare(const A, B: TValue): Integer;
|
|
begin
|
|
if not Assigned(ValueCompare) then
|
|
raise EJclNoComparerError.Create;
|
|
Result := ValueCompare(A, B);
|
|
end;
|
|
|
|
//=== { TJclSortedMapI<TKey, TValue> } =======================================
|
|
|
|
function TJclSortedMapI<TKey, TValue>.CreateEmptyArrayList(ACapacity: Integer;
|
|
AOwnsObjects: Boolean): IJclCollection<TValue>;
|
|
begin
|
|
Result := TArrayList.Create(ACapacity, AOwnsObjects);
|
|
end;
|
|
|
|
function TJclSortedMapI<TKey, TValue>.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclSortedMapI<TKey, TValue>.Create(FCapacity, FOwnsValues, FOwnsKeys);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclSortedMapI<TKey, TValue>.CreateEmptyArraySet(ACapacity: Integer; AOwnsObjects: Boolean): IJclSet<TKey>;
|
|
begin
|
|
Result := TArraySet.Create(FCapacity, AOwnsObjects);
|
|
end;
|
|
|
|
function TJclSortedMapI<TKey, TValue>.KeysCompare(const A, B: TKey): Integer;
|
|
begin
|
|
Result := A.CompareTo(B);
|
|
end;
|
|
|
|
function TJclSortedMapI<TKey, TValue>.ValuesCompare(const A, B: TValue): Integer;
|
|
begin
|
|
Result := A.CompareTo(B);
|
|
end;
|
|
|
|
{$ENDIF SUPPORTS_GENERICS}
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
initialization
|
|
RegisterUnitVersion(HInstance, UnitVersioning);
|
|
|
|
finalization
|
|
UnregisterUnitVersion(HInstance);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
end.
|