Results 1 to 13 of 13

Thread: inline toch mogelijk maken

  1. #1
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382

    inline toch mogelijk maken

    Om een main unit te ontdoen van gecompliceerde routines (en een te grote unit file), heb ik deze gecompliceerde routines in een andere unit ondergebracht.
    Zie onderstaande structuur.
    Nu wordt echter de FastProc - wanneer aangeroepen vanuit de tweede unit in ComplicatedProc - niet inlined aangeroepen.
    Dat is per definitie een onmogelijkheid in delphi.
    Is er een nette manier toch een inline call voorelkaar te krijgen? Snelheid is in deze van belang.

    Code:
    // main unit
    unit Main;
    
    interface
    
    procedure FastProc; inline;
    
    implementation
    
    uses
      Complicated;
    
    procedure FastProc; // inline;
    begin
      // do something fast
    end;
    
    procedure CallHelpUnit;
    begin
      ComplicatedProc;
    end;
    
    end.
    
    // complicated unit
    unit Complicated;
    
    interface
    
    uses
      Main;
    
    procedure ComplicatedProc;
    
    implementation
    
    procedure ComplicatedProc;
    begin
      for i := 1 to 100000 do
        MyFastProc;
    end;
    
    end.

  2. #2
    Quote Originally Posted by EricLang View Post
    Nu wordt echter de FastProc - wanneer aangeroepen vanuit de tweede unit in ComplicatedProc - niet inlined aangeroepen.
    Dat is per definitie een onmogelijkheid in delphi.
    Hier moest ik even over nadenken want dat vond ik toch heel vreemd.

    Maar het is volgens mij zo dat inline niet werkt als de units circularly dependent zijn.
    Anders zou inlining gewoon moeten werken.

    Dus de oplossing zal zijn om ze niet circularly dependent te maken.

    No inlining will be done between units that are circularly dependent. This included indirect circular dependencies, for example, unit A uses unit B, and unit B uses unit C which in turn uses unit A. In this example, when compiling unit A, no code from unit B or unit C will be inlined in unit A.
    https://www.delphipower.xyz/win32/us...directive.html
    http://docs.embarcadero.com/products...tions_xml.html

    Zorg er dus voor dat je FastProc in een aparte eigen unit staat die verder niet terugverwijst naar andere units.
    Daarvoor moet je dan dus wel die CallHelpUnit (die de main weer aanroept) in een andere unit plaatsen zodat je Complicated uit de uses kunt halen.

  3. #3
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    Helaas. Opsplitsen is onlogisch. Dan maar geen inline :-)

  4. #4
    En is de FastProc dan ook zo gecompliceerd?
    Want dan zou je die toch ook naar 'Complicated' mee kunnen verhuizen?
    Als snelheid echt een issue is zou ik dat zeker doen.

  5. #5
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    ik heb een baseclass die eenvoudige vormen tekent. daarin zit "fastproc" setpixel.
    De complicated unit is bijvoorbeeld een floodfill oid. En om de setpixel of horzline nou te verhuizen omwille van inlining gaat me iets te veel ten koste van logica :-)

  6. #6
    Maar in je eenvoudige baseclass unit heb je dus ook weer een call naar ComplicatedProc.
    Dat zou in principe niet logisch zijn.

    Maar goed... dat is het hele gedoe met het ontwerpen. Soms wordt het zo'n wirwar van calls heen en weer dat het moeilijk is daar weer structuur in te brengen.

    What's wrong with circular references?

    getting around circular references in Delphi

    Als je circular unit references hebt dan vraag ik me sowieso af hoe logisch de hele code in elkaar zit.

    Maar uiteindelijk is het de keuze van de ontwerper.

  7. #7
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    Nee hoor. circular is meestal een tekortkoming van delphi. of je moet alles met interfaces doen.

  8. #8
    Of met delegate classes, of gedeelde base classes in één van de twee units, of in een derde unit.

    Maar goed, ik snap ook niet helemaal waarom je de unit op deze manier zou opsplitsen als er toch een circulaire referentie is. Dat betekent dat je altijd beide units nodig hebt. Het idee van scheiden is dan toch een beetje weg. Waarom kan `CallHelpUnit` niet in Complicated staan? Eventueel, als je het lekker lowlevel wilt houden, zou je CallHelpUnit ook een reference naar proc kunnen maken, en Complicated die reference laten zetten. Dan heb je wel de snelheid van de call, maar toch ook de concrete scheiding.
    1+1=b

  9. #9
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    @Golez inderdaad een idee het proberen waard.
    Het splitsen is om hele lange gecompliceerde routines van een class in een aparte unit te zetten. Maar eigenlijk zijn ze onderdeel van de hoofdclass.

  10. #10
    Of Classhelpers?
    Of inheritence en de korte routines in de baseclass en de complexe in de inherited class zetten.

    Maar met onComplexProc werken kan ook.

    In de links die ik gaf staat dat ook allemaal vermeldt.
    Er zijn ook principe meerdere mogelijkheden om circulaire referentie te omzeilen.

  11. #11
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    Klopt en eerlijk gezegd: circulair vind ik ook niet echt mooi.
    Maar soms vind ik het wel beperkend qua indeling. Bij elkaar horende classes moeten in 1 unit wat niet altijd even leuk of wenselijk is in mijn beleving.
    neem bijv. TControl en TWinControl :-)

    class helper is hier geen optie.
    Ik ga de circulaire dinges eruit halen met een van bovengenoemde alternatieven.

  12. #12
    Als het gaat om teveel tekst in de unit dan kun je ook nog met includes werken.
    Lazarus werkt hier ontzettend veel mee (maar om andere redenen).

    Als de unit zelf te groot wordt qua code/dcu dan heeft dat uiteraard geen effect.

  13. #13
    Reader
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,382
    static class in de main
    Code:
      TComplex = class
      public
        type
          TEllipseProc = procedure(dst: TBmp; x1, y1, x2, y2: integer; const lineColor, fillColor: TPixel; skipBorder: boolean; skipFill: boolean);
          TFloodFillProc = procedure(dst: TBmp; x, y: Integer; aColor: TPixel);
      strict private
        class var EllipseProc: TEllipseProc;
        class var FloodFillProc: TFloodFillProc;
      public
        class procedure RegisterEllipseProc(const proc: TEllipseProc); static;
        class procedure RegisterFloodFillProc(const proc: TFloodFillProc); static;
      public
        class procedure DoEllipse(dst: TBmp; x1, y1, x2, y2: integer; const lineColor, fillColor: TPixel; skipBorder: boolean; skipFill: boolean); static;
        class procedure DoFloodFill(dst: TBmp; x, y: Integer; aColor: TPixel); static;
      end;

    Code:
    { TComplex }
    
    class procedure TComplex.RegisterEllipseProc(const proc: TEllipseProc);
    begin
      EllipseProc := proc;
    end;
    
    class procedure TComplex.RegisterFloodFillProc(const proc: TFloodFillProc);
    begin
      FloodFillProc := proc;
    end;
    
    class procedure TComplex.DoEllipse(dst: TBmp; x1, y1, x2, y2: integer; const lineColor, fillColor: TPixel; skipBorder, skipFill: boolean);
    begin
      if Assigned(EllipseProc) then
        EllipseProc(dst,  x1, y1, x2, y2, lineColor, fillColor, skipBorder, skipFill)
      else begin
        dst.Canvas.Pen.Color := lineColor.AsWinColor;
        dst.Canvas.Ellipse(x1, y1, x2, y2);
      end;
    end;
    
    class procedure TComplex.DoFloodFill(dst: TBmp; x, y: Integer; aColor: TPixel);
    begin
      if Assigned(FloodFillProc) then
        FloodfillProc(dst, x, y, aColor)
      else begin
        dst.Backend.Canvas.Brush.Color := aColor.AsWinColor;
        dst.Backend.Canvas.FloodFill(x, y, aColor.AsWinColor, TFillStyle.fsSurface);
      end;
    end;
    Init vanuit externe unit
    Code:
    initialization
      TComplex.RegisterEllipseProc(TEllipseDrawing.Ellipse);
    De call vanuit main
    Code:
    procedure TBmp.Ellipse(x1, y1, x2, y2: integer; const color: TPixel);
    begin
      TComplex.DoEllipse(Self, x1, y1, x2, y2, color, 0, False, True);
    end;
    misschien zijn interfaces toch soms wel handig en ook een mogelijkheid :-)
    met name de floodfill is 8x sneller dan de canvas versie.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •