@@ -94,7 +94,7 @@ class Builder(object):
94
94
It holds the following internal state:
95
95
- Bytes: an array of bytes.
96
96
- current_vtable: a list of integers.
97
- - vtables: a list of vtable entries (i.e. a list of list of integers) .
97
+ - vtables: a hash of vtable entries.
98
98
99
99
Attributes:
100
100
Bytes: The internal `bytearray` for the Builder.
@@ -129,7 +129,7 @@ def __init__(self, initialSize):
129
129
self .head = UOffsetTFlags .py_type (initialSize )
130
130
self .minalign = 1
131
131
self .objectEnd = None
132
- self .vtables = []
132
+ self .vtables = {}
133
133
self .nested = False
134
134
## @endcond
135
135
self .finished = False
@@ -191,52 +191,45 @@ def WriteVtable(self):
191
191
self .PrependSOffsetTRelative (0 )
192
192
193
193
objectOffset = self .Offset ()
194
- existingVtable = None
195
-
196
- # Trim trailing 0 offsets.
197
- while self .current_vtable and self .current_vtable [- 1 ] == 0 :
198
- self .current_vtable .pop ()
199
-
200
- # Search backwards through existing vtables, because similar vtables
201
- # are likely to have been recently appended. See
202
- # BenchmarkVtableDeduplication for a case in which this heuristic
203
- # saves about 30% of the time used in writing objects with duplicate
204
- # tables.
205
-
206
- i = len (self .vtables ) - 1
207
- while i >= 0 :
208
- # Find the other vtable, which is associated with `i`:
209
- vt2Offset = self .vtables [i ]
210
- vt2Start = len (self .Bytes ) - vt2Offset
211
- vt2Len = encode .Get (packer .voffset , self .Bytes , vt2Start )
212
-
213
- metadata = VtableMetadataFields * N .VOffsetTFlags .bytewidth
214
- vt2End = vt2Start + vt2Len
215
- vt2 = self .Bytes [vt2Start + metadata :vt2End ]
216
-
217
- # Compare the other vtable to the one under consideration.
218
- # If they are equal, store the offset and break:
219
- if vtableEqual (self .current_vtable , objectOffset , vt2 ):
220
- existingVtable = vt2Offset
221
- break
222
-
223
- i -= 1
224
-
225
- if existingVtable is None :
194
+
195
+ vtKey = []
196
+ trim = True
197
+ for elem in reversed (self .current_vtable ):
198
+ if elem == 0 :
199
+ if trim :
200
+ continue
201
+ else :
202
+ elem = objectOffset - elem
203
+ trim = False
204
+
205
+ vtKey .append (elem )
206
+
207
+ vtKey = tuple (vtKey )
208
+ vt2Offset = self .vtables .get (vtKey )
209
+ if vt2Offset is None :
226
210
# Did not find a vtable, so write this one to the buffer.
227
211
228
212
# Write out the current vtable in reverse , because
229
213
# serialization occurs in last-first order:
230
214
i = len (self .current_vtable ) - 1
215
+ trailing = 0
216
+ trim = True
231
217
while i >= 0 :
232
218
off = 0
233
- if self .current_vtable [i ] != 0 :
219
+ elem = self .current_vtable [i ]
220
+ i -= 1
221
+
222
+ if elem == 0 :
223
+ if trim :
224
+ trailing += 1
225
+ continue
226
+ else :
234
227
# Forward reference to field;
235
228
# use 32bit number to ensure no overflow:
236
- off = objectOffset - self .current_vtable [i ]
229
+ off = objectOffset - elem
230
+ trim = False
237
231
238
232
self .PrependVOffsetT (off )
239
- i -= 1
240
233
241
234
# The two metadata fields are written last.
242
235
@@ -245,7 +238,7 @@ def WriteVtable(self):
245
238
self .PrependVOffsetT (VOffsetTFlags .py_type (objectSize ))
246
239
247
240
# Second, store the vtable bytesize:
248
- vBytes = len (self .current_vtable ) + VtableMetadataFields
241
+ vBytes = len (self .current_vtable ) - trailing + VtableMetadataFields
249
242
vBytes *= N .VOffsetTFlags .bytewidth
250
243
self .PrependVOffsetT (VOffsetTFlags .py_type (vBytes ))
251
244
@@ -257,17 +250,16 @@ def WriteVtable(self):
257
250
258
251
# Finally, store this vtable in memory for future
259
252
# deduplication:
260
- self .vtables . append ( self .Offset () )
253
+ self .vtables [ vtKey ] = self .Offset ()
261
254
else :
262
255
# Found a duplicate vtable.
263
-
264
256
objectStart = SOffsetTFlags .py_type (len (self .Bytes ) - objectOffset )
265
257
self .head = UOffsetTFlags .py_type (objectStart )
266
258
267
259
# Write the offset to the found vtable in the
268
260
# already-allocated SOffsetT at the beginning of this object:
269
261
encode .Write (packer .soffset , self .Bytes , self .Head (),
270
- SOffsetTFlags .py_type (existingVtable - objectOffset ))
262
+ SOffsetTFlags .py_type (vt2Offset - objectOffset ))
271
263
272
264
self .current_vtable = None
273
265
return objectOffset
0 commit comments