@bldrs-ai/conway 1.389.1221 → 1.394.1504
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/README.md +36 -22
- package/compiled/Dist/ConwayGeomWasmNode.js +0 -0
- package/compiled/Dist/ConwayGeomWasmNodeMT.js +0 -0
- package/compiled/Dist/ConwayGeomWasmWeb.js +0 -0
- package/compiled/Dist/ConwayGeomWasmWebMT.js +1 -1
- package/compiled/Dist/ConwayGeomWasmWebMT.wasm +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmNode.js +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmNodeMT.js +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWeb.js +0 -0
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWebMT.js +1 -1
- package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWebMT.wasm +0 -0
- package/compiled/dependencies/conway-geom/interface/conway_geometry.d.ts +19 -0
- package/compiled/dependencies/conway-geom/interface/conway_geometry.d.ts.map +1 -1
- package/compiled/dependencies/conway-geom/interface/conway_geometry.js +17 -0
- package/compiled/dependencies/conway-geom/interface/parameters/surface_object.d.ts +6 -0
- package/compiled/dependencies/conway-geom/interface/parameters/surface_object.d.ts.map +1 -1
- package/compiled/examples/browser-bundled.cjs +1569 -51
- package/compiled/examples/cli-bundled.cjs +2790 -436
- package/compiled/examples/cli-step-bundled.cjs +1904 -229
- package/compiled/examples/validator-bundled.cjs +1569 -51
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.d.ts +2 -2
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.js +2 -2
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.d.ts +3 -3
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.js +3 -3
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.js +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/presentation_style_assignment.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/presentation_style_assignment.gen.js +2 -2
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/schema_ap214.gen.js +11 -11
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.d.ts +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.js +1 -1
- package/compiled/src/AP214E3_2010/ap214_command_line_main.js +7 -3
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.d.ts +181 -7
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.js +906 -137
- package/compiled/src/AP214E3_2010/ap214_geometry_extraction.test.js +10 -2
- package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.js +114 -0
- package/compiled/src/AP214E3_2010/ap214_model_geometry.d.ts +6 -0
- package/compiled/src/AP214E3_2010/ap214_model_geometry.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/ap214_model_geometry.js +9 -0
- package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.js +233 -0
- package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.js +147 -0
- package/compiled/src/AP214E3_2010/ap214_step_model.d.ts +2 -1
- package/compiled/src/AP214E3_2010/ap214_step_model.d.ts.map +1 -1
- package/compiled/src/AP214E3_2010/ap214_step_model.js +1 -1
- package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.js +65 -0
- package/compiled/src/AP214E3_2010/ap214_unit_scale.test.d.ts +2 -0
- package/compiled/src/AP214E3_2010/ap214_unit_scale.test.d.ts.map +1 -0
- package/compiled/src/AP214E3_2010/ap214_unit_scale.test.js +111 -0
- package/compiled/src/compat/web-ifc/ap214_streamed_open.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ap214_streamed_open.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ap214_streamed_open.test.js +190 -0
- package/compiled/src/compat/web-ifc/coordination_export_order.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/coordination_export_order.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/coordination_export_order.test.js +110 -0
- package/compiled/src/compat/web-ifc/coordination_f64.d.ts +165 -0
- package/compiled/src/compat/web-ifc/coordination_f64.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/coordination_f64.js +286 -0
- package/compiled/src/compat/web-ifc/coordination_f64.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/coordination_f64.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/coordination_f64.test.js +225 -0
- package/compiled/src/compat/web-ifc/ifc_api.d.ts +154 -0
- package/compiled/src/compat/web-ifc/ifc_api.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api.js +211 -3
- package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.js +288 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts +39 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.d.ts +30 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.js +83 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.js +383 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.js +124 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts +132 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.js +488 -92
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts +268 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.js +996 -149
- package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.js +129 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.d.ts +134 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.js +933 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/spatial_imposter.test.js +467 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.d.ts +187 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.js +524 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.test.js +234 -0
- package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts +306 -0
- package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/streamed_preview_channel.js +580 -0
- package/compiled/src/compat/web-ifc/web_wasm_directory.test.d.ts +2 -0
- package/compiled/src/compat/web-ifc/web_wasm_directory.test.d.ts.map +1 -0
- package/compiled/src/compat/web-ifc/web_wasm_directory.test.js +22 -0
- package/compiled/src/core/composed_model_skeleton.d.ts +63 -0
- package/compiled/src/core/composed_model_skeleton.d.ts.map +1 -0
- package/compiled/src/core/composed_model_skeleton.js +66 -0
- package/compiled/src/core/composed_model_skeleton.test.d.ts +2 -0
- package/compiled/src/core/composed_model_skeleton.test.d.ts.map +1 -0
- package/compiled/src/core/composed_model_skeleton.test.js +69 -0
- package/compiled/src/core/demand_geometry_queue.d.ts +147 -0
- package/compiled/src/core/demand_geometry_queue.d.ts.map +1 -0
- package/compiled/src/core/demand_geometry_queue.js +223 -0
- package/compiled/src/core/demand_geometry_queue.test.d.ts +2 -0
- package/compiled/src/core/demand_geometry_queue.test.d.ts.map +1 -0
- package/compiled/src/core/demand_geometry_queue.test.js +133 -0
- package/compiled/src/core/demand_residency_pump.d.ts +93 -0
- package/compiled/src/core/demand_residency_pump.d.ts.map +1 -0
- package/compiled/src/core/demand_residency_pump.js +120 -0
- package/compiled/src/core/demand_residency_pump.test.d.ts +2 -0
- package/compiled/src/core/demand_residency_pump.test.d.ts.map +1 -0
- package/compiled/src/core/demand_residency_pump.test.js +148 -0
- package/compiled/src/core/geometry_tile_bindings.d.ts +110 -0
- package/compiled/src/core/geometry_tile_bindings.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_bindings.js +76 -0
- package/compiled/src/core/geometry_tile_bindings.test.d.ts +2 -0
- package/compiled/src/core/geometry_tile_bindings.test.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_bindings.test.js +211 -0
- package/compiled/src/core/geometry_tile_pool.d.ts +99 -0
- package/compiled/src/core/geometry_tile_pool.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_pool.js +104 -0
- package/compiled/src/core/geometry_tile_pool.test.d.ts +2 -0
- package/compiled/src/core/geometry_tile_pool.test.d.ts.map +1 -0
- package/compiled/src/core/geometry_tile_pool.test.js +180 -0
- package/compiled/src/core/mem/chunked_pool.d.ts +116 -0
- package/compiled/src/core/mem/chunked_pool.d.ts.map +1 -0
- package/compiled/src/core/mem/chunked_pool.js +149 -0
- package/compiled/src/core/mem/chunked_pool.test.d.ts +2 -0
- package/compiled/src/core/mem/chunked_pool.test.d.ts.map +1 -0
- package/compiled/src/core/mem/chunked_pool.test.js +63 -0
- package/compiled/src/core/mem/shared_asset_pool.d.ts +82 -0
- package/compiled/src/core/mem/shared_asset_pool.d.ts.map +1 -0
- package/compiled/src/core/mem/shared_asset_pool.js +113 -0
- package/compiled/src/core/mem/shared_asset_pool.test.d.ts +2 -0
- package/compiled/src/core/mem/shared_asset_pool.test.d.ts.map +1 -0
- package/compiled/src/core/mem/shared_asset_pool.test.js +49 -0
- package/compiled/src/core/model_registry.d.ts +87 -0
- package/compiled/src/core/model_registry.d.ts.map +1 -0
- package/compiled/src/core/model_registry.js +101 -0
- package/compiled/src/core/model_registry.test.d.ts +2 -0
- package/compiled/src/core/model_registry.test.d.ts.map +1 -0
- package/compiled/src/core/model_registry.test.js +60 -0
- package/compiled/src/core/model_uri.d.ts +57 -0
- package/compiled/src/core/model_uri.d.ts.map +1 -0
- package/compiled/src/core/model_uri.js +101 -0
- package/compiled/src/core/model_uri.test.d.ts +2 -0
- package/compiled/src/core/model_uri.test.d.ts.map +1 -0
- package/compiled/src/core/model_uri.test.js +49 -0
- package/compiled/src/core/progress.d.ts +16 -2
- package/compiled/src/core/progress.d.ts.map +1 -1
- package/compiled/src/core/progress.js +31 -5
- package/compiled/src/core/progress.test.js +11 -2
- package/compiled/src/core/progress_log.d.ts +1 -0
- package/compiled/src/core/progress_log.d.ts.map +1 -1
- package/compiled/src/core/progress_log.js +7 -2
- package/compiled/src/core/progress_log.test.js +21 -0
- package/compiled/src/core/shared_byte_budget.d.ts +60 -0
- package/compiled/src/core/shared_byte_budget.d.ts.map +1 -0
- package/compiled/src/core/shared_byte_budget.js +85 -0
- package/compiled/src/core/shared_byte_budget.test.d.ts +2 -0
- package/compiled/src/core/shared_byte_budget.test.d.ts.map +1 -0
- package/compiled/src/core/shared_byte_budget.test.js +55 -0
- package/compiled/src/core/wasm_heap.d.ts +208 -0
- package/compiled/src/core/wasm_heap.d.ts.map +1 -0
- package/compiled/src/core/wasm_heap.js +417 -0
- package/compiled/src/core/wasm_heap.test.d.ts +2 -0
- package/compiled/src/core/wasm_heap.test.d.ts.map +1 -0
- package/compiled/src/core/wasm_heap.test.js +546 -0
- package/compiled/src/demand/index.d.ts +23 -0
- package/compiled/src/demand/index.d.ts.map +1 -0
- package/compiled/src/demand/index.js +22 -0
- package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.d.ts +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.d.ts.map +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.js +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcPresentationStyleAssignment.gen.d.ts.map +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcPresentationStyleAssignment.gen.js +2 -2
- package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.d.ts +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.d.ts.map +1 -1
- package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.js +1 -1
- package/compiled/src/ifc/ifc4_gen/schema_ifc.gen.js +2 -2
- package/compiled/src/ifc/ifc_demand_extraction.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_demand_extraction.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_demand_extraction.test.js +251 -0
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts +367 -6
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_geometry_extraction.js +1322 -389
- package/compiled/src/ifc/ifc_grid_placement.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_grid_placement.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_grid_placement.test.js +261 -0
- package/compiled/src/ifc/ifc_model_geometry.d.ts +12 -0
- package/compiled/src/ifc/ifc_model_geometry.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_model_geometry.js +15 -0
- package/compiled/src/ifc/ifc_regression_batch_main.js +210 -12
- package/compiled/src/ifc/ifc_spatial_skeleton.d.ts +145 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.js +266 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.js +199 -0
- package/compiled/src/ifc/ifc_step_model.d.ts +6 -2
- package/compiled/src/ifc/ifc_step_model.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_step_model.js +6 -4
- package/compiled/src/ifc/ifc_step_parser.d.ts +58 -0
- package/compiled/src/ifc/ifc_step_parser.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_step_parser.js +64 -0
- package/compiled/src/ifc/ifc_stream_model.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_stream_model.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_model.test.js +70 -0
- package/compiled/src/ifc/ifc_stream_open.d.ts +131 -0
- package/compiled/src/ifc/ifc_stream_open.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_open.js +116 -0
- package/compiled/src/ifc/ifc_stream_open.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_stream_open.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_open.test.js +230 -0
- package/compiled/src/ifc/ifc_tile_extractor.d.ts +84 -0
- package/compiled/src/ifc/ifc_tile_extractor.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_tile_extractor.js +134 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_tile_extractor.test.js +118 -0
- package/compiled/src/ifc/ifc_typed_select_enum.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_typed_select_enum.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_typed_select_enum.test.js +60 -0
- package/compiled/src/index.d.ts +21 -1
- package/compiled/src/index.d.ts.map +1 -1
- package/compiled/src/index.js +28 -1
- package/compiled/src/logging/logger.d.ts +16 -2
- package/compiled/src/logging/logger.d.ts.map +1 -1
- package/compiled/src/logging/logger.js +34 -7
- package/compiled/src/logging/logger.test.js +30 -0
- package/compiled/src/mem/index.d.ts +17 -0
- package/compiled/src/mem/index.d.ts.map +1 -0
- package/compiled/src/mem/index.js +16 -0
- package/compiled/src/namespace_surface.test.d.ts +2 -0
- package/compiled/src/namespace_surface.test.d.ts.map +1 -0
- package/compiled/src/namespace_surface.test.js +43 -0
- package/compiled/src/parsing/parsing_buffer.d.ts +23 -0
- package/compiled/src/parsing/parsing_buffer.d.ts.map +1 -1
- package/compiled/src/parsing/parsing_buffer.js +31 -0
- package/compiled/src/scripts/model_report_displacement.test.d.ts +2 -0
- package/compiled/src/scripts/model_report_displacement.test.d.ts.map +1 -0
- package/compiled/src/scripts/model_report_displacement.test.js +104 -0
- package/compiled/src/scripts/render_glb_paths.test.d.ts +2 -0
- package/compiled/src/scripts/render_glb_paths.test.d.ts.map +1 -0
- package/compiled/src/scripts/render_glb_paths.test.js +115 -0
- package/compiled/src/step/indexing/step_type_indexer.d.ts +20 -0
- package/compiled/src/step/indexing/step_type_indexer.d.ts.map +1 -1
- package/compiled/src/step/indexing/step_type_indexer.js +67 -0
- package/compiled/src/step/parsing/byte_source.d.ts +153 -0
- package/compiled/src/step/parsing/byte_source.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source.js +106 -0
- package/compiled/src/step/parsing/byte_source.test.d.ts +2 -0
- package/compiled/src/step/parsing/byte_source.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source.test.js +47 -0
- package/compiled/src/step/parsing/byte_source_node.d.ts +41 -0
- package/compiled/src/step/parsing/byte_source_node.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source_node.js +54 -0
- package/compiled/src/step/parsing/columnar_index.d.ts +103 -0
- package/compiled/src/step/parsing/columnar_index.d.ts.map +1 -0
- package/compiled/src/step/parsing/columnar_index.js +224 -0
- package/compiled/src/step/parsing/columnar_index.test.d.ts +2 -0
- package/compiled/src/step/parsing/columnar_index.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/columnar_index.test.js +155 -0
- package/compiled/src/step/parsing/cross_reference_registry.d.ts +95 -0
- package/compiled/src/step/parsing/cross_reference_registry.d.ts.map +1 -0
- package/compiled/src/step/parsing/cross_reference_registry.js +91 -0
- package/compiled/src/step/parsing/cross_reference_registry.test.d.ts +2 -0
- package/compiled/src/step/parsing/cross_reference_registry.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/cross_reference_registry.test.js +66 -0
- package/compiled/src/step/parsing/decode_utf8.d.ts +15 -0
- package/compiled/src/step/parsing/decode_utf8.d.ts.map +1 -1
- package/compiled/src/step/parsing/decode_utf8.js +28 -0
- package/compiled/src/step/parsing/express_ref_scan.d.ts +20 -0
- package/compiled/src/step/parsing/express_ref_scan.d.ts.map +1 -0
- package/compiled/src/step/parsing/express_ref_scan.js +91 -0
- package/compiled/src/step/parsing/express_ref_scan.test.d.ts +2 -0
- package/compiled/src/step/parsing/express_ref_scan.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/express_ref_scan.test.js +28 -0
- package/compiled/src/step/parsing/index_sidecar.d.ts +81 -0
- package/compiled/src/step/parsing/index_sidecar.d.ts.map +1 -0
- package/compiled/src/step/parsing/index_sidecar.js +283 -0
- package/compiled/src/step/parsing/index_sidecar.test.d.ts +2 -0
- package/compiled/src/step/parsing/index_sidecar.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/index_sidecar.test.js +122 -0
- package/compiled/src/step/parsing/inf_recovery_index.test.d.ts +2 -0
- package/compiled/src/step/parsing/inf_recovery_index.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/inf_recovery_index.test.js +108 -0
- package/compiled/src/step/parsing/prefix_type_index.d.ts +124 -0
- package/compiled/src/step/parsing/prefix_type_index.d.ts.map +1 -0
- package/compiled/src/step/parsing/prefix_type_index.js +207 -0
- package/compiled/src/step/parsing/prefix_type_index.test.d.ts +2 -0
- package/compiled/src/step/parsing/prefix_type_index.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/prefix_type_index.test.js +298 -0
- package/compiled/src/step/parsing/range_byte_source.d.ts +69 -0
- package/compiled/src/step/parsing/range_byte_source.d.ts.map +1 -0
- package/compiled/src/step/parsing/range_byte_source.js +78 -0
- package/compiled/src/step/parsing/range_byte_source.test.d.ts +2 -0
- package/compiled/src/step/parsing/range_byte_source.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/range_byte_source.test.js +70 -0
- package/compiled/src/step/parsing/record_event.d.ts +23 -0
- package/compiled/src/step/parsing/record_event.d.ts.map +1 -0
- package/compiled/src/step/parsing/record_event.js +1 -0
- package/compiled/src/step/parsing/record_field_cursor.d.ts +94 -0
- package/compiled/src/step/parsing/record_field_cursor.d.ts.map +1 -0
- package/compiled/src/step/parsing/record_field_cursor.js +189 -0
- package/compiled/src/step/parsing/step_deserialization_functions.d.ts +29 -0
- package/compiled/src/step/parsing/step_deserialization_functions.d.ts.map +1 -1
- package/compiled/src/step/parsing/step_deserialization_functions.js +45 -0
- package/compiled/src/step/parsing/step_deserialization_functions.test.js +59 -1
- package/compiled/src/step/parsing/step_parser.d.ts +66 -1
- package/compiled/src/step/parsing/step_parser.d.ts.map +1 -1
- package/compiled/src/step/parsing/step_parser.js +164 -10
- package/compiled/src/step/parsing/step_string_parser.js +8 -8
- package/compiled/src/step/parsing/streaming_index_builder.d.ts +141 -0
- package/compiled/src/step/parsing/streaming_index_builder.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_index_builder.js +280 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.d.ts +2 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.js +107 -0
- package/compiled/src/step/parsing/streaming_index_builder_async.test.d.ts +2 -0
- package/compiled/src/step/parsing/streaming_index_builder_async.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_index_builder_async.test.js +109 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts +71 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.js +88 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.test.d.ts +2 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_record_dispatcher.test.js +66 -0
- package/compiled/src/step/parsing/uint32_sink.d.ts +72 -0
- package/compiled/src/step/parsing/uint32_sink.d.ts.map +1 -0
- package/compiled/src/step/parsing/uint32_sink.js +180 -0
- package/compiled/src/step/parsing/uint32_sink.test.d.ts +2 -0
- package/compiled/src/step/parsing/uint32_sink.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/uint32_sink.test.js +199 -0
- package/compiled/src/step/step_buffer_provider.d.ts +48 -3
- package/compiled/src/step/step_buffer_provider.d.ts.map +1 -1
- package/compiled/src/step/step_buffer_provider.js +60 -11
- package/compiled/src/step/step_buffer_provider.test.js +14 -0
- package/compiled/src/step/step_entity_base.d.ts +65 -3
- package/compiled/src/step/step_entity_base.d.ts.map +1 -1
- package/compiled/src/step/step_entity_base.js +135 -3
- package/compiled/src/step/step_model_base.d.ts +221 -8
- package/compiled/src/step/step_model_base.d.ts.map +1 -1
- package/compiled/src/step/step_model_base.js +542 -7
- package/compiled/src/stream/index.d.ts +34 -0
- package/compiled/src/stream/index.d.ts.map +1 -0
- package/compiled/src/stream/index.js +32 -0
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A composed view over every model in a {@link ModelRegistry} (M5 / design S3).
|
|
3
|
+
*
|
|
4
|
+
* Federation's read side: a site plan that references per-building files, or a
|
|
5
|
+
* project split across disciplines, is browsed as **one** model whose entities
|
|
6
|
+
* carry universal {@link EntityAddress}es (`modelURI#expressID`). A type query
|
|
7
|
+
* here fans out across all registered members and yields addresses, not bare
|
|
8
|
+
* express IDs — so "every `IfcWall` in the project" spans files, and each
|
|
9
|
+
* result round-trips back through {@link ModelRegistry.resolve} to the right
|
|
10
|
+
* model.
|
|
11
|
+
*
|
|
12
|
+
* This is the composition scaffold: it unions the members' type skeletons
|
|
13
|
+
* under the shared address space. The spatial-containment merge (a site's
|
|
14
|
+
* `IfcRelAggregates` linking to building files) layers on top by resolving the
|
|
15
|
+
* cross-file references the {@link CrossReferenceRegistry} discovers — the next
|
|
16
|
+
* increment, gated on the loader registering streamed models here.
|
|
17
|
+
*/
|
|
18
|
+
export class ComposedModelSkeleton {
|
|
19
|
+
/**
|
|
20
|
+
* @param registry_ The registry whose models this composes over.
|
|
21
|
+
*/
|
|
22
|
+
constructor(registry_) {
|
|
23
|
+
this.registry_ = registry_;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* @return {ModelRegistry<H>} The registry backing this composed view.
|
|
27
|
+
*/
|
|
28
|
+
get registry() {
|
|
29
|
+
return this.registry_;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Yield the universal address of every entity of the given types across all
|
|
33
|
+
* registered models.
|
|
34
|
+
*
|
|
35
|
+
* @param types The entity constructors to query (subtype closures unioned).
|
|
36
|
+
* @return {IterableIterator<EntityAddress>} Addresses of matching entities.
|
|
37
|
+
* @yields {EntityAddress} Each matching entity's universal address.
|
|
38
|
+
*/
|
|
39
|
+
*entitiesOfType(...types) {
|
|
40
|
+
for (const modelURI of this.registry_.uris()) {
|
|
41
|
+
const model = this.registry_.get(modelURI);
|
|
42
|
+
if (model === void 0) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
for (const expressID of model.expressIDsOfTypes(...types)) {
|
|
46
|
+
yield { modelURI, expressID };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Count entities of the given types across all registered models.
|
|
52
|
+
*
|
|
53
|
+
* @param types The entity constructors to count.
|
|
54
|
+
* @return {number} The total across the federation.
|
|
55
|
+
*/
|
|
56
|
+
countOfType(...types) {
|
|
57
|
+
let total = 0;
|
|
58
|
+
for (const model of this.registry_.models()) {
|
|
59
|
+
for (const expressID of model.expressIDsOfTypes(...types)) {
|
|
60
|
+
void expressID;
|
|
61
|
+
++total;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return total;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composed_model_skeleton.test.d.ts","sourceRoot":"","sources":["../../../src/core/composed_model_skeleton.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* eslint-disable no-magic-numbers */
|
|
2
|
+
// M5: the composed view fans a type query across every registered model and
|
|
3
|
+
// yields universal addresses, so "every wall in the project" spans files and
|
|
4
|
+
// each result round-trips back through the registry to its model.
|
|
5
|
+
import { describe, expect, test } from "@jest/globals";
|
|
6
|
+
import { ComposedModelSkeleton } from "./composed_model_skeleton.js";
|
|
7
|
+
import { ModelRegistry } from "./model_registry.js";
|
|
8
|
+
import { SharedByteBudget } from "./shared_byte_budget.js";
|
|
9
|
+
/**
|
|
10
|
+
* A fake type-queryable model returning a fixed express-ID set regardless of
|
|
11
|
+
* the queried types (the query-closure matching itself is covered by the
|
|
12
|
+
* incremental-type-index tests; here we exercise cross-model composition).
|
|
13
|
+
*/
|
|
14
|
+
class FakeModel {
|
|
15
|
+
/**
|
|
16
|
+
* @param ids The express IDs this model reports for any query.
|
|
17
|
+
*/
|
|
18
|
+
constructor(ids) {
|
|
19
|
+
this.ids = ids;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* @return {IterableIterator<number>} The fixed express IDs.
|
|
23
|
+
*/
|
|
24
|
+
*expressIDsOfTypes() {
|
|
25
|
+
yield* this.ids;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// A dummy constructor to satisfy the query signature (unused by FakeModel).
|
|
29
|
+
const ANY_TYPE = { query: [1] };
|
|
30
|
+
describe("ComposedModelSkeleton", () => {
|
|
31
|
+
/**
|
|
32
|
+
* A composed view over two fake models.
|
|
33
|
+
*
|
|
34
|
+
* @return {ComposedModelSkeleton} The composed view.
|
|
35
|
+
*/
|
|
36
|
+
function composed() {
|
|
37
|
+
const registry = new ModelRegistry(new SharedByteBudget(1000));
|
|
38
|
+
registry.register("site/a.ifc", new FakeModel([1, 2]));
|
|
39
|
+
registry.register("site/b.ifc", new FakeModel([10, 11, 12]));
|
|
40
|
+
return new ComposedModelSkeleton(registry);
|
|
41
|
+
}
|
|
42
|
+
test("yields universal addresses across every registered model", () => {
|
|
43
|
+
const view = composed();
|
|
44
|
+
const addresses = [...view.entitiesOfType(ANY_TYPE)];
|
|
45
|
+
expect(addresses).toEqual([
|
|
46
|
+
{ modelURI: "site/a.ifc", expressID: 1 },
|
|
47
|
+
{ modelURI: "site/a.ifc", expressID: 2 },
|
|
48
|
+
{ modelURI: "site/b.ifc", expressID: 10 },
|
|
49
|
+
{ modelURI: "site/b.ifc", expressID: 11 },
|
|
50
|
+
{ modelURI: "site/b.ifc", expressID: 12 },
|
|
51
|
+
]);
|
|
52
|
+
});
|
|
53
|
+
test("counts across the federation", () => {
|
|
54
|
+
expect(composed().countOfType(ANY_TYPE)).toBe(5);
|
|
55
|
+
});
|
|
56
|
+
test("each composed address resolves back to its own model", () => {
|
|
57
|
+
const view = composed();
|
|
58
|
+
for (const address of view.entitiesOfType(ANY_TYPE)) {
|
|
59
|
+
const resolved = view.registry.resolve(address);
|
|
60
|
+
expect(resolved).toBeDefined();
|
|
61
|
+
expect(resolved?.expressID).toBe(address.expressID);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
test("an empty registry composes to nothing", () => {
|
|
65
|
+
const view = new ComposedModelSkeleton(new ModelRegistry(new SharedByteBudget(10)));
|
|
66
|
+
expect([...view.entitiesOfType(ANY_TYPE)]).toEqual([]);
|
|
67
|
+
expect(view.countOfType(ANY_TYPE)).toBe(0);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Demand-driven, budgeted geometry materialisation (M3).
|
|
3
|
+
*
|
|
4
|
+
* The streaming loader inverts geometry: instead of extracting every product
|
|
5
|
+
* up front, extraction becomes a **cache fill keyed by product**, ordered by
|
|
6
|
+
* demand (viewport frustum + distance, explicit selection, prefetch hints)
|
|
7
|
+
* and bounded by an explicit byte budget. This module is the scheduler: a
|
|
8
|
+
* priority queue over product local IDs plus an evictable resident set, with
|
|
9
|
+
* the actual extract / release delegated to a pluggable {@link GeometryTiles}.
|
|
10
|
+
*
|
|
11
|
+
* The heavy half — the wasm-side extract → tessellate → upload and the
|
|
12
|
+
* per-product native reclaim — lives behind {@link GeometryTiles}. Its
|
|
13
|
+
* production implementation needs a **conway-geom API to free one product's
|
|
14
|
+
* native geometry** (today the wasm heap has no per-product reclaim); scoping
|
|
15
|
+
* that C++ surface is the M3 blocker tracked in the design doc. This scheduler
|
|
16
|
+
* is engine-side, fully deterministic, and tested against a mock tiles impl,
|
|
17
|
+
* so the queue/budget/eviction policy is settled independently of the wasm
|
|
18
|
+
* work.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* The per-product geometry work behind the queue. Implementations do the
|
|
22
|
+
* expensive materialisation; the queue owns only ordering and the budget.
|
|
23
|
+
*/
|
|
24
|
+
export interface GeometryTiles {
|
|
25
|
+
/**
|
|
26
|
+
* Materialise a product's geometry tile and return its resident cost in
|
|
27
|
+
* bytes (GPU/scene + any retained wasm working set the budget should count).
|
|
28
|
+
* Called at most once per product between evictions.
|
|
29
|
+
*
|
|
30
|
+
* @param productLocalID The product's local ID.
|
|
31
|
+
* @return {number} The tile's resident byte cost (≥ 0).
|
|
32
|
+
*/
|
|
33
|
+
extract(productLocalID: number): number;
|
|
34
|
+
/**
|
|
35
|
+
* Release a product's materialised tile, freeing its resident bytes — the
|
|
36
|
+
* scene mesh and, crucially, the product's native (wasm) geometry. This is
|
|
37
|
+
* the per-product reclaim the production conway-geom surface must provide.
|
|
38
|
+
*
|
|
39
|
+
* @param productLocalID The product's local ID.
|
|
40
|
+
*/
|
|
41
|
+
release(productLocalID: number): void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Runtime counters for a queue, for tests and telemetry.
|
|
45
|
+
*/
|
|
46
|
+
export interface DemandQueueStats {
|
|
47
|
+
extractions: number;
|
|
48
|
+
evictions: number;
|
|
49
|
+
residentBytes: number;
|
|
50
|
+
residentCount: number;
|
|
51
|
+
pendingCount: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A budgeted, demand-ordered geometry materialisation queue.
|
|
55
|
+
*
|
|
56
|
+
* Usage: `request(productLocalID, priority)` as demand changes (higher
|
|
57
|
+
* priority = more wanted); `pump()` to materialise the most-wanted pending
|
|
58
|
+
* products until the queue drains or the byte budget forces eviction of
|
|
59
|
+
* lower-priority resident tiles. Re-requesting an evicted product re-fills it.
|
|
60
|
+
* A steady stream of `request` + `pump` keeps a bounded working set of the
|
|
61
|
+
* highest-priority products resident — the "full model navigable under a
|
|
62
|
+
* fixed budget" behaviour.
|
|
63
|
+
*/
|
|
64
|
+
export declare class DemandGeometryQueue {
|
|
65
|
+
private readonly tiles_;
|
|
66
|
+
private readonly budgetBytes_;
|
|
67
|
+
/** Highest priority a product currently wants materialising at. */
|
|
68
|
+
private readonly pending_;
|
|
69
|
+
/** Resident tiles by product local ID. */
|
|
70
|
+
private readonly resident_;
|
|
71
|
+
private residentBytes_;
|
|
72
|
+
private extractions_;
|
|
73
|
+
private evictions_;
|
|
74
|
+
/**
|
|
75
|
+
* @param tiles The extract/release backend.
|
|
76
|
+
* @param budgetBytes Maximum resident tile bytes before eviction kicks in.
|
|
77
|
+
*/
|
|
78
|
+
constructor(tiles: GeometryTiles, budgetBytes: number);
|
|
79
|
+
/**
|
|
80
|
+
* Request a product be materialised at the given demand priority. Updates
|
|
81
|
+
* the priority if already pending (keeping the higher of the two) or already
|
|
82
|
+
* resident (so eviction ranks it correctly). Requesting a resident product
|
|
83
|
+
* does not re-extract it.
|
|
84
|
+
*
|
|
85
|
+
* @param productLocalID The product to materialise.
|
|
86
|
+
* @param priority The demand priority (higher = more wanted).
|
|
87
|
+
*/
|
|
88
|
+
request(productLocalID: number, priority: number): void;
|
|
89
|
+
/**
|
|
90
|
+
* Materialise pending products in descending priority order, evicting the
|
|
91
|
+
* lowest-priority resident tiles whenever the budget is exceeded. A pending
|
|
92
|
+
* product whose priority is below every resident tile AND that can't fit is
|
|
93
|
+
* left pending (it will fill once demand raises it or resident tiles drop).
|
|
94
|
+
*
|
|
95
|
+
* @param maxExtractions Optional cap on how many tiles to extract this pump
|
|
96
|
+
* (e.g. a per-frame budget); unbounded when omitted.
|
|
97
|
+
* @return {number} The number of tiles extracted this pump.
|
|
98
|
+
*/
|
|
99
|
+
pump(maxExtractions?: number): number;
|
|
100
|
+
/**
|
|
101
|
+
* Evict every resident tile (e.g. on model close), releasing all bytes.
|
|
102
|
+
*/
|
|
103
|
+
evictAll(): void;
|
|
104
|
+
/**
|
|
105
|
+
* @return {boolean} True if the product's tile is resident.
|
|
106
|
+
* @param productLocalID The product to check.
|
|
107
|
+
*/
|
|
108
|
+
isResident(productLocalID: number): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* @return {DemandQueueStats} A snapshot of runtime counters.
|
|
111
|
+
*/
|
|
112
|
+
get stats(): DemandQueueStats;
|
|
113
|
+
/**
|
|
114
|
+
* Pop the highest-priority pending request. Linear scan — swap for a heap
|
|
115
|
+
* if a real workload shows the pending set growing large per pump.
|
|
116
|
+
*
|
|
117
|
+
* @return {PendingRequest | undefined} The request, or undefined if none.
|
|
118
|
+
*/
|
|
119
|
+
private popHighestPending_;
|
|
120
|
+
/**
|
|
121
|
+
* Ensure there is conceptual room for a tile requested at `priority` by
|
|
122
|
+
* evicting resident tiles strictly lower in priority while over budget.
|
|
123
|
+
* Returns false if the budget is full of tiles at least as wanted as this
|
|
124
|
+
* request (so it shouldn't displace them).
|
|
125
|
+
*
|
|
126
|
+
* @param priority The incoming request's priority.
|
|
127
|
+
* @return {boolean} True if extraction should proceed.
|
|
128
|
+
*/
|
|
129
|
+
private ensureRoomFor_;
|
|
130
|
+
/**
|
|
131
|
+
* Evict lowest-priority resident tiles until within budget (used after an
|
|
132
|
+
* extraction that pushed us over — e.g. a large tile).
|
|
133
|
+
*/
|
|
134
|
+
private evictToBudget_;
|
|
135
|
+
/**
|
|
136
|
+
* @return {{ productLocalID: number, priority: number } | undefined} The
|
|
137
|
+
* lowest-priority resident tile, or undefined if none.
|
|
138
|
+
*/
|
|
139
|
+
private lowestPriorityResident_;
|
|
140
|
+
/**
|
|
141
|
+
* Release one resident tile.
|
|
142
|
+
*
|
|
143
|
+
* @param productLocalID The tile to evict.
|
|
144
|
+
*/
|
|
145
|
+
private evictOne_;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=demand_geometry_queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demand_geometry_queue.d.ts","sourceRoot":"","sources":["../../../src/core/demand_geometry_queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;GAGG;AACH,MAAM,WAAW,aAAa;IAE5B;;;;;;;OAOG;IACH,OAAO,CAAE,cAAc,EAAE,MAAM,GAAI,MAAM,CAAA;IAEzC;;;;;;OAMG;IACH,OAAO,CAAE,cAAc,EAAE,MAAM,GAAI,IAAI,CAAA;CACxC;AAiBD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB;AAGD;;;;;;;;;;GAUG;AACH,qBAAa,mBAAmB;IAE9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IAEtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IAErC,mEAAmE;IACnE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IAErD,0CAA0C;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAE5D,OAAO,CAAC,cAAc,CAAI;IAE1B,OAAO,CAAC,YAAY,CAAI;IAExB,OAAO,CAAC,UAAU,CAAI;IAEtB;;;OAGG;gBACU,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM;IAUtD;;;;;;;;OAQG;IACI,OAAO,CAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAI,IAAI;IAiBhE;;;;;;;;;OASG;IACI,IAAI,CAAE,cAAc,GAAE,MAAiC,GAAI,MAAM;IAoCxE;;OAEG;IACI,QAAQ,IAAI,IAAI;IASvB;;;OAGG;IACI,UAAU,CAAE,cAAc,EAAE,MAAM,GAAI,OAAO;IAIpD;;OAEG;IACH,IAAW,KAAK,IAAI,gBAAgB,CAQnC;IAED;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAqB1B;;;;;;;;OAQG;IACH,OAAO,CAAC,cAAc;IAuBtB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAYtB;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAiB/B;;;;OAIG;IACH,OAAO,CAAC,SAAS;CAYlB"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Demand-driven, budgeted geometry materialisation (M3).
|
|
3
|
+
*
|
|
4
|
+
* The streaming loader inverts geometry: instead of extracting every product
|
|
5
|
+
* up front, extraction becomes a **cache fill keyed by product**, ordered by
|
|
6
|
+
* demand (viewport frustum + distance, explicit selection, prefetch hints)
|
|
7
|
+
* and bounded by an explicit byte budget. This module is the scheduler: a
|
|
8
|
+
* priority queue over product local IDs plus an evictable resident set, with
|
|
9
|
+
* the actual extract / release delegated to a pluggable {@link GeometryTiles}.
|
|
10
|
+
*
|
|
11
|
+
* The heavy half — the wasm-side extract → tessellate → upload and the
|
|
12
|
+
* per-product native reclaim — lives behind {@link GeometryTiles}. Its
|
|
13
|
+
* production implementation needs a **conway-geom API to free one product's
|
|
14
|
+
* native geometry** (today the wasm heap has no per-product reclaim); scoping
|
|
15
|
+
* that C++ surface is the M3 blocker tracked in the design doc. This scheduler
|
|
16
|
+
* is engine-side, fully deterministic, and tested against a mock tiles impl,
|
|
17
|
+
* so the queue/budget/eviction policy is settled independently of the wasm
|
|
18
|
+
* work.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* A budgeted, demand-ordered geometry materialisation queue.
|
|
22
|
+
*
|
|
23
|
+
* Usage: `request(productLocalID, priority)` as demand changes (higher
|
|
24
|
+
* priority = more wanted); `pump()` to materialise the most-wanted pending
|
|
25
|
+
* products until the queue drains or the byte budget forces eviction of
|
|
26
|
+
* lower-priority resident tiles. Re-requesting an evicted product re-fills it.
|
|
27
|
+
* A steady stream of `request` + `pump` keeps a bounded working set of the
|
|
28
|
+
* highest-priority products resident — the "full model navigable under a
|
|
29
|
+
* fixed budget" behaviour.
|
|
30
|
+
*/
|
|
31
|
+
export class DemandGeometryQueue {
|
|
32
|
+
/**
|
|
33
|
+
* @param tiles The extract/release backend.
|
|
34
|
+
* @param budgetBytes Maximum resident tile bytes before eviction kicks in.
|
|
35
|
+
*/
|
|
36
|
+
constructor(tiles, budgetBytes) {
|
|
37
|
+
/** Highest priority a product currently wants materialising at. */
|
|
38
|
+
this.pending_ = new Map();
|
|
39
|
+
/** Resident tiles by product local ID. */
|
|
40
|
+
this.resident_ = new Map();
|
|
41
|
+
this.residentBytes_ = 0;
|
|
42
|
+
this.extractions_ = 0;
|
|
43
|
+
this.evictions_ = 0;
|
|
44
|
+
if (budgetBytes <= 0) {
|
|
45
|
+
throw new Error(`Invalid budgetBytes ${budgetBytes}`);
|
|
46
|
+
}
|
|
47
|
+
this.tiles_ = tiles;
|
|
48
|
+
this.budgetBytes_ = budgetBytes;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Request a product be materialised at the given demand priority. Updates
|
|
52
|
+
* the priority if already pending (keeping the higher of the two) or already
|
|
53
|
+
* resident (so eviction ranks it correctly). Requesting a resident product
|
|
54
|
+
* does not re-extract it.
|
|
55
|
+
*
|
|
56
|
+
* @param productLocalID The product to materialise.
|
|
57
|
+
* @param priority The demand priority (higher = more wanted).
|
|
58
|
+
*/
|
|
59
|
+
request(productLocalID, priority) {
|
|
60
|
+
const tile = this.resident_.get(productLocalID);
|
|
61
|
+
if (tile !== void 0) {
|
|
62
|
+
// Already resident — just refresh its eviction ranking.
|
|
63
|
+
tile.priority = Math.max(tile.priority, priority);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const existing = this.pending_.get(productLocalID);
|
|
67
|
+
this.pending_.set(productLocalID, existing === void 0 ? priority : Math.max(existing, priority));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Materialise pending products in descending priority order, evicting the
|
|
71
|
+
* lowest-priority resident tiles whenever the budget is exceeded. A pending
|
|
72
|
+
* product whose priority is below every resident tile AND that can't fit is
|
|
73
|
+
* left pending (it will fill once demand raises it or resident tiles drop).
|
|
74
|
+
*
|
|
75
|
+
* @param maxExtractions Optional cap on how many tiles to extract this pump
|
|
76
|
+
* (e.g. a per-frame budget); unbounded when omitted.
|
|
77
|
+
* @return {number} The number of tiles extracted this pump.
|
|
78
|
+
*/
|
|
79
|
+
pump(maxExtractions = Number.POSITIVE_INFINITY) {
|
|
80
|
+
let extractedThisPump = 0;
|
|
81
|
+
while (extractedThisPump < maxExtractions && this.pending_.size > 0) {
|
|
82
|
+
const next = this.popHighestPending_();
|
|
83
|
+
if (next === void 0) {
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
// If the working set is full and this request can't beat the cheapest
|
|
87
|
+
// evictable (lower-priority) resident tile, stop — nothing more fits.
|
|
88
|
+
if (!this.ensureRoomFor_(next.priority)) {
|
|
89
|
+
// Put it back; it stays pending for a future pump.
|
|
90
|
+
this.pending_.set(next.productLocalID, next.priority);
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
const bytes = this.tiles_.extract(next.productLocalID);
|
|
94
|
+
this.resident_.set(next.productLocalID, { bytes, priority: next.priority });
|
|
95
|
+
this.residentBytes_ += bytes;
|
|
96
|
+
++this.extractions_;
|
|
97
|
+
++extractedThisPump;
|
|
98
|
+
// A single oversized tile can still exceed budget; evict what we can.
|
|
99
|
+
this.evictToBudget_();
|
|
100
|
+
}
|
|
101
|
+
return extractedThisPump;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Evict every resident tile (e.g. on model close), releasing all bytes.
|
|
105
|
+
*/
|
|
106
|
+
evictAll() {
|
|
107
|
+
for (const productLocalID of this.resident_.keys()) {
|
|
108
|
+
this.tiles_.release(productLocalID);
|
|
109
|
+
++this.evictions_;
|
|
110
|
+
}
|
|
111
|
+
this.resident_.clear();
|
|
112
|
+
this.residentBytes_ = 0;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* @return {boolean} True if the product's tile is resident.
|
|
116
|
+
* @param productLocalID The product to check.
|
|
117
|
+
*/
|
|
118
|
+
isResident(productLocalID) {
|
|
119
|
+
return this.resident_.has(productLocalID);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* @return {DemandQueueStats} A snapshot of runtime counters.
|
|
123
|
+
*/
|
|
124
|
+
get stats() {
|
|
125
|
+
return {
|
|
126
|
+
extractions: this.extractions_,
|
|
127
|
+
evictions: this.evictions_,
|
|
128
|
+
residentBytes: this.residentBytes_,
|
|
129
|
+
residentCount: this.resident_.size,
|
|
130
|
+
pendingCount: this.pending_.size,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Pop the highest-priority pending request. Linear scan — swap for a heap
|
|
135
|
+
* if a real workload shows the pending set growing large per pump.
|
|
136
|
+
*
|
|
137
|
+
* @return {PendingRequest | undefined} The request, or undefined if none.
|
|
138
|
+
*/
|
|
139
|
+
popHighestPending_() {
|
|
140
|
+
let bestID;
|
|
141
|
+
let bestPriority = Number.NEGATIVE_INFINITY;
|
|
142
|
+
for (const [productLocalID, priority] of this.pending_) {
|
|
143
|
+
if (priority > bestPriority) {
|
|
144
|
+
bestPriority = priority;
|
|
145
|
+
bestID = productLocalID;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (bestID === void 0) {
|
|
149
|
+
return void 0;
|
|
150
|
+
}
|
|
151
|
+
this.pending_.delete(bestID);
|
|
152
|
+
return { productLocalID: bestID, priority: bestPriority };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Ensure there is conceptual room for a tile requested at `priority` by
|
|
156
|
+
* evicting resident tiles strictly lower in priority while over budget.
|
|
157
|
+
* Returns false if the budget is full of tiles at least as wanted as this
|
|
158
|
+
* request (so it shouldn't displace them).
|
|
159
|
+
*
|
|
160
|
+
* @param priority The incoming request's priority.
|
|
161
|
+
* @return {boolean} True if extraction should proceed.
|
|
162
|
+
*/
|
|
163
|
+
ensureRoomFor_(priority) {
|
|
164
|
+
if (this.residentBytes_ < this.budgetBytes_) {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
// Over/at budget: only proceed if there's a lower-priority tile to evict.
|
|
168
|
+
let evictedAny = false;
|
|
169
|
+
while (this.residentBytes_ >= this.budgetBytes_) {
|
|
170
|
+
const victim = this.lowestPriorityResident_();
|
|
171
|
+
if (victim === void 0 || victim.priority >= priority) {
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
this.evictOne_(victim.productLocalID);
|
|
175
|
+
evictedAny = true;
|
|
176
|
+
}
|
|
177
|
+
return this.residentBytes_ < this.budgetBytes_ || evictedAny;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Evict lowest-priority resident tiles until within budget (used after an
|
|
181
|
+
* extraction that pushed us over — e.g. a large tile).
|
|
182
|
+
*/
|
|
183
|
+
evictToBudget_() {
|
|
184
|
+
while (this.residentBytes_ > this.budgetBytes_) {
|
|
185
|
+
const victim = this.lowestPriorityResident_();
|
|
186
|
+
if (victim === void 0) {
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
this.evictOne_(victim.productLocalID);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* @return {{ productLocalID: number, priority: number } | undefined} The
|
|
194
|
+
* lowest-priority resident tile, or undefined if none.
|
|
195
|
+
*/
|
|
196
|
+
lowestPriorityResident_() {
|
|
197
|
+
let worstID;
|
|
198
|
+
let worstPriority = Number.POSITIVE_INFINITY;
|
|
199
|
+
for (const [productLocalID, tile] of this.resident_) {
|
|
200
|
+
if (tile.priority < worstPriority) {
|
|
201
|
+
worstPriority = tile.priority;
|
|
202
|
+
worstID = productLocalID;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return worstID === void 0 ?
|
|
206
|
+
void 0 : { productLocalID: worstID, priority: worstPriority };
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Release one resident tile.
|
|
210
|
+
*
|
|
211
|
+
* @param productLocalID The tile to evict.
|
|
212
|
+
*/
|
|
213
|
+
evictOne_(productLocalID) {
|
|
214
|
+
const tile = this.resident_.get(productLocalID);
|
|
215
|
+
if (tile === void 0) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
this.tiles_.release(productLocalID);
|
|
219
|
+
this.resident_.delete(productLocalID);
|
|
220
|
+
this.residentBytes_ -= tile.bytes;
|
|
221
|
+
++this.evictions_;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demand_geometry_queue.test.d.ts","sourceRoot":"","sources":["../../../src/core/demand_geometry_queue.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* eslint-disable no-magic-numbers */
|
|
2
|
+
// M3: the demand-geometry scheduler — priority ordering, byte budget, and
|
|
3
|
+
// eviction — tested against a mock tiles backend so the policy is settled
|
|
4
|
+
// independently of the wasm extract/reclaim work.
|
|
5
|
+
import { describe, expect, test } from "@jest/globals";
|
|
6
|
+
import { DemandGeometryQueue } from "./demand_geometry_queue.js";
|
|
7
|
+
/**
|
|
8
|
+
* A mock tiles backend: every product costs a fixed number of bytes and
|
|
9
|
+
* records the extract/release calls so tests can assert on them.
|
|
10
|
+
*
|
|
11
|
+
* @param costBytes Per-tile resident cost.
|
|
12
|
+
* @return {object} `{ tiles, extracted, released }`.
|
|
13
|
+
*/
|
|
14
|
+
function mockTiles(costBytes) {
|
|
15
|
+
const extracted = [];
|
|
16
|
+
const released = [];
|
|
17
|
+
const tiles = {
|
|
18
|
+
extract(id) {
|
|
19
|
+
extracted.push(id);
|
|
20
|
+
return costBytes;
|
|
21
|
+
},
|
|
22
|
+
release(id) {
|
|
23
|
+
released.push(id);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
return { tiles, extracted, released };
|
|
27
|
+
}
|
|
28
|
+
describe("DemandGeometryQueue", () => {
|
|
29
|
+
test("materialises highest-priority requests first", () => {
|
|
30
|
+
const { tiles, extracted } = mockTiles(10);
|
|
31
|
+
const q = new DemandGeometryQueue(tiles, 1000);
|
|
32
|
+
q.request(1, 5);
|
|
33
|
+
q.request(2, 50);
|
|
34
|
+
q.request(3, 20);
|
|
35
|
+
q.pump();
|
|
36
|
+
// Extracted in descending priority: 2 (50), 3 (20), 1 (5).
|
|
37
|
+
expect(extracted).toEqual([2, 3, 1]);
|
|
38
|
+
expect(q.stats.residentCount).toBe(3);
|
|
39
|
+
expect(q.stats.residentBytes).toBe(30);
|
|
40
|
+
});
|
|
41
|
+
test("evicts the lowest-priority tile when the budget is exceeded", () => {
|
|
42
|
+
const { tiles, released } = mockTiles(100);
|
|
43
|
+
// Budget holds 3 tiles (300).
|
|
44
|
+
const q = new DemandGeometryQueue(tiles, 300);
|
|
45
|
+
for (const [id, pri] of [[1, 10], [2, 20], [3, 30]]) {
|
|
46
|
+
q.request(id, pri);
|
|
47
|
+
}
|
|
48
|
+
q.pump();
|
|
49
|
+
expect(q.stats.residentCount).toBe(3);
|
|
50
|
+
// A 4th, higher-priority request must evict the lowest (id 1, pri 10).
|
|
51
|
+
q.request(4, 40);
|
|
52
|
+
q.pump();
|
|
53
|
+
expect(q.isResident(4)).toBe(true);
|
|
54
|
+
expect(q.isResident(1)).toBe(false);
|
|
55
|
+
expect(released).toContain(1);
|
|
56
|
+
expect(q.stats.residentBytes).toBeLessThanOrEqual(300);
|
|
57
|
+
});
|
|
58
|
+
test("a request below every resident tile does not displace them", () => {
|
|
59
|
+
const { tiles, extracted } = mockTiles(100);
|
|
60
|
+
const q = new DemandGeometryQueue(tiles, 200); // holds 2
|
|
61
|
+
q.request(1, 50);
|
|
62
|
+
q.request(2, 40);
|
|
63
|
+
q.pump();
|
|
64
|
+
expect(q.stats.residentCount).toBe(2);
|
|
65
|
+
// Low-priority newcomer can't beat either resident tile → stays pending.
|
|
66
|
+
q.request(3, 5);
|
|
67
|
+
const n = q.pump();
|
|
68
|
+
expect(n).toBe(0);
|
|
69
|
+
expect(q.isResident(3)).toBe(false);
|
|
70
|
+
expect(extracted).toEqual([1, 2]);
|
|
71
|
+
expect(q.stats.pendingCount).toBe(1);
|
|
72
|
+
});
|
|
73
|
+
test("re-requesting an evicted product re-extracts it", () => {
|
|
74
|
+
const { tiles, extracted } = mockTiles(100);
|
|
75
|
+
const q = new DemandGeometryQueue(tiles, 100); // holds 1
|
|
76
|
+
q.request(1, 10);
|
|
77
|
+
q.pump();
|
|
78
|
+
q.request(2, 20); // evicts 1
|
|
79
|
+
q.pump();
|
|
80
|
+
expect(q.isResident(1)).toBe(false);
|
|
81
|
+
q.request(1, 30); // evicts 2, re-extracts 1
|
|
82
|
+
q.pump();
|
|
83
|
+
expect(q.isResident(1)).toBe(true);
|
|
84
|
+
// 1 extracted twice (first fill, then re-fill after eviction).
|
|
85
|
+
expect(extracted.filter((id) => id === 1).length).toBe(2);
|
|
86
|
+
});
|
|
87
|
+
test("requesting an already-resident product does not re-extract", () => {
|
|
88
|
+
const { tiles, extracted } = mockTiles(10);
|
|
89
|
+
const q = new DemandGeometryQueue(tiles, 1000);
|
|
90
|
+
q.request(1, 10);
|
|
91
|
+
q.pump();
|
|
92
|
+
q.request(1, 99); // already resident — just bumps ranking
|
|
93
|
+
q.pump();
|
|
94
|
+
expect(extracted).toEqual([1]);
|
|
95
|
+
});
|
|
96
|
+
test("a per-pump extraction cap bounds work per call", () => {
|
|
97
|
+
const { tiles } = mockTiles(1);
|
|
98
|
+
const q = new DemandGeometryQueue(tiles, 1000000);
|
|
99
|
+
for (let id = 0; id < 100; ++id) {
|
|
100
|
+
q.request(id, id);
|
|
101
|
+
}
|
|
102
|
+
expect(q.pump(10)).toBe(10);
|
|
103
|
+
expect(q.stats.residentCount).toBe(10);
|
|
104
|
+
expect(q.stats.pendingCount).toBe(90);
|
|
105
|
+
});
|
|
106
|
+
test("evictAll releases everything", () => {
|
|
107
|
+
const { tiles, released } = mockTiles(10);
|
|
108
|
+
const q = new DemandGeometryQueue(tiles, 1000);
|
|
109
|
+
for (let id = 0; id < 5; ++id) {
|
|
110
|
+
q.request(id, id);
|
|
111
|
+
}
|
|
112
|
+
q.pump();
|
|
113
|
+
q.evictAll();
|
|
114
|
+
expect(q.stats.residentCount).toBe(0);
|
|
115
|
+
expect(q.stats.residentBytes).toBe(0);
|
|
116
|
+
expect(released.sort()).toEqual([0, 1, 2, 3, 4]);
|
|
117
|
+
});
|
|
118
|
+
test("keeps the resident set bounded by the budget across a demand stream", () => {
|
|
119
|
+
const { tiles } = mockTiles(100);
|
|
120
|
+
const q = new DemandGeometryQueue(tiles, 500); // holds 5
|
|
121
|
+
// A moving "viewport": 200 products stream past with rising priority.
|
|
122
|
+
for (let id = 0; id < 200; ++id) {
|
|
123
|
+
q.request(id, id);
|
|
124
|
+
q.pump();
|
|
125
|
+
expect(q.stats.residentBytes).toBeLessThanOrEqual(500);
|
|
126
|
+
}
|
|
127
|
+
// The 5 most-wanted (highest ids) remain.
|
|
128
|
+
expect(q.stats.residentCount).toBe(5);
|
|
129
|
+
for (const id of [195, 196, 197, 198, 199]) {
|
|
130
|
+
expect(q.isResident(id)).toBe(true);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|