1
1
# Fallback pure Python implementation of msgpack
2
2
3
+ #
4
+ # Easy imports
5
+ #
3
6
import sys
4
7
import array
5
8
import struct
6
9
10
+ #
11
+ # Tricky imports
12
+ #
13
+ try :
14
+ from cStringIO import StringIO
15
+ except ImportError :
16
+ from StringIO import StringIO
17
+
18
+ # We will use wStringIO for buffering the writes for packing.
19
+ # Normally, we will use cStringIO.StringIO.
20
+ # On PyPy we will use PyPy's own StringBuilder.
7
21
if hasattr (sys , 'pypy_version_info' ):
8
- # cStringIO is slow on PyPy, StringIO is faster. However: PyPy's own
9
- # StringBuilder is fastest.
10
22
from __pypy__ .builders import StringBuilder
11
23
USING_STRINGBUILDER = True
12
- class StringIO (object ):
24
+ class wStringIO (object ):
13
25
def __init__ (self , s = '' ):
14
26
if s :
15
27
self .builder = StringBuilder (len (s ))
@@ -22,10 +34,18 @@ def getvalue(self):
22
34
return self .builder .build ()
23
35
else :
24
36
USING_STRINGBUILDER = False
25
- try :
26
- from cStringIO import StringIO
27
- except ImportError :
28
- from StringIO import StringIO
37
+ wStringIO = StringIO
38
+
39
+ # We will use rStringIO for unpacking.
40
+ # Normally, this is a mmap. A normal StringIO is not a drop-in replacement ---
41
+ # it misses the __len__ operation.
42
+ # TODO add fallback for when mmap is unavailable
43
+ import mmap
44
+ def rStringIO (s ):
45
+ m = mmap .mmap (- 1 , len (s ))
46
+ m .write (s )
47
+ m .seek (0 )
48
+ return m
29
49
30
50
from msgpack .exceptions import (
31
51
BufferFull ,
@@ -184,13 +204,13 @@ def feed(self, next_bytes):
184
204
if self ._fb_buf_n + len (next_bytes ) > self .max_buffer_size :
185
205
raise BufferFull
186
206
self ._fb_buf_n += len (next_bytes )
187
- self ._fb_buffers .append (next_bytes )
207
+ self ._fb_buffers .append (rStringIO ( next_bytes ) )
188
208
189
209
def _fb_consume (self ):
190
210
self ._fb_buffers = self ._fb_buffers [self ._fb_buf_i :]
191
211
if self ._fb_buffers :
192
- self ._fb_buffers [0 ] = self ._fb_buffers [0 ][self . _fb_buf_o :]
193
- self . _fb_buf_o = 0
212
+ self ._fb_buffers [0 ] = rStringIO ( self ._fb_buffers [0 ][
213
+ self . _fb_buffers [ 0 ]. tell ():])
194
214
self ._fb_buf_i = 0
195
215
self ._fb_buf_n = sum (map (len , self ._fb_buffers ))
196
216
@@ -212,16 +232,20 @@ def read_bytes(self, n):
212
232
return self ._fb_read (n )
213
233
214
234
def _fb_rollback (self ):
235
+ for buf in self ._fb_buffers :
236
+ buf .seek (0 )
215
237
self ._fb_buf_i = 0
216
- self ._fb_buf_o = 0
217
238
218
239
def _fb_get_extradata (self ):
219
240
bufs = self ._fb_buffers [self ._fb_buf_i :]
220
241
if bufs :
221
- bufs [0 ] = bufs [0 ][self . _fb_buf_o :]
222
- return '' .join (bufs )
242
+ bufs [0 ] = rStringIO ( bufs [0 ][bufs [ 0 ]. tell ():])
243
+ return '' .join ([ buf [:] for buf in bufs ] )
223
244
224
245
def _fb_read (self , n , write_bytes = None ):
246
+ if (write_bytes is None and self ._fb_buf_i < len (self ._fb_buffers )
247
+ and self ._fb_buffers [0 ].tell () + n < len (self ._fb_buffers [0 ])):
248
+ return self ._fb_buffers [0 ].read (n )
225
249
ret = ''
226
250
while len (ret ) != n :
227
251
if self ._fb_buf_i == len (self ._fb_buffers ):
@@ -230,14 +254,12 @@ def _fb_read(self, n, write_bytes=None):
230
254
tmp = self .file_like .read (self .read_size )
231
255
if not tmp :
232
256
break
233
- self ._fb_buffers .append (tmp )
257
+ self ._fb_buffers .append (rStringIO ( tmp ) )
234
258
continue
235
259
sliced = n - len (ret )
236
- ret += self ._fb_buffers [self ._fb_buf_i ][
237
- self ._fb_buf_o :self ._fb_buf_o + sliced ]
238
- self ._fb_buf_o += sliced
239
- if self ._fb_buf_o >= len (self ._fb_buffers [self ._fb_buf_i ]):
240
- self ._fb_buf_o = 0
260
+ ret += self ._fb_buffers [self ._fb_buf_i ].read (sliced )
261
+ if (self ._fb_buffers [self ._fb_buf_i ].tell ()
262
+ == len (self ._fb_buffers [self ._fb_buf_i ])):
241
263
self ._fb_buf_i += 1
242
264
if len (ret ) != n :
243
265
self ._fb_rollback ()
@@ -394,7 +416,7 @@ def __init__(self, default=None, encoding='utf-8', unicode_errors='strict',
394
416
self .autoreset = autoreset
395
417
self .encoding = encoding
396
418
self .unicode_errors = unicode_errors
397
- self .buffer = StringIO ()
419
+ self .buffer = wStringIO ()
398
420
if default is not None :
399
421
if not callable (default ):
400
422
raise TypeError ("default must be callable" )
@@ -464,33 +486,33 @@ def pack(self, obj):
464
486
self ._pack (obj )
465
487
ret = self .buffer .getvalue ()
466
488
if self .autoreset :
467
- self .buffer = StringIO ()
489
+ self .buffer = wStringIO ()
468
490
elif USING_STRINGBUILDER :
469
- self .buffer = StringIO (ret )
491
+ self .buffer = wStringIO (ret )
470
492
return ret
471
493
def pack_map_pairs (self , pairs ):
472
494
self ._fb_pack_map_pairs (len (pairs ), pairs )
473
495
ret = self .buffer .getvalue ()
474
496
if self .autoreset :
475
- self .buffer = StringIO ()
497
+ self .buffer = wStringIO ()
476
498
elif USING_STRINGBUILDER :
477
- self .buffer = StringIO (ret )
499
+ self .buffer = wStringIO (ret )
478
500
return ret
479
501
def pa
CA01
ck_array_header (self , n ):
480
502
self ._fb_pack_array_header (n )
481
503
ret = self .buffer .getvalue ()
482
504
if self .autoreset :
483
- self .buffer = StringIO ()
505
+ self .buffer = wStringIO ()
484
506
elif USING_STRINGBUILDER :
485
- self .buffer = StringIO (ret )
507
+ self .buffer = wStringIO (ret )
486
508
return ret
487
509
def pack_map_header (self , n ):
488
510
self ._fb_pack_map_header (n )
489
511
ret = self .buffer .getvalue ()
490
512
if self .autoreset :
491
- self .buffer = StringIO ()
513
+ self .buffer = wStringIO ()
492
514
elif USING_STRINGBUILDER :
493
- self .buffer = StringIO (ret )
515
+ self .buffer = wStringIO (ret )
494
516
return ret
495
517
def _fb_pack_array_header (self , n ):
496
518
if n <= 0x0f :
@@ -516,4 +538,4 @@ def _fb_pack_map_pairs(self, n, pairs, nest_limit=DEFAULT_RECURSE_LIMIT):
516
538
def bytes (self ):
517
539
return self .buffer .getvalue ()
518
540
def reset (self ):
519
- self .buffer = StringIO ()
541
+ self .buffer = wStringIO ()
0 commit comments