@bldrs-ai/conway 1.563.1540 → 1.566.1541

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.
@@ -30,7 +30,7 @@ var import_node_process = require("node:process");
30
30
  var readline = __toESM(require("node:readline"), 1);
31
31
 
32
32
  // compiled/src/version/version.js
33
- var versionString = "Conway v1.563.1540";
33
+ var versionString = "Conway v1.566.1541";
34
34
 
35
35
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
36
36
  var wasmType = "";
@@ -14965,7 +14965,7 @@ ${t5.join("\n")}` : "";
14965
14965
  var import_process = require("process");
14966
14966
 
14967
14967
  // compiled/src/version/version.js
14968
- var versionString = "Conway v1.563.1540";
14968
+ var versionString = "Conway v1.566.1541";
14969
14969
 
14970
14970
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
14971
14971
  function pThreadsAllowed() {
@@ -89338,6 +89338,9 @@ var FACES_FIELD_DEPTH = 4;
89338
89338
  var REL_AGGREGATES_RELATED_OFFSET = 5;
89339
89339
  var REL_AGGREGATES_RELATED_BASE = 4;
89340
89340
  var REL_AGGREGATES_RELATED_DEPTH = 3;
89341
+ var REL_AGGREGATES_RELATING_OFFSET = 4;
89342
+ var REL_AGGREGATES_RELATING_BASE = 4;
89343
+ var REL_AGGREGATES_RELATING_DEPTH = 3;
89341
89344
  var REL_ASSOCIATES_RELATED_OFFSET = 4;
89342
89345
  var REL_ASSOCIATES_RELATED_BASE = 4;
89343
89346
  var REL_ASSOCIATES_RELATED_DEPTH = 2;
@@ -94031,7 +94034,16 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
94031
94034
  * acquire: the relationship, the relating product (and its voids)
94032
94035
  * and every related product.
94033
94036
  *
94037
+ * The whole relationship at once, which is what a caller that extracts
94038
+ * it in one synchronous call needs. A caller that steps the
94039
+ * relationship (the demand pump, through
94040
+ * {@link extractRelAggregateGeometryIncremental}) wants
94041
+ * {@link beginAggregateExtract} instead: this one pins every related
94042
+ * product's closure simultaneously, which on an aggregate-structured
94043
+ * model is the whole file (conway#561 §5).
94044
+ *
94034
94045
  * @param relAggregate The relationship to prefetch.
94046
+ * @param leafSpans Coalesced Faces[] pin ranges — caller unpins.
94035
94047
  * @return {Promise<Set<number>>} Pinned local IDs — caller must unpin
94036
94048
  * after extract.
94037
94049
  */
@@ -94040,11 +94052,163 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
94040
94052
  return /* @__PURE__ */ new Set();
94041
94053
  }
94042
94054
  const pinned = /* @__PURE__ */ new Set();
94043
- const hop = [];
94055
+ await this.ensureResidentForAggregateBase(relAggregate, pinned, leafSpans);
94056
+ const products = this.relatedAggregateProductLocalIDs(relAggregate);
94057
+ if (products === void 0) {
94058
+ await this.ensureResidentForRelatedObjectsByGetter(relAggregate, pinned, leafSpans);
94059
+ return pinned;
94060
+ }
94061
+ await this.ensureResidentForAggregateProducts(products, 0, products.length, pinned, leafSpans);
94062
+ return pinned;
94063
+ }
94064
+ /**
94065
+ * The part of an aggregate prefetch that has to be resident for the
94066
+ * WHOLE relationship: the relationship record itself and the relating
94067
+ * product's closure (its rel-voids become the master override every
94068
+ * related product is cut with).
94069
+ *
94070
+ * Only the RELATING object's record is paged ahead of the getter that
94071
+ * hydrates it, deliberately — not the relationship's whole 1-hop, which
94072
+ * is what this used to do. On a model whose products are all aggregate
94073
+ * targets the 1-hop is every related product's record, scattered the
94074
+ * length of the file, so pinning it pins essentially every chunk before
94075
+ * a single mesh exists: 384 MiB held against a 64 MiB window on
94076
+ * SKYLARK250 (conway#561 §5). The related records are paged by the
94077
+ * caller instead, per product or per wave.
94078
+ *
94079
+ * Seam for {@link AggregateExtractPager}, which lives in this module.
94080
+ *
94081
+ * @param relAggregate The relationship to prefetch.
94082
+ * @param pinned Set to extend — caller unpins.
94083
+ * @param leafSpans Coalesced Faces[] pin ranges — caller unpins.
94084
+ * @return {Promise<void>} Resolves when the base is resident.
94085
+ */
94086
+ async ensureResidentForAggregateBase(relAggregate, pinned, leafSpans) {
94087
+ if (!this.model.isSourceExternal) {
94088
+ return;
94089
+ }
94044
94090
  this.model.pinByLocalID(relAggregate.localID);
94045
94091
  pinned.add(relAggregate.localID);
94092
+ await this.model.ensureResidentByLocalID(relAggregate.localID);
94093
+ const relatingLocalID = relAggregate.extractReferenceLocalID(REL_AGGREGATES_RELATING_OFFSET, REL_AGGREGATES_RELATING_BASE, REL_AGGREGATES_RELATING_DEPTH, true);
94094
+ if (relatingLocalID !== null) {
94095
+ this.model.pinByLocalID(relatingLocalID);
94096
+ await this.model.ensureResidentByLocalID(relatingLocalID);
94097
+ }
94098
+ try {
94099
+ const relating = relAggregate.RelatingObject;
94100
+ if (relating !== null && relating !== void 0) {
94101
+ await this.ensureResidentForProductExtract(relating.localID, pinned, leafSpans);
94102
+ }
94103
+ } finally {
94104
+ if (relatingLocalID !== null) {
94105
+ this.model.unpinByLocalID(relatingLocalID);
94106
+ }
94107
+ }
94108
+ }
94109
+ /**
94110
+ * The local IDs one relationship's aggregates pass will actually extract:
94111
+ * its RelatedObjects that are `IfcProduct`s, in record order.
94112
+ *
94113
+ * The n-th entry is the product
94114
+ * {@link extractRelAggregateGeometryIncremental} extracts for its n-th
94115
+ * yield — that pass materialises every related object, extracts and
94116
+ * yields for the ones that are products, and walks past the rest. So a
94117
+ * prefetch keyed on this list is in exact lockstep with the stepper, and
94118
+ * a run of non-products between two products costs it nothing.
94119
+ *
94120
+ * **Non-products are dropped, not skipped-but-paged.** Deciding an entry
94121
+ * is not a product costs no source bytes: `getTypedElementByExpressID`
94122
+ * builds its descriptor from the columns, and only
94123
+ * {@link extractProductGeometry} — products only — reads a record. Swept
94124
+ * that exact path (materialise as `IfcObjectDefinition`, test
94125
+ * `instanceof IfcProduct`) over every record of SKYLARK250 (7,818,778),
94126
+ * SEESTRASSE (294,704) and the whole in-repo corpus behind a deliberately
94127
+ * exhausted 4 KiB x 4 window: 0 throws, 0 store bytes read. Paging a
94128
+ * non-product's closure is therefore work that serves nothing — and it is
94129
+ * unbounded work, because a wave that had to span a run of them would
94130
+ * page the whole run at once, `waveSize` notwithstanding (conway#566
94131
+ * review). An `IfcTypeObject` carrying `RepresentationMaps` measures
94132
+ * 1,607 records of closure on its own.
94133
+ *
94134
+ * Classification goes through {@link relatedProductByExpressID_}, the same
94135
+ * call the pass itself makes — one test rather than two that have to
94136
+ * agree. A typeID-column test does NOT agree: a STEP complex instance is
94137
+ * recorded as type 0 (`EXTERNALMAPPINGCONTAINER`) while the pass finds the
94138
+ * `IfcProduct` among its `multiMapping` variants, and the product would
94139
+ * then be extracted without ever being paged (conway#566 review).
94140
+ *
94141
+ * Note {@link aggregateTargetLocalIDs} still reads the column, and has the
94142
+ * same blind spot — a complex product is not deferred, so it is extracted
94143
+ * by both passes. That is pre-existing and independent of paging: it costs
94144
+ * a duplicate extraction, not a non-resident read.
94145
+ *
94146
+ * Seam for {@link AggregateExtractPager}, which lives in this module.
94147
+ *
94148
+ * @param relAggregate The relationship to read.
94149
+ * @return {number[] | undefined} The related products' local IDs, or
94150
+ * undefined when the list holds something only the generated getter can
94151
+ * resolve (see {@link relatedObjectExpressIDs_}).
94152
+ */
94153
+ relatedAggregateProductLocalIDs(relAggregate) {
94154
+ const relatedExpressIDs = this.relatedObjectExpressIDs_(relAggregate);
94155
+ if (relatedExpressIDs === void 0) {
94156
+ return void 0;
94157
+ }
94158
+ const productLocalIDs = [];
94159
+ for (const relatedExpressID of relatedExpressIDs) {
94160
+ let relatedProduct;
94161
+ try {
94162
+ relatedProduct = this.relatedProductByExpressID_(relatedExpressID);
94163
+ } catch {
94164
+ break;
94165
+ }
94166
+ if (relatedProduct !== void 0) {
94167
+ productLocalIDs.push(relatedProduct.localID);
94168
+ }
94169
+ }
94170
+ return productLocalIDs;
94171
+ }
94172
+ /**
94173
+ * Page the closures of a contiguous run of
94174
+ * {@link relatedAggregateProductLocalIDs} entries.
94175
+ *
94176
+ * Seam for {@link AggregateExtractPager}, which lives in this module.
94177
+ *
94178
+ * @param productLocalIDs The related products, in record order.
94179
+ * @param from First index to page.
94180
+ * @param to One past the last index to page.
94181
+ * @param pinned Set to extend — caller unpins.
94182
+ * @param leafSpans Coalesced Faces[] pin ranges — caller unpins.
94183
+ * @return {Promise<void>} Resolves when the run is resident.
94184
+ */
94185
+ async ensureResidentForAggregateProducts(productLocalIDs, from, to, pinned, leafSpans) {
94186
+ for (let where = from; where < to; ++where) {
94187
+ await this.ensureResidentForProductExtract(productLocalIDs[where], pinned, leafSpans);
94188
+ }
94189
+ }
94190
+ /**
94191
+ * Whole-relationship prefetch for a RelatedObjects list that
94192
+ * {@link relatedAggregateProductLocalIDs} could not read as references — an
94193
+ * inline entity, `$` or junk.
94194
+ *
94195
+ * Only the generated getter can resolve (or reject) such a list, and it
94196
+ * materialises the whole array at once, so there is no per-entry cursor
94197
+ * to page against: this path keeps the pre-#561 shape, whole 1-hop and
94198
+ * all, because it is the one case that genuinely cannot be paged
94199
+ * incrementally. It is also the path that needs the 1-hop pinned — the
94200
+ * getter reads every related record while it materialises them.
94201
+ *
94202
+ * Seam for {@link AggregateExtractPager}, which lives in this module.
94203
+ *
94204
+ * @param relAggregate The relationship to prefetch.
94205
+ * @param pinned Set to extend — caller unpins.
94206
+ * @param leafSpans Coalesced Faces[] pin ranges — caller unpins.
94207
+ * @return {Promise<void>} Resolves when the relationship is resident.
94208
+ */
94209
+ async ensureResidentForRelatedObjectsByGetter(relAggregate, pinned, leafSpans) {
94210
+ const hop = [];
94046
94211
  try {
94047
- await this.model.ensureResidentByLocalID(relAggregate.localID);
94048
94212
  for (const expressID of this.model.referencedExpressIDs(relAggregate.localID)) {
94049
94213
  const localID = this.model.resolveExpressID(expressID);
94050
94214
  if (localID === void 0 || pinned.has(localID)) {
@@ -94054,34 +94218,37 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
94054
94218
  hop.push(localID);
94055
94219
  await this.model.ensureResidentByLocalID(localID);
94056
94220
  }
94057
- const relating = relAggregate.RelatingObject;
94058
- if (relating !== null && relating !== void 0) {
94059
- await this.ensureResidentForProductExtract(relating.localID, pinned, leafSpans);
94060
- }
94061
- const relatedExpressIDs = this.relatedObjectExpressIDs_(relAggregate);
94062
- if (relatedExpressIDs === void 0) {
94063
- const related = relAggregate.RelatedObjects;
94064
- if (related !== null && related !== void 0) {
94065
- for (const product of related) {
94066
- await this.ensureResidentForProductExtract(product.localID, pinned, leafSpans);
94067
- }
94068
- }
94069
- } else {
94070
- for (const relatedExpressID of relatedExpressIDs) {
94071
- const relatedLocalID = this.model.resolveExpressID(relatedExpressID);
94072
- if (relatedLocalID === void 0) {
94073
- continue;
94074
- }
94075
- await this.ensureResidentForProductExtract(relatedLocalID, pinned, leafSpans);
94221
+ const related = relAggregate.RelatedObjects;
94222
+ if (related !== null && related !== void 0) {
94223
+ for (const product of related) {
94224
+ await this.ensureResidentForProductExtract(product.localID, pinned, leafSpans);
94076
94225
  }
94077
94226
  }
94078
- return pinned;
94079
94227
  } finally {
94080
94228
  for (const localID of hop) {
94081
94229
  this.model.unpinByLocalID(localID);
94082
94230
  }
94083
94231
  }
94084
94232
  }
94233
+ /**
94234
+ * Begin a WAVE-PAGED residency for one relationship, for a caller that
94235
+ * steps it through {@link extractRelAggregateGeometryIncremental}.
94236
+ *
94237
+ * The windowed twin of {@link ensureResidentForAggregateExtract}: same
94238
+ * records, paged a wave at a time as the stepper reaches them and
94239
+ * released a wave at a time behind it, instead of all of them before the
94240
+ * first step. See {@link AggregateExtractPager}.
94241
+ *
94242
+ * @param relAggregate The relationship to prefetch.
94243
+ * @param waveSize Related products paged and held at once.
94244
+ * @return {Promise<AggregateExtractPager>} The paging handle — caller
94245
+ * must {@link AggregateExtractPager.release} it.
94246
+ */
94247
+ async beginAggregateExtract(relAggregate, waveSize = _IfcGeometryExtraction.AGGREGATE_PREFETCH_WAVE_SIZE_) {
94248
+ const pager = new AggregateExtractPager(this, relAggregate, waveSize);
94249
+ await pager.begin();
94250
+ return pager;
94251
+ }
94085
94252
  /**
94086
94253
  * The whole-model walk's SECOND product pass, shared with the demand
94087
94254
  * pump: for every IfcRelAggregates, re-extract the related products
@@ -94140,6 +94307,47 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
94140
94307
  });
94141
94308
  return allReferences ? expressIDs : void 0;
94142
94309
  }
94310
+ /**
94311
+ * How the rel-aggregates pass classifies ONE `RelatedObjects` entry: the
94312
+ * product it will extract, or undefined for an entry it walks past.
94313
+ *
94314
+ * **The single definition of "is this related object a product".** Both
94315
+ * the pass itself ({@link extractRelAggregateGeometryIncremental}) and the
94316
+ * prefetch that has to page ahead of it
94317
+ * ({@link relatedAggregateProductLocalIDs}) go through here, so they
94318
+ * cannot disagree — which they did, twice, when the prefetch derived its
94319
+ * own answer from the typeID column. A STEP complex/external-mapping
94320
+ * instance is the case that breaks a column test: the parser records the
94321
+ * container as type 0 (`EXTERNALMAPPINGCONTAINER`, see step_parser.ts)
94322
+ * while `getTypedElementByExpressID` searches the entry's `multiMapping`
94323
+ * variants and hands back the `IfcProduct` among them. On a windowed
94324
+ * source a prefetch that missed one would leave the pass reading a
94325
+ * non-resident record, and its permissive catch abandons the REST of the
94326
+ * relationship — geometry lost with a log line, not an error
94327
+ * (conway#566 review).
94328
+ *
94329
+ * Materialising the entry is what makes the two agree, and it is cheap:
94330
+ * `getTypedElementByExpressID` builds from the columns and reads no
94331
+ * source bytes. Measured by sweeping this exact call over every record of
94332
+ * SKYLARK250 (7,818,778), SEESTRASSE (294,704) and the in-repo corpus
94333
+ * behind a deliberately exhausted 4 KiB x 4 window — 0 throws, 0 store
94334
+ * bytes. The pass materialises every entry anyway; the prefetch just
94335
+ * reaches them first.
94336
+ *
94337
+ * @param relatedExpressID The RelatedObjects entry to classify.
94338
+ * @throws {Error} When the reference resolves to nothing, or to something
94339
+ * that is not an `IfcObjectDefinition` — what the generated getter throws
94340
+ * for the same entry, and what the pass has always thrown here.
94341
+ * @return {IfcProduct | undefined} The product to extract, or undefined
94342
+ * for a related object that is not one.
94343
+ */
94344
+ relatedProductByExpressID_(relatedExpressID) {
94345
+ const relatedObject = this.model.getTypedElementByExpressID(relatedExpressID, IfcObjectDefinition);
94346
+ if (relatedObject === void 0) {
94347
+ throw new Error("Value in STEP was incorrectly typed");
94348
+ }
94349
+ return relatedObject instanceof IfcProduct ? relatedObject : void 0;
94350
+ }
94143
94351
  /**
94144
94352
  * Extract one IfcRelAggregates' related products with the relating
94145
94353
  * object's ("master") rel-voids — the shared per-item body of the
@@ -94199,12 +94407,9 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
94199
94407
  }
94200
94408
  } else {
94201
94409
  for (const relatedExpressID of relatedExpressIDs) {
94202
- const relatedObject = this.model.getTypedElementByExpressID(relatedExpressID, IfcObjectDefinition);
94203
- if (relatedObject === void 0) {
94204
- throw new Error("Value in STEP was incorrectly typed");
94205
- }
94206
- if (relatedObject instanceof IfcProduct) {
94207
- this.extractProductGeometry(relatedObject, masterRelVoids);
94410
+ const relatedProduct = this.relatedProductByExpressID_(relatedExpressID);
94411
+ if (relatedProduct !== void 0) {
94412
+ this.extractProductGeometry(relatedProduct, masterRelVoids);
94208
94413
  yield ++extractedCount;
94209
94414
  }
94210
94415
  }
@@ -94476,6 +94681,98 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
94476
94681
  }
94477
94682
  };
94478
94683
  IfcGeometryExtraction.AGGREGATE_TARGET_WAVE_SIZE_ = 512;
94684
+ IfcGeometryExtraction.AGGREGATE_PREFETCH_WAVE_SIZE_ = 8;
94685
+ var AggregateExtractPager = class {
94686
+ /**
94687
+ * Construct paging for one relationship.
94688
+ *
94689
+ * @param extraction_ The extraction whose model is being paged.
94690
+ * @param relAggregate_ The relationship this pages for.
94691
+ * @param waveSize Related products paged and held at once.
94692
+ */
94693
+ constructor(extraction_, relAggregate_, waveSize) {
94694
+ this.extraction_ = extraction_;
94695
+ this.relAggregate_ = relAggregate_;
94696
+ this.basePins_ = /* @__PURE__ */ new Set();
94697
+ this.baseSpans_ = [];
94698
+ this.wavePins_ = /* @__PURE__ */ new Set();
94699
+ this.waveSpans_ = [];
94700
+ this.waveStart_ = 0;
94701
+ this.pagedThrough_ = 0;
94702
+ this.released_ = false;
94703
+ this.waveSize_ = Math.max(1, Math.floor(waveSize));
94704
+ }
94705
+ /**
94706
+ * Page what has to be resident for every step of this relationship.
94707
+ *
94708
+ * @return {Promise<void>} Resolves when the base is resident.
94709
+ */
94710
+ async begin() {
94711
+ if (!this.extraction_.model.isSourceExternal) {
94712
+ return;
94713
+ }
94714
+ await this.extraction_.ensureResidentForAggregateBase(this.relAggregate_, this.basePins_, this.baseSpans_);
94715
+ this.products_ = this.extraction_.relatedAggregateProductLocalIDs(this.relAggregate_);
94716
+ if (this.products_ !== void 0) {
94717
+ return;
94718
+ }
94719
+ await this.extraction_.ensureResidentForRelatedObjectsByGetter(this.relAggregate_, this.basePins_, this.baseSpans_);
94720
+ }
94721
+ /**
94722
+ * Make the product the stepper extracts for yield `step` resident,
94723
+ * rolling the wave forward if it does not already cover it.
94724
+ *
94725
+ * At most `waveSize` product closures are pinned at any moment, whatever
94726
+ * the related-object list holds between them.
94727
+ *
94728
+ * @param step Zero-based index of the stepper's next yield.
94729
+ * @return {Promise<void>} Resolves when that product is resident.
94730
+ */
94731
+ async ensureForStep(step) {
94732
+ const products = this.products_;
94733
+ if (products === void 0 || step >= products.length) {
94734
+ return;
94735
+ }
94736
+ if (step < this.pagedThrough_) {
94737
+ return;
94738
+ }
94739
+ this.releaseWave_();
94740
+ this.waveStart_ = step;
94741
+ this.pagedThrough_ = Math.min(products.length, step + this.waveSize_);
94742
+ await this.extraction_.ensureResidentForAggregateProducts(products, this.waveStart_, this.pagedThrough_, this.wavePins_, this.waveSpans_);
94743
+ }
94744
+ /**
94745
+ * Drop every pin this holds. Idempotent.
94746
+ */
94747
+ release() {
94748
+ if (this.released_) {
94749
+ return;
94750
+ }
94751
+ this.released_ = true;
94752
+ this.releaseWave_();
94753
+ const model = this.extraction_.model;
94754
+ model.releaseSourceViews(this.basePins_);
94755
+ model.unpinLocalIDs(this.basePins_);
94756
+ this.basePins_.clear();
94757
+ for (const span of this.baseSpans_) {
94758
+ model.unpinAddressRange(span.address, span.length);
94759
+ }
94760
+ this.baseSpans_.length = 0;
94761
+ }
94762
+ /**
94763
+ * Drop the current wave's pins and views.
94764
+ */
94765
+ releaseWave_() {
94766
+ const model = this.extraction_.model;
94767
+ model.releaseSourceViews(this.wavePins_);
94768
+ model.unpinLocalIDs(this.wavePins_);
94769
+ for (const span of this.waveSpans_) {
94770
+ model.unpinAddressRange(span.address, span.length);
94771
+ }
94772
+ this.wavePins_ = /* @__PURE__ */ new Set();
94773
+ this.waveSpans_ = [];
94774
+ }
94775
+ };
94479
94776
 
94480
94777
  // compiled/src/ifc/ifc_property_extraction.js
94481
94778
  var PropertyExtractResult;
@@ -15943,7 +15943,7 @@ var ParsingBuffer = class {
15943
15943
  };
15944
15944
 
15945
15945
  // compiled/src/version/version.js
15946
- var versionString = "Conway v1.563.1540";
15946
+ var versionString = "Conway v1.566.1541";
15947
15947
 
15948
15948
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
15949
15949
  function pThreadsAllowed() {
@@ -944,7 +944,7 @@ var EntityTypesIfcCount = 909;
944
944
  var entity_types_ifc_gen_default = EntityTypesIfc;
945
945
 
946
946
  // compiled/src/version/version.js
947
- var versionString = "Conway v1.563.1540";
947
+ var versionString = "Conway v1.566.1541";
948
948
 
949
949
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
950
950
  var wasmType = "";
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=aggregate_prefetch_paging.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregate_prefetch_paging.test.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/aggregate_prefetch_paging.test.ts"],"names":[],"mappings":""}