Permalink
Feb 1, 2020
May 17, 2019
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
1012 lines (903 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
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
}
70
klass.__repr__ = function(self){
71
return klass.$infos.__name__ + '(' + _b_.repr(self.items) + ')'
72
}
73
75
return klass
76
}
77
78
// Special version of __next__ for iterators on dict keys / values / items.
79
// Checks that the dictionary size didn't change during iteration.
80
function dict_iterator_next(self){
81
if(self.len_func() != self.len){
82
throw RuntimeError.$factory("dictionary changed size during iteration")
83
}
84
self.counter++
85
if(self.counter < self.items.length){
86
return self.items[self.counter]
87
}
88
throw _b_.StopIteration.$factory("StopIteration")
89
}
90
102
dict.$to_obj = function(d){
103
// Function applied to dictionary that only have string keys,
104
// return a Javascript objects with the kays mapped to the value,
105
// excluding the insertion rank
106
var res = {}
107
for(var key in d.$string_dict){
108
res[key] = d.$string_dict[key][0]
109
}
110
return res
111
}
112
122
if(val === undefined){val = _b_.NotImplemented}
123
else if(val === null){val = $N}
127
}else{
128
for(var k in d.$numeric_dict){
129
items.push([parseFloat(k), d.$numeric_dict[k]])
130
}
134
for(var k in d.$object_dict){
135
d.$object_dict[k].forEach(function(item){
136
items.push(item)
137
})
138
}
139
// sort by insertion order
140
items.sort(function(a, b){
141
return a[1][1] - b[1][1]
142
})
143
items = items.map(function(item){return [item[0], item[1][0]]})
146
if(ix !== undefined){
147
return items.map(function(item){return item[ix]})
148
}else{
149
items.__class__ = _b_.tuple
150
return items.map(function(item){
151
item.__class__ = _b_.tuple; return item}
152
)
153
}
156
$B.dict_to_list = to_list // used in py_types.js
157
158
// Special version of __next__ for iterators on dict keys / values / items.
159
// Checks that the dictionary size didn't change during iteration.
160
function dict_iterator_next(self){
161
if(self.len_func() != self.len){
162
throw RuntimeError.$factory("dictionary changed size during iteration")
163
}
164
self.counter++
165
if(self.counter < self.items.length){
166
return self.items[self.counter]
178
si(left, _l[i][0], _l[i][1])
179
if(right.$version != right_version){
180
throw _b_.RuntimeError.$factory("dict mutated during update")
181
}
182
}
185
function rank(self, hash, key){
186
// Search if object key, with hash = hash(key), is in
187
// self.$object_dict
188
var pairs = self.$object_dict[hash]
189
if(pairs !== undefined){
190
for(var i = 0, len = pairs.length; i < len; i++){
191
if($B.rich_comp("__eq__", key, pairs[i][0])){
192
return i
193
}
194
}
195
}
196
return -1
197
}
198
207
var $ = $B.args("__contains__", 2, {self: null, key: null},
208
["self", "key"], arguments, {}, null, null),
211
if(self.$is_namespace){key = $B.to_alias(key)} // issue 1244
212
213
if(self.$jsobj){
214
return self.$jsobj[key] !== undefined
215
}
221
return self.$numeric_dict[key] !== undefined
222
}
223
224
var hash = _b_.hash(key)
225
if(self.$str_hash[hash] !== undefined &&
226
$B.rich_comp("__eq__", key, self.$str_hash[hash])){return true}
227
if(self.$numeric_dict[hash] !== undefined &&
228
$B.rich_comp("__eq__", key, hash)){return true}
229
return rank(self, hash, key) > -1
234
var $ = $B.args("__eq__", 2, {self: null, arg: null},
235
["self", "arg"], arguments, {}, null, null),
240
if(self.$jsobj[arg] === undefined){throw KeyError.$factory(arg)}
241
delete self.$jsobj[arg]
244
switch(typeof arg){
245
case "string":
246
if(self.$string_dict[arg] === undefined){
247
throw KeyError.$factory(_b_.str.$factory(arg))
248
}
249
delete self.$string_dict[arg]
250
delete self.$str_hash[str_hash(arg)]
253
case "number":
254
if(self.$numeric_dict[arg] === undefined){
255
throw KeyError.$factory(_b_.str.$factory(arg))
266
if((ix = rank(self, hash, arg)) > -1){
267
self.$object_dict[hash].splice(ix, 1)
268
}else{
269
throw KeyError.$factory(_b_.str.$factory(arg))
277
var $ = $B.args("__eq__", 2, {self: null, other: null},
278
["self", "other"], arguments, {}, null, null),
284
if(self.$jsobj){self = jsobj2dict(self.$jsobj)}
285
if(other.$jsobj){other = jsobj2dict(other.$jsobj)}
296
if(!$B.rich_comp("__eq__", other.$numeric_dict[k][0],
297
self.$numeric_dict[k][0])){
301
var pairs = other.$object_dict[k],
302
flag = false
303
for(var i = 0, len = pairs.length; i < len; i++){
304
if($B.rich_comp("__eq__", k, pairs[i][0]) &&
305
$B.rich_comp("__eq__", self.$numeric_dict[k],
306
pairs[i][1])){
307
flag = true
308
break
309
}
324
var pairs = self.$object_dict[hash]
325
// Get all (key, value) pairs in other that have the same hash
326
var other_pairs = []
327
if(other.$numeric_dict[hash] !== undefined){
328
other_pairs.push([hash, other.$numeric_dict[hash]])
329
}
331
other_pairs = other_pairs.concat(other.$object_dict[hash])
332
}
333
if(other_pairs.length == 0){
334
return false
335
}
336
for(var i = 0, len_i = pairs.length; i < len_i; i++){
337
var flag = false
338
var key = pairs[i][0],
340
for(var j = 0, len_j = other_pairs.length; j < len_j; j++){
341
if($B.rich_comp("__eq__", key, other_pairs[j][0]) &&
356
var $ = $B.args("__getitem__", 2, {self: null, arg: null},
357
["self", "arg"], arguments, {}, null, null),
365
if(!self.$jsobj.hasOwnProperty(arg)){
366
throw _b_.KeyError.$factory(str.$factory(arg))
367
}else if(self.$jsobj[arg] === undefined){
372
373
switch(typeof arg){
374
case "string":
375
if(self.$string_dict[arg] !== undefined){
383
break
384
}
385
386
// since the key is more complex use 'default' method of getting item
387
400
}
401
if(isinstance(arg, _b_.str)){
402
// string subclass
403
var res = self.$string_dict[arg.valueOf()]
454
if(first === undefined){return $N}
455
if(second === undefined){
456
if(first.__class__ === $B.JSObject){
457
self.$jsobj = first.js
458
return $N
459
}else if(first.$jsobj){
460
self.$jsobj = {}
461
for(var attr in first.$jsobj){
462
self.$jsobj[attr] = first.$jsobj[attr]
472
arguments, {}, "first", "second")
473
var args = $.first
474
if(args.length > 1){
475
throw _b_.TypeError.$factory("dict expected at most 1 argument" +
476
", got 2")
477
}else if(args.length == 1){
478
args = args[0]
479
if(args.__class__ === dict){
480
['$string_dict', '$str_hash', '$numeric_dict', '$object_dict'].
481
forEach(function(d){
482
for(key in args[d]){self[d][key] = args[d][key]}
483
})
487
var keys = $B.$getattr(args, "keys", null)
488
if(keys !== null){
489
var gi = $B.$getattr(args, "__getitem__", null)
490
if(gi !== null){
491
// has keys and __getitem__ : it's a mapping, iterate on
492
// keys and values
493
gi = $B.$call(gi)
494
var kiter = _b_.iter($B.$call(keys)())
495
while(true){
496
try{
497
var key = _b_.next(kiter),
498
value = gi(key)
499
dict.__setitem__(self, key, value)
500
}catch(err){
501
if(err.__class__ === _b_.StopIteration){
502
break
503
}
504
throw err
505
}
506
}
507
return $N
508
}
509
}
510
if(! Array.isArray(args)){
511
args = _b_.list.$factory(args)
512
}
513
// Form "dict([[key1, value1], [key2,value2], ...])"
519
switch(typeof attr){
520
case "string":
521
self.$string_dict[attr] = kw[attr]
522
self.$str_hash[str_hash(attr)] = attr
523
break
524
case "number":
525
self.$numeric_dict[attr] = kw[attr]
526
break
527
default:
528
si(self, attr, kw[attr])
529
break
530
}
547
for(var k in self.$numeric_dict){_count++}
548
for(var k in self.$string_dict){_count++}
549
for(var hash in self.$object_dict){
550
_count += self.$object_dict[hash].length
551
}
570
if(cls !== dict){
571
instance.__dict__ = _b_.dict.$factory()
572
}
573
return instance
582
items.forEach(function(item){
583
if((!self.$jsobj && item[1] === self) ||
584
(self.$jsobj && item[1] === self.$jsobj)){
595
["self", "key", "value"], arguments, {}, null, null)
596
return dict.$setitem($.self, $.key, $.value)
597
}
600
// Set a dictionary item mapping key and value.
601
//
602
// If key is a string, set $string_dict[key] = value and
603
// $str_hash[hash(key)] to key
604
//
605
// If key is a number, set $numeric_dict[key] = value
606
//
607
// If key is another object, compute its hash value:
608
// - if the hash is a key of $str_hash, and key == $str_hash[hash],
609
// replace $string_dict[$str_hash[hash]] by value
610
// - if the hash is a key of $numeric_dict, and hash == key, replace
611
// $numeric_dict[hash] by value
612
// - if the hash is a key of $object_dict: $object_dict[hash] is a list
613
// of [k, v] pairs. If key is equal to one of the "k", replace the
614
// matching v by value. Otherwise, add [key, value] to the list
615
// - else set $object_dict[hash] = [[key, value]]
616
//
617
// In all cases, increment attribute $version, used to detect dictionary
618
// cahnges during an iteration.
619
//
620
// Parameter $hash is only set if this method is called by setdefault.
621
// In this case the hash of key has already been computed and we
622
// know that the key is not present in the dictionary, so it's no
623
// use computing hash(key) again, nor testing equality of keys
625
if(self.$from_js){
626
// dictionary created by method to_dict of JSObject instances
627
value = $B.pyobj2jsobj(value)
628
}
632
// If class attribute __init__ or __new__ are reset,
633
// the factory function has to change
634
self.$jsobj.$factory = $B.$instance_creator(self.$jsobj)
635
}
636
}else{
644
if(self.$string_dict === undefined){
645
console.log("pas de string dict", self, key, value)
646
}
647
self.$string_dict[key] = [value, self.$version]
674
// If $setitem is called from setdefault, don't test equality of key
675
// with any object
676
if($hash){
677
if(self.$object_dict[$hash] !== undefined){
681
}
682
self.$version++
683
return $N
684
}
685
var ix = rank(self, hash, key)
686
if(ix > -1){
687
// reset value
741
var $ = $B.args("fromkeys", 3, {cls: null, keys: null, value: null},
742
["cls", "keys", "value"], arguments, {value: _b_.None}, null, null),
754
if(klass === dict){dict.$setitem(res, key, value)}
755
else{$B.$getattr(res, "__setitem__")(key, value)}
766
var $ = $B.args("get", 3, {self: null, key: null, _default: null},
767
["self", "key", "_default"], arguments, {_default: $N}, null, null)
770
catch(err){
771
if(_b_.isinstance(err, _b_.KeyError)){return $._default}
772
else{throw err}
773
}
774
}
775
776
var dict_items = $B.make_view("dict_items", true)
777
dict_items.$iterator = $B.make_iterator_class("dict_itemiterator")
781
var _len = arguments.length - 1,
782
_msg = "items() takes no arguments (" + _len + " given)"
785
var it = dict_items.$factory(to_list(self))
786
it.len_func = function(){return dict.__len__(self)}
787
return it
790
var dict_keys = $B.make_view("dict_keys", true)
791
dict_keys.$iterator = $B.make_iterator_class("dict_keyiterator")
795
var _len = arguments.length - 1,
796
_msg = "keys() takes no arguments (" + _len + " given)"
799
var it = dict_keys.$factory(to_list(self, 0))
800
it.len_func = function(){return dict.__len__(self)}
801
return it
806
var missing = {},
807
$ = $B.args("pop", 3, {self: null, key: null, _default: null},
808
["self", "key", "_default"], arguments, {_default: missing}, null, null),
840
var $ = $B.args("setdefault", 3, {self: null, key: null, _default: null},
841
["self", "key", "_default"], arguments, {_default: $N}, null, null),
852
var hash = key.$hash
853
key.$hash = undefined
854
dict.$setitem(self, key, _default, hash)
861
var $ = $B.args("update", 1, {"self": null}, ["self"], arguments,
862
{}, "args", "kw"),
863
self = $.self,
864
args = $.args,
865
kw = $.kw
866
if(args.length > 0){
867
var o = args[0]
868
if(isinstance(o, dict)){
874
var _keys = _b_.list.$factory($B.$call($B.$getattr(o, "keys"))())
875
for(var i = 0, len = _keys.length; i < len; i++){
877
dict.$setitem(self, _keys[i], _value)
878
}
879
}else{
880
var it = _b_.iter(o),
881
i = 0
882
while(true){
883
try{
884
var item = _b_.next(it)
885
}catch(err){
886
if(err.__class__ === _b_.StopIteration){break}
887
throw err
888
}
889
try{
890
key_value = _b_.list.$factory(item)
891
}catch(err){
892
throw _b_.TypeError.$factory("cannot convert dictionary" +
893
" update sequence element #" + i + " to a sequence")
894
}
895
if(key_value.length !== 2){
896
throw _b_.ValueError.$factory("dictionary update " +
897
"sequence element #" + i + " has length " +
898
key_value.length + "; 2 is required")
899
}
900
dict.$setitem(self, key_value[0], key_value[1])
901
i++
910
var dict_values = $B.make_view("dict_values")
911
dict_values.$iterator = $B.make_iterator_class("dict_valueiterator")
915
var _len = arguments.length - 1,
916
_msg = "values() takes no arguments (" + _len + " given)"
919
var it = dict_values.$factory(to_list(self, 1))
920
it.len_func = function(){return dict.__len__(self)}
921
return it
926
var args = [res]
927
for(var i = 0, len = arguments.length; i < len ; i++){
928
args.push(arguments[i])
929
}
930
dict.__init__.apply(null, args)
938
// This must be done after set_func_names, otherwise dict.fromkeys doesn't
939
// have the attribute $infos
940
dict.fromkeys = _b_.classmethod.$factory(dict.fromkeys)
941
946
// obj is a dictionary, with $string_dict table such that
947
// obj.$string_dict[key] = [value, rank]
948
// Transform it into an object with attribute $jsobj such that
949
// res.$jsobj[key] = value
950
var res = $B.obj_dict(dict.$to_obj(obj))
960
throw _b_.TypeError.$factory("'mappingproxy' object does not support " +
961
"item assignment")
964
for(var attr in dict){
965
if(mappingproxy[attr] !== undefined ||
966
["__class__", "__mro__", "__new__", "__init__", "__delitem__",
967
"clear", "fromkeys", "pop", "popitem", "setdefault",
968
"update"].indexOf(attr) > -1){
969
continue
970
}
971
if(typeof dict[attr] == "function"){
972
mappingproxy[attr] = (function(key){
973
return function(){
974
return dict[key].apply(null, arguments)
975
}
976
})(attr)
977
}else{
978
mappingproxy[attr] = dict[attr]
979
}
980
}
981
1003
if(klass !== undefined && klass.$native){
1004
throw _b_.AttributeError.$factory(klass.__name__ +