[fpc-devel] How FPC handles dynamic arrays with const modifier?

Maciej Izak hnb.code at gmail.com
Tue Aug 13 14:41:54 CEST 2013


>  I don't see a reason to use hacks for such code.
>
It is hard to explain. You will see it soon in all its glory ;). It's very
important construction (I use this construction very often - generics,
serialization, script languages binding...). A short introduction:

===begin code===
// I need universal non generic method to compare arrays without knowledge
of its TypeInfo...
class function TEquals.DynArray(constref ALeft, ARight: Pointer): Boolean;
var
  _self: TAbstractHashCode.PSpoofInterfacedTypeSizeObject absolute Self; //
few more tricks...
  LLength: Integer;
begin
  LLength := DynArraySize(ALeft);
  if LLength <> DynArraySize(ARight) then
    Exit(False);

  Result := CompareMem(ALeft, ARight, LLength * _self.Size);
end;
===end code===

you wrote earlier in my other topic:

"You can't do things as equality tests in a general way anyway (best
example: case sensitive vs. case insensitive comparison of strings)."

So... I just finished writing something theoretically impossible to write
O_o. Now I do equality tests in a general way (partially because the
construction like in Foo).

To get:

===begin code===
    IEqualityComparer<T> = interface
    function Equals(constref ALeft, ARight: T): Boolean;
    function GetHashCode(constref AValue: T): UInt32; overload;
    function GetHashCode(constref AValue: T; out APrimaryHash: UInt32):
UInt32; overload; // for double hashing
  end;
===end code===

for any type (seriously any type supported by FPC except file type - Error:
File types must be var parameters), just call TEqualityComparer<T>.Default:

===begin code===
var
  ec_array: IEqualityComparer<TIntegerDynArray>;
  ec_string: IEqualityComparer<string>;
begin
  ec_array := TEqualityComparer<TIntegerDynArray>.Default;
  ec_array :=
TEqualityComparer<TIntegerDynArray>.Default(TOptionalNonDefaultHashFactory);

  // case insensitive comparer
  ec_string :=
TEqualityComparer<string>.Construct(MyNonCaseSensitiveComparerMethod);
  // or soon with anonymous methods
  ec_string := TEqualityComparer<string>.Construct(
      function(constref ALeft, ARight: string): Integer);
      begin
        Result := SameText(ALeft, ARight);
      end, TOptionalNonDefaultHashFactory);
===end code===

At this moment you can use dictionary (with any custom IEqualityComparer)
in FPC with any type (used type don't need to implement any additional
operators):

===begin code===
var
  dr: TDictionary<TMyRecord, string>;
  dp: TDictionary<PAnyPointer, Variant>;
  dcr: TDictionary<TClass, TArrayOfObjects>;
  da: TDictionary<TIntegerDynArray, Single>;
  dCaseInsensitive: TDictionary<string, TObject>;
  dCaseSensitive: TDictionary<string, TObject>;
  {... and so on...}
  dCaseInsensitive := TDictionary<string, TObject>(StringC
aseInsensitiveEqualityComparer);
  dCaseSensitive := TDictionary<string, TObject>.Create; // default case
sensitive
===end code===

If you need to use default freepascal operators for comparisons there is
also TFastDictionary - for some optimizations.

Btw. I proposed the creation of the new system functions: GetReferenceToValue
and GetValueSize (I think it's still a good idea). This would simplify some
things...

> I wonder why this combination compiles at all O.o
>
 comfortable for my tricks ^_^

Regards,
HNB
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-devel/attachments/20130813/bd0da09d/attachment.html>


More information about the fpc-devel mailing list