Ooops
March 05, 2021, 07:00:02 PM

Author Topic: Exiting Case/select statements  (Read 652 times)

Offline Baggey

Exiting Case/select statements
« on: January 30, 2021, 09:00:36 AM »
Hi ALL,
Im new here. But have been working behind the Scene's With BlitzMax. Ive tried other dialects and feel comfortable with BlitzMax. Would love to get IdealIDE working with it thou.

Im Currently writing a program for Emulation purpouses with huge Select/Case statements. Is there a way of breaking out of the Select/case as soon as ive found the case im looking for. Im trying to speed things up a little. Note im using Superstrict mode as well.

In most selects there are 6*256 cases but if i say find the first few can i step out of all the other case tests?  ::)

Kind Regards Baggey
Currently Running a PC that just Aint fast enough!?
ZX Spectrum 48k, NEXT, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip.

Jesus was only famous because of his DAD.

Offline Derron

Re: Exiting Case/select statements
« Reply #1 on: January 30, 2021, 09:22:26 AM »
You should not require to exit the select block.

Select blocks are like "if x, elseif y, elseif z..." blocks.

Select values are only evaluated once.


Also interesting: you can do "Select True ..." and have expressions in the "case".


Code: BlitzMax
  1. SuperStrict
  2. Framework Brl.StandardIO
  3.  
  4. Local i:Int = 1
  5.  
  6. Select True
  7.         Case i < 5
  8.                 Print "i < 5"
  9.         Case i < 2
  10.                 Print "i < 2"
  11. End Select
  12.  
  13.  
  14. Select i
  15.         Case 1
  16.                 Print "1"
  17.         Case 1, 2
  18.                 Print "1 or 2"
  19.         Case 2
  20.                 Print "2"
  21. End Select
  22.  


If it continued checking other "case" after it found one, it would print out multiple lines - but it only prints the first "hit".


bye
Ron

Offline Baggey

Re: Exiting Case/select statements
« Reply #2 on: January 30, 2021, 12:14:22 PM »
Thanks,

After case 1 it does the print"1". So Does BlitzMax stop the condition checking? Or will it still check conditions for 2 and 3 and so on, ie in my case another 254 checks! Or just fall out of the whole Select/Case loop so to speak?

If it does i supouse theres no other way of breaking out or creating an error to fall out or am i missing the point.

Speed for me here is crucial!

Kind Regards Baggey

Currently Running a PC that just Aint fast enough!?
ZX Spectrum 48k, NEXT, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip.

Jesus was only famous because of his DAD.

Offline Steve Elliott

Re: Exiting Case/select statements
« Reply #3 on: January 30, 2021, 01:09:20 PM »
Quote
After case 1 it does the print"1". So Does BlitzMax stop the condition checking?

Code: [Select]
Select i
        Case 1
                Print "1"
        Case 1, 2
                Print "1 or 2"
        Case 2
                Print "2"
End Select

In Derron's code, if i is set to 1 and it only prints "1" then it is breaking out and not checking any further - or you would get "1" printed, followed by "1 or 2".
Windows 10 64-bit, 16Gb RAM, Intel i5 3.2 GHz, Nvidia GeForce GTX 1050 (2Gb)
MacOS Big Sur 64-bit, 8Gb RAM, Intel i5 2.3 Ghz, Intel Iris Plus Graphics 640 1536 MB
Linux Mint 19.3 64-bit, 16Gb RAM, Intel i5 3.2 GHz, Nvidia GeForce GTX 1050 (2Gb)
Raspberry Pi 400, Pi4, BBC B, C64, ZX Spectrum

Offline Dabz

Re: Exiting Case/select statements
« Reply #4 on: January 30, 2021, 02:42:16 PM »
If I'm guessing correctly, you want to do something like this:-

Code: [Select]

Local i = 0

Repeat
i = i + 1
If i = 1
Print "1"
Continue 'Continue sends program flow back to "Repeat", ignoring everything below
EndIf

If i = 2
Print "2"
Continue
EndIf

If i = 3
Print "3"
If someCondition = False
'We can move i to 6, skipping 4 and 5
i = 5 'Set it to 5 as it gets incremented at the top
Continue
EndIf
Continue
EndIf

If i = 4
Print "4"
Continue
EndIf

If i = 5
Print "5"
Continue
EndIf


If i = 6
Print "6"
If someCondition = False
'break loop
Exit
EndIf
Continue
EndIf

'we never see this
If i = 7
Print "7"
Continue
End If
Until i = 254

Not sure if its the best way, you could put "i=i+1" instead of continue I suppose, but as you can see, you can juggle about with it, very spaghetti like setup, but, just off the cuff, maybe the answer unless someone knows a better way.

Dabz
Intel Core i5 6400 2.7GHz, NVIDIA GeForce GTX 1070 (8GB), 16Gig DDR4 RAM, 256GB SSD, 1TB HDD, Windows 10 64bit

Offline Baggey

Re: Exiting Case/select statements
« Reply #5 on: January 30, 2021, 03:08:06 PM »
Ah, Yes of course as the second iteration would be (one or Two) aswell! Thus proving it does break out of the Select/Case. So the Speed i was hoping to gain can't happen. Oh well.
I like the way the Select/Case makes the code eaisier to read. I like your idea Dabz as i could use The Rem or comment above each "If".

Would 255 If statments like that be Quicker than Select and then 255 Case's!?

Dare i say it I did even think of Functions But they'd still would have to be selected anyway. And Dare i really say it the OLD GOTO  >:D

So maybe a bunch of if's is quicker than a Select/Case senario? I proabably have stumbled across the easy way of doing the selection. But Speed is what im after!

Coding 256 if Statements 6 times right now, Dosent seem like a lot of Fun if theres no gain. So would a load of if's be quicker than Case/Select.
 
Baggey
Currently Running a PC that just Aint fast enough!?
ZX Spectrum 48k, NEXT, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip.

Jesus was only famous because of his DAD.

Offline Dabz

Re: Exiting Case/select statements
« Reply #6 on: January 30, 2021, 03:13:13 PM »
Quote
Would 255 If statments like that be Quicker than Select and then 255 Case's!?

Ultimately, I think it all boils down to what you do... You'll have to benchmark both ways... Generally going off the interwebs, in C languages at least, switch case setups are faster then ifelse ones, switch case v single if setups like my example, not a scooby do? :)

Dabz
Intel Core i5 6400 2.7GHz, NVIDIA GeForce GTX 1070 (8GB), 16Gig DDR4 RAM, 256GB SSD, 1TB HDD, Windows 10 64bit

Offline Steve Elliott

Re: Exiting Case/select statements
« Reply #7 on: January 30, 2021, 03:29:24 PM »
Quote
Ah, Yes of course as the second iteration would be (one or Two) aswell! Thus proving it does break out of the Select/Case.

Exactly.

Quote
Would 255 If statments like that be Quicker than Select and then 255 Case's!?

The more items the more the Select/Case wins in speed, basically hash tables (lookups) are used and the compiler will find it easier to optimize - plus it's far more readable too.

Windows 10 64-bit, 16Gb RAM, Intel i5 3.2 GHz, Nvidia GeForce GTX 1050 (2Gb)
MacOS Big Sur 64-bit, 8Gb RAM, Intel i5 2.3 Ghz, Intel Iris Plus Graphics 640 1536 MB
Linux Mint 19.3 64-bit, 16Gb RAM, Intel i5 3.2 GHz, Nvidia GeForce GTX 1050 (2Gb)
Raspberry Pi 400, Pi4, BBC B, C64, ZX Spectrum

Offline TomToad

Re: Exiting Case/select statements
« Reply #8 on: January 30, 2021, 04:18:07 PM »
What is fastest depends on what exactly you are trying to accomplish.  For example, if you are just trying to map values like so:
Code: [Select]
If a = 1
    b = 12
elseif a = 2
    b = 20
elseif a = 3
    b = 18
etc...
It may be easier to just use an array
Code: [Select]
local ValueMap:int[] = [0,12,20,18]
b = ValueMap[a]
If you need to map to an object, you can use TMap
Code: [Select]
Local ObjectMap:TMap = CreateMap()
ObjectMap.Insert("1",Object1)
ObjectMap.Insert("2",Object2)
ObjectMap.Insert("3",Object3)

local b:MyObject = MyObject(ObjectMap.ValueForKey(String.FromInt(a)))
If you need something more complex, You can use function pointers and arrays
Code: [Select]
Function Function1()
    Print "1"
End Function

Function Function2()
    Print "2"
End Function

Function Function3()
    Print "3"
ENd Function

Local FunctionArray:Function()[3]
FunctionArray[1] = Function1
FunctionArray[2] = Function2
FunctionArray[3] = Function3

FunctionArray[a]()

To make typing easier, you can use a type with reflection.  Adds a tiny bit of overhead, but is still better than 200+ Select/Case statements
Code: [Select]
SuperStrict

Type TCaseFunctions
Global Functions:TMethod[]

Method New()
Local TypeID:TTypeId = TTypeId.ForObject(Self)
functions = TMethod[](TypeID.EnumMethods().ToArray())
End Method

Method Case1()
Print "Case 1"
End Method

Method Case2()
Print "Case 2"
End Method

Method Case3()
Print "Case 3"
End Method
End Type

Local CaseFunctions:TCaseFunctions = New TCaseFunctions
For Local i:Int = 1 Until CaseFunctions.Functions.Length
CaseFunctions.Functions[i].invoke(CaseFunctions)
Next
------------------------------------------------
8 rabbits equals 1 rabbyte.

Offline Derron

Re: Exiting Case/select statements
« Reply #9 on: January 30, 2021, 05:16:08 PM »
If you use NG and do that objectmap thing:
Code: BlitzMax
  1. Local ObjectMap:TMap = CreateMap()
  2. ObjectMap.Insert("1",Object1)
  3. ObjectMap.Insert("2",Object2)
  4. ObjectMap.Insert("3",Object3)
  5.  
  6. local b:MyObject = MyObject(ObjectMap.ValueForKey(String.FromInt(a)))
  7.  

You could even use a TIntMap there... it is faster as it does not use string comparisons (and casts)
Code: BlitzMax
  1. Local ObjectMap:TIntMap = new TIntMap
  2. ObjectMap.Insert(1, Object1)
  3. ObjectMap.Insert(2, Object2)
  4. ObjectMap.Insert(3, Object3)
  5.  
  6. local a:int = 2
  7. local b:MyObject = MyObject(ObjectMap.ValueForKey(a))
  8.  


Same to say for TStringMap, TObjectMap, ...


But TomToad summarized it up really good : it depends on what you actually try to achieve.

If you have
Code: BlitzMax
  1. If a = 1
  2.   b = 2
  3. ElseIf a = 2
  4.   b = 3
  5. ElseIf a = 3
  6.   b = 4
  7. ElseIf a = 4
  8.   b = 5
  9. ElseIf a = 5
  10.   b = 6
  11. EndIf
  12.  

you would better write
If you have
Code: BlitzMax
  1. If a > minA and a < maxB
  2.   b = a + 1
  3. EndIf
  4.  


bye
Ron

Offline Baggey

Re: Exiting Case/select statements
« Reply #10 on: January 30, 2021, 05:48:04 PM »
Code: [Select]
SuperStrict

Type TCaseFunctions
Global Functions:TMethod[]

Method New()
Local TypeID:TTypeId = TTypeId.ForObject(Self)
functions = TMethod[](TypeID.EnumMethods().ToArray())
End Method

Method Case1()
Print "Case 1"
End Method

Method Case2()
Print "Case 2"
End Method

Method Case3()
Print "Case 3"
End Method
End Type

Local CaseFunctions:TCaseFunctions = New TCaseFunctions
For Local i:Int = 1 Until CaseFunctions.Functions.Length
CaseFunctions.Functions[i].invoke(CaseFunctions)
Next

Wow Thanks for or the help!
TOMTOAD the code above is a little bit beyond me but im having a look.
Im Writting a ZX Spectrum Emulator or i should say im almost finished! My programming isnt that good im a HOBBY programmer.

Also forgive me i dont know how to post things properly in the threads i think there called.

Im Basically selecting a byte ie i can have 256 outcomes including the 0.

Then im selecting the byte in the Case. So Z80 opcode 0 is NOP. And i run the code within the case.

What im actually trying todo is select the relevent OPCODE the quickest way!
Currently Running a PC that just Aint fast enough!?
ZX Spectrum 48k, NEXT, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip.

Jesus was only famous because of his DAD.

Offline Baggey

Re: Exiting Case/select statements
« Reply #11 on: January 30, 2021, 06:15:04 PM »
Code: [Select]
SuperStrict

Type OO_opcodes
Global Functions:TMethod[]

Method New()
Local TypeID:TTypeId = TTypeId.ForObject(Self)
functions = TMethod[](TypeID.EnumMethods().ToArray())
End Method

Method 0() ' This would be NOP case 0
' Perform task's for Nop
End Method

Method 1() ' This would be LD BC,nn
' Perform Task's for ld bc,NN
End Method

Method 2() ' This would be LD(BC),A
' Perform task's for ld (bc),a
End Method
End Type

Local CaseFunctions:TCaseFunctions = New TCaseFunctions
For Local i:Int = 1 Until CaseFunctions.Functions.Length
CaseFunctions.Functions[i].invoke(CaseFunctions)
Next

Ive altered the code above, But im not sure quite how to use the above!? ie if i have case 2 how would i use it and at the end of the day would it be quicker than 0 to 255 case statements?  :o
Currently Running a PC that just Aint fast enough!?
ZX Spectrum 48k, NEXT, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip.

Jesus was only famous because of his DAD.

Offline Derron

Re: Exiting Case/select statements
« Reply #12 on: January 30, 2021, 06:34:46 PM »
If you did not use "method" but "functions" you could even execute them then without utilizing reflection.mod's invoke.

Code: BlitzMax
  1. global opcodeFunctions:int()[]
  2. 'creating a new array each time - so only use it during initialization
  3. opcodeFunctions :+ [op1] 'adds the array to the existing one
  4. opcodeFunctions :+ [op2] 'adds the array to the existing one
  5. 'alternative
  6. 'global opcodeFunctions:int()[255]
  7. 'opcodeFunctions[0] = op1
  8. 'opcodeFunctions[1] = op1
  9.  
  10. 'execute
  11. opcodeFunctions[1]()
  12.  
  13.  
  14. Function op1:int()
  15. End Function
  16.  
  17. Function op2:int()
  18. End Function
  19.  


Why not reflection? Reflection.mod has issues on 32bit if your invoked functions or methods have "long" or "double" parameters (learned the hard way - and there are open issues on github for it). So if you can avoid reflection, then the better (especially as above code should be faster than using TMethod or TFunction.invoke())


Edit:
Nonetheless the "select case ..." should be the fastest here - albeit of course a bit more "text heavy".

bye
Ron

Offline Baggey

Re: Exiting Case/select statements
« Reply #13 on: January 30, 2021, 06:59:39 PM »
Hi Ron,
Im only using :Byte, :short and ":int's for checking CARRY" situations.

I think im going to stick to the the Select/Case. It's running fast enough, whislt im single stepping Opcode by Opcode. But when i Run in real time it bogs down, so to speak. As im watching memory in real time and Disassembling etc. When i turn all this off and go to full screen Mode im having to slow the Emulation down!

Just a few bugs to sort out and maybe ill put something up in Showcase but im interested in BLITZMAX only. Ive tried many other languages and it's what ive settled with. Coming from a retro basic progammers point of view so to speak.

Kind Regards Lee
Currently Running a PC that just Aint fast enough!?
ZX Spectrum 48k, NEXT, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip.

Jesus was only famous because of his DAD.

Offline TomToad

Re: Exiting Case/select statements
« Reply #14 on: January 30, 2021, 07:23:56 PM »
After a bit of experimenting, I've discovered that reflection is slower than I originally thought.  About 3.5x slower than using Select/Case.  But using function pointers in an array was fastest taking 1/3 the time of Select/Case.
------------------------------------------------
8 rabbits equals 1 rabbyte.

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal