comparison mercurial/pure/parsers.py @ 29133:255274719dc1

pure: write a really lazy version of pure indexObject On PyPy this version performs reasonably well compared to C version. Example command is "hg id" which gets faster, depending on details of your operating system and hard drive (it's bottlenecked on stat mostly) There is potential for improvements by storing extra as a condensed struct too.
author Maciej Fijalkowski <fijall@gmail.com>
date Sun, 24 Apr 2016 14:21:38 +0300
parents 86db5cb55d46
children 37596c980662
comparison
equal deleted inserted replaced
29132:12769703d4ba 29133:255274719dc1
23 # code outside this module should always use dirstatetuple. 23 # code outside this module should always use dirstatetuple.
24 def dirstatetuple(*x): 24 def dirstatetuple(*x):
25 # x is a tuple 25 # x is a tuple
26 return x 26 return x
27 27
28 indexformatng = ">Qiiiiii20s12x"
29 indexfirst = struct.calcsize('Q')
30 sizeint = struct.calcsize('i')
31 indexsize = struct.calcsize(indexformatng)
32
33 def gettype(q):
34 return int(q & 0xFFFF)
35
36 def offset_type(offset, type):
37 return long(long(offset) << 16 | type)
38
39 class BaseIndexObject(object):
40 def __len__(self):
41 return self._lgt + len(self._extra) + 1
42
43 def insert(self, i, tup):
44 assert i == -1
45 self._extra.append(tup)
46
47 def _fix_index(self, i):
48 if not isinstance(i, int):
49 raise TypeError("expecting int indexes")
50 if i < 0:
51 i = len(self) + i
52 if i < 0 or i >= len(self):
53 raise IndexError
54 return i
55
56 def __getitem__(self, i):
57 i = self._fix_index(i)
58 if i == len(self) - 1:
59 return (0, 0, 0, -1, -1, -1, -1, nullid)
60 if i >= self._lgt:
61 return self._extra[i - self._lgt]
62 index = self._calculate_index(i)
63 r = struct.unpack(indexformatng, self._data[index:index + indexsize])
64 if i == 0:
65 e = list(r)
66 type = gettype(e[0])
67 e[0] = offset_type(0, type)
68 return tuple(e)
69 return r
70
71 class IndexObject(BaseIndexObject):
72 def __init__(self, data):
73 assert len(data) % indexsize == 0
74 self._data = data
75 self._lgt = len(data) // indexsize
76 self._extra = []
77
78 def _calculate_index(self, i):
79 return i * indexsize
80
81 def __delitem__(self, i):
82 if not isinstance(i, slice) or not i.stop == -1 or not i.step is None:
83 raise ValueError("deleting slices only supports a:-1 with step 1")
84 i = self._fix_index(i.start)
85 if i < self._lgt:
86 self._data = self._data[:i * indexsize]
87 self._lgt = i
88 self._extra = []
89 else:
90 self._extra = self._extra[:i - self._lgt]
91
92 class InlinedIndexObject(BaseIndexObject):
93 def __init__(self, data, inline=0):
94 self._data = data
95 self._lgt = self._inline_scan(None)
96 self._inline_scan(self._lgt)
97 self._extra = []
98
99 def _inline_scan(self, lgt):
100 off = 0
101 if lgt is not None:
102 self._offsets = [0] * lgt
103 count = 0
104 while off <= len(self._data) - indexsize:
105 s, = struct.unpack('>i',
106 self._data[off + indexfirst:off + sizeint + indexfirst])
107 if lgt is not None:
108 self._offsets[count] = off
109 count += 1
110 off += indexsize + s
111 if off != len(self._data):
112 raise ValueError("corrupted data")
113 return count
114
115 def __delitem__(self, i):
116 if not isinstance(i, slice) or not i.stop == -1 or not i.step is None:
117 raise ValueError("deleting slices only supports a:-1 with step 1")
118 i = self._fix_index(i.start)
119 if i < self._lgt:
120 self._offsets = self._offsets[:i]
121 self._lgt = i
122 self._extra = []
123 else:
124 self._extra = self._extra[:i - self._lgt]
125
126 def _calculate_index(self, i):
127 return self._offsets[i]
128
28 def parse_index2(data, inline): 129 def parse_index2(data, inline):
29 def gettype(q): 130 if not inline:
30 return int(q & 0xFFFF) 131 return IndexObject(data), None
31 132 return InlinedIndexObject(data, inline), (0, data)
32 def offset_type(offset, type):
33 return long(long(offset) << 16 | type)
34
35 indexformatng = ">Qiiiiii20s12x"
36
37 s = struct.calcsize(indexformatng)
38 index = []
39 cache = None
40 off = 0
41
42 l = len(data) - s
43 append = index.append
44 if inline:
45 cache = (0, data)
46 while off <= l:
47 e = _unpack(indexformatng, data[off:off + s])
48 append(e)
49 if e[1] < 0:
50 break
51 off += e[1] + s
52 else:
53 while off <= l:
54 e = _unpack(indexformatng, data[off:off + s])
55 append(e)
56 off += s
57
58 if off != len(data):
59 raise ValueError('corrupt index file')
60
61 if index:
62 e = list(index[0])
63 type = gettype(e[0])
64 e[0] = offset_type(0, type)
65 index[0] = tuple(e)
66
67 # add the magic null revision at -1
68 index.append((0, 0, 0, -1, -1, -1, -1, nullid))
69
70 return index, cache
71 133
72 def parse_dirstate(dmap, copymap, st): 134 def parse_dirstate(dmap, copymap, st):
73 parents = [st[:20], st[20: 40]] 135 parents = [st[:20], st[20: 40]]
74 # dereference fields so they will be local in loop 136 # dereference fields so they will be local in loop
75 format = ">cllll" 137 format = ">cllll"