Skip to content

Commit ea2850f

Browse files
committed
stdlib
1 parent bcd73d7 commit ea2850f

File tree

6 files changed

+1503
-8
lines changed

6 files changed

+1503
-8
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
coclass 'jdictionary'
2+
3+
SIZE_GROWTH_GEOMETRIC_STEP =: 2
4+
5+
create =: {{)m
6+
'index_type creation_parameters' =. y
7+
8+
NB. Default values of params.
9+
keytype =: 4
10+
keyshape =: i. 0
11+
valuetype =: 4
12+
valueshape =: i. 0
13+
keyhash =: 16!:0`''
14+
keycompare =: 16!:0`''
15+
initsize =: 100
16+
name =: ''
17+
18+
if. (-: (index_type {.~ -@#)) 'concurrent' do.
19+
singlethreaded =. 0
20+
index_type =. (- # ' concurrent') }. index_type
21+
else.
22+
singlethreaded =. 1
23+
end.
24+
25+
select. index_type NB. set up params for create, based on map type
26+
case. 'hash' do.
27+
itype =: 0 NB. index type 0 is hash
28+
occupancy =: 0.5 NB. default for occupancy
29+
NB. Parse params and update above attributes.
30+
parse^:(*@#) creation_parameters
31+
internal_parameters =. (0 , initsize , <. initsize % occupancy) ; singlethreaded ; (keytype ; keyshape) ; < (valuetype ; valueshape)
32+
case. 'tree' do.
33+
itype =: 1 NB. index type 1 is tree
34+
NB. Parse params and update above attributes.
35+
parse^:(*@#) creation_parameters
36+
if. 0 <: 4!:0 < 'occupancy' do.
37+
13!:8 (3) [ 'Parameter not supported in tree dictionary: occupancy'
38+
end.
39+
internal_parameters =. (0 , initsize) ; singlethreaded ; (keytype ; keyshape) ; < (valuetype ; valueshape)
40+
case. do.
41+
13!:8 (3) [ 'Incorrect index type'
42+
end.
43+
44+
NB. Create the map, which remains as dict. dict is marked nondisplayable because 1 {:: dict is.
45+
NB. If 1 {:: dict (keys) is an indirect type, it is death to touch or display any part of 1 {:: dict that is on the empty list.
46+
NB. It might be better not to assign dict, to make it impossible to access 1 {:: dict from console level. But we have to be able to run 16!:_5 on it - make 16!:_5 an adverb
47+
if. keyhash -: keycompare do. keyfn =. keyhash `: 6 else. keyfn =. keyhash `: 6 : (keycompare `: 6) end.
48+
size =: initsize
49+
dict =: keyfn f. (16!:_1) internal_parameters
50+
51+
NB. Assign names.
52+
if. name -: '' do. prefix =. suffix =. '' else. 'prefix suffix' =. (,{:)&.>/\. split_name name end.
53+
(prefix , 'get' , suffix) =: dict 16!:_2
54+
(prefix , 'put' , suffix) =: dict 16!:_3
55+
(prefix , 'del' , suffix) =: dict 16!:_4
56+
(prefix , 'has' , suffix) =: dict 16!:_12
57+
(prefix , 'len' , suffix) =: 0&(16!:_8)@dict
58+
if. index_type -: 'tree' do. (prefix , 'getkv' , suffix) =: dict 16!:_6 end. NB. getkv only on rb trees
59+
EMPTY
60+
}}
61+
62+
destroy =: {{
63+
(1) 16!:_5 dict NB. clear the empty chain in the keys to avoid errors freeing it
64+
codestroy y NB. destroy the locale, freeing everything
65+
}}
66+
67+
NB. Resize operation. Nilad. Allocate a larger/smaller dictionary and repopulate its keys
68+
NB. We have a lock on (dict) during this entire operation
69+
resize =: {{)m
70+
size =: SIZE_GROWTH_GEOMETRIC_STEP * size
71+
NB. We allocate a new DIC block of the correct size. This is a temp whose contents, when filled, will be exchanged into (dict)
72+
NB. This also allocates new areas for the keys, vals, and hash/tree
73+
select. itype
74+
case. 0 do.
75+
newdict =. dict (16!:_1) 0 , size , <. size * % occupancy NB. allocate new DIC (hashed)
76+
NB. for hashing: call (newdict 16!:_3) to rehash all the keys. Limit the number of kvs per install to reduce temp space needed.
77+
NB. Install the kvs from dict into newdict. (e =. 1&(16!:_5) dict) (1) returns the list of empty key indexes; (2) erase the empty chains
78+
NB. to allow the key block to be freed. Then (<<<e) { keys/vals gives the kvs:
79+
empties =. (1) 16!:_5 dict NB. get list of empties in dict, then erase the empty chains. Prevents free error when releasing dict
80+
(newdict 16!:_3)&((<<<empties)&{)&:>/ 2 1 { dict NB. Install all keys from dict into newdict
81+
case. 1 do.
82+
newdict =. dict (16!:_1) 0 , size NB. allocate new DIC (tree)
83+
NB. for red/black: copying the keys, vals, and tree from dict to newdict is done in JE when we return
84+
end.
85+
newdict NB. Return the new block. Its contents will be swapped with the old block so that the EPILOG for the resize will free the old keys/vals/hash
86+
}}
87+
88+
NB. Utils.
89+
NB. Gives type ID (e.g. 4) from type name (e.g. integer).
90+
typeid_from_typename =: {{)m
91+
n =. 1 2 4 8 16 32 64 128 1024 2048 4096 8192 16384 32768 65536 131072 262144
92+
n =. n , 5 6 7 9 10 11
93+
n =. n , _1 NB. _1 if y is not a name of any type.
94+
t =. '/boolean/literal/integer/floating/complex/boxed/extended/rational'
95+
t =. t , '/sparse boolean/sparse literal/sparse integer/sparse floating'
96+
t =. t , '/sparse complex/sparse boxed/symbol/unicode/unicode4'
97+
t =. t , '/integer1/integer2/integer4/floating2/floating4/floating16'
98+
n {~ (<;._1 t) i. < y
99+
}}
100+
101+
NB. Parse attribute and set its value.
102+
parse =: {{)m
103+
'attribute value' =: y
104+
if. ('literal' -: datatype value) *. (attribute -: 'keytype') +. attribute -: 'valuetype' do.
105+
value =. typeid_from_typename value
106+
end.
107+
(attribute) =: value
108+
EMPTY
109+
}}"1
110+
111+
NB. y is string representing a name with possibly specified locale. Returns two boxes: name ; suffix with locale.
112+
NB. Right part of hook.
113+
NB. If '_' is the last character of y then the name has explicitly specified locale, so get the indexes of '_'.
114+
NB. Left part of hook.
115+
NB. Use the indexes to split the name or if the number of indexes is less than 2 then suppose name is from base.
116+
NB. Note that number of indexes may be smaller then number of '_' e.g. 0 when condition from right part of the hook was false.
117+
split_name =: ('__' ,~&< [)`(({. ,&< }.)~ _2&{)@.(2 <: #@]) ''"_`([: I. '_'&=)@.('_' -: {:)

0 commit comments

Comments
 (0)