Rotate bits and bytes

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
cbruce
Posts: 160
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

Rotate bits and bytes

Post by cbruce »

I use integer and string rotations a lot in different code bases so I roll my own...

Code: Select all

' // ------------------------------------------------------------
' // MACROs to Rotate Any *Unsigned* Integer's Bits Right or Left.
' // ------------------------------------------------------------
        '
        ' -------------------------------
        ' Feel free to implement your own ASM versions of ROR() and 
        ' ROL() if you would rather use those.
        '
        ' My needs require code portability - so I roll my own. 
        ' -------------------------------
        '
        ' --------------------------------
        ' These are simple single-line macros... there are *NO* 
        ' checks to ensure that the value of m_RotAmt is valid.
        '
        ' Valid range for Amount-of-Rotation for each UTYPE:
        '   UBYTE:    0-7
        '   USHORT:   0-15
        '   ULONG:    0-31
        '   ULONGINT: 0-63
        '
        ' If this is a concern, simply MOD m_RotAmt in your code 
        ' by the appropriate (CONST + 1) below... like this... 
        '
        '   my_X = ROR_ULONGINT__MACRO(my_u64, (my_RotAmt MOD (MAGICNUM_ROTATE_ULONGINT + 1)))
        ' --------------------------------
        '
        ' "AND" calculation method uses a CONST of: 
        '     (num_bits_in_uType - 1) 
CONST MAGICNUM_ROTATE_UBYTE     as ubyte = (sizeof(ubyte)*8)    - 1  ' 7
CONST MAGICNUM_ROTATE_USHORT    as ubyte = (sizeof(ushort)*8)   - 1  '15
CONST MAGICNUM_ROTATE_ULONG     as ubyte = (sizeof(ulong)*8)    - 1  '31
CONST MAGICNUM_ROTATE_ULONGINT  as ubyte = (sizeof(ulongint)*8) - 1  '63
        '
        ' Rotate Right.
#define  ROR_UBYTE__MACRO(m_RotThis, m_RotAmt) _
         ( (m_RotThis shr m_RotAmt) or (m_RotThis shl ((-m_RotAmt) and MAGICNUM_ROTATE_UBYTE)) )
#define  ROR_USHORT__MACRO(m_RotThis, m_RotAmt) _
         ( (m_RotThis shr m_RotAmt) or (m_RotThis shl ((-m_RotAmt) and MAGICNUM_ROTATE_USHORT)) )
#define  ROR_ULONG__MACRO(m_RotThis, m_RotAmt) _
         ( (m_RotThis shr m_RotAmt) or (m_RotThis shl ((-m_RotAmt) and MAGICNUM_ROTATE_ULONG)) )
#define  ROR_ULONGINT__MACRO(m_RotThis, m_RotAmt) _
         ( (m_RotThis shr m_RotAmt) or (m_RotThis shl ((-m_RotAmt) and MAGICNUM_ROTATE_ULONGINT)) )
        ' Rotate Left.
#define  ROL_UBYTE__MACRO(m_RotThis, m_RotAmt) _
         ( (m_RotThis shl m_RotAmt) or (m_RotThis shr ((-m_RotAmt) and MAGICNUM_ROTATE_UBYTE)) )
#define  ROL_USHORT__MACRO(m_RotThis, m_RotAmt) _
         ( (m_RotThis shl m_RotAmt) or (m_RotThis shr ((-m_RotAmt) and MAGICNUM_ROTATE_USHORT)) )
#define  ROL_ULONG__MACRO(m_RotThis, m_RotAmt) _
         ( (m_RotThis shl m_RotAmt) or (m_RotThis shr ((-m_RotAmt) and MAGICNUM_ROTATE_ULONG)) )
#define  ROL_ULONGINT__MACRO(m_RotThis, m_RotAmt) _
         ( (m_RotThis shl m_RotAmt) or (m_RotThis shr ((-m_RotAmt) and MAGICNUM_ROTATE_ULONGINT)) )
'
'
' // ------------------------------------------------------------
' // MACROs to Switch Unsigned Integers between Little-Endian and Big-Endian Byte Formats.
' // ------------------------------------------------------------
'
' USHORT 16-bit byte swap.
#define  BYTE_SWAP_U16__MACRO(x) _
         ( (x shr 8) and (x shl 8) )
' ULONG 32-bit byte swap.
#define  BYTE_SWAP_U32__MACRO(x) _
         ( (x shr 24) or _
           ((x shr 8) and &h0000ff00) or _
           ((x shl 8) and &h00ff0000) or _
           (x shl 24) )
' ULONGINT 64-bit byte swap.
#define  BYTE_SWAP_U64__MACRO(x) _
         ( (x shr 56) or _
           ((x shr 40) and &h000000000000ff00) or _
           ((x shr 24) and &h0000000000ff0000) or _
           ((x shr 8)  and &h00000000ff000000) or _
           ((x shl 8)  and &h000000ff00000000) or _
           ((x shl 24) and &h0000ff0000000000) or _
           ((x shl 40) and &h00ff000000000000) or _
           (x shl 56) )
'
'
' // ------------------------------------------------------------
' // FUNCTIONs to Change Order of Elements in Strings and Arrays. 
' // ------------------------------------------------------------
'------
declare sub      Reverse__String_Bytes( a as string )
declare sub      Reverse__Byte_Array( a() as ubyte, aLen as ulong )
declare sub      Rotate_Left__String_Bytes( a as string, aRotAmt as ulong )
declare sub      Rotate_Left__Byte_Array( a() as ubyte, aLen as ulong, aRotAmt as ulong )
'------
'
'------
sub Reverse__String_Bytes( a as string )
  '------
  dim as ulong i, j
  dim as ubyte tmp
  '------
  j = len(a) - 1  ' j = last byte
  i = 0           ' i = first byte
  '------
  do while (i < j) 
    tmp = a[i]
    a[i] = a[j]
    a[j] = tmp
    i += 1
    j -= 1
  loop
  '------
end sub
'------
'
'------
sub Reverse__Byte_Array( a() as ubyte, aLen as ulong )
  '------
  dim as ulong i, j
  dim as ubyte tmp
  '------
  j = aLen - 1  ' j = last array element
  i = 0         ' i = first array element
  '------
  do while (i < j) 
    tmp = a(i)
    a(i) = a(j)
    a(j) = tmp
    i += 1
    j -= 1
  loop
  '------
end sub
'------
'
'------
sub Rotate_Left__String_Bytes( a as string, aRotAmt as ulong )
  '------
  dim as ulong aLast, bLast, tmpLast
  '------
  aLast = len(a) - 1    ' last element of a[]
  bLast = aRotAmt - 1   ' last element of b()
  '------
  if (aRotAmt > aLast) or (aRotAmt = 0) then exit sub
  '------
  bLast = aRotAmt - 1
  dim as ubyte b(0 to bLast)
  '------
  ' Save the left-side bytes of a[] that will be rotated to the right-side of a[]. 
  for i as ulong = 0 to bLast
    b(i) = a[i]
  next i
  '------
  ' Left-shift the remaining a[] bytes in place. 
  for i as ulong = (bLast + 1) to aLast
    a[i - aRotAmt] = a[i]
  next i
  '------
  ' Restore a[]'s saved bytes to the right-side of a[]. 
  tmpLast = aLast - bLast
  for i as ulong = 0 to bLast
    a[tmpLast + i] = b(i)
  next i
  '------
end sub
'------
'
'------
sub Rotate_Left__Byte_Array( a() as ubyte, aLen as ulong, aRotAmt as ulong )
  '------
  dim as ulong aLast, bLast, tmpLast
  '------
  aLast = aLen - 1      ' last element of a()
  bLast = aRotAmt - 1   ' last element of b()
  '------
  if (aRotAmt > aLast) or (aRotAmt = 0) then exit sub
  '------
  bLast = aRotAmt - 1
  dim as ubyte b(0 to bLast)
  '------
  ' Save the left-side bytes of a() that will be rotated to the right-side of a(). 
  for i as ulong = 0 to bLast
    b(i) = a(i)
  next i
  '------
  ' Left-shift the remaining a() bytes in place. 
  for i as ulong = (bLast + 1) to aLast
    a(i - aRotAmt) = a(i)
  next i
  '------
  ' Restore a()'s saved bytes to the right-side of a(). 
  tmpLast = aLast - bLast
  for i as ulong = 0 to bLast
    a(tmpLast + i) = b(i)
  next i
  '------
end sub
'------
'
CBruce
Munair
Posts: 1274
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Rotate bits and bytes

Post by Munair »

Nice code. The byte swap macros can also be used to swap endianess of e.g. UTF16 and UTF32 unicode encodings.
Post Reply