Permalink
Feb 1, 2020
May 17, 2019
May 17, 2019
Feb 1, 2020
Jan 15, 2018
Apr 3, 2019
Apr 3, 2019
Feb 1, 2020
Apr 3, 2019
Apr 3, 2019
Dec 13, 2018
Nov 6, 2019
Dec 10, 2018
Dec 10, 2018
Dec 10, 2018
Dec 10, 2018
Mar 7, 2018
Feb 26, 2018
Feb 1, 2020
Dec 10, 2018
Dec 10, 2018
Dec 10, 2018
Dec 10, 2018
Dec 10, 2018
Jul 31, 2018
Jul 31, 2018
Dec 10, 2018
Nov 2, 2018
Jul 31, 2018
Dec 10, 2018
Dec 10, 2018
Nov 28, 2018
Feb 26, 2018
May 27, 2018
Feb 1, 2020
Oct 24, 2018
Feb 3, 2018
Feb 1, 2020
Mar 7, 2018
Mar 7, 2018
Nov 9, 2015
May 17, 2019
Feb 26, 2018
Apr 3, 2019
May 17, 2019
Feb 26, 2018
Apr 3, 2019
Dec 13, 2018
Mar 7, 2018
Mar 7, 2018
Feb 26, 2018
Apr 14, 2019
Dec 13, 2018
May 17, 2019
Feb 26, 2018
Apr 3, 2019
Dec 1, 2018
Jun 28, 2018
Feb 1, 2020
Mar 7, 2018
Aug 2, 2018
Feb 26, 2018
Newer
100644
1007 lines (900 sloc)
29.9 KB
3
/*
4
Implementation of Python dictionaries
5
6
We can't use Javascript's Map here, because the behaviour is not exactly the
7
same (eg with keys that are instances of classes with a __hash__ method...)
8
and because Map is much slower than regular Javascript objects.
9
10
A Python dictionary is implemented as a Javascript objects with these
11
attributes:
12
. $version: an integer with an initial value of 0, incremented at each
13
insertion
14
. $numeric_dict: for keys of type int
15
. $string_dict and $str_hash: for keys of type str
16
. $object_dict: for keys of other types
17
18
The value associated to a key in $numeric_dict and $string_dict is a pair
19
[value, rank] where "value" is the value associated with the key and "rank"
20
is the value of the dict attribute $version when the pair is inserted. This
21
is required to keep track of the insertion order, mandatory since Python 3.7.
22
23
For keys that are not str or int, their hash value is computed. Since several
24
keys with the same hash can be stored in a dictionary, $object_dict[hash] is a
25
list of [key, [value, rank]] lists.
26
*/
27
35
var set_ops = ["eq", "add", "sub", "and", "or", "xor", "le", "lt", "ge", "gt"]
36
37
$B.make_view = function(name, set_like){
38
var klass = $B.make_class(name, function(items){
39
return {
40
__class__: klass,
41
__dict__: _b_.dict.$factory(),
42
counter: -1,
43
items: items,
44
len: items.length
45
}
46
})
47
48
if(set_like){
49
for(var i = 0, len = set_ops.length; i < len; i++){
50
var op = "__" + set_ops[i] + "__"
51
klass[op] = (function(op){
52
return function(self, other){
53
// compare set of items to other
54
return _b_.set[op](_b_.set.$factory(self),
55
_b_.set.$factory(other))
56
}
57
})(op)
58
}
59
}
60
klass.__iter__ = function(self){
61
var it = klass.$iterator.$factory(self.items)
62
it.len_func = self.len_func
63
return it
64
}
65
klass.__repr__ = function(self){
66
return klass.$infos.__name__ + '(' + _b_.repr(self.items) + ')'
67
}
68
70
return klass
71
}
72
73
// Special version of __next__ for iterators on dict keys / values / items.
74
// Checks that the dictionary size didn't change during iteration.
75
function dict_iterator_next(self){
76
if(self.len_func() != self.len){
77
throw RuntimeError.$factory("dictionary changed size during iteration")
78
}
79
self.counter++
80
if(self.counter < self.items.length){
81
return self.items[self.counter]
82
}
83
throw _b_.StopIteration.$factory("StopIteration")
84
}
85
97
dict.$to_obj = function(d){
98
// Function applied to dictionary that only have string keys,
99
// return a Javascript objects with the kays mapped to the value,
100
// excluding the insertion rank
101
var res = {}
102
for(var key in d.$string_dict){
103
res[key] = d.$string_dict[key][0]
104
}
105
return res
106
}
107
117
if(val === undefined){val = _b_.NotImplemented}
118
else if(val === null){val = $N}
122
}else{
123
for(var k in d.$numeric_dict){
124
items.push([parseFloat(k), d.$numeric_dict[k]])
125
}
129
for(var k in d.$object_dict){
130
d.$object_dict[k].forEach(function(item){
131
items.push(item)
132
})
133
}
134
// sort by insertion order
135
items.sort(function(a, b){
136
return a[1][1] - b[1][1]
137
})
138
items = items.map(function(item){return [item[0], item[1][0]]})
141
if(ix !== undefined){
142
return items.map(function(item){return item[ix]})
143
}else{
144
items.__class__ = _b_.tuple
145
return items.map(function(item){
146
item.__class__ = _b_.tuple; return item}
147
)
148
}
151
$B.dict_to_list = to_list // used in py_types.js
152
153
// Special version of __next__ for iterators on dict keys / values / items.
154
// Checks that the dictionary size didn't change during iteration.
155
function dict_iterator_next(self){
156
if(self.len_func() != self.len){
157
throw RuntimeError.$factory("dictionary changed size during iteration")
158
}
159
self.counter++
160
if(self.counter < self.items.length){
161
return self.items[self.counter]
173
si(left, _l[i][0], _l[i][1])
174
if(right.$version != right_version){
175
throw _b_.RuntimeError.$factory("dict mutated during update")
176
}
177
}
180
function rank(self, hash, key){
181
// Search if object key, with hash = hash(key), is in
182
// self.$object_dict
183
var pairs = self.$object_dict[hash]
184
if(pairs !== undefined){
185
for(var i = 0, len = pairs.length; i < len; i++){
186
if($B.rich_comp("__eq__", key, pairs[i][0])){
187
return i
188
}
189
}
190
}
191
return -1
192
}
193
202
var $ = $B.args("__contains__", 2, {self: null, key: null},
203
["self", "key"], arguments, {}, null, null),
206
if(self.$is_namespace){key = $B.to_alias(key)} // issue 1244
207
208
if(self.$jsobj){
209
return self.$jsobj[key] !== undefined
210
}
216
return self.$numeric_dict[key] !== undefined
217
}
218
219
var hash = _b_.hash(key)
220
if(self.$str_hash[hash] !== undefined &&
221
$B.rich_comp("__eq__", key, self.$str_hash[hash])){return true}
222
if(self.$numeric_dict[hash] !== undefined &&
223
$B.rich_comp("__eq__", key, hash)){return true}
224
return rank(self, hash, key) > -1
229
var $ = $B.args("__eq__", 2, {self: null, arg: null},
230
["self", "arg"], arguments, {}, null, null),
235
if(self.$jsobj[arg] === undefined){throw KeyError.$factory(arg)}
236
delete self.$jsobj[arg]
239
switch(typeof arg){
240
case "string":
241
if(self.$string_dict[arg] === undefined){
242
throw KeyError.$factory(_b_.str.$factory(arg))
243
}
244
delete self.$string_dict[arg]
245
delete self.$str_hash[str_hash(arg)]
248
case "number":
249
if(self.$numeric_dict[arg] === undefined){
250
throw KeyError.$factory(_b_.str.$factory(arg))
261
if((ix = rank(self, hash, arg)) > -1){
262
self.$object_dict[hash].splice(ix, 1)
263
}else{
264
throw KeyError.$factory(_b_.str.$factory(arg))
272
var $ = $B.args("__eq__", 2, {self: null, other: null},
273
["self", "other"], arguments, {}, null, null),
279
if(self.$jsobj){self = jsobj2dict(self.$jsobj)}
280
if(other.$jsobj){other = jsobj2dict(other.$jsobj)}
291
if(!$B.rich_comp("__eq__", other.$numeric_dict[k][0],
292
self.$numeric_dict[k][0])){
296
var pairs = other.$object_dict[k],
297
flag = false
298
for(var i = 0, len = pairs.length; i < len; i++){
299
if($B.rich_comp("__eq__", k, pairs[i][0]) &&
300
$B.rich_comp("__eq__", self.$numeric_dict[k],
301
pairs[i][1])){
302
flag = true
303
break
304
}
319
var pairs = self.$object_dict[hash]
320
// Get all (key, value) pairs in other that have the same hash
321
var other_pairs = []
322
if(other.$numeric_dict[hash] !== undefined){
323
other_pairs.push([hash, other.$numeric_dict[hash]])
324
}
326
other_pairs = other_pairs.concat(other.$object_dict[hash])
327
}
328
if(other_pairs.length == 0){
329
return false
330
}
331
for(var i = 0, len_i = pairs.length; i < len_i; i++){
332
var flag = false
333
var key = pairs[i][0],
335
for(var j = 0, len_j = other_pairs.length; j < len_j; j++){
336
if($B.rich_comp("__eq__", key, other_pairs[j][0]) &&
351
var $ = $B.args("__getitem__", 2, {self: null, arg: null},
352
["self", "arg"], arguments, {}, null, null),
360
if(!self.$jsobj.hasOwnProperty(arg)){
361
throw _b_.KeyError.$factory(str.$factory(arg))
362
}else if(self.$jsobj[arg] === undefined){
367
368
switch(typeof arg){
369
case "string":
370
if(self.$string_dict[arg] !== undefined){
378
break
379
}
380
381
// since the key is more complex use 'default' method of getting item
382
395
}
396
if(isinstance(arg, _b_.str)){
397
// string subclass
398
var res = self.$string_dict[arg.valueOf()]
449
if(first === undefined){return $N}
450
if(second === undefined){
451
if(first.__class__ === $B.JSObject){
452
self.$jsobj = first.js
453
return $N
454
}else if(first.$jsobj){
455
self.$jsobj = {}
456
for(var attr in first.$jsobj){
457
self.$jsobj[attr] = first.$jsobj[attr]
467
arguments, {}, "first", "second")
468
var args = $.first
469
if(args.length > 1){
470
throw _b_.TypeError.$factory("dict expected at most 1 argument" +
471
", got 2")
472
}else if(args.length == 1){
473
args = args[0]
474
if(args.__class__ === dict){
475
['$string_dict', '$str_hash', '$numeric_dict', '$object_dict'].
476
forEach(function(d){
477
for(key in args[d]){self[d][key] = args[d][key]}
478
})
482
var keys = $B.$getattr(args, "keys", null)
483
if(keys !== null){
484
var gi = $B.$getattr(args, "__getitem__", null)
485
if(gi !== null){
486
// has keys and __getitem__ : it's a mapping, iterate on
487
// keys and values
488
gi = $B.$call(gi)
489
var kiter = _b_.iter($B.$call(keys)())
490
while(true){
491
try{
492
var key = _b_.next(kiter),
493
value = gi(key)
494
dict.__setitem__(self, key, value)
495
}catch(err){
496
if(err.__class__ === _b_.StopIteration){
497
break
498
}
499
throw err
500
}
501
}
502
return $N
503
}
504
}
505
if(! Array.isArray(args)){
506
args = _b_.list.$factory(args)
507
}
508
// Form "dict([[key1, value1], [key2,value2], ...])"
514
switch(typeof attr){
515
case "string":
516
self.$string_dict[attr] = kw[attr]
517
self.$str_hash[str_hash(attr)] = attr
518
break
519
case "number":
520
self.$numeric_dict[attr] = kw[attr]
521
break
522
default:
523
si(self, attr, kw[attr])
524
break
525
}
542
for(var k in self.$numeric_dict){_count++}
543
for(var k in self.$string_dict){_count++}
544
for(var hash in self.$object_dict){
545
_count += self.$object_dict[hash].length
546
}
565
if(cls !== dict){
566
instance.__dict__ = _b_.dict.$factory()
567
}
568
return instance
577
items.forEach(function(item){
578
if((!self.$jsobj && item[1] === self) ||
579
(self.$jsobj && item[1] === self.$jsobj)){
590
["self", "key", "value"], arguments, {}, null, null)
591
return dict.$setitem($.self, $.key, $.value)
592
}
595
// Set a dictionary item mapping key and value.
596
//
597
// If key is a string, set $string_dict[key] = value and
598
// $str_hash[hash(key)] to key
599
//
600
// If key is a number, set $numeric_dict[key] = value
601
//
602
// If key is another object, compute its hash value:
603
// - if the hash is a key of $str_hash, and key == $str_hash[hash],
604
// replace $string_dict[$str_hash[hash]] by value
605
// - if the hash is a key of $numeric_dict, and hash == key, replace
606
// $numeric_dict[hash] by value
607
// - if the hash is a key of $object_dict: $object_dict[hash] is a list
608
// of [k, v] pairs. If key is equal to one of the "k", replace the
609
// matching v by value. Otherwise, add [key, value] to the list
610
// - else set $object_dict[hash] = [[key, value]]
611
//
612
// In all cases, increment attribute $version, used to detect dictionary
613
// cahnges during an iteration.
614
//
615
// Parameter $hash is only set if this method is called by setdefault.
616
// In this case the hash of key has already been computed and we
617
// know that the key is not present in the dictionary, so it's no
618
// use computing hash(key) again, nor testing equality of keys
620
if(self.$from_js){
621
// dictionary created by method to_dict of JSObject instances
622
value = $B.pyobj2jsobj(value)
623
}
627
// If class attribute __init__ or __new__ are reset,
628
// the factory function has to change
629
self.$jsobj.$factory = $B.$instance_creator(self.$jsobj)
630
}
631
}else{
639
if(self.$string_dict === undefined){
640
console.log("pas de string dict", self, key, value)
641
}
642
self.$string_dict[key] = [value, self.$version]
669
// If $setitem is called from setdefault, don't test equality of key
670
// with any object
671
if($hash){
672
if(self.$object_dict[$hash] !== undefined){
676
}
677
self.$version++
678
return $N
679
}
680
var ix = rank(self, hash, key)
681
if(ix > -1){
682
// reset value
736
var $ = $B.args("fromkeys", 3, {cls: null, keys: null, value: null},
737
["cls", "keys", "value"], arguments, {value: _b_.None}, null, null),
749
if(klass === dict){dict.$setitem(res, key, value)}
750
else{$B.$getattr(res, "__setitem__")(key, value)}
761
var $ = $B.args("get", 3, {self: null, key: null, _default: null},
762
["self", "key", "_default"], arguments, {_default: $N}, null, null)
765
catch(err){
766
if(_b_.isinstance(err, _b_.KeyError)){return $._default}
767
else{throw err}
768
}
769
}
770
771
var dict_items = $B.make_view("dict_items", true)
772
dict_items.$iterator = $B.make_iterator_class("dict_itemiterator")
776
var _len = arguments.length - 1,
777
_msg = "items() takes no arguments (" + _len + " given)"
780
var it = dict_items.$factory(to_list(self))
781
it.len_func = function(){return dict.__len__(self)}
782
return it
785
var dict_keys = $B.make_view("dict_keys", true)
786
dict_keys.$iterator = $B.make_iterator_class("dict_keyiterator")
790
var _len = arguments.length - 1,
791
_msg = "keys() takes no arguments (" + _len + " given)"
794
var it = dict_keys.$factory(to_list(self, 0))
795
it.len_func = function(){return dict.__len__(self)}
796
return it
801
var missing = {},
802
$ = $B.args("pop", 3, {self: null, key: null, _default: null},
803
["self", "key", "_default"], arguments, {_default: missing}, null, null),
835
var $ = $B.args("setdefault", 3, {self: null, key: null, _default: null},
836
["self", "key", "_default"], arguments, {_default: $N}, null, null),
847
var hash = key.$hash
848
key.$hash = undefined
849
dict.$setitem(self, key, _default, hash)
856
var $ = $B.args("update", 1, {"self": null}, ["self"], arguments,
857
{}, "args", "kw"),
858
self = $.self,
859
args = $.args,
860
kw = $.kw
861
if(args.length > 0){
862
var o = args[0]
863
if(isinstance(o, dict)){
869
var _keys = _b_.list.$factory($B.$call($B.$getattr(o, "keys"))())
870
for(var i = 0, len = _keys.length; i < len; i++){
872
dict.$setitem(self, _keys[i], _value)
873
}
874
}else{
875
var it = _b_.iter(o),
876
i = 0
877
while(true){
878
try{
879
var item = _b_.next(it)
880
}catch(err){
881
if(err.__class__ === _b_.StopIteration){break}
882
throw err
883
}
884
try{
885
key_value = _b_.list.$factory(item)
886
}catch(err){
887
throw _b_.TypeError.$factory("cannot convert dictionary" +
888
" update sequence element #" + i + " to a sequence")
889
}
890
if(key_value.length !== 2){
891
throw _b_.ValueError.$factory("dictionary update " +
892
"sequence element #" + i + " has length " +
893
key_value.length + "; 2 is required")
894
}
895
dict.$setitem(self, key_value[0], key_value[1])
896
i++
905
var dict_values = $B.make_view("dict_values")
906
dict_values.$iterator = $B.make_iterator_class("dict_valueiterator")
910
var _len = arguments.length - 1,
911
_msg = "values() takes no arguments (" + _len + " given)"
914
var it = dict_values.$factory(to_list(self, 1))
915
it.len_func = function(){return dict.__len__(self)}
916
return it
921
var args = [res]
922
for(var i = 0, len = arguments.length; i < len ; i++){
923
args.push(arguments[i])
924
}
925
dict.__init__.apply(null, args)
933
// This must be done after set_func_names, otherwise dict.fromkeys doesn't
934
// have the attribute $infos
935
dict.fromkeys = _b_.classmethod.$factory(dict.fromkeys)
936
941
// obj is a dictionary, with $string_dict table such that
942
// obj.$string_dict[key] = [value, rank]
943
// Transform it into an object with attribute $jsobj such that
944
// res.$jsobj[key] = value
945
var res = $B.obj_dict(dict.$to_obj(obj))
955
throw _b_.TypeError.$factory("'mappingproxy' object does not support " +
956
"item assignment")
959
for(var attr in dict){
960
if(mappingproxy[attr] !== undefined ||
961
["__class__", "__mro__", "__new__", "__init__", "__delitem__",
962
"clear", "fromkeys", "pop", "popitem", "setdefault",
963
"update"].indexOf(attr) > -1){
964
continue
965
}
966
if(typeof dict[attr] == "function"){
967
mappingproxy[attr] = (function(key){
968
return function(){
969
return dict[key].apply(null, arguments)
970
}
971
})(attr)
972
}else{
973
mappingproxy[attr] = dict[attr]
974
}
975
}
976
998
if(klass !== undefined && klass.$native){
999
throw _b_.AttributeError.$factory(klass.__name__ +