Permalink
Newer
100644
651 lines (560 sloc)
17.7 KB
9
// dictionary
10
function $DictClass($keys,$values){
11
this.iter = null
12
this.__class__ = $DictDict
13
$DictDict.clear(this)
14
15
for (var i = 0; i < $keys.length; ++i) {
16
$DictDict.__setitem__($keys[i], $values[i])
17
}
18
}
19
20
dummy = {}
21
22
// can either grow or shrink depending on actual used items
23
var $grow_dict = function(self) {
24
var new_size = $DICT_MINSIZE
25
var target_size = (self.$used < 50000? 2 : 4) * self.$used
26
while (new_size < target_size) {
27
new_size <<= 1
28
}
29
var new_data = Array($DICT_MINSIZE)
30
try {
31
var ig = new $item_generator(self)
32
while(1) {
33
var itm = ig.next()
34
var bucket = $find_empty(itm[0], new_size, new_data)
35
new_data[bucket] = itm
36
}
37
} catch (err) {
38
if (err.__name__ !== "StopIteration") { throw err } else { $B.$pop_exc() }
39
}
40
self.$data = new_data
41
self.$fill = self.$used
42
self.$size = new_size
43
}
44
45
var $lookup_key = function(self, key) {
46
eq = _b_.getattr(key, "__eq__")
47
size = self.$size
48
data = self.$data
49
bucket = Math.abs(_b_.hash(key) % size)
50
val = data[bucket]
51
while (val !== undefined) {
52
if (val === dummy) {
53
bucket = $next_probe(bucket, size)
54
} else {
55
k_val = val[0] // [key, value]
56
if (eq(k_val)) {
57
return bucket
58
} else {
59
bucket = $next_probe(bucket, size)
60
}
61
}
62
val = data[bucket]
63
}
64
self.$empty_bucket = bucket
65
66
return undefined
67
}
68
69
var $find_empty = function(key, size, data) {
70
bucket = Math.abs(hash(key) % size)
71
val = data[bucket]
72
while (val !== undefined) {
73
bucket = $next_probe(bucket, size)
74
val = data[bucket]
75
}
76
return bucket
77
}
78
79
var $next_probe = function(i, size) {
80
return ((i * 5) + 1) % size
89
var $key_iterator = function(d) {
90
this.d = d
91
this.current = 0
92
this.iter = new $item_generator(d)
93
}
95
$key_iterator.prototype.next = function() { return this.iter.next()[0] }
96
97
var $value_iterator = function(d) {
98
this.d = d
99
this.current = 0
100
this.iter = new $item_generator(d)
101
}
103
$value_iterator.prototype.next = function() { return this.iter.next()[1] }
104
105
var $item_generator = function(d) {
110
this.length=0
111
112
this.items=[]
113
for (var k in d.$numeric_dict) {
114
this.items.push([parseFloat(k), d.$numeric_dict[k]])
115
}
116
117
for (var k in d.$string_dict) {
118
this.items.push([k, d.$string_dict[k]])
119
}
120
121
for (var i=0; i < this.data.length; i++) {
122
var _v=this.data[i]
123
if (_v === undefined || _v === dummy) continue
124
this.items.push(_v)
125
}
126
this.length=this.items.length
131
}
132
throw _b_.StopIteration("StopIteration")
133
}
134
$item_generator.prototype.as_list = function() {
136
}
137
138
var $item_iterator = function(d) {
139
this.d = d
140
this.current = 0
141
this.iter = new $item_generator(d)
142
}
144
$item_iterator.prototype.next = function() { return _b_.tuple(this.iter.next()) }
145
146
var $copy_dict = function(left, right) {
147
var gen = new $item_generator(right)
148
try {
149
while(1) {
150
var item = gen.next()
151
$DictDict.__setitem__(left, item[0], item[1])
152
}
153
} catch (err) {
154
if (err.__name__ !== "StopIteration") { throw err } else { $B.$pop_exc() }
155
}
156
}
157
158
$iterator_wrapper = function(items,klass){
159
var res = {
160
__class__:klass,
164
//if (items.length() !== items.iter.used) {
165
// throw _b_.RuntimeError("dictionary changed size during iteration")
166
//}
178
var $dict_keysDict = $B.$iterator_class('dict_keys')
179
180
$DictDict.keys = function(self){
181
if (arguments.length > 1) {
182
var _len=arguments.length - 1
183
var _msg="keys() takes no arguments ("+_len+" given)"
184
throw _b_.TypeError(_msg)
185
}
186
return $iterator_wrapper(new $key_iterator(self),$dict_keysDict)
187
}
188
189
var $dict_valuesDict = $B.$iterator_class('dict_values')
190
191
$DictDict.values = function(self){
192
if (arguments.length > 1) {
193
var _len=arguments.length - 1
194
var _msg="values() takes no arguments ("+_len+" given)"
195
throw _b_.TypeError(_msg)
196
}
201
202
$DictDict.__contains__ = function(self,item){
203
if(self.$jsobj) return self.$jsobj[item]!==undefined
204
switch(typeof item) {
205
case 'string':
206
return self.$string_dict[item] !==undefined
214
switch(typeof arg) {
215
case 'string':
216
if (self.$string_dict[arg] === undefined) throw KeyError(_b_.str(arg))
217
delete self.$string_dict[arg]
218
if (self.$jsobj) delete self.$jsobj[arg]
219
return
220
case 'number':
221
if (self.$numeric_dict[arg] === undefined) throw KeyError(_b_.str(arg))
222
delete self.$numeric_dict[arg]
223
if (self.$jsobj) delete self.$jsobj[arg]
224
return
228
var bucket = $lookup_key(self, arg)
229
if (bucket === undefined) throw KeyError(_b_.str(arg))
230
self.$data[bucket] = dummy
231
--self.$used
232
233
if(self.$jsobj) delete self.$jsobj[arg]
234
}
235
236
$DictDict.__eq__ = function(self,other){
237
if(other===undefined){ // compare self to class "dict"
238
return self===dict
239
}
241
242
if ($DictDict.__len__(self) != $DictDict.__len__(other)) return false
243
244
var gen = new $item_generator(self)
245
var keys1=[]
246
try {
247
while(1) keys1.push(gen.next()[0])
248
} catch (err) {
249
251
252
for (var i=0; i < keys1.length; i++) {
253
var key=keys1[i]
254
if (!$DictDict.__contains__(other, key)) return false
255
var v1=$DictDict.__getitem__(self, key)
256
var v2=$DictDict.__getitem__(other, key)
257
if (!getattr(v1, '__eq__')(v2)) return false
258
}
259
260
return true
264
if(self.$jsobj && self.$jsobj[arg] !== undefined) return self.$jsobj[arg]
265
266
switch(typeof arg) {
267
case 'string':
268
if (self.$string_dict[arg] !== undefined) return self.$string_dict[arg]
269
break
270
case 'number':
271
if (self.$numeric_dict[arg] !== undefined) return self.$numeric_dict[arg]
275
var bucket = $lookup_key(self, arg)
276
if (bucket !== undefined) return self.$data[bucket][1]
283
$DictDict.__hash__ = function(self) {
284
if (self === undefined) {
285
return $DictDict.__hashvalue__ || $B.$py_next_hash-- // for hash of dict type (not instance of dict)
286
}
287
throw _b_.TypeError("unhashable type: 'dict'");
288
}
292
for(var i=1;i<arguments.length;i++){args.push(arguments[i])}
293
$DictDict.clear(self)
294
switch(args.length) {
295
case 0:
296
return
297
case 1:
304
if(obj.__class__===$B.JSObject.$dict){
305
// convert a JSObject into a Python dictionary
306
for(var attr in obj.js){
309
// Attribute $jsobj is used to update the original JS object
310
// when the dictionary is modified
316
var $ns=$B.$MakeArgs('dict',args,[],[],'args','kw')
317
var args = $ns['args']
318
var kw = $ns['kw']
326
// format dict([(k1,v1),(k2,v2)...])
327
var iterable = iter(args[0])
328
while(1){
329
try{
330
var elt = next(iterable)
331
var key = getattr(elt,'__getitem__')(0)
332
var value = getattr(elt,'__getitem__')(1)
333
$DictDict.__setitem__(self, key, value)
334
}catch(err){
335
if(err.__name__==='StopIteration'){$B.$pop_exc();break}
336
throw err
337
}
338
}
348
$DictDict.__len__ = function(self) {
349
var _num_len=0, _str_len=0
350
351
for (var k in self.$numeric_dict) _num_len++
352
for (var k in self.$string_dict) _str_len++
353
354
return self.$used + _num_len + _str_len
355
}
356
357
$DictDict.__mro__ = [$DictDict,$ObjectDict]
358
359
$DictDict.__ne__ = function(self,other){return !$DictDict.__eq__(self,other)}
360
361
$DictDict.__next__ = function(self){
364
}
365
try {
366
return self.$iter.next()
367
} catch (err) {
368
if (err.__name__ !== "StopIteration") { throw err } else { $B.$pop_exc() }
369
}
370
}
371
372
$DictDict.__repr__ = function(self){
373
if(self===undefined) return "<class 'dict'>"
379
if (_objs.indexOf(itm[1]) > -1 && _b_.isinstance(itm[1], [_b_.dict,_b_.list,_b_.set, _b_.tuple])) {
380
var value='?'+_b_.type(itm[1])
381
if(isinstance(itm[1], dict)) value='{...}'
382
res.push(repr(itm[0])+': '+ value)
383
} else {
392
switch(typeof key) {
393
case 'string':
394
self.$string_dict[key]=value
395
if(self.$jsobj) self.$jsobj[key]=value
396
return
397
case 'number':
398
self.$numeric_dict[key]=value
399
if(self.$jsobj) self.$jsobj[key]=value
400
return
401
}
402
403
// if we got here the key is more complex, use default method
404
405
// if adding new item would invoke a grow...
406
if (self.$fill + 1 > self.$size * 3 / 4) {
407
$grow_dict(self)
408
}
409
410
var bucket = $lookup_key(self, key)
411
if (bucket === undefined) {
412
bucket = self.$empty_bucket
413
++self.$fill
414
++self.$used
418
if(self.$jsobj) self.$jsobj[key]=value
419
}
420
421
$DictDict.__str__ = $DictDict.__repr__
422
423
// add "reflected" methods
424
$B.make_rmethods($DictDict)
425
426
$DictDict.clear = function(self){
427
// Remove all items from the dictionary.
428
self.$data = Array($DICT_MINSIZE)
429
self.$size = $DICT_MINSIZE
430
self.$fill = 0
431
self.$used = 0
432
436
if(self.$jsobj) self.$jsobj={}
437
}
438
439
$DictDict.copy = function(self){
440
// Return a shallow copy of the dictionary
447
if (_default === undefined) _default=None
448
switch(typeof key) {
449
case 'string':
450
return self.$string_dict[key] || _default
454
455
var bucket = $lookup_key(self, key)
456
if(bucket !== undefined) return self.$data[bucket][1]
464
if (arguments.length > 1) {
465
var _len=arguments.length - 1
466
var _msg="items() takes no arguments ("+_len+" given)"
467
throw _b_.TypeError(_msg)
468
}
475
var res = dict()
476
var keys_iter = _b_.iter(keys)
477
while(1){
478
try{
479
var key = _b_.next(keys_iter)
480
$DictDict.__setitem__(res,key,value)
481
}catch(err){
482
if($B.is_exc(err,[_b_.StopIteration])){
483
$B.$pop_exc()
484
return res
485
}
486
throw err
487
}
488
}
489
}
490
491
$DictDict.pop = function(self,key,_default){
492
try{
493
var res = $DictDict.__getitem__(self,key)
494
$DictDict.__delitem__(self,key)
495
return res
496
}catch(err){
497
$B.$pop_exc()
498
if(err.__name__==='KeyError'){
499
if(_default!==undefined) return _default
500
throw err
501
}
502
throw err
503
}
504
}
505
506
$DictDict.popitem = function(self){
507
try{
508
var itm = new $item_iterator(self).next()
509
$DictDict.__delitem__(self,itm[0])
510
return _b_.tuple(itm)
511
}catch(err) {
512
if (err.__name__ == "StopIteration") {
513
$B.$pop_exc()
514
throw KeyError("'popitem(): dictionary is empty'")
515
}
516
}
517
}
518
519
$DictDict.setdefault = function(self,key,_default){
520
try{return $DictDict.__getitem__(self,key)}
521
catch(err){
522
if(_default===undefined) _default=None
523
$DictDict.__setitem__(self,key,_default)
524
return _default
525
}
526
}
527
528
$DictDict.update = function(self){
529
var params = []
531
var $ns=$B.$MakeArgs('$DictDict.update',params,[],[],'args','kw')
532
var args = $ns['args']
533
if(args.length>0) {
534
var o=args[0]
535
if (isinstance(o,dict)){
536
$copy_dict(self, o)
537
} else if (hasattr(o, '__getitem__') && hasattr(o, 'keys')) {
538
var _keys=_b_.list(getattr(o, 'keys')())
539
for (var i=0; i < _keys.length; i++) {
540
var _value = getattr(o, '__getitem__')(_keys[i])
541
$DictDict.__setitem__(self, _keys[i], _value)
542
}
543
}
547
}
548
549
function dict(){
550
var res = {__class__:$DictDict}
551
// apply __init__ with arguments of dict()
552
var args = [res]
558
$B.$dict = dict // used for dict literals : "x={}" is translated to "x=__BRYTHON__.$dict()",
559
// not to "x=dict()"
560
// otherwise this would fail :
561
// def foo(dict=None):
562
// x = {}
563
// because inside the function, 'dict' has beeen set to the
564
// value of argument 'dict'
565
dict.__class__ = $B.$factory
566
dict.$dict = $DictDict
567
$DictDict.$factory = dict
568
$DictDict.__new__ = $B.$__new__(dict)
569
570
_b_.dict = dict
572
// following are used for faster access elsewhere
573
$B.$dict_iterator = function(d) { return new $item_generator(d) }
574
$B.$dict_length = $DictDict.__len__
575
$B.$dict_getitem = $DictDict.__getitem__
576
$B.$dict_get = $DictDict.get
577
$B.$dict_set = $DictDict.__setitem__
578
$B.$dict_contains = $DictDict.__contains__
579
$B.$dict_items = function(d) { return new $item_generator(d).as_list() }
580
$B.$copy_dict = $copy_dict // copy from right to left
581
$B.$dict_get_copy = $DictDict.copy // return a shallow copy
582
588
$ObjDictDict.__delitem__ = function(self, key){
589
$DictDict.__delitem__(self, key)
590
delete self.$obj[key]
591
}
592
593
$ObjDictDict.__setitem__ = function(self, key, value){
594
$DictDict.__setitem__(self, key, value)
595
self.$obj[key] = value
596
}
597
598
$ObjDictDict.clear = function(self){
599
$DictDict.clear(self)
600
for(var key in self.$obj){delete self.$obj[key]}
601
}
602
603
$ObjDictDict.pop = function(self, key, _default){
604
$DictDict.pop(self, key, _default)
605
delete self.$obj[key]
606
return key
607
}
608
609
$ObjDictDict.popitem = function(self){
610
var res = $DictDict.popitem(self) // tuple
611
var key = res[0]
612
delete self.$obj[key]
613
return res
614
}
615
616
$ObjDictDict.update = function(self){
617
$DictDict.update.apply(null, arguments)
618
// Update attributes of underlying object by iterating on self.items()
619
var it = $DictDict.items(self)
620
while(true){
621
try{
622
var item = next(it)
623
self.$obj[item[0]] = item[1]
624
}catch(err){
625
if($B.is_exc(err,[_b_.StopIteration])){
626
$B.$pop_exc();return
627
}
628
throw err
629
}
630
}
634
// Function called to get attribute "__dict__" of an object
635
if(obj.__class__===$B.$factory){return obj.$dict.__dict__}
641
}
642
}
643
return res
644
}
645
obj_dict.$dict = $ObjDictDict
646
obj_dict.__class__ = $B.$factory
647
$ObjDictDict.$factory = obj_dict
648
649
$B.obj_dict = obj_dict
650