THRIFT-4318 Delphi performance improvements
Client: Delphi
Patch: Jens Geyer

This closes #1348
diff --git a/lib/delphi/src/Thrift.Protocol.Compact.pas b/lib/delphi/src/Thrift.Protocol.Compact.pas
index e9944d6..5b1253a 100644
--- a/lib/delphi/src/Thrift.Protocol.Compact.pas
+++ b/lib/delphi/src/Thrift.Protocol.Compact.pas
@@ -123,7 +123,7 @@
 
     // If we encounter a boolean field begin, save the TField here so it can
     // have the value incorporated.
-    private booleanField_ : IField;
+    private booleanField_ : TThriftField;
 
     // If we Read a field header, and it's a boolean field, save the boolean
     // value here so that ReadBool can use it.
@@ -148,21 +148,21 @@
   private
     // The workhorse of WriteFieldBegin. It has the option of doing a 'type override'
     // of the type header. This is used specifically in the boolean field case.
-    procedure WriteFieldBeginInternal( const field : IField; typeOverride : Byte);
+    procedure WriteFieldBeginInternal( const field : TThriftField; typeOverride : Byte);
 
   public
-    procedure WriteMessageBegin( const msg: IMessage); override;
+    procedure WriteMessageBegin( const msg: TThriftMessage); override;
     procedure WriteMessageEnd; override;
-    procedure WriteStructBegin( const struc: IStruct); override;
+    procedure WriteStructBegin( const struc: TThriftStruct); override;
     procedure WriteStructEnd; override;
-    procedure WriteFieldBegin( const field: IField); override;
+    procedure WriteFieldBegin( const field: TThriftField); override;
     procedure WriteFieldEnd; override;
     procedure WriteFieldStop; override;
-    procedure WriteMapBegin( const map: IMap); override;
+    procedure WriteMapBegin( const map: TThriftMap); override;
     procedure WriteMapEnd; override;
-    procedure WriteListBegin( const list: IList); override;
+    procedure WriteListBegin( const list: TThriftList); override;
     procedure WriteListEnd(); override;
-    procedure WriteSetBegin( const set_: ISet ); override;
+    procedure WriteSetBegin( const set_: TThriftSet ); override;
     procedure WriteSetEnd(); override;
     procedure WriteBool( b: Boolean); override;
     procedure WriteByte( b: ShortInt); override;
@@ -194,17 +194,17 @@
     class procedure fixedLongToBytes( const n : Int64; var buf : TBytes);
 
   public
-    function  ReadMessageBegin: IMessage; override;
+    function  ReadMessageBegin: TThriftMessage; override;
     procedure ReadMessageEnd(); override;
-    function  ReadStructBegin: IStruct; override;
+    function  ReadStructBegin: TThriftStruct; override;
     procedure ReadStructEnd; override;
-    function  ReadFieldBegin: IField; override;
+    function  ReadFieldBegin: TThriftField; override;
     procedure ReadFieldEnd(); override;
-    function  ReadMapBegin: IMap; override;
+    function  ReadMapBegin: TThriftMap; override;
     procedure ReadMapEnd(); override;
-    function  ReadListBegin: IList; override;
+    function  ReadListBegin: TThriftList; override;
     procedure ReadListEnd(); override;
-    function  ReadSetBegin: ISet; override;
+    function  ReadSetBegin: TThriftSet; override;
     procedure ReadSetEnd(); override;
     function  ReadBool: Boolean; override;
     function  ReadByte: ShortInt; override;
@@ -273,7 +273,7 @@
   lastFieldId_ := 0;
   lastField_ := TStack<Integer>.Create;
 
-  booleanField_ := nil;
+  Init( booleanField_, '', TType.Stop, 0);
   boolValue_ := unused;
 end;
 
@@ -293,7 +293,7 @@
 begin
   lastField_.Clear();
   lastFieldId_ := 0;
-  booleanField_ := nil;
+  Init( booleanField_, '', TType.Stop, 0);
   boolValue_ := unused;
 end;
 
@@ -301,11 +301,8 @@
 // Writes a byte without any possibility of all that field header nonsense.
 // Used internally by other writing methods that know they need to Write a byte.
 procedure TCompactProtocolImpl.WriteByteDirect( const b : Byte);
-var data : TBytes;
 begin
-  SetLength( data, 1);
-  data[0] := b;
-  Transport.Write( data);
+  Transport.Write( @b, SizeOf(b));
 end;
 
 
@@ -344,7 +341,7 @@
 
 // Write a message header to the wire. Compact Protocol messages contain the
 // protocol version so we can migrate forwards in the future if need be.
-procedure TCompactProtocolImpl.WriteMessageBegin( const msg: IMessage);
+procedure TCompactProtocolImpl.WriteMessageBegin( const msg: TThriftMessage);
 var versionAndType : Byte;
 begin
   Reset;
@@ -362,7 +359,7 @@
 // Write a struct begin. This doesn't actually put anything on the wire. We use it as an
 // opportunity to put special placeholder markers on the field stack so we can get the
 // field id deltas correct.
-procedure TCompactProtocolImpl.WriteStructBegin( const struc: IStruct);
+procedure TCompactProtocolImpl.WriteStructBegin( const struc: TThriftStruct);
 begin
   lastField_.Push(lastFieldId_);
   lastFieldId_ := 0;
@@ -380,7 +377,7 @@
 // Write a field header containing the field id and field type. If the difference between the
 // current field id and the last one is small (< 15), then the field id will be encoded in
 // the 4 MSB as a delta. Otherwise, the field id will follow the type header as a zigzag varint.
-procedure TCompactProtocolImpl.WriteFieldBegin( const field: IField);
+procedure TCompactProtocolImpl.WriteFieldBegin( const field: TThriftField);
 begin
   case field.Type_ of
     TType.Bool_ : booleanField_ := field; // we want to possibly include the value, so we'll wait.
@@ -392,7 +389,7 @@
 
 // The workhorse of WriteFieldBegin. It has the option of doing a 'type override'
 // of the type header. This is used specifically in the boolean field case.
-procedure TCompactProtocolImpl.WriteFieldBeginInternal( const field : IField; typeOverride : Byte);
+procedure TCompactProtocolImpl.WriteFieldBeginInternal( const field : TThriftField; typeOverride : Byte);
 var typeToWrite : Byte;
 begin
   // if there's a type override, use that.
@@ -425,7 +422,7 @@
 
 // Write a map header. If the map is empty, omit the key and value type
 // headers, as we don't need any additional information to skip it.
-procedure TCompactProtocolImpl.WriteMapBegin( const map: IMap);
+procedure TCompactProtocolImpl.WriteMapBegin( const map: TThriftMap);
 var key, val : Byte;
 begin
   if (map.Count = 0)
@@ -440,14 +437,14 @@
 
 
 // Write a list header.
-procedure TCompactProtocolImpl.WriteListBegin( const list: IList);
+procedure TCompactProtocolImpl.WriteListBegin( const list: TThriftList);
 begin
   WriteCollectionBegin( list.ElementType, list.Count);
 end;
 
 
 // Write a set header.
-procedure TCompactProtocolImpl.WriteSetBegin( const set_: ISet );
+procedure TCompactProtocolImpl.WriteSetBegin( const set_: TThriftSet );
 begin
   WriteCollectionBegin( set_.ElementType, set_.Count);
 end;
@@ -464,10 +461,10 @@
   then bt := Types.BOOLEAN_TRUE
   else bt := Types.BOOLEAN_FALSE;
 
-  if booleanField_ <> nil then begin
+  if booleanField_.Type_ = TType.Bool_ then begin
     // we haven't written the field header yet
     WriteFieldBeginInternal( booleanField_, Byte(bt));
-    booleanField_ := nil;
+    booleanField_.Type_ := TType.Stop;
   end
   else begin
     // we're not part of a field, so just Write the value.
@@ -642,7 +639,7 @@
 
 
 // Read a message header.
-function TCompactProtocolImpl.ReadMessageBegin : IMessage;
+function TCompactProtocolImpl.ReadMessageBegin : TThriftMessage;
 var protocolId, versionAndType, version, type_ : Byte;
     seqid : Integer;
     msgNm : String;
@@ -663,17 +660,17 @@
   type_ := Byte( (versionAndType shr TYPE_SHIFT_AMOUNT) and TYPE_BITS);
   seqid := Integer( ReadVarint32);
   msgNm := ReadString;
-  result := TMessageImpl.Create( msgNm, TMessageType(type_), seqid);
+  Init( result, msgNm, TMessageType(type_), seqid);
 end;
 
 
 // Read a struct begin. There's nothing on the wire for this, but it is our
 // opportunity to push a new struct begin marker onto the field stack.
-function TCompactProtocolImpl.ReadStructBegin: IStruct;
+function TCompactProtocolImpl.ReadStructBegin: TThriftStruct;
 begin
   lastField_.Push( lastFieldId_);
   lastFieldId_ := 0;
-  result := TStructImpl.Create('');
+  Init( result);
 end;
 
 
@@ -687,7 +684,7 @@
 
 
 // Read a field header off the wire.
-function TCompactProtocolImpl.ReadFieldBegin: IField;
+function TCompactProtocolImpl.ReadFieldBegin: TThriftField;
 var type_ : Byte;
     fieldId, modifier : ShortInt;
 begin
@@ -695,7 +692,7 @@
 
   // if it's a stop, then we can return immediately, as the struct is over.
   if type_ = Byte(Types.STOP) then begin
-    result := TFieldImpl.Create( '', TType.Stop, 0);
+    Init( result, '', TType.Stop, 0);
     Exit;
   end;
 
@@ -705,7 +702,7 @@
   then fieldId := ReadI16    // not a delta. look ahead for the zigzag varint field id.
   else fieldId := ShortInt( lastFieldId_ + modifier); // add the delta to the last Read field id.
 
-  result := TFieldImpl.Create( '', getTType(Byte(type_ and $0F)), fieldId);
+  Init( result, '', getTType(Byte(type_ and $0F)), fieldId);
 
   // if this happens to be a boolean field, the value is encoded in the type
    // save the boolean value in a special instance variable.
@@ -723,7 +720,7 @@
 // Read a map header off the wire. If the size is zero, skip Reading the key
 // and value type. This means that 0-length maps will yield TMaps without the
 // "correct" types.
-function TCompactProtocolImpl.ReadMapBegin: IMap;
+function TCompactProtocolImpl.ReadMapBegin: TThriftMap;
 var size : Integer;
     keyAndValueType : Byte;
     key, val : TType;
@@ -735,7 +732,7 @@
 
   key := getTType( Byte( keyAndValueType shr 4));
   val := getTType( Byte( keyAndValueType and $F));
-  result := TMapImpl.Create( key, val, size);
+  Init( result, key, val, size);
   ASSERT( (result.KeyType = key) and (result.ValueType = val));
 end;
 
@@ -744,7 +741,7 @@
 // be packed into the element type header. If it's a longer list, the 4 MSB
 // of the element type header will be $F, and a varint will follow with the
 // true size.
-function TCompactProtocolImpl.ReadListBegin: IList;
+function TCompactProtocolImpl.ReadListBegin: TThriftList;
 var size_and_type : Byte;
     size : Integer;
     type_ : TType;
@@ -756,7 +753,7 @@
   then size := Integer( ReadVarint32);
 
   type_ := getTType( size_and_type);
-  result := TListImpl.Create( type_, size);
+  Init( result, type_, size);
 end;
 
 
@@ -764,7 +761,7 @@
 // be packed into the element type header. If it's a longer set, the 4 MSB
 // of the element type header will be $F, and a varint will follow with the
 // true size.
-function TCompactProtocolImpl.ReadSetBegin: ISet;
+function TCompactProtocolImpl.ReadSetBegin: TThriftSet;
 var size_and_type : Byte;
     size : Integer;
     type_ : TType;
@@ -776,7 +773,7 @@
   then size := Integer( ReadVarint32);
 
   type_ := getTType( size_and_type);
-  result := TSetImpl.Create( type_, size);
+  Init( result, type_, size);
 end;
 
 
@@ -797,11 +794,8 @@
 
 // Read a single byte off the wire. Nothing interesting here.
 function TCompactProtocolImpl.ReadByte: ShortInt;
-var data : TBytes;
 begin
-  SetLength( data, 1);
-  Transport.ReadAll( data, 0, 1);
-  result := ShortInt(data[0]);
+  Transport.ReadAll( @result, SizeOf(result), 0, 1);
 end;