NB. dictionary - see system\classes\dict\dict.txt
NB.
NB. Methods:
NB. allkv           return all keys and values
NB. clear           clear entries in dictionary
NB. delete          delete keys
NB. destroy         destroy dictionary
NB. exporttofile    write dictionary to file
NB. get             return values for given keys
NB. getfill         return the fill value
NB. getkv           return keys and values for given keys
NB. hasvalues       return keys having given values
NB. importfromfile  read dictionary from file
NB. includes        checks for keywords in dictionary
NB. isempty         return 1 if dictionary is empty
NB. putkv           replace keys and values into dictionary
NB. setfill         set the fill value
NB. size            returns number of entries in dictionary
NB.
NB. Methods:
NB. deletep         permissive delete keys
NB. exporttofilep   permissive write dictionary to file
NB. getp            permissive return values (or fill element) for given keys
NB. getkvp          permissive return keys and values for given keys
NB. importfromfilep permissive read dictionary from file
NB. putkvp          permissive append or replace keys and values into dictionary

coclass 'jzdict'

NB. =========================================================
NB.*allkv v return all keys and values
allkv=: 3 : 0
keys;values
)

NB. =========================================================
NB.*clear v clear entries in dictionary
NB. doesn't clear the fill element
clear=: 3 : 0
keys=: $0
values=: $0
)

NB. =========================================================
NB.*create v create dictionary
create=: 3 : 0
clear''
setfill $0
0
)

NB. =========================================================
NB.*delete v delete keys
NB. permissive delete__d ('key0';'key1';'key2')
NB. permissive=0 only delete keys that exist, else error
NB.            1 delete keys
NB. return: boolean mask of keys deleted
delete=: 3 : 0
0 delete y.
:
foundmsk=. keys e.~ y=. fixkeys y.
assert x. +. *./foundmsk
if. +./foundmsk do.
  keepmsk=. -.keys e. y
  keys=: keepmsk#keys
  values=: keepmsk#values
end.
foundmsk
)

NB. =========================================================
NB.*destroy v destroy dictionary
NB. default destroy
destroy=: codestroy

NB. =========================================================
NB.*exporttofile v write dictionary to file
NB. permissive exporttofile filename
NB. permissive=0 don't overwrite non-empty file
NB.            1 can overwrite non-empty file
NB. return: filename
exporttofile=: 3 : 0
0 exporttofile y.
:
ty=. 1!:21 boxopen y.
assert x. +. 0=1!:4 ty
(3!:1(<fill),(<keys),<values)1!:2 ty
1!:22 ty
y.
)

NB. =========================================================
NB.*get v return values for given keys
NB. permissive get__d ('key0';'key1';'key2')
NB. permissive=0 only return values for  keys that exist, else error
NB.            1 return values for keys that exist, else fill element
NB. return: values
get=: 3 : 0
0 get y.
:
i=. keys i. fixkeys y.
if. x. do.
  i{values,<fill
else.
  i{values
end.
)

NB. =========================================================
NB.*getfill v return the fill value
getfill=: 3 : 0
fill
)

NB. =========================================================
NB.*getkv v return keys and values for given keys
NB. permissive getkv__d ('key0';'key1';'key2')
NB. permissive=0 only return keys+values for keys that exist, else error
NB.            1 return keys+values, missing keys have value <fill>
NB. form: getkv__d ('key0';'key1';'key2')
NB. return: keys ; values
getkv=: 3 : 0
0 getkv y.
:
i=. keys i. k=. fixkeys y.
if. x. do.
  k;i{values,<fill
else.
  k;i{values
end.
)

NB. =========================================================
NB.*hasvalues v return keys with given values
hasvalues=: 3 : 0
(values e. }.0;y.)#keys
)

NB. =========================================================
NB.*importfromfile v read dictionary from file
NB. permissive importfromfile filename
NB. permissive=0 error if dictionary is non-empty
NB.            1 allow replace of non-empty dictionary
NB. return: filename
NB. see exporttofile
importfromfile=: 3 : 0
0 importfromfile y.
:
assert x. +. isempty''
ty=. 1!:21 boxopen y.
'fill keys values'=: 3!:2( 1!:1 ty)
1!:22 ty
y.
)

NB. =========================================================
NB.*includes v checks for keywords in dictionary
NB. includes__d ('key0';'key1';'key2')
NB. return: boolean key_found mask
includes=: 3 : 0
keys e.~ fixkeys y.
)

NB. =========================================================
NB.*isempty v return 1 if dictionary is empty
isempty=: 3 : 0
0 = size''
)

NB. =========================================================
NB.*putkv v put keys and values into dictionary
NB. permissive putkv__d ('key0';'key1';'key2');value0;value1;value2
NB. permissive=0 only replace existing keys, error if key not found
NB.            1 replace or append as necessary
NB. return: boolean was_updated mask (may be zero if multiple replaces attempted)
putkv=: 3 : 0
0 putkv y.
:
k=. fixkeys >{. y.
nubmsk=. ~:&.|.k NB. nub from end, last value gets taken
v=. }. y.
k=. nubmsk#k
if. 1=#v do.
  v=. (#nubmsk)#v NB. scalar extension
end.
v=. nubmsk#v
i=. keys i. k
notfoundmsk=. i = #keys
if. x. *. +./notfoundmsk do.
  i=. ((#keys)+i.+/notfoundmsk) (I. notfoundmsk)}i
  keys=: keys,notfoundmsk#k
  values=: values,(+/notfoundmsk)#a:
end.
values=: v i} values
nubmsk
)

NB. =========================================================
NB.*setfill v set the fill value
setfill=: 3 : 0
fill=: y.
)

NB. =========================================================
NB.*size v returns number of entries in dictionary
size=: 3 : 0
#keys
)

NB. =========================================================
NB. convenient shortcuts for using permissive versions of methods
putkvp=: 1: putkv ]
getkvp=: 1: getkv ]
getp=: 1: get ]
deletep=: 1: delete ]
importfromfilep=: 1: importfromfile [
exporttofilep=: 1: exporttofile [

NB. =========================================================
NB. fixkeys
fixkeys=: 3 : 0
if. 0= L. y. do.
  <y.
else.
  ,&.>y. NB. make sure that 'a' is ,'a'
end.
)
