在Delphi中实现类型安全的容器
          by [email protected],2004.09.12
Delphi中的容器和算法实在太缺乏了,又存在很多不一致,使用也很不方便。在构造一些容器和算法的时候,总是怀念C++的泛型和STL;所以就尝试在Delphi中编写泛型代码;其它现有的Deplhi容器和算法库实现中,主要的实现途径有利用Delphi中的array of const(相当于弱类型,而且对结构的支持差,如Decal);或者建立一套类体系作为容器中的元素(主要使用虚函数机制,如:左轻侯有篇文章也谈到过; 一般简单类型需要做打包拆包);还有的实现是针对TObject、IInterface、String等做多套代码实现(如:DCL库); 但他们相对于C++的STL来说缺陷也很明显,类型不安全,速度慢,代码重复;   DGL库克服了这些问题,能够用类型安全的方式支持所有基本类型、指针(包括类的指针)、Interface、结构(record)、Object结构(Delphi中已经不推荐使用)、类成员函数指针、类(class)的值语义(一般Delphi中不习惯使用类的值语义,所以不建议使用)等其它用户自定义类型,并且类型安全(速度当然没有问题啦), 没有重复代码!
库现在包括以下组件:
<object>
_IIterator    容器迭代器
_IMapIterator Map迭代器
(PointerBox函数可以将原生指针包装成一个与库兼容的迭代器)<接口interface>                     
_ICollection        容器接口
_ISerialContainer   序列容器的接口     
_IVector            向量接口(容器的一种)
_IList              链表接口(容器的一种)
_IDeque             队列接口(容器的一种)
_IStack             堆栈接口(一种容器配接器)
_IQueue             双端队列接口(一种容器配接器)
_IPriorityQueue     优先级队列_ISet               Set接口                       
_IMultiSet          MultiSet接口        
_IMap               Map接口                       
_IMultiMap          MultiMap接口               <类class>
_TAlgorithms        算法类(包括:拷贝、替换、删除、排序、搜索等算法)_TAbstractContainer  容器虚基类
_TAbstractSerialContainer  序列容器类的虚基类 
_TAbstractSet       Set(MultiSet)的抽象虚基类    
_TAbstractMap       Map(MultiMap)的抽象虚基类         
_TVector            向量实现类        
_TList              链表List的一个实现                   
_TDeque             队列Deque的一个实现           
_TStack             堆栈Stack     
_TQueue             双端队列Queue  (_THashTableBase     Hash表(库内部使用))
_THashSet           用Hash表实现的Set             
_THashMultiSet      用Hash表实现的MultiSet        
_THashMap           用Hash表实现的Map             
_THashMultiMap      用Hash表实现的MultiMap

解决方案 »

  1.   

    下载地址:
      http://www.tomore.com/1/41811.html我使用这个库两年了,用它构造的程序可能已经有上百万人在使用:)这个库的特色在于类型安全\快速\容易使用,库的结构大量借鉴了STL,当然结合了Delphi本身的特点;代码支持Delphi7和TurboDelphi编译环境(其他环境没有测试过)
      

  2.   

    下载那地方有人问你了:和JCL的容器类比有什么优势?:)
      

  3.   

    看这个代码比较郁闷那,作者明显就是VC的角度,专门弄个.Inc_H, .Inc_pas,引来引去,累代码中的变量命名是纯粹是C++风格,看这些代码,还不如直接用C++写DLL给D用,郁闷,先不管效率了,看这代码就头大。情愿看JCL去了,最起码代码习惯与VCL一致些。
      

  4.   

    就像stack.inc_pas中的函数
    procedure _TStack.Assign(const ItBegin, ItEnd: _IIterator);
    begin
      self.FBaseContainer.Assign(ItBegin, ItEnd);
    end;如在Delphi IDE中,直接用CTRL+Shift+上下箭头,即可切换声明与实现的代码,
    而我却找了半天,还没找到TStack的声明,晕
    估计看你代码的同事,头大不已,或者说你同事也是搞C的。我只觉得我是Delphi程序员,我会按VCL标准写法去写代码,如果写VC代码会用标准MFC代码写,不过另搞一套,搞的大家郁闷那。
      

  5.   

    纯粹发劳骚,LZ勿怪。看楼主的一些函数还是有点用的,有机会可以用用。:D
      

  6.   

    to:DelphiGuy()  "下载那地方有人问你了:和JCL的容器类比有什么优势?:)"housisong:发表于 2006-9-28 09:34 AM  资料 短消息   
    JCL的DCL针对TObject、IInterface、String三种类型分别写了三套代码实现 
    1。也就是代码重复了三次,而且我在使用它的一个版本(2004年的)的时候发现Hash表的实现有一个错误(也有人报告了同样的问题),然后修改了三处; 2。支持三种类型也就是它不能支持其他类型,比如Byte类型,你会说可以用TObject指针强制类型转换当作Byte用,但内存使用变成4倍,用户使用也很繁琐; 而且如果我想在容器中储存Record,那就很难了; 严格的说,DCL并不是“泛型”库;
    ————————
     而DGL库内部的代码编写是完全“泛型”的,用户使用库界面(也就是易用性)和DCL一致
      

  7.   

    呵呵,我承认这个库和STL很像,有点不像Delphi代码的风格,但Delhpi支持真正的范型编码吗?
    所以按照STL的思想代码,使用手工扩展代码的方式来完成“范型”的任务;我相信源代码的可阅读还是不错的(如果你看过Decal的底层实现的话:)
      

  8.   

    to cncharles(旺仔) 
      我自己写的,但并不是闭门造车,你可以和其他几个实现对比,不管是编码质量\还是代码效率\或者易用性,都欢迎批评;   我的工作中需要的容器和算法比较多,对效率要求也非常高,所以就有了DGL;
      最近在构造一个新的版本,与以前的兼容,但速度会更快;我想使用新的语法特性inline来提高性能,目标是使库中的Vector接近数组的效率(基本达到),迭代器的效率接近指针的效率(正在考虑方案);这样的话库的包装优势将更加明显;
      
      
      

  9.   

    to ERR0RC0DE() :
      你的观点和意见都比较集中于可读性,那么我想知道你有没有读过STL的源代码(SGI的那个实现比较好读)?  或者读Decal的实现(我觉得是个恐怖的经历,而且Decal其实只支持一种类型,就是delphi中的TVarRec弱类型)  DCL的源代码可读性很不错,就是功能上弱了一些,所有代码一式三份:)  ; 而我想要支持Byte流的容器,想要操作一个特殊数据区中的算法,我想要支持函数映射表的map,支持我的大量TChatData记录的算法,我想要一个快速高性能的网络消息栈...  DCL都不能给我; (这也是我从头构造DGL的原因)  把STL中的功能做成Dll来调用,可行,但工作量太大了,而且易用性会受到很大的影响;不知道有多少人这样用:)
        
      JCL太庞大了,无所不包(也就想拆出一小块来用也不容易:);要想使用它和测试它然后用于商业软件中感觉就像一个恐龙(这是我从不用它的个人意见而已:)  有一次我仅翻遍这个库的源代码文件就用了2个小时(就像翻书那样翻,几秒一个文件)!
      
      DGL库的源文件组织上有点像C\C++ (没有办法,只能这样), 但库的可读性个人认为还是很不错的,而且我也不会要求使用DGL的Delphi开发人员都来阅读DGL,直接在Delphi中使用那些DGL_XXX.pas文件就可以了;
      

  10.   

    差不多是这个意思D的IDE对它熟悉之后,就会感觉到其它IDE环境真是很不爽的,就像我上面说的其中一个功能,当然这是一个习惯问题,习惯就好,呵。至于你所说的BYTE流之类的,你可能做网络方面的东西多,之前我也做了一些协议的处理,对我认为,只是内存流处理而已,无所谓BYTE,INT, CHAT,有时都使用到算法的东西,像HASH之类,因为都交给DB去处理了。通讯只关心数据的IN和OUT。当然如需大量的数据分发,而且要求效率,队列,栈都最好是自己写。不过需要时间考验就是了。呵呵,我也有想法想写一个队列的处理,下次你再开源这个东西,俺过来参考参考。另:我看很多LIST,QUEUE, Statck的代码,其中部分是尽量减少内存的New, Dispose处理,增加对内存缓冲的处理,这方面在DGL还没,下次加加,这样效率会好些。
      

  11.   

    哦,俺真没看过STL的源代码,而且也不太懂其语法,都是看看D里面的东西,更不了解,所以,看到有D的实现,当然要看看其中意思。
      

  12.   

    哦,问一下:
    泛型和STL主要的功能就是实现数组(LIST),队列(QUEUE),栈(Stack),散列表(HASH),还有什么?应该还有树,图吧,感觉比较少用,这两个。差不多之前学的数据结构都用到了。
    容器,集合感觉可以用上面的东西扩展出来,其它的也类型。
      

  13.   

    楼主的作品可以说是广大delphi支持者的一种启示。之前真的没有见过delphi的泛化应用。
      

  14.   

    我这几天修改出了一个版本,整个库快了很多!   
      新的下载地址:http://cosoft.org.cn/projects/dgl/在inline的支持下,其中的Vector的效率甚至可以和Delphi中的array of type想抗衡(如果编译器优化的好,甚至会生成相同的汇编码);
      

  15.   

    to: ERR0RC0DE() 
    “另:我看很多LIST,QUEUE, Statck的代码,其中部分是尽量减少内存的New, Dispose处理,增加对内存缓冲的处理,这方面在DGL还没,下次加加,这样效率会好些。”  恩,你的意见不错; DGL中Vector和Deque都有了类似的结构;相应的QUEUE和Statck也有了,因为他们内部就是使用Deque来实现的;List可以考虑增加一个自己的专用的内存管理器来提高效率,但在Delphi中这个(从现在实际的性能测试来看)必要性并不强,如果程序中使用FastMM(一个替代Delphi内存管理的第三方库,新版Delphi使用了它),好像必要性就更不强了;我会做一次性能对比来决定是否在List的实现中替换内存管理方案
    “哦,问一下:泛型和STL主要的功能就是实现数组(LIST),队列(QUEUE),栈(Stack),散列表(HASH),还有什么?应该还有树,图吧,感觉比较少用,这两个。差不多之前学的数据结构都用到了。
    容器,集合感觉可以用上面的东西扩展出来,其它的也类型。”  “泛型”是一种编程范型(其他比如过程式编程、面向对象、函数Functor式编程),在C++中的泛型使用模板(template)来实现(java中使用编译器支持的弱类型);
       “STL”是C++的标准模板库,库主要实现了泛型的容器、算法等;
        DGL在Delphi中主要使用手工代码扩展的技术来实现泛型的容器、算法。
      

  16.   

    to alphax(豪言壮语的乌鸦):我看了一下ezdsl库,感觉有点像教学库,框架上感觉没有STL好;
    ezdsl也并不是泛型库,也就是支持的类型有限,比如hash表只支持string做key映射到pointer;ezdsl中有些代码写的比较死,使用了很多汇编,比如TStringStack的实现就很不优雅,只能支持255个字符的串,效率也很低库里面有很多不安全或者hack的代码,如:
    procedure TStringStack.Push(const S : string);
    var
      NewS : string;
    begin
      NewS := S; //为了增加引用计数
      Stack.Push(pointer(NewS));
      pointer(NewS) := nil;
    end;
    procedure EZLongStrDisposeData(aData : pointer);
    begin
      string(aData) := '';//这里释放引用计数
    end;string在Delphi中现在的实现利用了写时复制(copy on write)加引用计数的手法来实现的,其实这是一个很有争议的实现方案,特别是现在有很多的多线程程序和多核CPU流行的背景下;ezdsl利用Delphi的现有string实现方案来hack实现是比较危险的;
      

  17.   

    除非语言本身支持,否则所谓的generic怎么搞都显得很不自然,相反,个人习惯和熟悉程度可能选择库的主要因素,我没说你的不好,这是要先声明的其实我也是间接使用ezdsl,把它作为底层实现封装一下,使用起来也没感觉有太大的问题,如果到时候觉得有更好的库,或者汇编代码成了问题,只要修改封装的内部就可以了,现在可以用的库还是比较多的,而且ezdsl使用起来也不象你想象那么不济,首先,性能上应该算是比较好的,稳定性也很好,我用几年了,除了扩展功能以外,没有因为bug修改过他的代码,虽然我实际上只使用其中某几个类,第二,使用虽然有点麻烦,但是麻烦一次,以后就好了,比如做个string stack,你可以直接用tstack作为底层实现,一样的,
    type
      {
         icontainer = interface
        [xxx...]
           ...
        end;
        
        tdata_carrier = class
        public
          function compare(a: tobject): integer; virtual; abstract;
        end;
        
        tdata_carrier_class = class of tdata_carrier;
        tabstractcontainer_class = class of Ezdslbse.TAbstractContainer;
        
        tcontainerbase = class(tinrefacedobject, icontainer)
        protected
          fcontainer: tabstractcontainer;
        protected
          class function get_container_class: tabstractcontainer_class; virtual; abstract;
        public
          constractor create(const aOwnsData: boolean); virtual;
          constractor create2(const aOwnsData: boolean; const aCompareFunc: tlistsortcompare); virtual;
        end;
        
        function data_carrier_compare(a, b: pointer): integer;
        var
          x, y: tdata_carrier;
        begin
          x := tdata_carrier(a);
          y := tdata_carrier(b);
        
          result := x.compare(y);
        end;
        
        procedure dispose_data_object(p: pointer):
        begin
          tobject(p).free();
        end;
        
        
        constructor tcontainerbase.create(const aOwnsData: boolean);
        begin
          fcontainer :=  get_container_class().create(aOwnsData);
          fcontainer.compare := data_carrier_compare;
          fcontainer.disposedata := dispose_data_object;
        end;
        
        constractor tcontainerbase.create2(const aOwnsData: boolean; const aCompareFunc: tlistsortcompare);
        begin
          fcontainer :=  get_container_class().create(aOwnsData);
          fcontainer.compare := aCompareFunc;
          fcontainer.disposedata := dispose_data_object;
        end;
      }
    type    
      tstring_carrier = class(t_data_carrier)
      protected
        function compare(a: tobject): integer; override;
      public
        value: string;
      end;function tstring_carrier.compare (a: tobject): integer;
    var
      x: tstring_carrier;
    begin
      x := tstring_carrier(a);  result := comparestring(value, x.value);
    end;
      
    type
      //特化
      istringstack = interface(icontainer)
      [xxxx-xxxxx...]
         procedure push(const aValue: string);
         function pop(): string;
      end;  tstringstack = class(tcontainerbase, istringstack)
      private
        fstack: tstack;
      protected
        ...
        class function get_container_class: tabstractcontainer_class; override;
        
        procedure push(const aValue: string);
        function pop(): string;
      end;procedure tstringstack.push(const avalue: string);
    var
      carrier: tstringcarrier;
    begin
      carrier := tstringcarrier.create();
      carrier.value := avalue;
      fstack.push(carrier);
    end;...
      

  18.   

    to alphax(豪言壮语的乌鸦):
      要说易用性,你用一下DGL就可以知道了; 若果你知道DCL库(我见到的其他几个算法库中最易用的库),那么DGL库的使用方法和它非常接近,如果你熟悉STL,那就更容易上手;
      Delphi虽然不直接支持范型,带这并没有带来多少底层实现的复杂度,DGL库的实现并不比STL库的实现难读;  你可以看一下DGL,自己运行里面的示例;它的速度足够让你满意,如果把C++中的STL看作利用tamplate来扩展代码得到类型安全和快速;那么DGL可以看作利用了Include直接扩展代码来得到等价的类型安全和速度!
      

  19.   

    建议楼主放到 sourceforge 上去,影响会更大一些。
      

  20.   

    另外我觉得下划线打头很不爽,建议楼主把_T改成G打头,如 GList, GHashSet。
      

  21.   

    同意楼上,放到sf上去可能更好,不过我觉得_T前缀挺好你这个思路我以前看过,叫template什么来着?当初看法和现在看法一样,反正亲爱的ezdsl能够胜任工作,也懒得换别的风格的库了
      

  22.   

    todo: agui(阿贵: 高级图形用户界面) ( ):
      DGL中那些使用_T开头的类或者其他用下划线前缀的定义,代表的是“库内部”使用的意思,不希望库的使用者直接使用这些定义;
      

  23.   

    新版本1.20 , 下载地址: http://www.tomore.com/1/41811.html我做了一个DGL、STL、DCL 、DeCal 、EZDSL  的性能对比,如下:(2006.10.12 DGL Profiler)CPU: AMD Athlon(tm)64 3000+(1.81G)
    Delphi7 Compile DGL lib============================================================================
    Container:PushBack Next Visite Random Visite Insert At Middle PushFront
    TVector 0.010 us 0.008 us 0.102 us 34400.000 us 78000.000 us
    TDeque 0.009 us 0.055 us 0.155 us 143800.000 us 0.010 us
    TList 0.067 us 0.022 us 15310.000 us 0.073 us 0.053 us

    IVector 0.014 us 0.018 us 0.156 us 34400.000 us 78200.000 us
    IDeque 0.013 us 0.070 us 0.235 us 153000.000 us 0.016 us
    IList 0.073 us 0.022 us 15160.000 us 0.078 us 0.056 us

    Container: Insert Find Next Visite
    IMap 0.274 us 0.797 us 0.048 us
    IMultiMap 0.298 us 0.899 us 0.067 us
    ISet 0.272 us 0.805 us 0.044 us
    IMultiSet 0.253 us 0.805 us 0.043 us
    ====================================================================================Delphi7=============================================================================
    Container:PushBack Next Visite Random Visite Insert At Middle PushFront
    arrayof 0.168 us 0.006 us 0.086 us 40600.000 us 121800.000 us
    TList 0.023 us 0.013 us 0.164 us 28000.000 us 65600.000 us
    ====================================================================================STL : VC6 Compile===================================================================
    Container:PushBack Next Visite Random Visite Insert At Middle PushFront
    vector 0.049 us 0.005 us 0.032 us 34400 us 68800 us  
    deque 0.013 us 0.016 us 0.055 us 212400 us 0.013 us  
    list 0.142 us 0.022 us 18800 us 0.161 us 0.159 us  Container: Insert Find Next Visite
    map 0.408 us 0.277 us 0.054 us   
    set 0.405 us 0.278 us 0.048 us   
    multimap 0.430 us 0.277 us 0.055 us   
    multiset 0.405 us 0.278 us 0.048 us  
    ====================================================================================DCL lib===============================================================================
    Container:  PushBack Next Visite Random Visite Insert At Middle  PushFront
    TArrayList  0.019 us 0.029 us 0.164 us 25000.000 us 65600.000 us
    TVector     0.014 us 0.025 us 0.164 us 25000.000 us 62400.000 us
    TLinkedList 0.050 us 0.023 us 5780.000 us 0.056 us 0.086 us

    Container: Insert Find   Next Visite
    TBinaryTree 0.470 us 1.047 us 0.086 us
    THashMap 0.422 us 0.788 us 0.084 us(copy Values to TArrayList,it is not ture test!)
    THashSet 0.485 us 0.588 us "Container.First" is O(N*N), is bad,can not test! ps: THashXXX.Create() 
      for I := 0 to FCapacity - 1 do
        SetLength(FBuckets[I].Entries, 64);) //is bad design, slow and waste memory!ps: THashXXX   //is bad design for dynamic sizeps: TLinkedList.Clear() ERROR !!!
    procedure TLinkedList.Clear;
      .....
      //ERROR , must add line:  FStart:=nil;
    end;
    =====================================================================================DeCal lab============================================================================
    Container: PushBack Next Visite Random Visite Insert At Middle PushFront
    DArray 0.206 us 0.184 us 0.305 us 53200.000 us 128000.000 us
    DList 0.147 us 0.127 us 13109.000 us 0.167 us 0.141 us

    Container: Insert Find Next Visite
    DSet 2.117 us 6.594 us 0.117 us
    DMultiSet 2.000 us 5.532 us 0.117 us
    DMap 1.961 us 4.969 us 0.115 us
    DMultiMap 1.875 us 5.234 us 0.149 us DHashSet 22.500 us 58.740 us 0.833 us
    DMultiHashSet 0.372 us 5465.000 us 0.788 us
    DHashMap 29.680 us 62.820 us 0.727 us
    DMultiHashMap 0.681 us 2970.000 us 0.786 us
    =====================================================================================EZDSL lab============================================================================
    Container:    PushBack Next Visite Random Visite Insert At Middle PushFront
    TEZCollection is maxsize is N=10922*92 for test! it is  very small for test;
    TEZCollection 0.078 us 0.077 us 6.233 us 0.388 us 0.588 us
    TDList       0.175 us 0.028 us 7050.000 us 0.170 us 0.150 us
    TLinkList     0.155 us 0.033 us 15650.000 us 0.167 us 0.147 us

    Container: Push Pop
    TQueue 0.139 us 0.150 us
    TStack 0.142 us 0.145 us

    Container: Insert Find Next Visite
    THashTable 7.580 us 1.720 us (not find way to test!)
    =====================================================================================
      

  24.   

    ( 我编辑的各式全乱了:( )1.20下载地址给错了,应该是:http://cosoft.org.cn/projects/dgl/DGL的速度可以和vc自带的STL相抗衡了,呵呵  DGL应该还有优化的空间;
    奇怪的是array(Delphi自己的)\Tvector和TDeque的随机寻址速度比STL的慢很多! 可能是随机数发生器的调用问题;什么时候测试一下SGI的STL看看性能怎样:)
      

  25.   

    数据的格式没有了,比较乱,可以去我的blog看:http://blog.csdn.net/housisong
    增加了SGI实现的STL的性能测试数据,果然很强!
      

  26.   

    STL的map测试写的有误,该后测试结果:
    DGL lib=========================================================================
    Container:  PushBack  Next Visite Random Visite Insert At Middle  PushFront
    TVector     0.010 us  0.008 us    0.102 us      34400.000 us      78000.000 us
    TDeque      0.009 us  0.055 us    0.155 us      143800.000 us     0.010 us
    TList       0.067 us  0.022 us    15310.000 us  0.073 us          0.053 us
     
    IVector     0.014 us  0.018 us    0.156 us      34400.000 us      78200.000 us
    IDeque      0.013 us  0.070 us    0.235 us      153000.000 us     0.016 us
    IList       0.073 us  0.022 us    15160.000 us  0.078 us          0.056 us
     
    Container:  Insert      Find        Next Visite
    IMap        0.274 us    0.797 us    0.048 us
    IMultiMap   0.298 us    0.899 us    0.067 us
    ISet        0.272 us    0.805 us    0.044 us
    IMultiSet   0.253 us    0.805 us    0.043 us
    ================================================================================Delphi7=========================================================================
    Container:  PushBack  Next Visite Random Visite Insert At Middle  PushFront
    array       0.168 us  0.006 us    0.086 us      40600.000 us      121800.000 us
    TList       0.023 us  0.013 us    0.164 us      28000.000 us      65600.000 us
    ================================================================================STL : VC6 Compile===============================================================
    Container:  PushBack  Next Visite Random Visite Insert At Middle  PushFront
    vector      0.049 us  0.005 us    0.032 us      34400 us          68800 us
    deque       0.013 us  0.016 us    0.055 us      212400 us         0.013 us
    list        0.142 us  0.022 us    18800 us      0.161 us          0.159 usContainer:  Insert      Find        Next Visite
    map         0.424 us    3.297 us    0.047 us  
    set         0.431 us    3.289 us    0.048 us  
    multimap    0.433 us    3.298 us    0.047 us  
    multiset    0.431 us    3.288 us    0.048 us  
    (SGI)STL : DEV-C++4.98 (GCC max optimize) Compile===============================
    Container:  PushBack  Next Visite Random Visite Insert At Middle  PushFront
    vector      0.016 us  0.005 us    0.032 us      34400 us          56200 us
    deque       0.012 us  0.008 us    0.133 us      875000 us         0.013 us
    list        0.044 us  0.016 us    12400 us      0.052 us          0.036 usContainer:  Insert      Find        Next Visite
    map         0.458 us    3.352 us    0.035 us  
    set         0.445 us    3.336 us    0.036 us  
    multimap    0.403 us    3.236 us    0.035 us  
    multiset    0.413 us    3.222 us    0.036 us  hash_map    0.155 us    0.705 us    0.043 us  
    hash_set    0.147 us    0.653 us    0.043 us  
    hash_multimap 0.141 us  0.706 us    0.044 us  
    hash_multiset 0.138 us  0.652 us    0.043 us  
    ================================================================================
      

  27.   

    越看你的代码越看不懂,想整理一下都没法。楼主,你将下次更新的代码改成pas格式吧。不然按我理解,所有的东西就是内存流+一些算法的操作,慢慢作自己的积累得了。
      

  28.   

    还有尽量不要写class function ,class procedure,单独写成函数集就行了。可能是习惯问题。
      

  29.   

    to: ERR0RC0DE() ( ) 
      安装DGL的方法是把DGL源代码所在的目录设置到Delphi的搜索路径中;
      DGL设计成了扁平风格的类框架,这是最容易实用的吧,不用记各种各样的函数名:);
      你直接使用那些DGL_XX.pas单元就可以了,不用关心那些底层实现:) 比如直接在项目中引用DGL_Pointer.pas  使用其中的TPointerDeque类;
      var
        piDeque : IPointerDeque;
      begin
        piDeque :=TPointerDeque.Create();
        piDeque.PushBack(Pointer(2));   
        piDeque.PushFront(Pointer(3));
        Assert(piDeque.iterms[0]=Pointer(3));    
        Assert(piDeque.iterms[1]=Pointer(2));
        //not need free piDeque,it auto free;
      end;
      

  30.   

    幸亏Delphi 2007将在Win32和.NET下面都实现范型(不过Win32方面的支持或许不是很全面),而且重要的是语法简单多了,似乎会提供更加方便一些的东西。
      

  31.   

    todo: lextm(LeLe)
      是啊,“语法糖”对于编写简单易读的代码还是很有用的;
      我想只要有了这层“范型”语法糖,我的DGL将很容易移植到泛型实现(代码已经按这个写好了:),并且也更易用;
      今天会发布一个新版本,主要改进了Deque的迭代器的内部实现;DGL的性能可以和C++中SGI实现的STL进行对比(对比数据可以看我的blog);(算法部分还没有做评估)
      
      

  32.   

    to  zhangl_cn(和尚-修行-希望圆寂时可以烧出舍利而非结石) :
      DGL的Demo和Doc比较少,如果熟悉STL的话到没有多少问题;
      DGL下载包中现在可以看作例子就仅仅是单元测试和性能测试程序;我随手写了几个DGL的Demo,一个函数是一个:///////////////////////////...implementation
    uses
      DGL_Pointer,DGL_Byte,DGL_Integer,_DGLMap_String_Integer,DGL_String;{$R *.dfm}procedure TForm1.btn_IIntVectorClick(Sender: TObject);
    var
      intVector : IIntVector; //interface type ; Vector use as delphi's array;
      i,Sum : integer;
    begin
      intVector :=TIntVector.Create;  for i:=0 to 100-1 do
        intVector.PushBack(i);
      Assert(intVector.Size()=100);  Sum:=0;
      for i:=0 to intVector.Size()-1 do
        Sum:=Sum+intVector.Items[i];
      Assert(Sum=(0+99)*100 div 2);  // intVector is interface type not need free;
    end;procedure TForm1.btn_TIntVectorClick(Sender: TObject);
    var
      intVector : TIntVector; //class type
      i,Sum : integer;
    begin
      intVector :=TIntVector.Create;
      try
        for i:=0 to 100-1 do
          intVector.PushBack(i);
        Assert(intVector.Size()=100);    Sum:=0;
        for i:=0 to intVector.Size()-1 do
          Sum:=Sum+intVector.Items[i];
        Assert(Sum=(0+99)*100 div 2);  finally
        intVector.Free;  //intVector is class type;
        //use class type is maybe faster than interface type;
        //recommend priority use DGL container as interface by most time;
      end;end;procedure TForm1.btn_IIntDequeClick(Sender: TObject);
    var
      intDeque : IIntDeque;
      i,Sum : integer;
    begin
      intDeque :=TIntDeque.Create;  for i:=0 to 100-1 do
        intDeque.PushBack(i);
      Assert(intDeque.Back()=99);Assert(intDeque.Front()=0);
      Assert(intDeque.Size()=100);  for i:=0 to 100-1 do
        intDeque.PushFront(i); //Deque's PushFront and PushBack is the same fast;
      Assert(intDeque.Back()=99);Assert(intDeque.Front()=99);
      Assert(intDeque.Size()=200);  Sum:=0;
      for i:=0 to intDeque.Size()-1 do
        Sum:=Sum+intDeque.Items[i];
      Assert(Sum=((0+99)*100 div 2)*2);
    end;procedure TForm1.btn_IPointerListClick(Sender: TObject);
    var
      piList : IPointerList;
      it : IPointerIterator;
      i,Sum : integer;
    begin
      piList :=TPointerList.Create;  for i:=0 to 100-1 do
        piList.PushBack(Pointer(i));
      for i:=0 to 100-1 do
        piList.PushFront(Pointer(i));  it:=piList.ItBegin.Clone(100); //it is pointer to piList's middle;
      for i:=0 to 100-1 do
        piList.Insert(it,Pointer(i));
      //List's PushFront and PushBack and insert at any pos is the same fast;
      Assert(piList.Size()=300);  Sum:=0;
      it:=piList.ItBegin; //it is pointer to piList's first;
      for i:=0 to piList.Size()-1 do
      begin
        Sum:=Sum+integer(it.Value);
        it.Next;
      end;
      Assert(it.IsEqual(piList.ItEnd));
      Assert(Sum=((0+99)*100 div 2)*3);
    end;
    procedure TForm1.btn_IIntSerialContainerClick(Sender: TObject);
      procedure SetVaues(const Container:IByteSerialContainer);
      var
        i : integer;
      begin
        for i:=0 to 100-1 do
          Container.PushBack(i);
      end;  procedure CheckSum(const Container:IByteSerialContainer);
      var
        it : IByteIterator;
        Sum : integer;
      begin
        it:=Container.ItBegin;
        Sum :=0;
        while (not it.IsEqual(Container.ItEnd)) do
        begin
          sum:=sum+it.Value;
          it.Next;
        end;
        Assert(Sum=(0+99)*100 div 2);
      end;var
      BVector : IByteVector;
      BDeque  : IByteDeque;
      BList   : IByteList;
      it: IByteIterator;
    begin
      BVector :=TByteVector.Create;
      BDeque  :=TByteDeque.Create;
      BList   :=TByteList.Create;  SetVaues(BVector);
      CheckSum(BVector);
      SetVaues(BDeque);
      CheckSum(BDeque);
      SetVaues(BList);
      CheckSum(BList);
    end;
      

  33.   

    //一个函数是一个Demo,接上:
    procedure TForm1.btn_IPointerSetClick(Sender: TObject);
    var
      piSet : IPointerSet;
      it : IPointerIterator;
      i,Sum : integer;
    begin
      piSet :=TPointerHashSet.Create;  for i:=0 to 200-1 do
        piSet.Insert(Pointer(i div 2)); //values is [0,1,..99]
      Assert(piSet.size()=100);  Sum:=0;
      it:=piSet.ItBegin;
      for i:=0 to piSet.Size-1 do
      begin
        inc(Sum,integer(it.Value));
        it.Next;
      end;
      Assert(Sum=((0+99)*100 div 2));  for i:=0 to 100-1 do
      begin
        it:=piSet.Find(Pointer(i));
        Assert(not it.IsEqual(piSet.ItEnd));
        Assert(it.Value=Pointer(i));
      end;  for i:=0 to 100-1 do
        piSet.EraseValue(Pointer(i)); //== piSet.Erase(piSet.Find(Pointer(i)));
      Assert(piSet.IsEmpty());
      Assert(piSet.Size()=0);end;procedure TForm1.btn_IPointerMultiSetClick(Sender: TObject);
    var
      piMSet : IPointerMultiSet;
      it,itt : IPointerIterator;
      i,Sum : integer;
    begin
      piMSet :=TPointerHashMultiSet.Create;  for i:=0 to 200-1 do
        piMSet.Insert(Pointer(i div 2)); //values is [0,0,1,1..99,99]
      Assert(piMSet.size()=200);  Sum:=0;
      it:=piMSet.ItBegin;
      for i:=0 to piMSet.Size-1 do
      begin
        inc(Sum,integer(it.Value));
        it.Next;
      end;
      Assert(Sum=((0+99)*100 div 2)*2);  for i:=0 to 100-1 do
      begin
        it:=piMSet.Find(Pointer(i));
        Assert(not it.IsEqual(piMSet.ItEnd));
        Assert(it.Value=Pointer(i));    Assert(piMSet.Count(Pointer(i))=2);    it:=piMSet.LowerBound(Pointer(i));
        Assert(it.Value=Pointer(i));
        itt:=piMSet.UpperBound(Pointer(i));
        Assert(it.Distance(itt)=2);
      end;  Assert(piMSet.Size()=200);
      for i:=0 to 100-1 do
        piMSet.Erase(piMSet.Find(Pointer(i)));
      Assert(piMSet.Size()=100);
      for i:=0 to 100-1 do
        piMSet.Erase(piMSet.Find(Pointer(i)));
      Assert(piMSet.Size()=0);end;procedure TForm1.btn_IStrIntMapClick(Sender: TObject);
    var
      StrIntMap : IStrIntMap;
      i,Sum : integer;
      it: IStrIntMapIterator;
    begin
      StrIntMap :=TStrIntHashMap.Create;
      StrIntMap.Insert('a1',1);
      StrIntMap.Insert('a2',2);
      StrIntMap.Insert('a3',3);
      Assert(StrIntMap.Items['a1']=1);
      Assert(StrIntMap.Items['a2']=2);
      Assert(StrIntMap.Items['a3']=3);
      StrIntMap.Clear();  for i:=0 to 100 -1 do
        StrIntMap.Items[inttostr(i)]:=i*3; //== StrIntMap.Insert(inttostr(i),i*3);
      Assert(StrIntMap.size()=100);  Sum:=0;
      for i:=0 to StrIntMap.Size-1 do
        inc(Sum,StrIntMap.Items[inttostr(i)]);
      Assert(Sum=((0+99)*100 div 2)*3);  for i:=0 to 100-1 do
      begin
        it:=StrIntMap.Find(inttostr(i));
        Assert(not it.IsEqual(StrIntMap.ItEnd));
        Assert(it.Value=i*3);
        Assert(strToint(it.Key)=i);
      end;  for i:=0 to 100-1 do
        StrIntMap.Erase(StrIntMap.Find(inttostr(i)));
      Assert(StrIntMap.Size()=0);
    end;procedure TForm1.btn_IStrMultiMapClick(Sender: TObject);
    var
      StrMMap : IStrMultiMap;
      i,Sum : integer;
      it,itt: IStrMapIterator;
    begin
      StrMMap :=TStrHashMultiMap.Create;
      StrMMap.Insert('a1','1');
      StrMMap.Insert('a2','2');
      StrMMap.Insert('a3','3');
      Assert(StrMMap.Items['a1']='1');
      Assert(StrMMap.Items['a2']='2');
      Assert(StrMMap.Items['a3']='3');  StrMMap.Insert('a1','4');
      Assert((StrMMap.Items['a1']='1') or (StrMMap.Items['a1']='4'));
      Assert(StrMMap.Count('a1')=2);
      it:=StrMMap.LowerBound('a1');
      Assert((strtoint(it.Value)+strtoint(it.NextValue[1]))=(1+4));  /////////////////////////  StrMMap.Clear();  for i:=0 to 200 -1 do
        StrMMap.Items[inttostr(i div 2)]:=inttostr(i div 2); //== StrMMap.Insert(inttostr(i),inttostr(i*3));
      Assert(StrMMap.size()=200);  Sum:=0;
      for i:=0 to StrMMap.Size-1 do
        inc(Sum,strtoint(StrMMap.Items[inttostr(i div 2)]));
      Assert(Sum=((0+99)*100 div 2)*2);  for i:=0 to 100-1 do
      begin
        it:=StrMMap.Find(inttostr(i));
        Assert(not it.IsEqual(StrMMap.ItEnd));
        Assert(strtoint(it.Value)=i);
        Assert(strToint(it.Key)=i);    Assert(StrMMap.Count(inttostr(i))=2);    it:=StrMMap.LowerBound(inttostr(i));
        Assert(it.Value=inttostr(i));
        Assert(it.Key=inttostr(i));
        itt:=StrMMap.UpperBound(inttostr(i));
        Assert(it.Distance(itt)=2);
      end;  for i:=0 to 100-1 do
        StrMMap.Erase(StrMMap.Find(inttostr(i)));
      Assert(StrMMap.Size()=100);
      for i:=0 to 100-1 do
        StrMMap.Erase(StrMMap.Find(inttostr(i)));
      Assert(StrMMap.Size()=0);end;var
      AgSum : integer;
      procedure SumAValue(const Value: Byte);
      begin
        inc(AgSum,Value);
      end;
    var
      AgStr: string;
    procedure TForm1.btn_IByteIteratorClick(Sender: TObject);
      function ValuesAsStr(const it0,it1:IByteIterator):string;
      var
        it : IByteIterator;
      begin
        result:='';
        it:=it0;
        while not it.IsEqual(it1) do
        begin
          result:=result+inttostr(it.Value)+' ';
          it.Next;
        end;
      end;
    var
      BContainer : IByteContainer;
      it0,it1: IByteIterator;
      i,sum : integer;
    begin
      BContainer :=TByteVector.Create(100);
      //BContainer :=TByteDeque.Create(100);
      //BContainer :=TByteList.Create(100);
      Assert(BContainer.Size()=100);  it0:=BContainer.ItBegin();
      it1:=BContainer.ItEnd();
      while not it0.IsEqual(it1) do
      begin
        it0.Value:=random(256);
        it0.Next;
      end;  it0:=BContainer.ItBegin();
      it1:=BContainer.ItEnd();
      Sum:=0;
      while not it0.IsEqual(it1) do
      begin
        inc(sum,it0.Value);
        it0.Next;
      end;  AgSum:=0;
      TByteAlgorithms.ForEach(BContainer.ItBegin(),BContainer.ItEnd(),@SumAValue);
      Assert(AgSum=Sum);  AgStr:=ValuesAsStr(BContainer.ItBegin(),BContainer.ItEnd());
      TByteAlgorithms.Sort(BContainer.ItBegin(),BContainer.ItEnd());
      AgStr:=ValuesAsStr(BContainer.ItBegin(),BContainer.ItEnd());
      Assert(TByteAlgorithms.IsSorted(BContainer.ItBegin(),BContainer.ItEnd()));end;
      

  34.   

    网上关于此类产品还是比较多,你能讲讲与他们比你的产品的特点吗
    谢谢了如
    DECAL 数据结构与算法泛型类库
    http://sourceforge.net/projects/decal/
      

  35.   

    to stevenpeng(第九种兵器) :
      DGL的易用性很好,你可以看看上面那些Demo :) 对于熟悉STL的人来说,更加容易上手;
      DGL是类型安全的,库内部使用泛型思想编码,支持任何类型(基本类型\String\Record\Interface\Class等),而且可以很容易支持自定义类型(手工代码扩展,或者叫具现化);DECAL其实只支持Delphi的变体类型;
      DGL的实现是高效的,你甚至可以拿DGL和C++中有名的SGI实现的STL对比性能;
      (DGL的可读性很好)
      (DGL是可以移植的,今天我就顺利用FreePascal编译了DGL的代码)  (可以看我的Blog: http://blog.csdn.net/HouSisong )
      

  36.   

    不太明白,delphi不是没有template语法吗
      

  37.   

    to zzzl(不拉拉链) :
    Delphi现在不支持泛型语法,但并不妨碍泛型思想在Delphi中的使用;Delphi中一般实现“泛型”的方案有弱类型,就是利用const array和Variant变体类型,Decal(SDL)就使用了这个方案;  还可以利用类体系来完成,定义一个元素基类,然后所有元素都是这个基类的子类,库写一套代码支持基类;这种库对基本类型支持不好,需要做打包(放到容器之前)和拆包(从容器取出后)(我的库的第一个尝试方案,java的泛型本质上也是这个方案); DCL库的实现是写了3套一样的代码来分别支持string\interface\TObject类型;
       DGL库从本质上来讲和STL是最像的,不管缺点还是优点都很像,比如 高效的代码 和 代码膨胀问题;  如果把STL的使用看作利用tamplate作代码展开,不同的类型扩展出一套新的代码,然后编译器编译;那么DGL实现的原理是利用$include文件的方式作代码展开(和STL一样,不同的类型生成不同的代码让编译器编译)
      大多数时候直接使用DGL已经扩展好的代码(就是那些DGL_"ValueType".pas文件)就可以了(上面的Demo都是这种方式),这就如STL使用中的预先具现化: typedef std::vector<int> TIntVector;  typedef std::vector<string> TStringVector;
      对于自定义类型,比如Record,在STL中可以直接用std::list<YouType> ,在DGL中没有这么方便(缺乏编译器支持的语法糖);要完成这个任务,在DGL中需要用户新开一个pas文件来完成具现化,具现化的方法可以借鉴那些DGL_"ValueType".pas文件
      

  38.   

    首先感谢楼主的回复~~
    我对比过DECAL与DGL的代码,我个人感觉
    **可读性,对于DELPHI程序DECAL可读性较高,这一点前面好多人有提到过..
    **性能.是此类产品的生命力所在.此类产品性能我还没完整对比过~~~~不过很关注~~~
    **至于可移植,DECAL针对Delphi写的.移植性差~~
      

  39.   

    to stevenpeng(第九种兵器) : 
      Decal的代码都在一个pas单元,分成上面的定义部分和实现部分,比较符合Delphi的习惯;DGL的代码按功能和类分成了多个文件实现,而且使用了C\C++的文件组织方式(这样组织是因为DGL的代码需要支持任何可能的类型);所以开始有点不习惯:)
      Decal比DGL慢很多;各个库的性能对比测试数据(今天做了更新)可以参见:http://blog.csdn.net/housisong/archive/2006/10/12/1331993.aspx
      

  40.   

    to zenghuaunix001(童话):
      谢谢关注; 不过说得也太.... 哈哈    (宝兰才顾不上Delphi呢)
      DGL成型于2004年,最近对库的结构和一些实现进行了一些优化,容器部分差不多完成; 算法部分以前完成了大部分常用的算法(很多时候都是我用到了才添加上:),还需要做一次增加和优化(使其至少达到STL的标准);今天计划给DGL增加一个单向链表容器;
      一个人的精力有限;