View Issue Details

IDProjectCategoryView StatusLast Update
0036146FPCRTLpublic2019-11-09 16:36
ReporterThaddy de KoningAssigned ToMichael Van Canneyt 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
PlatformallOSallOS Versionall
Product Version3.3.1Product Build43151 
Target VersionFixed in Version3.3.1 
Summary0036146: PATCH extended ordinal helpers for bit patterns
DescriptionAdded for all ordinals for which there is a type helper:
Proper range for all sizes.

- String representation as bit string
  ToBinString
- Set a bit
  SetBit(const Index: proper_range);
-Clear a bit
  ClearBit(const Index: proper_range);
-Toggle a bit
 ToggleBit(const Index: proper_range);
- Test if a bit is set
  TestBit(const Index: proper_range);
Additional InformationI had this laying around for some time and I finally am satisfied that it actually adds something for other users too.
Playing with hardware can be dangerous for old men like me...

The patch is straightforward, but if tests are required I will add them. Just point me to where I should add them
TagsNo tags attached.
Fixed in Revision43417
FPCOldBugId
FPCTarget3.2.0
Attached Files
  • sysordinalbitshelpers.patch (11,823 bytes)
    Index: rtl/objpas/sysutils/syshelp.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelp.inc	(revision 43151)
    +++ rtl/objpas/sysutils/syshelp.inc	(working copy)
    @@ -1550,6 +1550,7 @@
     
     {$define TORDINALHELPER:=TByteHelper}
     {$define TORDINALTYPE:=Byte}
    +{$define TORDINALBITINDEX:=TByteBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1558,6 +1559,7 @@
     
     {$define TORDINALHELPER:=TShortIntHelper}
     {$define TORDINALTYPE:=ShortInt}
    +{$define TORDINALBITINDEX:=TShortIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1566,6 +1568,7 @@
     
     {$define TORDINALHELPER:=TSmallIntHelper}
     {$define TORDINALTYPE:=SmallInt}
    +{$define TORDINALBITINDEX:=TSmallIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1574,6 +1577,7 @@
     
     {$define TORDINALHELPER:=TWordHelper}
     {$define TORDINALTYPE:=Word}
    +{$define TORDINALBITINDEX:=TWordBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1582,6 +1586,7 @@
     
     {$define TORDINALHELPER:=TCardinalHelper}
     {$define TORDINALTYPE:=Cardinal}
    +{$define TORDINALBITINDEX:=TCardinalBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1590,6 +1595,7 @@
     
     {$define TORDINALHELPER:=TIntegerHelper}
     {$define TORDINALTYPE:=Integer}
    +{$define TORDINALBITINDEX:=TIntegerBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1598,6 +1604,7 @@
     
     {$define TORDINALHELPER:=TInt64Helper}
     {$define TORDINALTYPE:=Int64}
    +{$define TORDINALBITINDEX:=TInt64BitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1606,6 +1613,7 @@
     
     {$define TORDINALHELPER:=TQWordHelper}
     {$define TORDINALTYPE:=QWord}
    +{$define TORDINALBITINDEX:=TQwordBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1614,6 +1622,7 @@
     
     {$define TORDINALHELPER:=TNativeIntHelper}
     {$define TORDINALTYPE:=NativeInt}
    +{$define TORDINALBITINDEX:=TNativeIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1622,6 +1631,7 @@
     
     {$define TORDINALHELPER:=TNativeUIntHelper}
     {$define TORDINALTYPE:=NativeUInt}
    +{$define TORDINALBITINDEX:=TNativeUIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    Index: rtl/objpas/sysutils/syshelph.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelph.inc	(revision 43151)
    +++ rtl/objpas/sysutils/syshelph.inc	(working copy)
    @@ -5,7 +5,18 @@
       TStringArray = Array of string;
       TCharArray = Array of char;
       TEndian = ObjPas.TEndian;
    +  TByteBitIndex = 0..Pred(SizeOf(Byte));
    +  TShortIntBitIndex = TByteBitIndex;
    +  TWordBitIndex = 0..SizeOf(Word)-1;
    +  TSmallIntBitIndex = TWordBitIndex;
    +  TCardinalBitIndex = 0..Pred(SizeOf(Cardinal));
    +  TIntegerBitIndex = TCardinalBitIndex;
    +  TNativeUIntBitIndex = 0.. Pred(SizeOf(NativeUint));
    +  TNativeIntBitIndex = TNativeUintBitIndex;
    +  TQwordBitIndex = 0..Pred(SizeOf(Qword));
    +  TInt64BitIndex = TQwordBitIndex;
       
    +  
     Const
       CPUEndian = {$IFDEF FPC_LITTLE_ENDIAN}TEndian.Little{$ELSE}TEndian.Big{$ENDIF};
     
    @@ -373,10 +384,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TByteBitIndex); inline;
    +    Procedure ClearBit(const Index: TByteBitIndex); inline;
    +    Procedure ToggleBit(const Index: TByteBitIndex); inline;
    +    Function TestBit(const Index:TByteBitIndex):Boolean; inline;
       end;
     
       TShortIntHelper = Type Helper for ShortInt
    @@ -393,10 +409,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TShortIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TShortIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TShortIntBitIndex); inline;
    +    Function TestBit(const Index:TShortIntBitIndex):Boolean;
       end;
     
       TSmallIntHelper = Type Helper for SmallInt
    @@ -412,11 +433,16 @@
       public
         Function ToString: string; overload; inline;
         Function ToBoolean: Boolean; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString: string; overload; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Procedure SetBit(const Index: TSmallIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TSmallIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TSmallIntBitIndex); inline;
    +    Function TestBit(const Index:TSmallIntBitIndex):Boolean;    
       end;
     
       TWordHelper = Type Helper for Word
    @@ -433,10 +459,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TWordBitIndex); inline;
    +    Procedure ClearBit(const Index: TWordBitIndex); inline;
    +    Procedure ToggleBit(const Index: TWordBitIndex); inline;
    +    Function TestBit(const Index:TWordBitIndex):Boolean; inline;    
       end;
     
       TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
    @@ -453,10 +484,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TCardinalBitIndex); inline;
    +    Procedure ClearBit(const Index: TCardinalBitIndex); inline;
    +    Procedure ToggleBit(const Index: TCardinalBitIndex); inline;
    +    Function TestBit(const Index:TCardinalBitIndex):Boolean; inline;   
       end;
     
       TIntegerHelper = Type Helper for Integer { for LongInt Type too }
    @@ -473,10 +509,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TIntegerBitIndex); inline;
    +    Procedure ClearBit(const Index: TIntegerBitIndex); inline;
    +    Procedure ToggleBit(const Index: TIntegerBitIndex); inline;
    +    Function TestBit(const Index:TIntegerBitIndex):Boolean; inline;   
       end;
     
       TInt64Helper = Type Helper for Int64
    @@ -493,10 +534,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TInt64BitIndex); inline;
    +    Procedure ClearBit(const Index: TInt64BitIndex); inline;
    +    Procedure ToggleBit(const Index: TInt64BitIndex); inline;
    +    Function TestBit(const Index:TInt64BitIndex):Boolean; inline; 
       end;
     
       TQWordHelper = Type Helper for QWord
    @@ -513,10 +559,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TQwordBitIndex); inline;
    +    Procedure ClearBit(const Index: TQwordBitIndex); inline;
    +    Procedure ToggleBit(const Index: TQwordBitIndex); inline;
    +    Function TestBit(const Index:TQwordBitIndex):Boolean; inline; 
       end;
     
       TNativeIntHelper = Type Helper for NativeInt
    @@ -533,10 +584,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TNativeIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TNativeIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TNativeIntBitIndex); inline;
    +    Function TestBit(const Index:TNativeIntBitIndex):Boolean; inline; 
       end;
     
       TNativeUIntHelper = Type Helper for NativeUInt
    @@ -553,10 +609,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TNativeUIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TNativeUIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TNativeUIntBitIndex); inline;
    +    Function TestBit(const Index:TNativeUIntBitIndex):Boolean; inline; 
       end;
     
       {$SCOPEDENUMS ON}
    Index: rtl/objpas/sysutils/syshelpo.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelpo.inc	(revision 43151)
    +++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
    @@ -45,6 +45,12 @@
       Result:=Self;
     end;
     
    +Function TORDINALHELPER.ToBinString: string; inline;
    +
    +begin
    +  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
    +end;
    +
     Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
     overload; inline;
     
    @@ -69,3 +75,27 @@
     begin
       Result:=IntToStr(Self);
     end;
    +
    +Procedure TORDINALHELPER.SetBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self := Self or (TORDINALTYPE(1) << index);
    +end;
    +
    +Procedure TORDINALHELPER.ClearBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self:=Self and not (1 << index);
    +end;
    +
    +Procedure TORDINALHELPER.ToggleBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self := Self xor (1 << index);
    +end;
    +
    +Function TORDINALHELPER.TestBit(const Index: TORDINALBITINDEX):Boolean; inline;
    +
    +begin
    +  Result := Boolean(Self and (TORDINALTYPE(1) << index));
    +end;
    
  • sysordinalbitshelpers_corrected.patch (11,851 bytes)
    Index: rtl/objpas/sysutils/syshelp.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelp.inc	(revision 43151)
    +++ rtl/objpas/sysutils/syshelp.inc	(working copy)
    @@ -1550,6 +1550,7 @@
     
     {$define TORDINALHELPER:=TByteHelper}
     {$define TORDINALTYPE:=Byte}
    +{$define TORDINALBITINDEX:=TByteBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1558,6 +1559,7 @@
     
     {$define TORDINALHELPER:=TShortIntHelper}
     {$define TORDINALTYPE:=ShortInt}
    +{$define TORDINALBITINDEX:=TShortIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1566,6 +1568,7 @@
     
     {$define TORDINALHELPER:=TSmallIntHelper}
     {$define TORDINALTYPE:=SmallInt}
    +{$define TORDINALBITINDEX:=TSmallIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1574,6 +1577,7 @@
     
     {$define TORDINALHELPER:=TWordHelper}
     {$define TORDINALTYPE:=Word}
    +{$define TORDINALBITINDEX:=TWordBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1582,6 +1586,7 @@
     
     {$define TORDINALHELPER:=TCardinalHelper}
     {$define TORDINALTYPE:=Cardinal}
    +{$define TORDINALBITINDEX:=TCardinalBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1590,6 +1595,7 @@
     
     {$define TORDINALHELPER:=TIntegerHelper}
     {$define TORDINALTYPE:=Integer}
    +{$define TORDINALBITINDEX:=TIntegerBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1598,6 +1604,7 @@
     
     {$define TORDINALHELPER:=TInt64Helper}
     {$define TORDINALTYPE:=Int64}
    +{$define TORDINALBITINDEX:=TInt64BitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1606,6 +1613,7 @@
     
     {$define TORDINALHELPER:=TQWordHelper}
     {$define TORDINALTYPE:=QWord}
    +{$define TORDINALBITINDEX:=TQwordBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1614,6 +1622,7 @@
     
     {$define TORDINALHELPER:=TNativeIntHelper}
     {$define TORDINALTYPE:=NativeInt}
    +{$define TORDINALBITINDEX:=TNativeIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1622,6 +1631,7 @@
     
     {$define TORDINALHELPER:=TNativeUIntHelper}
     {$define TORDINALTYPE:=NativeUInt}
    +{$define TORDINALBITINDEX:=TNativeUIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    Index: rtl/objpas/sysutils/syshelph.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelph.inc	(revision 43151)
    +++ rtl/objpas/sysutils/syshelph.inc	(working copy)
    @@ -5,7 +5,18 @@
       TStringArray = Array of string;
       TCharArray = Array of char;
       TEndian = ObjPas.TEndian;
    +  TByteBitIndex = 0..Pred(SizeOf(Byte));
    +  TShortIntBitIndex = TByteBitIndex;
    +  TWordBitIndex = 0..SizeOf(Word)-1;
    +  TSmallIntBitIndex = TWordBitIndex;
    +  TCardinalBitIndex = 0..Pred(SizeOf(Cardinal));
    +  TIntegerBitIndex = TCardinalBitIndex;
    +  TNativeUIntBitIndex = 0.. Pred(SizeOf(NativeUint));
    +  TNativeIntBitIndex = TNativeUintBitIndex;
    +  TQwordBitIndex = 0..Pred(SizeOf(Qword));
    +  TInt64BitIndex = TQwordBitIndex;
       
    +  
     Const
       CPUEndian = {$IFDEF FPC_LITTLE_ENDIAN}TEndian.Little{$ELSE}TEndian.Big{$ENDIF};
     
    @@ -373,10 +384,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TByteBitIndex); inline;
    +    Procedure ClearBit(const Index: TByteBitIndex); inline;
    +    Procedure ToggleBit(const Index: TByteBitIndex); inline;
    +    Function TestBit(const Index:TByteBitIndex):Boolean; inline;
       end;
     
       TShortIntHelper = Type Helper for ShortInt
    @@ -393,10 +409,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TShortIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TShortIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TShortIntBitIndex); inline;
    +    Function TestBit(const Index:TShortIntBitIndex):Boolean;
       end;
     
       TSmallIntHelper = Type Helper for SmallInt
    @@ -412,11 +433,16 @@
       public
         Function ToString: string; overload; inline;
         Function ToBoolean: Boolean; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString: string; overload; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Procedure SetBit(const Index: TSmallIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TSmallIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TSmallIntBitIndex); inline;
    +    Function TestBit(const Index:TSmallIntBitIndex):Boolean;    
       end;
     
       TWordHelper = Type Helper for Word
    @@ -433,10 +459,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TWordBitIndex); inline;
    +    Procedure ClearBit(const Index: TWordBitIndex); inline;
    +    Procedure ToggleBit(const Index: TWordBitIndex); inline;
    +    Function TestBit(const Index:TWordBitIndex):Boolean; inline;    
       end;
     
       TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
    @@ -453,10 +484,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TCardinalBitIndex); inline;
    +    Procedure ClearBit(const Index: TCardinalBitIndex); inline;
    +    Procedure ToggleBit(const Index: TCardinalBitIndex); inline;
    +    Function TestBit(const Index:TCardinalBitIndex):Boolean; inline;   
       end;
     
       TIntegerHelper = Type Helper for Integer { for LongInt Type too }
    @@ -473,10 +509,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TIntegerBitIndex); inline;
    +    Procedure ClearBit(const Index: TIntegerBitIndex); inline;
    +    Procedure ToggleBit(const Index: TIntegerBitIndex); inline;
    +    Function TestBit(const Index:TIntegerBitIndex):Boolean; inline;   
       end;
     
       TInt64Helper = Type Helper for Int64
    @@ -493,10 +534,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TInt64BitIndex); inline;
    +    Procedure ClearBit(const Index: TInt64BitIndex); inline;
    +    Procedure ToggleBit(const Index: TInt64BitIndex); inline;
    +    Function TestBit(const Index:TInt64BitIndex):Boolean; inline; 
       end;
     
       TQWordHelper = Type Helper for QWord
    @@ -513,10 +559,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TQwordBitIndex); inline;
    +    Procedure ClearBit(const Index: TQwordBitIndex); inline;
    +    Procedure ToggleBit(const Index: TQwordBitIndex); inline;
    +    Function TestBit(const Index:TQwordBitIndex):Boolean; inline; 
       end;
     
       TNativeIntHelper = Type Helper for NativeInt
    @@ -533,10 +584,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TNativeIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TNativeIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TNativeIntBitIndex); inline;
    +    Function TestBit(const Index:TNativeIntBitIndex):Boolean; inline; 
       end;
     
       TNativeUIntHelper = Type Helper for NativeUInt
    @@ -553,10 +609,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TNativeUIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TNativeUIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TNativeUIntBitIndex); inline;
    +    Function TestBit(const Index:TNativeUIntBitIndex):Boolean; inline; 
       end;
     
       {$SCOPEDENUMS ON}
    Index: rtl/objpas/sysutils/syshelpo.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelpo.inc	(revision 43151)
    +++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
    @@ -45,6 +45,12 @@
       Result:=Self;
     end;
     
    +Function TORDINALHELPER.ToBinString: string; inline;
    +
    +begin
    +  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
    +end;
    +
     Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
     overload; inline;
     
    @@ -69,3 +75,27 @@
     begin
       Result:=IntToStr(Self);
     end;
    +
    +Procedure TORDINALHELPER.SetBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self := Self or (TORDINALTYPE(1) << index);
    +end;
    +
    +Procedure TORDINALHELPER.ClearBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self:=Self and not (TORDINALTYPE(1) << index);
    +end;
    +
    +Procedure TORDINALHELPER.ToggleBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self := Self xor (TORDINALTYPE(1) << index);
    +end;
    +
    +Function TORDINALHELPER.TestBit(const Index: TORDINALBITINDEX):Boolean; inline;
    +
    +begin
    +  Result := Boolean(Self and (TORDINALTYPE(1) << index));
    +end;
    
  • sysordinalbitshelpers3.patch (11,847 bytes)
    Index: rtl/objpas/sysutils/syshelp.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelp.inc	(revision 43151)
    +++ rtl/objpas/sysutils/syshelp.inc	(working copy)
    @@ -1550,6 +1550,7 @@
     
     {$define TORDINALHELPER:=TByteHelper}
     {$define TORDINALTYPE:=Byte}
    +{$define TORDINALBITINDEX:=TByteBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1558,6 +1559,7 @@
     
     {$define TORDINALHELPER:=TShortIntHelper}
     {$define TORDINALTYPE:=ShortInt}
    +{$define TORDINALBITINDEX:=TShortIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1566,6 +1568,7 @@
     
     {$define TORDINALHELPER:=TSmallIntHelper}
     {$define TORDINALTYPE:=SmallInt}
    +{$define TORDINALBITINDEX:=TSmallIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1574,6 +1577,7 @@
     
     {$define TORDINALHELPER:=TWordHelper}
     {$define TORDINALTYPE:=Word}
    +{$define TORDINALBITINDEX:=TWordBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1582,6 +1586,7 @@
     
     {$define TORDINALHELPER:=TCardinalHelper}
     {$define TORDINALTYPE:=Cardinal}
    +{$define TORDINALBITINDEX:=TCardinalBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1590,6 +1595,7 @@
     
     {$define TORDINALHELPER:=TIntegerHelper}
     {$define TORDINALTYPE:=Integer}
    +{$define TORDINALBITINDEX:=TIntegerBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1598,6 +1604,7 @@
     
     {$define TORDINALHELPER:=TInt64Helper}
     {$define TORDINALTYPE:=Int64}
    +{$define TORDINALBITINDEX:=TInt64BitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1606,6 +1613,7 @@
     
     {$define TORDINALHELPER:=TQWordHelper}
     {$define TORDINALTYPE:=QWord}
    +{$define TORDINALBITINDEX:=TQwordBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1614,6 +1622,7 @@
     
     {$define TORDINALHELPER:=TNativeIntHelper}
     {$define TORDINALTYPE:=NativeInt}
    +{$define TORDINALBITINDEX:=TNativeIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1622,6 +1631,7 @@
     
     {$define TORDINALHELPER:=TNativeUIntHelper}
     {$define TORDINALTYPE:=NativeUInt}
    +{$define TORDINALBITINDEX:=TNativeUIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    Index: rtl/objpas/sysutils/syshelph.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelph.inc	(revision 43151)
    +++ rtl/objpas/sysutils/syshelph.inc	(working copy)
    @@ -5,7 +5,18 @@
       TStringArray = Array of string;
       TCharArray = Array of char;
       TEndian = ObjPas.TEndian;
    +  TByteBitIndex = 0..Pred(SizeOf(Byte));
    +  TShortIntBitIndex = TByteBitIndex;
    +  TWordBitIndex = 0..SizeOf(Word)-1;
    +  TSmallIntBitIndex = TWordBitIndex;
    +  TCardinalBitIndex = 0..Pred(SizeOf(Cardinal));
    +  TIntegerBitIndex = TCardinalBitIndex;
    +  TNativeUIntBitIndex = 0.. Pred(SizeOf(NativeUint));
    +  TNativeIntBitIndex = TNativeUintBitIndex;
    +  TQwordBitIndex = 0..Pred(SizeOf(Qword));
    +  TInt64BitIndex = TQwordBitIndex;
       
    +  
     Const
       CPUEndian = {$IFDEF FPC_LITTLE_ENDIAN}TEndian.Little{$ELSE}TEndian.Big{$ENDIF};
     
    @@ -373,10 +384,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TByteBitIndex); inline;
    +    Procedure ClearBit(const Index: TByteBitIndex); inline;
    +    Procedure ToggleBit(const Index: TByteBitIndex); inline;
    +    Function TestBit(const Index:TByteBitIndex):Boolean; inline;
       end;
     
       TShortIntHelper = Type Helper for ShortInt
    @@ -393,10 +409,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TShortIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TShortIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TShortIntBitIndex); inline;
    +    Function TestBit(const Index:TShortIntBitIndex):Boolean;
       end;
     
       TSmallIntHelper = Type Helper for SmallInt
    @@ -412,11 +433,16 @@
       public
         Function ToString: string; overload; inline;
         Function ToBoolean: Boolean; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString: string; overload; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Procedure SetBit(const Index: TSmallIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TSmallIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TSmallIntBitIndex); inline;
    +    Function TestBit(const Index:TSmallIntBitIndex):Boolean;    
       end;
     
       TWordHelper = Type Helper for Word
    @@ -433,10 +459,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TWordBitIndex); inline;
    +    Procedure ClearBit(const Index: TWordBitIndex); inline;
    +    Procedure ToggleBit(const Index: TWordBitIndex); inline;
    +    Function TestBit(const Index:TWordBitIndex):Boolean; inline;    
       end;
     
       TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
    @@ -453,10 +484,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TCardinalBitIndex); inline;
    +    Procedure ClearBit(const Index: TCardinalBitIndex); inline;
    +    Procedure ToggleBit(const Index: TCardinalBitIndex); inline;
    +    Function TestBit(const Index:TCardinalBitIndex):Boolean; inline;   
       end;
     
       TIntegerHelper = Type Helper for Integer { for LongInt Type too }
    @@ -473,10 +509,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TIntegerBitIndex); inline;
    +    Procedure ClearBit(const Index: TIntegerBitIndex); inline;
    +    Procedure ToggleBit(const Index: TIntegerBitIndex); inline;
    +    Function TestBit(const Index:TIntegerBitIndex):Boolean; inline;   
       end;
     
       TInt64Helper = Type Helper for Int64
    @@ -493,10 +534,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TInt64BitIndex); inline;
    +    Procedure ClearBit(const Index: TInt64BitIndex); inline;
    +    Procedure ToggleBit(const Index: TInt64BitIndex); inline;
    +    Function TestBit(const Index:TInt64BitIndex):Boolean; inline; 
       end;
     
       TQWordHelper = Type Helper for QWord
    @@ -513,10 +559,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TQwordBitIndex); inline;
    +    Procedure ClearBit(const Index: TQwordBitIndex); inline;
    +    Procedure ToggleBit(const Index: TQwordBitIndex); inline;
    +    Function TestBit(const Index:TQwordBitIndex):Boolean; inline; 
       end;
     
       TNativeIntHelper = Type Helper for NativeInt
    @@ -533,10 +584,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TNativeIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TNativeIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TNativeIntBitIndex); inline;
    +    Function TestBit(const Index:TNativeIntBitIndex):Boolean; inline; 
       end;
     
       TNativeUIntHelper = Type Helper for NativeUInt
    @@ -553,10 +609,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TNativeUIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TNativeUIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TNativeUIntBitIndex); inline;
    +    Function TestBit(const Index:TNativeUIntBitIndex):Boolean; inline; 
       end;
     
       {$SCOPEDENUMS ON}
    Index: rtl/objpas/sysutils/syshelpo.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelpo.inc	(revision 43151)
    +++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
    @@ -45,6 +45,12 @@
       Result:=Self;
     end;
     
    +Function TORDINALHELPER.ToBinString: string; inline;
    +
    +begin
    +  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
    +end;
    +
     Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
     overload; inline;
     
    @@ -69,3 +75,27 @@
     begin
       Result:=IntToStr(Self);
     end;
    +
    +Procedure TORDINALHELPER.SetBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self := Self or (TORDINALTYPE(1) << index);
    +end;
    +
    +Procedure TORDINALHELPER.ClearBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self:=Self and not (TORDINALTYPE(1) << index);
    +end;
    +
    +Procedure TORDINALHELPER.ToggleBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self := Self xor (TORDINALTYPE(1) << index);
    +end;
    +
    +Function TORDINALHELPER.TestBit(const Index: TORDINALBITINDEX):Boolean; inline;
    +
    +begin
    +  Result := Self and (TORDINALTYPE(1) << index) <> 0;
    +end;
    
  • bittests.pas (1,988 bytes)
    program bittests;
    {$mode delphi}{$H+}
    {$assertions on}
    uses sysutils;
    
    var 
      i:byte;
      b:byte = 0;
      sh:ShortInt =0;
      w:word = 0;
      si:SmallInt = 0;
      c:Cardinal = 0;
      int:Integer = 0;
      ni:NativeInt = 0;
      nu:NativeUint = 0;
      i64:Int64 = 0;
      q:qword = 0;
    begin
      for i:= 0 to  sizeof(Shortint)*8-1 do
      begin
        Assert(b.TestBit(i) = false);
        b.setbit(i);
        Assert(b.TestBit(Byte(i)) = true);
        writeln(b.ToBinString);
      end;
    
      for i := 0 to sizeof(Shortint)*8-1 do
      begin
        Assert(sh.TestBit(i) = false);
        sh.setbit(i);
        Assert(Sh.TestBit(Byte(i))= true);
        writeln(sh.ToBinString);
      end;
    
      for i := 0 to sizeof(Word)*8-1 do
      begin
        Assert(w.TestBit(i) = false);
        w.setbit(i);
        Assert(w.TestBit(i) = true);
        writeln(w.ToBinString);
      end;
    
      for i := 0 to sizeof(Smallint)*8-1 do
      begin
        Assert(si.TestBit(i) = false);
        si.setbit(i);
        Assert(si.TestBit(i) = true);
        writeln(si.ToBinString);
      end;
    
      for i := 0 to sizeof(Cardinal)*8-1 do
      begin
        Assert(c.TestBit(i) = false);
        c.setbit(i);
        Assert(c.TestBit(i) = true);
        writeln(c.ToBinString);
      end;
    
      for i := 0 to sizeof(integer)*8-1 do
      begin
        Assert(int.TestBit(int) = false);
        int.setbit(i);
        Assert(int.TestBit(i) = true);
        writeln(int.ToBinString);
      end;
    
      for i := 0 to sizeof(NativeInt)*8-1 do
      begin
        Assert(ni.TestBit(i) = false);
        ni.setbit(i);
        Assert(ni.TestBit(i) = true);
        writeln(ni.ToBinString);
      end;
    
      for i := 0 to sizeof(NativeUint)*8-1 do
      begin
        Assert(nu.TestBit(i) = false);
        nu.setbit(i);
        Assert(nu.TestBit(i) = true);
        writeln(nu.ToBinString);
      end;
    
      for i := 0 to sizeof(Int64)*8-1 do
      begin
        Assert(i64.TestBit(i) = false);
        i64.setbit(i);
        Assert(i64.TestBit(i) = true);
        writeln(i64.ToBinString);
      end;
    
      for i := 0 to sizeof(Qword)*8-1 do
      begin
        Assert(q.TestBit(i) = false);
        q.setbit(i);
        Assert(q.TestBit(i) = true);
        writeln(q.ToBinString);
      end;
    end.
    
    bittests.pas (1,988 bytes)
  • bittests2.pas (2,147 bytes)
    program bittests;
    {$mode objfpc}{$H+}
    {$assertions on}
    uses sysutils;
    
    var 
      i:integer;
      b:byte = 0;
      sh:ShortInt =0;
      w:word = 0;
      si:SmallInt = 0;
      c:Cardinal = 0;
      int:Integer = 0;
      ni:NativeInt = 0;
      nu:NativeUint = 0;
      i64:Int64 = 0;
      q:qword = 0;
    begin
      for i:= 0 to  sizeof(Byte)*8-1 do
      begin
        if b.TestBit(i) = true then Halt(1);
        b.setbit(i);
        if b.TestBit(i) = false then Halt(2);
        writeln(b.ToBinString);
      end;
    
      for i := 0 to sizeof(Shortint)*8-1 do
      begin
        if sh.TestBit(i) = true then Halt(3);
        sh.setbit(i);
        if Sh.TestBit(i) = false then Halt(4);
        writeln(sh.ToBinString);
      end;
    
      for i := 0 to sizeof(Word)*8-1 do
      begin
        if w.TestBit(i) = true then Halt(5);
        w.setbit(i);
        if w.TestBit(i) = false then halt(6);
        writeln(w.ToBinString);
      end;
    
      for i := 0 to sizeof(Smallint)*8-1 do
      begin
        if si.TestBit(i) = true then Halt(7);
        si.setbit(i);
        if si.TestBit(i) = false then Halt(8);
        writeln(si.ToBinString);
      end;
    
      for i := 0 to sizeof(Cardinal)*8-1 do
      begin
        if c.TestBit(i) = true then Halt(9);
        c.setbit(i);
        if c.TestBit(i) = false then Halt(10);
        writeln(c.ToBinString);
      end;
    
      for i := 0 to sizeof(integer)*8-1 do
      begin
        if int.TestBit(int) = true then Halt(11);
        int.setbit(i);
        if int.TestBit(i) = false then Halt(12);
        writeln(int.ToBinString);
      end;
    
      for i := 0 to sizeof(NativeInt)*8-1 do
      begin
        if ni.TestBit(i) = true then Halt(13);
        ni.setbit(i);
        if ni.TestBit(i) = false then Halt(14);
        writeln(ni.ToBinString);
      end;
    
      for i := 0 to sizeof(NativeUint)*8-1 do
      begin
        if nu.TestBit(i) = true then Halt(15);
        nu.setbit(i);
        if nu.TestBit(i) = false then Halt(16);
        writeln(nu.ToBinString);
      end;
    
      for i := 0 to sizeof(Int64)*8-1 do
      begin
        if i64.TestBit(i) = true then Halt(17);
        i64.setbit(i);
        if i64.TestBit(i) = false then Halt(18);
        writeln(i64.ToBinString);
      end;
    
      for i := 0 to sizeof(Qword)*8-1 do
      begin
        if q.TestBit(i) = true then Halt(19);
        q.setbit(i);
        if q.TestBit(i) = false then Halt(20);
        writeln(q.ToBinString);
      end;
    end.
    
    bittests2.pas (2,147 bytes)
  • ordinalbitshelper4.patch (11,871 bytes)
    Index: rtl/objpas/sysutils/syshelp.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelp.inc	(revision 43156)
    +++ rtl/objpas/sysutils/syshelp.inc	(working copy)
    @@ -1550,6 +1550,7 @@
     
     {$define TORDINALHELPER:=TByteHelper}
     {$define TORDINALTYPE:=Byte}
    +{$define TORDINALBITINDEX:=TByteBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1558,6 +1559,7 @@
     
     {$define TORDINALHELPER:=TShortIntHelper}
     {$define TORDINALTYPE:=ShortInt}
    +{$define TORDINALBITINDEX:=TShortIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1566,6 +1568,7 @@
     
     {$define TORDINALHELPER:=TSmallIntHelper}
     {$define TORDINALTYPE:=SmallInt}
    +{$define TORDINALBITINDEX:=TSmallIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1574,6 +1577,7 @@
     
     {$define TORDINALHELPER:=TWordHelper}
     {$define TORDINALTYPE:=Word}
    +{$define TORDINALBITINDEX:=TWordBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1582,6 +1586,7 @@
     
     {$define TORDINALHELPER:=TCardinalHelper}
     {$define TORDINALTYPE:=Cardinal}
    +{$define TORDINALBITINDEX:=TCardinalBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1590,6 +1595,7 @@
     
     {$define TORDINALHELPER:=TIntegerHelper}
     {$define TORDINALTYPE:=Integer}
    +{$define TORDINALBITINDEX:=TIntegerBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1598,6 +1604,7 @@
     
     {$define TORDINALHELPER:=TInt64Helper}
     {$define TORDINALTYPE:=Int64}
    +{$define TORDINALBITINDEX:=TInt64BitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1606,6 +1613,7 @@
     
     {$define TORDINALHELPER:=TQWordHelper}
     {$define TORDINALTYPE:=QWord}
    +{$define TORDINALBITINDEX:=TQwordBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1614,6 +1622,7 @@
     
     {$define TORDINALHELPER:=TNativeIntHelper}
     {$define TORDINALTYPE:=NativeInt}
    +{$define TORDINALBITINDEX:=TNativeIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1622,6 +1631,7 @@
     
     {$define TORDINALHELPER:=TNativeUIntHelper}
     {$define TORDINALTYPE:=NativeUInt}
    +{$define TORDINALBITINDEX:=TNativeUIntBitIndex}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    Index: rtl/objpas/sysutils/syshelph.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelph.inc	(revision 43156)
    +++ rtl/objpas/sysutils/syshelph.inc	(working copy)
    @@ -5,7 +5,18 @@
       TStringArray = Array of string;
       TCharArray = Array of char;
       TEndian = ObjPas.TEndian;
    +  TByteBitIndex = 0..Pred(SizeOf(Byte) * 8);
    +  TShortIntBitIndex = TByteBitIndex;
    +  TWordBitIndex = 0..pred(SizeOf(Word) * 8);
    +  TSmallIntBitIndex = TWordBitIndex;
    +  TCardinalBitIndex = 0..Pred(SizeOf(Cardinal) * 8);
    +  TIntegerBitIndex = TCardinalBitIndex;
    +  TNativeUIntBitIndex = 0.. Pred(SizeOf(NativeUint) * 8);
    +  TNativeIntBitIndex = TNativeUintBitIndex;
    +  TQwordBitIndex = 0..Pred(SizeOf(Qword) * 8);
    +  TInt64BitIndex = TQwordBitIndex;
       
    +  
     Const
       CPUEndian = {$IFDEF FPC_LITTLE_ENDIAN}TEndian.Little{$ELSE}TEndian.Big{$ENDIF};
     
    @@ -373,10 +384,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TByteBitIndex); inline;
    +    Procedure ClearBit(const Index: TByteBitIndex); inline;
    +    Procedure ToggleBit(const Index: TByteBitIndex); inline;
    +    Function TestBit(const Index:TByteBitIndex):Boolean; inline;
       end;
     
       TShortIntHelper = Type Helper for ShortInt
    @@ -393,10 +409,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TShortIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TShortIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TShortIntBitIndex); inline;
    +    Function TestBit(const Index:TShortIntBitIndex):Boolean;
       end;
     
       TSmallIntHelper = Type Helper for SmallInt
    @@ -412,11 +433,16 @@
       public
         Function ToString: string; overload; inline;
         Function ToBoolean: Boolean; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString: string; overload; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Procedure SetBit(const Index: TSmallIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TSmallIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TSmallIntBitIndex); inline;
    +    Function TestBit(const Index:TSmallIntBitIndex):Boolean;    
       end;
     
       TWordHelper = Type Helper for Word
    @@ -433,10 +459,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TWordBitIndex); inline;
    +    Procedure ClearBit(const Index: TWordBitIndex); inline;
    +    Procedure ToggleBit(const Index: TWordBitIndex); inline;
    +    Function TestBit(const Index:TWordBitIndex):Boolean; inline;    
       end;
     
       TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
    @@ -453,10 +484,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TCardinalBitIndex); inline;
    +    Procedure ClearBit(const Index: TCardinalBitIndex); inline;
    +    Procedure ToggleBit(const Index: TCardinalBitIndex); inline;
    +    Function TestBit(const Index:TCardinalBitIndex):Boolean; inline;   
       end;
     
       TIntegerHelper = Type Helper for Integer { for LongInt Type too }
    @@ -473,10 +509,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TIntegerBitIndex); inline;
    +    Procedure ClearBit(const Index: TIntegerBitIndex); inline;
    +    Procedure ToggleBit(const Index: TIntegerBitIndex); inline;
    +    Function TestBit(const Index:TIntegerBitIndex):Boolean; inline;   
       end;
     
       TInt64Helper = Type Helper for Int64
    @@ -493,10 +534,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TInt64BitIndex); inline;
    +    Procedure ClearBit(const Index: TInt64BitIndex); inline;
    +    Procedure ToggleBit(const Index: TInt64BitIndex); inline;
    +    Function TestBit(const Index:TInt64BitIndex):Boolean; inline; 
       end;
     
       TQWordHelper = Type Helper for QWord
    @@ -513,10 +559,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TQwordBitIndex); inline;
    +    Procedure ClearBit(const Index: TQwordBitIndex); inline;
    +    Procedure ToggleBit(const Index: TQwordBitIndex); inline;
    +    Function TestBit(const Index:TQwordBitIndex):Boolean; inline; 
       end;
     
       TNativeIntHelper = Type Helper for NativeInt
    @@ -533,10 +584,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TNativeIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TNativeIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TNativeIntBitIndex); inline;
    +    Function TestBit(const Index:TNativeIntBitIndex):Boolean; inline; 
       end;
     
       TNativeUIntHelper = Type Helper for NativeUInt
    @@ -553,10 +609,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TNativeUIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TNativeUIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TNativeUIntBitIndex); inline;
    +    Function TestBit(const Index:TNativeUIntBitIndex):Boolean; inline; 
       end;
     
       {$SCOPEDENUMS ON}
    Index: rtl/objpas/sysutils/syshelpo.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelpo.inc	(revision 43156)
    +++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
    @@ -45,6 +45,12 @@
       Result:=Self;
     end;
     
    +Function TORDINALHELPER.ToBinString: string; inline;
    +
    +begin
    +  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
    +end;
    +
     Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
     overload; inline;
     
    @@ -69,3 +75,27 @@
     begin
       Result:=IntToStr(Self);
     end;
    +
    +Procedure TORDINALHELPER.SetBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self := Self or (TORDINALTYPE(1) << index);
    +end;
    +
    +Procedure TORDINALHELPER.ClearBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self:=Self and not (TORDINALTYPE(1) << index);
    +end;
    +
    +Procedure TORDINALHELPER.ToggleBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self := Self xor (TORDINALTYPE(1) << index);
    +end;
    +
    +Function TORDINALHELPER.TestBit(const Index: TORDINALBITINDEX):Boolean; inline;
    +
    +begin
    +  Result := Self and (TORDINALTYPE(1) << index) <> 0;
    +end;
    
    ordinalbitshelper4.patch (11,871 bytes)
  • testbits.zip (10,872 bytes)
  • testbits2.zip (11,182 bytes)
  • testbug.pas (1,327 bytes)
    program untitled;
    {$mode delphi}{$H+}{$rangechecks on}
    uses sysutils;
    var 
      a:Shortint = 0;
      b:SmallInt = 0;
      c:Integer = 0;
      d:NativeInt = 0;
      e:Int64 = 0;
    begin
      a.setbit(7);
      writeln('1:',a.tobinstring:64, a.testbit(7):7);
      b.setbit(15);
      writeln('2:',b.tobinstring:64, b.testbit(15):7);
      c.setbit(31);
      writeln('3:',c.tobinstring:64, c.testbit(31):7);
      d.setbit(SizeOf(NativeInt)* 8 -1);
      writeln('4:',d.tobinstring:64,d.testbit(SizeOf(NativeInt)* 8 - 1):7);
      e.setbit(63);
      writeln('5:',e.tobinstring:64,e.testbit(63):7);
      a.clearbit(7);
      writeln('1:',a.tobinstring:64, a.testbit(7):7);
      b.clearbit(15);
      writeln('2:',b.tobinstring:64, b.testbit(15):7);
      c.clearbit(31);
      writeln('3:',c.tobinstring:64, c.testbit(31):7);
      d.clearbit(SizeOf(NativeInt)* 8 -1);
      writeln('4:',d.tobinstring:64, d.testbit(SizeOf(NativeInt)* 8 - 1):7);
      e.clearbit(63);
      writeln('5:',e.tobinstring:64, e.testbit(63):7);
      a.togglebit(7);
      writeln('1:',a.tobinstring:64, a.testbit(7):7);
      b.togglebit(15);
      writeln('2:',b.tobinstring:64, b.testbit(15):7);
      c.togglebit(31);
      writeln('3:',c.tobinstring:64, c.testbit(31):7);
      d.togglebit(SizeOf(NativeInt)* 8 -1);
      writeln('4:',d.tobinstring:64, d.testbit(SizeOf(NativeInt) * 8 - 1):7);
      e.togglebit(63);
      writeln('5:',e.tobinstring:64, e.testbit(63):7);  
    end.
    
    testbug.pas (1,327 bytes)
  • ordinalbithelpers-20191012.patch (12,251 bytes)
    Index: rtl/objpas/sysutils/syshelp.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelp.inc	(revision 43168)
    +++ rtl/objpas/sysutils/syshelp.inc	(working copy)
    @@ -1550,6 +1550,8 @@
     
     {$define TORDINALHELPER:=TByteHelper}
     {$define TORDINALTYPE:=Byte}
    +{$define TORDINALBITINDEX:=TByteBitIndex}
    +{$define TUNSIGNED:=Byte}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1558,6 +1560,8 @@
     
     {$define TORDINALHELPER:=TShortIntHelper}
     {$define TORDINALTYPE:=ShortInt}
    +{$define TORDINALBITINDEX:=TShortIntBitIndex}
    +{$define TUNSIGNED:=Byte}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1566,6 +1570,8 @@
     
     {$define TORDINALHELPER:=TSmallIntHelper}
     {$define TORDINALTYPE:=SmallInt}
    +{$define TORDINALBITINDEX:=TSmallIntBitIndex}
    +{$define TUNSIGNED:=Word}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1574,6 +1580,8 @@
     
     {$define TORDINALHELPER:=TWordHelper}
     {$define TORDINALTYPE:=Word}
    +{$define TORDINALBITINDEX:=TWordBitIndex}
    +{$define TUNSIGNED:=Word}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1582,6 +1590,8 @@
     
     {$define TORDINALHELPER:=TCardinalHelper}
     {$define TORDINALTYPE:=Cardinal}
    +{$define TORDINALBITINDEX:=TCardinalBitIndex}
    +{$define TUNSIGNED:=Cardinal}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1590,6 +1600,8 @@
     
     {$define TORDINALHELPER:=TIntegerHelper}
     {$define TORDINALTYPE:=Integer}
    +{$define TORDINALBITINDEX:=TIntegerBitIndex}
    +{$define TUNSIGNED:=Cardinal}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1598,6 +1610,8 @@
     
     {$define TORDINALHELPER:=TInt64Helper}
     {$define TORDINALTYPE:=Int64}
    +{$define TORDINALBITINDEX:=TInt64BitIndex}
    +{$define TUNSIGNED:=Qword}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1606,6 +1620,8 @@
     
     {$define TORDINALHELPER:=TQWordHelper}
     {$define TORDINALTYPE:=QWord}
    +{$define TORDINALBITINDEX:=TQwordBitIndex}
    +{$define TUNSIGNED:=Qword}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1614,6 +1630,8 @@
     
     {$define TORDINALHELPER:=TNativeIntHelper}
     {$define TORDINALTYPE:=NativeInt}
    +{$define TORDINALBITINDEX:=TNativeIntBitIndex}
    +{$define TUNSIGNED:=NativeUInt}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1622,6 +1640,8 @@
     
     {$define TORDINALHELPER:=TNativeUIntHelper}
     {$define TORDINALTYPE:=NativeUInt}
    +{$define TORDINALBITINDEX:=TNativeUIntBitIndex}
    +{$define TUNSIGNED:=NativeUInt}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    Index: rtl/objpas/sysutils/syshelph.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelph.inc	(revision 43168)
    +++ rtl/objpas/sysutils/syshelph.inc	(working copy)
    @@ -5,7 +5,18 @@
       TStringArray = Array of string;
       TCharArray = Array of char;
       TEndian = ObjPas.TEndian;
    +  TByteBitIndex = 0..Pred(SizeOf(Byte) * 8);
    +  TShortIntBitIndex = TByteBitIndex;
    +  TWordBitIndex = 0..pred(SizeOf(Word) * 8);
    +  TSmallIntBitIndex = TWordBitIndex;
    +  TCardinalBitIndex = 0..Pred(SizeOf(Cardinal) * 8);
    +  TIntegerBitIndex = TCardinalBitIndex;
    +  TNativeUIntBitIndex = 0.. Pred(SizeOf(NativeUint) * 8);
    +  TNativeIntBitIndex = TNativeUintBitIndex;
    +  TQwordBitIndex = 0..Pred(SizeOf(Qword) * 8);
    +  TInt64BitIndex = TQwordBitIndex;
       
    +  
     Const
       CPUEndian = {$IFDEF FPC_LITTLE_ENDIAN}TEndian.Little{$ELSE}TEndian.Big{$ENDIF};
     
    @@ -373,10 +384,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TByteBitIndex); inline;
    +    Procedure ClearBit(const Index: TByteBitIndex); inline;
    +    Procedure ToggleBit(const Index: TByteBitIndex); inline;
    +    Function TestBit(const Index:TByteBitIndex):Boolean; inline;
       end;
     
       TShortIntHelper = Type Helper for ShortInt
    @@ -393,10 +409,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TShortIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TShortIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TShortIntBitIndex); inline;
    +    Function TestBit(const Index:TShortIntBitIndex):Boolean;
       end;
     
       TSmallIntHelper = Type Helper for SmallInt
    @@ -412,11 +433,16 @@
       public
         Function ToString: string; overload; inline;
         Function ToBoolean: Boolean; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString: string; overload; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Procedure SetBit(const Index: TSmallIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TSmallIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TSmallIntBitIndex); inline;
    +    Function TestBit(const Index:TSmallIntBitIndex):Boolean;    
       end;
     
       TWordHelper = Type Helper for Word
    @@ -433,10 +459,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TWordBitIndex); inline;
    +    Procedure ClearBit(const Index: TWordBitIndex); inline;
    +    Procedure ToggleBit(const Index: TWordBitIndex); inline;
    +    Function TestBit(const Index:TWordBitIndex):Boolean; inline;    
       end;
     
       TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
    @@ -453,10 +484,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TCardinalBitIndex); inline;
    +    Procedure ClearBit(const Index: TCardinalBitIndex); inline;
    +    Procedure ToggleBit(const Index: TCardinalBitIndex); inline;
    +    Function TestBit(const Index:TCardinalBitIndex):Boolean; inline;   
       end;
     
       TIntegerHelper = Type Helper for Integer { for LongInt Type too }
    @@ -473,10 +509,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TIntegerBitIndex); inline;
    +    Procedure ClearBit(const Index: TIntegerBitIndex); inline;
    +    Procedure ToggleBit(const Index: TIntegerBitIndex); inline;
    +    Function TestBit(const Index:TIntegerBitIndex):Boolean; inline;   
       end;
     
       TInt64Helper = Type Helper for Int64
    @@ -493,10 +534,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TInt64BitIndex); inline;
    +    Procedure ClearBit(const Index: TInt64BitIndex); inline;
    +    Procedure ToggleBit(const Index: TInt64BitIndex); inline;
    +    Function TestBit(const Index:TInt64BitIndex):Boolean; inline; 
       end;
     
       TQWordHelper = Type Helper for QWord
    @@ -513,10 +559,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TQwordBitIndex); inline;
    +    Procedure ClearBit(const Index: TQwordBitIndex); inline;
    +    Procedure ToggleBit(const Index: TQwordBitIndex); inline;
    +    Function TestBit(const Index:TQwordBitIndex):Boolean; inline; 
       end;
     
       TNativeIntHelper = Type Helper for NativeInt
    @@ -533,10 +584,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TNativeIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TNativeIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TNativeIntBitIndex); inline;
    +    Function TestBit(const Index:TNativeIntBitIndex):Boolean; inline; 
       end;
     
       TNativeUIntHelper = Type Helper for NativeUInt
    @@ -553,10 +609,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Procedure SetBit(const Index: TNativeUIntBitIndex); inline;
    +    Procedure ClearBit(const Index: TNativeUIntBitIndex); inline;
    +    Procedure ToggleBit(const Index: TNativeUIntBitIndex); inline;
    +    Function TestBit(const Index:TNativeUIntBitIndex):Boolean; inline; 
       end;
     
       {$SCOPEDENUMS ON}
    Index: rtl/objpas/sysutils/syshelpo.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelpo.inc	(revision 43168)
    +++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
    @@ -45,6 +45,12 @@
       Result:=Self;
     end;
     
    +Function TORDINALHELPER.ToBinString: string; inline;
    +
    +begin
    +  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
    +end;
    +
     Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
     overload; inline;
     
    @@ -69,3 +75,27 @@
     begin
       Result:=IntToStr(Self);
     end;
    +
    +Procedure TORDINALHELPER.SetBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self := TORDINALTYPE(TUNSIGNED(Self) or TUNSIGNED(1) shl index);
    +end;
    +
    +Procedure TORDINALHELPER.ClearBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self:=TORDINALTYPE(TUNSIGNED(Self) and not TUNSIGNED(1) shl index);
    +end;
    +
    +Procedure TORDINALHELPER.ToggleBit(const index: TORDINALBITINDEX); inline;
    +
    +begin
    +  Self := TORDINALTYPE(TUNSIGNED(Self) xor (TUNSIGNED(1) shl index));
    +end;
    +
    +Function TORDINALHELPER.TestBit(const Index: TORDINALBITINDEX):Boolean; inline;
    +
    +begin
    +  Result := TORDINALTYPE(TUNSIGNED(Self) and (TUNSIGNED(1) shl index)) <> 0;
    +end;
    
  • ordinalbithelpers-20191013.patch (11,114 bytes)
    Index: rtl/objpas/sysutils/syshelp.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelp.inc	(revision 43182)
    +++ rtl/objpas/sysutils/syshelp.inc	(working copy)
    @@ -1550,6 +1550,7 @@
     
     {$define TORDINALHELPER:=TByteHelper}
     {$define TORDINALTYPE:=Byte}
    +{$define TUNSIGNED:=Byte}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1558,6 +1559,7 @@
     
     {$define TORDINALHELPER:=TShortIntHelper}
     {$define TORDINALTYPE:=ShortInt}
    +{$define TUNSIGNED:=Byte}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1566,6 +1568,7 @@
     
     {$define TORDINALHELPER:=TSmallIntHelper}
     {$define TORDINALTYPE:=SmallInt}
    +{$define TUNSIGNED:=Word}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1574,6 +1577,7 @@
     
     {$define TORDINALHELPER:=TWordHelper}
     {$define TORDINALTYPE:=Word}
    +{$define TUNSIGNED:=Word}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1582,6 +1586,7 @@
     
     {$define TORDINALHELPER:=TCardinalHelper}
     {$define TORDINALTYPE:=Cardinal}
    +{$define TUNSIGNED:=Cardinal}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1590,6 +1595,7 @@
     
     {$define TORDINALHELPER:=TIntegerHelper}
     {$define TORDINALTYPE:=Integer}
    +{$define TUNSIGNED:=Cardinal}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1598,6 +1604,7 @@
     
     {$define TORDINALHELPER:=TInt64Helper}
     {$define TORDINALTYPE:=Int64}
    +{$define TUNSIGNED:=Qword}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1606,6 +1613,7 @@
     
     {$define TORDINALHELPER:=TQWordHelper}
     {$define TORDINALTYPE:=QWord}
    +{$define TUNSIGNED:=Qword}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1614,6 +1622,7 @@
     
     {$define TORDINALHELPER:=TNativeIntHelper}
     {$define TORDINALTYPE:=NativeInt}
    +{$define TUNSIGNED:=NativeUInt}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    @@ -1622,6 +1631,7 @@
     
     {$define TORDINALHELPER:=TNativeUIntHelper}
     {$define TORDINALTYPE:=NativeUInt}
    +{$define TUNSIGNED:=NativeUInt}
     {$i syshelpo.inc}
     
     { ---------------------------------------------------------------------
    Index: rtl/objpas/sysutils/syshelph.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelph.inc	(revision 43182)
    +++ rtl/objpas/sysutils/syshelph.inc	(working copy)
    @@ -373,10 +373,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Function SetBit(const Index: integer):Boolean; inline;
    +    Function ClearBit(const Index: integer):Boolean; inline;
    +    Function ToggleBit(const Index: integer):Boolean; inline;
    +    Function TestBit(const Index:integer):Boolean; inline;
       end;
     
       TShortIntHelper = Type Helper for ShortInt
    @@ -393,10 +398,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Function SetBit(const Index: integer):Boolean; inline;
    +    Function ClearBit(const Index: integer):Boolean; inline;
    +    Function ToggleBit(const Index: integer):Boolean; inline;
    +    Function TestBit(const Index:integer):Boolean;
       end;
     
       TSmallIntHelper = Type Helper for SmallInt
    @@ -412,11 +422,16 @@
       public
         Function ToString: string; overload; inline;
         Function ToBoolean: Boolean; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString: string; overload; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function SetBit(const Index: integer):Boolean; inline;
    +    Function ClearBit(const Index: integer):Boolean; inline;
    +    Function ToggleBit(const Index: integer):Boolean; inline;
    +    Function TestBit(const Index:integer):Boolean;    
       end;
     
       TWordHelper = Type Helper for Word
    @@ -433,10 +448,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Function SetBit(const Index: integer):Boolean; inline;
    +    Function ClearBit(const Index: integer):Boolean; inline;
    +    Function ToggleBit(const Index: integer):Boolean; inline;
    +    Function TestBit(const Index:integer):Boolean; inline;    
       end;
     
       TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
    @@ -453,10 +473,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Function SetBit(const Index: integer):Boolean; inline;
    +    Function ClearBit(const Index: integer):Boolean; inline;
    +    Function ToggleBit(const Index: integer):Boolean; inline;
    +    Function TestBit(const Index:integer):Boolean; inline;   
       end;
     
       TIntegerHelper = Type Helper for Integer { for LongInt Type too }
    @@ -473,10 +498,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Function SetBit(const Index: integer):Boolean; inline;
    +    Function ClearBit(const Index: integer):Boolean; inline;
    +    Function ToggleBit(const Index: integer):Boolean; inline;
    +    Function TestBit(const Index:integer):Boolean; inline;   
       end;
     
       TInt64Helper = Type Helper for Int64
    @@ -493,10 +523,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Function SetBit(const Index: integer):Boolean; inline;
    +    Function ClearBit(const Index: integer):Boolean; inline;
    +    Function ToggleBit(const Index: integer):Boolean; inline;
    +    Function TestBit(const Index:integer):Boolean; inline; 
       end;
     
       TQWordHelper = Type Helper for QWord
    @@ -513,10 +548,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Function SetBit(const Index: integer):Boolean; inline;
    +    Function ClearBit(const Index: integer):Boolean; inline;
    +    Function ToggleBit(const Index: integer):Boolean; inline;
    +    Function TestBit(const Index:integer):Boolean; inline; 
       end;
     
       TNativeIntHelper = Type Helper for NativeInt
    @@ -533,10 +573,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Function SetBit(const Index: integer):Boolean; inline;
    +    Function ClearBit(const Index: integer):Boolean; inline;
    +    Function ToggleBit(const Index: integer):Boolean; inline;
    +    Function TestBit(const Index:integer):Boolean; inline; 
       end;
     
       TNativeUIntHelper = Type Helper for NativeUInt
    @@ -553,10 +598,15 @@
         Function ToBoolean: Boolean; inline;
         Function ToDouble: Double; inline;
         Function ToExtended: Extended; inline;
    +    Function ToBinString:string; inline;
         Function ToHexString(const AMinDigits: Integer): string; overload; inline;
         Function ToHexString: string; overload; inline;
         Function ToSingle: Single; inline;
         Function ToString: string; overload; inline;
    +    Function SetBit(const Index: integer):Boolean; inline;
    +    Function ClearBit(const Index: integer):Boolean; inline;
    +    Function ToggleBit(const Index: integer):Boolean; inline;
    +    Function TestBit(const Index:integer):Boolean; inline; 
       end;
     
       {$SCOPEDENUMS ON}
    Index: rtl/objpas/sysutils/syshelpo.inc
    ===================================================================
    --- rtl/objpas/sysutils/syshelpo.inc	(revision 43182)
    +++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
    @@ -45,6 +45,12 @@
       Result:=Self;
     end;
     
    +Function TORDINALHELPER.ToBinString: string; inline;
    +
    +begin
    +  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
    +end;
    +
     Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
     overload; inline;
     
    @@ -69,3 +75,31 @@
     begin
       Result:=IntToStr(Self);
     end;
    +
    +function TORDINALHELPER.SetBit(const index: integer):Boolean; inline;
    +
    +begin
    +  Self := TORDINALTYPE(TUNSIGNED(Self) or TUNSIGNED(1) shl index);
    +  Result := TestBit(Index) = true;
    +end;
    +
    +function TORDINALHELPER.ClearBit(const index: integer):Boolean; inline;
    +
    +begin
    +  Self:=TORDINALTYPE(TUNSIGNED(Self) and not TUNSIGNED(1) shl index);
    +  Result := TestBit(Index) = false;
    +end;
    +
    +function TORDINALHELPER.ToggleBit(const index: integer):Boolean; inline;
    +
    +begin
    +  Result := TestBit(Index);
    +  Self := TORDINALTYPE(TUNSIGNED(Self) xor (TUNSIGNED(1) shl index));
    +  Result := Result <> TestBit(Index);
    +end;
    +
    +Function TORDINALHELPER.TestBit(const Index: integer):Boolean; inline;
    +
    +begin
    +  Result := TORDINALTYPE(TUNSIGNED(Self) and (TUNSIGNED(1) shl index)) <> 0;
    +end;
    
  • testbits.pas (3,219 bytes)
    program testbits;
    {$H+}
    uses 
      sysutils;
    const
      ByteLimit = SizeOf(Byte) * 8 -1;
      ShortIntLimit = ByteLimit;
      WordLimit = SizeOf(Word) * 8 -1;
      SmallIntLimit = WordLimit;
      CardinalLimit = SizeOf(Cardinal) * 8 -1;
      IntegerLimit = SizeOf(Integer) * 8 -1;
      NativeUIntLimit = SizeOf(NativeUInt) * 8 -1;
      NativeIntLimit = NativeUIntLimit;
      QwordLimit = SizeOf(Qword) * 8 -1;
      Int64Limit = QwordLimit;
     
    var
      a:byte = 0;
      b:shortint = 0;
      c:Word = 0;
      d:SmallInt = 0;
      e:Cardinal = 0;
      f:Integer = 0;
      g:NativeUInt = 0;
      h:NativeInt = 0;
      k:Qword = 0;
      l:Int64 = 0;
      i:integer;
    begin
      { create a bit pattern of walking 1's (and two rows of zero per iteration, do not print) }
      for i := 0 to ByteLimit do
      begin
        { add the one in case of error, because Ord(0) is 0 if no error detected }
        if a.Setbit(i) = false then Halt(1 + Ord(a));
        writeln(a.ToBinstring);  
        if a.Togglebit(i) = false then Halt(1 + Ord(a));  
        if a.Clearbit(i) = false then Halt(1 + Ord(a));
      end; 
      
      for i := 0 to ShortIntLimit do
      begin
        if b.Setbit(i) = false then Halt(1 + Ord(b));
        writeln(b.ToBinstring);     
        if b.Togglebit(i) = false then Halt(1 + Ord(b));    
        if b.Clearbit(i) = false then Halt(1 + Ord(b));
      end; 
      
      for i := 0 to WordLimit do
      begin
        if c.Setbit(i) = false then Halt(1 + Ord(c));
        writeln(c.ToBinstring); 
        if c.Togglebit(i) = false then Halt(1 + Ord(c));    
        if c.Clearbit(i) = false then Halt(1 + Ord(c));
      end; 
      
      for i := 0 to SmallIntLimit do
      begin
        if d.Setbit(i) = false then Halt(1 + Ord(d));
        writeln(d.ToBinstring); 
        if d.Togglebit(i) = false then Halt(1 + Ord(d));    
        if d.Clearbit(i) = false then Halt(1 + Ord(d));
      end;
      
      for i := 0 to CardinalLimit do
      begin
        if e.Setbit(i) = false then Halt(1 + Ord(e));
        writeln(e.ToBinstring); 
        if e.Togglebit(i) = false then Halt(1 + Ord(e));    
        if e.Clearbit(i) = false then Halt(1 + Ord(e));
      end;
      
      for i := 0 to IntegerLimit do
      begin
        if f.Setbit(i) = false then Halt(1 + Ord(f));
        writeln(f.ToBinstring); 
        if f.Togglebit(i) = false then Halt(1 + Ord(f));    
        if f.Clearbit(i) = false then Halt(1 + Ord(f));
      end; 
      
      for i := 0 to NativeUIntLimit do
      begin
        if g.Setbit(i) = false then Halt(1 + Ord(g));
        writeln(g.ToBinstring); 
        if g.Togglebit(i) = false then Halt(1 + Ord(g));    
        if g.Clearbit(i) = false then Halt(1 + Ord(g));
      end; 
      
      for i := 0 to NativeIntLimit do
      begin
        if h.Setbit(i) = false then Halt(1 + Ord(h));
        writeln(h.ToBinstring); 
        if h.Togglebit(i) = false then Halt(1 + Ord(h));    
        if h.Clearbit(i) = false then Halt(1 + Ord(h));
      end; 
      
      for i := 0 to QWordLimit do
      begin
        if k.Setbit(i) = false then Halt(1 + Ord(k));
        writeln(k.ToBinstring); 
        if k.Togglebit(i) = false then Halt(1 + Ord(k));    
        if k.Clearbit(i) = false then Halt(1 + Ord(k));
      end; 
      
      for i := 0 to Int64Limit do
      begin
        if l.Setbit(i) = false then Halt(1 + Ord(l));
        writeln(l.ToBinstring); 
        if l.Togglebit(i) = false then Halt(1 + Ord(l));    
        if l.Clearbit(i) = false then Halt(1 + Ord(l));
      end; 
      { result should be zero, all individual bits tested }
    end.
    
    testbits.pas (3,219 bytes)
  • buildruntest.txt (398,067 bytes)
  • testbits3.zip (12,599 bytes)

Activities

Thaddy de Koning

2019-10-08 10:46

reporter  

sysordinalbitshelpers.patch (11,823 bytes)
Index: rtl/objpas/sysutils/syshelp.inc
===================================================================
--- rtl/objpas/sysutils/syshelp.inc	(revision 43151)
+++ rtl/objpas/sysutils/syshelp.inc	(working copy)
@@ -1550,6 +1550,7 @@
 
 {$define TORDINALHELPER:=TByteHelper}
 {$define TORDINALTYPE:=Byte}
+{$define TORDINALBITINDEX:=TByteBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1558,6 +1559,7 @@
 
 {$define TORDINALHELPER:=TShortIntHelper}
 {$define TORDINALTYPE:=ShortInt}
+{$define TORDINALBITINDEX:=TShortIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1566,6 +1568,7 @@
 
 {$define TORDINALHELPER:=TSmallIntHelper}
 {$define TORDINALTYPE:=SmallInt}
+{$define TORDINALBITINDEX:=TSmallIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1574,6 +1577,7 @@
 
 {$define TORDINALHELPER:=TWordHelper}
 {$define TORDINALTYPE:=Word}
+{$define TORDINALBITINDEX:=TWordBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1582,6 +1586,7 @@
 
 {$define TORDINALHELPER:=TCardinalHelper}
 {$define TORDINALTYPE:=Cardinal}
+{$define TORDINALBITINDEX:=TCardinalBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1590,6 +1595,7 @@
 
 {$define TORDINALHELPER:=TIntegerHelper}
 {$define TORDINALTYPE:=Integer}
+{$define TORDINALBITINDEX:=TIntegerBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1598,6 +1604,7 @@
 
 {$define TORDINALHELPER:=TInt64Helper}
 {$define TORDINALTYPE:=Int64}
+{$define TORDINALBITINDEX:=TInt64BitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1606,6 +1613,7 @@
 
 {$define TORDINALHELPER:=TQWordHelper}
 {$define TORDINALTYPE:=QWord}
+{$define TORDINALBITINDEX:=TQwordBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1614,6 +1622,7 @@
 
 {$define TORDINALHELPER:=TNativeIntHelper}
 {$define TORDINALTYPE:=NativeInt}
+{$define TORDINALBITINDEX:=TNativeIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1622,6 +1631,7 @@
 
 {$define TORDINALHELPER:=TNativeUIntHelper}
 {$define TORDINALTYPE:=NativeUInt}
+{$define TORDINALBITINDEX:=TNativeUIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
Index: rtl/objpas/sysutils/syshelph.inc
===================================================================
--- rtl/objpas/sysutils/syshelph.inc	(revision 43151)
+++ rtl/objpas/sysutils/syshelph.inc	(working copy)
@@ -5,7 +5,18 @@
   TStringArray = Array of string;
   TCharArray = Array of char;
   TEndian = ObjPas.TEndian;
+  TByteBitIndex = 0..Pred(SizeOf(Byte));
+  TShortIntBitIndex = TByteBitIndex;
+  TWordBitIndex = 0..SizeOf(Word)-1;
+  TSmallIntBitIndex = TWordBitIndex;
+  TCardinalBitIndex = 0..Pred(SizeOf(Cardinal));
+  TIntegerBitIndex = TCardinalBitIndex;
+  TNativeUIntBitIndex = 0.. Pred(SizeOf(NativeUint));
+  TNativeIntBitIndex = TNativeUintBitIndex;
+  TQwordBitIndex = 0..Pred(SizeOf(Qword));
+  TInt64BitIndex = TQwordBitIndex;
   
+  
 Const
   CPUEndian = {$IFDEF FPC_LITTLE_ENDIAN}TEndian.Little{$ELSE}TEndian.Big{$ENDIF};
 
@@ -373,10 +384,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TByteBitIndex); inline;
+    Procedure ClearBit(const Index: TByteBitIndex); inline;
+    Procedure ToggleBit(const Index: TByteBitIndex); inline;
+    Function TestBit(const Index:TByteBitIndex):Boolean; inline;
   end;
 
   TShortIntHelper = Type Helper for ShortInt
@@ -393,10 +409,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TShortIntBitIndex); inline;
+    Procedure ClearBit(const Index: TShortIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TShortIntBitIndex); inline;
+    Function TestBit(const Index:TShortIntBitIndex):Boolean;
   end;
 
   TSmallIntHelper = Type Helper for SmallInt
@@ -412,11 +433,16 @@
   public
     Function ToString: string; overload; inline;
     Function ToBoolean: Boolean; inline;
+    Function ToBinString:string; inline;
     Function ToHexString: string; overload; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Procedure SetBit(const Index: TSmallIntBitIndex); inline;
+    Procedure ClearBit(const Index: TSmallIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TSmallIntBitIndex); inline;
+    Function TestBit(const Index:TSmallIntBitIndex):Boolean;    
   end;
 
   TWordHelper = Type Helper for Word
@@ -433,10 +459,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TWordBitIndex); inline;
+    Procedure ClearBit(const Index: TWordBitIndex); inline;
+    Procedure ToggleBit(const Index: TWordBitIndex); inline;
+    Function TestBit(const Index:TWordBitIndex):Boolean; inline;    
   end;
 
   TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
@@ -453,10 +484,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TCardinalBitIndex); inline;
+    Procedure ClearBit(const Index: TCardinalBitIndex); inline;
+    Procedure ToggleBit(const Index: TCardinalBitIndex); inline;
+    Function TestBit(const Index:TCardinalBitIndex):Boolean; inline;   
   end;
 
   TIntegerHelper = Type Helper for Integer { for LongInt Type too }
@@ -473,10 +509,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TIntegerBitIndex); inline;
+    Procedure ClearBit(const Index: TIntegerBitIndex); inline;
+    Procedure ToggleBit(const Index: TIntegerBitIndex); inline;
+    Function TestBit(const Index:TIntegerBitIndex):Boolean; inline;   
   end;
 
   TInt64Helper = Type Helper for Int64
@@ -493,10 +534,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TInt64BitIndex); inline;
+    Procedure ClearBit(const Index: TInt64BitIndex); inline;
+    Procedure ToggleBit(const Index: TInt64BitIndex); inline;
+    Function TestBit(const Index:TInt64BitIndex):Boolean; inline; 
   end;
 
   TQWordHelper = Type Helper for QWord
@@ -513,10 +559,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TQwordBitIndex); inline;
+    Procedure ClearBit(const Index: TQwordBitIndex); inline;
+    Procedure ToggleBit(const Index: TQwordBitIndex); inline;
+    Function TestBit(const Index:TQwordBitIndex):Boolean; inline; 
   end;
 
   TNativeIntHelper = Type Helper for NativeInt
@@ -533,10 +584,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TNativeIntBitIndex); inline;
+    Procedure ClearBit(const Index: TNativeIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TNativeIntBitIndex); inline;
+    Function TestBit(const Index:TNativeIntBitIndex):Boolean; inline; 
   end;
 
   TNativeUIntHelper = Type Helper for NativeUInt
@@ -553,10 +609,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TNativeUIntBitIndex); inline;
+    Procedure ClearBit(const Index: TNativeUIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TNativeUIntBitIndex); inline;
+    Function TestBit(const Index:TNativeUIntBitIndex):Boolean; inline; 
   end;
 
   {$SCOPEDENUMS ON}
Index: rtl/objpas/sysutils/syshelpo.inc
===================================================================
--- rtl/objpas/sysutils/syshelpo.inc	(revision 43151)
+++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
@@ -45,6 +45,12 @@
   Result:=Self;
 end;
 
+Function TORDINALHELPER.ToBinString: string; inline;
+
+begin
+  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
+end;
+
 Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
 overload; inline;
 
@@ -69,3 +75,27 @@
 begin
   Result:=IntToStr(Self);
 end;
+
+Procedure TORDINALHELPER.SetBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self := Self or (TORDINALTYPE(1) << index);
+end;
+
+Procedure TORDINALHELPER.ClearBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self:=Self and not (1 << index);
+end;
+
+Procedure TORDINALHELPER.ToggleBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self := Self xor (1 << index);
+end;
+
+Function TORDINALHELPER.TestBit(const Index: TORDINALBITINDEX):Boolean; inline;
+
+begin
+  Result := Boolean(Self and (TORDINALTYPE(1) << index));
+end;

Michael Van Canneyt

2019-10-08 10:56

administrator   ~0118407

@thaddy,

please make a small program that tests the functionality. It must not necessarily do any output but must halt with a nonzero exit code if something is wrong.

Thaddy de Koning

2019-10-08 11:05

reporter   ~0118408

Will do. In the mean time I have just seen the patch (which is correct) needs a slight adjustment: better make sure that all 1's are type casted to the underlying type.

sysordinalbitshelpers_corrected.patch (11,851 bytes)
Index: rtl/objpas/sysutils/syshelp.inc
===================================================================
--- rtl/objpas/sysutils/syshelp.inc	(revision 43151)
+++ rtl/objpas/sysutils/syshelp.inc	(working copy)
@@ -1550,6 +1550,7 @@
 
 {$define TORDINALHELPER:=TByteHelper}
 {$define TORDINALTYPE:=Byte}
+{$define TORDINALBITINDEX:=TByteBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1558,6 +1559,7 @@
 
 {$define TORDINALHELPER:=TShortIntHelper}
 {$define TORDINALTYPE:=ShortInt}
+{$define TORDINALBITINDEX:=TShortIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1566,6 +1568,7 @@
 
 {$define TORDINALHELPER:=TSmallIntHelper}
 {$define TORDINALTYPE:=SmallInt}
+{$define TORDINALBITINDEX:=TSmallIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1574,6 +1577,7 @@
 
 {$define TORDINALHELPER:=TWordHelper}
 {$define TORDINALTYPE:=Word}
+{$define TORDINALBITINDEX:=TWordBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1582,6 +1586,7 @@
 
 {$define TORDINALHELPER:=TCardinalHelper}
 {$define TORDINALTYPE:=Cardinal}
+{$define TORDINALBITINDEX:=TCardinalBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1590,6 +1595,7 @@
 
 {$define TORDINALHELPER:=TIntegerHelper}
 {$define TORDINALTYPE:=Integer}
+{$define TORDINALBITINDEX:=TIntegerBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1598,6 +1604,7 @@
 
 {$define TORDINALHELPER:=TInt64Helper}
 {$define TORDINALTYPE:=Int64}
+{$define TORDINALBITINDEX:=TInt64BitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1606,6 +1613,7 @@
 
 {$define TORDINALHELPER:=TQWordHelper}
 {$define TORDINALTYPE:=QWord}
+{$define TORDINALBITINDEX:=TQwordBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1614,6 +1622,7 @@
 
 {$define TORDINALHELPER:=TNativeIntHelper}
 {$define TORDINALTYPE:=NativeInt}
+{$define TORDINALBITINDEX:=TNativeIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1622,6 +1631,7 @@
 
 {$define TORDINALHELPER:=TNativeUIntHelper}
 {$define TORDINALTYPE:=NativeUInt}
+{$define TORDINALBITINDEX:=TNativeUIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
Index: rtl/objpas/sysutils/syshelph.inc
===================================================================
--- rtl/objpas/sysutils/syshelph.inc	(revision 43151)
+++ rtl/objpas/sysutils/syshelph.inc	(working copy)
@@ -5,7 +5,18 @@
   TStringArray = Array of string;
   TCharArray = Array of char;
   TEndian = ObjPas.TEndian;
+  TByteBitIndex = 0..Pred(SizeOf(Byte));
+  TShortIntBitIndex = TByteBitIndex;
+  TWordBitIndex = 0..SizeOf(Word)-1;
+  TSmallIntBitIndex = TWordBitIndex;
+  TCardinalBitIndex = 0..Pred(SizeOf(Cardinal));
+  TIntegerBitIndex = TCardinalBitIndex;
+  TNativeUIntBitIndex = 0.. Pred(SizeOf(NativeUint));
+  TNativeIntBitIndex = TNativeUintBitIndex;
+  TQwordBitIndex = 0..Pred(SizeOf(Qword));
+  TInt64BitIndex = TQwordBitIndex;
   
+  
 Const
   CPUEndian = {$IFDEF FPC_LITTLE_ENDIAN}TEndian.Little{$ELSE}TEndian.Big{$ENDIF};
 
@@ -373,10 +384,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TByteBitIndex); inline;
+    Procedure ClearBit(const Index: TByteBitIndex); inline;
+    Procedure ToggleBit(const Index: TByteBitIndex); inline;
+    Function TestBit(const Index:TByteBitIndex):Boolean; inline;
   end;
 
   TShortIntHelper = Type Helper for ShortInt
@@ -393,10 +409,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TShortIntBitIndex); inline;
+    Procedure ClearBit(const Index: TShortIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TShortIntBitIndex); inline;
+    Function TestBit(const Index:TShortIntBitIndex):Boolean;
   end;
 
   TSmallIntHelper = Type Helper for SmallInt
@@ -412,11 +433,16 @@
   public
     Function ToString: string; overload; inline;
     Function ToBoolean: Boolean; inline;
+    Function ToBinString:string; inline;
     Function ToHexString: string; overload; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Procedure SetBit(const Index: TSmallIntBitIndex); inline;
+    Procedure ClearBit(const Index: TSmallIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TSmallIntBitIndex); inline;
+    Function TestBit(const Index:TSmallIntBitIndex):Boolean;    
   end;
 
   TWordHelper = Type Helper for Word
@@ -433,10 +459,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TWordBitIndex); inline;
+    Procedure ClearBit(const Index: TWordBitIndex); inline;
+    Procedure ToggleBit(const Index: TWordBitIndex); inline;
+    Function TestBit(const Index:TWordBitIndex):Boolean; inline;    
   end;
 
   TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
@@ -453,10 +484,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TCardinalBitIndex); inline;
+    Procedure ClearBit(const Index: TCardinalBitIndex); inline;
+    Procedure ToggleBit(const Index: TCardinalBitIndex); inline;
+    Function TestBit(const Index:TCardinalBitIndex):Boolean; inline;   
   end;
 
   TIntegerHelper = Type Helper for Integer { for LongInt Type too }
@@ -473,10 +509,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TIntegerBitIndex); inline;
+    Procedure ClearBit(const Index: TIntegerBitIndex); inline;
+    Procedure ToggleBit(const Index: TIntegerBitIndex); inline;
+    Function TestBit(const Index:TIntegerBitIndex):Boolean; inline;   
   end;
 
   TInt64Helper = Type Helper for Int64
@@ -493,10 +534,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TInt64BitIndex); inline;
+    Procedure ClearBit(const Index: TInt64BitIndex); inline;
+    Procedure ToggleBit(const Index: TInt64BitIndex); inline;
+    Function TestBit(const Index:TInt64BitIndex):Boolean; inline; 
   end;
 
   TQWordHelper = Type Helper for QWord
@@ -513,10 +559,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TQwordBitIndex); inline;
+    Procedure ClearBit(const Index: TQwordBitIndex); inline;
+    Procedure ToggleBit(const Index: TQwordBitIndex); inline;
+    Function TestBit(const Index:TQwordBitIndex):Boolean; inline; 
   end;
 
   TNativeIntHelper = Type Helper for NativeInt
@@ -533,10 +584,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TNativeIntBitIndex); inline;
+    Procedure ClearBit(const Index: TNativeIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TNativeIntBitIndex); inline;
+    Function TestBit(const Index:TNativeIntBitIndex):Boolean; inline; 
   end;
 
   TNativeUIntHelper = Type Helper for NativeUInt
@@ -553,10 +609,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TNativeUIntBitIndex); inline;
+    Procedure ClearBit(const Index: TNativeUIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TNativeUIntBitIndex); inline;
+    Function TestBit(const Index:TNativeUIntBitIndex):Boolean; inline; 
   end;
 
   {$SCOPEDENUMS ON}
Index: rtl/objpas/sysutils/syshelpo.inc
===================================================================
--- rtl/objpas/sysutils/syshelpo.inc	(revision 43151)
+++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
@@ -45,6 +45,12 @@
   Result:=Self;
 end;
 
+Function TORDINALHELPER.ToBinString: string; inline;
+
+begin
+  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
+end;
+
 Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
 overload; inline;
 
@@ -69,3 +75,27 @@
 begin
   Result:=IntToStr(Self);
 end;
+
+Procedure TORDINALHELPER.SetBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self := Self or (TORDINALTYPE(1) << index);
+end;
+
+Procedure TORDINALHELPER.ClearBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self:=Self and not (TORDINALTYPE(1) << index);
+end;
+
+Procedure TORDINALHELPER.ToggleBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self := Self xor (TORDINALTYPE(1) << index);
+end;
+
+Function TORDINALHELPER.TestBit(const Index: TORDINALBITINDEX):Boolean; inline;
+
+begin
+  Result := Boolean(Self and (TORDINALTYPE(1) << index));
+end;

Thaddy de Koning

2019-10-08 12:26

reporter   ~0118409

Added tests and a final patch (3)
Tests revealed another small bug: Boolean cast generates faster code, I thought, but comparison to zero is necessary for TestBit due to Boolean size.
Tests based on assertions before / after

Should be OK now?

sysordinalbitshelpers3.patch (11,847 bytes)
Index: rtl/objpas/sysutils/syshelp.inc
===================================================================
--- rtl/objpas/sysutils/syshelp.inc	(revision 43151)
+++ rtl/objpas/sysutils/syshelp.inc	(working copy)
@@ -1550,6 +1550,7 @@
 
 {$define TORDINALHELPER:=TByteHelper}
 {$define TORDINALTYPE:=Byte}
+{$define TORDINALBITINDEX:=TByteBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1558,6 +1559,7 @@
 
 {$define TORDINALHELPER:=TShortIntHelper}
 {$define TORDINALTYPE:=ShortInt}
+{$define TORDINALBITINDEX:=TShortIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1566,6 +1568,7 @@
 
 {$define TORDINALHELPER:=TSmallIntHelper}
 {$define TORDINALTYPE:=SmallInt}
+{$define TORDINALBITINDEX:=TSmallIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1574,6 +1577,7 @@
 
 {$define TORDINALHELPER:=TWordHelper}
 {$define TORDINALTYPE:=Word}
+{$define TORDINALBITINDEX:=TWordBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1582,6 +1586,7 @@
 
 {$define TORDINALHELPER:=TCardinalHelper}
 {$define TORDINALTYPE:=Cardinal}
+{$define TORDINALBITINDEX:=TCardinalBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1590,6 +1595,7 @@
 
 {$define TORDINALHELPER:=TIntegerHelper}
 {$define TORDINALTYPE:=Integer}
+{$define TORDINALBITINDEX:=TIntegerBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1598,6 +1604,7 @@
 
 {$define TORDINALHELPER:=TInt64Helper}
 {$define TORDINALTYPE:=Int64}
+{$define TORDINALBITINDEX:=TInt64BitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1606,6 +1613,7 @@
 
 {$define TORDINALHELPER:=TQWordHelper}
 {$define TORDINALTYPE:=QWord}
+{$define TORDINALBITINDEX:=TQwordBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1614,6 +1622,7 @@
 
 {$define TORDINALHELPER:=TNativeIntHelper}
 {$define TORDINALTYPE:=NativeInt}
+{$define TORDINALBITINDEX:=TNativeIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1622,6 +1631,7 @@
 
 {$define TORDINALHELPER:=TNativeUIntHelper}
 {$define TORDINALTYPE:=NativeUInt}
+{$define TORDINALBITINDEX:=TNativeUIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
Index: rtl/objpas/sysutils/syshelph.inc
===================================================================
--- rtl/objpas/sysutils/syshelph.inc	(revision 43151)
+++ rtl/objpas/sysutils/syshelph.inc	(working copy)
@@ -5,7 +5,18 @@
   TStringArray = Array of string;
   TCharArray = Array of char;
   TEndian = ObjPas.TEndian;
+  TByteBitIndex = 0..Pred(SizeOf(Byte));
+  TShortIntBitIndex = TByteBitIndex;
+  TWordBitIndex = 0..SizeOf(Word)-1;
+  TSmallIntBitIndex = TWordBitIndex;
+  TCardinalBitIndex = 0..Pred(SizeOf(Cardinal));
+  TIntegerBitIndex = TCardinalBitIndex;
+  TNativeUIntBitIndex = 0.. Pred(SizeOf(NativeUint));
+  TNativeIntBitIndex = TNativeUintBitIndex;
+  TQwordBitIndex = 0..Pred(SizeOf(Qword));
+  TInt64BitIndex = TQwordBitIndex;
   
+  
 Const
   CPUEndian = {$IFDEF FPC_LITTLE_ENDIAN}TEndian.Little{$ELSE}TEndian.Big{$ENDIF};
 
@@ -373,10 +384,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TByteBitIndex); inline;
+    Procedure ClearBit(const Index: TByteBitIndex); inline;
+    Procedure ToggleBit(const Index: TByteBitIndex); inline;
+    Function TestBit(const Index:TByteBitIndex):Boolean; inline;
   end;
 
   TShortIntHelper = Type Helper for ShortInt
@@ -393,10 +409,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TShortIntBitIndex); inline;
+    Procedure ClearBit(const Index: TShortIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TShortIntBitIndex); inline;
+    Function TestBit(const Index:TShortIntBitIndex):Boolean;
   end;
 
   TSmallIntHelper = Type Helper for SmallInt
@@ -412,11 +433,16 @@
   public
     Function ToString: string; overload; inline;
     Function ToBoolean: Boolean; inline;
+    Function ToBinString:string; inline;
     Function ToHexString: string; overload; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Procedure SetBit(const Index: TSmallIntBitIndex); inline;
+    Procedure ClearBit(const Index: TSmallIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TSmallIntBitIndex); inline;
+    Function TestBit(const Index:TSmallIntBitIndex):Boolean;    
   end;
 
   TWordHelper = Type Helper for Word
@@ -433,10 +459,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TWordBitIndex); inline;
+    Procedure ClearBit(const Index: TWordBitIndex); inline;
+    Procedure ToggleBit(const Index: TWordBitIndex); inline;
+    Function TestBit(const Index:TWordBitIndex):Boolean; inline;    
   end;
 
   TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
@@ -453,10 +484,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TCardinalBitIndex); inline;
+    Procedure ClearBit(const Index: TCardinalBitIndex); inline;
+    Procedure ToggleBit(const Index: TCardinalBitIndex); inline;
+    Function TestBit(const Index:TCardinalBitIndex):Boolean; inline;   
   end;
 
   TIntegerHelper = Type Helper for Integer { for LongInt Type too }
@@ -473,10 +509,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TIntegerBitIndex); inline;
+    Procedure ClearBit(const Index: TIntegerBitIndex); inline;
+    Procedure ToggleBit(const Index: TIntegerBitIndex); inline;
+    Function TestBit(const Index:TIntegerBitIndex):Boolean; inline;   
   end;
 
   TInt64Helper = Type Helper for Int64
@@ -493,10 +534,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TInt64BitIndex); inline;
+    Procedure ClearBit(const Index: TInt64BitIndex); inline;
+    Procedure ToggleBit(const Index: TInt64BitIndex); inline;
+    Function TestBit(const Index:TInt64BitIndex):Boolean; inline; 
   end;
 
   TQWordHelper = Type Helper for QWord
@@ -513,10 +559,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TQwordBitIndex); inline;
+    Procedure ClearBit(const Index: TQwordBitIndex); inline;
+    Procedure ToggleBit(const Index: TQwordBitIndex); inline;
+    Function TestBit(const Index:TQwordBitIndex):Boolean; inline; 
   end;
 
   TNativeIntHelper = Type Helper for NativeInt
@@ -533,10 +584,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TNativeIntBitIndex); inline;
+    Procedure ClearBit(const Index: TNativeIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TNativeIntBitIndex); inline;
+    Function TestBit(const Index:TNativeIntBitIndex):Boolean; inline; 
   end;
 
   TNativeUIntHelper = Type Helper for NativeUInt
@@ -553,10 +609,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TNativeUIntBitIndex); inline;
+    Procedure ClearBit(const Index: TNativeUIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TNativeUIntBitIndex); inline;
+    Function TestBit(const Index:TNativeUIntBitIndex):Boolean; inline; 
   end;
 
   {$SCOPEDENUMS ON}
Index: rtl/objpas/sysutils/syshelpo.inc
===================================================================
--- rtl/objpas/sysutils/syshelpo.inc	(revision 43151)
+++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
@@ -45,6 +45,12 @@
   Result:=Self;
 end;
 
+Function TORDINALHELPER.ToBinString: string; inline;
+
+begin
+  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
+end;
+
 Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
 overload; inline;
 
@@ -69,3 +75,27 @@
 begin
   Result:=IntToStr(Self);
 end;
+
+Procedure TORDINALHELPER.SetBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self := Self or (TORDINALTYPE(1) << index);
+end;
+
+Procedure TORDINALHELPER.ClearBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self:=Self and not (TORDINALTYPE(1) << index);
+end;
+
+Procedure TORDINALHELPER.ToggleBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self := Self xor (TORDINALTYPE(1) << index);
+end;
+
+Function TORDINALHELPER.TestBit(const Index: TORDINALBITINDEX):Boolean; inline;
+
+begin
+  Result := Self and (TORDINALTYPE(1) << index) <> 0;
+end;
bittests.pas (1,988 bytes)
program bittests;
{$mode delphi}{$H+}
{$assertions on}
uses sysutils;

var 
  i:byte;
  b:byte = 0;
  sh:ShortInt =0;
  w:word = 0;
  si:SmallInt = 0;
  c:Cardinal = 0;
  int:Integer = 0;
  ni:NativeInt = 0;
  nu:NativeUint = 0;
  i64:Int64 = 0;
  q:qword = 0;
begin
  for i:= 0 to  sizeof(Shortint)*8-1 do
  begin
    Assert(b.TestBit(i) = false);
    b.setbit(i);
    Assert(b.TestBit(Byte(i)) = true);
    writeln(b.ToBinString);
  end;

  for i := 0 to sizeof(Shortint)*8-1 do
  begin
    Assert(sh.TestBit(i) = false);
    sh.setbit(i);
    Assert(Sh.TestBit(Byte(i))= true);
    writeln(sh.ToBinString);
  end;

  for i := 0 to sizeof(Word)*8-1 do
  begin
    Assert(w.TestBit(i) = false);
    w.setbit(i);
    Assert(w.TestBit(i) = true);
    writeln(w.ToBinString);
  end;

  for i := 0 to sizeof(Smallint)*8-1 do
  begin
    Assert(si.TestBit(i) = false);
    si.setbit(i);
    Assert(si.TestBit(i) = true);
    writeln(si.ToBinString);
  end;

  for i := 0 to sizeof(Cardinal)*8-1 do
  begin
    Assert(c.TestBit(i) = false);
    c.setbit(i);
    Assert(c.TestBit(i) = true);
    writeln(c.ToBinString);
  end;

  for i := 0 to sizeof(integer)*8-1 do
  begin
    Assert(int.TestBit(int) = false);
    int.setbit(i);
    Assert(int.TestBit(i) = true);
    writeln(int.ToBinString);
  end;

  for i := 0 to sizeof(NativeInt)*8-1 do
  begin
    Assert(ni.TestBit(i) = false);
    ni.setbit(i);
    Assert(ni.TestBit(i) = true);
    writeln(ni.ToBinString);
  end;

  for i := 0 to sizeof(NativeUint)*8-1 do
  begin
    Assert(nu.TestBit(i) = false);
    nu.setbit(i);
    Assert(nu.TestBit(i) = true);
    writeln(nu.ToBinString);
  end;

  for i := 0 to sizeof(Int64)*8-1 do
  begin
    Assert(i64.TestBit(i) = false);
    i64.setbit(i);
    Assert(i64.TestBit(i) = true);
    writeln(i64.ToBinString);
  end;

  for i := 0 to sizeof(Qword)*8-1 do
  begin
    Assert(q.TestBit(i) = false);
    q.setbit(i);
    Assert(q.TestBit(i) = true);
    writeln(q.ToBinString);
  end;
end.
bittests.pas (1,988 bytes)

Thaddy de Koning

2019-10-08 12:36

reporter   ~0118411

Last edited: 2019-10-08 12:42

View 3 revisions

For documentation purposes, this is what is does:

Bit operator extensions to ordinal type helpers
-----------------------------------------------
These methods extend the type helpers for ordinal types to
support bitwise manipulation of the ordinal type.

The type helpers now add support for:
- Setting an arbitrary bit in an ordinal
- Clearing an arbitrary bit in an ordinal
- Toggling an arbitrary bit in an ordinal
- Testing if an arbitrary bit in an ordinal is set
- The ordinal type can return the bit pattern of an ordinal as a string

Only ordinals that have type helpers in sysutils are supported, except for Boolean (which is also an ordinal).

Thaddy de Koning

2019-10-08 14:07

reporter   ~0118417

Last edited: 2019-10-08 14:08

View 2 revisions

Sorry Michael, here is a test version without asserts:

Thaddy de Koning

2019-10-08 14:09

reporter  

bittests2.pas (2,147 bytes)
program bittests;
{$mode objfpc}{$H+}
{$assertions on}
uses sysutils;

var 
  i:integer;
  b:byte = 0;
  sh:ShortInt =0;
  w:word = 0;
  si:SmallInt = 0;
  c:Cardinal = 0;
  int:Integer = 0;
  ni:NativeInt = 0;
  nu:NativeUint = 0;
  i64:Int64 = 0;
  q:qword = 0;
begin
  for i:= 0 to  sizeof(Byte)*8-1 do
  begin
    if b.TestBit(i) = true then Halt(1);
    b.setbit(i);
    if b.TestBit(i) = false then Halt(2);
    writeln(b.ToBinString);
  end;

  for i := 0 to sizeof(Shortint)*8-1 do
  begin
    if sh.TestBit(i) = true then Halt(3);
    sh.setbit(i);
    if Sh.TestBit(i) = false then Halt(4);
    writeln(sh.ToBinString);
  end;

  for i := 0 to sizeof(Word)*8-1 do
  begin
    if w.TestBit(i) = true then Halt(5);
    w.setbit(i);
    if w.TestBit(i) = false then halt(6);
    writeln(w.ToBinString);
  end;

  for i := 0 to sizeof(Smallint)*8-1 do
  begin
    if si.TestBit(i) = true then Halt(7);
    si.setbit(i);
    if si.TestBit(i) = false then Halt(8);
    writeln(si.ToBinString);
  end;

  for i := 0 to sizeof(Cardinal)*8-1 do
  begin
    if c.TestBit(i) = true then Halt(9);
    c.setbit(i);
    if c.TestBit(i) = false then Halt(10);
    writeln(c.ToBinString);
  end;

  for i := 0 to sizeof(integer)*8-1 do
  begin
    if int.TestBit(int) = true then Halt(11);
    int.setbit(i);
    if int.TestBit(i) = false then Halt(12);
    writeln(int.ToBinString);
  end;

  for i := 0 to sizeof(NativeInt)*8-1 do
  begin
    if ni.TestBit(i) = true then Halt(13);
    ni.setbit(i);
    if ni.TestBit(i) = false then Halt(14);
    writeln(ni.ToBinString);
  end;

  for i := 0 to sizeof(NativeUint)*8-1 do
  begin
    if nu.TestBit(i) = true then Halt(15);
    nu.setbit(i);
    if nu.TestBit(i) = false then Halt(16);
    writeln(nu.ToBinString);
  end;

  for i := 0 to sizeof(Int64)*8-1 do
  begin
    if i64.TestBit(i) = true then Halt(17);
    i64.setbit(i);
    if i64.TestBit(i) = false then Halt(18);
    writeln(i64.ToBinString);
  end;

  for i := 0 to sizeof(Qword)*8-1 do
  begin
    if q.TestBit(i) = true then Halt(19);
    q.setbit(i);
    if q.TestBit(i) = false then Halt(20);
    writeln(q.ToBinString);
  end;
end.
bittests2.pas (2,147 bytes)

Thaddy de Koning

2019-10-09 17:50

reporter   ~0118451

My tests showed a range error (I tried to avoid just that) which I have fixed. So new patch and here a small demo.

uses sysutils;
var a:qword = 0;
begin
  writeln(a.ToBinString);
  a.setbit(63);
  writeln(a.ToBinString);
  writeln(a);
  a.Togglebit(1);
  writeln(a.ToBinString);
  writeln(a.testbit(1));
  writeln(a);
  a.Togglebit(1);
  writeln(a.ToBinString);
  writeln(a.testbit(1));
  a.clearbit(4);
  writeln(a.ToBinString);
  writeln(a.testbit(1));
  writeln(High(TQwordBitIndex)); // should be 63
end.

I hope you can now apply it, because it is very useful to me.

ordinalbitshelper4.patch (11,871 bytes)
Index: rtl/objpas/sysutils/syshelp.inc
===================================================================
--- rtl/objpas/sysutils/syshelp.inc	(revision 43156)
+++ rtl/objpas/sysutils/syshelp.inc	(working copy)
@@ -1550,6 +1550,7 @@
 
 {$define TORDINALHELPER:=TByteHelper}
 {$define TORDINALTYPE:=Byte}
+{$define TORDINALBITINDEX:=TByteBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1558,6 +1559,7 @@
 
 {$define TORDINALHELPER:=TShortIntHelper}
 {$define TORDINALTYPE:=ShortInt}
+{$define TORDINALBITINDEX:=TShortIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1566,6 +1568,7 @@
 
 {$define TORDINALHELPER:=TSmallIntHelper}
 {$define TORDINALTYPE:=SmallInt}
+{$define TORDINALBITINDEX:=TSmallIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1574,6 +1577,7 @@
 
 {$define TORDINALHELPER:=TWordHelper}
 {$define TORDINALTYPE:=Word}
+{$define TORDINALBITINDEX:=TWordBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1582,6 +1586,7 @@
 
 {$define TORDINALHELPER:=TCardinalHelper}
 {$define TORDINALTYPE:=Cardinal}
+{$define TORDINALBITINDEX:=TCardinalBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1590,6 +1595,7 @@
 
 {$define TORDINALHELPER:=TIntegerHelper}
 {$define TORDINALTYPE:=Integer}
+{$define TORDINALBITINDEX:=TIntegerBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1598,6 +1604,7 @@
 
 {$define TORDINALHELPER:=TInt64Helper}
 {$define TORDINALTYPE:=Int64}
+{$define TORDINALBITINDEX:=TInt64BitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1606,6 +1613,7 @@
 
 {$define TORDINALHELPER:=TQWordHelper}
 {$define TORDINALTYPE:=QWord}
+{$define TORDINALBITINDEX:=TQwordBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1614,6 +1622,7 @@
 
 {$define TORDINALHELPER:=TNativeIntHelper}
 {$define TORDINALTYPE:=NativeInt}
+{$define TORDINALBITINDEX:=TNativeIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1622,6 +1631,7 @@
 
 {$define TORDINALHELPER:=TNativeUIntHelper}
 {$define TORDINALTYPE:=NativeUInt}
+{$define TORDINALBITINDEX:=TNativeUIntBitIndex}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
Index: rtl/objpas/sysutils/syshelph.inc
===================================================================
--- rtl/objpas/sysutils/syshelph.inc	(revision 43156)
+++ rtl/objpas/sysutils/syshelph.inc	(working copy)
@@ -5,7 +5,18 @@
   TStringArray = Array of string;
   TCharArray = Array of char;
   TEndian = ObjPas.TEndian;
+  TByteBitIndex = 0..Pred(SizeOf(Byte) * 8);
+  TShortIntBitIndex = TByteBitIndex;
+  TWordBitIndex = 0..pred(SizeOf(Word) * 8);
+  TSmallIntBitIndex = TWordBitIndex;
+  TCardinalBitIndex = 0..Pred(SizeOf(Cardinal) * 8);
+  TIntegerBitIndex = TCardinalBitIndex;
+  TNativeUIntBitIndex = 0.. Pred(SizeOf(NativeUint) * 8);
+  TNativeIntBitIndex = TNativeUintBitIndex;
+  TQwordBitIndex = 0..Pred(SizeOf(Qword) * 8);
+  TInt64BitIndex = TQwordBitIndex;
   
+  
 Const
   CPUEndian = {$IFDEF FPC_LITTLE_ENDIAN}TEndian.Little{$ELSE}TEndian.Big{$ENDIF};
 
@@ -373,10 +384,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TByteBitIndex); inline;
+    Procedure ClearBit(const Index: TByteBitIndex); inline;
+    Procedure ToggleBit(const Index: TByteBitIndex); inline;
+    Function TestBit(const Index:TByteBitIndex):Boolean; inline;
   end;
 
   TShortIntHelper = Type Helper for ShortInt
@@ -393,10 +409,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TShortIntBitIndex); inline;
+    Procedure ClearBit(const Index: TShortIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TShortIntBitIndex); inline;
+    Function TestBit(const Index:TShortIntBitIndex):Boolean;
   end;
 
   TSmallIntHelper = Type Helper for SmallInt
@@ -412,11 +433,16 @@
   public
     Function ToString: string; overload; inline;
     Function ToBoolean: Boolean; inline;
+    Function ToBinString:string; inline;
     Function ToHexString: string; overload; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Procedure SetBit(const Index: TSmallIntBitIndex); inline;
+    Procedure ClearBit(const Index: TSmallIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TSmallIntBitIndex); inline;
+    Function TestBit(const Index:TSmallIntBitIndex):Boolean;    
   end;
 
   TWordHelper = Type Helper for Word
@@ -433,10 +459,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TWordBitIndex); inline;
+    Procedure ClearBit(const Index: TWordBitIndex); inline;
+    Procedure ToggleBit(const Index: TWordBitIndex); inline;
+    Function TestBit(const Index:TWordBitIndex):Boolean; inline;    
   end;
 
   TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
@@ -453,10 +484,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TCardinalBitIndex); inline;
+    Procedure ClearBit(const Index: TCardinalBitIndex); inline;
+    Procedure ToggleBit(const Index: TCardinalBitIndex); inline;
+    Function TestBit(const Index:TCardinalBitIndex):Boolean; inline;   
   end;
 
   TIntegerHelper = Type Helper for Integer { for LongInt Type too }
@@ -473,10 +509,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TIntegerBitIndex); inline;
+    Procedure ClearBit(const Index: TIntegerBitIndex); inline;
+    Procedure ToggleBit(const Index: TIntegerBitIndex); inline;
+    Function TestBit(const Index:TIntegerBitIndex):Boolean; inline;   
   end;
 
   TInt64Helper = Type Helper for Int64
@@ -493,10 +534,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TInt64BitIndex); inline;
+    Procedure ClearBit(const Index: TInt64BitIndex); inline;
+    Procedure ToggleBit(const Index: TInt64BitIndex); inline;
+    Function TestBit(const Index:TInt64BitIndex):Boolean; inline; 
   end;
 
   TQWordHelper = Type Helper for QWord
@@ -513,10 +559,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TQwordBitIndex); inline;
+    Procedure ClearBit(const Index: TQwordBitIndex); inline;
+    Procedure ToggleBit(const Index: TQwordBitIndex); inline;
+    Function TestBit(const Index:TQwordBitIndex):Boolean; inline; 
   end;
 
   TNativeIntHelper = Type Helper for NativeInt
@@ -533,10 +584,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TNativeIntBitIndex); inline;
+    Procedure ClearBit(const Index: TNativeIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TNativeIntBitIndex); inline;
+    Function TestBit(const Index:TNativeIntBitIndex):Boolean; inline; 
   end;
 
   TNativeUIntHelper = Type Helper for NativeUInt
@@ -553,10 +609,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TNativeUIntBitIndex); inline;
+    Procedure ClearBit(const Index: TNativeUIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TNativeUIntBitIndex); inline;
+    Function TestBit(const Index:TNativeUIntBitIndex):Boolean; inline; 
   end;
 
   {$SCOPEDENUMS ON}
Index: rtl/objpas/sysutils/syshelpo.inc
===================================================================
--- rtl/objpas/sysutils/syshelpo.inc	(revision 43156)
+++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
@@ -45,6 +45,12 @@
   Result:=Self;
 end;
 
+Function TORDINALHELPER.ToBinString: string; inline;
+
+begin
+  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
+end;
+
 Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
 overload; inline;
 
@@ -69,3 +75,27 @@
 begin
   Result:=IntToStr(Self);
 end;
+
+Procedure TORDINALHELPER.SetBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self := Self or (TORDINALTYPE(1) << index);
+end;
+
+Procedure TORDINALHELPER.ClearBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self:=Self and not (TORDINALTYPE(1) << index);
+end;
+
+Procedure TORDINALHELPER.ToggleBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self := Self xor (TORDINALTYPE(1) << index);
+end;
+
+Function TORDINALHELPER.TestBit(const Index: TORDINALBITINDEX):Boolean; inline;
+
+begin
+  Result := Self and (TORDINALTYPE(1) << index) <> 0;
+end;
ordinalbitshelper4.patch (11,871 bytes)

Michael Van Canneyt

2019-10-09 18:01

administrator   ~0118452

Thaddy, the main obstruction to applying a patch like this is time. I will check it out during the weekend.

Thaddy de Koning

2019-10-09 19:36

reporter   ~0118453

I understand. Some people have a day job ;)

Bart Broersma

2019-10-10 14:38

reporter   ~0118462

Last edited: 2019-10-10 14:45

View 3 revisions

As reported on the forum (https://forum.lazarus.freepascal.org/index.php/topic,47020.msg335943.html#msg335943)

AShortInt.SetBit(7) gives rangecheckerror.
ASmallInt.SetBit(15) gives rangecheckerror.
At compiletime Integer.SetBit(31) (where 31 is a constant) gives rangecheck error, while at runtime (31 being a variable) this does not happen.

Same goes for ToggleBit().

Bart Broersma

2019-10-10 15:25

reporter   ~0118463

Possible fix suggested in the same forum thread.

Thaddy de Koning

2019-10-10 16:37

reporter   ~0118464

@Bart
In trunk this does *not* have rangecheck errors.
It only does with the factored out code for lower FPC versions:

{$mode delphi}{$H+}{$rangechecks on}
uses sysutils;
var a:shortint = 0;
begin
  a.setbit(7);
  writeln(a);
end.

No errors on any 64 or 32 bit platform.
For the purpose of the patch is it not relevant.
For a factored out version for previous versions of FPC as on the forum it is.

Bart Broersma

2019-10-10 23:02

reporter   ~0118482

TIntegerBitIndex = TCardinalBitIndex;

Is that also the case on 16-bit platform?

Bart Broersma

2019-10-10 23:07

reporter   ~0118483

> In trunk this does *not* have rangecheck errors.
> It only does with the factored out code for lower FPC versions

Yes, the test run fine.
I'll upload my test program.

Bart Broersma

2019-10-10 23:29

reporter   ~0118485

Last edited: 2019-10-10 23:38

View 2 revisions

Still some compilation errors:

{$mode objfpc}
uses
  sysutils;
var
  LI: Integer;
  NI: NativeInt;

...
begin
  LI.SetBit(31); //compiler error on 32 and 64-bit: Range check error while evaluating constants (2147483648 must be between -2147483648 and 2147483647)
  NI.SetBit(31); //compiler error on 32-bit: Range check error while evaluating constants (2147483648 must be between -2147483648 and 2147483647)
end.

Bart Broersma

2019-10-11 00:14

reporter  

testbits.zip (10,872 bytes)

Bart Broersma

2019-10-11 22:44

reporter   ~0118497

Last edited: 2019-10-11 22:51

View 2 revisions

There is another problem with the range defines.
Sysutils is compiled in {$mode objfpc}.
This will make TIntegerBitIndex 0..31 always.

However if a user uses the TIntegerBitIndex as a range for an array (as does my test program), this will no longer work if he/she compiles his program in {$mode tp} or {$mode fpc}, since for these modes Integer = SmallInt and the range now should only be 0..15.
For that reason my attached test program did not compile in those 2 modes.

The same may be true for TNativeUIntBitIndex and TNativeIntBitIndex because "on i8086 their size changes between 16-bit and 32-bit according to the memory model" (quote from rtl/inc/systemh.inc.

Using those pre-defined constants gives the user a false sense of security when using these (otherwise really helpfull) "bithelpers".

I adapted my test program (it now duplicates the defines), so that it compiles in every mode (and passes).

Bart Broersma

2019-10-11 22:50

reporter  

testbits2.zip (11,182 bytes)

jamie philbrook

2019-10-12 01:39

reporter   ~0118499

While you guys are working on the bit problems here you may want to take note of the fact that I discovered a helper problem with the Qword and Int64 in the 64 bit 2.0.4 release for windows using fpc 3.0.4.

 The helpers report 32 bit values instead of their 64 bit typed values.

 Maybe a closer look at these helpers to fix some overlooked errors may help fix the bit problems here?

jamie philbrook

2019-10-12 03:18

reporter   ~0118501

Apparently this has been fixed in fpc 3.3.x

 I feel sorry for the rest of us that don't want to use fluxing software that changes like my wife's attitude from day to day!

Thaddy de Koning

2019-10-12 13:55

reporter   ~0118512

New patch based on information from Bart, but not equal to it.
Also added a small test for the signed integer limits.
All tests including Bart's now verify correct.

testbug.pas (1,327 bytes)
program untitled;
{$mode delphi}{$H+}{$rangechecks on}
uses sysutils;
var 
  a:Shortint = 0;
  b:SmallInt = 0;
  c:Integer = 0;
  d:NativeInt = 0;
  e:Int64 = 0;
begin
  a.setbit(7);
  writeln('1:',a.tobinstring:64, a.testbit(7):7);
  b.setbit(15);
  writeln('2:',b.tobinstring:64, b.testbit(15):7);
  c.setbit(31);
  writeln('3:',c.tobinstring:64, c.testbit(31):7);
  d.setbit(SizeOf(NativeInt)* 8 -1);
  writeln('4:',d.tobinstring:64,d.testbit(SizeOf(NativeInt)* 8 - 1):7);
  e.setbit(63);
  writeln('5:',e.tobinstring:64,e.testbit(63):7);
  a.clearbit(7);
  writeln('1:',a.tobinstring:64, a.testbit(7):7);
  b.clearbit(15);
  writeln('2:',b.tobinstring:64, b.testbit(15):7);
  c.clearbit(31);
  writeln('3:',c.tobinstring:64, c.testbit(31):7);
  d.clearbit(SizeOf(NativeInt)* 8 -1);
  writeln('4:',d.tobinstring:64, d.testbit(SizeOf(NativeInt)* 8 - 1):7);
  e.clearbit(63);
  writeln('5:',e.tobinstring:64, e.testbit(63):7);
  a.togglebit(7);
  writeln('1:',a.tobinstring:64, a.testbit(7):7);
  b.togglebit(15);
  writeln('2:',b.tobinstring:64, b.testbit(15):7);
  c.togglebit(31);
  writeln('3:',c.tobinstring:64, c.testbit(31):7);
  d.togglebit(SizeOf(NativeInt)* 8 -1);
  writeln('4:',d.tobinstring:64, d.testbit(SizeOf(NativeInt) * 8 - 1):7);
  e.togglebit(63);
  writeln('5:',e.tobinstring:64, e.testbit(63):7);  
end.
testbug.pas (1,327 bytes)
ordinalbithelpers-20191012.patch (12,251 bytes)
Index: rtl/objpas/sysutils/syshelp.inc
===================================================================
--- rtl/objpas/sysutils/syshelp.inc	(revision 43168)
+++ rtl/objpas/sysutils/syshelp.inc	(working copy)
@@ -1550,6 +1550,8 @@
 
 {$define TORDINALHELPER:=TByteHelper}
 {$define TORDINALTYPE:=Byte}
+{$define TORDINALBITINDEX:=TByteBitIndex}
+{$define TUNSIGNED:=Byte}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1558,6 +1560,8 @@
 
 {$define TORDINALHELPER:=TShortIntHelper}
 {$define TORDINALTYPE:=ShortInt}
+{$define TORDINALBITINDEX:=TShortIntBitIndex}
+{$define TUNSIGNED:=Byte}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1566,6 +1570,8 @@
 
 {$define TORDINALHELPER:=TSmallIntHelper}
 {$define TORDINALTYPE:=SmallInt}
+{$define TORDINALBITINDEX:=TSmallIntBitIndex}
+{$define TUNSIGNED:=Word}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1574,6 +1580,8 @@
 
 {$define TORDINALHELPER:=TWordHelper}
 {$define TORDINALTYPE:=Word}
+{$define TORDINALBITINDEX:=TWordBitIndex}
+{$define TUNSIGNED:=Word}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1582,6 +1590,8 @@
 
 {$define TORDINALHELPER:=TCardinalHelper}
 {$define TORDINALTYPE:=Cardinal}
+{$define TORDINALBITINDEX:=TCardinalBitIndex}
+{$define TUNSIGNED:=Cardinal}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1590,6 +1600,8 @@
 
 {$define TORDINALHELPER:=TIntegerHelper}
 {$define TORDINALTYPE:=Integer}
+{$define TORDINALBITINDEX:=TIntegerBitIndex}
+{$define TUNSIGNED:=Cardinal}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1598,6 +1610,8 @@
 
 {$define TORDINALHELPER:=TInt64Helper}
 {$define TORDINALTYPE:=Int64}
+{$define TORDINALBITINDEX:=TInt64BitIndex}
+{$define TUNSIGNED:=Qword}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1606,6 +1620,8 @@
 
 {$define TORDINALHELPER:=TQWordHelper}
 {$define TORDINALTYPE:=QWord}
+{$define TORDINALBITINDEX:=TQwordBitIndex}
+{$define TUNSIGNED:=Qword}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1614,6 +1630,8 @@
 
 {$define TORDINALHELPER:=TNativeIntHelper}
 {$define TORDINALTYPE:=NativeInt}
+{$define TORDINALBITINDEX:=TNativeIntBitIndex}
+{$define TUNSIGNED:=NativeUInt}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1622,6 +1640,8 @@
 
 {$define TORDINALHELPER:=TNativeUIntHelper}
 {$define TORDINALTYPE:=NativeUInt}
+{$define TORDINALBITINDEX:=TNativeUIntBitIndex}
+{$define TUNSIGNED:=NativeUInt}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
Index: rtl/objpas/sysutils/syshelph.inc
===================================================================
--- rtl/objpas/sysutils/syshelph.inc	(revision 43168)
+++ rtl/objpas/sysutils/syshelph.inc	(working copy)
@@ -5,7 +5,18 @@
   TStringArray = Array of string;
   TCharArray = Array of char;
   TEndian = ObjPas.TEndian;
+  TByteBitIndex = 0..Pred(SizeOf(Byte) * 8);
+  TShortIntBitIndex = TByteBitIndex;
+  TWordBitIndex = 0..pred(SizeOf(Word) * 8);
+  TSmallIntBitIndex = TWordBitIndex;
+  TCardinalBitIndex = 0..Pred(SizeOf(Cardinal) * 8);
+  TIntegerBitIndex = TCardinalBitIndex;
+  TNativeUIntBitIndex = 0.. Pred(SizeOf(NativeUint) * 8);
+  TNativeIntBitIndex = TNativeUintBitIndex;
+  TQwordBitIndex = 0..Pred(SizeOf(Qword) * 8);
+  TInt64BitIndex = TQwordBitIndex;
   
+  
 Const
   CPUEndian = {$IFDEF FPC_LITTLE_ENDIAN}TEndian.Little{$ELSE}TEndian.Big{$ENDIF};
 
@@ -373,10 +384,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TByteBitIndex); inline;
+    Procedure ClearBit(const Index: TByteBitIndex); inline;
+    Procedure ToggleBit(const Index: TByteBitIndex); inline;
+    Function TestBit(const Index:TByteBitIndex):Boolean; inline;
   end;
 
   TShortIntHelper = Type Helper for ShortInt
@@ -393,10 +409,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TShortIntBitIndex); inline;
+    Procedure ClearBit(const Index: TShortIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TShortIntBitIndex); inline;
+    Function TestBit(const Index:TShortIntBitIndex):Boolean;
   end;
 
   TSmallIntHelper = Type Helper for SmallInt
@@ -412,11 +433,16 @@
   public
     Function ToString: string; overload; inline;
     Function ToBoolean: Boolean; inline;
+    Function ToBinString:string; inline;
     Function ToHexString: string; overload; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Procedure SetBit(const Index: TSmallIntBitIndex); inline;
+    Procedure ClearBit(const Index: TSmallIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TSmallIntBitIndex); inline;
+    Function TestBit(const Index:TSmallIntBitIndex):Boolean;    
   end;
 
   TWordHelper = Type Helper for Word
@@ -433,10 +459,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TWordBitIndex); inline;
+    Procedure ClearBit(const Index: TWordBitIndex); inline;
+    Procedure ToggleBit(const Index: TWordBitIndex); inline;
+    Function TestBit(const Index:TWordBitIndex):Boolean; inline;    
   end;
 
   TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
@@ -453,10 +484,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TCardinalBitIndex); inline;
+    Procedure ClearBit(const Index: TCardinalBitIndex); inline;
+    Procedure ToggleBit(const Index: TCardinalBitIndex); inline;
+    Function TestBit(const Index:TCardinalBitIndex):Boolean; inline;   
   end;
 
   TIntegerHelper = Type Helper for Integer { for LongInt Type too }
@@ -473,10 +509,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TIntegerBitIndex); inline;
+    Procedure ClearBit(const Index: TIntegerBitIndex); inline;
+    Procedure ToggleBit(const Index: TIntegerBitIndex); inline;
+    Function TestBit(const Index:TIntegerBitIndex):Boolean; inline;   
   end;
 
   TInt64Helper = Type Helper for Int64
@@ -493,10 +534,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TInt64BitIndex); inline;
+    Procedure ClearBit(const Index: TInt64BitIndex); inline;
+    Procedure ToggleBit(const Index: TInt64BitIndex); inline;
+    Function TestBit(const Index:TInt64BitIndex):Boolean; inline; 
   end;
 
   TQWordHelper = Type Helper for QWord
@@ -513,10 +559,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TQwordBitIndex); inline;
+    Procedure ClearBit(const Index: TQwordBitIndex); inline;
+    Procedure ToggleBit(const Index: TQwordBitIndex); inline;
+    Function TestBit(const Index:TQwordBitIndex):Boolean; inline; 
   end;
 
   TNativeIntHelper = Type Helper for NativeInt
@@ -533,10 +584,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TNativeIntBitIndex); inline;
+    Procedure ClearBit(const Index: TNativeIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TNativeIntBitIndex); inline;
+    Function TestBit(const Index:TNativeIntBitIndex):Boolean; inline; 
   end;
 
   TNativeUIntHelper = Type Helper for NativeUInt
@@ -553,10 +609,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Procedure SetBit(const Index: TNativeUIntBitIndex); inline;
+    Procedure ClearBit(const Index: TNativeUIntBitIndex); inline;
+    Procedure ToggleBit(const Index: TNativeUIntBitIndex); inline;
+    Function TestBit(const Index:TNativeUIntBitIndex):Boolean; inline; 
   end;
 
   {$SCOPEDENUMS ON}
Index: rtl/objpas/sysutils/syshelpo.inc
===================================================================
--- rtl/objpas/sysutils/syshelpo.inc	(revision 43168)
+++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
@@ -45,6 +45,12 @@
   Result:=Self;
 end;
 
+Function TORDINALHELPER.ToBinString: string; inline;
+
+begin
+  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
+end;
+
 Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
 overload; inline;
 
@@ -69,3 +75,27 @@
 begin
   Result:=IntToStr(Self);
 end;
+
+Procedure TORDINALHELPER.SetBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self := TORDINALTYPE(TUNSIGNED(Self) or TUNSIGNED(1) shl index);
+end;
+
+Procedure TORDINALHELPER.ClearBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self:=TORDINALTYPE(TUNSIGNED(Self) and not TUNSIGNED(1) shl index);
+end;
+
+Procedure TORDINALHELPER.ToggleBit(const index: TORDINALBITINDEX); inline;
+
+begin
+  Self := TORDINALTYPE(TUNSIGNED(Self) xor (TUNSIGNED(1) shl index));
+end;
+
+Function TORDINALHELPER.TestBit(const Index: TORDINALBITINDEX):Boolean; inline;
+
+begin
+  Result := TORDINALTYPE(TUNSIGNED(Self) and (TUNSIGNED(1) shl index)) <> 0;
+end;

Thaddy de Koning

2019-10-13 08:56

reporter   ~0118545

PUT ON HOLD PLZ
I discovered some errors in Bart's testcode depending on mode (e.g. %0101010101010101 in mode delphi/tp fails)
I also discovered some additional problems with integer sizes that I only partially solved.
Means I have to rethink if the type safe ranges are worth it.

Michael Van Canneyt

2019-10-13 09:08

administrator   ~0118546

I don't see any value in the type safe ranges. A byte-typed index, plus a check inside the routines is equally good.

This has the advantage that you'll get an error even with range checks off.

I don't think I have ever enabled range checks when compiling.

Thaddy de Koning

2019-10-13 09:45

reporter   ~0118550

OK. Will do that. There is after all a similar issue already present in the class functions TORDINALHELPER.Size

Thaddy de Koning

2019-10-13 14:23

reporter   ~0118563

Changed design:
- simple integer index
- internal evaluation
- all are now Boolean functions ( no exceptions, like TryXXX and family)
- tested modes fpc, objfpc and delphi on 32 bit arm-linux and 32/64 bit windows.
- New test added.

ordinalbithelpers-20191013.patch (11,114 bytes)
Index: rtl/objpas/sysutils/syshelp.inc
===================================================================
--- rtl/objpas/sysutils/syshelp.inc	(revision 43182)
+++ rtl/objpas/sysutils/syshelp.inc	(working copy)
@@ -1550,6 +1550,7 @@
 
 {$define TORDINALHELPER:=TByteHelper}
 {$define TORDINALTYPE:=Byte}
+{$define TUNSIGNED:=Byte}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1558,6 +1559,7 @@
 
 {$define TORDINALHELPER:=TShortIntHelper}
 {$define TORDINALTYPE:=ShortInt}
+{$define TUNSIGNED:=Byte}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1566,6 +1568,7 @@
 
 {$define TORDINALHELPER:=TSmallIntHelper}
 {$define TORDINALTYPE:=SmallInt}
+{$define TUNSIGNED:=Word}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1574,6 +1577,7 @@
 
 {$define TORDINALHELPER:=TWordHelper}
 {$define TORDINALTYPE:=Word}
+{$define TUNSIGNED:=Word}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1582,6 +1586,7 @@
 
 {$define TORDINALHELPER:=TCardinalHelper}
 {$define TORDINALTYPE:=Cardinal}
+{$define TUNSIGNED:=Cardinal}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1590,6 +1595,7 @@
 
 {$define TORDINALHELPER:=TIntegerHelper}
 {$define TORDINALTYPE:=Integer}
+{$define TUNSIGNED:=Cardinal}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1598,6 +1604,7 @@
 
 {$define TORDINALHELPER:=TInt64Helper}
 {$define TORDINALTYPE:=Int64}
+{$define TUNSIGNED:=Qword}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1606,6 +1613,7 @@
 
 {$define TORDINALHELPER:=TQWordHelper}
 {$define TORDINALTYPE:=QWord}
+{$define TUNSIGNED:=Qword}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1614,6 +1622,7 @@
 
 {$define TORDINALHELPER:=TNativeIntHelper}
 {$define TORDINALTYPE:=NativeInt}
+{$define TUNSIGNED:=NativeUInt}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
@@ -1622,6 +1631,7 @@
 
 {$define TORDINALHELPER:=TNativeUIntHelper}
 {$define TORDINALTYPE:=NativeUInt}
+{$define TUNSIGNED:=NativeUInt}
 {$i syshelpo.inc}
 
 { ---------------------------------------------------------------------
Index: rtl/objpas/sysutils/syshelph.inc
===================================================================
--- rtl/objpas/sysutils/syshelph.inc	(revision 43182)
+++ rtl/objpas/sysutils/syshelph.inc	(working copy)
@@ -373,10 +373,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Function SetBit(const Index: integer):Boolean; inline;
+    Function ClearBit(const Index: integer):Boolean; inline;
+    Function ToggleBit(const Index: integer):Boolean; inline;
+    Function TestBit(const Index:integer):Boolean; inline;
   end;
 
   TShortIntHelper = Type Helper for ShortInt
@@ -393,10 +398,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Function SetBit(const Index: integer):Boolean; inline;
+    Function ClearBit(const Index: integer):Boolean; inline;
+    Function ToggleBit(const Index: integer):Boolean; inline;
+    Function TestBit(const Index:integer):Boolean;
   end;
 
   TSmallIntHelper = Type Helper for SmallInt
@@ -412,11 +422,16 @@
   public
     Function ToString: string; overload; inline;
     Function ToBoolean: Boolean; inline;
+    Function ToBinString:string; inline;
     Function ToHexString: string; overload; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function SetBit(const Index: integer):Boolean; inline;
+    Function ClearBit(const Index: integer):Boolean; inline;
+    Function ToggleBit(const Index: integer):Boolean; inline;
+    Function TestBit(const Index:integer):Boolean;    
   end;
 
   TWordHelper = Type Helper for Word
@@ -433,10 +448,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Function SetBit(const Index: integer):Boolean; inline;
+    Function ClearBit(const Index: integer):Boolean; inline;
+    Function ToggleBit(const Index: integer):Boolean; inline;
+    Function TestBit(const Index:integer):Boolean; inline;    
   end;
 
   TCardinalHelper = Type Helper for Cardinal { for LongWord Type too }
@@ -453,10 +473,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Function SetBit(const Index: integer):Boolean; inline;
+    Function ClearBit(const Index: integer):Boolean; inline;
+    Function ToggleBit(const Index: integer):Boolean; inline;
+    Function TestBit(const Index:integer):Boolean; inline;   
   end;
 
   TIntegerHelper = Type Helper for Integer { for LongInt Type too }
@@ -473,10 +498,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Function SetBit(const Index: integer):Boolean; inline;
+    Function ClearBit(const Index: integer):Boolean; inline;
+    Function ToggleBit(const Index: integer):Boolean; inline;
+    Function TestBit(const Index:integer):Boolean; inline;   
   end;
 
   TInt64Helper = Type Helper for Int64
@@ -493,10 +523,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Function SetBit(const Index: integer):Boolean; inline;
+    Function ClearBit(const Index: integer):Boolean; inline;
+    Function ToggleBit(const Index: integer):Boolean; inline;
+    Function TestBit(const Index:integer):Boolean; inline; 
   end;
 
   TQWordHelper = Type Helper for QWord
@@ -513,10 +548,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Function SetBit(const Index: integer):Boolean; inline;
+    Function ClearBit(const Index: integer):Boolean; inline;
+    Function ToggleBit(const Index: integer):Boolean; inline;
+    Function TestBit(const Index:integer):Boolean; inline; 
   end;
 
   TNativeIntHelper = Type Helper for NativeInt
@@ -533,10 +573,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Function SetBit(const Index: integer):Boolean; inline;
+    Function ClearBit(const Index: integer):Boolean; inline;
+    Function ToggleBit(const Index: integer):Boolean; inline;
+    Function TestBit(const Index:integer):Boolean; inline; 
   end;
 
   TNativeUIntHelper = Type Helper for NativeUInt
@@ -553,10 +598,15 @@
     Function ToBoolean: Boolean; inline;
     Function ToDouble: Double; inline;
     Function ToExtended: Extended; inline;
+    Function ToBinString:string; inline;
     Function ToHexString(const AMinDigits: Integer): string; overload; inline;
     Function ToHexString: string; overload; inline;
     Function ToSingle: Single; inline;
     Function ToString: string; overload; inline;
+    Function SetBit(const Index: integer):Boolean; inline;
+    Function ClearBit(const Index: integer):Boolean; inline;
+    Function ToggleBit(const Index: integer):Boolean; inline;
+    Function TestBit(const Index:integer):Boolean; inline; 
   end;
 
   {$SCOPEDENUMS ON}
Index: rtl/objpas/sysutils/syshelpo.inc
===================================================================
--- rtl/objpas/sysutils/syshelpo.inc	(revision 43182)
+++ rtl/objpas/sysutils/syshelpo.inc	(working copy)
@@ -45,6 +45,12 @@
   Result:=Self;
 end;
 
+Function TORDINALHELPER.ToBinString: string; inline;
+
+begin
+  Result:=BinStr(Self,SizeOf(TORDINALTYPE)*8);
+end;
+
 Function TORDINALHELPER.ToHexString(const AMinDigits: Integer): string;
 overload; inline;
 
@@ -69,3 +75,31 @@
 begin
   Result:=IntToStr(Self);
 end;
+
+function TORDINALHELPER.SetBit(const index: integer):Boolean; inline;
+
+begin
+  Self := TORDINALTYPE(TUNSIGNED(Self) or TUNSIGNED(1) shl index);
+  Result := TestBit(Index) = true;
+end;
+
+function TORDINALHELPER.ClearBit(const index: integer):Boolean; inline;
+
+begin
+  Self:=TORDINALTYPE(TUNSIGNED(Self) and not TUNSIGNED(1) shl index);
+  Result := TestBit(Index) = false;
+end;
+
+function TORDINALHELPER.ToggleBit(const index: integer):Boolean; inline;
+
+begin
+  Result := TestBit(Index);
+  Self := TORDINALTYPE(TUNSIGNED(Self) xor (TUNSIGNED(1) shl index));
+  Result := Result <> TestBit(Index);
+end;
+
+Function TORDINALHELPER.TestBit(const Index: integer):Boolean; inline;
+
+begin
+  Result := TORDINALTYPE(TUNSIGNED(Self) and (TUNSIGNED(1) shl index)) <> 0;
+end;
testbits.pas (3,219 bytes)
program testbits;
{$H+}
uses 
  sysutils;
const
  ByteLimit = SizeOf(Byte) * 8 -1;
  ShortIntLimit = ByteLimit;
  WordLimit = SizeOf(Word) * 8 -1;
  SmallIntLimit = WordLimit;
  CardinalLimit = SizeOf(Cardinal) * 8 -1;
  IntegerLimit = SizeOf(Integer) * 8 -1;
  NativeUIntLimit = SizeOf(NativeUInt) * 8 -1;
  NativeIntLimit = NativeUIntLimit;
  QwordLimit = SizeOf(Qword) * 8 -1;
  Int64Limit = QwordLimit;
 
var
  a:byte = 0;
  b:shortint = 0;
  c:Word = 0;
  d:SmallInt = 0;
  e:Cardinal = 0;
  f:Integer = 0;
  g:NativeUInt = 0;
  h:NativeInt = 0;
  k:Qword = 0;
  l:Int64 = 0;
  i:integer;
begin
  { create a bit pattern of walking 1's (and two rows of zero per iteration, do not print) }
  for i := 0 to ByteLimit do
  begin
    { add the one in case of error, because Ord(0) is 0 if no error detected }
    if a.Setbit(i) = false then Halt(1 + Ord(a));
    writeln(a.ToBinstring);  
    if a.Togglebit(i) = false then Halt(1 + Ord(a));  
    if a.Clearbit(i) = false then Halt(1 + Ord(a));
  end; 
  
  for i := 0 to ShortIntLimit do
  begin
    if b.Setbit(i) = false then Halt(1 + Ord(b));
    writeln(b.ToBinstring);     
    if b.Togglebit(i) = false then Halt(1 + Ord(b));    
    if b.Clearbit(i) = false then Halt(1 + Ord(b));
  end; 
  
  for i := 0 to WordLimit do
  begin
    if c.Setbit(i) = false then Halt(1 + Ord(c));
    writeln(c.ToBinstring); 
    if c.Togglebit(i) = false then Halt(1 + Ord(c));    
    if c.Clearbit(i) = false then Halt(1 + Ord(c));
  end; 
  
  for i := 0 to SmallIntLimit do
  begin
    if d.Setbit(i) = false then Halt(1 + Ord(d));
    writeln(d.ToBinstring); 
    if d.Togglebit(i) = false then Halt(1 + Ord(d));    
    if d.Clearbit(i) = false then Halt(1 + Ord(d));
  end;
  
  for i := 0 to CardinalLimit do
  begin
    if e.Setbit(i) = false then Halt(1 + Ord(e));
    writeln(e.ToBinstring); 
    if e.Togglebit(i) = false then Halt(1 + Ord(e));    
    if e.Clearbit(i) = false then Halt(1 + Ord(e));
  end;
  
  for i := 0 to IntegerLimit do
  begin
    if f.Setbit(i) = false then Halt(1 + Ord(f));
    writeln(f.ToBinstring); 
    if f.Togglebit(i) = false then Halt(1 + Ord(f));    
    if f.Clearbit(i) = false then Halt(1 + Ord(f));
  end; 
  
  for i := 0 to NativeUIntLimit do
  begin
    if g.Setbit(i) = false then Halt(1 + Ord(g));
    writeln(g.ToBinstring); 
    if g.Togglebit(i) = false then Halt(1 + Ord(g));    
    if g.Clearbit(i) = false then Halt(1 + Ord(g));
  end; 
  
  for i := 0 to NativeIntLimit do
  begin
    if h.Setbit(i) = false then Halt(1 + Ord(h));
    writeln(h.ToBinstring); 
    if h.Togglebit(i) = false then Halt(1 + Ord(h));    
    if h.Clearbit(i) = false then Halt(1 + Ord(h));
  end; 
  
  for i := 0 to QWordLimit do
  begin
    if k.Setbit(i) = false then Halt(1 + Ord(k));
    writeln(k.ToBinstring); 
    if k.Togglebit(i) = false then Halt(1 + Ord(k));    
    if k.Clearbit(i) = false then Halt(1 + Ord(k));
  end; 
  
  for i := 0 to Int64Limit do
  begin
    if l.Setbit(i) = false then Halt(1 + Ord(l));
    writeln(l.ToBinstring); 
    if l.Togglebit(i) = false then Halt(1 + Ord(l));    
    if l.Clearbit(i) = false then Halt(1 + Ord(l));
  end; 
  { result should be zero, all individual bits tested }
end.
testbits.pas (3,219 bytes)

Bart Broersma

2019-10-13 16:55

reporter   ~0118564

With ordinalbithelpers-20191013.patch applied all my tests fail in ClearBit (off by one) when index > 0 e.g.:
Index: 1, Found: 11111100, Expected: 11111101
Index: 2, Found: 11111000, Expected: 11111011
Index: 3, Found: 11110000, Expected: 11110111
Index: 4, Found: 11100000, Expected: 11101111
Index: 5, Found: 11000000, Expected: 11011111
Index: 6, Found: 10000000, Expected: 10111111
Index: 7, Found: 00000000, Expected: 01111111

TestIntegerTestBit also fails for all indexes.

Attached file buildruntest.txt gives details (including the mode and target the test was compiled for).

buildruntest.txt (398,067 bytes)

Bart Broersma

2019-10-13 22:11

reporter   ~0118569

function TORDINALHELPER.ClearBit(const index: integer):Boolean; inline;

begin
  Self:=TORDINALTYPE(TUNSIGNED(Self) and not TUNSIGNED(1) shl index);
  Result := TestBit(Index) = false;
end;

Misses brackets around "TUNSIGNED(1) shl index"

Bart Broersma

2019-10-13 23:03

reporter   ~0118570

Last edited: 2019-10-13 23:04

View 2 revisions

> TestIntegerTestBit also fails for all indexes.
Sorry for that noise on that part: error in my test-code (missed a dangling ';' right afther 'if .. then').

Some further remarks:
I don't think making these bitesetters (SetBit,ToggleBit,Clear) a function is the right way to go, a procedure was better IMO.
The test for succes is questionable at least.

Casting back all results to TORDINALTYPE is unneccessary.

You might consider changing the type of Index to an unsigned type?
For the time being Byte would be enough (the largest ordinal is 64bit a.t.m.)

> Misses brackets around "TUNSIGNED(1) shl index"
With that fixed all tests run OK again.

Thaddy de Koning

2019-10-14 07:55

reporter   ~0118579

Last edited: 2019-10-14 07:57

View 3 revisions

The functions can of course already be called as procedures depending on modeswitch /mode.
Index as integer is what is used throughout sysutils, hence the choice.
I also made a version that took a word parameter, not byte, because modern processors already support width upto 512, I anticipated that such ordinals may be implemented in the future (e.g. on 64 bit systems qword is already a full ordinal nowadays)
Glad to see the tests were not in my code ;)
TORDINALTYPE is not always assignment compatible with an unsigned type

The concept regarding the Boolean functions is that:
- such a value can be under hardware control (e.g. mmapped to control word or GPIO), so you can test the operations for success. Main reason I implemented it.
- Boundary/range tests need no exceptions to be handled correctly
- Testing for setting/clearing an already set/cleared bit can be useful information (again regarding hardware control)

Bart Broersma

2019-10-14 22:36

reporter   ~0118604

Updated testprogram.

testbits3.zip (12,599 bytes)

Thaddy de Koning

2019-10-15 10:21

reporter   ~0118615

Last edited: 2019-10-15 10:29

View 3 revisions

Bart:
  TestByteSetBit; // should be one and it is
  TestByteToggleBit; // should be zero and it is
  TestByteClearBit; // should be zero and it is (and returns false, because there is no bit to clear!
  TestByteTestBit; // should be false and it is
So your tests are possibly flawed?
Otherwise the walking bit test that I added would also fail.

Your Expected is off by one? Not the code as far as I can test it. (which happens to be Dennis Richie based and is pure Boolean logic: where is the error?)
With respect for the efforts of course! Point me to it..

Thaddy de Koning

2019-10-15 12:20

reporter   ~0118616

No you are re-using the const data array, which you should not have done.

Bart Broersma

2019-10-15 23:04

reporter   ~0118623

Last edited: 2019-10-15 23:14

View 5 revisions

> No you are re-using the const data array, which you should not have done.
Huh?
Now you are telling me the data arrays are wrong?
Or they cannot be constants?
Why?
Please explain to me why (for shortint) these expected values are wrong for ClearBit(ShortInt(%11111111))?
Index: 0: Expected: ShortInt(%11111111)
Index: 1: Expected: ShortInt(%11111101)
Index: 2: Expected: ShortInt(%11111011)
Index: 3: Expected: ShortInt(%11110111)
Index: 4: Expected: ShortInt(%11101111)
Index: 5: Expected: ShortInt(%11011111)
Index: 6: Expected: ShortInt(%10111111)
Index: 7: Expected: ShortInt(%01111111)
The above expected values are in the Expected array constant, which has range 0..Pred(SizeOf(ShortInt) * 8), so 0..7 in this case.

Previously thet were defined as initialized variables, but that doesn't compile in TP mode, so I changed them to const.
They are never written to, so no worries there.
(Even that does not matter since each and every test is run only once in the compiled program.
The output I attached is the result of building and running the program 10 times (5 modes x 2 CPU-bitness (32 and 64 bit))
It also includes the output of the compilation process, so you can easily see:
- if compilation fails
- if the program fails, for what mode and bitness it was compiled.
)

Your new ClearBit is wrong: as I explained, you missed a couple of parenthesis there.

Self:=TORDINALTYPE(TUNSIGNED(Self) and not TUNSIGNED(1) shl index);
should be
Self:=TORDINALTYPE(TUNSIGNED(Self) and not (TUNSIGNED(1) shl index));

The first is the same as
Self:=TORDINALTYPE ((TUNSIGNED(Self) and not TUNSIGNED(1))   shl index);

So it removes the last bit, then shifts that result left by index amount.
That explains the observed patterns of failure:
Index: 1, Found: 11111100, Expected: 11111101
Index: 2, Found: 11111000, Expected: 11111011
Index: 3, Found: 11110000, Expected: 11110111

Index: 0 will be OK of course, it clears last bit (by chance) then does shl 0 on the result.

I fixed that, rebuild fpc, ran the tests in all possible fpc modes on 32 and 64 bit (on Windows 10-64 only), and with that fix all test are OK.
Also, no more compile time errors (nothing to do with my fix to ClearBit, but with the fact that all bit-calculations are now done on unsigned ordinals).

I already apologized about the TestBit tests, they were errors in my test (misplaced semicolon).

Michael Van Canneyt

2019-10-19 16:14

administrator   ~0118698

Bart, can you please provide a patch with your fix applied, and also indicate what the correct test program is ?

With all the files & revisions, I no longer know what to use....

Thaddy de Koning

2019-10-19 16:53

reporter   ~0118700

Last edited: 2019-10-19 16:58

View 3 revisions

Michael, it is just a small subset of Boolean operations with typecasts to circumvent some quirks with Freepascal expansions of variables.
They are simply completely *standard Boolean operations* , well described in literature and the basics should work in any language. If it still does not work, the language is at fault: there may be a bug.

I also do not know what longer to use.

You can close this. My code "does not work"? and Bart's code is a work-around.
You can examine my first patch to establish for yourself it is just based on solid, well-known, theory.

Please close. But with thanks to Bart and yourself for evaluating it! Really much appreciated both of you for your input.

Michael Van Canneyt

2019-10-19 17:04

administrator   ~0118703

Thaddy, I think your additions are useful, so I would like to add them to the sysutils unit.

But of course I want to be sure they are bug-free.
50+ Revisions of comments later, I no longer have an overview of what is and what is not :)

Michael Van Canneyt

2019-11-08 12:49

administrator   ~0119156

Added the patch, slightly adapted.

The Set/Clear/Toggle methods now also return the value itself. That allows for things like:

if B.SetBit(1)=1 then
or, for the afficiniados of such notation:
B:=B.SetBit(1).ClearBit(2);
although one should be careful with this kind of thing, since
B.SetBit(1).ClearBit(2);
will not clear the second bit on B itself.

The tests run fine.
The compile error with {$R+} I also get when I do that test, I will report this to the compiler team.

It is difficult to reproduce in a standalone program, presumably it has to do with the fact that the helper is in a different unit.

Thanks to Thaddy for the implementation, and Bart for the extensive testing.





Issue History

Date Modified Username Field Change
2019-10-08 10:46 Thaddy de Koning New Issue
2019-10-08 10:46 Thaddy de Koning File Added: sysordinalbitshelpers.patch
2019-10-08 10:54 Michael Van Canneyt Assigned To => Michael Van Canneyt
2019-10-08 10:54 Michael Van Canneyt Status new => assigned
2019-10-08 10:56 Michael Van Canneyt Note Added: 0118407
2019-10-08 11:05 Thaddy de Koning File Added: sysordinalbitshelpers_corrected.patch
2019-10-08 11:05 Thaddy de Koning Note Added: 0118408
2019-10-08 12:26 Thaddy de Koning File Added: sysordinalbitshelpers3.patch
2019-10-08 12:26 Thaddy de Koning File Added: bittests.pas
2019-10-08 12:26 Thaddy de Koning Note Added: 0118409
2019-10-08 12:36 Thaddy de Koning Note Added: 0118411
2019-10-08 12:38 Thaddy de Koning Note Edited: 0118411 View Revisions
2019-10-08 12:42 Thaddy de Koning Note Edited: 0118411 View Revisions
2019-10-08 14:07 Thaddy de Koning Note Added: 0118417
2019-10-08 14:08 Thaddy de Koning Note Edited: 0118417 View Revisions
2019-10-08 14:09 Thaddy de Koning File Added: bittests2.pas
2019-10-09 17:50 Thaddy de Koning File Added: ordinalbitshelper4.patch
2019-10-09 17:50 Thaddy de Koning Note Added: 0118451
2019-10-09 18:01 Michael Van Canneyt Note Added: 0118452
2019-10-09 19:36 Thaddy de Koning Note Added: 0118453
2019-10-10 14:38 Bart Broersma Note Added: 0118462
2019-10-10 14:40 Bart Broersma Note Edited: 0118462 View Revisions
2019-10-10 14:45 Bart Broersma Note Edited: 0118462 View Revisions
2019-10-10 15:25 Bart Broersma Note Added: 0118463
2019-10-10 16:37 Thaddy de Koning Note Added: 0118464
2019-10-10 23:02 Bart Broersma Note Added: 0118482
2019-10-10 23:07 Bart Broersma Note Added: 0118483
2019-10-10 23:29 Bart Broersma Note Added: 0118485
2019-10-10 23:38 Bart Broersma Note Edited: 0118485 View Revisions
2019-10-11 00:14 Bart Broersma File Added: testbits.zip
2019-10-11 22:44 Bart Broersma Note Added: 0118497
2019-10-11 22:50 Bart Broersma File Added: testbits2.zip
2019-10-11 22:51 Bart Broersma Note Edited: 0118497 View Revisions
2019-10-12 01:39 jamie philbrook Note Added: 0118499
2019-10-12 03:18 jamie philbrook Note Added: 0118501
2019-10-12 13:55 Thaddy de Koning File Added: testbug.pas
2019-10-12 13:55 Thaddy de Koning File Added: ordinalbithelpers-20191012.patch
2019-10-12 13:55 Thaddy de Koning Note Added: 0118512
2019-10-13 08:56 Thaddy de Koning Note Added: 0118545
2019-10-13 09:08 Michael Van Canneyt Note Added: 0118546
2019-10-13 09:45 Thaddy de Koning Note Added: 0118550
2019-10-13 14:23 Thaddy de Koning File Added: ordinalbithelpers-20191013.patch
2019-10-13 14:23 Thaddy de Koning File Added: testbits.pas
2019-10-13 14:23 Thaddy de Koning Note Added: 0118563
2019-10-13 16:55 Bart Broersma File Added: buildruntest.txt
2019-10-13 16:55 Bart Broersma Note Added: 0118564
2019-10-13 22:11 Bart Broersma Note Added: 0118569
2019-10-13 23:03 Bart Broersma Note Added: 0118570
2019-10-13 23:04 Bart Broersma Note Edited: 0118570 View Revisions
2019-10-14 07:55 Thaddy de Koning Note Added: 0118579
2019-10-14 07:55 Thaddy de Koning Note Edited: 0118579 View Revisions
2019-10-14 07:57 Thaddy de Koning Note Edited: 0118579 View Revisions
2019-10-14 22:36 Bart Broersma File Added: testbits3.zip
2019-10-14 22:36 Bart Broersma Note Added: 0118604
2019-10-15 10:21 Thaddy de Koning Note Added: 0118615
2019-10-15 10:27 Thaddy de Koning Note Edited: 0118615 View Revisions
2019-10-15 10:29 Thaddy de Koning Note Edited: 0118615 View Revisions
2019-10-15 12:20 Thaddy de Koning Note Added: 0118616
2019-10-15 23:04 Bart Broersma Note Added: 0118623
2019-10-15 23:10 Bart Broersma Note Edited: 0118623 View Revisions
2019-10-15 23:11 Bart Broersma Note Edited: 0118623 View Revisions
2019-10-15 23:13 Bart Broersma Note Edited: 0118623 View Revisions
2019-10-15 23:14 Bart Broersma Note Edited: 0118623 View Revisions
2019-10-19 16:14 Michael Van Canneyt Note Added: 0118698
2019-10-19 16:53 Thaddy de Koning Note Added: 0118700
2019-10-19 16:58 Thaddy de Koning Note Edited: 0118700 View Revisions
2019-10-19 16:58 Thaddy de Koning Note Edited: 0118700 View Revisions
2019-10-19 17:04 Michael Van Canneyt Note Added: 0118703
2019-11-08 12:49 Michael Van Canneyt Status assigned => resolved
2019-11-08 12:49 Michael Van Canneyt Resolution open => fixed
2019-11-08 12:49 Michael Van Canneyt Fixed in Version => 3.3.1
2019-11-08 12:49 Michael Van Canneyt Fixed in Revision => 43417
2019-11-08 12:49 Michael Van Canneyt FPCTarget => 3.2.0
2019-11-08 12:49 Michael Van Canneyt Note Added: 0119156