@@ -68,6 +68,24 @@ fn estimate_total_nodes(num_items: usize, node_size: usize) -> usize {
6868 ( num_items * node_size) / ( node_size - 1 ) + 1
6969}
7070
71+ /// Helper: Calculate EXACT total nodes by simulating tree construction (O(log n) - tree depth)
72+ #[ inline]
73+ fn calculate_exact_total_nodes ( num_items : usize , node_size : usize ) -> usize {
74+ if num_items == 0 {
75+ return 0 ;
76+ }
77+ let mut total_nodes = num_items;
78+ let mut count = num_items;
79+ loop {
80+ count = count. div_ceil ( node_size) ;
81+ total_nodes += count;
82+ if count <= 1 {
83+ break ;
84+ }
85+ }
86+ total_nodes
87+ }
88+
7189/// Helper: Calculate required buffer size for estimated nodes
7290#[ inline]
7391fn estimate_buffer_size ( num_items : usize , node_size : usize ) -> usize {
@@ -147,36 +165,40 @@ impl HilbertRTree {
147165 let num_items = self . num_items ;
148166 let node_size = self . node_size ;
149167
150- // Calculate total nodes and level bounds
168+ // Calculate exact total nodes needed (O(log n) - only tree depth iterations)
169+ let total_nodes = calculate_exact_total_nodes ( num_items, node_size) ;
170+ let data_size = HEADER_SIZE + total_nodes * ( size_of :: < Box > ( ) + size_of :: < u32 > ( ) ) ;
171+
172+ // Reserve all needed space at once (avoids reallocation during build)
173+ if data_size > self . data . capacity ( ) {
174+ self . data . reserve ( data_size - self . data . capacity ( ) ) ;
175+ self . allocated_capacity = self . data . capacity ( ) ;
176+ }
177+
178+ // CRITICAL: Must zero-fill parent node memory. The build process writes parent nodes
179+ // incrementally in the loop below, and during tree traversal we may read indices/boxes
180+ // from parent positions before they're written. Zero values act as sentinels.
181+ // This is unavoidable without additional bookkeeping to track which positions are initialized.
182+ if self . data . len ( ) < data_size {
183+ self . data . resize ( data_size, 0 ) ;
184+ }
185+
186+ // Calculate level bounds
151187 let mut level_bounds = Vec :: with_capacity ( 16 ) ; // Max tree depth ~16 for 1M items
152188 let mut count = num_items;
153- let mut total_nodes = num_items;
154- level_bounds. push ( total_nodes ) ;
189+ let mut level_total_nodes = num_items;
190+ level_bounds. push ( level_total_nodes ) ;
155191
156192 // Create parent levels until we have a single root
157193 loop {
158194 count = count. div_ceil ( node_size) ;
159- total_nodes += count;
160- level_bounds. push ( total_nodes ) ;
195+ level_total_nodes += count;
196+ level_bounds. push ( level_total_nodes ) ;
161197 if count <= 1 {
162198 break ;
163199 }
164200 }
165201
166- // Ensure data buffer has sufficient capacity and length for all writes
167- let data_size = HEADER_SIZE + total_nodes * ( size_of :: < Box > ( ) + size_of :: < u32 > ( ) ) ;
168- if data_size > self . data . capacity ( ) {
169- self . data . reserve ( data_size - self . data . capacity ( ) ) ;
170- self . allocated_capacity = self . data . capacity ( ) ;
171- }
172- // Set length to required size (uninitialized, but we'll overwrite everything)
173- // This avoids the zero-fill overhead of resize()
174- if self . data . len ( ) < data_size {
175- unsafe {
176- self . data . set_len ( data_size) ;
177- }
178- }
179-
180202 // Write header
181203 self . data [ 0 ] = 0xfb ; // magic
182204 self . data [ 1 ] = 0x01 ; // version 1 + double type (8)
0 commit comments