@mlightcad/data-model 1.10.4 → 1.10.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data-model.cjs +12 -11
- package/lib/converter/AcDbRegenerator.d.ts +4 -0
- package/lib/converter/AcDbRegenerator.d.ts.map +1 -1
- package/lib/converter/AcDbRegenerator.js +6 -0
- package/lib/converter/AcDbRegenerator.js.map +1 -1
- package/lib/database/AcDbClass.d.ts +45 -0
- package/lib/database/AcDbClass.d.ts.map +1 -0
- package/lib/database/AcDbClass.js +2 -0
- package/lib/database/AcDbClass.js.map +1 -0
- package/lib/database/AcDbDatabase.d.ts +20 -0
- package/lib/database/AcDbDatabase.d.ts.map +1 -1
- package/lib/database/AcDbDatabase.js +93 -26
- package/lib/database/AcDbDatabase.js.map +1 -1
- package/lib/database/AcDbDatabaseConverter.d.ts +1 -0
- package/lib/database/AcDbDatabaseConverter.d.ts.map +1 -1
- package/lib/database/AcDbDatabaseConverter.js +4 -0
- package/lib/database/AcDbDatabaseConverter.js.map +1 -1
- package/lib/database/AcDbTextStyleTableRecord.d.ts +7 -0
- package/lib/database/AcDbTextStyleTableRecord.d.ts.map +1 -1
- package/lib/database/AcDbTextStyleTableRecord.js +22 -1
- package/lib/database/AcDbTextStyleTableRecord.js.map +1 -1
- package/lib/database/AcDbViewportTableRecord.d.ts +11 -1
- package/lib/database/AcDbViewportTableRecord.d.ts.map +1 -1
- package/lib/database/AcDbViewportTableRecord.js +33 -5
- package/lib/database/AcDbViewportTableRecord.js.map +1 -1
- package/lib/database/index.d.ts +1 -0
- package/lib/database/index.d.ts.map +1 -1
- package/lib/database/index.js.map +1 -1
- package/lib/entity/AcDbHatch.d.ts.map +1 -1
- package/lib/entity/AcDbHatch.js +5 -2
- package/lib/entity/AcDbHatch.js.map +1 -1
- package/lib/entity/AcDbMText.d.ts.map +1 -1
- package/lib/entity/AcDbMText.js +4 -3
- package/lib/entity/AcDbMText.js.map +1 -1
- package/lib/entity/AcDbPolyline.d.ts +5 -0
- package/lib/entity/AcDbPolyline.d.ts.map +1 -1
- package/lib/entity/AcDbPolyline.js +70 -7
- package/lib/entity/AcDbPolyline.js.map +1 -1
- package/lib/entity/AcDbProxyEntity.d.ts +59 -13
- package/lib/entity/AcDbProxyEntity.d.ts.map +1 -1
- package/lib/entity/AcDbProxyEntity.js +96 -27
- package/lib/entity/AcDbProxyEntity.js.map +1 -1
- package/lib/entity/AcDbShape.d.ts +17 -0
- package/lib/entity/AcDbShape.d.ts.map +1 -1
- package/lib/entity/AcDbShape.js +45 -10
- package/lib/entity/AcDbShape.js.map +1 -1
- package/lib/entity/AcDbSolid.d.ts +15 -0
- package/lib/entity/AcDbSolid.d.ts.map +1 -0
- package/lib/entity/AcDbSolid.js +42 -0
- package/lib/entity/AcDbSolid.js.map +1 -0
- package/lib/entity/AcDbTrace.d.ts +1 -1
- package/lib/entity/AcDbTrace.d.ts.map +1 -1
- package/lib/entity/AcDbTrace.js +8 -4
- package/lib/entity/AcDbTrace.js.map +1 -1
- package/lib/entity/index.d.ts +1 -0
- package/lib/entity/index.d.ts.map +1 -1
- package/lib/entity/index.js +1 -0
- package/lib/entity/index.js.map +1 -1
- package/lib/index.d.ts +4 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/misc/AcDbMemoryEstimator.d.ts +115 -0
- package/lib/misc/AcDbMemoryEstimator.d.ts.map +1 -0
- package/lib/misc/AcDbMemoryEstimator.js +753 -0
- package/lib/misc/AcDbMemoryEstimator.js.map +1 -0
- package/lib/misc/index.d.ts +2 -0
- package/lib/misc/index.d.ts.map +1 -1
- package/lib/misc/index.js +1 -0
- package/lib/misc/index.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,753 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Heuristic in-memory size estimator for {@link AcDbDatabase}.
|
|
3
|
+
*
|
|
4
|
+
* Walks the ownership graph with a {@link WeakSet} to avoid cycles and estimates
|
|
5
|
+
* bytes using V8-inspired constants. Results are reproducible and useful for
|
|
6
|
+
* comparing drawings; they are not exact Chrome heap retained sizes.
|
|
7
|
+
* Cross-check with `performance.memory` / DevTools heap snapshots when needed.
|
|
8
|
+
*
|
|
9
|
+
* @module AcDbMemoryEstimator
|
|
10
|
+
*/
|
|
11
|
+
var __values = (this && this.__values) || function(o) {
|
|
12
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
13
|
+
if (m) return m.call(o);
|
|
14
|
+
if (o && typeof o.length === "number") return {
|
|
15
|
+
next: function () {
|
|
16
|
+
if (o && i >= o.length) o = void 0;
|
|
17
|
+
return { value: o && o[i++], done: !o };
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
21
|
+
};
|
|
22
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
23
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
24
|
+
if (!m) return o;
|
|
25
|
+
var i = m.call(o), r, ar = [], e;
|
|
26
|
+
try {
|
|
27
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
28
|
+
}
|
|
29
|
+
catch (error) { e = { error: error }; }
|
|
30
|
+
finally {
|
|
31
|
+
try {
|
|
32
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
33
|
+
}
|
|
34
|
+
finally { if (e) throw e.error; }
|
|
35
|
+
}
|
|
36
|
+
return ar;
|
|
37
|
+
};
|
|
38
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
39
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
40
|
+
if (ar || !(i in from)) {
|
|
41
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
42
|
+
ar[i] = from[i];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
46
|
+
};
|
|
47
|
+
import { AcDbEntity } from '../entity/AcDbEntity';
|
|
48
|
+
/** Estimated per-object header size in bytes (V8-inspired heuristic). */
|
|
49
|
+
var OBJECT_OVERHEAD = 48;
|
|
50
|
+
/** Estimated pointer / slot size in bytes. */
|
|
51
|
+
var POINTER_SIZE = 8;
|
|
52
|
+
/** Estimated array object header size in bytes. */
|
|
53
|
+
var ARRAY_OVERHEAD = 48;
|
|
54
|
+
/** Estimated `Map` object header size in bytes. */
|
|
55
|
+
var MAP_OVERHEAD = 80;
|
|
56
|
+
/** Estimated cost of one `Map` entry (excluding key/value payloads). */
|
|
57
|
+
var MAP_ENTRY_OVERHEAD = 32;
|
|
58
|
+
/** Estimated `Set` object header size in bytes. */
|
|
59
|
+
var SET_OVERHEAD = 80;
|
|
60
|
+
/** Estimated cost of one `Set` entry (excluding value payload). */
|
|
61
|
+
var SET_ENTRY_OVERHEAD = 24;
|
|
62
|
+
/** Estimated string object header size in bytes (UTF-16 payload billed separately). */
|
|
63
|
+
var STRING_OVERHEAD = 40;
|
|
64
|
+
/** Estimated size of a JavaScript `number`. */
|
|
65
|
+
var NUMBER_SIZE = 8;
|
|
66
|
+
/** Estimated size of a JavaScript `boolean`. */
|
|
67
|
+
var BOOLEAN_SIZE = 4;
|
|
68
|
+
/** Estimated TypedArray / ArrayBuffer object header size in bytes. */
|
|
69
|
+
var TYPED_ARRAY_OVERHEAD = 64;
|
|
70
|
+
/** Estimated `Blob` object header size in bytes (`size` billed separately). */
|
|
71
|
+
var BLOB_OVERHEAD = 64;
|
|
72
|
+
/**
|
|
73
|
+
* {@link AcDbDatabase} own-property names treated as system variables / header
|
|
74
|
+
* state when classifying memory into the `sysvars` category.
|
|
75
|
+
*/
|
|
76
|
+
var SYSVAR_KEYS = new Set([
|
|
77
|
+
'_version',
|
|
78
|
+
'_angbase',
|
|
79
|
+
'_angdir',
|
|
80
|
+
'_aunits',
|
|
81
|
+
'_auprec',
|
|
82
|
+
'_lunits',
|
|
83
|
+
'_luprec',
|
|
84
|
+
'_celtscale',
|
|
85
|
+
'_cecolor',
|
|
86
|
+
'_celtype',
|
|
87
|
+
'_celweight',
|
|
88
|
+
'_cetransparency',
|
|
89
|
+
'_clayer',
|
|
90
|
+
'_cmlstyle',
|
|
91
|
+
'_cmlscale',
|
|
92
|
+
'_cmleaderstyle',
|
|
93
|
+
'_hpbackgroundcolor',
|
|
94
|
+
'_hpcolor',
|
|
95
|
+
'_hplayer',
|
|
96
|
+
'_hptransparency',
|
|
97
|
+
'_textstyle',
|
|
98
|
+
'_extents',
|
|
99
|
+
'_insunits',
|
|
100
|
+
'_unitmode',
|
|
101
|
+
'_measurement',
|
|
102
|
+
'_ltscale',
|
|
103
|
+
'_lwdisplay',
|
|
104
|
+
'_pdmode',
|
|
105
|
+
'_pdsize',
|
|
106
|
+
'_osmode',
|
|
107
|
+
'_orthomode',
|
|
108
|
+
'_maxHandle',
|
|
109
|
+
'_drawNoPlotLayers',
|
|
110
|
+
'_dwgname',
|
|
111
|
+
'_currentSpace',
|
|
112
|
+
'_formatter',
|
|
113
|
+
'_eventBatchDepth',
|
|
114
|
+
'_pendingEntityAppended',
|
|
115
|
+
'_pendingEntityErased',
|
|
116
|
+
'_pendingDictObjectSet',
|
|
117
|
+
'_pendingDictObjectErased',
|
|
118
|
+
'_lastOpenError'
|
|
119
|
+
]);
|
|
120
|
+
/**
|
|
121
|
+
* Property names that are never walked (prototype / call-stack noise).
|
|
122
|
+
*/
|
|
123
|
+
var SKIP_ALWAYS = new Set([
|
|
124
|
+
'constructor',
|
|
125
|
+
'prototype',
|
|
126
|
+
'__proto__',
|
|
127
|
+
'caller',
|
|
128
|
+
'callee',
|
|
129
|
+
'arguments'
|
|
130
|
+
]);
|
|
131
|
+
/**
|
|
132
|
+
* Returns the bucket for `key`, creating an empty one when missing.
|
|
133
|
+
*
|
|
134
|
+
* @param map - Category or entity-type bucket map.
|
|
135
|
+
* @param key - Bucket key to look up or create.
|
|
136
|
+
* @returns The existing or newly created bucket.
|
|
137
|
+
* @internal
|
|
138
|
+
*/
|
|
139
|
+
function ensureBucket(map, key) {
|
|
140
|
+
var bucket = map.get(key);
|
|
141
|
+
if (!bucket) {
|
|
142
|
+
bucket = { bytes: 0, count: 0 };
|
|
143
|
+
map.set(key, bucket);
|
|
144
|
+
}
|
|
145
|
+
return bucket;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Adds estimated bytes (and optional object count) to a category bucket.
|
|
149
|
+
*
|
|
150
|
+
* No-op when both `bytes` and `objectDelta` are zero.
|
|
151
|
+
*
|
|
152
|
+
* @param state - Shared walk state.
|
|
153
|
+
* @param category - Category name to update.
|
|
154
|
+
* @param bytes - Bytes to add to the category.
|
|
155
|
+
* @param objectDelta - Object count delta to add (default `0`).
|
|
156
|
+
* @internal
|
|
157
|
+
*/
|
|
158
|
+
function addBytes(state, category, bytes, objectDelta) {
|
|
159
|
+
if (objectDelta === void 0) { objectDelta = 0; }
|
|
160
|
+
if (bytes <= 0 && objectDelta === 0)
|
|
161
|
+
return;
|
|
162
|
+
var bucket = ensureBucket(state.byCategory, category);
|
|
163
|
+
bucket.bytes += bytes;
|
|
164
|
+
bucket.count += objectDelta;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Returns whether `value` is a plain object (`Object` prototype or `null`
|
|
168
|
+
* prototype), as opposed to a class instance.
|
|
169
|
+
*
|
|
170
|
+
* @param value - Object to test.
|
|
171
|
+
* @returns `true` when `value` is a plain object.
|
|
172
|
+
* @internal
|
|
173
|
+
*/
|
|
174
|
+
function isPlainObject(value) {
|
|
175
|
+
var proto = Object.getPrototypeOf(value);
|
|
176
|
+
return proto === Object.prototype || proto === null;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Type guard for TypedArray / DataView values (`ArrayBuffer.isView`).
|
|
180
|
+
*
|
|
181
|
+
* @param value - Value to test.
|
|
182
|
+
* @returns `true` when `value` is an {@link ArrayBufferView}.
|
|
183
|
+
* @internal
|
|
184
|
+
*/
|
|
185
|
+
function isTypedArray(value) {
|
|
186
|
+
return ArrayBuffer.isView(value);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Heuristic detection of {@link AcCmEventManager}-like objects so their
|
|
190
|
+
* listener lists can be skipped when event managers are excluded.
|
|
191
|
+
*
|
|
192
|
+
* @param value - Object to test.
|
|
193
|
+
* @returns `true` when `value` looks like an event manager.
|
|
194
|
+
* @internal
|
|
195
|
+
*/
|
|
196
|
+
function isAcCmEventManager(value) {
|
|
197
|
+
return (typeof value.addEventListener ===
|
|
198
|
+
'function' &&
|
|
199
|
+
typeof value.dispatch === 'function' &&
|
|
200
|
+
'listeners' in value);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Returns whether a property should be skipped based on walk options and
|
|
204
|
+
* always-skipped names.
|
|
205
|
+
*
|
|
206
|
+
* @param state - Shared walk state (options).
|
|
207
|
+
* @param key - Property name being considered.
|
|
208
|
+
* @param category - Current ownership category of the parent object.
|
|
209
|
+
* @returns `true` when the property must not be walked.
|
|
210
|
+
* @internal
|
|
211
|
+
*/
|
|
212
|
+
function shouldSkipProperty(state, key, category) {
|
|
213
|
+
if (SKIP_ALWAYS.has(key))
|
|
214
|
+
return true;
|
|
215
|
+
if (!state.includeEventManagers &&
|
|
216
|
+
(key === 'events' || category === 'events')) {
|
|
217
|
+
return key === 'events';
|
|
218
|
+
}
|
|
219
|
+
if (!state.includeTransactionManager &&
|
|
220
|
+
(key === 'transactionManager' || category === 'transaction')) {
|
|
221
|
+
return key === 'transactionManager';
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Resolves the ownership category for a child value based on the parent
|
|
227
|
+
* category, property name, and runtime type.
|
|
228
|
+
*
|
|
229
|
+
* @param parentCategory - Category of the owning object.
|
|
230
|
+
* @param key - Child property name (or array index as string).
|
|
231
|
+
* @param value - Child value (used for entity detection).
|
|
232
|
+
* @returns Category to use when measuring the child.
|
|
233
|
+
* @internal
|
|
234
|
+
*/
|
|
235
|
+
function resolveChildCategory(parentCategory, key, value) {
|
|
236
|
+
if (key === '_xDataMap' || parentCategory === 'xdata') {
|
|
237
|
+
return 'xdata';
|
|
238
|
+
}
|
|
239
|
+
if (key === '_tables' || parentCategory === 'tables') {
|
|
240
|
+
if (value instanceof AcDbEntity)
|
|
241
|
+
return 'entities';
|
|
242
|
+
return 'tables';
|
|
243
|
+
}
|
|
244
|
+
if (key === '_entities' || parentCategory === 'entities') {
|
|
245
|
+
return 'entities';
|
|
246
|
+
}
|
|
247
|
+
if (key === '_objects' || parentCategory === 'objects') {
|
|
248
|
+
return 'objects';
|
|
249
|
+
}
|
|
250
|
+
if (key === '_handleRegistry' || parentCategory === 'handleRegistry') {
|
|
251
|
+
return 'handleRegistry';
|
|
252
|
+
}
|
|
253
|
+
if (key === 'transactionManager' || parentCategory === 'transaction') {
|
|
254
|
+
return 'transaction';
|
|
255
|
+
}
|
|
256
|
+
if (key === 'events' || parentCategory === 'events') {
|
|
257
|
+
return 'events';
|
|
258
|
+
}
|
|
259
|
+
if (parentCategory === 'sysvars' || SYSVAR_KEYS.has(key)) {
|
|
260
|
+
return 'sysvars';
|
|
261
|
+
}
|
|
262
|
+
if (value instanceof AcDbEntity) {
|
|
263
|
+
return 'entities';
|
|
264
|
+
}
|
|
265
|
+
return parentCategory === 'other' ? 'other' : parentCategory;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Collects instance data property names from `obj` and its class prototype
|
|
269
|
+
* chain (TypeScript `private` fields are still present as `_foo` on the
|
|
270
|
+
* instance / class field storage).
|
|
271
|
+
*
|
|
272
|
+
* Skips methods, accessors without a data value, and built-in prototypes
|
|
273
|
+
* such as `Array.prototype`.
|
|
274
|
+
*
|
|
275
|
+
* @param obj - Class instance or plain object to inspect.
|
|
276
|
+
* @returns Deduplicated list of instance property names.
|
|
277
|
+
* @internal
|
|
278
|
+
*/
|
|
279
|
+
function collectInstanceKeys(obj) {
|
|
280
|
+
var e_1, _a;
|
|
281
|
+
var keys = new Set();
|
|
282
|
+
var current = obj;
|
|
283
|
+
while (current && current !== Object.prototype) {
|
|
284
|
+
try {
|
|
285
|
+
for (var _b = (e_1 = void 0, __values(Object.getOwnPropertyNames(current))), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
286
|
+
var key = _c.value;
|
|
287
|
+
if (SKIP_ALWAYS.has(key))
|
|
288
|
+
continue;
|
|
289
|
+
// Skip prototype methods; we only want instance data fields.
|
|
290
|
+
var desc = Object.getOwnPropertyDescriptor(current, key);
|
|
291
|
+
if (desc && typeof desc.value === 'function')
|
|
292
|
+
continue;
|
|
293
|
+
if (desc && (desc.get || desc.set) && desc.value === undefined)
|
|
294
|
+
continue;
|
|
295
|
+
keys.add(key);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
299
|
+
finally {
|
|
300
|
+
try {
|
|
301
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
302
|
+
}
|
|
303
|
+
finally { if (e_1) throw e_1.error; }
|
|
304
|
+
}
|
|
305
|
+
current = Object.getPrototypeOf(current);
|
|
306
|
+
// Stop before walking built-in prototypes for class instances that store
|
|
307
|
+
// data only on the instance / custom prototypes above Object.
|
|
308
|
+
if (current === Object.prototype || current === null)
|
|
309
|
+
break;
|
|
310
|
+
// For arrays/maps, own keys on the instance are enough; avoid Array.prototype.
|
|
311
|
+
if (current === Array.prototype ||
|
|
312
|
+
current === Map.prototype ||
|
|
313
|
+
current === Set.prototype) {
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return __spreadArray([], __read(keys), false);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Estimates the size of a primitive value (number, boolean, string, bigint,
|
|
321
|
+
* or symbol). Returns `0` for `null`, `undefined`, and non-primitives.
|
|
322
|
+
*
|
|
323
|
+
* @param value - Value to measure.
|
|
324
|
+
* @returns Estimated size in bytes.
|
|
325
|
+
* @internal
|
|
326
|
+
*/
|
|
327
|
+
function measurePrimitive(value) {
|
|
328
|
+
var _a;
|
|
329
|
+
if (value === null || value === undefined)
|
|
330
|
+
return 0;
|
|
331
|
+
switch (typeof value) {
|
|
332
|
+
case 'number':
|
|
333
|
+
return NUMBER_SIZE;
|
|
334
|
+
case 'boolean':
|
|
335
|
+
return BOOLEAN_SIZE;
|
|
336
|
+
case 'string':
|
|
337
|
+
return STRING_OVERHEAD + value.length * 2;
|
|
338
|
+
case 'bigint':
|
|
339
|
+
return 16;
|
|
340
|
+
case 'symbol':
|
|
341
|
+
return STRING_OVERHEAD + String((_a = value.description) !== null && _a !== void 0 ? _a : '').length * 2;
|
|
342
|
+
default:
|
|
343
|
+
return 0;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Measures only the structure of the database handle registry `Map`
|
|
348
|
+
* (header, entry slots, and key strings). Registered object values are
|
|
349
|
+
* expected to be counted via the ownership graph instead.
|
|
350
|
+
*
|
|
351
|
+
* @param state - Shared walk state.
|
|
352
|
+
* @param registry - The database `_handleRegistry` map.
|
|
353
|
+
* @returns Estimated registry overhead in bytes, or `0` if already visited.
|
|
354
|
+
* @internal
|
|
355
|
+
*/
|
|
356
|
+
function measureHandleRegistryOverhead(state, registry) {
|
|
357
|
+
var e_2, _a;
|
|
358
|
+
if (state.visited.has(registry))
|
|
359
|
+
return 0;
|
|
360
|
+
state.visited.add(registry);
|
|
361
|
+
state.objectCount += 1;
|
|
362
|
+
// Objects are counted via the ownership graph; only Map structure + keys.
|
|
363
|
+
var bytes = MAP_OVERHEAD + registry.size * MAP_ENTRY_OVERHEAD;
|
|
364
|
+
try {
|
|
365
|
+
for (var _b = __values(registry.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
366
|
+
var key = _c.value;
|
|
367
|
+
bytes += measurePrimitive(key);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
371
|
+
finally {
|
|
372
|
+
try {
|
|
373
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
374
|
+
}
|
|
375
|
+
finally { if (e_2) throw e_2.error; }
|
|
376
|
+
}
|
|
377
|
+
addBytes(state, 'handleRegistry', bytes, 1);
|
|
378
|
+
return bytes;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Recursively walks a value, attributing estimated bytes to the current
|
|
382
|
+
* category and optional entity type. Uses {@link WalkState.visited} to avoid
|
|
383
|
+
* recounting shared or cyclic references.
|
|
384
|
+
*
|
|
385
|
+
* @param state - Shared walk state.
|
|
386
|
+
* @param value - Value to measure.
|
|
387
|
+
* @param category - Ownership category for this value.
|
|
388
|
+
* @param entityType - Active entity type name when walking entity payload,
|
|
389
|
+
* or `null` when outside an entity.
|
|
390
|
+
* @returns Estimated size in bytes for this subtree (also recorded in `state`).
|
|
391
|
+
* @internal
|
|
392
|
+
*/
|
|
393
|
+
function walkValue(state, value, category, entityType) {
|
|
394
|
+
var e_3, _a, e_4, _b, e_5, _c, e_6, _d;
|
|
395
|
+
if (value === null || value === undefined)
|
|
396
|
+
return 0;
|
|
397
|
+
var valueType = typeof value;
|
|
398
|
+
if (valueType === 'function')
|
|
399
|
+
return 0;
|
|
400
|
+
if (valueType !== 'object') {
|
|
401
|
+
var bytes_1 = measurePrimitive(value);
|
|
402
|
+
addBytes(state, category, bytes_1);
|
|
403
|
+
if (entityType) {
|
|
404
|
+
var bucket = ensureBucket(state.byEntityType, entityType);
|
|
405
|
+
bucket.bytes += bytes_1;
|
|
406
|
+
}
|
|
407
|
+
return bytes_1;
|
|
408
|
+
}
|
|
409
|
+
var obj = value;
|
|
410
|
+
// DOM / host objects
|
|
411
|
+
if (typeof obj.nodeType === 'number')
|
|
412
|
+
return 0;
|
|
413
|
+
if (state.visited.has(obj))
|
|
414
|
+
return 0;
|
|
415
|
+
state.visited.add(obj);
|
|
416
|
+
state.objectCount += 1;
|
|
417
|
+
if (!state.includeEventManagers && isAcCmEventManager(obj)) {
|
|
418
|
+
addBytes(state, category, OBJECT_OVERHEAD, 1);
|
|
419
|
+
return OBJECT_OVERHEAD;
|
|
420
|
+
}
|
|
421
|
+
var localEntityType = entityType;
|
|
422
|
+
var localCategory = category;
|
|
423
|
+
var isEntity = false;
|
|
424
|
+
if (obj instanceof AcDbEntity) {
|
|
425
|
+
isEntity = true;
|
|
426
|
+
localCategory = 'entities';
|
|
427
|
+
localEntityType = obj.type;
|
|
428
|
+
state.entityCount += 1;
|
|
429
|
+
var typeBucket = ensureBucket(state.byEntityType, localEntityType);
|
|
430
|
+
typeBucket.count += 1;
|
|
431
|
+
}
|
|
432
|
+
// Promise
|
|
433
|
+
if (typeof obj.then === 'function') {
|
|
434
|
+
addBytes(state, localCategory, OBJECT_OVERHEAD, 1);
|
|
435
|
+
return OBJECT_OVERHEAD;
|
|
436
|
+
}
|
|
437
|
+
// ArrayBuffer
|
|
438
|
+
if (obj instanceof ArrayBuffer) {
|
|
439
|
+
var bytes_2 = TYPED_ARRAY_OVERHEAD + obj.byteLength;
|
|
440
|
+
addBytes(state, localCategory, bytes_2, 1);
|
|
441
|
+
if (localEntityType) {
|
|
442
|
+
ensureBucket(state.byEntityType, localEntityType).bytes += bytes_2;
|
|
443
|
+
}
|
|
444
|
+
return bytes_2;
|
|
445
|
+
}
|
|
446
|
+
// TypedArray / DataView
|
|
447
|
+
if (isTypedArray(obj)) {
|
|
448
|
+
var bytes_3 = TYPED_ARRAY_OVERHEAD + obj.byteLength;
|
|
449
|
+
// Count underlying buffer only once via visited set when shared.
|
|
450
|
+
if (obj.buffer && !state.visited.has(obj.buffer)) {
|
|
451
|
+
state.visited.add(obj.buffer);
|
|
452
|
+
}
|
|
453
|
+
addBytes(state, localCategory, bytes_3, 1);
|
|
454
|
+
if (localEntityType) {
|
|
455
|
+
ensureBucket(state.byEntityType, localEntityType).bytes += bytes_3;
|
|
456
|
+
}
|
|
457
|
+
return bytes_3;
|
|
458
|
+
}
|
|
459
|
+
// Blob
|
|
460
|
+
if (typeof Blob !== 'undefined' && obj instanceof Blob) {
|
|
461
|
+
var bytes_4 = BLOB_OVERHEAD + obj.size;
|
|
462
|
+
addBytes(state, localCategory, bytes_4, 1);
|
|
463
|
+
if (localEntityType) {
|
|
464
|
+
ensureBucket(state.byEntityType, localEntityType).bytes += bytes_4;
|
|
465
|
+
}
|
|
466
|
+
return bytes_4;
|
|
467
|
+
}
|
|
468
|
+
// Date
|
|
469
|
+
if (obj instanceof Date) {
|
|
470
|
+
var bytes_5 = OBJECT_OVERHEAD + 8;
|
|
471
|
+
addBytes(state, localCategory, bytes_5, 1);
|
|
472
|
+
return bytes_5;
|
|
473
|
+
}
|
|
474
|
+
// Map — special-case handle registry values (already counted via ownership)
|
|
475
|
+
if (obj instanceof Map) {
|
|
476
|
+
var isHandleRegistry = localCategory === 'handleRegistry';
|
|
477
|
+
var structureBytes = MAP_OVERHEAD + obj.size * MAP_ENTRY_OVERHEAD;
|
|
478
|
+
var bytes_6 = structureBytes;
|
|
479
|
+
addBytes(state, localCategory, structureBytes, 1);
|
|
480
|
+
if (localEntityType) {
|
|
481
|
+
ensureBucket(state.byEntityType, localEntityType).bytes += structureBytes;
|
|
482
|
+
}
|
|
483
|
+
try {
|
|
484
|
+
for (var obj_1 = __values(obj), obj_1_1 = obj_1.next(); !obj_1_1.done; obj_1_1 = obj_1.next()) {
|
|
485
|
+
var _e = __read(obj_1_1.value, 2), k = _e[0], v = _e[1];
|
|
486
|
+
bytes_6 += walkValue(state, k, localCategory, localEntityType);
|
|
487
|
+
if (!isHandleRegistry) {
|
|
488
|
+
bytes_6 += walkValue(state, v, localCategory, localEntityType);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
493
|
+
finally {
|
|
494
|
+
try {
|
|
495
|
+
if (obj_1_1 && !obj_1_1.done && (_a = obj_1.return)) _a.call(obj_1);
|
|
496
|
+
}
|
|
497
|
+
finally { if (e_3) throw e_3.error; }
|
|
498
|
+
}
|
|
499
|
+
return bytes_6;
|
|
500
|
+
}
|
|
501
|
+
// Set
|
|
502
|
+
if (obj instanceof Set) {
|
|
503
|
+
var bytes_7 = SET_OVERHEAD + obj.size * SET_ENTRY_OVERHEAD;
|
|
504
|
+
try {
|
|
505
|
+
for (var obj_2 = __values(obj), obj_2_1 = obj_2.next(); !obj_2_1.done; obj_2_1 = obj_2.next()) {
|
|
506
|
+
var item = obj_2_1.value;
|
|
507
|
+
bytes_7 += walkValue(state, item, localCategory, localEntityType);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
511
|
+
finally {
|
|
512
|
+
try {
|
|
513
|
+
if (obj_2_1 && !obj_2_1.done && (_b = obj_2.return)) _b.call(obj_2);
|
|
514
|
+
}
|
|
515
|
+
finally { if (e_4) throw e_4.error; }
|
|
516
|
+
}
|
|
517
|
+
addBytes(state, localCategory, SET_OVERHEAD + obj.size * SET_ENTRY_OVERHEAD, 1);
|
|
518
|
+
if (localEntityType) {
|
|
519
|
+
ensureBucket(state.byEntityType, localEntityType).bytes +=
|
|
520
|
+
SET_OVERHEAD + obj.size * SET_ENTRY_OVERHEAD;
|
|
521
|
+
}
|
|
522
|
+
return bytes_7;
|
|
523
|
+
}
|
|
524
|
+
// Array
|
|
525
|
+
if (Array.isArray(obj)) {
|
|
526
|
+
var bytes_8 = ARRAY_OVERHEAD + obj.length * POINTER_SIZE;
|
|
527
|
+
addBytes(state, localCategory, bytes_8, 1);
|
|
528
|
+
if (localEntityType) {
|
|
529
|
+
ensureBucket(state.byEntityType, localEntityType).bytes += bytes_8;
|
|
530
|
+
}
|
|
531
|
+
for (var i = 0; i < obj.length; i++) {
|
|
532
|
+
var child = obj[i];
|
|
533
|
+
var childCategory = resolveChildCategory(localCategory, String(i), child);
|
|
534
|
+
bytes_8 += walkValue(state, child, childCategory, localEntityType);
|
|
535
|
+
}
|
|
536
|
+
return bytes_8;
|
|
537
|
+
}
|
|
538
|
+
// Generic object / class instance
|
|
539
|
+
var bytes = OBJECT_OVERHEAD;
|
|
540
|
+
var keys = isPlainObject(obj)
|
|
541
|
+
? Object.getOwnPropertyNames(obj)
|
|
542
|
+
: collectInstanceKeys(obj);
|
|
543
|
+
try {
|
|
544
|
+
// Property name strings + pointer slots
|
|
545
|
+
for (var keys_1 = __values(keys), keys_1_1 = keys_1.next(); !keys_1_1.done; keys_1_1 = keys_1.next()) {
|
|
546
|
+
var key = keys_1_1.value;
|
|
547
|
+
bytes += POINTER_SIZE;
|
|
548
|
+
// Hidden class / property name cost amortized; count key string once lightly
|
|
549
|
+
bytes += Math.min(STRING_OVERHEAD + key.length * 2, 64);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
553
|
+
finally {
|
|
554
|
+
try {
|
|
555
|
+
if (keys_1_1 && !keys_1_1.done && (_c = keys_1.return)) _c.call(keys_1);
|
|
556
|
+
}
|
|
557
|
+
finally { if (e_5) throw e_5.error; }
|
|
558
|
+
}
|
|
559
|
+
addBytes(state, localCategory, bytes, 1);
|
|
560
|
+
if (localEntityType) {
|
|
561
|
+
ensureBucket(state.byEntityType, localEntityType).bytes += bytes;
|
|
562
|
+
}
|
|
563
|
+
if (isEntity) {
|
|
564
|
+
// Entity count already incremented; category count for entities tracks objects
|
|
565
|
+
}
|
|
566
|
+
try {
|
|
567
|
+
for (var keys_2 = __values(keys), keys_2_1 = keys_2.next(); !keys_2_1.done; keys_2_1 = keys_2.next()) {
|
|
568
|
+
var key = keys_2_1.value;
|
|
569
|
+
if (shouldSkipProperty(state, key, localCategory))
|
|
570
|
+
continue;
|
|
571
|
+
// Avoid walking back to owning database through private refs (cycle).
|
|
572
|
+
if (key === '_database' || key === 'database')
|
|
573
|
+
continue;
|
|
574
|
+
var child = void 0;
|
|
575
|
+
try {
|
|
576
|
+
child = obj[key];
|
|
577
|
+
}
|
|
578
|
+
catch (_f) {
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
if (typeof child === 'function')
|
|
582
|
+
continue;
|
|
583
|
+
// Dedicated handle-registry path: structure only
|
|
584
|
+
if (key === '_handleRegistry' && child instanceof Map) {
|
|
585
|
+
bytes += measureHandleRegistryOverhead(state, child);
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
var childCategory = resolveChildCategory(localCategory, key, child);
|
|
589
|
+
if (!state.includeTransactionManager &&
|
|
590
|
+
childCategory === 'transaction') {
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
if (!state.includeEventManagers && childCategory === 'events') {
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
bytes += walkValue(state, child, childCategory, localEntityType);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
600
|
+
finally {
|
|
601
|
+
try {
|
|
602
|
+
if (keys_2_1 && !keys_2_1.done && (_d = keys_2.return)) _d.call(keys_2);
|
|
603
|
+
}
|
|
604
|
+
finally { if (e_6) throw e_6.error; }
|
|
605
|
+
}
|
|
606
|
+
return bytes;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Estimates the in-memory footprint of an {@link AcDbDatabase} by walking its
|
|
610
|
+
* ownership graph and applying V8-inspired size heuristics.
|
|
611
|
+
*
|
|
612
|
+
* The estimate is reproducible and suitable for comparing drawings. It is not
|
|
613
|
+
* an exact Chrome / V8 heap retained size; expect roughly ±20–30% versus
|
|
614
|
+
* DevTools heap snapshots. Rendering GPU buffers and converter worker / WASM
|
|
615
|
+
* heaps are not included.
|
|
616
|
+
*
|
|
617
|
+
* @param db - Drawing database to measure (typically after `read` / `openUri`).
|
|
618
|
+
* @param options - Optional inclusion of transaction / event graphs.
|
|
619
|
+
* @returns Structured estimate with category and entity-type breakdowns.
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* ```typescript
|
|
623
|
+
* const report = acdbEstimateDatabaseMemory(database)
|
|
624
|
+
* console.log(acdbFormatMemoryEstimate(report))
|
|
625
|
+
* ```
|
|
626
|
+
*/
|
|
627
|
+
export function acdbEstimateDatabaseMemory(db, options) {
|
|
628
|
+
var e_7, _a, e_8, _b;
|
|
629
|
+
var state = {
|
|
630
|
+
visited: new WeakSet(),
|
|
631
|
+
objectCount: 0,
|
|
632
|
+
entityCount: 0,
|
|
633
|
+
byCategory: new Map(),
|
|
634
|
+
byEntityType: new Map(),
|
|
635
|
+
includeTransactionManager: (options === null || options === void 0 ? void 0 : options.includeTransactionManager) === true,
|
|
636
|
+
includeEventManagers: (options === null || options === void 0 ? void 0 : options.includeEventManagers) === true
|
|
637
|
+
};
|
|
638
|
+
// Root walk starts as sysvars for db-owned scalars; tables/objects keys
|
|
639
|
+
// reclassify via resolveChildCategory.
|
|
640
|
+
walkValue(state, db, 'sysvars', null);
|
|
641
|
+
var totalBytes = 0;
|
|
642
|
+
var byCategory = {};
|
|
643
|
+
try {
|
|
644
|
+
for (var _c = __values(state.byCategory), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
645
|
+
var _e = __read(_d.value, 2), key = _e[0], bucket = _e[1];
|
|
646
|
+
byCategory[key] = { bytes: bucket.bytes, count: bucket.count };
|
|
647
|
+
totalBytes += bucket.bytes;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
catch (e_7_1) { e_7 = { error: e_7_1 }; }
|
|
651
|
+
finally {
|
|
652
|
+
try {
|
|
653
|
+
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
654
|
+
}
|
|
655
|
+
finally { if (e_7) throw e_7.error; }
|
|
656
|
+
}
|
|
657
|
+
var byEntityType = {};
|
|
658
|
+
try {
|
|
659
|
+
for (var _f = __values(state.byEntityType), _g = _f.next(); !_g.done; _g = _f.next()) {
|
|
660
|
+
var _h = __read(_g.value, 2), key = _h[0], bucket = _h[1];
|
|
661
|
+
byEntityType[key] = { bytes: bucket.bytes, count: bucket.count };
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
catch (e_8_1) { e_8 = { error: e_8_1 }; }
|
|
665
|
+
finally {
|
|
666
|
+
try {
|
|
667
|
+
if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
|
|
668
|
+
}
|
|
669
|
+
finally { if (e_8) throw e_8.error; }
|
|
670
|
+
}
|
|
671
|
+
return {
|
|
672
|
+
totalBytes: totalBytes,
|
|
673
|
+
objectCount: state.objectCount,
|
|
674
|
+
entityCount: state.entityCount,
|
|
675
|
+
byCategory: byCategory,
|
|
676
|
+
byEntityType: byEntityType
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Formats a byte count as a short human-readable string using binary units
|
|
681
|
+
* (`B`, `KiB`, or `MiB`).
|
|
682
|
+
*
|
|
683
|
+
* @param bytes - Non-negative byte count to format.
|
|
684
|
+
* @returns Formatted size string, for example `"512 B"` or `"2.00 KiB"`.
|
|
685
|
+
*
|
|
686
|
+
* @example
|
|
687
|
+
* ```typescript
|
|
688
|
+
* acdbFormatMemoryBytes(512) // "512 B"
|
|
689
|
+
* acdbFormatMemoryBytes(2048) // "2.00 KiB"
|
|
690
|
+
* ```
|
|
691
|
+
*/
|
|
692
|
+
export function acdbFormatMemoryBytes(bytes) {
|
|
693
|
+
if (bytes < 1024)
|
|
694
|
+
return "".concat(bytes, " B");
|
|
695
|
+
if (bytes < 1024 * 1024)
|
|
696
|
+
return "".concat((bytes / 1024).toFixed(2), " KiB");
|
|
697
|
+
return "".concat((bytes / (1024 * 1024)).toFixed(2), " MiB");
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Formats an {@link AcDbMemoryEstimate} as multi-line text for console or UI
|
|
701
|
+
* output, including totals plus category and entity-type breakdowns sorted by
|
|
702
|
+
* descending byte size.
|
|
703
|
+
*
|
|
704
|
+
* @param report - Estimate produced by {@link acdbEstimateDatabaseMemory}.
|
|
705
|
+
* @returns Human-readable multi-line summary string.
|
|
706
|
+
*
|
|
707
|
+
* @example
|
|
708
|
+
* ```typescript
|
|
709
|
+
* const report = acdbEstimateDatabaseMemory(database)
|
|
710
|
+
* console.log(acdbFormatMemoryEstimate(report))
|
|
711
|
+
* ```
|
|
712
|
+
*/
|
|
713
|
+
export function acdbFormatMemoryEstimate(report) {
|
|
714
|
+
var e_9, _a, e_10, _b;
|
|
715
|
+
var lines = [
|
|
716
|
+
"AcDbDatabase memory estimate: ".concat(acdbFormatMemoryBytes(report.totalBytes), " (").concat(report.totalBytes, " bytes)"),
|
|
717
|
+
"Objects: ".concat(report.objectCount, ", Entities: ").concat(report.entityCount),
|
|
718
|
+
'By category:'
|
|
719
|
+
];
|
|
720
|
+
var categories = Object.entries(report.byCategory).sort(function (a, b) { return b[1].bytes - a[1].bytes; });
|
|
721
|
+
try {
|
|
722
|
+
for (var categories_1 = __values(categories), categories_1_1 = categories_1.next(); !categories_1_1.done; categories_1_1 = categories_1.next()) {
|
|
723
|
+
var _c = __read(categories_1_1.value, 2), name_1 = _c[0], bucket = _c[1];
|
|
724
|
+
lines.push(" ".concat(name_1, ": ").concat(acdbFormatMemoryBytes(bucket.bytes), " (").concat(bucket.bytes, " bytes), count=").concat(bucket.count));
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
catch (e_9_1) { e_9 = { error: e_9_1 }; }
|
|
728
|
+
finally {
|
|
729
|
+
try {
|
|
730
|
+
if (categories_1_1 && !categories_1_1.done && (_a = categories_1.return)) _a.call(categories_1);
|
|
731
|
+
}
|
|
732
|
+
finally { if (e_9) throw e_9.error; }
|
|
733
|
+
}
|
|
734
|
+
var entityTypes = Object.entries(report.byEntityType).sort(function (a, b) { return b[1].bytes - a[1].bytes; });
|
|
735
|
+
if (entityTypes.length > 0) {
|
|
736
|
+
lines.push('By entity type:');
|
|
737
|
+
try {
|
|
738
|
+
for (var entityTypes_1 = __values(entityTypes), entityTypes_1_1 = entityTypes_1.next(); !entityTypes_1_1.done; entityTypes_1_1 = entityTypes_1.next()) {
|
|
739
|
+
var _d = __read(entityTypes_1_1.value, 2), name_2 = _d[0], bucket = _d[1];
|
|
740
|
+
lines.push(" ".concat(name_2, ": ").concat(acdbFormatMemoryBytes(bucket.bytes), " (").concat(bucket.bytes, " bytes), count=").concat(bucket.count));
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
catch (e_10_1) { e_10 = { error: e_10_1 }; }
|
|
744
|
+
finally {
|
|
745
|
+
try {
|
|
746
|
+
if (entityTypes_1_1 && !entityTypes_1_1.done && (_b = entityTypes_1.return)) _b.call(entityTypes_1);
|
|
747
|
+
}
|
|
748
|
+
finally { if (e_10) throw e_10.error; }
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return lines.join('\n');
|
|
752
|
+
}
|
|
753
|
+
//# sourceMappingURL=AcDbMemoryEstimator.js.map
|