Recent

Author Topic: CASE statement with strings.  (Read 47252 times)

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: CASE statement with strings.
« Reply #15 on: May 07, 2020, 08:59:45 pm »
Fact is this feature is just sintactic sugar, albeit a very palatable one. How palatable can be seen by comparing the example Remy quoted with the equivalent:

Code: Pascal  [Select][+][-]
  1. sOS := lowercase(OS);
  2. if (sOS = 'windows')
  3. or (sOS = 'dos') then
  4.   WriteLn ('Microsoft playtform')
  5. else
  6.   if (sOS = 'macos')
  7.   or (sOs = 'darwin') then
  8.     Writeln('Apple platform')
  9.   else
  10.     if (sOS = 'linux')
  11.     or (sOS = 'freebsd')
  12.     or (sOS = 'netbsd') then
  13.       Writeln('Community platform')
  14.     else
  15.       WriteLn ('Other platform');

Who wouldn't prefer the 'case'? ;)
« Last Edit: May 07, 2020, 09:01:28 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: CASE statement with strings.
« Reply #16 on: May 07, 2020, 09:32:44 pm »
Hi!

The reality was even worse when you had to handle complicated stuff.
Then it went this way:

Code: Pascal  [Select][+][-]
  1.     sOS := lowercase(OS);
  2.     if (sOS = 'windows')
  3.     or (sOS = 'dos') then
  4.      Plattform := 4
  5.     else
  6.       if (sOS = 'macos')
  7.       or (sOs = 'darwin') then
  8.         Plattform := 3
  9.       else
  10.         if (sOS = 'linux')
  11.         or (sOS = 'freebsd')
  12.         or (sOS = 'netbsd') then
  13.           Plattform := 2
  14.         else
  15.           Plattform := 1;
  16.  
  17. case Plattform of
  18. 1 : begin  ........
  19.  
  20.  
  21.  

The implementation of case with strings might be slow, but we dont work on Apple II with two floppy drives anymore. That was slow.

Winni

PS.: Plattform is german. Sorry
« Last Edit: May 07, 2020, 09:36:18 pm by winni »

Bart

  • Hero Member
  • *****
  • Posts: 5265
    • Bart en Mariska's Webstek
Re: CASE statement with strings.
« Reply #17 on: May 07, 2020, 10:22:04 pm »
The case of strings was added just for convenience.

Bart

dbannon

  • Hero Member
  • *****
  • Posts: 2778
    • tomboy-ng, a rewrite of the classic Tomboy
Re: CASE statement with strings.
« Reply #18 on: May 08, 2020, 01:00:15 am »
The case of strings was added just for convenience.
Bart

And very convenient it is !

If we did not have that capability, we'd probably still stick with a cascading series of 'if' statements, just as slow and much more error prone.

David
Lazarus 2, Linux (and reluctantly Win10, OSX)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: CASE statement with strings.
« Reply #19 on: May 08, 2020, 01:11:20 am »
I did not notice the lowercase before.

That is even worse. Never allocate memory for a comparison.

I have actually benchmarked the lowercase case: https://gist.github.com/benibela/f7f1f4d6ba04a0f84045b77904306c75

It is like 4 times slower than other approaches

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: CASE statement with strings.
« Reply #20 on: May 08, 2020, 02:08:09 am »

It is like 4 times slower than other approaches

How much µ seconds?

Winni

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: CASE statement with strings.
« Reply #21 on: May 08, 2020, 05:07:21 am »
It is like 4 times slower than other approaches

That's quite logical; using a string-case is almost exactly as doing the long series of nested IFs, while the hash (or any other ordinal) CASE is optimized through jumptables and what-not.

Note, though, that AFAICS your test doesn't capture the time taken to calculate the hash from the strings; it might or might not be significant, depending on the hash method and the kind (and length) of the strings.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: CASE statement with strings.
« Reply #22 on: May 08, 2020, 09:15:47 am »

The case with strings is equivalent to a series of if then else statements, no optimizations are performed.


Business as usual

A great idea and then a crap implementation

It should use a trie or at least a hashmap

It also needs to support ranges.

But hey, guess what, if you want you can provide patches to improve it.

It also does not yet support constant propagation (like the normal case-statement does).

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: CASE statement with strings.
« Reply #23 on: May 08, 2020, 03:55:56 pm »

How much µ seconds?


120 Nanoseconds each iteration !





That's quite logical; using a string-case is almost exactly as doing the long series of nested IFs, while the hash (or any other ordinal) CASE is optimized through jumptables and what-not.

The hash case also becomes a series of nested IFs. But an integer comparison is faster than a string comparison


Note, though, that AFAICS your test doesn't capture the time taken to calculate the hash from the strings; it might or might not be significant, depending on the hash method and the kind (and length) of the strings.

It tests both.

But that is on purpose, since I use it for HTML and calculate the hash for all HTML elements when loading the file



Nevertheless that is why I have a hunch that that a trie would perform better than a hash


It also needs to support ranges.

Is there really a need for ranges?


But hey, guess what, if you want you can provide patches to improve it.


I already wrote a bye-coded trie for my Internet Tools. You could copy it

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: CASE statement with strings.
« Reply #24 on: May 08, 2020, 04:02:14 pm »
It also needs to support ranges.

Is there really a need for ranges?

The normal case-statement supports ranges as well, thus case-of-string got support for that as well. This will not be removed.


But hey, guess what, if you want you can provide patches to improve it.


I already wrote a bye-coded trie for my Internet Tools. You could copy it

I'm not interested in optimizing case-of-string except maybe constant propagation.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8744
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: CASE statement with strings.
« Reply #25 on: May 10, 2020, 12:11:47 am »
Back in the day I proposed to implement this using prefix tree (or trie) instead (fastest, guaranteed O(n) where n is the query length), but it turns out generating code that calls AnsiCompareStr sequentially is much easier and the resulting code is smaller, too.

CCRDude

  • Hero Member
  • *****
  • Posts: 596
Re: CASE statement with strings.
« Reply #26 on: September 17, 2021, 05:16:09 pm »
Hello, I guess you use
Code: [Select]
{$mode delphi}
It works here with FPC 3.1.1 and
Code: [Select]
{$mode objfpc}
It works in FPC/ObjFPC mode only. Delphi, TP, MacPas and ISO mode doesn't support it for compatibility.

Bringing up an old thread here... would it be possible to enable this in other modes using a $modeswitch maybe?

tr_escape

  • Sr. Member
  • ****
  • Posts: 432
  • sector name toys | respect to spectre
    • Github:

cdbc

  • Hero Member
  • *****
  • Posts: 995
    • http://www.cdbc.dk
Re: CASE statement with strings.
« Reply #28 on: October 17, 2022, 02:53:05 pm »
Hi
A long time ago, I needed to use strings in a case statement...
I came up with this and i've been using it a lot, since then  ;)
Code: Pascal  [Select][+][-]
  1. { bcStrCase usage....
  2.   case bcStrCase(S,['+date','+hello','+data','+quit']) of
  3.     0..1: ShowMessage('Hello @ '+datetimetostr(now)); // '+date' -> '+hello'
  4.     2: SendDataSomewhere; //+data
  5.     3: Close; // +quit
  6.   end; }
  7. { bcStrCase is zero-based, returns -1 on not found }
  8. function bcStrCase(const S: string;Elements: array of string): ptrint;
  9. var Idx: ptrint;
  10. begin
  11.   Result:= -1; { hence the result ~ ptrint }
  12.   { perform a linear search }
  13.   for Idx:= low(Elements) to high(Elements) do if S = Elements[Idx] then begin
  14.     Result:= Idx;
  15.     break;
  16.   end;
  17. end; { bcStrCase }
  18.  
It deals with range too, see "0..1: showme...."
I dunno how fast it is, I just find it conveinient to use.
Regards Benny
« Last Edit: October 17, 2022, 03:01:36 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: CASE statement with strings.
« Reply #29 on: October 18, 2022, 07:34:02 am »
A long time ago, I needed to use strings in a case statement...
I came up with this and i've been using it a lot, since then  ;)
Code: Pascal  [Select][+][-]
  1. { bcStrCase usage....
  2.   case bcStrCase(S,['+date','+hello','+data','+quit']) of
  3.     0..1: ShowMessage('Hello @ '+datetimetostr(now)); // '+date' -> '+hello'
  4.     2: SendDataSomewhere; //+data
  5.     3: Close; // +quit
  6.   end; }
  7. { bcStrCase is zero-based, returns -1 on not found }
  8. function bcStrCase(const S: string;Elements: array of string): ptrint;
  9. var Idx: ptrint;
  10. begin
  11.   Result:= -1; { hence the result ~ ptrint }
  12.   { perform a linear search }
  13.   for Idx:= low(Elements) to high(Elements) do if S = Elements[Idx] then begin
  14.     Result:= Idx;
  15.     break;
  16.   end;
  17. end; { bcStrCase }
  18.  
It deals with range too, see "0..1: showme...."
I dunno how fast it is, I just find it conveinient to use.

Are you aware that this already exists in the StrUtils unit in the form of IndexStr and IndexText?

 

TinyPortal © 2005-2018