mIRC Home    About    Download    Register    News    Help

Print Thread
Hashtable enhancements #270137 08/04/22 12:55 PM
Joined: Jan 2004
Posts: 1,745
maroon Offline OP
Hoopy frood
OP Offline
Hoopy frood
Joined: Jan 2004
Posts: 1,745
Several changes to hashtable functions that would make them better able to mimic the behavior of %variables, and changes to /var -g to enable it to better mimic /set. Perhaps requiring a new switch if any changes are considered to violate backwards compatibility


1. Currently, /var ignores switches like -uN -z under the theory that these are irrelevant. However these are no longer irrelevant in the presence of the -g switch

//var -sgz %foo 5 , %bar 4 | timer 1 10 echo -a future: foo: % $+ foo bar: % $+ bar

//var -sgu2 %foo 5 , %bar 4 | timer 1 5 echo -a future: foo: % $+ foo bar: % $+ bar

After the change, these examples would no longer ignore -z and -u2, and either create countdown-to-zero variables, or unset them after 2 secs

They'd continue to be errors if -g isn't used

At first I was thinking that -uN wasn't even irrelevant for /var without using -g, but the snippet below demonstrates to me that, not only does the -u5 cause %string to not vanish after 5 secs during the time the script runs for 10 secs, but the countdown clock for deleting it doesn't start until after the script quits

//set -su5 %string string | var %delay 10 , %ctime $ctime | while (%delay) { while (%ctime == $ctime) { noop } | echo -a time $time string %string unset in $var(%string,1).secs secs | var %ctime $ctime | dec %delay } | timer 6 1 echo 4 -a string: % $+ string


2. /hinc and /hdec should be consistent with /inc and /dec in how they handle non-numeric strings - whichever way that may be

Currently, /inc and /dec leave a text variable unmodified, but /hinc and /hdec treat it as if it's zero, then change the value to 1 or -1:

//var -s %init text , %foo %init | hadd -ms test foo %init | inc -s %foo | hinc -s test foo | echo -a result: var: %foo table: $hget(test,foo)

result: var: text table: 1

It seems reasonable that both should be consistent with each other

If this violates backwards compatibility, then some arbitrary switch could house the compatible-between-inc-hinc behavior when interacting with non-numeric strings. This is not wanting any change from the current behavior of treating blank same as zero.

This treatment of the prior text value by /inc is also at odds with how it treats its own increment parm, treating text as if it's not present so uses the default +1:

//var %foo text | inc -s %foo | echo -a result: %foo
result: text
//var %foo 3 | inc -s %foo text | echo -a result: %foo
result: 4
//var %foo 3 | inc -s %foo 0 | echo -a result: %foo
result: 3


3. Give /hadd an enhancement of the -iN switch similar to the capability of /var and /set, which adds the item only if it doesn't already exist. Perhaps also enable the alternative behavior that updates the item only if it DOES exist.

For the next example, the data would remain at value1, since the -i switch would prevent overwriting an existing item's value. Same as with /var and /set, using -i would not cause the script to halt simply because the item already exists.

//hadd -sm test item value1 | hadd -s test item value2 | echo -a value: $hget(test,item)

The default of -i would be the same as -i1 which adds the item only if it does not exist.

The -i2 switch would be the opposite of -i, where -i2 adds the item only if it DOES exist. i.e. update-only.

It may be simpler from a coding perspective to have the alternatives be -i0 and -i1 to treat this as a bitflag mask.

I assume that using -i and -m together should not result in the table being created unless the item is added/updated into the table.

This change would avoid the need to use $hfind or $var() to hunt for an item before having a branch decision which chooses whether or not it should be added/updated.

As the next example shows, var -i checks whether the variable exists, not whether it's non-NULL, and the variable is not set to 3 even if it already exists as blank, so I foresee /hadd -i to be the same, where an existing item with a blank data is treated no differently than an existing item with a non-blank string

//var -s %a | set -si %a 3


4. Make -s (or something like -S or -v verbose) be more useful info.

//var -s %foo bar
* Set %foo to bar
//hadd -ms table item value
* Added item 'item' to hash table 'table'

Since /var /set /hadd do not treat -S as a case-insensitive equivalent to -s, that could be a way to get the more useful debugging info if it's decided that updating the /hadd -s behavior is not backwards compatible

This text for /hadd /hinc /hdec would be much more valuable as a debugging aid if it actually told you the value, and also if it informed you the truth as to whether the item was actually 'added' or was merely 'updated'. Changing an existing item from $null data to non-blank is updated. Proposed would be:

/hadd -mS table item value1
* Added item 'item' to hash table 'table' as value 'value1'
/hadd -mS table item value2
* Updated item 'item' in hash table 'table' to value 'value2'
/hadd -bS table item &binvar
* Updated item 'item' in hash table 'table' from binvar '&binvar'

I assume /hload and /hsave have the item count at their fingertips

/hload -mS test filename.txt
* Loaded hash table 'test' from 'filename.txt' 123 items
/hsave -mS test filename.txt
* Saved hash table 'test' to 'filename.txt' 123 items

/hinc -S test counter1
* Inc item 'counter1' in hash table 'test' to '1'
/hdec -S test counter2
* Dec item 'counter2' in hash table 'test' to '-1'

Using -s with /set and /var is very helpful as a debugging tool, and would make it similarly helpful with /hadd if it told you what it did rather than just telling you that it set an item to "i'm not telling you" without indicating whether this is a new or changed item.


5. Give $hfind and /hdel the -x switch owned by /filter which allows matching everything except the matchtext.

Delete all items except those beginning with 'index':

/hdel -swx table index*

Match all items except those whose data value is 0

//noop $hfind(table,0,0,nx,hinc -sx table $1).data

Match all items except those begining with @

//noop $hfind(pnicks,@*,0,wx,kick $chan $1)

Delete all items whose value is non-integer

//noop $hfind(table,-?\d+,0,rx,hdel -sx table $1).data

Re: Hashtable enhancements [Re: maroon] #270144 10/04/22 09:03 AM
Joined: Jan 2004
Posts: 1,745
maroon Offline OP
Hoopy frood
OP Offline
Hoopy frood
Joined: Jan 2004
Posts: 1,745
Regarding bullet item#2 where /inc and /dec don't alter the %variable if it's not numeric, here's an example where the input to /inc is not altered, resulting in an infinite loop freeze. The alternatives are:

1. Continue existing /inc behavior of not altering non-numeric non-blank input, leaving %counter unchanged forever
2. Do like /hinc does and treat %counter as if it has value zero, then inc that to 1, regardless of the string's contents
3. Do like $calc() does and harvest numerics from the beginning to treat as if this is '2' that needs to inc to 3
4. Halt with error
5. Unrelated change in design that doesn't address the issue of incrementing text, to not treat a lone trailing pipe symbol the same as $chr(124)

While testing
where the script started out with everything on 1 line, I was testing to see what's the max that stays on the same line without having the 'duplicate goto' error.

I separated the 1st command from everything else, and everything froze. At first I thought this was fallout from the duplicate label, but when adding the -s switch to /var, I realized that leaving the trailing pipe symbol caused the variable to be set to a string containing the | pipe symbol, so /inc was seeing this as non-numeric, so it didn't increment the counter. If I alter this to have 2 separate trailing pipes, it's a separate error due to not linking an empty command between 2 pipes.

Warning to forum readers that they will need to use Ctrl+Break to halt the infinite loop in this alias, but it doesn't freeze if you remove the | pipe symbol:

alias inc_freeze {
  ;var -s %counter 2 | |
  var  -s %counter 2 |
  inc -s %counter
  if (%counter == 4) return
  goto sup