|
| 1 | +coclass 'jdict' |
| 2 | + |
| 3 | +SIZE_GROWTH_GEOMETRIC_STEP =: 2 |
| 4 | + |
| 5 | +create =: {{)m |
| 6 | +if. 'literal' -: datatype y do. |
| 7 | + index_type =. y |
| 8 | + creation_parameters =. '' |
| 9 | +else. |
| 10 | + 'index_type creation_parameters' =. y |
| 11 | +end. |
| 12 | +NB. Default values of params. |
| 13 | +keytype =: 4 |
| 14 | +keyshape =: i. 0 |
| 15 | +valuetype =: 4 |
| 16 | +valueshape =: i. 0 |
| 17 | +keyhash =: 16!:0`'' |
| 18 | +keycompare =: 16!:0`'' |
| 19 | +initcapacity =: 100 |
| 20 | +NB. Names of params. |
| 21 | +long_param_names =: <;._2 {{)n |
| 22 | +keytype |
| 23 | +keyshape |
| 24 | +valuetype |
| 25 | +valueshape |
| 26 | +keyhash |
| 27 | +keycompare |
| 28 | +initcapacity |
| 29 | +}} |
| 30 | +short_param_names =: 4 2 $ 'ktksvtvs' |
| 31 | +search_short_param_names =: short_param_names&i. |
| 32 | + |
| 33 | +if. (-: (index_type {.~ -@#)) 'concurrent' do. |
| 34 | + singlethreaded =. 0 |
| 35 | + index_type =. (- # ' concurrent') }. index_type |
| 36 | +else. |
| 37 | + singlethreaded =. 1 |
| 38 | +end. |
| 39 | + |
| 40 | +select. index_type NB. set up params for create, based on map type |
| 41 | +case. 'hash' do. |
| 42 | + itype =: 0 NB. index type 0 is hash |
| 43 | + occupancy =: 0.5 NB. default for occupancy |
| 44 | + NB. Parse params and update above attributes. |
| 45 | + long_param_names =: long_param_names , < 'occupancy' |
| 46 | + search_long_param_names =: long_param_names&i. |
| 47 | + parse^:(*@#) creation_parameters |
| 48 | + internal_parameters =. (0 , initcapacity , <. initcapacity % occupancy) ; singlethreaded ; (keytype ; keyshape) ; < (valuetype ; valueshape) |
| 49 | +case. 'tree' do. |
| 50 | + itype =: 1 NB. index type 1 is tree |
| 51 | + NB. Parse params and update above attributes. |
| 52 | + search_long_param_names =: long_param_names&i. |
| 53 | + parse^:(*@#) creation_parameters |
| 54 | + internal_parameters =. (0 , initcapacity) ; singlethreaded ; (keytype ; keyshape) ; < (valuetype ; valueshape) |
| 55 | +case. do. |
| 56 | + 13!:8&3 'Incorrect index type' |
| 57 | +end. |
| 58 | + |
| 59 | +NB. Create the map, which remains as dict. dict is marked nondisplayable because 1 {:: dict is. |
| 60 | +NB. 1 2{::dict appear to be empty so that the user can't crash by touching them. To see the actual values, use 1 2 (16!:_8) dict which returns a virtual block. |
| 61 | +if. keyhash -: keycompare do. keyfn =. keyhash `: 6 else. keyfn =. keyhash `: 6 : (keycompare `: 6) end. |
| 62 | +size =: initcapacity |
| 63 | +dict =: keyfn f. (16!:_1) internal_parameters |
| 64 | + |
| 65 | +NB. Assign names. |
| 66 | +get =: dict 16!:_2 |
| 67 | +put =: dict 16!:_3 |
| 68 | +del =: dict 16!:_4 |
| 69 | +has =: dict 16!:_12 |
| 70 | +count =: 0&(16!:_8)@dict |
| 71 | +if. index_type -: 'tree' do. |
| 72 | + valuemask =. 2b100 * valueshape -.@-: 0 |
| 73 | + check1x =: (_1:^:(_&-:))@:(13!:8@3^:(<&0))@:(13!:8@14^:('' -.@-: $)) |
| 74 | + mget =: dict 16!:_6 |
| 75 | + min =: [: 13!:8@6^:(0 = +/@:(#@>)) (2b11000 + valuemask)&mget |
| 76 | + max =: [: 13!:8@6^:(0 = +/@:(#@>)) (2b11001 + valuemask)&mget |
| 77 | + items =:(_1 ,~ 2b11001 + valuemask)&mget |
| 78 | + after =: _&$: : ((mget~ (2b101010 + valuemask) , check1x)~) |
| 79 | + since =: _&$: : ((mget~ (2b101011 + valuemask) , check1x)~) |
| 80 | + before =: _&$: : ((mget~ (2b101000 + valuemask) , check1x)~) |
| 81 | + until =: _&$: : ((mget~ (2b101001 + valuemask) , check1x)~) |
| 82 | + range =: 1 1&$: : ((mget~ 2b1001000 + valuemask + #.@:|.@:(13!:8@3^:(1 1 -.@-: e.&0 1))@:(13!:8@14^:((, 2) -.@-: $)))~) |
| 83 | +else. |
| 84 | + items =: {{ |
| 85 | + (0 0) 16!:_9 dict NB. read-lock. |
| 86 | + r =. memu (<<<0 (16!:_5) dict) { 1 (16!:_8) dict |
| 87 | + if. -. valueshape -: 0 do. |
| 88 | + r =. r ,&< memu (<<<0 (16!:_5) dict) { 2 (16!:_8) dict |
| 89 | + end. |
| 90 | + (1 0) 16!:_9 dict |
| 91 | + r |
| 92 | + }} |
| 93 | +end. |
| 94 | +EMPTY |
| 95 | +}} |
| 96 | + |
| 97 | +destroy =: {{ |
| 98 | +(1) 16!:_5 dict NB. clear the empty chain in the keys to avoid errors freeing it |
| 99 | +codestroy y NB. destroy the locale, freeing everything |
| 100 | +}} |
| 101 | + |
| 102 | +NB. Resize operation. Nilad. Allocate a larger/smaller dictionary and repopulate its keys |
| 103 | +NB. We have a lock on (dict) during this entire operation |
| 104 | +resize =: {{)m |
| 105 | +size =: SIZE_GROWTH_GEOMETRIC_STEP * size |
| 106 | +NB. We allocate a new DIC block of the correct size. This is a temp whose contents, when filled, will be exchanged into (dict) |
| 107 | +NB. This also allocates new areas for the keys, vals, and hash/tree |
| 108 | +select. itype |
| 109 | +case. 0 do. |
| 110 | + newdict =. dict (16!:_1) 0 , size , <. size * % occupancy NB. allocate new DIC (hashed) |
| 111 | +NB. for hashing: call (newdict 16!:_3) to rehash all the keys. Limit the number of kvs per install to reduce temp space needed. |
| 112 | +NB. Install the kvs from dict into newdict. |
| 113 | +NB. to allow the key block to be freed. Then (<<<e) { keys/vals gives the kvs: |
| 114 | + empties =. (0) 16!:_5 dict NB. get list of empties in dict |
| 115 | + (2 (16!:_8) dict) (newdict 16!:_3)&((<<<empties)&{) (1 (16!:_8) dict) NB. Install all keys from dict into newdict |
| 116 | + (1) 16!:_5 dict NB. Delete chains; prevents free error when releasing dict |
| 117 | +case. 1 do. |
| 118 | + newdict =. dict (16!:_1) 0 , size NB. allocate new DIC (tree) |
| 119 | + NB. for red/black: copying the keys, vals, and tree from dict to newdict is done in JE when we return |
| 120 | +end. |
| 121 | +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 |
| 122 | +}} |
| 123 | + |
| 124 | +NB. Utils. |
| 125 | +NB. Gives type ID (e.g. 4) from type name (e.g. integer). |
| 126 | +typeid_from_typename =: {{)m |
| 127 | +n =. 1 2 4 8 16 32 64 128 1024 2048 4096 8192 16384 32768 65536 131072 262144 |
| 128 | +n =. n , 5 6 7 9 10 11 |
| 129 | +n =. n , _1 NB. _1 if y is not a name of any type. |
| 130 | +t =. '/boolean/literal/integer/floating/complex/boxed/extended/rational' |
| 131 | +t =. t , '/sparse boolean/sparse literal/sparse integer/sparse floating' |
| 132 | +t =. t , '/sparse complex/sparse boxed/symbol/unicode/unicode4' |
| 133 | +t =. t , '/integer1/integer2/integer4/floating2/floating4/floating16' |
| 134 | +n {~ (<;._1 t) i. < y |
| 135 | +}} |
| 136 | + |
| 137 | +NB. Parse attribute and set its value. |
| 138 | +parse =: {{)m |
| 139 | +'attribute value' =: y |
| 140 | +if. (# short_param_names) > idx =. search_short_param_names attribute do. |
| 141 | + attribute =. idx {:: long_param_names |
| 142 | +end. |
| 143 | +incorrect =. (# long_param_names) -: search_long_param_names < attribute |
| 144 | +13!:8&3^:incorrect attribute , ' parameter not supported' |
| 145 | +if. ('literal' -: datatype value) *. (attribute -: 'keytype') +. attribute -: 'valuetype' do. |
| 146 | + value =. typeid_from_typename value |
| 147 | +end. |
| 148 | +(attribute) =: value |
| 149 | +EMPTY |
| 150 | +}}"1 |
0 commit comments