hashtable.inc_pas

来自「delphi的范型代码库」· INC_PAS 代码 · 共 752 行 · 第 1/2 页

INC_PAS
752
字号
(*
 * DGL(The Delphi Generic Library)
 *
 * Copyright (c) 2004
 * HouSisong@263.net
 *
 * This material is provided "as is", with absolutely no warranty expressed
 * or implied. Any use is at your own risk.
 *
 * Permission to use or copy this software for any purpose is hereby granted
 * without fee, provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 *
 *)

//------------------------------------------------------------------------------
// _THashTableBase\_THashBaseIterator的实现
// Create by HouSisong, 2004.03.05
//------------------------------------------------------------------------------

{$ifndef __HashTable_inc_pas_}
{$define __HashTable_inc_pas_}

{$I DGLIntf.inc_pas}

{ _THashTableBase }

procedure _THashTableBase.UniqueInsert(const Key: _HashKeyType;const Value: _HashValueType);
begin
  self.UniqueInsertNode(FindItem(Key).pPNode,Key,Value);
end;

procedure  _THashTableBase.DisposeNode(const PHashNode: _PHashNode);
begin
  {$ifdef _DGL_ObjValue_Key}
  _Free_Key(PHashNode.Key);
  {$endif}
  {$ifdef _DGL_ObjValue_Value}
    if not F_DGL_OnlySet then
      _Free_Value(PHashNode.Value);
  {$endif}

  if F_DGL_OnlySet then
    system.Dispose(_PHashNode_OnlySet(PHashNode))
  else
    system.Dispose(PHashNode);

  //dec(testTHashNodeCount);
end;

procedure _THashTableBase.Clear;
var
  i         : integer;
  PNode     : _PHashNode;
  PNodeTemp : _PHashNode;
begin
  if (self.FCount>0) then
  begin
    for i:=low(self.FDataList) to high(self.FDataList) do
    begin
      PNode:=self.FDataList[i];
      while (PNode<>nil) do
      begin
        PNodeTemp:=PNode.PNext;
        DisposeNode(PNode);
        PNode:=PNodeTemp;
      end;
    end;
  end;

  self.FCount:=0;
  if FAlwaysReserveSize<=0 then
  begin
    if FCapacity=0 then
      self.FCapacity:=1 shl 5;
    self.FDataList:=nil;
  end
  else
  begin
    FCapacity:=FAlwaysReserveSize;
    i:=length(FDataList);
    if FAlwaysReserveSize<i then
      i:=FAlwaysReserveSize;
    fillchar((@FDataList[0])^,i*sizeof(_PHashNode),0);
  end;
  self.FHashMask:=self.FCapacity-1;
  setlength(self.FDataList,self.FCapacity);
end;

constructor _THashTableBase.Create(const IsOnlySet : boolean);
begin
  inherited Create;
  self.F_DGL_OnlySet:=IsOnlySet;
  self.Clear();
end;

destructor _THashTableBase.Destroy;
begin
  self.Clear();
  inherited;
end;

function _THashTableBase.GetItemValue(const Key: _HashKeyType): _HashValueType;
var
  pPHashNode: _PPHashNode ;
begin
  pPHashNode:=self.FindItem(Key).pPNode;
  if (pPHashNode^<>nil) then
    result:=(pPHashNode^).Value
  else
    raise EHashKeyRangeError.Create(csHashKey_Error);
    //raise EHashKeyRangeError.Create();
end;


procedure _THashTableBase.SetCapacity(NewCapacity: integer);
var
  OldDataList : array of _PHashNode;
  pNode       : _PHashNode;
  pNodeTemp   : _PHashNode;
  i           : integer;

  procedure   move_insert(pMoveNode : _PHashNode);
  var
    pPHashNode: _PPHashNode ;
  begin
    pPHashNode:=self.FindItem(pMoveNode.Key).pPNode;
    pMoveNode.PNext:=pPHashNode^;
    pPHashNode^:=pMoveNode;
  end;
  function To2Power(x :integer):integer;
  var
    powi : integer;
  begin
    Assert(x>0);
    if x=1 then
      result:=2
    else
    begin
      //下面与此等价:result:=Round(math.IntPower(2,1+math.Floor(log2(x-1))));
      powi:=0;
      while (x>0) do
      begin
        x:=x shr 1;
        inc(powi);
      end;
      result:=1 shl powi;
      if result<x then result:=result shl 1;
    end;
  end;
begin
  self.FCapacity:=To2Power(NewCapacity);
  self.FHashMask:=self.FCapacity-1;

  setlength(OldDataList,length(self.FDataList));
  for i:=low(OldDataList) to high(OldDataList) do
    OldDataList[i]:=self.FDataList[i];
  setlength(self.FDataList,0);
  setlength(self.FDataList,FCapacity);

  //
  for i:=low(OldDataList) to high(OldDataList) do
  begin
    pNode:=OldDataList[i];
    while (pNode<>nil) do
    begin
      pNodeTemp:=PNode.PNext;
      move_insert(PNode);
      PNode:=pNodeTemp;
    end;
  end;
end;

//找到返回节点指针
//没有找到返回插入位置节点指针
function _THashTableBase.FindItem(const Key: _HashKeyType):_TTagHashIterator;
begin
  result.ArrayIndex:=(_HashValue(Key)) and (self.FHashMask);
  result.pPNode:=@self.FDataList[result.ArrayIndex];
  if (result.pPNode^<>nil) then //节点还没有使用
  begin
    repeat
      {$ifdef _DGL_Compare_Key}
      if (_IsEqual_Key(Key,(result.pPNode^).Key)) then  //找到
      {$else}
      if ((Key=(result.pPNode^).Key)) then  //找到
      {$endif}
      begin
        exit;
      end;
      result.pPNode:=@(result.pPNode^).PNext;
    until (result.pPNode^=nil);
  end;
end;


procedure _THashTableBase.DeleteNode(const pPHashNode: _PPHashNode);
var
  ptmpNode : _PHashNode;
begin
  if (pPHashNode^<>nil) then
  begin
    ptmpNode:= (pPHashNode^).PNext;
    DisposeNode(pPHashNode^);
    pPHashNode^:=ptmpNode;
    dec(self.FCount);
  end
  else
    raise EHashKeyRangeError.Create(csHashKey_Error);
    //raise EHashKeyRangeError.Create();
end;

procedure _THashTableBase.MultiInsert(const Key: _HashKeyType;const Value: _HashValueType);
begin
  self.MultiInsertNode(FindItem(Key).pPNode,Key,Value);
end;

procedure _THashTableBase.Swap(HastTable: _THashTableBase);
var
  tempi     : integer;
  tempArray : array of _PHashNode;
begin

  tempi:=self.FCount;
  self.FCount:=HastTable.FCount;
  HastTable.FCount:=tempi;

  tempi:=self.FCapacity;
  self.FCapacity:=HastTable.FCapacity;
  HastTable.FCapacity:=tempi;

  tempi:=self.FHashMask;
  self.FHashMask:=HastTable.FHashMask;
  HastTable.FHashMask:=tempi;

  //tempArray:=self.FDataList;
  setlength(tempArray,length(self.FDataList));
  for tempi:=low(self.FDataList) to high(self.FDataList) do
    tempArray[tempi]:=self.FDataList[tempi];
  //self.FDataList:=HastTable.FDataList;
  setlength(self.FDataList,length(HastTable.FDataList));
  for tempi:=low(HastTable.FDataList) to high(HastTable.FDataList) do
    self.FDataList[tempi]:=HastTable.FDataList[tempi];
  //HastTable.FDataList:=tempArray;
  setlength(HastTable.FDataList,length(tempArray));
  for tempi:=low(tempArray) to high(tempArray) do
    HastTable.FDataList[tempi]:=tempArray[tempi];
end;


function _THashTableBase.ItBegin: _TTagHashIterator;
var
  i :integer;
begin
  for i:=low(self.FDataList) to high(self.FDataList) do
  begin
    if (self.FDataList[i]<>nil) then
    begin
      result.ArrayIndex:=i;
      result.pPNode:=@self.FDataList[i];
      exit;
    end;
  end;
  result.ArrayIndex:=high(self.FDataList);
  result.PPNode:=nil;
end;

function _THashTableBase.ItEnd: _TTagHashIterator;
begin
  result.ArrayIndex:=high(self.FDataList);
  result.pPNode:=nil;
end;

procedure _THashTableBase.AlwaysReserve(const aAlwaysReserveSize: integer);
begin
  self.Reserve(aAlwaysReserveSize);
  FAlwaysReserveSize:=FCapacity;
end;

procedure _THashTableBase.Reserve(const ReserveSize: integer);
begin
  if ReserveSize>self.FCount then
  begin
    self.SetCapacity(ReserveSize);
  end;
end;

function _THashTableBase.Size: integer;
begin
  result:=self.FCount;
end;

procedure _THashTableBase.MultiInsert(const Key: _HashKeyType);
begin
  self.MultiInsertNode(FindItem(Key).pPNode,Key);
end;

procedure _THashTableBase.UniqueInsert(const Key: _HashKeyType);
begin
  self.UniqueInsertNode(FindItem(Key).pPNode,Key);
end;

procedure _THashTableBase.UniqueInsertNode(pPHashNode: _PPHashNode;
  const Key: _HashKeyType);
begin
  if (pPHashNode^=nil) then
    self.MultiInsertNode(pPHashNode,Key)
  else
  begin   //replace key
    {$ifdef _DGL_ObjValue_Key}
    _Assign_Key(pPHashNode^.Key,Key);
    {$else}
    pPHashNode^.Key:=Key;
    {$endif}
  end;
end;

function _THashTableBase.Count(const Key: _HashKeyType): integer;
var
  ItBegin,ItEnd: _TTagHashIterator;
begin
  result:=self.CountRange(Key,ItBegin,ItEnd);
end;

procedure _THashTableBase.EqualRange(const Key: _HashKeyType; out ItBegin,
  ItEnd: _TTagHashIterator);
begin
  self.CountRange(Key,ItBegin,ItEnd);
end;


function _DGL_Int_Min_HashTableBase(const x,y:integer):integer;  {$ifdef _DGL_Inline} inline; {$endif}
begin
  if x<y then
    result:=x
  else
    result:=y;
end;

procedure _THashTableBase.Erase(const ItBegin, ItEnd: _IIterator);
var
  It0,It1:_TTagHashIterator;
  tmp :_PHashNode;
  i : integer;
  MinIndex : integer;
begin
  It0:=_PtmpHashIt_Data(@ItBegin).FNodeIt;
  if self.IsEndIt(It0) then exit;
  It1:=_PtmpHashIt_Data(@ItEnd).FNodeIt;
  while true do
  begin
    if It0.ArrayIndex=It1.ArrayIndex then
    begin  //It1.pPNode<>nil
      tmp:=It1.pPNode^;
      while It0.pPNode^<>tmp do
      begin
        self.DeleteNode(It0.pPNode);
      end;
      DecCapacity();
      exit;   //出口
    end
    else
    begin
      while (It0.pPNode^<>nil)  do
        self.DeleteNode(It0.pPNode);
      MinIndex:=_DGL_Int_Min_HashTableBase(high(self.FDataList),It1.ArrayIndex);
      for i:=It0.ArrayIndex+1 to MinIndex do
      begin
        if self.FDataList[i]<>nil then
        begin
          It0.ArrayIndex:=i;
          It0.pPNode:=@self.FDataList[i];
        end;
      end;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?