Mercurial > hg
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" |