Jump to content

David Heffernan

Members
  • Content Count

    3499
  • Joined

  • Last visited

  • Days Won

    174

Posts posted by David Heffernan


  1. 1 hour ago, dormky said:

    I'm looking into this because we have config files that are just memory dumps of records. I need to be able to meaningfully compare and manipulate those files. There is A LOT of them and doing so manually would be hopeless.

    This sounds like a pretty unfortunate design choice. But since your compiler knows the layout of those records you can just work with the record types and the compiler takes care of the layout. 


  2. 2 hours ago, dormky said:

    This is incredibly annoying. It's basically impossible to predict how much space a record is going to take !

    It's actually very easy to predict this, once you know the rules. 

     

    2 hours ago, dormky said:

    Just looking for some insight on the subject, because this makes static analysis incredibly difficult for really no good reason...

    There is a good reason. 

     

    Instead of ranting, maybe you should assume that the people that designed this knew what they were doing and that you just don't understand it. 

     

    The question I have for you, is why are you so interested in size and layout of the records. What is motivating your interest. That might be helpful for us to understand. 


  3. 13 hours ago, Dave Novo said:

    In fact, I also have to write out large matrices of floating point values, so will try to modify the Delphi float conversion routines to work on array of char similar to what you proposed below. 

    I have routines to do that. Because the Delphi code to convert between text and floats is irredeemably broken. I'm using dragon4 for float to text, but these days there are better algorithms around. I use dtoa in the other direction.

     

    13 hours ago, Dave Novo said:

    I wonder if the overhead of writing the file to disk dwarfs the time it takes for the conversions. 

    My code base is spewing out a lot of floats to text files and yes it makes a significant difference to performance. Especially for files on a local drive.


  4. On 12/11/2023 at 3:17 PM, David Heffernan said:

    Is CompressFile CPU bound? Are we supposed to know what is in there? Seems like it would be important? 

    The funny thing here, to my mind, is that I'd have expected that the first thing you did would have been to replace the actual function with a pointless work tasks that span in a loop for a certain period of time. If you then found that the behaviour was the same, i.e. not using all processor resources, you would know that the issue was in the library, or how you were using it. In fact had that been the case you could have come up with a very short example to capture the behaviour. You'd probably then have had an answer in an hour or two.


  5. 13 hours ago, Dave Novo said:

    The one thing that pops to my head is if saving a large number of integers to a file (as strings of course), when you can write to the file directly from the char buffer allocated on the stack.

    Yes, this is it. It's a very important use case though. Imagine writing large YAML or JSON files containing a lot of data. And then imagine trying to do the same with multiple threads with extra contention on a memory manager.

     

    The point is that you build IntToStr using a function like mine above. And publish both. This allows the consumer of the library to have both options. Even if avoiding heap allocation is something that is only done in a narrow set of circumstances, that doesn't render it unnecessary.

    • Thanks 1

  6. 57 minutes ago, #ifdef said:

    It's free - because it's useless (because it's outdated) 😒

    I guess all the software that I've released in recent times didn't happen because I was using a useless tool. 

    • Like 1

  7. 31 minutes ago, corneliusdavid said:

    So you want 4 random values, one each in the ranges 1-250, 251-500, 501-750, and 751-1000, right:


    Try this:

    
    value1 := random(250) + 1;
    value2 := random(250) + 250;
    value3 := random(250) + 500;
    value4 := random(250) + 750;

    Each random number is restricted to a 250 range but adding a number to it puts it into different range brackets.

    value2, value3, value 4 all have an off by one error. 

    • Like 1

  8. From my codebase:

    // disable range checks and overflow checks so that Abs() functions in case Value = Low(Value)
    {$R-}
    {$Q-}
    function CopyIntegerToAnsiBuffer(const Value: Integer; var Buffer: array of AnsiChar): Integer;
    var
      i, j: Integer;
      val, remainder: Cardinal;
      negative: Boolean;
      tmp: array [0..15] of AnsiChar;
    begin
      negative := Value<0;
      val := Abs(Value);
      Result := 0;
      repeat
        DivMod(val, 10, val, remainder);
        tmp[Result] := AnsiChar(remainder + Ord('0'));
        Inc(Result);
      until val=0;
      if negative then begin
        tmp[Result] := '-';
        Inc(Result);
      end;
      Assert(Result<=Length(Buffer));
    
      i := 0;
      j := Result-1;
      while i<Result do begin
        Buffer[i] := tmp[j];
        Inc(i);
        Dec(j);
      end;
    end;
    
    function CopyIntegerToWideBuffer(const Value: Integer; var Buffer: array of WideChar): Integer;
    var
      i, j: Integer;
      val, remainder: Cardinal;
      negative: Boolean;
      tmp: array [0..15] of WideChar;
    begin
      negative := Value<0;
      val := Abs(Value);
      Result := 0;
      repeat
        DivMod(val, 10, val, remainder);
        tmp[Result] := WideChar(remainder + Ord('0'));
        Inc(Result);
      until val=0;
      if negative then begin
        tmp[Result] := '-';
        Inc(Result);
      end;
      Assert(Result<=Length(Buffer));
    
      i := 0;
      j := Result-1;
      while i<Result do begin
        Buffer[i] := tmp[j];
        Inc(i);
        Dec(j);
      end;
    end;
    
    function CopyInt64ToAnsiBuffer(const Value: Int64; var Buffer: array of AnsiChar): Integer;
    var
      i, j: Integer;
      val, remainder: UInt64;
      negative: Boolean;
      tmp: array [0..23] of AnsiChar;
    begin
      negative := Value<0;
      val := Abs(Value);
      Result := 0;
      repeat
        DivMod(val, 10, val, remainder);
        tmp[Result] := AnsiChar(remainder + Ord('0'));
        Inc(Result);
      until val=0;
      if negative then begin
        tmp[Result] := '-';
        Inc(Result);
      end;
      Assert(Result<=Length(Buffer));
    
      i := 0;
      j := Result-1;
      while i<Result do begin
        Buffer[i] := tmp[j];
        Inc(i);
        Dec(j);
      end;
    end;
    
    function CopyInt64ToWideBuffer(const Value: Int64; var Buffer: array of WideChar): Integer;
    var
      i, j: Integer;
      val, remainder: UInt64;
      negative: Boolean;
      tmp: array [0..23] of WideChar;
    begin
      negative := Value<0;
      val := Abs(Value);
      Result := 0;
      repeat
        DivMod(val, 10, val, remainder);
        tmp[Result] := WideChar(remainder + Ord('0'));
        Inc(Result);
      until val=0;
      if negative then begin
        tmp[Result] := '-';
        Inc(Result);
      end;
      Assert(Result<=Length(Buffer));
    
      i := 0;
      j := Result-1;
      while i<Result do begin
        Buffer[i] := tmp[j];
        Inc(i);
        Dec(j);
      end;
    end;
    {$IFDEF RANGECHECKSON}{$R+}{$ENDIF}
    {$IFDEF OVERFLOWCHECKSON}{$Q+}{$ENDIF}

    No heap allocation. I guess I could avoid that DivMod now and do something better.

     

    The main point is that a good runtime library should have building block functions like this that allow us to perform such conversions without forcing heap allocation. 

     

    The RTL should have functionality like this on top of which all conversion functions can be built. Then the RTL function can be optimised and everyone benefits. 

    • Like 5
    • Thanks 1

  9. 59 minutes ago, DelphiUdIT said:

    Mantra "But it compiles to native code!" is a must for my business, may be only for me but that's enough.

    I have customers with dozens of machines (industrial lines) who are tired of hearing about frameworks that must be constantly updated,

    So it's just an issue of deployment. Fair enough. I guess there's a bit of complexity in deploying applications well. 

×