Jump to content

Alex7691

Members
  • Content Count

    25
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by Alex7691


  1. On 4/7/2025 at 12:50 PM, pyscripter said:

    @Alex7691Good work.  It is useful to have a drop-in fast generics replacement.

     

    A couple of questions:

    • Is there an impact on code size?
    • I see a lot of code included that it is not directly related to generics.  (e.g. TSyncSpinlock, TSyncLocker, TaggedPointer, TCustomObject. TLiteCustomObject  etc.).  Are they actually essential for the rapid collections?   

    Thanks.

    Responding to your questions:

     

    a) The only metrics I have is the size of the executable. Using Rapid.Generics, I got a slightly smaller executable.

     

    b) Most of these classes that you mentioned are not necessary for most containers (the sync objects are needed for the TThreadList<>, TThreadedQueue<>. But if you don't use them, Delphi smart linker won't include them.


  2. 23 hours ago, Stefan Glienke said:

    I am very curious about this particular scenario. Can you tell me the dictionary's key and value types and usage? Is it mostly looking up values or adding/removing items?

    Hi Stefan,

     

    In our application there is a notification bus which internally has 2 dictionaries. The main one has an object (the "observable") as the key and a list of objects (each object has references to observers and notification methods) as the value. The second dictionary also has an object (the "observer") as the key and and Integer as the value. 

     

    The dictionary may contain a large number of objects (dozens of thousands) and at some point in time all the objects need to be freed. So when ObjA (an observable) is being destroyed it will notify all it's observers. Then it will remove itself from the dictionary and all oberservers will also be removed if they are only observing ObjA. This is where the new dictionary performance surprised me. The notification happens faster (because retriving the values from the keys is faster), but more importantly removing them from the dictionary is way faster than the previous version based on std TDictionary.

     

     


  3. On 4/7/2025 at 8:34 PM, Rollo62 said:

    Have you tested this under VCL, FMX, Win32, Win64, Macos (x86/ARM), iOS, Android, Linux as well?

     

     

    Tested using Win32 and Win64 compilers only for now. Android and Linux, it's possible in a near future. Not sure if I'm going to test on any Apple OS, though... Not into MacOS/iOS dev myself.

     

    FMX and VCL are UI frameworks and don't have any relevance for the testing.

    • Like 1

  4. 31 minutes ago, Ian Branch said:

    D12.3, latest Git release of Rapid Generics 2, 64-bit testing using RapidGenericsTestSuite:

    [dcc64 Error] uListTest.pas(2225): E2532 Couldn't infer generic type argument from different argument types for method 'AreEqual'

     

     

    It has also been fixed in the lastest version in github repo.

     

    Cheers,


  5. 6 hours ago, Sebam said:

    TObjectList<T> does not free owned objects upon destruction.

     

    True thing. 

     

    Please update the source code from github repo. It's fixed now and there are a few new test cases to cover TObjectList (tests for TObjectList are not complete yet).

     

    Thanks

    • Like 2
    • Thanks 1

  6. 9 hours ago, Anders Melander said:

    It looks to have the same interface but jeez it's a lot of code to maintain.

    As I said, it started more like a curiosity... like "it's so damn fast, but it's buggy... Can it be fixed to the point of being useful?" And after "wasting" the weekend, here I am :classic_laugh:


  7. 10 hours ago, David Heffernan said:

    And yet you did this with a other library? I'm curious. Why was it simple to integrate rapid? Does it have the same interface as rtl but is just faster? 

    Yep, Rapid is a drop-in replacement. Actually my code now has: 

    uses
    {$IFDEF USE_RAPIDGENERICS}
      Rapid.Generics,
    {$ELSE}
      System.Generics.Collections,
      System.Generics.Defaults,
    {$ENDIF}

    I can just toggle this compiler directive globally and the 3+ MLOC application can be built either using Rapid generics or std System.Generics.Collections, which is a major bonus. At anytime I can just switch this off with minimal impact (e.g. let's say EMB releases a new faster System.Generics.Collections in Delphi 12+x?)

    • Like 1

  8. Hi Stefan,

     

    yes, I know that Spring4D is great but it would be impossible to refactor hundreds of occurrences of different data structures in a massive 3+ MLOC application... 

     

    Rapid.Generics took me no more than 2 or 3 hours do change the application (of course, excluding many hours devoted to fix the library itself, but I was mostly doing it for fun in a "let's see if I can make it work" spirit). Basically I needed to do a grep seach/replace + a handful of tweaks here and there and voilá... it was building....

     

    Cheers,


  9. Hello everyone,


    Last week I (unsuccessfully) tried to use the Rapid.Generics library in a specific project. After replacing the std TDictionary/TList with the Rapid.Generics equivalents, the application fell apart within the first 10 seconds of testing, which was quite disappointing.


    Having some spare time during the weekend, I decided to give it a shot and see if I could make it work properly, at least fixing the most important and visible issues.


    As a result, I am now sharing my changes so others can benefit from them or contribute.


    https://github.com/Alexandre-Atozed/Rapid.Generics.v2


    Improvements (Readme contains a more detailed list):  

    • Fixed multiple bugs  
    • Refactored and streamlined the code  
    • Removed some unused code  
    • Added 123 unit tests, creating a comprehensive test suite

     

    The modified code passes all tests and is also free of memory leaks.


    The real world application is being tested with it now and the initial results are promising. One specific scenario where I replaced the std TDictionary with the Rapid.Generics one (a notification bus where a dictionary is used to map the instances) had a performance increase of 10x or more which is beyond what I would expect and too good to ignore.


    Any feedback or contributions are welcome!


    Cheers,

    • Like 4
    • Thanks 3

  10. I have a huge application in production using VCL Styles and the package mentioned above: https://www.almdev.com/prods/stylecontrols/stylecontrols.html

     

    The adapter works well with DevExpress grid and other controls like their different tree views. That's all we use from them. We decided to use other StyleControls components (buttons, date editors, page controls) instead of DevExpress ones because:

    1) they play well with VCL Styles

    2) Their code is much simpler and in general any issue you find can be fixed by yourself in a couple of  hours (compared to days to impossible to fix in DevExpress). It's clear that the author just wants to create something that does its job and works well, instead of trying to use every single pattern in any Gang of Four book.

    3) They are lightweight insted of the Dx famous kitchen-sink design

    I strongly recommend it if you are going down the VCL styles route (disclaimer: I'm not related to almdev company)

     

    Cheers,


  11. Has anyone had any luck with Tiny.Library (https://github.com/d-mozulyov/Tiny.Library), more specifically with its Generic classes?

    BTW, Rapid.Generics contains an older/simpler version of its Tiny.Generics unit (https://github.com/d-mozulyov/Rapid.Generics)

     

    I did a quick test on a TDictionary and the performance is impressive compared to the standard System.Generics. Collections dictionary.

    However, some other tests with TList<> , for example, showed random errors that were difficult to identify the cause, such as exceptions in ReallocMem().

    In addition, I identified some bizarre bugs in the code, such as in the TArray.InternalSearch() method, see below:

     

    class function TArray.InternalSearch<T>(Values: Pointer; Index, Count: Integer; const Item: T;
      out FoundIndex: Integer; Comparer: Pointer): Boolean;
    var
      I: Integer;
      Helper: TSearchHelper;
    begin
      if (Count <= 0) then
      begin
        if (Count = 0) then
        begin
          FoundIndex := Index;
          Result := True;      <---------- The result cannot be True when Count = 0
          Exit;
        end else
        begin
          raise EArgumentOutOfRangeException.CreateRes(Pointer(@SArgumentOutOfRange));
        end;
      end;

    System.Generics.Collections has a similar code and the result is obviously false:

     

    class function TArray.DoBinarySearch<T>(const Values: array of T; const Item: T;
      out FoundIndex: NativeInt; const Comparer: IComparer<T>; Index, Count: NativeInt): Boolean;
    var
      L, H, mid: NativeInt;
      cmp: NativeInt;
    begin
      if Count = 0 then
      begin
        FoundIndex := Index;
        Exit(False);
      end;


    I wouldn't expect to find this in a library of this level, unless it has never actually been tested/used.

     

    The lack of unit tests is also concerning....


  12. On 11/9/2023 at 9:25 AM, Stefan Glienke said:

    It better be - I spent quite some time on it. FWIW it was already introduced in 11.3

     

    I ran some benchmark applications this week and I found out that the servers built with Delphi 12 are 13-16% faster than the same built with Delphi 10.4.

     

    I can't currently pinpoint the exact source of the performance gain but I guess that Move() and others are playing an important part on it. Anyway, very well done!

     

    Cheers,

    • Thanks 1

  13. On 12/23/2023 at 9:04 PM, David Heffernan said:

    Ha ha ha. I think we all know the answer to this. 

     

    They can't even do menus properly. Even for the standard  windows theme the menus are custom drawn and the Emba code gets it wrong in various mixed dpi scenarios. 

     

    When I switched to Delphi 11.3 I'd hoped to avoid having to patch the VCL to suppress its custom drawn menus. Alas that hope was doomed. 

    Seems that you are referring to the TMainMenu control. We don't use it in our application. We used the TActionMainMenuBar which renders the menu. Not sure how much code they share and if the same problem affects both, but IIRC, the menu rendered correctly on high DPI monitors and in mixed setups.

     

    One thing that's really messed up in TActionMainMenuBar is the customization at runtime via TCustomizeDlg, and it happens all the time regardless of your monitor DPI. I've reported the issue to EMB but no fix so far: https://quality.embarcadero.com/browse/RSP-31714

     

    Other than that we haven't found any major issues so far.


  14. On 12/23/2023 at 9:51 AM, Darian Miller said:

    So what happens when you drag your window from a non-High DPI monitor to a High DPI monitor and vice-versa?   Do you get a lag and a bunch of flicker?

    We tested the application in a mixed monitor setup and it behaved in an acceptably manner (built with 10.3.3). I'm not saying that it is perfect. I'm saying that we couldn't find any showstopper issue.

     

    But I also found issues with several other applications in the same scenario, including WPF ones. I think MS didn't get it perfect either.

     

    As I said, the application has thousands of users around the world and the general feedback has been good. Nobody ever said that "it doesn't look prefessional" because of some minor issue like this.

     


  15. On 3/19/2023 at 1:24 AM, David Schwartz said:

     IntraWeb was introduced well over a decade ago and it's still hardly being used

    That's an old post but since I don't come here often, here it goes:

     

    David, 

     

    you are wrong.

     

    IntraWeb is not one decade old. IntraWeb was introduced in 1994, as a product, before Delphi 1.0. In the Delphi world it is as "old" as Delphi itself. And IntraWeb's doing fine, for 30 years, thank you.  I dare you to name another product/framework that started before IntraWeb and is still around. And, no, DevExpress and TMS were both founded *after* Atozed and IntraWeb.

     

    The same argument that you use against IntraWeb is the one that a Python developer uses against your application that you wrote in Delphi: "Hey, nobody uses Delphi anymore!". The Python developer will never get it, simply because he doesn't know it.

     

    Cheers

     

     

     


  16. This is an rather old thread but I'd like to give my 2c for future readers:

     

    I was lead of a team modernizing a huge (300+ forms, 3+ MLOC) Delphi application. The major part of the modernization process was about styling it, using VCL Styles. We used Delphi 10.3 at that time, and then eventually we migrated to Delphi 10.4.

     

    It took 3 months and we decided to purchase a 3rd party library (StyleControls) to make the process easier and faster. StyleControls has simliar controls (e.g. buttons) that work better with styles than the standard ones. Besides that, SyleControls have some classes to help styling controls that don't support VCL Styles directly (e.g. the DevExpress grid that we extensively use in our application). Disclosure: I'm not connected to StyleControls company in any way.

    Regarding VCL code, some hacking was necessary to fix bugs that couldn't be avoided and no workaround was found (mostly runtime patching of VCL classes). We also used the Rodrigo Ruz's VCL Style Utils package, and it also required some tweaking (nothing major though). 

    Repainting of complex forms when resizing can also be problematic. A non-styled VCL form with hundreds of controls will repaint itself very fast and there is very little flicker. The same form when styled will cause a severe and ugly flicker that can't be ignored and we also needed to find ways to reduce or interrupt form refreshing in many scenarios in order to reduce this effect.

     

    But basically I disagree with who says that it doesn't look professional, or "not quite there yet". The final result looks nice and professional, although there are things that could be improved and refined. The application has been in production, with thousands of users and the general feedback has always been positive. I think it's totaly worth it.

     

    • Like 5

  17. This is an old thread that was pointed out to me by an IntraWeb user. I'm adding some information for future readers.

     

    IntraWeb has it's own ISAPI classes and doesn't rely at all on Delphi's IsapiHTTP.pas (or any other Delphi Web.* namespace unit). Any bug in that area doesn't affect IntraWeb applications.

     

    Cheers,


  18. I've just tested his test application (without ICS, but the same issue will definitely happen). There is nothing wrong with IntraWeb.

     

    He's using an Indy-based IntraWeb server. He creates a window handle when his application is receiving an incoming request. The Indy HTTP server spawns a worker thread which is freed afterward. The window handle is released when the thread is destroyed. Then he tries to use the same window handle in a subsequent request, from another thread (there is no guarantee that the original thread which created the window handle hasn't been destroyed).

     

    This is documented here: https://docs.microsoft.com/en-us/windows/win32/procthread/terminating-a-thread

     

    BTW: his example works when using Http.sys-based IntraWeb application (not Indy) because the threads are obtained from a thread pool and recycled, so the windows created in one request will be still valid in a subsequent request (although I don't recommend his way of using it at all).

     

    Quote

    In the IntraWeb forum, they just want to hide a problem they overlooked with IntraWeb and they want you to use their product.

    Given that the application behavior is not only expected but also correct, your statement above is obviously false.

     

    Regards


  19. Quote

    ICS has his own AllocateHWnd method that is thread safe. It make use of a critical section to protect the class registration (GetClassInfo and RegisterClass) and then use CreateWindowEx to create the handle. For those interested, look at TIcsWndHandler.AllocateHWnd in unit OverbyteIcsWndControl.

    I did not mention ICS at all. I'm pointing at his test case application which does not use ICS. This is a standard AllocateHWnd RTL call and it won't work reliably. That's a fact.

     

    Once you mention that you patch AllocateHWnd from ICS code, are you 100% sure that your patch doesn't break anything else that IntraWeb relies on?

     

    Quote

    In the IntraWeb forum, they just want to hide a problem they overlooked with IntraWeb and they want you to use their product.

    After saying yourself that you know nothing about IntraWeb, this kind of statement is at least curious.

     

    Regards


  20. Hi Arthur,

     

    Indeed, IntraWeb DCUs are built with debug info ON. Mainly because the built-in exception logger (Based on Jedi's JCLDebug code) requires the debug information to create an human readable call stack).

     

    Also, not sure how many IW developers add the source code to their build (or add them to the browsing path), but I believe it is a considerable number.

     

    The ideal is to have 2 sets of DCUs but it would just explode the size of the setup. We are trying different approaches with the build script and setup program. I will have more information about it soon.

     

    Unfortunately, Delphi doesn't have any option to filter out some units or paths from debugger. Personally I have other 3rd party libraries for other projects and it is painful to debug certain applications because of this.

     

    Cheers,


  21. Would you mind elaborating why you need it?

    In general it is not possible to effectively minify HTML content unless it contains heaps of comments.

    In that case, simple gzip compression for http(s) transmission is as effective as (if not more, i.e. the cost to compress it using gzip is less compared to the cost of minifying it + compressing it and the benefit is almost the same)

     

    Cheers


  22. 8 hours ago, Lars Fosdal said:

    At what point is the instance pointer reference for the string, interface or dyn.array changed? 

     

    When are field values in instances not aligned (unless overrides have been added)?

     

    https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement

     

    Quote

    Avoid using the same lock object instance for different shared resources, as it might result in deadlock or lock contention.

     

    Contention yes, deadlock, no. Actually it is quite the contrary. Deadlocks only occur because more than one lock is used (or one which can't be called recursively, like Windows' SRWLock objects). This document is *really* wrong.

×