@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,211 @@
|
|
|
1
|
+
/* eslint-disable no-magic-numbers */
|
|
2
|
+
// Phase B: the wasm-backed tile composition — TS accounting over the module's
|
|
3
|
+
// physical pool — and the segment-walk payload reader, verified against a
|
|
4
|
+
// faithful in-memory fake of the embind surface (same layout, same chunking,
|
|
5
|
+
// same non-contiguous segments a fragmented pool produces).
|
|
6
|
+
import { describe, expect, test } from "@jest/globals";
|
|
7
|
+
import { DemandGeometryQueue } from "./demand_geometry_queue.js";
|
|
8
|
+
import { createWasmTileBackend, readGeometryTilePayload, } from "./geometry_tile_bindings.js";
|
|
9
|
+
const HEADER_BYTES = 8;
|
|
10
|
+
/**
|
|
11
|
+
* A faithful in-memory fake of the wasm tile pool bindings: a byte "heap"
|
|
12
|
+
* carved into chunks with a LIFO freelist, tiles committed as (possibly
|
|
13
|
+
* non-contiguous) chunk lists — the same observable behaviour as the C++
|
|
14
|
+
* TilePool through the embind surface.
|
|
15
|
+
*
|
|
16
|
+
* @return {object} `{ bindings, heap, commitPayload }` where commitPayload
|
|
17
|
+
* scatter-commits a payload built from header+floats+indices.
|
|
18
|
+
*/
|
|
19
|
+
function fakeWasmPool() {
|
|
20
|
+
const HEAP_BYTES = 64 * 1024;
|
|
21
|
+
const heap = new Uint8Array(HEAP_BYTES);
|
|
22
|
+
let chunkBytes = 0;
|
|
23
|
+
let regionBase = 0;
|
|
24
|
+
let freeList = [];
|
|
25
|
+
const tiles = new Map();
|
|
26
|
+
let failedCommits = 0;
|
|
27
|
+
let totalChunks = 0;
|
|
28
|
+
const bindings = {
|
|
29
|
+
initGeometryTilePool: (budget, chunk) => {
|
|
30
|
+
if (chunk < 16 || budget < chunk) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
chunkBytes = chunk;
|
|
34
|
+
totalChunks = Math.floor(budget / chunk);
|
|
35
|
+
regionBase = 1024; // nonzero base, like a real heap allocation
|
|
36
|
+
freeList = [];
|
|
37
|
+
for (let c = totalChunks - 1; c >= 0; --c) {
|
|
38
|
+
freeList.push(c);
|
|
39
|
+
}
|
|
40
|
+
tiles.clear();
|
|
41
|
+
return true;
|
|
42
|
+
},
|
|
43
|
+
geometryTilePoolInitialized: () => chunkBytes > 0,
|
|
44
|
+
commitGeometryTileBytes: (assetID, sourceAddress, byteLength) => {
|
|
45
|
+
const needed = Math.ceil(byteLength / chunkBytes);
|
|
46
|
+
if (tiles.has(assetID) || needed > freeList.length) {
|
|
47
|
+
++failedCommits;
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const chunks = [];
|
|
51
|
+
let copied = 0;
|
|
52
|
+
for (let where = 0; where < needed; ++where) {
|
|
53
|
+
const chunk = freeList.pop();
|
|
54
|
+
chunks.push(chunk);
|
|
55
|
+
const span = Math.min(byteLength - copied, chunkBytes);
|
|
56
|
+
heap.set(heap.subarray(sourceAddress + copied, sourceAddress + copied + span), regionBase + chunk * chunkBytes);
|
|
57
|
+
copied += span;
|
|
58
|
+
}
|
|
59
|
+
tiles.set(assetID, { chunks, byteSize: byteLength, refCount: 1 });
|
|
60
|
+
return true;
|
|
61
|
+
},
|
|
62
|
+
retainGeometryTile: (assetID) => {
|
|
63
|
+
const tile = tiles.get(assetID);
|
|
64
|
+
if (tile === void 0) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
++tile.refCount;
|
|
68
|
+
return true;
|
|
69
|
+
},
|
|
70
|
+
releaseGeometryTile: (assetID) => {
|
|
71
|
+
const tile = tiles.get(assetID);
|
|
72
|
+
if (tile === void 0) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
if (--tile.refCount > 0) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
freeList.push(...tile.chunks);
|
|
79
|
+
tiles.delete(assetID);
|
|
80
|
+
return true;
|
|
81
|
+
},
|
|
82
|
+
geometryTileResident: (assetID) => tiles.has(assetID),
|
|
83
|
+
geometryTileRefCount: (assetID) => tiles.get(assetID)?.refCount ?? 0,
|
|
84
|
+
geometryTileByteSize: (assetID) => tiles.get(assetID)?.byteSize ?? 0,
|
|
85
|
+
geometryTileSegmentCount: (assetID) => tiles.get(assetID)?.chunks.length ?? 0,
|
|
86
|
+
geometryTileSegmentAddress: (assetID, segment) => {
|
|
87
|
+
const tile = tiles.get(assetID);
|
|
88
|
+
if (tile === void 0 || segment >= tile.chunks.length) {
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
return regionBase + tile.chunks[segment] * chunkBytes;
|
|
92
|
+
},
|
|
93
|
+
geometryTileSegmentByteLength: (assetID, segment) => {
|
|
94
|
+
const tile = tiles.get(assetID);
|
|
95
|
+
if (tile === void 0 || segment >= tile.chunks.length) {
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
return Math.min(tile.byteSize - segment * chunkBytes, chunkBytes);
|
|
99
|
+
},
|
|
100
|
+
geometryTileVertexByteLength: (assetID) => {
|
|
101
|
+
const address = bindings.geometryTileSegmentAddress(assetID, 0);
|
|
102
|
+
return address === 0 ?
|
|
103
|
+
0 : new DataView(heap.buffer).getUint32(address, true);
|
|
104
|
+
},
|
|
105
|
+
geometryTileIndexByteLength: (assetID) => {
|
|
106
|
+
const address = bindings.geometryTileSegmentAddress(assetID, 0);
|
|
107
|
+
return address === 0 ?
|
|
108
|
+
0 : new DataView(heap.buffer).getUint32(address + 4, true);
|
|
109
|
+
},
|
|
110
|
+
geometryTilePoolBytesInUse: () => (totalChunks - freeList.length) * chunkBytes,
|
|
111
|
+
geometryTilePoolTotalBytes: () => totalChunks * chunkBytes,
|
|
112
|
+
geometryTilePoolFreeChunks: () => freeList.length,
|
|
113
|
+
geometryTilePoolFailedCommits: () => failedCommits,
|
|
114
|
+
};
|
|
115
|
+
// Stage a payload high in the fake heap and scatter-commit it.
|
|
116
|
+
const commitPayload = (assetID, floats, indices) => {
|
|
117
|
+
const staging = HEAP_BYTES - 8192;
|
|
118
|
+
const view = new DataView(heap.buffer, staging);
|
|
119
|
+
view.setUint32(0, floats.length * 4, true);
|
|
120
|
+
view.setUint32(4, indices.length * 4, true);
|
|
121
|
+
floats.forEach((value, i) => view.setFloat32(HEADER_BYTES + i * 4, value, true));
|
|
122
|
+
indices.forEach((value, i) => view.setUint32(HEADER_BYTES + floats.length * 4 + i * 4, value, true));
|
|
123
|
+
return bindings.commitGeometryTileBytes(assetID, staging, HEADER_BYTES + floats.length * 4 + indices.length * 4);
|
|
124
|
+
};
|
|
125
|
+
return { bindings, heap, commitPayload };
|
|
126
|
+
}
|
|
127
|
+
describe("createWasmTileBackend", () => {
|
|
128
|
+
test("composes TS accounting over the wasm pool end to end with the queue", () => {
|
|
129
|
+
const { bindings, commitPayload } = fakeWasmPool();
|
|
130
|
+
// Two products share one representation; extraction commits real bytes.
|
|
131
|
+
const composition = {
|
|
132
|
+
1: [{ assetID: 100, byteSize: 200 }],
|
|
133
|
+
2: [{ assetID: 100, byteSize: 200 }, { assetID: 200, byteSize: 100 }],
|
|
134
|
+
};
|
|
135
|
+
const extracted = [];
|
|
136
|
+
const extractor = {
|
|
137
|
+
assetsOf: (id) => composition[id] ?? [],
|
|
138
|
+
extractIntoTile: (assetID) => {
|
|
139
|
+
extracted.push(assetID);
|
|
140
|
+
if (!commitPayload(assetID, [1, 2, 3], [0, 1, 2])) {
|
|
141
|
+
throw new Error("commit failed");
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
const backend = createWasmTileBackend(bindings, extractor, 4096, 64);
|
|
146
|
+
const queue = new DemandGeometryQueue(backend.tiles, 4096);
|
|
147
|
+
queue.request(1, 10);
|
|
148
|
+
queue.request(2, 20);
|
|
149
|
+
queue.pump();
|
|
150
|
+
// Shared asset extracted once; both tiles resident wasm-side.
|
|
151
|
+
expect(extracted).toEqual([100, 200]);
|
|
152
|
+
expect(bindings.geometryTileResident(100)).toBe(true);
|
|
153
|
+
expect(bindings.geometryTileResident(200)).toBe(true);
|
|
154
|
+
// Evicting product 2 releases only its unique asset (100 is shared).
|
|
155
|
+
queue.evictAll();
|
|
156
|
+
expect(bindings.geometryTileResident(100)).toBe(false);
|
|
157
|
+
expect(bindings.geometryTileResident(200)).toBe(false);
|
|
158
|
+
expect(bindings.geometryTilePoolBytesInUse()).toBe(0);
|
|
159
|
+
});
|
|
160
|
+
test("rejects a config the wasm pool refuses", () => {
|
|
161
|
+
const { bindings } = fakeWasmPool();
|
|
162
|
+
const extractor = {
|
|
163
|
+
assetsOf: () => [],
|
|
164
|
+
extractIntoTile: () => { },
|
|
165
|
+
};
|
|
166
|
+
expect(() => createWasmTileBackend(bindings, extractor, 4096, 8))
|
|
167
|
+
.toThrow(/rejected init/);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
describe("readGeometryTilePayload", () => {
|
|
171
|
+
test("gathers a multi-segment payload back to exact typed arrays", () => {
|
|
172
|
+
const { bindings, heap, commitPayload } = fakeWasmPool();
|
|
173
|
+
bindings.initGeometryTilePool(4096, 64);
|
|
174
|
+
// 40 floats + 20 indices + header = 248 bytes over 64-byte chunks →
|
|
175
|
+
// 4 non-contiguous segments with a partial tail.
|
|
176
|
+
const floats = Array.from({ length: 40 }, (_v, i) => i * 0.5);
|
|
177
|
+
const indices = Array.from({ length: 20 }, (_v, i) => i * 3);
|
|
178
|
+
expect(commitPayload(7, floats, indices)).toBe(true);
|
|
179
|
+
expect(bindings.geometryTileSegmentCount(7)).toBe(4);
|
|
180
|
+
const payload = readGeometryTilePayload(bindings, heap, 7);
|
|
181
|
+
expect(Array.from(payload.vertexData)).toEqual(floats);
|
|
182
|
+
expect(Array.from(payload.indexData)).toEqual(indices);
|
|
183
|
+
expect(bindings.geometryTileVertexByteLength(7)).toBe(160);
|
|
184
|
+
expect(bindings.geometryTileIndexByteLength(7)).toBe(80);
|
|
185
|
+
});
|
|
186
|
+
test("survives freelist fragmentation (interleaved tiles)", () => {
|
|
187
|
+
const { bindings, heap, commitPayload } = fakeWasmPool();
|
|
188
|
+
bindings.initGeometryTilePool(4096, 64);
|
|
189
|
+
commitPayload(1, [1, 1, 1, 1], [1]);
|
|
190
|
+
commitPayload(2, Array(30).fill(2), [2, 2]);
|
|
191
|
+
bindings.releaseGeometryTile(1);
|
|
192
|
+
// Tile 3's chunks interleave with tile 2's.
|
|
193
|
+
const floats = Array.from({ length: 25 }, (_v, i) => i + 0.25);
|
|
194
|
+
commitPayload(3, floats, [9, 8, 7]);
|
|
195
|
+
const payload = readGeometryTilePayload(bindings, heap, 3);
|
|
196
|
+
expect(Array.from(payload.vertexData)).toEqual(floats);
|
|
197
|
+
expect(Array.from(payload.indexData)).toEqual([9, 8, 7]);
|
|
198
|
+
});
|
|
199
|
+
test("rejects a non-resident tile and a corrupt header", () => {
|
|
200
|
+
const { bindings, heap, commitPayload } = fakeWasmPool();
|
|
201
|
+
bindings.initGeometryTilePool(4096, 64);
|
|
202
|
+
expect(() => readGeometryTilePayload(bindings, heap, 42))
|
|
203
|
+
.toThrow(/not resident/);
|
|
204
|
+
commitPayload(5, [1], [2]);
|
|
205
|
+
// Corrupt the header's vertex byte length in place.
|
|
206
|
+
const address = bindings.geometryTileSegmentAddress(5, 0);
|
|
207
|
+
new DataView(heap.buffer).setUint32(address, 9999, true);
|
|
208
|
+
expect(() => readGeometryTilePayload(bindings, heap, 5))
|
|
209
|
+
.toThrow(/inconsistent/);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { GeometryTiles } from "./demand_geometry_queue.js";
|
|
2
|
+
import { ChunkedPool } from "./mem/chunked_pool.js";
|
|
3
|
+
import { SharedAssetPool } from "./mem/shared_asset_pool.js";
|
|
4
|
+
/**
|
|
5
|
+
* One shareable geometry payload an instance needs resident: the asset's
|
|
6
|
+
* identity and its byte size. For IFC, the asset is a representation's
|
|
7
|
+
* tessellated geometry and `byteSize` comes from the wasm-side extract.
|
|
8
|
+
*/
|
|
9
|
+
export interface GeometryAsset<AssetID> {
|
|
10
|
+
assetID: AssetID;
|
|
11
|
+
byteSize: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The domain half the tile pool delegates to: what assets an instance is made
|
|
15
|
+
* of, and how to materialise / discard one asset's payload. This is the seam
|
|
16
|
+
* the production conway-geom surface implements (extract → tessellate into
|
|
17
|
+
* the asset's chunks; discard on last release); tests implement it with
|
|
18
|
+
* recording mocks.
|
|
19
|
+
*/
|
|
20
|
+
export interface InstanceAssetSource<AssetID> {
|
|
21
|
+
/**
|
|
22
|
+
* The assets an instance requires resident, with their byte sizes. For a
|
|
23
|
+
* simple product this is one asset; mapped/instanced representations return
|
|
24
|
+
* the same assetID from many instances — that sharing is the point.
|
|
25
|
+
*
|
|
26
|
+
* @param instanceID The instance (product local ID in the geometry case).
|
|
27
|
+
* @return {GeometryAsset<AssetID>[]} The instance's assets.
|
|
28
|
+
*/
|
|
29
|
+
assetsOf(instanceID: number): GeometryAsset<AssetID>[];
|
|
30
|
+
/**
|
|
31
|
+
* Materialise an asset's payload (called exactly once per residency, on
|
|
32
|
+
* the 0→1 reference). In production: run the wasm extract/tessellate and
|
|
33
|
+
* write the result into the asset's pool chunks.
|
|
34
|
+
*
|
|
35
|
+
* @param assetID The asset to materialise.
|
|
36
|
+
*/
|
|
37
|
+
materialize(assetID: AssetID): void;
|
|
38
|
+
/**
|
|
39
|
+
* Discard an asset's payload (called exactly once per residency, on the
|
|
40
|
+
* 1→0 reference, after its chunks are already back in the pool).
|
|
41
|
+
*
|
|
42
|
+
* @param assetID The asset to discard.
|
|
43
|
+
*/
|
|
44
|
+
discard(assetID: AssetID): void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The geometry narrowing of the general memory system (`src/core/mem/`): a
|
|
48
|
+
* {@link GeometryTiles} backend where a product's "tile" is a set of
|
|
49
|
+
* refcounted, chunk-resident **assets** in a {@link SharedAssetPool}.
|
|
50
|
+
*
|
|
51
|
+
* Composed with {@link DemandGeometryQueue} this completes the M3 resident
|
|
52
|
+
* design: the queue owns demand ordering and the logical budget; this pool
|
|
53
|
+
* owns physical residency. Two accounting views, one invariant:
|
|
54
|
+
*
|
|
55
|
+
* - **Logical (queue-side):** `extract` charges an instance the full
|
|
56
|
+
* chunk-rounded cost of *every* asset it references, shared or not. Sharing
|
|
57
|
+
* is thus double-charged logically — deliberately conservative: summed
|
|
58
|
+
* logical charges always cover physical use, so with the queue's budget set
|
|
59
|
+
* to the pool's budget, an acquire can never fail mid-extract. (Heavy
|
|
60
|
+
* sharing under-utilises the logical budget; the production wiring can
|
|
61
|
+
* widen the queue budget once measured. The safe direction first.)
|
|
62
|
+
* - **Physical (pool-side):** `bytesInUse` counts real chunks. Shared assets
|
|
63
|
+
* are stored once, refcounted, and freed only on the last release — so
|
|
64
|
+
* evicting product A never discards the representation product B still
|
|
65
|
+
* renders (the mapped-item correctness rule, held structurally).
|
|
66
|
+
*/
|
|
67
|
+
export declare class GeometryTilePool<AssetID> implements GeometryTiles {
|
|
68
|
+
private readonly assets_;
|
|
69
|
+
private readonly source_;
|
|
70
|
+
/** Assets each extracted instance holds references on. */
|
|
71
|
+
private readonly held_;
|
|
72
|
+
/**
|
|
73
|
+
* @param pool The chunk pool residents live in.
|
|
74
|
+
* @param source The domain half (asset composition + materialise/discard).
|
|
75
|
+
*/
|
|
76
|
+
constructor(pool: ChunkedPool, source: InstanceAssetSource<AssetID>);
|
|
77
|
+
/**
|
|
78
|
+
* @return {SharedAssetPool<AssetID>} The refcounted asset layer (physical
|
|
79
|
+
* accounting lives here / on its pool).
|
|
80
|
+
*/
|
|
81
|
+
get assets(): SharedAssetPool<AssetID>;
|
|
82
|
+
/**
|
|
83
|
+
* Materialise an instance's tile: take a reference on each of its assets,
|
|
84
|
+
* materialising the ones not yet resident.
|
|
85
|
+
*
|
|
86
|
+
* @param instanceID The instance (product local ID).
|
|
87
|
+
* @return {number} The instance's logical byte cost (chunk-rounded, every
|
|
88
|
+
* asset fully charged — see class docs for why sharing is double-charged).
|
|
89
|
+
*/
|
|
90
|
+
extract(instanceID: number): number;
|
|
91
|
+
/**
|
|
92
|
+
* Release an instance's tile: drop the reference on each of its assets,
|
|
93
|
+
* discarding those this instance was the last holder of.
|
|
94
|
+
*
|
|
95
|
+
* @param instanceID The instance (product local ID).
|
|
96
|
+
*/
|
|
97
|
+
release(instanceID: number): void;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=geometry_tile_pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry_tile_pool.d.ts","sourceRoot":"","sources":["../../../src/core/geometry_tile_pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAGzD;;;;GAIG;AACH,MAAM,WAAW,aAAa,CAAC,OAAO;IACpC,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAGD;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB,CAAC,OAAO;IAE1C;;;;;;;OAOG;IACH,QAAQ,CAAE,UAAU,EAAE,MAAM,GAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAA;IAExD;;;;;;OAMG;IACH,WAAW,CAAE,OAAO,EAAE,OAAO,GAAI,IAAI,CAAA;IAErC;;;;;OAKG;IACH,OAAO,CAAE,OAAO,EAAE,OAAO,GAAI,IAAI,CAAA;CAClC;AAGD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,gBAAgB,CAAC,OAAO,CAAE,YAAW,aAAa;IAE7D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAElD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;IAEtD,0DAA0D;IAC1D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8C;IAEpE;;;OAGG;gBACU,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,mBAAmB,CAAC,OAAO,CAAC;IAKpE;;;OAGG;IACH,IAAW,MAAM,IAAI,eAAe,CAAC,OAAO,CAAC,CAE5C;IAED;;;;;;;OAOG;IACI,OAAO,CAAE,UAAU,EAAE,MAAM,GAAI,MAAM;IAoD5C;;;;;OAKG;IACI,OAAO,CAAE,UAAU,EAAE,MAAM,GAAI,IAAI;CAgB3C"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { SharedAssetPool } from "./mem/shared_asset_pool.js";
|
|
2
|
+
/**
|
|
3
|
+
* The geometry narrowing of the general memory system (`src/core/mem/`): a
|
|
4
|
+
* {@link GeometryTiles} backend where a product's "tile" is a set of
|
|
5
|
+
* refcounted, chunk-resident **assets** in a {@link SharedAssetPool}.
|
|
6
|
+
*
|
|
7
|
+
* Composed with {@link DemandGeometryQueue} this completes the M3 resident
|
|
8
|
+
* design: the queue owns demand ordering and the logical budget; this pool
|
|
9
|
+
* owns physical residency. Two accounting views, one invariant:
|
|
10
|
+
*
|
|
11
|
+
* - **Logical (queue-side):** `extract` charges an instance the full
|
|
12
|
+
* chunk-rounded cost of *every* asset it references, shared or not. Sharing
|
|
13
|
+
* is thus double-charged logically — deliberately conservative: summed
|
|
14
|
+
* logical charges always cover physical use, so with the queue's budget set
|
|
15
|
+
* to the pool's budget, an acquire can never fail mid-extract. (Heavy
|
|
16
|
+
* sharing under-utilises the logical budget; the production wiring can
|
|
17
|
+
* widen the queue budget once measured. The safe direction first.)
|
|
18
|
+
* - **Physical (pool-side):** `bytesInUse` counts real chunks. Shared assets
|
|
19
|
+
* are stored once, refcounted, and freed only on the last release — so
|
|
20
|
+
* evicting product A never discards the representation product B still
|
|
21
|
+
* renders (the mapped-item correctness rule, held structurally).
|
|
22
|
+
*/
|
|
23
|
+
export class GeometryTilePool {
|
|
24
|
+
/**
|
|
25
|
+
* @param pool The chunk pool residents live in.
|
|
26
|
+
* @param source The domain half (asset composition + materialise/discard).
|
|
27
|
+
*/
|
|
28
|
+
constructor(pool, source) {
|
|
29
|
+
/** Assets each extracted instance holds references on. */
|
|
30
|
+
this.held_ = new Map();
|
|
31
|
+
this.assets_ = new SharedAssetPool(pool);
|
|
32
|
+
this.source_ = source;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @return {SharedAssetPool<AssetID>} The refcounted asset layer (physical
|
|
36
|
+
* accounting lives here / on its pool).
|
|
37
|
+
*/
|
|
38
|
+
get assets() {
|
|
39
|
+
return this.assets_;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Materialise an instance's tile: take a reference on each of its assets,
|
|
43
|
+
* materialising the ones not yet resident.
|
|
44
|
+
*
|
|
45
|
+
* @param instanceID The instance (product local ID).
|
|
46
|
+
* @return {number} The instance's logical byte cost (chunk-rounded, every
|
|
47
|
+
* asset fully charged — see class docs for why sharing is double-charged).
|
|
48
|
+
*/
|
|
49
|
+
extract(instanceID) {
|
|
50
|
+
if (this.held_.has(instanceID)) {
|
|
51
|
+
throw new Error(`Instance ${instanceID} already extracted`);
|
|
52
|
+
}
|
|
53
|
+
const assets = this.source_.assetsOf(instanceID);
|
|
54
|
+
const pool = this.assets_.pool;
|
|
55
|
+
// Validate and price every asset BEFORE taking any references, so a bad
|
|
56
|
+
// byte size (a source bug) throws at zero state instead of mid-extract
|
|
57
|
+
// with references already taken. chunkRound throws on negatives.
|
|
58
|
+
let logicalBytes = 0;
|
|
59
|
+
for (const asset of assets) {
|
|
60
|
+
logicalBytes += pool.chunkRound(asset.byteSize);
|
|
61
|
+
}
|
|
62
|
+
for (const asset of assets) {
|
|
63
|
+
const { retained, wasAbsent } = this.assets_.retain(asset.assetID, asset.byteSize);
|
|
64
|
+
if (!retained) {
|
|
65
|
+
// Unwind references already taken so a failed extract has no effect —
|
|
66
|
+
// keeping the materialize/discard pairing: an asset this unwind takes
|
|
67
|
+
// to zero references must be discarded like any other last release.
|
|
68
|
+
for (const taken of assets) {
|
|
69
|
+
if (taken === asset) {
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
if (this.assets_.release(taken.assetID)) {
|
|
73
|
+
this.source_.discard(taken.assetID);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
throw new Error(`Geometry pool exhausted materialising instance ${instanceID} — ` +
|
|
77
|
+
"the scheduler budget must not exceed the pool budget");
|
|
78
|
+
}
|
|
79
|
+
if (wasAbsent) {
|
|
80
|
+
this.source_.materialize(asset.assetID);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
this.held_.set(instanceID, assets);
|
|
84
|
+
return logicalBytes;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Release an instance's tile: drop the reference on each of its assets,
|
|
88
|
+
* discarding those this instance was the last holder of.
|
|
89
|
+
*
|
|
90
|
+
* @param instanceID The instance (product local ID).
|
|
91
|
+
*/
|
|
92
|
+
release(instanceID) {
|
|
93
|
+
const assets = this.held_.get(instanceID);
|
|
94
|
+
if (assets === void 0) {
|
|
95
|
+
throw new Error(`Release of un-extracted instance ${instanceID}`);
|
|
96
|
+
}
|
|
97
|
+
this.held_.delete(instanceID);
|
|
98
|
+
for (const asset of assets) {
|
|
99
|
+
if (this.assets_.release(asset.assetID)) {
|
|
100
|
+
this.source_.discard(asset.assetID);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry_tile_pool.test.d.ts","sourceRoot":"","sources":["../../../src/core/geometry_tile_pool.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/* eslint-disable no-magic-numbers */
|
|
2
|
+
// M3 production design: the geometry narrowing of the mem system, alone and
|
|
3
|
+
// composed with DemandGeometryQueue. The load-bearing assertions: shared
|
|
4
|
+
// representations are stored once and never freed while any product still
|
|
5
|
+
// holds them, and the queue's logical budget always covers the pool's
|
|
6
|
+
// physical use (so an extract can never blow the pool mid-flight).
|
|
7
|
+
import { describe, expect, test } from "@jest/globals";
|
|
8
|
+
import { DemandGeometryQueue } from "./demand_geometry_queue.js";
|
|
9
|
+
import { GeometryTilePool } from "./geometry_tile_pool.js";
|
|
10
|
+
import { ChunkedPool } from "./mem/chunked_pool.js";
|
|
11
|
+
/**
|
|
12
|
+
* A recording mock of the domain half: instance → assets from a fixture map,
|
|
13
|
+
* with materialize/discard calls captured.
|
|
14
|
+
*
|
|
15
|
+
* @param composition Instance → assets fixture.
|
|
16
|
+
* @return {object} `{ source, materialized, discarded }`.
|
|
17
|
+
*/
|
|
18
|
+
function mockSource(composition) {
|
|
19
|
+
const materialized = [];
|
|
20
|
+
const discarded = [];
|
|
21
|
+
const source = {
|
|
22
|
+
assetsOf: (instanceID) => composition[instanceID] ?? [],
|
|
23
|
+
materialize: (assetID) => {
|
|
24
|
+
materialized.push(assetID);
|
|
25
|
+
},
|
|
26
|
+
discard: (assetID) => {
|
|
27
|
+
discarded.push(assetID);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
return { source, materialized, discarded };
|
|
31
|
+
}
|
|
32
|
+
describe("GeometryTilePool", () => {
|
|
33
|
+
test("a shared representation is materialised once and stored once", () => {
|
|
34
|
+
// Products 1 and 2 both instance rep-X (mapped item); 2 also has its own.
|
|
35
|
+
const { source, materialized } = mockSource({
|
|
36
|
+
1: [{ assetID: "rep-X", byteSize: 100 }],
|
|
37
|
+
2: [{ assetID: "rep-X", byteSize: 100 }, { assetID: "rep-Y", byteSize: 100 }],
|
|
38
|
+
});
|
|
39
|
+
const tiles = new GeometryTilePool(new ChunkedPool(1000, 100), source);
|
|
40
|
+
tiles.extract(1);
|
|
41
|
+
tiles.extract(2);
|
|
42
|
+
expect(materialized).toEqual(["rep-X", "rep-Y"]);
|
|
43
|
+
// Physically: two assets, 200 bytes — not 300.
|
|
44
|
+
expect(tiles.assets.pool.bytesInUse).toBe(200);
|
|
45
|
+
expect(tiles.assets.refCountOf("rep-X")).toBe(2);
|
|
46
|
+
});
|
|
47
|
+
test("evicting one product never discards a representation another still renders", () => {
|
|
48
|
+
const { source, discarded } = mockSource({
|
|
49
|
+
1: [{ assetID: "rep-X", byteSize: 100 }],
|
|
50
|
+
2: [{ assetID: "rep-X", byteSize: 100 }],
|
|
51
|
+
});
|
|
52
|
+
const tiles = new GeometryTilePool(new ChunkedPool(1000, 100), source);
|
|
53
|
+
tiles.extract(1);
|
|
54
|
+
tiles.extract(2);
|
|
55
|
+
tiles.release(1);
|
|
56
|
+
expect(discarded).toEqual([]);
|
|
57
|
+
expect(tiles.assets.isResident("rep-X")).toBe(true);
|
|
58
|
+
tiles.release(2);
|
|
59
|
+
expect(discarded).toEqual(["rep-X"]);
|
|
60
|
+
expect(tiles.assets.pool.bytesInUse).toBe(0);
|
|
61
|
+
});
|
|
62
|
+
test("extract charges the logical (chunk-rounded, fully-charged) cost", () => {
|
|
63
|
+
const { source } = mockSource({
|
|
64
|
+
1: [{ assetID: "a", byteSize: 150 }, { assetID: "b", byteSize: 10 }],
|
|
65
|
+
2: [{ assetID: "a", byteSize: 150 }],
|
|
66
|
+
});
|
|
67
|
+
const tiles = new GeometryTilePool(new ChunkedPool(1000, 100), source);
|
|
68
|
+
// 150 → 200 rounded, 10 → 100 rounded.
|
|
69
|
+
expect(tiles.extract(1)).toBe(300);
|
|
70
|
+
// Sharing is deliberately double-charged logically (conservative)...
|
|
71
|
+
expect(tiles.extract(2)).toBe(200);
|
|
72
|
+
// ...while physical stays single-stored.
|
|
73
|
+
expect(tiles.assets.pool.bytesInUse).toBe(300);
|
|
74
|
+
});
|
|
75
|
+
test("a failed extract unwinds cleanly, discarding what it materialised", () => {
|
|
76
|
+
// Asset a fits; asset b cannot (pool holds 2 chunks, b needs 3). The
|
|
77
|
+
// extract must throw, and the unwind must keep the materialize/discard
|
|
78
|
+
// pairing for a (which it took to zero references) and leave the pool
|
|
79
|
+
// exactly as before — a failed extract has no effect.
|
|
80
|
+
const { source, materialized, discarded } = mockSource({
|
|
81
|
+
1: [{ assetID: "a", byteSize: 100 }, { assetID: "b", byteSize: 300 }],
|
|
82
|
+
});
|
|
83
|
+
const pool = new ChunkedPool(200, 100);
|
|
84
|
+
const tiles = new GeometryTilePool(pool, source);
|
|
85
|
+
expect(() => tiles.extract(1)).toThrow(/exhausted/);
|
|
86
|
+
expect(materialized).toEqual(["a"]);
|
|
87
|
+
expect(discarded).toEqual(["a"]);
|
|
88
|
+
expect(pool.bytesInUse).toBe(0);
|
|
89
|
+
expect(tiles.assets.isResident("a")).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
test("a failed extract never discards an asset another instance still holds", () => {
|
|
92
|
+
// Instance 1 holds shared. Instance 2 wants shared + big; big fails.
|
|
93
|
+
// The unwind drops 2's reference on shared but must NOT discard it —
|
|
94
|
+
// instance 1 still renders it.
|
|
95
|
+
const { source, discarded } = mockSource({
|
|
96
|
+
1: [{ assetID: "shared", byteSize: 100 }],
|
|
97
|
+
2: [{ assetID: "shared", byteSize: 100 }, { assetID: "big", byteSize: 300 }],
|
|
98
|
+
});
|
|
99
|
+
const pool = new ChunkedPool(200, 100);
|
|
100
|
+
const tiles = new GeometryTilePool(pool, source);
|
|
101
|
+
tiles.extract(1);
|
|
102
|
+
expect(() => tiles.extract(2)).toThrow(/exhausted/);
|
|
103
|
+
expect(discarded).toEqual([]);
|
|
104
|
+
expect(tiles.assets.isResident("shared")).toBe(true);
|
|
105
|
+
expect(tiles.assets.refCountOf("shared")).toBe(1);
|
|
106
|
+
expect(pool.bytesInUse).toBe(100);
|
|
107
|
+
});
|
|
108
|
+
test("double extract and unmatched release are errors", () => {
|
|
109
|
+
const { source } = mockSource({ 1: [{ assetID: "a", byteSize: 10 }] });
|
|
110
|
+
const tiles = new GeometryTilePool(new ChunkedPool(1000, 100), source);
|
|
111
|
+
tiles.extract(1);
|
|
112
|
+
expect(() => tiles.extract(1)).toThrow(/already extracted/);
|
|
113
|
+
expect(() => tiles.release(2)).toThrow(/un-extracted/);
|
|
114
|
+
});
|
|
115
|
+
test("a malformed byte size throws before any state changes", () => {
|
|
116
|
+
// A buggy source returning a negative size must fail at zero state —
|
|
117
|
+
// no references taken, nothing materialised, pool untouched.
|
|
118
|
+
const { source, materialized } = mockSource({
|
|
119
|
+
1: [{ assetID: "ok", byteSize: 100 }, { assetID: "bad", byteSize: -5 }],
|
|
120
|
+
});
|
|
121
|
+
const pool = new ChunkedPool(1000, 100);
|
|
122
|
+
const tiles = new GeometryTilePool(pool, source);
|
|
123
|
+
expect(() => tiles.extract(1)).toThrow(/Invalid byte size/);
|
|
124
|
+
expect(materialized).toEqual([]);
|
|
125
|
+
expect(pool.bytesInUse).toBe(0);
|
|
126
|
+
expect(tiles.assets.isResident("ok")).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
test("composed with the demand queue: budget holds, shared reps survive eviction", () => {
|
|
129
|
+
// 20 products all sharing one heavy rep, each with a light unique rep —
|
|
130
|
+
// the mapped-item shape (fixtures, repeated windows).
|
|
131
|
+
const composition = {};
|
|
132
|
+
for (let id = 0; id < 20; ++id) {
|
|
133
|
+
composition[id] = [
|
|
134
|
+
{ assetID: "shared-heavy", byteSize: 400 },
|
|
135
|
+
{ assetID: `unique-${id}`, byteSize: 100 },
|
|
136
|
+
];
|
|
137
|
+
}
|
|
138
|
+
const { source, materialized, discarded } = mockSource(composition);
|
|
139
|
+
const pool = new ChunkedPool(4000, 100);
|
|
140
|
+
const tiles = new GeometryTilePool(pool, source);
|
|
141
|
+
// Queue budget == pool budget: the safety invariant under test.
|
|
142
|
+
const queue = new DemandGeometryQueue(tiles, 4000);
|
|
143
|
+
// Stream demand across all 20 products with rising priority.
|
|
144
|
+
for (let id = 0; id < 20; ++id) {
|
|
145
|
+
queue.request(id, id);
|
|
146
|
+
queue.pump();
|
|
147
|
+
// Physical use never exceeds the logical budget the queue enforces.
|
|
148
|
+
expect(pool.bytesInUse).toBeLessThanOrEqual(queue.stats.residentBytes);
|
|
149
|
+
expect(queue.stats.residentBytes).toBeLessThanOrEqual(4000);
|
|
150
|
+
}
|
|
151
|
+
// The shared rep was materialised exactly once across all that churn...
|
|
152
|
+
expect(materialized.filter((a) => a === "shared-heavy").length).toBe(1);
|
|
153
|
+
// ...and never discarded, because some product always held it.
|
|
154
|
+
expect(discarded).not.toContain("shared-heavy");
|
|
155
|
+
// Evicting everything finally discards it and empties the pool.
|
|
156
|
+
queue.evictAll();
|
|
157
|
+
expect(discarded).toContain("shared-heavy");
|
|
158
|
+
expect(pool.bytesInUse).toBe(0);
|
|
159
|
+
});
|
|
160
|
+
test("composed queue at exact pool budget never exhausts the pool", () => {
|
|
161
|
+
// Every product unique (worst case for the invariant: no sharing slack).
|
|
162
|
+
const composition = {};
|
|
163
|
+
for (let id = 0; id < 50; ++id) {
|
|
164
|
+
composition[id] = [{ assetID: `u-${id}`, byteSize: 190 }];
|
|
165
|
+
}
|
|
166
|
+
const { source } = mockSource(composition);
|
|
167
|
+
const pool = new ChunkedPool(1000, 100);
|
|
168
|
+
const tiles = new GeometryTilePool(pool, source);
|
|
169
|
+
const queue = new DemandGeometryQueue(tiles, 1000);
|
|
170
|
+
// 190 rounds to 200 → 5 tiles fit. Churn all 50 through; extract must
|
|
171
|
+
// never throw pool-exhausted because logical charges cover physical.
|
|
172
|
+
for (let id = 0; id < 50; ++id) {
|
|
173
|
+
queue.request(id, id);
|
|
174
|
+
queue.pump();
|
|
175
|
+
}
|
|
176
|
+
expect(queue.stats.residentCount).toBe(5);
|
|
177
|
+
expect(pool.bytesInUse).toBe(1000);
|
|
178
|
+
expect(pool.stats.failedAcquires).toBe(0);
|
|
179
|
+
});
|
|
180
|
+
});
|