VFP BIT* functions
Posted: Wed Apr 07, 2021 10:24 pm
This is a kind of a by-product of another thread of the forum. The VFP BIT* functions were briefly discussed as an example of incomplete implementation by the VFP Toolkit for .Net. One of the key aspects that were missing was support for Binary strings.
This is a proposal of an X# implementation of all BIT* functions, accepting both Int and Binary modes when needed, and USUAL parameters as well. Possibly not on the top of the list of anyone looking for X# implementation of VFP functions, but hopefully it has the merit of illustration.
The code is separated into groups, to facilitate the reading and (eventually) the discussion. Some testing is provided in the final. Nevertheless, sorry for being a bit long.
BITAND, OR and XOR
BITNOT
BITCLEAR and BITSET
BITTEST
BITRSHIFT and BITLSHIFT
This is a proposal of an X# implementation of all BIT* functions, accepting both Int and Binary modes when needed, and USUAL parameters as well. Possibly not on the top of the list of anyone looking for X# implementation of VFP functions, but hopefully it has the merit of illustration.
The code is separated into groups, to facilitate the reading and (eventually) the discussion. Some testing is provided in the final. Nevertheless, sorry for being a bit long.
BITAND, OR and XOR
Code: Select all
FUNCTION BITAND (Arg1 AS USUAL, Arg2 PARAMS USUAL[]) AS USUAL
RETURN _BITANDORX(c'A', Arg1, Arg2)
END FUNC
FUNCTION BITAND (Arg1 AS Int, Arg2 PARAMS Int[]) AS Int
RETURN _BITANDORX(c'A', Arg1, Arg2)
END FUNC
FUNCTION BITAND (Arg1 AS Binary, Arg2 PARAMS Binary[]) AS Binary
RETURN _BITANDORX(c'A', Arg1, Arg2)
END FUNC
FUNCTION BITOR (Arg1 AS USUAL, Arg2 PARAMS USUAL[]) AS USUAL
RETURN _BITANDORX(c'O', Arg1, Arg2)
END FUNC
FUNCTION BITOR (Arg1 AS Int, Arg2 PARAMS Int[]) AS Int
RETURN _BITANDORX(c'O', Arg1, Arg2)
END FUNC
FUNCTION BITOR (Arg1 AS Binary, Arg2 PARAMS Binary[]) AS Binary
RETURN _BITANDORX(c'O', Arg1, Arg2)
END FUNC
FUNCTION BITXOR (Arg1 AS USUAL, Arg2 PARAMS USUAL[]) AS USUAL
RETURN _BITANDORX(c'X', Arg1, Arg2)
END FUNC
FUNCTION BITXOR (Arg1 AS Int, Arg2 PARAMS Int[]) AS Int
RETURN _BITANDORX(c'X', Arg1, Arg2)
END FUNC
FUNCTION BITXOR (Arg1 AS Binary, Arg2 PARAMS Binary[]) AS Binary
RETURN _BITANDORX(c'X', Arg1, Arg2)
END FUNC
STATIC FUNCTION _BITANDORX (LogicalOp AS Char, Arg1 AS USUAL, Arg2 PARAMS USUAL[]) AS USUAL
IF VARTYPE(Arg1) == "Q"
VAR Args = Binary[]{Arg2.Length}
LOCAL ArgIndex AS Int
FOR ArgIndex := 1 TO Args.Length
Args[ArgIndex] := (Binary)Arg2[ArgIndex]
NEXT
RETURN _BITANDORX(LogicalOp, (Binary)Arg1, Args)
ELSE
VAR Args = Int[]{Arg2.Length}
LOCAL ArgIndex AS Int
FOR ArgIndex := 1 TO Args.Length
Args[ArgIndex] := (Int)Arg2[ArgIndex]
NEXT
RETURN _BITANDORX(LogicalOp, (Int)Arg1, Args)
ENDIF
END FUNC
STATIC FUNCTION _BITANDORX (LogicalOp AS Char, Arg1 AS Int, Arg2 PARAMS Int[]) AS Int
LOCAL Result := Arg1 AS Int
LOCAL ArgIndex AS Int
SWITCH LogicalOp
CASE c'A'
FOR ArgIndex := 1 TO Arg2.Length
Result := _And(Result, Arg2[ArgIndex])
NEXT
CASE c'O'
FOR ArgIndex := 1 TO Arg2.Length
Result := _Or(Result, Arg2[ArgIndex])
NEXT
CASE c'X'
FOR ArgIndex := 1 TO Arg2.Length
Result := _Xor(Result, Arg2[ArgIndex])
NEXT
END
RETURN Result
END FUNC
STATIC FUNCTION _BITANDORX (LogicalOp AS Char, Arg1 AS Binary, Arg2 PARAMS Binary[]) AS Binary
LOCAL Result := 0h + Arg1 AS Byte[]
LOCAL ArgIndex AS Int
FOR ArgIndex := 1 TO Arg2.Length
LOCAL Arg := 0h + Arg2[ArgIndex] AS Byte[]
IF Result.Length < Arg.Length
Array.Resize(Result, Arg.Length)
ELSE
IF Result.Length > Arg.Length
Array.Resize(Arg, Result.Length)
ENDIF
ENDIF
LOCAL ByteIndex AS Int
SWITCH LogicalOp
CASE c'A'
FOR ByteIndex := 1 TO Result.Length
Result[ByteIndex] := _And(Result[ByteIndex], Arg[ByteIndex])
NEXT
CASE c'O'
FOR ByteIndex := 1 TO Result.Length
Result[ByteIndex] := _Or(Result[ByteIndex], Arg[ByteIndex])
NEXT
CASE c'X'
FOR ByteIndex := 1 TO Result.Length
Result[ByteIndex] := _Xor(Result[ByteIndex], Arg[ByteIndex])
NEXT
END
ENDFOR
RETURN (Binary)Result
END FUNC
Code: Select all
FUNCTION BITNOT (Arg1 AS USUAL) AS USUAL
IF VARTYPE(Arg1) == "Q"
RETURN BITNOT((Binary)Arg1)
ELSE
RETURN BITNOT((Int)Arg1)
ENDIF
END FUNC
FUNCTION BITNOT (Arg1 AS USUAL, Arg2 AS USUAL, Arg3 := 1 AS USUAL) AS Binary
IF VARTYPE(Arg1) == "Q"
RETURN BITNOT((Binary)Arg1, (Int)Arg2, (Int)Arg3)
ELSE
THROW ArgumentException {}
ENDIF
END FUNC
FUNCTION BITNOT (Num AS Int) AS Int
RETURN ~Num
END FUNC
FUNCTION BITNOT (BinString AS Binary) AS Binary
RETURN BITNOT(BinString, 0, BinString.Length * 8)
END FUNC
FUNCTION BITNOT (BinString AS Binary, StartBit AS Int, BitCount := 1 AS Int) AS Binary
LOCAL Result := 0h + BinString AS Byte[]
LOCAL ByteIndex AS Int
LOCAL BitIndex := StartBit AS Int
LOCAL BitCounter AS Int
FOR BitCounter := 1 TO BitCount
ByteIndex := BitIndex / 8 + 1
IF BETWEEN(ByteIndex, 1, Result.Length)
Result[ByteIndex] := _Xor(Result[ByteIndex], 1 << BitIndex % 8)
BitIndex++
ELSE
THROW ArgumentException {}
ENDIF
NEXT
RETURN (Binary)Result
END FUNC
Code: Select all
FUNCTION BITCLEAR (Arg1 AS USUAL) AS Binary
RETURN BITCLEAR((Binary)Arg1)
END FUNC
FUNCTION BITCLEAR (Arg1 AS USUAL, Arg2 AS USUAL) AS USUAL
IF VARTYPE(Arg1) == "Q"
RETURN IIF(Arg1.Length == 0, 0h, BITCLEAR((Binary)Arg1, (Int)Arg2, 1))
ELSE
RETURN BITCLEAR((Int)Arg1, (Int)Arg2)
ENDIF
END FUNC
FUNCTION BITCLEAR (Arg1 AS USUAL, Arg2 AS USUAL, Arg3 AS USUAL) AS Binary
RETURN BITCLEAR((Binary)Arg1, (Int)Arg2, (Int)Arg3)
END FUNC
FUNCTION BITCLEAR (Num AS Int, Bit AS Int) AS Int
IF BETWEEN(Bit, 0, 31)
RETURN _And(Num, _Not(1 << Bit))
ELSE
THROW ArgumentException {}
ENDIF
END FUNC
FUNCTION BITCLEAR (BinString AS Binary) AS Binary
RETURN IIF(BinString.Length == 0, 0h, BITCLEAR(BinString, 0, BinString.Length * 8))
END FUNC
FUNCTION BITCLEAR (BinString AS Binary, StartBit AS Int) AS Binary
RETURN IIF(BinString.Length == 0, 0h, BITCLEAR(BinString, StartBit, 1))
END FUNC
FUNCTION BITCLEAR (BinString AS Binary, StartBit AS Int, BitCount AS Int) AS Binary
LOCAL Result := 0h + BinString AS Byte[]
LOCAL ByteIndex AS Int
LOCAL BitIndex := StartBit AS Int
LOCAL BitCounter AS Int
FOR BitCounter := 1 TO BitCount
ByteIndex := BitIndex / 8 + 1
IF BETWEEN(ByteIndex, 1, Result.Length)
Result[ByteIndex] := _And(Result[ByteIndex], _Not(1 << BitIndex % 8))
BitIndex++
ELSE
THROW ArgumentException {}
ENDIF
NEXT
RETURN (Binary)Result
END FUNC
FUNCTION BITSET (Arg1 AS USUAL) AS Binary
RETURN BITSET((Binary)Arg1)
END FUNC
FUNCTION BITSET (Arg1 AS USUAL, Arg2 AS USUAL) AS USUAL
IF VARTYPE(Arg1) == "Q"
RETURN BITSET((Binary)Arg1, (Int)Arg2, 1)
ELSE
RETURN BITSET((Int)Arg1, (Int)Arg2)
ENDIF
END FUNC
FUNCTION BITSET (Arg1 AS USUAL, Arg2 AS USUAL, Arg3 AS USUAL) AS Binary
RETURN BITSET((Binary)Arg1, (Int)Arg2, (Int)Arg3)
END FUNC
FUNCTION BITSET (Num AS Int, Bit AS Int) AS Int
IF BETWEEN(Bit, 0, 31)
RETURN _Or(Num, 1 << Bit)
ELSE
THROW ArgumentException {}
ENDIF
END FUNC
FUNCTION BITSET (BinString AS Binary) AS Binary
RETURN IIF(BinString.Length == 0, 0h, BITSET(BinString, 0, BinString.Length * 8))
END FUNC
FUNCTION BITSET (BinString AS Binary, StartBit AS Int) AS Binary
RETURN IIF(BinString.Length == 0, 0h, BITSET(BinString, StartBit, 1))
END FUNC
FUNCTION BITSET (BinString AS Binary, StartBit AS Int, BitCount AS Int) AS Binary
LOCAL Result := 0h + BinString AS Byte[]
LOCAL ByteIndex AS Int
LOCAL BitIndex := StartBit AS Int
LOCAL BitCounter AS Int
FOR BitCounter := 1 TO BitCount
ByteIndex := BitIndex / 8 + 1
IF BETWEEN(ByteIndex, 1, Result.Length)
Result[ByteIndex] := _Or(Result[ByteIndex], 1 << BitIndex % 8)
BitIndex++
ELSE
THROW ArgumentException {}
ENDIF
NEXT
RETURN (Binary)Result
END FUNC
Code: Select all
FUNCTION BITTEST (Arg1 AS USUAL, Arg2 AS USUAL) AS Logic
IF VARTYPE(Arg1) == "Q"
RETURN BITTEST((Binary)Arg1, (Int)Arg2)
ELSE
RETURN BITTEST((Int)Arg1, (Int)Arg2)
ENDIF
END FUNC
FUNCTION BITTEST (Arg AS Int, Bit AS Int) AS Logic
IF BETWEEN(Bit, 0, 31)
RETURN _And(Arg, 1 << Bit) != 0
ELSE
THROW ArgumentException {}
ENDIF
END FUNC
FUNCTION BITTEST (Arg AS Binary, Bit AS Int) AS Logic
LOCAL Buff := 0h + Arg AS Byte[]
IF BETWEEN(Bit, 0, Buff.Length * 8 - 1)
RETURN _And(Buff[Bit / 8 + 1], 1 << Bit % 8) != 0
ELSE
THROW ArgumentException {}
ENDIF
END FUNC
Code: Select all
FUNCTION BITRSHIFT (Arg AS USUAL, Bits AS USUAL) AS Int
RETURN BITRSHIFT((Int)Arg1, (Int)Bits)
END FUNC
FUNCTION BITLSHIFT (Arg AS USUAL, Bits AS USUAL) AS Int
RETURN BITLSHIFT((Int)Arg1, (Int)Bits)
END FUNC
FUNCTION BITRSHIFT (Arg AS Int, Bits AS Int) AS Int
IF BETWEEN(Bits, 0, 31)
IF !BITTEST(Arg, 31) OR Bits == 0
RETURN Arg >> Bits
ELSE
RETURN BITSET(BITCLEAR(Arg, 31) >> Bits, 31 - Bits)
ENDIF
ELSE
THROW ArgumentException {}
ENDIF