home *** CD-ROM | disk | FTP | other *** search
/ Chip 2003 January / Chip_2003-01_cd1.bin / zkuste / delphi / unity / d56 / FNDUTL.ZIP / Datastructs / cDictionaries.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-10-29  |  126.0 KB  |  3,734 lines

  1. {$INCLUDE ..\cDefines.inc}
  2. unit cDictionaries;
  3.  
  4. {                                                                              }
  5. {                     Data structures: Dictionaries v3.10                      }
  6. {                                                                              }
  7. {      This unit is copyright ⌐ 1999-2002 by David Butler (david@e.co.za)      }
  8. {                                                                              }
  9. {                  This unit is part of Delphi Fundamentals.                   }
  10. {                 Its original file name is cDictionaries.pas                  }
  11. {                     It was generated 29 Oct 2002 02:22.                      }
  12. {       The latest version is available from the Fundamentals home page        }
  13. {                     http://fundementals.sourceforge.net/                     }
  14. {                                                                              }
  15. {                I invite you to use this unit, free of charge.                }
  16. {        I invite you to distibute this unit, but it must be for free.         }
  17. {             I also invite you to contribute to its development,              }
  18. {             but do not distribute a modified copy of this file.              }
  19. {                                                                              }
  20. {          A forum is available on SourceForge for general discussion          }
  21. {             http://sourceforge.net/forum/forum.php?forum_id=2117             }
  22. {                                                                              }
  23. {                                                                              }
  24. { Revision history:                                                            }
  25. {   [ cDataStructs ]                                                           }
  26. {   1999/11/12  0.01  Split cTypes from cDataStruct and cHolder.               }
  27. {   2000/06/16  1.02  Added ADictionary.                                       }
  28. {   2000/06/14  1.03  Converted cDataStructs to template.                      }
  29. {   2000/06/16  1.04  Added dictionaries stored in AArrays.                    }
  30. {   2000/07/07  1.05  Added ATypeDictionary.                                   }
  31. {   2001/01/19  1.06  Added THashedStringDictionary.                           }
  32. {   2001/04/13  1.07  Added TObjectDictionary.                                 }
  33. {   2001/08/20  2.08  Merged cTypes and cDataStructs to allow object           }
  34. {                     interface implementation in base classes.                }
  35. {   2002/01/14  2.09  Replaced AllowDuplicates property with DuplicatesAction  }
  36. {                     property.                                                }
  37. {   [ cDictionaries ]                                                          }
  38. {   2002/05/15  3.10  Created cDictionaries unit from cDataStructs.            }
  39. {                     Refactored for Fundamentals 3.                           }
  40. {                                                                              }
  41.  
  42. interface
  43.  
  44. uses
  45.   // Delphi
  46.   SysUtils,
  47.  
  48.   // Fundamentals
  49.   cUtils,
  50.   cTypes,
  51.   cArrays;
  52.  
  53. const
  54.   UnitName      = 'cDictionaries';
  55.   UnitVersion   = '3.10';
  56.   UnitDesc      = 'Data structures: Dictionaries';
  57.   UnitCopyright = '(c) 1999-2002 David Butler';
  58.  
  59.  
  60.  
  61. {                                                                              }
  62. { DICTIONARY BASE CLASSES                                                      }
  63. {   Classes with the A-prefix are Abstract base classes. They define the       }
  64. {   interface for the type and must never be instanciated.                     }
  65. {   Instead, create one of the implementation classes (T-prefix).              }
  66. {                                                                              }
  67.  
  68.  
  69.  
  70. {                                                                              }
  71. { ADictionary                                                                  }
  72. {   Base class for a dictionary (key-value pair where the key is a string).    }
  73. {                                                                              }
  74. type
  75.   TDictionaryDuplicatesAction = (ddError,    // raises an exception on duplicate keys
  76.                                  ddAccept,   // allow duplicate keys
  77.                                  ddIgnore);  // silently discard duplicates
  78.   ADictionary = class (AType)
  79.     protected
  80.     Procedure DictionaryError (const Msg : String);
  81.     Procedure KeyNotFoundError (const Key : String);
  82.  
  83.     Function  GetAddOnSet : Boolean; virtual; abstract;
  84.     Procedure SetAddOnSet (const AddOnSet : Boolean); virtual; abstract;
  85.     Function  GetDuplicatesAction : TDictionaryDuplicatesAction; virtual; abstract;
  86.     Procedure SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction); virtual; abstract;
  87.     Function  GetKeysCaseSensitive : Boolean; virtual; abstract;
  88.  
  89.     public
  90.     Procedure Delete (const Key : String); virtual; abstract;
  91.     Function  HasKey (const Key : String) : Boolean; virtual; abstract;
  92.     Procedure Rename (const Key, NewKey : String); virtual; abstract;
  93.  
  94.     Function  Count : Integer; virtual; abstract;
  95.     Function  GetKeyByIndex (const Idx : Integer) : String; virtual; abstract;
  96.  
  97.     Property  AddOnSet : Boolean read GetAddOnSet write SetAddOnSet;
  98.     Property  DuplicatesAction : TDictionaryDuplicatesAction read GetDuplicatesAction write SetDuplicatesAction;
  99.     Property  KeysCaseSensitive : Boolean read GetKeysCaseSensitive;
  100.   end;
  101.   EDictionary = class (EType);
  102.  
  103.  
  104.  
  105. {                                                                              }
  106. { ALongIntDictionary                                                           }
  107. {   A Dictionary with LongInt values and String keys.                          }
  108. {                                                                              }
  109. type
  110.   ALongIntDictionary = class (ADictionary)
  111.     protected
  112.     Function  GetAsString : String; override;
  113.  
  114.     Function  GetItem (const Key : String) : LongInt; virtual;
  115.     Procedure SetItem (const Key : String; const Value : LongInt); virtual; abstract;
  116.  
  117.     public
  118.     { AType implementations                                                    }
  119.     Procedure Assign (const Source : TObject); override;
  120.  
  121.     { ALongIntDictionary interface                                            }
  122.     Property  Item [const Key : String] : LongInt read GetItem write SetItem; default;
  123.     Procedure Add (const Key : String; const Value : LongInt); virtual; abstract;
  124.  
  125.     Function  GetItemByIndex (const Idx : Integer) : LongInt; virtual; abstract;
  126.     Function  LocateItem (const Key : String; var Value : LongInt) : Integer; virtual; abstract;
  127.     Function  LocateNext (const Key : String; const Idx : Integer;
  128.               var Value : LongInt) : Integer; virtual; abstract;
  129.   end;
  130.   ELongIntDictionary = class (EDictionary);
  131.  
  132.  
  133.  
  134. {                                                                              }
  135. { AIntegerDictionary                                                           }
  136. {                                                                              }
  137. type
  138.   AIntegerDictionary = ALongIntDictionary;
  139.  
  140.  
  141.  
  142. {                                                                              }
  143. { ALongWordDictionary                                                          }
  144. {   A Dictionary with LongWord values and String keys.                         }
  145. {                                                                              }
  146. type
  147.   ALongWordDictionary = class (ADictionary)
  148.     protected
  149.     Function  GetAsString : String; override;
  150.  
  151.     Function  GetItem (const Key : String) : LongWord; virtual;
  152.     Procedure SetItem (const Key : String; const Value : LongWord); virtual; abstract;
  153.  
  154.     public
  155.     { AType implementations                                                    }
  156.     Procedure Assign (const Source : TObject); override;
  157.  
  158.     { ALongWordDictionary interface                                            }
  159.     Property  Item [const Key : String] : LongWord read GetItem write SetItem; default;
  160.     Procedure Add (const Key : String; const Value : LongWord); virtual; abstract;
  161.  
  162.     Function  GetItemByIndex (const Idx : Integer) : LongWord; virtual; abstract;
  163.     Function  LocateItem (const Key : String; var Value : LongWord) : Integer; virtual; abstract;
  164.     Function  LocateNext (const Key : String; const Idx : Integer;
  165.               var Value : LongWord) : Integer; virtual; abstract;
  166.   end;
  167.   ELongWordDictionary = class (EDictionary);
  168.  
  169.  
  170.  
  171. {                                                                              }
  172. { ACardinalArray                                                               }
  173. {                                                                              }
  174. type
  175.   ACardinalDictionary = ALongWordDictionary;
  176.  
  177.  
  178.  
  179. {                                                                              }
  180. { AInt64Dictionary                                                             }
  181. {   A Dictionary with Int64 values and String keys.                            }
  182. {                                                                              }
  183. type
  184.   AInt64Dictionary = class (ADictionary)
  185.     protected
  186.     Function  GetAsString : String; override;
  187.  
  188.     Function  GetItem (const Key : String) : Int64; virtual;
  189.     Procedure SetItem (const Key : String; const Value : Int64); virtual; abstract;
  190.  
  191.     public
  192.     { AType implementations                                                    }
  193.     Procedure Assign (const Source : TObject); override;
  194.  
  195.     { AInt64Dictionary interface                                            }
  196.     Property  Item [const Key : String] : Int64 read GetItem write SetItem; default;
  197.     Procedure Add (const Key : String; const Value : Int64); virtual; abstract;
  198.  
  199.     Function  GetItemByIndex (const Idx : Integer) : Int64; virtual; abstract;
  200.     Function  LocateItem (const Key : String; var Value : Int64) : Integer; virtual; abstract;
  201.     Function  LocateNext (const Key : String; const Idx : Integer;
  202.               var Value : Int64) : Integer; virtual; abstract;
  203.   end;
  204.   EInt64Dictionary = class (EDictionary);
  205.  
  206.  
  207.  
  208. {                                                                              }
  209. { ASingleDictionary                                                            }
  210. {   A Dictionary with Single values and String keys.                           }
  211. {                                                                              }
  212. type
  213.   ASingleDictionary = class (ADictionary)
  214.     protected
  215.     Function  GetAsString : String; override;
  216.  
  217.     Function  GetItem (const Key : String) : Single; virtual;
  218.     Procedure SetItem (const Key : String; const Value : Single); virtual; abstract;
  219.  
  220.     public
  221.     { AType implementations                                                    }
  222.     Procedure Assign (const Source : TObject); override;
  223.  
  224.     { ASingleDictionary interface                                            }
  225.     Property  Item [const Key : String] : Single read GetItem write SetItem; default;
  226.     Procedure Add (const Key : String; const Value : Single); virtual; abstract;
  227.  
  228.     Function  GetItemByIndex (const Idx : Integer) : Single; virtual; abstract;
  229.     Function  LocateItem (const Key : String; var Value : Single) : Integer; virtual; abstract;
  230.     Function  LocateNext (const Key : String; const Idx : Integer;
  231.               var Value : Single) : Integer; virtual; abstract;
  232.   end;
  233.   ESingleDictionary = class (EDictionary);
  234.  
  235.  
  236.  
  237. {                                                                              }
  238. { ADoubleDictionary                                                            }
  239. {   A Dictionary with Double values and String keys.                           }
  240. {                                                                              }
  241. type
  242.   ADoubleDictionary = class (ADictionary)
  243.     protected
  244.     Function  GetAsString : String; override;
  245.  
  246.     Function  GetItem (const Key : String) : Double; virtual;
  247.     Procedure SetItem (const Key : String; const Value : Double); virtual; abstract;
  248.  
  249.     public
  250.     { AType implementations                                                    }
  251.     Procedure Assign (const Source : TObject); override;
  252.  
  253.     { ADoubleDictionary interface                                            }
  254.     Property  Item [const Key : String] : Double read GetItem write SetItem; default;
  255.     Procedure Add (const Key : String; const Value : Double); virtual; abstract;
  256.  
  257.     Function  GetItemByIndex (const Idx : Integer) : Double; virtual; abstract;
  258.     Function  LocateItem (const Key : String; var Value : Double) : Integer; virtual; abstract;
  259.     Function  LocateNext (const Key : String; const Idx : Integer;
  260.               var Value : Double) : Integer; virtual; abstract;
  261.   end;
  262.   EDoubleDictionary = class (EDictionary);
  263.  
  264.  
  265.  
  266. {                                                                              }
  267. { AExtendedDictionary                                                          }
  268. {   A Dictionary with Extended values and String keys.                         }
  269. {                                                                              }
  270. type
  271.   AExtendedDictionary = class (ADictionary)
  272.     protected
  273.     Function  GetAsString : String; override;
  274.  
  275.     Function  GetItem (const Key : String) : Extended; virtual;
  276.     Procedure SetItem (const Key : String; const Value : Extended); virtual; abstract;
  277.  
  278.     public
  279.     { AType implementations                                                    }
  280.     Procedure Assign (const Source : TObject); override;
  281.  
  282.     { AExtendedDictionary interface                                            }
  283.     Property  Item [const Key : String] : Extended read GetItem write SetItem; default;
  284.     Procedure Add (const Key : String; const Value : Extended); virtual; abstract;
  285.  
  286.     Function  GetItemByIndex (const Idx : Integer) : Extended; virtual; abstract;
  287.     Function  LocateItem (const Key : String; var Value : Extended) : Integer; virtual; abstract;
  288.     Function  LocateNext (const Key : String; const Idx : Integer;
  289.               var Value : Extended) : Integer; virtual; abstract;
  290.   end;
  291.   EExtendedDictionary = class (EDictionary);
  292.  
  293.  
  294.  
  295. {                                                                              }
  296. { APointerDictionary                                                           }
  297. {   A Dictionary with Pointer values and String keys.                          }
  298. {                                                                              }
  299. type
  300.   APointerDictionary = class (ADictionary)
  301.     protected
  302.     Function  GetAsString : String; override;
  303.  
  304.     Function  GetItem (const Key : String) : Pointer; virtual;
  305.     Procedure SetItem (const Key : String; const Value : Pointer); virtual; abstract;
  306.  
  307.     public
  308.     { AType implementations                                                    }
  309.     Procedure Assign (const Source : TObject); override;
  310.  
  311.     { APointerDictionary interface                                            }
  312.     Property  Item [const Key : String] : Pointer read GetItem write SetItem; default;
  313.     Procedure Add (const Key : String; const Value : Pointer); virtual; abstract;
  314.  
  315.     Function  GetItemByIndex (const Idx : Integer) : Pointer; virtual; abstract;
  316.     Function  LocateItem (const Key : String; var Value : Pointer) : Integer; virtual; abstract;
  317.     Function  LocateNext (const Key : String; const Idx : Integer;
  318.               var Value : Pointer) : Integer; virtual; abstract;
  319.   end;
  320.   EPointerDictionary = class (EDictionary);
  321.  
  322.  
  323.  
  324. {                                                                              }
  325. { AStringDictionary                                                            }
  326. {   A Dictionary with String values and String keys.                           }
  327. {                                                                              }
  328. type
  329.   AStringDictionary = class (ADictionary)
  330.     protected
  331.     Function  GetAsString : String; override;
  332.  
  333.     Function  GetItem (const Key : String) : String; virtual;
  334.     Procedure SetItem (const Key : String; const Value : String); virtual; abstract;
  335.  
  336.     public
  337.     { AType implementations                                                    }
  338.     Procedure Assign (const Source : TObject); override;
  339.  
  340.     { AStringDictionary interface                                            }
  341.     Property  Item [const Key : String] : String read GetItem write SetItem; default;
  342.     Procedure Add (const Key : String; const Value : String); virtual; abstract;
  343.  
  344.     Function  GetItemByIndex (const Idx : Integer) : String; virtual; abstract;
  345.     Function  LocateItem (const Key : String; var Value : String) : Integer; virtual; abstract;
  346.     Function  LocateNext (const Key : String; const Idx : Integer;
  347.               var Value : String) : Integer; virtual; abstract;
  348.  
  349.     Function  GetItemLength (const Key : String) : Integer; virtual;
  350.     Function  GetTotalLength : Int64; virtual;
  351.   end;
  352.   EStringDictionary = class (EDictionary);
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359. {                                                                              }
  360. { AObjectDictionary                                                            }
  361. {                                                                              }
  362. type
  363.   AObjectDictionary = class (ADictionary)
  364.     protected
  365.     Function  GetItem (const Key : String) : TObject; virtual;
  366.     Procedure SetItem (const Key : String; const Value : TObject); virtual; abstract;
  367.     Function  GetIsItemOwner : Boolean; virtual; abstract;
  368.     Procedure SetIsItemOwner (const IsItemOwner : Boolean); virtual; abstract;
  369.  
  370.     public
  371.     { AType implementation                                                     }
  372.     Function  GetAsString : String; override;
  373.     Procedure Clear; override;
  374.     Procedure Assign (const Source : TObject); reintroduce; overload; override;
  375.  
  376.     { AObjectDictionary interface                                              }
  377.     Procedure Add (const Key : String; const Value : TObject); virtual; abstract;
  378.     Property  Item [const Key : String] : TObject read GetItem write SetItem; default;
  379.  
  380.     Function  GetItemByIndex (const Idx : Integer) : TObject; virtual; abstract;
  381.     Function  LocateItem (const Key : String; var Value : TObject) : Integer; virtual; abstract;
  382.     Function  LocateNext (const Key : String; const Idx : Integer;
  383.               var Value : TObject) : Integer; virtual; abstract;
  384.  
  385.     Property  IsItemOwner : Boolean read GetIsItemOwner write SetIsItemOwner;
  386.     Function  ReleaseItem (const Key : String) : TObject; virtual; abstract;
  387.     Procedure ReleaseItems; virtual; abstract;
  388.     Procedure FreeItems; virtual; abstract;
  389.   end;
  390.   EObjectDictionary = class (EDictionary);
  391.  
  392.  
  393.  
  394. {                                                                              }
  395. { DICTIONARY IMPLEMENTATIONS                                                   }
  396. {                                                                              }
  397.  
  398.  
  399.  
  400. {                                                                              }
  401. { TLongIntDictionary                                                           }
  402. {   Implements ALongIntDictionary using arrays.                                }
  403. {   A 'chained-hash' lookup table is used for quick access.                    }
  404. {                                                                              }
  405. type
  406.   TLongIntDictionary = class (ALongIntDictionary)
  407.     protected
  408.     FKeys             : AStringArray;
  409.     FValues           : ALongIntArray;
  410.     FLookup           : Array of IntegerArray;
  411.     FCaseSensitive    : Boolean;
  412.     FAddOnSet         : Boolean;
  413.     FDuplicatesAction : TDictionaryDuplicatesAction;
  414.  
  415.     Function  LocateKey (const Key : String; var LookupIdx : Integer;
  416.               const ErrorIfNotFound : Boolean) : Integer;
  417.     Function  KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  418.     Procedure DeleteByIndex (const Idx : Integer; const Hash : Integer = -1);
  419.     Procedure Rehash;
  420.     Function  GetHashTableSize : Integer;
  421.     Procedure IndexError;
  422.  
  423.     { ADictionary implementations                                              }
  424.     Function  GetKeysCaseSensitive : Boolean; override;
  425.     Function  GetAddOnSet : Boolean; override;
  426.     Procedure SetAddOnSet (const AddOnSet : Boolean); override;
  427.     Function  GetDuplicatesAction : TDictionaryDuplicatesAction; override;
  428.     Procedure SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction); override;
  429.  
  430.     { ALongIntDictionary implementations                                    }
  431.     Procedure SetItem (const Key : String; const Value : LongInt); override;
  432.  
  433.     public
  434.     { TLongIntDictionary interface                                            }
  435.     Constructor Create;
  436.     Constructor CreateEx (const Keys : AStringArray = nil; const Values : ALongIntArray = nil;
  437.                 const KeysCaseSensitive : Boolean = True;
  438.                 const AddOnSet : Boolean = True;
  439.                 const DuplicatesAction : TDictionaryDuplicatesAction = ddAccept);
  440.     Destructor Destroy; override;
  441.  
  442.     { AType implementations                                                    }
  443.     class Function CreateInstance : AType; override;
  444.     Procedure Clear; override;
  445.  
  446.     { ADictionary implementations                                              }
  447.     Procedure Delete (const Key : String); override;
  448.     Function  HasKey (const Key : String) : Boolean; override;
  449.     Procedure Rename (const Key : String; const NewKey : String); override;
  450.     Function  Count : Integer; override;
  451.     Function  GetKeyByIndex (const Idx : Integer) : String; override;
  452.  
  453.     { ALongIntDictionary implementations                                    }
  454.     Procedure Add (const Key : String; const Value : LongInt); override;
  455.     Function  GetItemByIndex (const Idx : Integer) : LongInt; override;
  456.     Procedure SetItemByIndex (const Idx : Integer; const Value : LongInt);
  457.     Function  LocateItem (const Key : String; var Value : LongInt) : Integer; override;
  458.     Function  LocateNext (const Key : String; const Idx : Integer;
  459.               var Value : LongInt) : Integer; override;
  460.  
  461.     { TLongIntDictionary interface                                            }
  462.     Property  HashTableSize : Integer read GetHashTableSize;
  463.     Procedure DeleteItemByIndex (const Idx : Integer);
  464.   end;
  465.  
  466.  
  467.  
  468. {                                                                              }
  469. { TIntegerDictionary                                                           }
  470. {                                                                              }
  471. type
  472.   TIntegerDictionary = TLongIntDictionary;
  473.  
  474.  
  475.  
  476. {                                                                              }
  477. { TLongWordDictionary                                                          }
  478. {   Implements ALongWordDictionary using arrays.                               }
  479. {   A 'chained-hash' lookup table is used for quick access.                    }
  480. {                                                                              }
  481. type
  482.   TLongWordDictionary = class (ALongWordDictionary)
  483.     protected
  484.     FKeys             : AStringArray;
  485.     FValues           : ALongWordArray;
  486.     FLookup           : Array of IntegerArray;
  487.     FCaseSensitive    : Boolean;
  488.     FAddOnSet         : Boolean;
  489.     FDuplicatesAction : TDictionaryDuplicatesAction;
  490.  
  491.     Function  LocateKey (const Key : String; var LookupIdx : Integer;
  492.               const ErrorIfNotFound : Boolean) : Integer;
  493.     Function  KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  494.     Procedure DeleteByIndex (const Idx : Integer; const Hash : Integer = -1);
  495.     Procedure Rehash;
  496.     Function  GetHashTableSize : Integer;
  497.     Procedure IndexError;
  498.  
  499.     { ADictionary implementations                                              }
  500.     Function  GetKeysCaseSensitive : Boolean; override;
  501.     Function  GetAddOnSet : Boolean; override;
  502.     Procedure SetAddOnSet (const AddOnSet : Boolean); override;
  503.     Function  GetDuplicatesAction : TDictionaryDuplicatesAction; override;
  504.     Procedure SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction); override;
  505.  
  506.     { ALongWordDictionary implementations                                    }
  507.     Procedure SetItem (const Key : String; const Value : LongWord); override;
  508.  
  509.     public
  510.     { TLongWordDictionary interface                                            }
  511.     Constructor Create;
  512.     Constructor CreateEx (const Keys : AStringArray = nil; const Values : ALongWordArray = nil;
  513.                 const KeysCaseSensitive : Boolean = True;
  514.                 const AddOnSet : Boolean = True;
  515.                 const DuplicatesAction : TDictionaryDuplicatesAction = ddAccept);
  516.     Destructor Destroy; override;
  517.  
  518.     { AType implementations                                                    }
  519.     class Function CreateInstance : AType; override;
  520.     Procedure Clear; override;
  521.  
  522.     { ADictionary implementations                                              }
  523.     Procedure Delete (const Key : String); override;
  524.     Function  HasKey (const Key : String) : Boolean; override;
  525.     Procedure Rename (const Key : String; const NewKey : String); override;
  526.     Function  Count : Integer; override;
  527.     Function  GetKeyByIndex (const Idx : Integer) : String; override;
  528.  
  529.     { ALongWordDictionary implementations                                    }
  530.     Procedure Add (const Key : String; const Value : LongWord); override;
  531.     Function  GetItemByIndex (const Idx : Integer) : LongWord; override;
  532.     Procedure SetItemByIndex (const Idx : Integer; const Value : LongWord);
  533.     Function  LocateItem (const Key : String; var Value : LongWord) : Integer; override;
  534.     Function  LocateNext (const Key : String; const Idx : Integer;
  535.               var Value : LongWord) : Integer; override;
  536.  
  537.     { TLongWordDictionary interface                                            }
  538.     Property  HashTableSize : Integer read GetHashTableSize;
  539.     Procedure DeleteItemByIndex (const Idx : Integer);
  540.   end;
  541.  
  542.  
  543.  
  544. {                                                                              }
  545. { TCardinalDictionary                                                          }
  546. {                                                                              }
  547. type
  548.   TCardinalDictionary = TLongWordDictionary;
  549.  
  550.  
  551.  
  552. {                                                                              }
  553. { TInt64Dictionary                                                             }
  554. {   Implements AInt64Dictionary using arrays.                                  }
  555. {   A 'chained-hash' lookup table is used for quick access.                    }
  556. {                                                                              }
  557. type
  558.   TInt64Dictionary = class (AInt64Dictionary)
  559.     protected
  560.     FKeys             : AStringArray;
  561.     FValues           : AInt64Array;
  562.     FLookup           : Array of IntegerArray;
  563.     FCaseSensitive    : Boolean;
  564.     FAddOnSet         : Boolean;
  565.     FDuplicatesAction : TDictionaryDuplicatesAction;
  566.  
  567.     Function  LocateKey (const Key : String; var LookupIdx : Integer;
  568.               const ErrorIfNotFound : Boolean) : Integer;
  569.     Function  KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  570.     Procedure DeleteByIndex (const Idx : Integer; const Hash : Integer = -1);
  571.     Procedure Rehash;
  572.     Function  GetHashTableSize : Integer;
  573.     Procedure IndexError;
  574.  
  575.     { ADictionary implementations                                              }
  576.     Function  GetKeysCaseSensitive : Boolean; override;
  577.     Function  GetAddOnSet : Boolean; override;
  578.     Procedure SetAddOnSet (const AddOnSet : Boolean); override;
  579.     Function  GetDuplicatesAction : TDictionaryDuplicatesAction; override;
  580.     Procedure SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction); override;
  581.  
  582.     { AInt64Dictionary implementations                                    }
  583.     Procedure SetItem (const Key : String; const Value : Int64); override;
  584.  
  585.     public
  586.     { TInt64Dictionary interface                                            }
  587.     Constructor Create;
  588.     Constructor CreateEx (const Keys : AStringArray = nil; const Values : AInt64Array = nil;
  589.                 const KeysCaseSensitive : Boolean = True;
  590.                 const AddOnSet : Boolean = True;
  591.                 const DuplicatesAction : TDictionaryDuplicatesAction = ddAccept);
  592.     Destructor Destroy; override;
  593.  
  594.     { AType implementations                                                    }
  595.     class Function CreateInstance : AType; override;
  596.     Procedure Clear; override;
  597.  
  598.     { ADictionary implementations                                              }
  599.     Procedure Delete (const Key : String); override;
  600.     Function  HasKey (const Key : String) : Boolean; override;
  601.     Procedure Rename (const Key : String; const NewKey : String); override;
  602.     Function  Count : Integer; override;
  603.     Function  GetKeyByIndex (const Idx : Integer) : String; override;
  604.  
  605.     { AInt64Dictionary implementations                                    }
  606.     Procedure Add (const Key : String; const Value : Int64); override;
  607.     Function  GetItemByIndex (const Idx : Integer) : Int64; override;
  608.     Procedure SetItemByIndex (const Idx : Integer; const Value : Int64);
  609.     Function  LocateItem (const Key : String; var Value : Int64) : Integer; override;
  610.     Function  LocateNext (const Key : String; const Idx : Integer;
  611.               var Value : Int64) : Integer; override;
  612.  
  613.     { TInt64Dictionary interface                                            }
  614.     Property  HashTableSize : Integer read GetHashTableSize;
  615.     Procedure DeleteItemByIndex (const Idx : Integer);
  616.   end;
  617.  
  618.  
  619.  
  620. {                                                                              }
  621. { TSingleDictionary                                                            }
  622. {   Implements ASingleDictionary using arrays.                                 }
  623. {   A 'chained-hash' lookup table is used for quick access.                    }
  624. {                                                                              }
  625. type
  626.   TSingleDictionary = class (ASingleDictionary)
  627.     protected
  628.     FKeys             : AStringArray;
  629.     FValues           : ASingleArray;
  630.     FLookup           : Array of IntegerArray;
  631.     FCaseSensitive    : Boolean;
  632.     FAddOnSet         : Boolean;
  633.     FDuplicatesAction : TDictionaryDuplicatesAction;
  634.  
  635.     Function  LocateKey (const Key : String; var LookupIdx : Integer;
  636.               const ErrorIfNotFound : Boolean) : Integer;
  637.     Function  KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  638.     Procedure DeleteByIndex (const Idx : Integer; const Hash : Integer = -1);
  639.     Procedure Rehash;
  640.     Function  GetHashTableSize : Integer;
  641.     Procedure IndexError;
  642.  
  643.     { ADictionary implementations                                              }
  644.     Function  GetKeysCaseSensitive : Boolean; override;
  645.     Function  GetAddOnSet : Boolean; override;
  646.     Procedure SetAddOnSet (const AddOnSet : Boolean); override;
  647.     Function  GetDuplicatesAction : TDictionaryDuplicatesAction; override;
  648.     Procedure SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction); override;
  649.  
  650.     { ASingleDictionary implementations                                    }
  651.     Procedure SetItem (const Key : String; const Value : Single); override;
  652.  
  653.     public
  654.     { TSingleDictionary interface                                            }
  655.     Constructor Create;
  656.     Constructor CreateEx (const Keys : AStringArray = nil; const Values : ASingleArray = nil;
  657.                 const KeysCaseSensitive : Boolean = True;
  658.                 const AddOnSet : Boolean = True;
  659.                 const DuplicatesAction : TDictionaryDuplicatesAction = ddAccept);
  660.     Destructor Destroy; override;
  661.  
  662.     { AType implementations                                                    }
  663.     class Function CreateInstance : AType; override;
  664.     Procedure Clear; override;
  665.  
  666.     { ADictionary implementations                                              }
  667.     Procedure Delete (const Key : String); override;
  668.     Function  HasKey (const Key : String) : Boolean; override;
  669.     Procedure Rename (const Key : String; const NewKey : String); override;
  670.     Function  Count : Integer; override;
  671.     Function  GetKeyByIndex (const Idx : Integer) : String; override;
  672.  
  673.     { ASingleDictionary implementations                                    }
  674.     Procedure Add (const Key : String; const Value : Single); override;
  675.     Function  GetItemByIndex (const Idx : Integer) : Single; override;
  676.     Procedure SetItemByIndex (const Idx : Integer; const Value : Single);
  677.     Function  LocateItem (const Key : String; var Value : Single) : Integer; override;
  678.     Function  LocateNext (const Key : String; const Idx : Integer;
  679.               var Value : Single) : Integer; override;
  680.  
  681.     { TSingleDictionary interface                                            }
  682.     Property  HashTableSize : Integer read GetHashTableSize;
  683.     Procedure DeleteItemByIndex (const Idx : Integer);
  684.   end;
  685.  
  686.  
  687.  
  688. {                                                                              }
  689. { TDoubleDictionary                                                            }
  690. {   Implements ADoubleDictionary using arrays.                                 }
  691. {   A 'chained-hash' lookup table is used for quick access.                    }
  692. {                                                                              }
  693. type
  694.   TDoubleDictionary = class (ADoubleDictionary)
  695.     protected
  696.     FKeys             : AStringArray;
  697.     FValues           : ADoubleArray;
  698.     FLookup           : Array of IntegerArray;
  699.     FCaseSensitive    : Boolean;
  700.     FAddOnSet         : Boolean;
  701.     FDuplicatesAction : TDictionaryDuplicatesAction;
  702.  
  703.     Function  LocateKey (const Key : String; var LookupIdx : Integer;
  704.               const ErrorIfNotFound : Boolean) : Integer;
  705.     Function  KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  706.     Procedure DeleteByIndex (const Idx : Integer; const Hash : Integer = -1);
  707.     Procedure Rehash;
  708.     Function  GetHashTableSize : Integer;
  709.     Procedure IndexError;
  710.  
  711.     { ADictionary implementations                                              }
  712.     Function  GetKeysCaseSensitive : Boolean; override;
  713.     Function  GetAddOnSet : Boolean; override;
  714.     Procedure SetAddOnSet (const AddOnSet : Boolean); override;
  715.     Function  GetDuplicatesAction : TDictionaryDuplicatesAction; override;
  716.     Procedure SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction); override;
  717.  
  718.     { ADoubleDictionary implementations                                    }
  719.     Procedure SetItem (const Key : String; const Value : Double); override;
  720.  
  721.     public
  722.     { TDoubleDictionary interface                                            }
  723.     Constructor Create;
  724.     Constructor CreateEx (const Keys : AStringArray = nil; const Values : ADoubleArray = nil;
  725.                 const KeysCaseSensitive : Boolean = True;
  726.                 const AddOnSet : Boolean = True;
  727.                 const DuplicatesAction : TDictionaryDuplicatesAction = ddAccept);
  728.     Destructor Destroy; override;
  729.  
  730.     { AType implementations                                                    }
  731.     class Function CreateInstance : AType; override;
  732.     Procedure Clear; override;
  733.  
  734.     { ADictionary implementations                                              }
  735.     Procedure Delete (const Key : String); override;
  736.     Function  HasKey (const Key : String) : Boolean; override;
  737.     Procedure Rename (const Key : String; const NewKey : String); override;
  738.     Function  Count : Integer; override;
  739.     Function  GetKeyByIndex (const Idx : Integer) : String; override;
  740.  
  741.     { ADoubleDictionary implementations                                    }
  742.     Procedure Add (const Key : String; const Value : Double); override;
  743.     Function  GetItemByIndex (const Idx : Integer) : Double; override;
  744.     Procedure SetItemByIndex (const Idx : Integer; const Value : Double);
  745.     Function  LocateItem (const Key : String; var Value : Double) : Integer; override;
  746.     Function  LocateNext (const Key : String; const Idx : Integer;
  747.               var Value : Double) : Integer; override;
  748.  
  749.     { TDoubleDictionary interface                                            }
  750.     Property  HashTableSize : Integer read GetHashTableSize;
  751.     Procedure DeleteItemByIndex (const Idx : Integer);
  752.   end;
  753.  
  754.  
  755.  
  756. {                                                                              }
  757. { TExtendedDictionary                                                          }
  758. {   Implements AExtendedDictionary using arrays.                               }
  759. {   A 'chained-hash' lookup table is used for quick access.                    }
  760. {                                                                              }
  761. type
  762.   TExtendedDictionary = class (AExtendedDictionary)
  763.     protected
  764.     FKeys             : AStringArray;
  765.     FValues           : AExtendedArray;
  766.     FLookup           : Array of IntegerArray;
  767.     FCaseSensitive    : Boolean;
  768.     FAddOnSet         : Boolean;
  769.     FDuplicatesAction : TDictionaryDuplicatesAction;
  770.  
  771.     Function  LocateKey (const Key : String; var LookupIdx : Integer;
  772.               const ErrorIfNotFound : Boolean) : Integer;
  773.     Function  KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  774.     Procedure DeleteByIndex (const Idx : Integer; const Hash : Integer = -1);
  775.     Procedure Rehash;
  776.     Function  GetHashTableSize : Integer;
  777.     Procedure IndexError;
  778.  
  779.     { ADictionary implementations                                              }
  780.     Function  GetKeysCaseSensitive : Boolean; override;
  781.     Function  GetAddOnSet : Boolean; override;
  782.     Procedure SetAddOnSet (const AddOnSet : Boolean); override;
  783.     Function  GetDuplicatesAction : TDictionaryDuplicatesAction; override;
  784.     Procedure SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction); override;
  785.  
  786.     { AExtendedDictionary implementations                                    }
  787.     Procedure SetItem (const Key : String; const Value : Extended); override;
  788.  
  789.     public
  790.     { TExtendedDictionary interface                                            }
  791.     Constructor Create;
  792.     Constructor CreateEx (const Keys : AStringArray = nil; const Values : AExtendedArray = nil;
  793.                 const KeysCaseSensitive : Boolean = True;
  794.                 const AddOnSet : Boolean = True;
  795.                 const DuplicatesAction : TDictionaryDuplicatesAction = ddAccept);
  796.     Destructor Destroy; override;
  797.  
  798.     { AType implementations                                                    }
  799.     class Function CreateInstance : AType; override;
  800.     Procedure Clear; override;
  801.  
  802.     { ADictionary implementations                                              }
  803.     Procedure Delete (const Key : String); override;
  804.     Function  HasKey (const Key : String) : Boolean; override;
  805.     Procedure Rename (const Key : String; const NewKey : String); override;
  806.     Function  Count : Integer; override;
  807.     Function  GetKeyByIndex (const Idx : Integer) : String; override;
  808.  
  809.     { AExtendedDictionary implementations                                    }
  810.     Procedure Add (const Key : String; const Value : Extended); override;
  811.     Function  GetItemByIndex (const Idx : Integer) : Extended; override;
  812.     Procedure SetItemByIndex (const Idx : Integer; const Value : Extended);
  813.     Function  LocateItem (const Key : String; var Value : Extended) : Integer; override;
  814.     Function  LocateNext (const Key : String; const Idx : Integer;
  815.               var Value : Extended) : Integer; override;
  816.  
  817.     { TExtendedDictionary interface                                            }
  818.     Property  HashTableSize : Integer read GetHashTableSize;
  819.     Procedure DeleteItemByIndex (const Idx : Integer);
  820.   end;
  821.  
  822.  
  823.  
  824. {                                                                              }
  825. { TStringDictionary                                                            }
  826. {   Implements AStringDictionary using arrays.                                 }
  827. {   A 'chained-hash' lookup table is used for quick access.                    }
  828. {                                                                              }
  829. type
  830.   TStringDictionary = class (AStringDictionary)
  831.     protected
  832.     FKeys             : AStringArray;
  833.     FValues           : AStringArray;
  834.     FLookup           : Array of IntegerArray;
  835.     FCaseSensitive    : Boolean;
  836.     FAddOnSet         : Boolean;
  837.     FDuplicatesAction : TDictionaryDuplicatesAction;
  838.  
  839.     Function  LocateKey (const Key : String; var LookupIdx : Integer;
  840.               const ErrorIfNotFound : Boolean) : Integer;
  841.     Function  KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  842.     Procedure DeleteByIndex (const Idx : Integer; const Hash : Integer = -1);
  843.     Procedure Rehash;
  844.     Function  GetHashTableSize : Integer;
  845.     Procedure IndexError;
  846.  
  847.     { ADictionary implementations                                              }
  848.     Function  GetKeysCaseSensitive : Boolean; override;
  849.     Function  GetAddOnSet : Boolean; override;
  850.     Procedure SetAddOnSet (const AddOnSet : Boolean); override;
  851.     Function  GetDuplicatesAction : TDictionaryDuplicatesAction; override;
  852.     Procedure SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction); override;
  853.  
  854.     { AStringDictionary implementations                                    }
  855.     Procedure SetItem (const Key : String; const Value : String); override;
  856.  
  857.     public
  858.     { TStringDictionary interface                                            }
  859.     Constructor Create;
  860.     Constructor CreateEx (const Keys : AStringArray = nil; const Values : AStringArray = nil;
  861.                 const KeysCaseSensitive : Boolean = True;
  862.                 const AddOnSet : Boolean = True;
  863.                 const DuplicatesAction : TDictionaryDuplicatesAction = ddAccept);
  864.     Destructor Destroy; override;
  865.  
  866.     { AType implementations                                                    }
  867.     class Function CreateInstance : AType; override;
  868.     Procedure Clear; override;
  869.  
  870.     { ADictionary implementations                                              }
  871.     Procedure Delete (const Key : String); override;
  872.     Function  HasKey (const Key : String) : Boolean; override;
  873.     Procedure Rename (const Key : String; const NewKey : String); override;
  874.     Function  Count : Integer; override;
  875.     Function  GetKeyByIndex (const Idx : Integer) : String; override;
  876.  
  877.     { AStringDictionary implementations                                    }
  878.     Procedure Add (const Key : String; const Value : String); override;
  879.     Function  GetItemByIndex (const Idx : Integer) : String; override;
  880.     Procedure SetItemByIndex (const Idx : Integer; const Value : String);
  881.     Function  LocateItem (const Key : String; var Value : String) : Integer; override;
  882.     Function  LocateNext (const Key : String; const Idx : Integer;
  883.               var Value : String) : Integer; override;
  884.  
  885.     { TStringDictionary interface                                            }
  886.     Property  HashTableSize : Integer read GetHashTableSize;
  887.     Procedure DeleteItemByIndex (const Idx : Integer);
  888.   end;
  889.  
  890.  
  891.  
  892. {                                                                              }
  893. { TObjectDictionary                                                            }
  894. {   Implements AObjectDictionary using arrays.                                 }
  895. {   A 'chained-hash' lookup table is used for quick access.                    }
  896. {                                                                              }
  897. type
  898.   TObjectDictionary = class (AObjectDictionary)
  899.     protected
  900.     FKeys             : AStringArray;
  901.     FValues           : AObjectArray;
  902.     FLookup           : Array of IntegerArray;
  903.     FCaseSensitive    : Boolean;
  904.     FAddOnSet         : Boolean;
  905.     FDuplicatesAction : TDictionaryDuplicatesAction;
  906.  
  907.     Function  LocateKey (const Key : String; var LookupIdx : Integer;
  908.               const ErrorIfNotFound : Boolean) : Integer;
  909.     Function  KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  910.     Procedure DeleteByIndex (const Idx : Integer; const Hash : Integer = -1);
  911.     Procedure Rehash;
  912.     Function  GetHashTableSize : Integer;
  913.     Procedure IndexError;
  914.  
  915.     { ADictionary implementations                                              }
  916.     Function  GetKeysCaseSensitive : Boolean; override;
  917.     Function  GetAddOnSet : Boolean; override;
  918.     Procedure SetAddOnSet (const AddOnSet : Boolean); override;
  919.     Function  GetDuplicatesAction : TDictionaryDuplicatesAction; override;
  920.     Procedure SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction); override;
  921.  
  922.     { AObjectDictionary implementations                                        }
  923.     Function  GetIsItemOwner : Boolean; override;
  924.     Procedure SetIsItemOwner (const IsItemOwner : Boolean); override;
  925.     
  926.     Procedure SetItem (const Key : String; const Value : TObject); override;
  927.  
  928.     public
  929.     { TObjectDictionary interface                                            }
  930.     Constructor Create;
  931.     Constructor CreateEx (const Keys : AStringArray = nil; const Values : AObjectArray = nil;
  932.                 const IsItemOwner : Boolean = False;
  933.                 const KeysCaseSensitive : Boolean = True;
  934.                 const AddOnSet : Boolean = True;
  935.                 const DuplicatesAction : TDictionaryDuplicatesAction = ddAccept);
  936.     Destructor Destroy; override;
  937.  
  938.     { AType implementations                                                    }
  939.     class Function CreateInstance : AType; override;
  940.     Procedure Clear; override;
  941.  
  942.     { ADictionary implementations                                              }
  943.     Procedure Delete (const Key : String); override;
  944.     Function  HasKey (const Key : String) : Boolean; override;
  945.     Procedure Rename (const Key : String; const NewKey : String); override;
  946.     Function  Count : Integer; override;
  947.     Function  GetKeyByIndex (const Idx : Integer) : String; override;
  948.  
  949.     { AObjectDictionary implementations                                        }
  950.     Procedure Add (const Key : String; const Value : TObject); override;
  951.     Function  GetItemByIndex (const Idx : Integer) : TObject; override;
  952.     Procedure SetItemByIndex (const Idx : Integer; const Value : TObject);
  953.     Function  LocateItem (const Key : String; var Value : TObject) : Integer; override;
  954.     Function  LocateNext (const Key : String; const Idx : Integer;
  955.               var Value : TObject) : Integer; override;
  956.  
  957.     Function  ReleaseItem (const Key : String) : TObject; override;
  958.     Procedure ReleaseItems; override;
  959.     Procedure FreeItems; override;
  960.  
  961.     { TObjectDictionary interface                                            }
  962.     Property  HashTableSize : Integer read GetHashTableSize;
  963.     Procedure DeleteItemByIndex (const Idx : Integer);
  964.   end;
  965.  
  966.  
  967.  
  968. {                                                                              }
  969. { Dictionary functions                                                         }
  970. {                                                                              }
  971. const
  972.   AverageHashChainSize = 4;
  973.  
  974. Function  DictionaryRehashSize (const Count : Integer) : Integer;
  975.  
  976.  
  977.  
  978. {                                                                              }
  979. { Self testing code                                                            }
  980. {                                                                              }
  981. Procedure SelfTest;
  982.  
  983.  
  984.  
  985. implementation
  986.  
  987. uses
  988.   // Fundamentals
  989.   cStrings;
  990.  
  991.  
  992.  
  993. {                                                                              }
  994. { DICTIONARY BASE CLASSES                                                      }
  995. {                                                                              }
  996.  
  997.  
  998.  
  999. {                                                                              }
  1000. { ADictionary                                                                  }
  1001. {                                                                              }
  1002. Procedure ADictionary.DictionaryError (const Msg : String);
  1003.   Begin
  1004.     TypeError (Msg, nil, EDictionary);
  1005.   End;
  1006.  
  1007. Procedure ADictionary.KeyNotFoundError (const Key : String);
  1008.   Begin
  1009.     DictionaryError ('Key not found: ' + Key);
  1010.   End;
  1011.  
  1012.  
  1013.  
  1014. {                                                                              }
  1015. { ALongIntDictionary                                                           }
  1016. {                                                                              }
  1017. Function ALongIntDictionary.GetItem (const Key : String) : LongInt;
  1018.   Begin
  1019.     if LocateItem (Key, Result) < 0 then
  1020.       KeyNotFoundError (Key);
  1021.   End;
  1022.  
  1023. Procedure ALongIntDictionary.Assign (const Source : TObject);
  1024. var I : Integer;
  1025.   Begin
  1026.     if Source is ALongIntDictionary then
  1027.       begin
  1028.         Clear;
  1029.         For I := 0 to ALongIntDictionary (Source).Count - 1 do
  1030.           Add (ALongIntDictionary (Source).GetKeyByIndex (I),
  1031.                ALongIntDictionary (Source).GetItemByIndex (I));
  1032.       end else
  1033.       inherited Assign (Source);
  1034.   End;
  1035.  
  1036. Function ALongIntDictionary.GetAsString : String;
  1037. var I, L : Integer;
  1038.   Begin
  1039.     L := Count - 1;
  1040.     For I := 0 to L do
  1041.       begin
  1042.         Result := Result + GetKeyByIndex (I) + ':' + IntToStr (GetItemByIndex (I));
  1043.         if I < L then
  1044.           Result := Result + ',';
  1045.       end;
  1046.   End;
  1047.  
  1048.  
  1049.  
  1050. {                                                                              }
  1051. { ALongWordDictionary                                                          }
  1052. {                                                                              }
  1053. Function ALongWordDictionary.GetItem (const Key : String) : LongWord;
  1054.   Begin
  1055.     if LocateItem (Key, Result) < 0 then
  1056.       KeyNotFoundError (Key);
  1057.   End;
  1058.  
  1059. Procedure ALongWordDictionary.Assign (const Source : TObject);
  1060. var I : Integer;
  1061.   Begin
  1062.     if Source is ALongWordDictionary then
  1063.       begin
  1064.         Clear;
  1065.         For I := 0 to ALongWordDictionary (Source).Count - 1 do
  1066.           Add (ALongWordDictionary (Source).GetKeyByIndex (I),
  1067.                ALongWordDictionary (Source).GetItemByIndex (I));
  1068.       end else
  1069.       inherited Assign (Source);
  1070.   End;
  1071.  
  1072. Function ALongWordDictionary.GetAsString : String;
  1073. var I, L : Integer;
  1074.   Begin
  1075.     L := Count - 1;
  1076.     For I := 0 to L do
  1077.       begin
  1078.         Result := Result + GetKeyByIndex (I) + ':' + IntToStr (GetItemByIndex (I));
  1079.         if I < L then
  1080.           Result := Result + ',';
  1081.       end;
  1082.   End;
  1083.  
  1084.  
  1085.  
  1086. {                                                                              }
  1087. { AInt64Dictionary                                                             }
  1088. {                                                                              }
  1089. Function AInt64Dictionary.GetItem (const Key : String) : Int64;
  1090.   Begin
  1091.     if LocateItem (Key, Result) < 0 then
  1092.       KeyNotFoundError (Key);
  1093.   End;
  1094.  
  1095. Procedure AInt64Dictionary.Assign (const Source : TObject);
  1096. var I : Integer;
  1097.   Begin
  1098.     if Source is AInt64Dictionary then
  1099.       begin
  1100.         Clear;
  1101.         For I := 0 to AInt64Dictionary (Source).Count - 1 do
  1102.           Add (AInt64Dictionary (Source).GetKeyByIndex (I),
  1103.                AInt64Dictionary (Source).GetItemByIndex (I));
  1104.       end else
  1105.       inherited Assign (Source);
  1106.   End;
  1107.  
  1108. Function AInt64Dictionary.GetAsString : String;
  1109. var I, L : Integer;
  1110.   Begin
  1111.     L := Count - 1;
  1112.     For I := 0 to L do
  1113.       begin
  1114.         Result := Result + GetKeyByIndex (I) + ':' + IntToStr (GetItemByIndex (I));
  1115.         if I < L then
  1116.           Result := Result + ',';
  1117.       end;
  1118.   End;
  1119.  
  1120.  
  1121.  
  1122. {                                                                              }
  1123. { ASingleDictionary                                                            }
  1124. {                                                                              }
  1125. Function ASingleDictionary.GetItem (const Key : String) : Single;
  1126.   Begin
  1127.     if LocateItem (Key, Result) < 0 then
  1128.       KeyNotFoundError (Key);
  1129.   End;
  1130.  
  1131. Procedure ASingleDictionary.Assign (const Source : TObject);
  1132. var I : Integer;
  1133.   Begin
  1134.     if Source is ASingleDictionary then
  1135.       begin
  1136.         Clear;
  1137.         For I := 0 to ASingleDictionary (Source).Count - 1 do
  1138.           Add (ASingleDictionary (Source).GetKeyByIndex (I),
  1139.                ASingleDictionary (Source).GetItemByIndex (I));
  1140.       end else
  1141.       inherited Assign (Source);
  1142.   End;
  1143.  
  1144. Function ASingleDictionary.GetAsString : String;
  1145. var I, L : Integer;
  1146.   Begin
  1147.     L := Count - 1;
  1148.     For I := 0 to L do
  1149.       begin
  1150.         Result := Result + GetKeyByIndex (I) + ':' + FloatToStr (GetItemByIndex (I));
  1151.         if I < L then
  1152.           Result := Result + ',';
  1153.       end;
  1154.   End;
  1155.  
  1156.  
  1157.  
  1158. {                                                                              }
  1159. { ADoubleDictionary                                                            }
  1160. {                                                                              }
  1161. Function ADoubleDictionary.GetItem (const Key : String) : Double;
  1162.   Begin
  1163.     if LocateItem (Key, Result) < 0 then
  1164.       KeyNotFoundError (Key);
  1165.   End;
  1166.  
  1167. Procedure ADoubleDictionary.Assign (const Source : TObject);
  1168. var I : Integer;
  1169.   Begin
  1170.     if Source is ADoubleDictionary then
  1171.       begin
  1172.         Clear;
  1173.         For I := 0 to ADoubleDictionary (Source).Count - 1 do
  1174.           Add (ADoubleDictionary (Source).GetKeyByIndex (I),
  1175.                ADoubleDictionary (Source).GetItemByIndex (I));
  1176.       end else
  1177.       inherited Assign (Source);
  1178.   End;
  1179.  
  1180. Function ADoubleDictionary.GetAsString : String;
  1181. var I, L : Integer;
  1182.   Begin
  1183.     L := Count - 1;
  1184.     For I := 0 to L do
  1185.       begin
  1186.         Result := Result + GetKeyByIndex (I) + ':' + FloatToStr (GetItemByIndex (I));
  1187.         if I < L then
  1188.           Result := Result + ',';
  1189.       end;
  1190.   End;
  1191.  
  1192.  
  1193.  
  1194. {                                                                              }
  1195. { AExtendedDictionary                                                          }
  1196. {                                                                              }
  1197. Function AExtendedDictionary.GetItem (const Key : String) : Extended;
  1198.   Begin
  1199.     if LocateItem (Key, Result) < 0 then
  1200.       KeyNotFoundError (Key);
  1201.   End;
  1202.  
  1203. Procedure AExtendedDictionary.Assign (const Source : TObject);
  1204. var I : Integer;
  1205.   Begin
  1206.     if Source is AExtendedDictionary then
  1207.       begin
  1208.         Clear;
  1209.         For I := 0 to AExtendedDictionary (Source).Count - 1 do
  1210.           Add (AExtendedDictionary (Source).GetKeyByIndex (I),
  1211.                AExtendedDictionary (Source).GetItemByIndex (I));
  1212.       end else
  1213.       inherited Assign (Source);
  1214.   End;
  1215.  
  1216. Function AExtendedDictionary.GetAsString : String;
  1217. var I, L : Integer;
  1218.   Begin
  1219.     L := Count - 1;
  1220.     For I := 0 to L do
  1221.       begin
  1222.         Result := Result + GetKeyByIndex (I) + ':' + FloatToStr (GetItemByIndex (I));
  1223.         if I < L then
  1224.           Result := Result + ',';
  1225.       end;
  1226.   End;
  1227.  
  1228.  
  1229.  
  1230. {                                                                              }
  1231. { AStringDictionary                                                            }
  1232. {                                                                              }
  1233. Function AStringDictionary.GetItem (const Key : String) : String;
  1234.   Begin
  1235.     if LocateItem (Key, Result) < 0 then
  1236.       KeyNotFoundError (Key);
  1237.   End;
  1238.  
  1239. Procedure AStringDictionary.Assign (const Source : TObject);
  1240. var I : Integer;
  1241.   Begin
  1242.     if Source is AStringDictionary then
  1243.       begin
  1244.         Clear;
  1245.         For I := 0 to AStringDictionary (Source).Count - 1 do
  1246.           Add (AStringDictionary (Source).GetKeyByIndex (I),
  1247.                AStringDictionary (Source).GetItemByIndex (I));
  1248.       end else
  1249.       inherited Assign (Source);
  1250.   End;
  1251.  
  1252. Function AStringDictionary.GetAsString : String;
  1253. var I, L : Integer;
  1254.   Begin
  1255.     L := Count - 1;
  1256.     For I := 0 to L do
  1257.       begin
  1258.         Result := Result + GetKeyByIndex (I) + ':' + QuoteText (GetItemByIndex (I));
  1259.         if I < L then
  1260.           Result := Result + ',';
  1261.       end;
  1262.   End;
  1263.  
  1264. Function AStringDictionary.GetItemLength (const Key : String) : Integer;
  1265.   Begin
  1266.     Result := Length (GetItem (Key));
  1267.   End;
  1268.  
  1269. Function AStringDictionary.GetTotalLength : Int64;
  1270. var I : Integer;
  1271.   Begin
  1272.     Result := 0;
  1273.     For I := 0 to Count - 1 do
  1274.       Inc (Result, Length (GetItemByIndex (I)));
  1275.   End;
  1276.  
  1277.  
  1278.  
  1279. {                                                                              }
  1280. { APointerDictionary                                                           }
  1281. {                                                                              }
  1282. Function APointerDictionary.GetItem (const Key : String) : Pointer;
  1283.   Begin
  1284.     if LocateItem (Key, Result) < 0 then
  1285.       KeyNotFoundError (Key);
  1286.   End;
  1287.  
  1288. Procedure APointerDictionary.Assign (const Source : TObject);
  1289. var I : Integer;
  1290.   Begin
  1291.     if Source is APointerDictionary then
  1292.       begin
  1293.         Clear;
  1294.         For I := 0 to APointerDictionary (Source).Count - 1 do
  1295.           Add (APointerDictionary (Source).GetKeyByIndex (I),
  1296.                APointerDictionary (Source).GetItemByIndex (I));
  1297.       end else
  1298.       inherited Assign (Source);
  1299.   End;
  1300.  
  1301. Function APointerDictionary.GetAsString : String;
  1302. var I, L : Integer;
  1303.   Begin
  1304.     L := Count - 1;
  1305.     For I := 0 to L do
  1306.       begin
  1307.         Result := Result + GetKeyByIndex (I) + ':' + PointerToStr (GetItemByIndex (I));
  1308.         if I < L then
  1309.           Result := Result + ',';
  1310.       end;
  1311.   End;
  1312.  
  1313.  
  1314.  
  1315. {                                                                              }
  1316. { AObjectDictionary                                                            }
  1317. {                                                                              }
  1318. Function AObjectDictionary.GetItem (const Key : String) : TObject;
  1319.   Begin
  1320.     if LocateItem (Key, Result) < 0 then
  1321.       KeyNotFoundError (Key);
  1322.   End;
  1323.  
  1324. Function AObjectDictionary.GetAsString : String;
  1325. var I, L : Integer;
  1326.   Begin
  1327.     L := Count - 1;
  1328.     For I := 0 to L do
  1329.       begin
  1330.         Result := Result + GetKeyByIndex (I) + ':' + ObjectClassName (GetItemByIndex (I));
  1331.         if I < L then
  1332.           Result := Result + ',';
  1333.       end;
  1334.   End;
  1335.  
  1336. Procedure AObjectDictionary.Clear;
  1337.   Begin
  1338.     if IsItemOwner then
  1339.       FreeItems else
  1340.       ReleaseItems;
  1341.   End;
  1342.  
  1343. Procedure AObjectDictionary.Assign (const Source : TObject);
  1344. var I : Integer;
  1345.   Begin
  1346.     if Source is AObjectDictionary then
  1347.       begin
  1348.         Clear;
  1349.         For I := 0 to AObjectDictionary (Source).Count - 1 do
  1350.           Add (AObjectDictionary (Source).GetKeyByIndex (I),
  1351.                AObjectDictionary (Source).GetItemByIndex (I));
  1352.       end else
  1353.       inherited Assign (Source);
  1354.   End;
  1355.  
  1356.  
  1357.  
  1358. {                                                                              }
  1359. { DICTIONARY IMPLEMENTATIONS                                                   }
  1360. {                                                                              }
  1361.  
  1362.  
  1363.  
  1364. { Dictionary helper functions                                                  }
  1365. Function DictionaryRehashSize (const Count : Integer) : Integer;
  1366. var L : Integer;
  1367.   Begin
  1368.     L := Count div AverageHashChainSize; // Number of slots
  1369.     if L <= 16 then                      // Rehash in powers of 16
  1370.       Result := 16 else
  1371.     if L <= 256 then
  1372.       Result := 256 else
  1373.     if L <= 4096 then
  1374.       Result := 4096 else
  1375.     if L <= 65536 then
  1376.       Result := 65536 else
  1377.     if L <= 1048576 then
  1378.       Result := 1048576 else
  1379.     if L <= 16777216 then
  1380.       Result := 16777216 else
  1381.       Result := 268435456;
  1382.   End;
  1383.  
  1384. {                                                                              }
  1385. { TLongIntDictionary                                                           }
  1386. {                                                                              }
  1387. Constructor TLongIntDictionary.Create;
  1388.   Begin
  1389.     inherited Create;
  1390.     FCaseSensitive := True;
  1391.     FDuplicatesAction := ddAccept;
  1392.     FAddOnSet := True;
  1393.     FKeys := TStringArray.Create;
  1394.     FValues := TLongIntArray.Create;
  1395.   End;
  1396.   
  1397. Constructor TLongIntDictionary.CreateEx (const Keys : AStringArray; const Values : ALongIntArray; const KeysCaseSensitive : Boolean; const AddOnSet : Boolean; const DuplicatesAction : TDictionaryDuplicatesAction);
  1398.   Begin
  1399.     inherited Create;
  1400.     if Assigned (Keys) then
  1401.       FKeys := Keys else
  1402.       FKeys := TStringArray.Create;
  1403.     if Assigned (Values) then
  1404.       FValues := Values else
  1405.       FValues := TLongIntArray.Create;
  1406.     Assert (FKeys.Count = FValues.Count, 'Keys and Values must be equal length');
  1407.     FAddOnSet := AddOnSet;
  1408.     FDuplicatesAction := DuplicatesAction;
  1409.     Rehash;
  1410.   End;
  1411.  
  1412. Destructor TLongIntDictionary.Destroy;
  1413.   Begin
  1414.     FreeAndNil (FValues);
  1415.     FreeAndNil (FKeys);
  1416.     inherited Destroy;
  1417.   End;
  1418.  
  1419. Function TLongIntDictionary.GetKeysCaseSensitive : Boolean;
  1420.   Begin
  1421.     Result := FCaseSensitive;
  1422.   End;
  1423.  
  1424. Function TLongIntDictionary.GetAddOnSet : Boolean;
  1425.   Begin
  1426.     Result := FAddOnSet;
  1427.   End;
  1428.  
  1429. Procedure TLongIntDictionary.SetAddOnSet (const AddOnSet : Boolean);
  1430.   Begin
  1431.     FAddOnSet := AddOnSet;
  1432.   End;
  1433.  
  1434. Function TLongIntDictionary.GetHashTableSize : Integer;
  1435.   Begin
  1436.     Result := Length (FLookup);
  1437.   End;
  1438.  
  1439. Procedure TLongIntDictionary.Rehash;
  1440. var I, C, L : Integer;
  1441.   Begin
  1442.     C := FKeys.Count;
  1443.     L := DictionaryRehashSize (C);
  1444.     FLookup := nil;
  1445.     SetLength (FLookup, L);
  1446.     For I := 0 to C - 1 do
  1447.       Append (FLookup [HashStr (FKeys [I], L, FCaseSensitive)], I);
  1448.   End;
  1449.  
  1450. class Function TLongIntDictionary.CreateInstance : AType;
  1451.   Begin
  1452.     Result := TLongIntDictionary.Create;
  1453.   End;
  1454.  
  1455. Function TLongIntDictionary.LocateKey (const Key : String; var LookupIdx : Integer; const ErrorIfNotFound : Boolean) : Integer;
  1456. var H, I, J, L : Integer;
  1457.   Begin
  1458.     Result := -1;
  1459.     L := Length (FLookup);
  1460.     if L > 0 then
  1461.       begin
  1462.         H := HashStr (Key, L, FCaseSensitive);
  1463.         LookupIdx := H;
  1464.         For I := 0 to Length (FLookup [H]) - 1 do
  1465.           begin
  1466.             J := FLookup [H, I];
  1467.             if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  1468.               begin
  1469.                 Result := J;
  1470.                 break;
  1471.               end;
  1472.           end;
  1473.       end;
  1474.     if ErrorIfNotFound and (Result = -1) then
  1475.       KeyNotFoundError (Key);
  1476.   End;
  1477.  
  1478. Function TLongIntDictionary.KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  1479. var H : Integer;
  1480.   Begin
  1481.     Result := LocateKey (Key, H, ErrorIfNotFound);
  1482.   End;
  1483.  
  1484. Procedure TLongIntDictionary.Add (const Key : String; const Value : LongInt);
  1485. var H, L, I : Integer;
  1486.   Begin
  1487.     if FDuplicatesAction in [ddIgnore, ddError] then
  1488.       if LocateKey (Key, H, False) >= 0 then
  1489.         if FDuplicatesAction = ddIgnore then
  1490.           exit else
  1491.           DictionaryError ('Duplicate key: ' + QuoteText (Key));
  1492.     L := Length (FLookup);
  1493.     if L = 0 then
  1494.       begin
  1495.         Rehash;
  1496.         L := Length (FLookup);
  1497.       end;
  1498.     H := Integer (HashStr (Key, LongWord (L), FCaseSensitive));
  1499.     I := FKeys.AddItem (Key);
  1500.     Append (FLookup [H], I);
  1501.     FValues.AddItem (Value);
  1502.  
  1503.     if (I + 1) div AverageHashChainSize > L then
  1504.       Rehash;
  1505.   End;
  1506.  
  1507. Procedure TLongIntDictionary.DeleteByIndex (const Idx : Integer; const Hash : Integer);
  1508. var I, J, H : Integer;
  1509.   Begin
  1510.     if Hash = -1 then
  1511.       H := HashStr (FKeys [Idx], Length (FLookup), FCaseSensitive) else
  1512.       H := Hash;
  1513.     FKeys.Delete (Idx);
  1514.     FValues.Delete (Idx);
  1515.     J := PosNext (Idx, FLookup [H]);
  1516.     Assert (J >= 0, 'Invalid hash value/lookup table');
  1517.     Remove (FLookup [H], J, 1);
  1518.  
  1519.     For I := 0 to Length (FLookup) - 1 do
  1520.       For J := 0 to Length (FLookup [I]) - 1 do
  1521.         if FLookup [I][J] > Idx then
  1522.           Dec (FLookup [I][J]);
  1523.   End;
  1524.  
  1525. Procedure TLongIntDictionary.Delete (const Key : String);
  1526. var I, H : Integer;
  1527.   Begin
  1528.     I := LocateKey (Key, H, True);
  1529.     DeleteByIndex (I, H);
  1530.   End;
  1531.  
  1532. Function TLongIntDictionary.HasKey (const Key : String) : Boolean;
  1533.   Begin
  1534.     Result := KeyIndex (Key, False) >= 0;
  1535.   End;
  1536.  
  1537. Procedure TLongIntDictionary.Rename (const Key, NewKey : String);
  1538. var I, J, H : Integer;
  1539.   Begin
  1540.     I := LocateKey (Key, H, True);
  1541.     FKeys [I] := NewKey;
  1542.     J := PosNext (I, FLookup [H]);
  1543.     Assert (J >= 0, 'Invalid hash value/lookup table');
  1544.     Remove (FLookup [H], J, 1);
  1545.     Append (FLookup [HashStr (NewKey, Length (FLookup), FCaseSensitive)], I);
  1546.   End;
  1547.  
  1548. Function TLongIntDictionary.GetDuplicatesAction : TDictionaryDuplicatesAction;
  1549.   Begin
  1550.     Result := FDuplicatesAction;
  1551.   End;
  1552.  
  1553. Procedure TLongIntDictionary.SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction);
  1554.   Begin
  1555.     FDuplicatesAction := DuplicatesAction;
  1556.   End;
  1557.  
  1558. Function TLongIntDictionary.LocateItem (const Key : String; var Value : LongInt) : Integer;
  1559.   Begin
  1560.     Result := KeyIndex (Key, False);
  1561.     if Result >= 0 then
  1562.       Value := FValues [Result] else
  1563.       Value := 0;
  1564.   End;
  1565.  
  1566. Function TLongIntDictionary.LocateNext (const Key : String; const Idx : Integer; var Value : LongInt) : Integer;
  1567. var L, H, I, J, K : Integer;
  1568.   Begin
  1569.     Result := -1;
  1570.     L := Length (FLookup);
  1571.     if L = 0 then
  1572.       DictionaryError ('Item not found');
  1573.     H := HashStr (Key, L, FCaseSensitive);
  1574.     For I := 0 to Length (FLookup [H]) - 1 do
  1575.       begin
  1576.         J := FLookup [H, I];
  1577.         if J = Idx then
  1578.           begin
  1579.             if not cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  1580.               DictionaryError ('Item not found');
  1581.             For K := I + 1 to Length (FLookup [H]) - 1 do
  1582.               begin
  1583.                 J := FLookup [H, K];
  1584.                 if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  1585.                   begin
  1586.                     Value := FValues [J];
  1587.                     Result := J;
  1588.                     exit;
  1589.                   end;
  1590.               end;
  1591.             Result := -1;
  1592.             exit;
  1593.           end;
  1594.       end;
  1595.     DictionaryError ('Item not found');
  1596.   End;
  1597.  
  1598. Procedure TLongIntDictionary.SetItem (const Key : String; const Value : LongInt);
  1599. var I : Integer;
  1600.   Begin
  1601.     I := KeyIndex (Key, False);
  1602.     if I >= 0 then
  1603.       FValues [I] := Value else
  1604.       if AddOnSet then
  1605.         Add (Key, Value) else
  1606.         KeyNotFoundError (Key);
  1607.   End;
  1608.  
  1609. Procedure TLongIntDictionary.IndexError;
  1610.   Begin
  1611.     DictionaryError ('Index out of range');
  1612.   End;
  1613.  
  1614. Function TLongIntDictionary.Count : Integer;
  1615.   Begin
  1616.     Result := FKeys.Count;
  1617.     Assert (FValues.Count = Result, 'Key/Value count mismatch');
  1618.   End;
  1619.  
  1620. Function TLongIntDictionary.GetKeyByIndex (const Idx : Integer) : String;
  1621.   Begin
  1622.     {$IFOPT R+}
  1623.     if (Idx < 0) or (Idx >= FKeys.Count) then
  1624.       IndexError;
  1625.     {$ENDIF}
  1626.     Result := FKeys [Idx];
  1627.   End;
  1628.  
  1629. Procedure TLongIntDictionary.DeleteItemByIndex (const Idx : Integer);
  1630.   Begin
  1631.     {$IFOPT R+}
  1632.     if (Idx < 0) or (Idx >= FValues.Count) then
  1633.       IndexError;
  1634.     {$ENDIF}
  1635.     DeleteByIndex (Idx, -1);
  1636.   End;
  1637.  
  1638. Function TLongIntDictionary.GetItemByIndex (const Idx : Integer) : LongInt;
  1639.   Begin
  1640.     {$IFOPT R+}
  1641.     if (Idx < 0) or (Idx >= FValues.Count) then
  1642.       IndexError;
  1643.     {$ENDIF}
  1644.     Result := FValues [Idx];
  1645.   End;
  1646.  
  1647. Procedure TLongIntDictionary.SetItemByIndex (const Idx : Integer; const Value : LongInt);
  1648.   Begin
  1649.     {$IFOPT R+}
  1650.     if (Idx < 0) or (Idx >= FValues.Count) then
  1651.       IndexError;
  1652.     {$ENDIF}
  1653.     FValues [Idx] := Value;
  1654.   End;
  1655.  
  1656. Procedure TLongIntDictionary.Clear;
  1657.   Begin
  1658.     FKeys.Clear;
  1659.     FValues.Clear;
  1660.     Rehash;
  1661.   End;
  1662.  
  1663.  
  1664.  
  1665. {                                                                              }
  1666. { TLongWordDictionary                                                          }
  1667. {                                                                              }
  1668. Constructor TLongWordDictionary.Create;
  1669.   Begin
  1670.     inherited Create;
  1671.     FCaseSensitive := True;
  1672.     FDuplicatesAction := ddAccept;
  1673.     FAddOnSet := True;
  1674.     FKeys := TStringArray.Create;
  1675.     FValues := TLongWordArray.Create;
  1676.   End;
  1677.   
  1678. Constructor TLongWordDictionary.CreateEx (const Keys : AStringArray; const Values : ALongWordArray; const KeysCaseSensitive : Boolean; const AddOnSet : Boolean; const DuplicatesAction : TDictionaryDuplicatesAction);
  1679.   Begin
  1680.     inherited Create;
  1681.     if Assigned (Keys) then
  1682.       FKeys := Keys else
  1683.       FKeys := TStringArray.Create;
  1684.     if Assigned (Values) then
  1685.       FValues := Values else
  1686.       FValues := TLongWordArray.Create;
  1687.     Assert (FKeys.Count = FValues.Count, 'Keys and Values must be equal length');
  1688.     FAddOnSet := AddOnSet;
  1689.     FDuplicatesAction := DuplicatesAction;
  1690.     Rehash;
  1691.   End;
  1692.  
  1693. Destructor TLongWordDictionary.Destroy;
  1694.   Begin
  1695.     FreeAndNil (FValues);
  1696.     FreeAndNil (FKeys);
  1697.     inherited Destroy;
  1698.   End;
  1699.  
  1700. Function TLongWordDictionary.GetKeysCaseSensitive : Boolean;
  1701.   Begin
  1702.     Result := FCaseSensitive;
  1703.   End;
  1704.  
  1705. Function TLongWordDictionary.GetAddOnSet : Boolean;
  1706.   Begin
  1707.     Result := FAddOnSet;
  1708.   End;
  1709.  
  1710. Procedure TLongWordDictionary.SetAddOnSet (const AddOnSet : Boolean);
  1711.   Begin
  1712.     FAddOnSet := AddOnSet;
  1713.   End;
  1714.  
  1715. Function TLongWordDictionary.GetHashTableSize : Integer;
  1716.   Begin
  1717.     Result := Length (FLookup);
  1718.   End;
  1719.  
  1720. Procedure TLongWordDictionary.Rehash;
  1721. var I, C, L : Integer;
  1722.   Begin
  1723.     C := FKeys.Count;
  1724.     L := DictionaryRehashSize (C);
  1725.     FLookup := nil;
  1726.     SetLength (FLookup, L);
  1727.     For I := 0 to C - 1 do
  1728.       Append (FLookup [HashStr (FKeys [I], L, FCaseSensitive)], I);
  1729.   End;
  1730.  
  1731. class Function TLongWordDictionary.CreateInstance : AType;
  1732.   Begin
  1733.     Result := TLongWordDictionary.Create;
  1734.   End;
  1735.  
  1736. Function TLongWordDictionary.LocateKey (const Key : String; var LookupIdx : Integer; const ErrorIfNotFound : Boolean) : Integer;
  1737. var H, I, J, L : Integer;
  1738.   Begin
  1739.     Result := -1;
  1740.     L := Length (FLookup);
  1741.     if L > 0 then
  1742.       begin
  1743.         H := HashStr (Key, L, FCaseSensitive);
  1744.         LookupIdx := H;
  1745.         For I := 0 to Length (FLookup [H]) - 1 do
  1746.           begin
  1747.             J := FLookup [H, I];
  1748.             if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  1749.               begin
  1750.                 Result := J;
  1751.                 break;
  1752.               end;
  1753.           end;
  1754.       end;
  1755.     if ErrorIfNotFound and (Result = -1) then
  1756.       KeyNotFoundError (Key);
  1757.   End;
  1758.  
  1759. Function TLongWordDictionary.KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  1760. var H : Integer;
  1761.   Begin
  1762.     Result := LocateKey (Key, H, ErrorIfNotFound);
  1763.   End;
  1764.  
  1765. Procedure TLongWordDictionary.Add (const Key : String; const Value : LongWord);
  1766. var H, L, I : Integer;
  1767.   Begin
  1768.     if FDuplicatesAction in [ddIgnore, ddError] then
  1769.       if LocateKey (Key, H, False) >= 0 then
  1770.         if FDuplicatesAction = ddIgnore then
  1771.           exit else
  1772.           DictionaryError ('Duplicate key: ' + QuoteText (Key));
  1773.     L := Length (FLookup);
  1774.     if L = 0 then
  1775.       begin
  1776.         Rehash;
  1777.         L := Length (FLookup);
  1778.       end;
  1779.     H := Integer (HashStr (Key, LongWord (L), FCaseSensitive));
  1780.     I := FKeys.AddItem (Key);
  1781.     Append (FLookup [H], I);
  1782.     FValues.AddItem (Value);
  1783.  
  1784.     if (I + 1) div AverageHashChainSize > L then
  1785.       Rehash;
  1786.   End;
  1787.  
  1788. Procedure TLongWordDictionary.DeleteByIndex (const Idx : Integer; const Hash : Integer);
  1789. var I, J, H : Integer;
  1790.   Begin
  1791.     if Hash = -1 then
  1792.       H := HashStr (FKeys [Idx], Length (FLookup), FCaseSensitive) else
  1793.       H := Hash;
  1794.     FKeys.Delete (Idx);
  1795.     FValues.Delete (Idx);
  1796.     J := PosNext (Idx, FLookup [H]);
  1797.     Assert (J >= 0, 'Invalid hash value/lookup table');
  1798.     Remove (FLookup [H], J, 1);
  1799.  
  1800.     For I := 0 to Length (FLookup) - 1 do
  1801.       For J := 0 to Length (FLookup [I]) - 1 do
  1802.         if FLookup [I][J] > Idx then
  1803.           Dec (FLookup [I][J]);
  1804.   End;
  1805.  
  1806. Procedure TLongWordDictionary.Delete (const Key : String);
  1807. var I, H : Integer;
  1808.   Begin
  1809.     I := LocateKey (Key, H, True);
  1810.     DeleteByIndex (I, H);
  1811.   End;
  1812.  
  1813. Function TLongWordDictionary.HasKey (const Key : String) : Boolean;
  1814.   Begin
  1815.     Result := KeyIndex (Key, False) >= 0;
  1816.   End;
  1817.  
  1818. Procedure TLongWordDictionary.Rename (const Key, NewKey : String);
  1819. var I, J, H : Integer;
  1820.   Begin
  1821.     I := LocateKey (Key, H, True);
  1822.     FKeys [I] := NewKey;
  1823.     J := PosNext (I, FLookup [H]);
  1824.     Assert (J >= 0, 'Invalid hash value/lookup table');
  1825.     Remove (FLookup [H], J, 1);
  1826.     Append (FLookup [HashStr (NewKey, Length (FLookup), FCaseSensitive)], I);
  1827.   End;
  1828.  
  1829. Function TLongWordDictionary.GetDuplicatesAction : TDictionaryDuplicatesAction;
  1830.   Begin
  1831.     Result := FDuplicatesAction;
  1832.   End;
  1833.  
  1834. Procedure TLongWordDictionary.SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction);
  1835.   Begin
  1836.     FDuplicatesAction := DuplicatesAction;
  1837.   End;
  1838.  
  1839. Function TLongWordDictionary.LocateItem (const Key : String; var Value : LongWord) : Integer;
  1840.   Begin
  1841.     Result := KeyIndex (Key, False);
  1842.     if Result >= 0 then
  1843.       Value := FValues [Result] else
  1844.       Value := 0;
  1845.   End;
  1846.  
  1847. Function TLongWordDictionary.LocateNext (const Key : String; const Idx : Integer; var Value : LongWord) : Integer;
  1848. var L, H, I, J, K : Integer;
  1849.   Begin
  1850.     Result := -1;
  1851.     L := Length (FLookup);
  1852.     if L = 0 then
  1853.       DictionaryError ('Item not found');
  1854.     H := HashStr (Key, L, FCaseSensitive);
  1855.     For I := 0 to Length (FLookup [H]) - 1 do
  1856.       begin
  1857.         J := FLookup [H, I];
  1858.         if J = Idx then
  1859.           begin
  1860.             if not cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  1861.               DictionaryError ('Item not found');
  1862.             For K := I + 1 to Length (FLookup [H]) - 1 do
  1863.               begin
  1864.                 J := FLookup [H, K];
  1865.                 if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  1866.                   begin
  1867.                     Value := FValues [J];
  1868.                     Result := J;
  1869.                     exit;
  1870.                   end;
  1871.               end;
  1872.             Result := -1;
  1873.             exit;
  1874.           end;
  1875.       end;
  1876.     DictionaryError ('Item not found');
  1877.   End;
  1878.  
  1879. Procedure TLongWordDictionary.SetItem (const Key : String; const Value : LongWord);
  1880. var I : Integer;
  1881.   Begin
  1882.     I := KeyIndex (Key, False);
  1883.     if I >= 0 then
  1884.       FValues [I] := Value else
  1885.       if AddOnSet then
  1886.         Add (Key, Value) else
  1887.         KeyNotFoundError (Key);
  1888.   End;
  1889.  
  1890. Procedure TLongWordDictionary.IndexError;
  1891.   Begin
  1892.     DictionaryError ('Index out of range');
  1893.   End;
  1894.  
  1895. Function TLongWordDictionary.Count : Integer;
  1896.   Begin
  1897.     Result := FKeys.Count;
  1898.     Assert (FValues.Count = Result, 'Key/Value count mismatch');
  1899.   End;
  1900.  
  1901. Function TLongWordDictionary.GetKeyByIndex (const Idx : Integer) : String;
  1902.   Begin
  1903.     {$IFOPT R+}
  1904.     if (Idx < 0) or (Idx >= FKeys.Count) then
  1905.       IndexError;
  1906.     {$ENDIF}
  1907.     Result := FKeys [Idx];
  1908.   End;
  1909.  
  1910. Procedure TLongWordDictionary.DeleteItemByIndex (const Idx : Integer);
  1911.   Begin
  1912.     {$IFOPT R+}
  1913.     if (Idx < 0) or (Idx >= FValues.Count) then
  1914.       IndexError;
  1915.     {$ENDIF}
  1916.     DeleteByIndex (Idx, -1);
  1917.   End;
  1918.  
  1919. Function TLongWordDictionary.GetItemByIndex (const Idx : Integer) : LongWord;
  1920.   Begin
  1921.     {$IFOPT R+}
  1922.     if (Idx < 0) or (Idx >= FValues.Count) then
  1923.       IndexError;
  1924.     {$ENDIF}
  1925.     Result := FValues [Idx];
  1926.   End;
  1927.  
  1928. Procedure TLongWordDictionary.SetItemByIndex (const Idx : Integer; const Value : LongWord);
  1929.   Begin
  1930.     {$IFOPT R+}
  1931.     if (Idx < 0) or (Idx >= FValues.Count) then
  1932.       IndexError;
  1933.     {$ENDIF}
  1934.     FValues [Idx] := Value;
  1935.   End;
  1936.  
  1937. Procedure TLongWordDictionary.Clear;
  1938.   Begin
  1939.     FKeys.Clear;
  1940.     FValues.Clear;
  1941.     Rehash;
  1942.   End;
  1943.  
  1944.  
  1945.  
  1946. {                                                                              }
  1947. { TInt64Dictionary                                                             }
  1948. {                                                                              }
  1949. Constructor TInt64Dictionary.Create;
  1950.   Begin
  1951.     inherited Create;
  1952.     FCaseSensitive := True;
  1953.     FDuplicatesAction := ddAccept;
  1954.     FAddOnSet := True;
  1955.     FKeys := TStringArray.Create;
  1956.     FValues := TInt64Array.Create;
  1957.   End;
  1958.   
  1959. Constructor TInt64Dictionary.CreateEx (const Keys : AStringArray; const Values : AInt64Array; const KeysCaseSensitive : Boolean; const AddOnSet : Boolean; const DuplicatesAction : TDictionaryDuplicatesAction);
  1960.   Begin
  1961.     inherited Create;
  1962.     if Assigned (Keys) then
  1963.       FKeys := Keys else
  1964.       FKeys := TStringArray.Create;
  1965.     if Assigned (Values) then
  1966.       FValues := Values else
  1967.       FValues := TInt64Array.Create;
  1968.     Assert (FKeys.Count = FValues.Count, 'Keys and Values must be equal length');
  1969.     FAddOnSet := AddOnSet;
  1970.     FDuplicatesAction := DuplicatesAction;
  1971.     Rehash;
  1972.   End;
  1973.  
  1974. Destructor TInt64Dictionary.Destroy;
  1975.   Begin
  1976.     FreeAndNil (FValues);
  1977.     FreeAndNil (FKeys);
  1978.     inherited Destroy;
  1979.   End;
  1980.  
  1981. Function TInt64Dictionary.GetKeysCaseSensitive : Boolean;
  1982.   Begin
  1983.     Result := FCaseSensitive;
  1984.   End;
  1985.  
  1986. Function TInt64Dictionary.GetAddOnSet : Boolean;
  1987.   Begin
  1988.     Result := FAddOnSet;
  1989.   End;
  1990.  
  1991. Procedure TInt64Dictionary.SetAddOnSet (const AddOnSet : Boolean);
  1992.   Begin
  1993.     FAddOnSet := AddOnSet;
  1994.   End;
  1995.  
  1996. Function TInt64Dictionary.GetHashTableSize : Integer;
  1997.   Begin
  1998.     Result := Length (FLookup);
  1999.   End;
  2000.  
  2001. Procedure TInt64Dictionary.Rehash;
  2002. var I, C, L : Integer;
  2003.   Begin
  2004.     C := FKeys.Count;
  2005.     L := DictionaryRehashSize (C);
  2006.     FLookup := nil;
  2007.     SetLength (FLookup, L);
  2008.     For I := 0 to C - 1 do
  2009.       Append (FLookup [HashStr (FKeys [I], L, FCaseSensitive)], I);
  2010.   End;
  2011.  
  2012. class Function TInt64Dictionary.CreateInstance : AType;
  2013.   Begin
  2014.     Result := TInt64Dictionary.Create;
  2015.   End;
  2016.  
  2017. Function TInt64Dictionary.LocateKey (const Key : String; var LookupIdx : Integer; const ErrorIfNotFound : Boolean) : Integer;
  2018. var H, I, J, L : Integer;
  2019.   Begin
  2020.     Result := -1;
  2021.     L := Length (FLookup);
  2022.     if L > 0 then
  2023.       begin
  2024.         H := HashStr (Key, L, FCaseSensitive);
  2025.         LookupIdx := H;
  2026.         For I := 0 to Length (FLookup [H]) - 1 do
  2027.           begin
  2028.             J := FLookup [H, I];
  2029.             if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2030.               begin
  2031.                 Result := J;
  2032.                 break;
  2033.               end;
  2034.           end;
  2035.       end;
  2036.     if ErrorIfNotFound and (Result = -1) then
  2037.       KeyNotFoundError (Key);
  2038.   End;
  2039.  
  2040. Function TInt64Dictionary.KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  2041. var H : Integer;
  2042.   Begin
  2043.     Result := LocateKey (Key, H, ErrorIfNotFound);
  2044.   End;
  2045.  
  2046. Procedure TInt64Dictionary.Add (const Key : String; const Value : Int64);
  2047. var H, L, I : Integer;
  2048.   Begin
  2049.     if FDuplicatesAction in [ddIgnore, ddError] then
  2050.       if LocateKey (Key, H, False) >= 0 then
  2051.         if FDuplicatesAction = ddIgnore then
  2052.           exit else
  2053.           DictionaryError ('Duplicate key: ' + QuoteText (Key));
  2054.     L := Length (FLookup);
  2055.     if L = 0 then
  2056.       begin
  2057.         Rehash;
  2058.         L := Length (FLookup);
  2059.       end;
  2060.     H := Integer (HashStr (Key, LongWord (L), FCaseSensitive));
  2061.     I := FKeys.AddItem (Key);
  2062.     Append (FLookup [H], I);
  2063.     FValues.AddItem (Value);
  2064.  
  2065.     if (I + 1) div AverageHashChainSize > L then
  2066.       Rehash;
  2067.   End;
  2068.  
  2069. Procedure TInt64Dictionary.DeleteByIndex (const Idx : Integer; const Hash : Integer);
  2070. var I, J, H : Integer;
  2071.   Begin
  2072.     if Hash = -1 then
  2073.       H := HashStr (FKeys [Idx], Length (FLookup), FCaseSensitive) else
  2074.       H := Hash;
  2075.     FKeys.Delete (Idx);
  2076.     FValues.Delete (Idx);
  2077.     J := PosNext (Idx, FLookup [H]);
  2078.     Assert (J >= 0, 'Invalid hash value/lookup table');
  2079.     Remove (FLookup [H], J, 1);
  2080.  
  2081.     For I := 0 to Length (FLookup) - 1 do
  2082.       For J := 0 to Length (FLookup [I]) - 1 do
  2083.         if FLookup [I][J] > Idx then
  2084.           Dec (FLookup [I][J]);
  2085.   End;
  2086.  
  2087. Procedure TInt64Dictionary.Delete (const Key : String);
  2088. var I, H : Integer;
  2089.   Begin
  2090.     I := LocateKey (Key, H, True);
  2091.     DeleteByIndex (I, H);
  2092.   End;
  2093.  
  2094. Function TInt64Dictionary.HasKey (const Key : String) : Boolean;
  2095.   Begin
  2096.     Result := KeyIndex (Key, False) >= 0;
  2097.   End;
  2098.  
  2099. Procedure TInt64Dictionary.Rename (const Key, NewKey : String);
  2100. var I, J, H : Integer;
  2101.   Begin
  2102.     I := LocateKey (Key, H, True);
  2103.     FKeys [I] := NewKey;
  2104.     J := PosNext (I, FLookup [H]);
  2105.     Assert (J >= 0, 'Invalid hash value/lookup table');
  2106.     Remove (FLookup [H], J, 1);
  2107.     Append (FLookup [HashStr (NewKey, Length (FLookup), FCaseSensitive)], I);
  2108.   End;
  2109.  
  2110. Function TInt64Dictionary.GetDuplicatesAction : TDictionaryDuplicatesAction;
  2111.   Begin
  2112.     Result := FDuplicatesAction;
  2113.   End;
  2114.  
  2115. Procedure TInt64Dictionary.SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction);
  2116.   Begin
  2117.     FDuplicatesAction := DuplicatesAction;
  2118.   End;
  2119.  
  2120. Function TInt64Dictionary.LocateItem (const Key : String; var Value : Int64) : Integer;
  2121.   Begin
  2122.     Result := KeyIndex (Key, False);
  2123.     if Result >= 0 then
  2124.       Value := FValues [Result] else
  2125.       Value := 0;
  2126.   End;
  2127.  
  2128. Function TInt64Dictionary.LocateNext (const Key : String; const Idx : Integer; var Value : Int64) : Integer;
  2129. var L, H, I, J, K : Integer;
  2130.   Begin
  2131.     Result := -1;
  2132.     L := Length (FLookup);
  2133.     if L = 0 then
  2134.       DictionaryError ('Item not found');
  2135.     H := HashStr (Key, L, FCaseSensitive);
  2136.     For I := 0 to Length (FLookup [H]) - 1 do
  2137.       begin
  2138.         J := FLookup [H, I];
  2139.         if J = Idx then
  2140.           begin
  2141.             if not cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2142.               DictionaryError ('Item not found');
  2143.             For K := I + 1 to Length (FLookup [H]) - 1 do
  2144.               begin
  2145.                 J := FLookup [H, K];
  2146.                 if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2147.                   begin
  2148.                     Value := FValues [J];
  2149.                     Result := J;
  2150.                     exit;
  2151.                   end;
  2152.               end;
  2153.             Result := -1;
  2154.             exit;
  2155.           end;
  2156.       end;
  2157.     DictionaryError ('Item not found');
  2158.   End;
  2159.  
  2160. Procedure TInt64Dictionary.SetItem (const Key : String; const Value : Int64);
  2161. var I : Integer;
  2162.   Begin
  2163.     I := KeyIndex (Key, False);
  2164.     if I >= 0 then
  2165.       FValues [I] := Value else
  2166.       if AddOnSet then
  2167.         Add (Key, Value) else
  2168.         KeyNotFoundError (Key);
  2169.   End;
  2170.  
  2171. Procedure TInt64Dictionary.IndexError;
  2172.   Begin
  2173.     DictionaryError ('Index out of range');
  2174.   End;
  2175.  
  2176. Function TInt64Dictionary.Count : Integer;
  2177.   Begin
  2178.     Result := FKeys.Count;
  2179.     Assert (FValues.Count = Result, 'Key/Value count mismatch');
  2180.   End;
  2181.  
  2182. Function TInt64Dictionary.GetKeyByIndex (const Idx : Integer) : String;
  2183.   Begin
  2184.     {$IFOPT R+}
  2185.     if (Idx < 0) or (Idx >= FKeys.Count) then
  2186.       IndexError;
  2187.     {$ENDIF}
  2188.     Result := FKeys [Idx];
  2189.   End;
  2190.  
  2191. Procedure TInt64Dictionary.DeleteItemByIndex (const Idx : Integer);
  2192.   Begin
  2193.     {$IFOPT R+}
  2194.     if (Idx < 0) or (Idx >= FValues.Count) then
  2195.       IndexError;
  2196.     {$ENDIF}
  2197.     DeleteByIndex (Idx, -1);
  2198.   End;
  2199.  
  2200. Function TInt64Dictionary.GetItemByIndex (const Idx : Integer) : Int64;
  2201.   Begin
  2202.     {$IFOPT R+}
  2203.     if (Idx < 0) or (Idx >= FValues.Count) then
  2204.       IndexError;
  2205.     {$ENDIF}
  2206.     Result := FValues [Idx];
  2207.   End;
  2208.  
  2209. Procedure TInt64Dictionary.SetItemByIndex (const Idx : Integer; const Value : Int64);
  2210.   Begin
  2211.     {$IFOPT R+}
  2212.     if (Idx < 0) or (Idx >= FValues.Count) then
  2213.       IndexError;
  2214.     {$ENDIF}
  2215.     FValues [Idx] := Value;
  2216.   End;
  2217.  
  2218. Procedure TInt64Dictionary.Clear;
  2219.   Begin
  2220.     FKeys.Clear;
  2221.     FValues.Clear;
  2222.     Rehash;
  2223.   End;
  2224.  
  2225.  
  2226.  
  2227. {                                                                              }
  2228. { TSingleDictionary                                                            }
  2229. {                                                                              }
  2230. Constructor TSingleDictionary.Create;
  2231.   Begin
  2232.     inherited Create;
  2233.     FCaseSensitive := True;
  2234.     FDuplicatesAction := ddAccept;
  2235.     FAddOnSet := True;
  2236.     FKeys := TStringArray.Create;
  2237.     FValues := TSingleArray.Create;
  2238.   End;
  2239.   
  2240. Constructor TSingleDictionary.CreateEx (const Keys : AStringArray; const Values : ASingleArray; const KeysCaseSensitive : Boolean; const AddOnSet : Boolean; const DuplicatesAction : TDictionaryDuplicatesAction);
  2241.   Begin
  2242.     inherited Create;
  2243.     if Assigned (Keys) then
  2244.       FKeys := Keys else
  2245.       FKeys := TStringArray.Create;
  2246.     if Assigned (Values) then
  2247.       FValues := Values else
  2248.       FValues := TSingleArray.Create;
  2249.     Assert (FKeys.Count = FValues.Count, 'Keys and Values must be equal length');
  2250.     FAddOnSet := AddOnSet;
  2251.     FDuplicatesAction := DuplicatesAction;
  2252.     Rehash;
  2253.   End;
  2254.  
  2255. Destructor TSingleDictionary.Destroy;
  2256.   Begin
  2257.     FreeAndNil (FValues);
  2258.     FreeAndNil (FKeys);
  2259.     inherited Destroy;
  2260.   End;
  2261.  
  2262. Function TSingleDictionary.GetKeysCaseSensitive : Boolean;
  2263.   Begin
  2264.     Result := FCaseSensitive;
  2265.   End;
  2266.  
  2267. Function TSingleDictionary.GetAddOnSet : Boolean;
  2268.   Begin
  2269.     Result := FAddOnSet;
  2270.   End;
  2271.  
  2272. Procedure TSingleDictionary.SetAddOnSet (const AddOnSet : Boolean);
  2273.   Begin
  2274.     FAddOnSet := AddOnSet;
  2275.   End;
  2276.  
  2277. Function TSingleDictionary.GetHashTableSize : Integer;
  2278.   Begin
  2279.     Result := Length (FLookup);
  2280.   End;
  2281.  
  2282. Procedure TSingleDictionary.Rehash;
  2283. var I, C, L : Integer;
  2284.   Begin
  2285.     C := FKeys.Count;
  2286.     L := DictionaryRehashSize (C);
  2287.     FLookup := nil;
  2288.     SetLength (FLookup, L);
  2289.     For I := 0 to C - 1 do
  2290.       Append (FLookup [HashStr (FKeys [I], L, FCaseSensitive)], I);
  2291.   End;
  2292.  
  2293. class Function TSingleDictionary.CreateInstance : AType;
  2294.   Begin
  2295.     Result := TSingleDictionary.Create;
  2296.   End;
  2297.  
  2298. Function TSingleDictionary.LocateKey (const Key : String; var LookupIdx : Integer; const ErrorIfNotFound : Boolean) : Integer;
  2299. var H, I, J, L : Integer;
  2300.   Begin
  2301.     Result := -1;
  2302.     L := Length (FLookup);
  2303.     if L > 0 then
  2304.       begin
  2305.         H := HashStr (Key, L, FCaseSensitive);
  2306.         LookupIdx := H;
  2307.         For I := 0 to Length (FLookup [H]) - 1 do
  2308.           begin
  2309.             J := FLookup [H, I];
  2310.             if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2311.               begin
  2312.                 Result := J;
  2313.                 break;
  2314.               end;
  2315.           end;
  2316.       end;
  2317.     if ErrorIfNotFound and (Result = -1) then
  2318.       KeyNotFoundError (Key);
  2319.   End;
  2320.  
  2321. Function TSingleDictionary.KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  2322. var H : Integer;
  2323.   Begin
  2324.     Result := LocateKey (Key, H, ErrorIfNotFound);
  2325.   End;
  2326.  
  2327. Procedure TSingleDictionary.Add (const Key : String; const Value : Single);
  2328. var H, L, I : Integer;
  2329.   Begin
  2330.     if FDuplicatesAction in [ddIgnore, ddError] then
  2331.       if LocateKey (Key, H, False) >= 0 then
  2332.         if FDuplicatesAction = ddIgnore then
  2333.           exit else
  2334.           DictionaryError ('Duplicate key: ' + QuoteText (Key));
  2335.     L := Length (FLookup);
  2336.     if L = 0 then
  2337.       begin
  2338.         Rehash;
  2339.         L := Length (FLookup);
  2340.       end;
  2341.     H := Integer (HashStr (Key, LongWord (L), FCaseSensitive));
  2342.     I := FKeys.AddItem (Key);
  2343.     Append (FLookup [H], I);
  2344.     FValues.AddItem (Value);
  2345.  
  2346.     if (I + 1) div AverageHashChainSize > L then
  2347.       Rehash;
  2348.   End;
  2349.  
  2350. Procedure TSingleDictionary.DeleteByIndex (const Idx : Integer; const Hash : Integer);
  2351. var I, J, H : Integer;
  2352.   Begin
  2353.     if Hash = -1 then
  2354.       H := HashStr (FKeys [Idx], Length (FLookup), FCaseSensitive) else
  2355.       H := Hash;
  2356.     FKeys.Delete (Idx);
  2357.     FValues.Delete (Idx);
  2358.     J := PosNext (Idx, FLookup [H]);
  2359.     Assert (J >= 0, 'Invalid hash value/lookup table');
  2360.     Remove (FLookup [H], J, 1);
  2361.  
  2362.     For I := 0 to Length (FLookup) - 1 do
  2363.       For J := 0 to Length (FLookup [I]) - 1 do
  2364.         if FLookup [I][J] > Idx then
  2365.           Dec (FLookup [I][J]);
  2366.   End;
  2367.  
  2368. Procedure TSingleDictionary.Delete (const Key : String);
  2369. var I, H : Integer;
  2370.   Begin
  2371.     I := LocateKey (Key, H, True);
  2372.     DeleteByIndex (I, H);
  2373.   End;
  2374.  
  2375. Function TSingleDictionary.HasKey (const Key : String) : Boolean;
  2376.   Begin
  2377.     Result := KeyIndex (Key, False) >= 0;
  2378.   End;
  2379.  
  2380. Procedure TSingleDictionary.Rename (const Key, NewKey : String);
  2381. var I, J, H : Integer;
  2382.   Begin
  2383.     I := LocateKey (Key, H, True);
  2384.     FKeys [I] := NewKey;
  2385.     J := PosNext (I, FLookup [H]);
  2386.     Assert (J >= 0, 'Invalid hash value/lookup table');
  2387.     Remove (FLookup [H], J, 1);
  2388.     Append (FLookup [HashStr (NewKey, Length (FLookup), FCaseSensitive)], I);
  2389.   End;
  2390.  
  2391. Function TSingleDictionary.GetDuplicatesAction : TDictionaryDuplicatesAction;
  2392.   Begin
  2393.     Result := FDuplicatesAction;
  2394.   End;
  2395.  
  2396. Procedure TSingleDictionary.SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction);
  2397.   Begin
  2398.     FDuplicatesAction := DuplicatesAction;
  2399.   End;
  2400.  
  2401. Function TSingleDictionary.LocateItem (const Key : String; var Value : Single) : Integer;
  2402.   Begin
  2403.     Result := KeyIndex (Key, False);
  2404.     if Result >= 0 then
  2405.       Value := FValues [Result] else
  2406.       Value := 0.0;
  2407.   End;
  2408.  
  2409. Function TSingleDictionary.LocateNext (const Key : String; const Idx : Integer; var Value : Single) : Integer;
  2410. var L, H, I, J, K : Integer;
  2411.   Begin
  2412.     Result := -1;
  2413.     L := Length (FLookup);
  2414.     if L = 0 then
  2415.       DictionaryError ('Item not found');
  2416.     H := HashStr (Key, L, FCaseSensitive);
  2417.     For I := 0 to Length (FLookup [H]) - 1 do
  2418.       begin
  2419.         J := FLookup [H, I];
  2420.         if J = Idx then
  2421.           begin
  2422.             if not cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2423.               DictionaryError ('Item not found');
  2424.             For K := I + 1 to Length (FLookup [H]) - 1 do
  2425.               begin
  2426.                 J := FLookup [H, K];
  2427.                 if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2428.                   begin
  2429.                     Value := FValues [J];
  2430.                     Result := J;
  2431.                     exit;
  2432.                   end;
  2433.               end;
  2434.             Result := -1;
  2435.             exit;
  2436.           end;
  2437.       end;
  2438.     DictionaryError ('Item not found');
  2439.   End;
  2440.  
  2441. Procedure TSingleDictionary.SetItem (const Key : String; const Value : Single);
  2442. var I : Integer;
  2443.   Begin
  2444.     I := KeyIndex (Key, False);
  2445.     if I >= 0 then
  2446.       FValues [I] := Value else
  2447.       if AddOnSet then
  2448.         Add (Key, Value) else
  2449.         KeyNotFoundError (Key);
  2450.   End;
  2451.  
  2452. Procedure TSingleDictionary.IndexError;
  2453.   Begin
  2454.     DictionaryError ('Index out of range');
  2455.   End;
  2456.  
  2457. Function TSingleDictionary.Count : Integer;
  2458.   Begin
  2459.     Result := FKeys.Count;
  2460.     Assert (FValues.Count = Result, 'Key/Value count mismatch');
  2461.   End;
  2462.  
  2463. Function TSingleDictionary.GetKeyByIndex (const Idx : Integer) : String;
  2464.   Begin
  2465.     {$IFOPT R+}
  2466.     if (Idx < 0) or (Idx >= FKeys.Count) then
  2467.       IndexError;
  2468.     {$ENDIF}
  2469.     Result := FKeys [Idx];
  2470.   End;
  2471.  
  2472. Procedure TSingleDictionary.DeleteItemByIndex (const Idx : Integer);
  2473.   Begin
  2474.     {$IFOPT R+}
  2475.     if (Idx < 0) or (Idx >= FValues.Count) then
  2476.       IndexError;
  2477.     {$ENDIF}
  2478.     DeleteByIndex (Idx, -1);
  2479.   End;
  2480.  
  2481. Function TSingleDictionary.GetItemByIndex (const Idx : Integer) : Single;
  2482.   Begin
  2483.     {$IFOPT R+}
  2484.     if (Idx < 0) or (Idx >= FValues.Count) then
  2485.       IndexError;
  2486.     {$ENDIF}
  2487.     Result := FValues [Idx];
  2488.   End;
  2489.  
  2490. Procedure TSingleDictionary.SetItemByIndex (const Idx : Integer; const Value : Single);
  2491.   Begin
  2492.     {$IFOPT R+}
  2493.     if (Idx < 0) or (Idx >= FValues.Count) then
  2494.       IndexError;
  2495.     {$ENDIF}
  2496.     FValues [Idx] := Value;
  2497.   End;
  2498.  
  2499. Procedure TSingleDictionary.Clear;
  2500.   Begin
  2501.     FKeys.Clear;
  2502.     FValues.Clear;
  2503.     Rehash;
  2504.   End;
  2505.  
  2506.  
  2507.  
  2508. {                                                                              }
  2509. { TDoubleDictionary                                                            }
  2510. {                                                                              }
  2511. Constructor TDoubleDictionary.Create;
  2512.   Begin
  2513.     inherited Create;
  2514.     FCaseSensitive := True;
  2515.     FDuplicatesAction := ddAccept;
  2516.     FAddOnSet := True;
  2517.     FKeys := TStringArray.Create;
  2518.     FValues := TDoubleArray.Create;
  2519.   End;
  2520.   
  2521. Constructor TDoubleDictionary.CreateEx (const Keys : AStringArray; const Values : ADoubleArray; const KeysCaseSensitive : Boolean; const AddOnSet : Boolean; const DuplicatesAction : TDictionaryDuplicatesAction);
  2522.   Begin
  2523.     inherited Create;
  2524.     if Assigned (Keys) then
  2525.       FKeys := Keys else
  2526.       FKeys := TStringArray.Create;
  2527.     if Assigned (Values) then
  2528.       FValues := Values else
  2529.       FValues := TDoubleArray.Create;
  2530.     Assert (FKeys.Count = FValues.Count, 'Keys and Values must be equal length');
  2531.     FAddOnSet := AddOnSet;
  2532.     FDuplicatesAction := DuplicatesAction;
  2533.     Rehash;
  2534.   End;
  2535.  
  2536. Destructor TDoubleDictionary.Destroy;
  2537.   Begin
  2538.     FreeAndNil (FValues);
  2539.     FreeAndNil (FKeys);
  2540.     inherited Destroy;
  2541.   End;
  2542.  
  2543. Function TDoubleDictionary.GetKeysCaseSensitive : Boolean;
  2544.   Begin
  2545.     Result := FCaseSensitive;
  2546.   End;
  2547.  
  2548. Function TDoubleDictionary.GetAddOnSet : Boolean;
  2549.   Begin
  2550.     Result := FAddOnSet;
  2551.   End;
  2552.  
  2553. Procedure TDoubleDictionary.SetAddOnSet (const AddOnSet : Boolean);
  2554.   Begin
  2555.     FAddOnSet := AddOnSet;
  2556.   End;
  2557.  
  2558. Function TDoubleDictionary.GetHashTableSize : Integer;
  2559.   Begin
  2560.     Result := Length (FLookup);
  2561.   End;
  2562.  
  2563. Procedure TDoubleDictionary.Rehash;
  2564. var I, C, L : Integer;
  2565.   Begin
  2566.     C := FKeys.Count;
  2567.     L := DictionaryRehashSize (C);
  2568.     FLookup := nil;
  2569.     SetLength (FLookup, L);
  2570.     For I := 0 to C - 1 do
  2571.       Append (FLookup [HashStr (FKeys [I], L, FCaseSensitive)], I);
  2572.   End;
  2573.  
  2574. class Function TDoubleDictionary.CreateInstance : AType;
  2575.   Begin
  2576.     Result := TDoubleDictionary.Create;
  2577.   End;
  2578.  
  2579. Function TDoubleDictionary.LocateKey (const Key : String; var LookupIdx : Integer; const ErrorIfNotFound : Boolean) : Integer;
  2580. var H, I, J, L : Integer;
  2581.   Begin
  2582.     Result := -1;
  2583.     L := Length (FLookup);
  2584.     if L > 0 then
  2585.       begin
  2586.         H := HashStr (Key, L, FCaseSensitive);
  2587.         LookupIdx := H;
  2588.         For I := 0 to Length (FLookup [H]) - 1 do
  2589.           begin
  2590.             J := FLookup [H, I];
  2591.             if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2592.               begin
  2593.                 Result := J;
  2594.                 break;
  2595.               end;
  2596.           end;
  2597.       end;
  2598.     if ErrorIfNotFound and (Result = -1) then
  2599.       KeyNotFoundError (Key);
  2600.   End;
  2601.  
  2602. Function TDoubleDictionary.KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  2603. var H : Integer;
  2604.   Begin
  2605.     Result := LocateKey (Key, H, ErrorIfNotFound);
  2606.   End;
  2607.  
  2608. Procedure TDoubleDictionary.Add (const Key : String; const Value : Double);
  2609. var H, L, I : Integer;
  2610.   Begin
  2611.     if FDuplicatesAction in [ddIgnore, ddError] then
  2612.       if LocateKey (Key, H, False) >= 0 then
  2613.         if FDuplicatesAction = ddIgnore then
  2614.           exit else
  2615.           DictionaryError ('Duplicate key: ' + QuoteText (Key));
  2616.     L := Length (FLookup);
  2617.     if L = 0 then
  2618.       begin
  2619.         Rehash;
  2620.         L := Length (FLookup);
  2621.       end;
  2622.     H := Integer (HashStr (Key, LongWord (L), FCaseSensitive));
  2623.     I := FKeys.AddItem (Key);
  2624.     Append (FLookup [H], I);
  2625.     FValues.AddItem (Value);
  2626.  
  2627.     if (I + 1) div AverageHashChainSize > L then
  2628.       Rehash;
  2629.   End;
  2630.  
  2631. Procedure TDoubleDictionary.DeleteByIndex (const Idx : Integer; const Hash : Integer);
  2632. var I, J, H : Integer;
  2633.   Begin
  2634.     if Hash = -1 then
  2635.       H := HashStr (FKeys [Idx], Length (FLookup), FCaseSensitive) else
  2636.       H := Hash;
  2637.     FKeys.Delete (Idx);
  2638.     FValues.Delete (Idx);
  2639.     J := PosNext (Idx, FLookup [H]);
  2640.     Assert (J >= 0, 'Invalid hash value/lookup table');
  2641.     Remove (FLookup [H], J, 1);
  2642.  
  2643.     For I := 0 to Length (FLookup) - 1 do
  2644.       For J := 0 to Length (FLookup [I]) - 1 do
  2645.         if FLookup [I][J] > Idx then
  2646.           Dec (FLookup [I][J]);
  2647.   End;
  2648.  
  2649. Procedure TDoubleDictionary.Delete (const Key : String);
  2650. var I, H : Integer;
  2651.   Begin
  2652.     I := LocateKey (Key, H, True);
  2653.     DeleteByIndex (I, H);
  2654.   End;
  2655.  
  2656. Function TDoubleDictionary.HasKey (const Key : String) : Boolean;
  2657.   Begin
  2658.     Result := KeyIndex (Key, False) >= 0;
  2659.   End;
  2660.  
  2661. Procedure TDoubleDictionary.Rename (const Key, NewKey : String);
  2662. var I, J, H : Integer;
  2663.   Begin
  2664.     I := LocateKey (Key, H, True);
  2665.     FKeys [I] := NewKey;
  2666.     J := PosNext (I, FLookup [H]);
  2667.     Assert (J >= 0, 'Invalid hash value/lookup table');
  2668.     Remove (FLookup [H], J, 1);
  2669.     Append (FLookup [HashStr (NewKey, Length (FLookup), FCaseSensitive)], I);
  2670.   End;
  2671.  
  2672. Function TDoubleDictionary.GetDuplicatesAction : TDictionaryDuplicatesAction;
  2673.   Begin
  2674.     Result := FDuplicatesAction;
  2675.   End;
  2676.  
  2677. Procedure TDoubleDictionary.SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction);
  2678.   Begin
  2679.     FDuplicatesAction := DuplicatesAction;
  2680.   End;
  2681.  
  2682. Function TDoubleDictionary.LocateItem (const Key : String; var Value : Double) : Integer;
  2683.   Begin
  2684.     Result := KeyIndex (Key, False);
  2685.     if Result >= 0 then
  2686.       Value := FValues [Result] else
  2687.       Value := 0.0;
  2688.   End;
  2689.  
  2690. Function TDoubleDictionary.LocateNext (const Key : String; const Idx : Integer; var Value : Double) : Integer;
  2691. var L, H, I, J, K : Integer;
  2692.   Begin
  2693.     Result := -1;
  2694.     L := Length (FLookup);
  2695.     if L = 0 then
  2696.       DictionaryError ('Item not found');
  2697.     H := HashStr (Key, L, FCaseSensitive);
  2698.     For I := 0 to Length (FLookup [H]) - 1 do
  2699.       begin
  2700.         J := FLookup [H, I];
  2701.         if J = Idx then
  2702.           begin
  2703.             if not cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2704.               DictionaryError ('Item not found');
  2705.             For K := I + 1 to Length (FLookup [H]) - 1 do
  2706.               begin
  2707.                 J := FLookup [H, K];
  2708.                 if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2709.                   begin
  2710.                     Value := FValues [J];
  2711.                     Result := J;
  2712.                     exit;
  2713.                   end;
  2714.               end;
  2715.             Result := -1;
  2716.             exit;
  2717.           end;
  2718.       end;
  2719.     DictionaryError ('Item not found');
  2720.   End;
  2721.  
  2722. Procedure TDoubleDictionary.SetItem (const Key : String; const Value : Double);
  2723. var I : Integer;
  2724.   Begin
  2725.     I := KeyIndex (Key, False);
  2726.     if I >= 0 then
  2727.       FValues [I] := Value else
  2728.       if AddOnSet then
  2729.         Add (Key, Value) else
  2730.         KeyNotFoundError (Key);
  2731.   End;
  2732.  
  2733. Procedure TDoubleDictionary.IndexError;
  2734.   Begin
  2735.     DictionaryError ('Index out of range');
  2736.   End;
  2737.  
  2738. Function TDoubleDictionary.Count : Integer;
  2739.   Begin
  2740.     Result := FKeys.Count;
  2741.     Assert (FValues.Count = Result, 'Key/Value count mismatch');
  2742.   End;
  2743.  
  2744. Function TDoubleDictionary.GetKeyByIndex (const Idx : Integer) : String;
  2745.   Begin
  2746.     {$IFOPT R+}
  2747.     if (Idx < 0) or (Idx >= FKeys.Count) then
  2748.       IndexError;
  2749.     {$ENDIF}
  2750.     Result := FKeys [Idx];
  2751.   End;
  2752.  
  2753. Procedure TDoubleDictionary.DeleteItemByIndex (const Idx : Integer);
  2754.   Begin
  2755.     {$IFOPT R+}
  2756.     if (Idx < 0) or (Idx >= FValues.Count) then
  2757.       IndexError;
  2758.     {$ENDIF}
  2759.     DeleteByIndex (Idx, -1);
  2760.   End;
  2761.  
  2762. Function TDoubleDictionary.GetItemByIndex (const Idx : Integer) : Double;
  2763.   Begin
  2764.     {$IFOPT R+}
  2765.     if (Idx < 0) or (Idx >= FValues.Count) then
  2766.       IndexError;
  2767.     {$ENDIF}
  2768.     Result := FValues [Idx];
  2769.   End;
  2770.  
  2771. Procedure TDoubleDictionary.SetItemByIndex (const Idx : Integer; const Value : Double);
  2772.   Begin
  2773.     {$IFOPT R+}
  2774.     if (Idx < 0) or (Idx >= FValues.Count) then
  2775.       IndexError;
  2776.     {$ENDIF}
  2777.     FValues [Idx] := Value;
  2778.   End;
  2779.  
  2780. Procedure TDoubleDictionary.Clear;
  2781.   Begin
  2782.     FKeys.Clear;
  2783.     FValues.Clear;
  2784.     Rehash;
  2785.   End;
  2786.  
  2787.  
  2788.  
  2789. {                                                                              }
  2790. { TExtendedDictionary                                                          }
  2791. {                                                                              }
  2792. Constructor TExtendedDictionary.Create;
  2793.   Begin
  2794.     inherited Create;
  2795.     FCaseSensitive := True;
  2796.     FDuplicatesAction := ddAccept;
  2797.     FAddOnSet := True;
  2798.     FKeys := TStringArray.Create;
  2799.     FValues := TExtendedArray.Create;
  2800.   End;
  2801.   
  2802. Constructor TExtendedDictionary.CreateEx (const Keys : AStringArray; const Values : AExtendedArray; const KeysCaseSensitive : Boolean; const AddOnSet : Boolean; const DuplicatesAction : TDictionaryDuplicatesAction);
  2803.   Begin
  2804.     inherited Create;
  2805.     if Assigned (Keys) then
  2806.       FKeys := Keys else
  2807.       FKeys := TStringArray.Create;
  2808.     if Assigned (Values) then
  2809.       FValues := Values else
  2810.       FValues := TExtendedArray.Create;
  2811.     Assert (FKeys.Count = FValues.Count, 'Keys and Values must be equal length');
  2812.     FAddOnSet := AddOnSet;
  2813.     FDuplicatesAction := DuplicatesAction;
  2814.     Rehash;
  2815.   End;
  2816.  
  2817. Destructor TExtendedDictionary.Destroy;
  2818.   Begin
  2819.     FreeAndNil (FValues);
  2820.     FreeAndNil (FKeys);
  2821.     inherited Destroy;
  2822.   End;
  2823.  
  2824. Function TExtendedDictionary.GetKeysCaseSensitive : Boolean;
  2825.   Begin
  2826.     Result := FCaseSensitive;
  2827.   End;
  2828.  
  2829. Function TExtendedDictionary.GetAddOnSet : Boolean;
  2830.   Begin
  2831.     Result := FAddOnSet;
  2832.   End;
  2833.  
  2834. Procedure TExtendedDictionary.SetAddOnSet (const AddOnSet : Boolean);
  2835.   Begin
  2836.     FAddOnSet := AddOnSet;
  2837.   End;
  2838.  
  2839. Function TExtendedDictionary.GetHashTableSize : Integer;
  2840.   Begin
  2841.     Result := Length (FLookup);
  2842.   End;
  2843.  
  2844. Procedure TExtendedDictionary.Rehash;
  2845. var I, C, L : Integer;
  2846.   Begin
  2847.     C := FKeys.Count;
  2848.     L := DictionaryRehashSize (C);
  2849.     FLookup := nil;
  2850.     SetLength (FLookup, L);
  2851.     For I := 0 to C - 1 do
  2852.       Append (FLookup [HashStr (FKeys [I], L, FCaseSensitive)], I);
  2853.   End;
  2854.  
  2855. class Function TExtendedDictionary.CreateInstance : AType;
  2856.   Begin
  2857.     Result := TExtendedDictionary.Create;
  2858.   End;
  2859.  
  2860. Function TExtendedDictionary.LocateKey (const Key : String; var LookupIdx : Integer; const ErrorIfNotFound : Boolean) : Integer;
  2861. var H, I, J, L : Integer;
  2862.   Begin
  2863.     Result := -1;
  2864.     L := Length (FLookup);
  2865.     if L > 0 then
  2866.       begin
  2867.         H := HashStr (Key, L, FCaseSensitive);
  2868.         LookupIdx := H;
  2869.         For I := 0 to Length (FLookup [H]) - 1 do
  2870.           begin
  2871.             J := FLookup [H, I];
  2872.             if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2873.               begin
  2874.                 Result := J;
  2875.                 break;
  2876.               end;
  2877.           end;
  2878.       end;
  2879.     if ErrorIfNotFound and (Result = -1) then
  2880.       KeyNotFoundError (Key);
  2881.   End;
  2882.  
  2883. Function TExtendedDictionary.KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  2884. var H : Integer;
  2885.   Begin
  2886.     Result := LocateKey (Key, H, ErrorIfNotFound);
  2887.   End;
  2888.  
  2889. Procedure TExtendedDictionary.Add (const Key : String; const Value : Extended);
  2890. var H, L, I : Integer;
  2891.   Begin
  2892.     if FDuplicatesAction in [ddIgnore, ddError] then
  2893.       if LocateKey (Key, H, False) >= 0 then
  2894.         if FDuplicatesAction = ddIgnore then
  2895.           exit else
  2896.           DictionaryError ('Duplicate key: ' + QuoteText (Key));
  2897.     L := Length (FLookup);
  2898.     if L = 0 then
  2899.       begin
  2900.         Rehash;
  2901.         L := Length (FLookup);
  2902.       end;
  2903.     H := Integer (HashStr (Key, LongWord (L), FCaseSensitive));
  2904.     I := FKeys.AddItem (Key);
  2905.     Append (FLookup [H], I);
  2906.     FValues.AddItem (Value);
  2907.  
  2908.     if (I + 1) div AverageHashChainSize > L then
  2909.       Rehash;
  2910.   End;
  2911.  
  2912. Procedure TExtendedDictionary.DeleteByIndex (const Idx : Integer; const Hash : Integer);
  2913. var I, J, H : Integer;
  2914.   Begin
  2915.     if Hash = -1 then
  2916.       H := HashStr (FKeys [Idx], Length (FLookup), FCaseSensitive) else
  2917.       H := Hash;
  2918.     FKeys.Delete (Idx);
  2919.     FValues.Delete (Idx);
  2920.     J := PosNext (Idx, FLookup [H]);
  2921.     Assert (J >= 0, 'Invalid hash value/lookup table');
  2922.     Remove (FLookup [H], J, 1);
  2923.  
  2924.     For I := 0 to Length (FLookup) - 1 do
  2925.       For J := 0 to Length (FLookup [I]) - 1 do
  2926.         if FLookup [I][J] > Idx then
  2927.           Dec (FLookup [I][J]);
  2928.   End;
  2929.  
  2930. Procedure TExtendedDictionary.Delete (const Key : String);
  2931. var I, H : Integer;
  2932.   Begin
  2933.     I := LocateKey (Key, H, True);
  2934.     DeleteByIndex (I, H);
  2935.   End;
  2936.  
  2937. Function TExtendedDictionary.HasKey (const Key : String) : Boolean;
  2938.   Begin
  2939.     Result := KeyIndex (Key, False) >= 0;
  2940.   End;
  2941.  
  2942. Procedure TExtendedDictionary.Rename (const Key, NewKey : String);
  2943. var I, J, H : Integer;
  2944.   Begin
  2945.     I := LocateKey (Key, H, True);
  2946.     FKeys [I] := NewKey;
  2947.     J := PosNext (I, FLookup [H]);
  2948.     Assert (J >= 0, 'Invalid hash value/lookup table');
  2949.     Remove (FLookup [H], J, 1);
  2950.     Append (FLookup [HashStr (NewKey, Length (FLookup), FCaseSensitive)], I);
  2951.   End;
  2952.  
  2953. Function TExtendedDictionary.GetDuplicatesAction : TDictionaryDuplicatesAction;
  2954.   Begin
  2955.     Result := FDuplicatesAction;
  2956.   End;
  2957.  
  2958. Procedure TExtendedDictionary.SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction);
  2959.   Begin
  2960.     FDuplicatesAction := DuplicatesAction;
  2961.   End;
  2962.  
  2963. Function TExtendedDictionary.LocateItem (const Key : String; var Value : Extended) : Integer;
  2964.   Begin
  2965.     Result := KeyIndex (Key, False);
  2966.     if Result >= 0 then
  2967.       Value := FValues [Result] else
  2968.       Value := 0.0;
  2969.   End;
  2970.  
  2971. Function TExtendedDictionary.LocateNext (const Key : String; const Idx : Integer; var Value : Extended) : Integer;
  2972. var L, H, I, J, K : Integer;
  2973.   Begin
  2974.     Result := -1;
  2975.     L := Length (FLookup);
  2976.     if L = 0 then
  2977.       DictionaryError ('Item not found');
  2978.     H := HashStr (Key, L, FCaseSensitive);
  2979.     For I := 0 to Length (FLookup [H]) - 1 do
  2980.       begin
  2981.         J := FLookup [H, I];
  2982.         if J = Idx then
  2983.           begin
  2984.             if not cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2985.               DictionaryError ('Item not found');
  2986.             For K := I + 1 to Length (FLookup [H]) - 1 do
  2987.               begin
  2988.                 J := FLookup [H, K];
  2989.                 if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  2990.                   begin
  2991.                     Value := FValues [J];
  2992.                     Result := J;
  2993.                     exit;
  2994.                   end;
  2995.               end;
  2996.             Result := -1;
  2997.             exit;
  2998.           end;
  2999.       end;
  3000.     DictionaryError ('Item not found');
  3001.   End;
  3002.  
  3003. Procedure TExtendedDictionary.SetItem (const Key : String; const Value : Extended);
  3004. var I : Integer;
  3005.   Begin
  3006.     I := KeyIndex (Key, False);
  3007.     if I >= 0 then
  3008.       FValues [I] := Value else
  3009.       if AddOnSet then
  3010.         Add (Key, Value) else
  3011.         KeyNotFoundError (Key);
  3012.   End;
  3013.  
  3014. Procedure TExtendedDictionary.IndexError;
  3015.   Begin
  3016.     DictionaryError ('Index out of range');
  3017.   End;
  3018.  
  3019. Function TExtendedDictionary.Count : Integer;
  3020.   Begin
  3021.     Result := FKeys.Count;
  3022.     Assert (FValues.Count = Result, 'Key/Value count mismatch');
  3023.   End;
  3024.  
  3025. Function TExtendedDictionary.GetKeyByIndex (const Idx : Integer) : String;
  3026.   Begin
  3027.     {$IFOPT R+}
  3028.     if (Idx < 0) or (Idx >= FKeys.Count) then
  3029.       IndexError;
  3030.     {$ENDIF}
  3031.     Result := FKeys [Idx];
  3032.   End;
  3033.  
  3034. Procedure TExtendedDictionary.DeleteItemByIndex (const Idx : Integer);
  3035.   Begin
  3036.     {$IFOPT R+}
  3037.     if (Idx < 0) or (Idx >= FValues.Count) then
  3038.       IndexError;
  3039.     {$ENDIF}
  3040.     DeleteByIndex (Idx, -1);
  3041.   End;
  3042.  
  3043. Function TExtendedDictionary.GetItemByIndex (const Idx : Integer) : Extended;
  3044.   Begin
  3045.     {$IFOPT R+}
  3046.     if (Idx < 0) or (Idx >= FValues.Count) then
  3047.       IndexError;
  3048.     {$ENDIF}
  3049.     Result := FValues [Idx];
  3050.   End;
  3051.  
  3052. Procedure TExtendedDictionary.SetItemByIndex (const Idx : Integer; const Value : Extended);
  3053.   Begin
  3054.     {$IFOPT R+}
  3055.     if (Idx < 0) or (Idx >= FValues.Count) then
  3056.       IndexError;
  3057.     {$ENDIF}
  3058.     FValues [Idx] := Value;
  3059.   End;
  3060.  
  3061. Procedure TExtendedDictionary.Clear;
  3062.   Begin
  3063.     FKeys.Clear;
  3064.     FValues.Clear;
  3065.     Rehash;
  3066.   End;
  3067.  
  3068.  
  3069.  
  3070. {                                                                              }
  3071. { TStringDictionary                                                            }
  3072. {                                                                              }
  3073. Constructor TStringDictionary.Create;
  3074.   Begin
  3075.     inherited Create;
  3076.     FCaseSensitive := True;
  3077.     FDuplicatesAction := ddAccept;
  3078.     FAddOnSet := True;
  3079.     FKeys := TStringArray.Create;
  3080.     FValues := TStringArray.Create;
  3081.   End;
  3082.   
  3083. Constructor TStringDictionary.CreateEx (const Keys : AStringArray; const Values : AStringArray; const KeysCaseSensitive : Boolean; const AddOnSet : Boolean; const DuplicatesAction : TDictionaryDuplicatesAction);
  3084.   Begin
  3085.     inherited Create;
  3086.     if Assigned (Keys) then
  3087.       FKeys := Keys else
  3088.       FKeys := TStringArray.Create;
  3089.     if Assigned (Values) then
  3090.       FValues := Values else
  3091.       FValues := TStringArray.Create;
  3092.     Assert (FKeys.Count = FValues.Count, 'Keys and Values must be equal length');
  3093.     FAddOnSet := AddOnSet;
  3094.     FDuplicatesAction := DuplicatesAction;
  3095.     Rehash;
  3096.   End;
  3097.  
  3098. Destructor TStringDictionary.Destroy;
  3099.   Begin
  3100.     FreeAndNil (FValues);
  3101.     FreeAndNil (FKeys);
  3102.     inherited Destroy;
  3103.   End;
  3104.  
  3105. Function TStringDictionary.GetKeysCaseSensitive : Boolean;
  3106.   Begin
  3107.     Result := FCaseSensitive;
  3108.   End;
  3109.  
  3110. Function TStringDictionary.GetAddOnSet : Boolean;
  3111.   Begin
  3112.     Result := FAddOnSet;
  3113.   End;
  3114.  
  3115. Procedure TStringDictionary.SetAddOnSet (const AddOnSet : Boolean);
  3116.   Begin
  3117.     FAddOnSet := AddOnSet;
  3118.   End;
  3119.  
  3120. Function TStringDictionary.GetHashTableSize : Integer;
  3121.   Begin
  3122.     Result := Length (FLookup);
  3123.   End;
  3124.  
  3125. Procedure TStringDictionary.Rehash;
  3126. var I, C, L : Integer;
  3127.   Begin
  3128.     C := FKeys.Count;
  3129.     L := DictionaryRehashSize (C);
  3130.     FLookup := nil;
  3131.     SetLength (FLookup, L);
  3132.     For I := 0 to C - 1 do
  3133.       Append (FLookup [HashStr (FKeys [I], L, FCaseSensitive)], I);
  3134.   End;
  3135.  
  3136. class Function TStringDictionary.CreateInstance : AType;
  3137.   Begin
  3138.     Result := TStringDictionary.Create;
  3139.   End;
  3140.  
  3141. Function TStringDictionary.LocateKey (const Key : String; var LookupIdx : Integer; const ErrorIfNotFound : Boolean) : Integer;
  3142. var H, I, J, L : Integer;
  3143.   Begin
  3144.     Result := -1;
  3145.     L := Length (FLookup);
  3146.     if L > 0 then
  3147.       begin
  3148.         H := HashStr (Key, L, FCaseSensitive);
  3149.         LookupIdx := H;
  3150.         For I := 0 to Length (FLookup [H]) - 1 do
  3151.           begin
  3152.             J := FLookup [H, I];
  3153.             if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  3154.               begin
  3155.                 Result := J;
  3156.                 break;
  3157.               end;
  3158.           end;
  3159.       end;
  3160.     if ErrorIfNotFound and (Result = -1) then
  3161.       KeyNotFoundError (Key);
  3162.   End;
  3163.  
  3164. Function TStringDictionary.KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  3165. var H : Integer;
  3166.   Begin
  3167.     Result := LocateKey (Key, H, ErrorIfNotFound);
  3168.   End;
  3169.  
  3170. Procedure TStringDictionary.Add (const Key : String; const Value : String);
  3171. var H, L, I : Integer;
  3172.   Begin
  3173.     if FDuplicatesAction in [ddIgnore, ddError] then
  3174.       if LocateKey (Key, H, False) >= 0 then
  3175.         if FDuplicatesAction = ddIgnore then
  3176.           exit else
  3177.           DictionaryError ('Duplicate key: ' + QuoteText (Key));
  3178.     L := Length (FLookup);
  3179.     if L = 0 then
  3180.       begin
  3181.         Rehash;
  3182.         L := Length (FLookup);
  3183.       end;
  3184.     H := Integer (HashStr (Key, LongWord (L), FCaseSensitive));
  3185.     I := FKeys.AddItem (Key);
  3186.     Append (FLookup [H], I);
  3187.     FValues.AddItem (Value);
  3188.  
  3189.     if (I + 1) div AverageHashChainSize > L then
  3190.       Rehash;
  3191.   End;
  3192.  
  3193. Procedure TStringDictionary.DeleteByIndex (const Idx : Integer; const Hash : Integer);
  3194. var I, J, H : Integer;
  3195.   Begin
  3196.     if Hash = -1 then
  3197.       H := HashStr (FKeys [Idx], Length (FLookup), FCaseSensitive) else
  3198.       H := Hash;
  3199.     FKeys.Delete (Idx);
  3200.     FValues.Delete (Idx);
  3201.     J := PosNext (Idx, FLookup [H]);
  3202.     Assert (J >= 0, 'Invalid hash value/lookup table');
  3203.     Remove (FLookup [H], J, 1);
  3204.  
  3205.     For I := 0 to Length (FLookup) - 1 do
  3206.       For J := 0 to Length (FLookup [I]) - 1 do
  3207.         if FLookup [I][J] > Idx then
  3208.           Dec (FLookup [I][J]);
  3209.   End;
  3210.  
  3211. Procedure TStringDictionary.Delete (const Key : String);
  3212. var I, H : Integer;
  3213.   Begin
  3214.     I := LocateKey (Key, H, True);
  3215.     DeleteByIndex (I, H);
  3216.   End;
  3217.  
  3218. Function TStringDictionary.HasKey (const Key : String) : Boolean;
  3219.   Begin
  3220.     Result := KeyIndex (Key, False) >= 0;
  3221.   End;
  3222.  
  3223. Procedure TStringDictionary.Rename (const Key, NewKey : String);
  3224. var I, J, H : Integer;
  3225.   Begin
  3226.     I := LocateKey (Key, H, True);
  3227.     FKeys [I] := NewKey;
  3228.     J := PosNext (I, FLookup [H]);
  3229.     Assert (J >= 0, 'Invalid hash value/lookup table');
  3230.     Remove (FLookup [H], J, 1);
  3231.     Append (FLookup [HashStr (NewKey, Length (FLookup), FCaseSensitive)], I);
  3232.   End;
  3233.  
  3234. Function TStringDictionary.GetDuplicatesAction : TDictionaryDuplicatesAction;
  3235.   Begin
  3236.     Result := FDuplicatesAction;
  3237.   End;
  3238.  
  3239. Procedure TStringDictionary.SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction);
  3240.   Begin
  3241.     FDuplicatesAction := DuplicatesAction;
  3242.   End;
  3243.  
  3244. Function TStringDictionary.LocateItem (const Key : String; var Value : String) : Integer;
  3245.   Begin
  3246.     Result := KeyIndex (Key, False);
  3247.     if Result >= 0 then
  3248.       Value := FValues [Result] else
  3249.       Value := '';
  3250.   End;
  3251.  
  3252. Function TStringDictionary.LocateNext (const Key : String; const Idx : Integer; var Value : String) : Integer;
  3253. var L, H, I, J, K : Integer;
  3254.   Begin
  3255.     Result := -1;
  3256.     L := Length (FLookup);
  3257.     if L = 0 then
  3258.       DictionaryError ('Item not found');
  3259.     H := HashStr (Key, L, FCaseSensitive);
  3260.     For I := 0 to Length (FLookup [H]) - 1 do
  3261.       begin
  3262.         J := FLookup [H, I];
  3263.         if J = Idx then
  3264.           begin
  3265.             if not cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  3266.               DictionaryError ('Item not found');
  3267.             For K := I + 1 to Length (FLookup [H]) - 1 do
  3268.               begin
  3269.                 J := FLookup [H, K];
  3270.                 if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  3271.                   begin
  3272.                     Value := FValues [J];
  3273.                     Result := J;
  3274.                     exit;
  3275.                   end;
  3276.               end;
  3277.             Result := -1;
  3278.             exit;
  3279.           end;
  3280.       end;
  3281.     DictionaryError ('Item not found');
  3282.   End;
  3283.  
  3284. Procedure TStringDictionary.SetItem (const Key : String; const Value : String);
  3285. var I : Integer;
  3286.   Begin
  3287.     I := KeyIndex (Key, False);
  3288.     if I >= 0 then
  3289.       FValues [I] := Value else
  3290.       if AddOnSet then
  3291.         Add (Key, Value) else
  3292.         KeyNotFoundError (Key);
  3293.   End;
  3294.  
  3295. Procedure TStringDictionary.IndexError;
  3296.   Begin
  3297.     DictionaryError ('Index out of range');
  3298.   End;
  3299.  
  3300. Function TStringDictionary.Count : Integer;
  3301.   Begin
  3302.     Result := FKeys.Count;
  3303.     Assert (FValues.Count = Result, 'Key/Value count mismatch');
  3304.   End;
  3305.  
  3306. Function TStringDictionary.GetKeyByIndex (const Idx : Integer) : String;
  3307.   Begin
  3308.     {$IFOPT R+}
  3309.     if (Idx < 0) or (Idx >= FKeys.Count) then
  3310.       IndexError;
  3311.     {$ENDIF}
  3312.     Result := FKeys [Idx];
  3313.   End;
  3314.  
  3315. Procedure TStringDictionary.DeleteItemByIndex (const Idx : Integer);
  3316.   Begin
  3317.     {$IFOPT R+}
  3318.     if (Idx < 0) or (Idx >= FValues.Count) then
  3319.       IndexError;
  3320.     {$ENDIF}
  3321.     DeleteByIndex (Idx, -1);
  3322.   End;
  3323.  
  3324. Function TStringDictionary.GetItemByIndex (const Idx : Integer) : String;
  3325.   Begin
  3326.     {$IFOPT R+}
  3327.     if (Idx < 0) or (Idx >= FValues.Count) then
  3328.       IndexError;
  3329.     {$ENDIF}
  3330.     Result := FValues [Idx];
  3331.   End;
  3332.  
  3333. Procedure TStringDictionary.SetItemByIndex (const Idx : Integer; const Value : String);
  3334.   Begin
  3335.     {$IFOPT R+}
  3336.     if (Idx < 0) or (Idx >= FValues.Count) then
  3337.       IndexError;
  3338.     {$ENDIF}
  3339.     FValues [Idx] := Value;
  3340.   End;
  3341.  
  3342. Procedure TStringDictionary.Clear;
  3343.   Begin
  3344.     FKeys.Clear;
  3345.     FValues.Clear;
  3346.     Rehash;
  3347.   End;
  3348.  
  3349.  
  3350.  
  3351. {                                                                              }
  3352. { TObjectDictionary                                                            }
  3353. {                                                                              }
  3354. Constructor TObjectDictionary.Create;
  3355.   Begin
  3356.     inherited Create;
  3357.     FCaseSensitive := True;
  3358.     FDuplicatesAction := ddAccept;
  3359.     FAddOnSet := True;
  3360.     FKeys := TStringArray.Create;
  3361.     FValues := TObjectArray.Create;
  3362.   End;
  3363.   
  3364. Constructor TObjectDictionary.CreateEx (const Keys : AStringArray; const Values : AObjectArray; const IsItemOwner : Boolean; const KeysCaseSensitive : Boolean; const AddOnSet : Boolean; const DuplicatesAction : TDictionaryDuplicatesAction);
  3365.   Begin
  3366.     inherited Create;
  3367.     if Assigned (Keys) then
  3368.       FKeys := Keys else
  3369.       FKeys := TStringArray.Create;
  3370.     if Assigned (Values) then
  3371.       FValues := Values else
  3372.       FValues := TObjectArray.Create;
  3373.     Assert (FKeys.Count = FValues.Count, 'Keys and Values must be equal length');
  3374.     FAddOnSet := AddOnSet;
  3375.     FValues.IsItemOwner := IsItemOwner;
  3376.     FCaseSensitive := KeysCaseSensitive;
  3377.     FDuplicatesAction := DuplicatesAction;
  3378.     Rehash;
  3379.   End;
  3380.  
  3381. Destructor TObjectDictionary.Destroy;
  3382.   Begin
  3383.     FreeAndNil (FValues);
  3384.     FreeAndNil (FKeys);
  3385.     inherited Destroy;
  3386.   End;
  3387.  
  3388. Function TObjectDictionary.GetKeysCaseSensitive : Boolean;
  3389.   Begin
  3390.     Result := FCaseSensitive;
  3391.   End;
  3392.  
  3393. Function TObjectDictionary.GetAddOnSet : Boolean;
  3394.   Begin
  3395.     Result := FAddOnSet;
  3396.   End;
  3397.  
  3398. Procedure TObjectDictionary.SetAddOnSet (const AddOnSet : Boolean);
  3399.   Begin
  3400.     FAddOnSet := AddOnSet;
  3401.   End;
  3402.  
  3403. Function TObjectDictionary.GetHashTableSize : Integer;
  3404.   Begin
  3405.     Result := Length (FLookup);
  3406.   End;
  3407.  
  3408. Function TObjectDictionary.GetIsItemOwner : Boolean;
  3409.   Begin
  3410.     Result := FValues.IsItemOwner;
  3411.   End;
  3412.  
  3413. Procedure TObjectDictionary.SetIsItemOwner (const IsItemOwner : Boolean);
  3414.   Begin
  3415.     FValues.IsItemOwner := IsItemOwner;
  3416.   End;
  3417.  
  3418. Procedure TObjectDictionary.Rehash;
  3419. var I, C, L : Integer;
  3420.   Begin
  3421.     C := FKeys.Count;
  3422.     L := DictionaryRehashSize (C);
  3423.     FLookup := nil;
  3424.     SetLength (FLookup, L);
  3425.     For I := 0 to C - 1 do
  3426.       Append (FLookup [HashStr (FKeys [I], L, FCaseSensitive)], I);
  3427.   End;
  3428.  
  3429. class Function TObjectDictionary.CreateInstance : AType;
  3430.   Begin
  3431.     Result := TObjectDictionary.Create;
  3432.   End;
  3433.  
  3434. Function TObjectDictionary.LocateKey (const Key : String; var LookupIdx : Integer; const ErrorIfNotFound : Boolean) : Integer;
  3435. var H, I, J, L : Integer;
  3436.   Begin
  3437.     Result := -1;
  3438.     L := Length (FLookup);
  3439.     if L > 0 then
  3440.       begin
  3441.         H := HashStr (Key, L, FCaseSensitive);
  3442.         LookupIdx := H;
  3443.         For I := 0 to Length (FLookup [H]) - 1 do
  3444.           begin
  3445.             J := FLookup [H, I];
  3446.             if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  3447.               begin
  3448.                 Result := J;
  3449.                 break;
  3450.               end;
  3451.           end;
  3452.       end;
  3453.     if ErrorIfNotFound and (Result = -1) then
  3454.       KeyNotFoundError (Key);
  3455.   End;
  3456.  
  3457. Function TObjectDictionary.KeyIndex (const Key : String; const ErrorIfNotFound : Boolean) : Integer;
  3458. var H : Integer;
  3459.   Begin
  3460.     Result := LocateKey (Key, H, ErrorIfNotFound);
  3461.   End;
  3462.  
  3463. Procedure TObjectDictionary.Add (const Key : String; const Value : TObject);
  3464. var H, L, I : Integer;
  3465.   Begin
  3466.     if FDuplicatesAction in [ddIgnore, ddError] then
  3467.       if LocateKey (Key, H, False) >= 0 then
  3468.         if FDuplicatesAction = ddIgnore then
  3469.           exit else
  3470.           DictionaryError ('Duplicate key: ' + QuoteText (Key));
  3471.     L := Length (FLookup);
  3472.     if L = 0 then
  3473.       begin
  3474.         Rehash;
  3475.         L := Length (FLookup);
  3476.       end;
  3477.     H := Integer (HashStr (Key, LongWord (L), FCaseSensitive));
  3478.     I := FKeys.AddItem (Key);
  3479.     Append (FLookup [H], I);
  3480.     FValues.AddItem (Value);
  3481.  
  3482.     if (I + 1) div AverageHashChainSize > L then
  3483.       Rehash;
  3484.   End;
  3485.  
  3486. Procedure TObjectDictionary.DeleteByIndex (const Idx : Integer; const Hash : Integer);
  3487. var I, J, H : Integer;
  3488.   Begin
  3489.     if Hash = -1 then
  3490.       H := HashStr (FKeys [Idx], Length (FLookup), FCaseSensitive) else
  3491.       H := Hash;
  3492.     FKeys.Delete (Idx);
  3493.     FValues.Delete (Idx);
  3494.     J := PosNext (Idx, FLookup [H]);
  3495.     Assert (J >= 0, 'Invalid hash value/lookup table');
  3496.     Remove (FLookup [H], J, 1);
  3497.  
  3498.     For I := 0 to Length (FLookup) - 1 do
  3499.       For J := 0 to Length (FLookup [I]) - 1 do
  3500.         if FLookup [I][J] > Idx then
  3501.           Dec (FLookup [I][J]);
  3502.   End;
  3503.  
  3504. Procedure TObjectDictionary.Delete (const Key : String);
  3505. var I, H : Integer;
  3506.   Begin
  3507.     I := LocateKey (Key, H, True);
  3508.     DeleteByIndex (I, H);
  3509.   End;
  3510.  
  3511. Function TObjectDictionary.HasKey (const Key : String) : Boolean;
  3512.   Begin
  3513.     Result := KeyIndex (Key, False) >= 0;
  3514.   End;
  3515.  
  3516. Procedure TObjectDictionary.Rename (const Key, NewKey : String);
  3517. var I, J, H : Integer;
  3518.   Begin
  3519.     I := LocateKey (Key, H, True);
  3520.     FKeys [I] := NewKey;
  3521.     J := PosNext (I, FLookup [H]);
  3522.     Assert (J >= 0, 'Invalid hash value/lookup table');
  3523.     Remove (FLookup [H], J, 1);
  3524.     Append (FLookup [HashStr (NewKey, Length (FLookup), FCaseSensitive)], I);
  3525.   End;
  3526.  
  3527. Function TObjectDictionary.GetDuplicatesAction : TDictionaryDuplicatesAction;
  3528.   Begin
  3529.     Result := FDuplicatesAction;
  3530.   End;
  3531.  
  3532. Procedure TObjectDictionary.SetDuplicatesAction (const DuplicatesAction : TDictionaryDuplicatesAction);
  3533.   Begin
  3534.     FDuplicatesAction := DuplicatesAction;
  3535.   End;
  3536.  
  3537. Function TObjectDictionary.LocateItem (const Key : String; var Value : TObject) : Integer;
  3538.   Begin
  3539.     Result := KeyIndex (Key, False);
  3540.     if Result >= 0 then
  3541.       Value := FValues [Result] else
  3542.       Value := nil;
  3543.   End;
  3544.  
  3545. Function TObjectDictionary.LocateNext (const Key : String; const Idx : Integer; var Value : TObject) : Integer;
  3546. var L, H, I, J, K : Integer;
  3547.   Begin
  3548.     Result := -1;
  3549.     L := Length (FLookup);
  3550.     if L = 0 then
  3551.       DictionaryError ('Item not found');
  3552.     H := HashStr (Key, L, FCaseSensitive);
  3553.     For I := 0 to Length (FLookup [H]) - 1 do
  3554.       begin
  3555.         J := FLookup [H, I];
  3556.         if J = Idx then
  3557.           begin
  3558.             if not cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  3559.               DictionaryError ('Item not found');
  3560.             For K := I + 1 to Length (FLookup [H]) - 1 do
  3561.               begin
  3562.                 J := FLookup [H, K];
  3563.                 if cStrings.IsEqual (Key, FKeys [J], FCaseSensitive) then
  3564.                   begin
  3565.                     Value := FValues [J];
  3566.                     Result := J;
  3567.                     exit;
  3568.                   end;
  3569.               end;
  3570.             Result := -1;
  3571.             exit;
  3572.           end;
  3573.       end;
  3574.     DictionaryError ('Item not found');
  3575.   End;
  3576.  
  3577. Procedure TObjectDictionary.SetItem (const Key : String; const Value : TObject);
  3578. var I : Integer;
  3579.   Begin
  3580.     I := KeyIndex (Key, False);
  3581.     if I >= 0 then
  3582.       FValues [I] := Value else
  3583.       if AddOnSet then
  3584.         Add (Key, Value) else
  3585.         KeyNotFoundError (Key);
  3586.   End;
  3587.  
  3588. Procedure TObjectDictionary.IndexError;
  3589.   Begin
  3590.     DictionaryError ('Index out of range');
  3591.   End;
  3592.  
  3593. Function TObjectDictionary.Count : Integer;
  3594.   Begin
  3595.     Result := FKeys.Count;
  3596.     Assert (FValues.Count = Result, 'Key/Value count mismatch');
  3597.   End;
  3598.  
  3599. Function TObjectDictionary.GetKeyByIndex (const Idx : Integer) : String;
  3600.   Begin
  3601.     {$IFOPT R+}
  3602.     if (Idx < 0) or (Idx >= FKeys.Count) then
  3603.       IndexError;
  3604.     {$ENDIF}
  3605.     Result := FKeys [Idx];
  3606.   End;
  3607.  
  3608. Procedure TObjectDictionary.DeleteItemByIndex (const Idx : Integer);
  3609.   Begin
  3610.     {$IFOPT R+}
  3611.     if (Idx < 0) or (Idx >= FValues.Count) then
  3612.       IndexError;
  3613.     {$ENDIF}
  3614.     DeleteByIndex (Idx, -1);
  3615.   End;
  3616.  
  3617. Function TObjectDictionary.GetItemByIndex (const Idx : Integer) : TObject;
  3618.   Begin
  3619.     {$IFOPT R+}
  3620.     if (Idx < 0) or (Idx >= FValues.Count) then
  3621.       IndexError;
  3622.     {$ENDIF}
  3623.     Result := FValues [Idx];
  3624.   End;
  3625.  
  3626. Procedure TObjectDictionary.SetItemByIndex (const Idx : Integer; const Value : TObject);
  3627.   Begin
  3628.     {$IFOPT R+}
  3629.     if (Idx < 0) or (Idx >= FValues.Count) then
  3630.       IndexError;
  3631.     {$ENDIF}
  3632.     FValues [Idx] := Value;
  3633.   End;
  3634.  
  3635. Function TObjectDictionary.ReleaseItem (const Key : String) : TObject;
  3636. var I : Integer;
  3637.   Begin
  3638.     I := KeyIndex (Key, True);
  3639.     Result := FValues.ReleaseItem (I);
  3640.   End;
  3641.  
  3642. Procedure TObjectDictionary.ReleaseItems;
  3643.   Begin
  3644.     FKeys.Clear;
  3645.     FValues.ReleaseItems;
  3646.     Rehash;
  3647.   End;
  3648.  
  3649. Procedure TObjectDictionary.FreeItems;
  3650.   Begin
  3651.     FKeys.Clear;
  3652.     FValues.FreeItems;
  3653.     Rehash;
  3654.   End;
  3655.  
  3656. Procedure TObjectDictionary.Clear;
  3657.   Begin
  3658.     FKeys.Clear;
  3659.     FValues.Clear;
  3660.     Rehash;
  3661.   End;
  3662.  
  3663.  
  3664.  
  3665. {                                                                              }
  3666. { Self testing code                                                            }
  3667. {                                                                              }
  3668. Procedure SelfTest;
  3669. var F : TIntegerDictionary;
  3670.     G : TStringDictionary;
  3671.     I : Integer;
  3672.   Begin
  3673.     F := TIntegerDictionary.Create;
  3674.     For I := 0 to 16384 do
  3675.       F.Add (IntToStr (I), I);
  3676.     Assert (F.Count = 16385, 'Dictionary.Count');
  3677.     For I := 0 to 16384 do
  3678.       Assert (F.GetKeyByIndex (I) = IntToStr (I), 'Dictionary.GetKeyByIndex');
  3679.     Assert (F ['0'] = 0, 'Dictionary.GetItem');
  3680.     Assert (F ['5'] = 5, 'Dictionary.GetItem');
  3681.     Assert (F ['16384'] = 16384, 'Dictionary.GetItem');
  3682.     For I := 0 to 16384 do
  3683.       Assert (F.GetItemByIndex (I) = I, 'Dictionary.GetItemByIndex');
  3684.     Assert (F.HasKey ('5'), 'Dictionary.HasKey');
  3685.     Assert (not F.HasKey ('X'), 'Dictionary.HasKey');
  3686.     F.Rename ('5', 'X');
  3687.     Assert (not F.HasKey ('5'), 'Dictionary.Rename');
  3688.     Assert (F.HasKey ('X'), 'Dictionary.Rename');
  3689.     Assert (F ['X'] = 5, 'Dictionary.Rename');
  3690.     F.Delete ('X');
  3691.     Assert (not F.HasKey ('X'), 'Dictionary.Delete');
  3692.     Assert (F.Count = 16384, 'Dictionary.Delete');
  3693.     F.Delete ('0');
  3694.     Assert (not F.HasKey ('0'), 'Dictionary.Delete');
  3695.     Assert (F.Count = 16383, 'Dictionary.Delete');
  3696.     F.DeleteItemByIndex (0);
  3697.     Assert (not F.HasKey ('1'), 'Dictionary.DeleteItemByIndex');
  3698.     Assert (F.Count = 16382, 'Dictionary.DeleteItemByIndex');
  3699.     F.Free;
  3700.  
  3701.     G := TStringDictionary.Create;
  3702.     For I := 0 to 16384 do
  3703.       G.Add (IntToStr (I), IntToStr (I));
  3704.     Assert (G.Count = 16385, 'Dictionary.Count');
  3705.     For I := 0 to 16384 do
  3706.       Assert (G.GetKeyByIndex (I) = IntToStr (I), 'Dictionary.GetKeyByIndex');
  3707.     Assert (G ['0'] = '0', 'Dictionary.GetItem');
  3708.     Assert (G ['5'] = '5', 'Dictionary.GetItem');
  3709.     Assert (G ['16384'] = '16384', 'Dictionary.GetItem');
  3710.     For I := 0 to 16384 do
  3711.       Assert (G.GetItemByIndex (I) = IntToStr (I), 'Dictionary.GetItemByIndex');
  3712.     Assert (G.HasKey ('5'), 'Dictionary.HasKey');
  3713.     Assert (not G.HasKey ('X'), 'Dictionary.HasKey');
  3714.     G.Rename ('5', 'X');
  3715.     Assert (not G.HasKey ('5'), 'Dictionary.Rename');
  3716.     Assert (G.HasKey ('X'), 'Dictionary.Rename');
  3717.     Assert (G ['X'] = '5', 'Dictionary.Rename');
  3718.     G.Delete ('X');
  3719.     Assert (not G.HasKey ('X'), 'Dictionary.Delete');
  3720.     Assert (G.Count = 16384, 'Dictionary.Delete');
  3721.     G.Delete ('0');
  3722.     Assert (not G.HasKey ('0'), 'Dictionary.Delete');
  3723.     Assert (G.Count = 16383, 'Dictionary.Delete');
  3724.     G.DeleteItemByIndex (0);
  3725.     Assert (not G.HasKey ('1'), 'Dictionary.DeleteItemByIndex');
  3726.     Assert (G.Count = 16382, 'Dictionary.DeleteItemByIndex');
  3727.     G.Free;
  3728.   End;
  3729.  
  3730.  
  3731.  
  3732. end.
  3733.  
  3734.