Stuck writing a simple bit toggle routine

New to FreeBASIC? Post your questions here.
olympic sleeper
Posts: 41
Joined: Jun 07, 2020 15:47

Stuck writing a simple bit toggle routine

Postby olympic sleeper » Aug 03, 2020 20:12

Hello

I have a set of bit flags I want to toggle, so if set reset, if reset - set. I put this together;

Code: Select all

sub toggle_bit(flag as any ptr,position as integer)

   if bit(*flag,position) then
      flag=bitreset(*flag,position)
   else
      flag=bitset(*flag,position)
   end if
end sub


But am having problems getting it to compile as it errors (a lot) but mainly with

Code: Select all

 error 71: Incomplete type, before ')' in 'if bit(*flag,position) then'
error 71: Incomplete type, before ')' in 'flag=bitreset(*flag,position)'
warning 4(1): Suspicious pointer assignment


etc. As I am struggling to work out how to define the pointer and access it.

I'm calling the function with lines like,

Code: Select all

toggle(.status,_hidden)


which I would like to simply toggle the bit '_hidden' in flag var '.status', though I may need to use @.status ?

The flag vars are either ubytes or 16 bit uintegers hence my use of an any ptr. Could someone untangle this for me?

Many thanks in advance.
MrSwiss
Posts: 3581
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Stuck writing a simple bit toggle routine

Postby MrSwiss » Aug 03, 2020 20:40

olympic sleeper wrote:The flag vars are either ubytes or 16 bit uintegers hence my use of an any ptr. Could someone untangle this for me?

The "untyped" Any Ptr is the problem here. No type information inside procedure.
The other approach to solve the two possible data-types is overload(ing) the procedure:

Code: Select all

Sub toggle_bit OverLoad( _
    ByVal flag      As UByte, _
    ByVal position  As UByte  _
    )
    If position > 7 Then Exit Sub
   
    If Bit(flag, position) Then
        flag = BitReset(flag, position)
    Else
        flag = BitSet(flag, position)
    End if
End Sub

Sub toggle_bit OverLoad( _
    ByVal flag      As UShort, _
    ByVal position  As UByte   _
    )
    If position > 15 Then Exit Sub
   
    If Bit(flag, position) Then
        flag = BitReset(flag, position)
    Else
        flag = BitSet(flag, position)
    End if
End Sub
fxm
Posts: 9834
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Stuck writing a simple bit toggle routine

Postby fxm » Aug 03, 2020 20:54

flag must be passed by reference:
Byref flag As Ubyte/Ushort
MrSwiss
Posts: 3581
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Stuck writing a simple bit toggle routine

Postby MrSwiss » Aug 03, 2020 21:00

fxm wrote:flag must be passed by reference: Byref flag As Ubyte/Ushort
Correct for a Sub, for a Function however (return flag) ByVal passing can be used.

Code: Select all

Function toggle_bit OverLoad( _
    ByVal flag      As UByte, _
    ByVal position  As UByte  _
    ) As UByte
    If position > 7 Then Exit Function
   
    If Bit(flag, position) Then
        flag = BitReset(flag, position)
    Else
        flag = BitSet(flag, position)
    End If
   
    Return flag
End Function

Function toggle_bit OverLoad( _
    ByVal flag      As UShort, _
    ByVal position  As UByte   _
    ) As UShort
    If position > 15 Then Exit Function
   
    If Bit(flag, position) Then
        flag = BitReset(flag, position)
    Else
        flag = BitSet(flag, position)
    End If
   
    Return flag
End Function
Edited: corrected typo
Last edited by MrSwiss on Aug 03, 2020 22:27, edited 1 time in total.
jj2007
Posts: 1645
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Stuck writing a simple bit toggle routine

Postby jj2007 » Aug 03, 2020 21:12

Toggling a bit:

Code: Select all

Dim MyInt As integer=0
  MyInt=MyInt xor 1
  print "MyInt=", MyInt
  MyInt=MyInt xor 2
  print "MyInt=", MyInt
  MyInt=MyInt xor 2
  print "MyInt=", MyInt
  MyInt=MyInt xor 1
  print "MyInt=", MyInt
  sleep
Output:

Code: Select all

MyInt=         1
MyInt=         3
MyInt=         1
MyInt=         0
MrSwiss
Posts: 3581
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Stuck writing a simple bit toggle routine

Postby MrSwiss » Aug 03, 2020 21:15

??? NOT a procedure (Sub / Function) ???
dodicat
Posts: 6648
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Stuck writing a simple bit toggle routine

Postby dodicat » Aug 04, 2020 9:36

You could split the difference with a macro

Code: Select all


#macro toggle(flag_,position_)
    If Bit((flag_), (position_)) Then
        (flag_) = BitReset((flag_), (position_))
    Else
        (flag_) = BitSet((flag_), (position_))
    End If
 #endmacro 


dim as ubyte u=1
dim as long p=0


for n as long=1 to 10
 toggle(u,p)
print u
next
print

dim as ulongint k=18446744073709551610
for n as long=1 to 10
 toggle(k,p)
print k
next
sleep


 
jj2007
Posts: 1645
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Stuck writing a simple bit toggle routine

Postby jj2007 » Aug 04, 2020 10:52

dodicat wrote:You could split the difference with a macro
You could do an awful lot of very complicated things, but a simple flags=flags xor 32 (e.g. for toggling bit 5) is faster and shorter and does the job, too.
grindstone
Posts: 744
Joined: May 05, 2015 5:35
Location: Germany

Re: Stuck writing a simple bit toggle routine

Postby grindstone » Aug 04, 2020 11:14

You don't need a Sub/Function to do that job:

Code: Select all

Dim As Any Ptr flag
Dim As Integer position

flag = -1
? Bin(flag)

position = 3
flag = Cast(Integer, flag) Xor (2^position)
? Bin(flag)

position = 5
flag = Cast(Integer, flag) Xor (2^position)
? Bin(flag)

Sleep


EDIT: Oops, jj2007 was faster.
dodicat
Posts: 6648
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Stuck writing a simple bit toggle routine

Postby dodicat » Aug 04, 2020 12:29

The power of two kills the method (j2007).
You can work around it by either solving the correct power of two and using the value or

Code: Select all



'============ original ===========
#macro toggle(flag_,position_)
    If Bit((flag_), (position_)) Then
        (flag_) = BitReset((flag_), (position_))
    Else
        (flag_) = BitSet((flag_), (position_))
    End If
 #endmacro
 
 
 '===========  j2007 =======
 
 #macro pow(n)
 iif(n=0,1,_
 iif(n=1,2,_
 iif(n=2,4,_
 iif(n=3,8,_
 iif(n=4,16,_
 iif(n=5,32,_
 iif(n=6,64,_
 iif(n=7,128,_
 iif(n=8,256,_
 iif(n=9,512,_
 iif(n=10,1024,0)))))))))))
 #endmacro
 

#define tog(flag_,position_) flag_ = flag_ xor (pow(position_))

dim as ulong start

dim as ulong u
dim as long p

for k as long=1 to 5
    start=20+rnd*1000000
    p=rnd*9
    u=start

dim as double t=timer
'var p2=2^p 'alternative
for n as long=1 to 100000001
    tog(u,p)
next
print timer-t,u,"tog","u= ";u;" p= ";p
u=start
t=timer
for n as long=1 to 100000001
 toggle(u,p)
next
print timer-t,u,"toggle","u= ";u;" p= ";p
print
next k
print
print "done"

sleep

 

I only did up to 2^10, the pow macro can be extended of course.
counting_pine
Site Admin
Posts: 6221
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Stuck writing a simple bit toggle routine

Postby counting_pine » Aug 04, 2020 14:40

I would probably recommend just doing :

Code: Select all

.status xor= (1 shl _hidden)
dodicat
Posts: 6648
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Stuck writing a simple bit toggle routine

Postby dodicat » Aug 04, 2020 16:44

Indeed
#define tog(flag_,position_) flag_ = flag_ xor (1 shl position_)
is very fast.
Don't know why I didn't think of that.
Must be getting old. (brain dead).
MrSwiss
Posts: 3581
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Stuck writing a simple bit toggle routine

Postby MrSwiss » Aug 04, 2020 18:05

Sorry dodicat, the assignment can't be inside the #Define (aka: a function like, single line #Macro).

Code: Select all

#Define tog(flag_, position_)   (flag_) Xor (1 Shl (position_))

Dim As UShort USh = &h0F0F, res

For i As UInteger = 0 To SizeOf(USh) * 8 - 1
    res = tog(USh, i)
    ? i, Bin(USh, 16), Bin(res, 16)
Next

? : ? : ? "done"

Sleep
Result:

Code: Select all

0             0000111100001111            0000111100001110
1             0000111100001111            0000111100001101
2             0000111100001111            0000111100001011
3             0000111100001111            0000111100000111
4             0000111100001111            0000111100011111
5             0000111100001111            0000111100101111
6             0000111100001111            0000111101001111
7             0000111100001111            0000111110001111
8             0000111100001111            0000111000001111
9             0000111100001111            0000110100001111
10            0000111100001111            0000101100001111
11            0000111100001111            0000011100001111
12            0000111100001111            0001111100001111
13            0000111100001111            0010111100001111
14            0000111100001111            0100111100001111
15            0000111100001111            1000111100001111


done
jj2007
Posts: 1645
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Stuck writing a simple bit toggle routine

Postby jj2007 » Aug 04, 2020 20:01

MrSwiss wrote:Sorry dodicat, the assignment can't be inside the #Define
dodicat's solution works perfectly:

Code: Select all

Dim flag_ As integer=0
  #define tog(flag_, position_) flag_ = flag_ xor (1 shl position_)
  tog(flag_, 2)
  print "flag_=", flag_
  tog(flag_, 2)
  print "flag_=", flag_
  sleep
If one 32-bit flag variable is sufficient, it can be shortened:

Code: Select all

Dim flag_ As integer=0
  #define tog(position_) flag_ = flag_ xor (1 shl position_)
  tog(2)
  print "flag_=", flag_
  tog(2)
  print "flag_=", flag_
  sleep
Output in both cases (as expected):

Code: Select all

flag_=         4
flag_=         0
olympic sleeper
Posts: 41
Joined: Jun 07, 2020 15:47

Re: Stuck writing a simple bit toggle routine

Postby olympic sleeper » Aug 04, 2020 20:16

Hello and many thanks for the replies and suggestions.

The reason I thought about doing this in a sub/function is that I have a very similar requirement (needing different types going into a sub) in a verification routine.

To save me typing if this then whatever in a massive nest I thought of perhaps having a function that takes a value, any value - string, integer, boolean etc and compares it to another value returning 1 if they match and 0 if they do not. I'm now wondering if overload will solve this, or even its possible.

The calls would be something like:

Code: Select all

compare(string_var,"")
compare(integer_var,0)
compare(ubyte,6)
compare(ushort,9)


The great thing about this would be that you can just add them together like so

Code: Select all

value=compare(string_var,"")+compare(integer_var,0)+compare(ubyte,6)+compare(ushort,9)

if value=0 then ....


So would several functions like this, work?

Code: Select all

function compare OverLoad(thing_to_check As string,value  As string)
   if thing_to_check=value then return 1
return 0
end function
function compare OverLoad(thing_to_check As ubyte,value ubyte)
   if bit(thing_to_check,value) then return 1
return 0
end function
etc...

Return to “Beginners”

Who is online

Users browsing this forum: No registered users and 6 guests