polar-objc 5.44
An Objective-C runtime library
Loading...
Searching...
No Matches
polar-sparse-array.c
1/* Internal API: sparse array type for polar-objc.
2 Copyright (C) 2022-2025 Michael Malicoat <[email protected]>
3
4 This file is part of polar-objc.
5
6 polar-objc is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
7 License as published by the Free Software Foundation; either version 3, or (at your option) any later version.
8
9 polar-objc is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
10 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11 details.
12
13 You should have received a copy of the GNU General Public License along with this program; see the file LICENSE. If
14 not, see <http://www.gnu.org/licenses/>.
15*/
16
17// polar_sparse_array **************************************************************************************************
18// Private =============================================================================================================
19
20// This variable is initialized in polar_sparse_array_get_type()
21static polar_sparse_array_class class_polar_sparse_array;
22
23// This variable is initialized in _polar_sparse_array_class_init()
24static polar_runtime_object_class *superclass_polar_sparse_array = NULL;
25
26// ---------------------------------------------------------------------------------------------------------------------
27
28POLAR_FUNCTION_INTERNAL void
29polar_sparse_array_insert_page( polar_sparse_array *self, polar_sparse_array_page *page_new );
30
31static inline polar_sparse_array_page *
32polar_sparse_array_next_page_after( polar_sparse_array *self, polar_sparse_array_page *page_current )
33{
34 assert( POLAR_IS_SPARSE_ARRAY(self) );
35
37 polar_btree_next_node_after( (polar_btree *)self, (polar_btree_node *)page_current );
38}
39
40POLAR_FUNCTION_INTERNAL void
41polar_sparse_array_maybe_replace_root( polar_sparse_array *self, polar_sparse_array_page *page_root_new )
42{
43 polar_sparse_array_page *page_root_current, *page_current, *page_temp;
44 size_t instance_size;
45 intptr_t i;
46
47 assert( POLAR_IS_SPARSE_ARRAY(self) );
48 assert( self->data_inherited.node_root != NULL );
49 assert( POLAR_IS_SPARSE_ARRAY_PAGE(page_root_new) );
50
51 page_root_current = (polar_sparse_array_page *)( self->data_inherited.node_root );
52 if( page_root_current != page_root_new )
53 ;
54
55 else
56 return;
57
58 if( polar_sparse_array_page_compare_elements_used(page_root_new, page_root_current, self->value_element_empty) > 0 )
59 ;
60
61 else
62 return;
63
64 ( (polar_btree_node *)page_root_new )->branch_right = NULL;
65 ( (polar_btree_node *)page_root_new )->branch_left = NULL;
66
67 // Exchange our current root node for our new root node
68 instance_size = polar_internal_type_get_instance_size( ((polar_btree *)self)->id_node_type );
69 page_temp = (polar_sparse_array_page *)polar_memory_duplicate(page_root_current, instance_size);
70
71 objc_memcpy(page_root_current, page_root_new, instance_size);
72 objc_memcpy(page_root_new, page_temp, instance_size);
73
74 polar_memory_free(page_temp, instance_size);
75
76 // Re-sort the tree
77 page_current = NULL;
78 for( i = 0; i < self->data_inherited.count_nodes; i++ )
79 {
80 page_current = polar_sparse_array_next_page_after(self, page_current);
81
82 if( page_current != page_root_current )
83 {
84 ( (polar_btree_node *)page_current )->branch_right = NULL;
85 ( (polar_btree_node *)page_current )->branch_left = NULL;
86
87 polar_sparse_array_insert_page(self, page_current);
88 }
89 }
90}
91
92POLAR_FUNCTION_INTERNAL polar_sparse_array_page *
93polar_sparse_array_new_page( polar_sparse_array **p_array_target )
94{
96
97 assert( *p_array_target != NULL );
98 assert( POLAR_IS_SPARSE_ARRAY(*p_array_target) );
99
100 result = (polar_sparse_array_page *)polar_btree_new_node( (polar_btree **)p_array_target );
101
102 if( (*p_array_target)->value_element_empty == NULL )
103 return result;
104
105 polar_sparse_array_page_fill_elements(result, (*p_array_target)->value_element_empty);
106 return result;
107}
108
109POLAR_FUNCTION_INTERNAL OBJC_FUNCTION_HOTSPOT polar_sparse_array_page *
110polar_sparse_array_get_page( polar_sparse_array *self, intptr_t idx_page_desired )
111{
113 intptr_t i;
114
115 assert( POLAR_IS_SPARSE_ARRAY(self) );
116 assert( idx_page_desired >= 0 );
117
118 result = (polar_sparse_array_page *)( self->data_inherited.node_root );
119
120 // The compiler optimization code seems to handle a loop with a known quantity better than a while loop
121 for( i = 0; i < self->data_inherited.count_nodes; i++ )
122 {
123 if( (void *)idx_page_desired > ((polar_btree_node *)result)->node_key )
124 result = (polar_sparse_array_page *)( ((polar_btree_node *)result)->branch_right );
125
126 else if( (void *)idx_page_desired < ((polar_btree_node *)result)->node_key )
127 result = (polar_sparse_array_page *)( ((polar_btree_node *)result)->branch_left );
128
129 else
130 return result;
131
132 if( result != NULL )
133 ;
134
135 else
136 return &self->page_empty;
137 }
138
139 return &self->page_empty;
140}
141
142POLAR_FUNCTION_INTERNAL void
143polar_sparse_array_insert_page( polar_sparse_array *self, polar_sparse_array_page *page_new )
144{
145 polar_sparse_array_page *page_current, *page_temp;
146 polar_btree_node **page_placement;
147 size_t instance_size;
148 intptr_t idx_logical_max;
149
150 assert( POLAR_IS_SPARSE_ARRAY(self) );
151
152 if( page_new != NULL )
153 assert( POLAR_IS_SPARSE_ARRAY_PAGE(page_new) );
154
155 else
156 return;
157
158 page_current = (polar_sparse_array_page *)( self->data_inherited.node_root );
159
160 if( page_current == NULL )
161 self->data_inherited.node_root = (polar_btree_node *)page_new;
162
163 else if( polar_sparse_array_page_compare_elements_used(page_new, page_current, self->value_element_empty) > 0 )
164 polar_sparse_array_maybe_replace_root(self, page_new);
165
166 else
167 {
168 /* The idea here is to find where the new page will be placed, all else being equal, and then to check whether or
169 not the new page contains more live data than the one that will serve as its immediate root. If so, the
170 positions of the two pages are swapped, so that pages with more live data are closer to the root node of the
171 overall tree.
172 */
173 page_placement = NULL;
174
175 do
176 {
177 if( ((polar_btree_node *)page_new)->node_key > ((polar_btree_node *)page_current)->node_key )
178 {
179 if( ((polar_btree_node *)page_current)->branch_right != NULL )
180 page_current = (polar_sparse_array_page *)( ((polar_btree_node *)page_current)->branch_right );
181
182 else
183 page_placement = &( (polar_btree_node *)page_current )->branch_right;
184 }
185
186 else
187 {
188 if( ((polar_btree_node *)page_current)->branch_left != NULL )
189 page_current = (polar_sparse_array_page *)( ((polar_btree_node *)page_current)->branch_left );
190
191 else
192 page_placement = &( (polar_btree_node *)page_current )->branch_left;
193 }
194 } while( page_placement == NULL );
195
196 if( polar_sparse_array_page_compare_elements_used(page_new, page_current, self->value_element_empty) > 0 )
197 {
198 /* Swap `page_new` and `page_current`, so that `page_new` is closer to the root of the tree. This has the added
199 benefit of swapping `page_new` in without the need to update branch links further upstream. However, it swaps
200 `page_current` out of the tree entirely until we put it back, below.
201 */
202
203 instance_size = polar_internal_type_get_instance_size( ((polar_btree *)self)->id_node_type );
204
205 page_temp = (polar_sparse_array_page *)polar_memory_duplicate(page_current, instance_size);
206
207 objc_memcpy(page_current, page_new, instance_size);
208 objc_memcpy(page_new, page_temp, instance_size);
209
210 polar_memory_free(page_temp, instance_size);
211
212 page_temp = page_current;
213 page_current = page_new;
214 page_new = page_temp;
215
216 // Place `page_current` back into the tree
217 if( ((polar_btree_node *)page_current)->node_key > ((polar_btree_node *)page_new)->node_key )
218 ( (polar_btree_node *)page_new )->branch_right = (polar_btree_node *)page_current;
219
220 else
221 ( (polar_btree_node *)page_new )->branch_left = (polar_btree_node *)page_current;
222 }
223
224 else
225 *page_placement = (polar_btree_node *)page_new;
226 }
227
228 idx_logical_max = POLAR_MASK_SPARSE_ARRAY +
229 ( polar_sparse_array_page_get_page_number(page_new) << POLAR_SHIFT_SPARSE_ARRAY );
230
231 if( idx_logical_max > self->idx_logical_max )
232 self->idx_logical_max = idx_logical_max;
233}
234
235// ---------------------------------------------------------------------------------------------------------------------
236
237POLAR_FUNCTION_INTERNAL polar_sparse_array *
238_polar_sparse_array_init( polar_sparse_array *self )
239{
240 // Chain up first
241 self = (polar_sparse_array *)
242 POLAR_RUNTIME_OBJECT_CLASS(superclass_polar_sparse_array)->init( (polar_runtime_object *)self );
243
244 if( self != NULL )
245 {
246 self->data_inherited.id_node_type = POLAR_TYPE_SPARSE_ARRAY_PAGE;
247 self->idx_logical_max = -1;
248
249 ( (polar_runtime_object *)(&self->page_empty) )->class_pointer = self->data_inherited.id_node_type;
250 }
251
252 return self;
253}
254
255POLAR_FUNCTION_INTERNAL void
256_polar_sparse_array_class_init( polar_sparse_array_class *self )
257{
258 // Acquire our superclass
259 superclass_polar_sparse_array = POLAR_RUNTIME_OBJECT_CLASS(self)->class_superclass;
260
261 // Establish our virtual methods
262 ( (polar_runtime_object_class *)self )->init = (polar_func_runtime_object_lifecycle)_polar_sparse_array_init;
263}
264
265static struct polar_internal_type_info pti_polar_sparse_array =
266{
267 .name_type = "polar_sparse_array",
268 .size_type_instance = sizeof(polar_sparse_array),
269 .size_type_class = sizeof(polar_sparse_array_class),
270 .type_class_init = (polar_func_runtime_object_class_lifecycle)_polar_sparse_array_class_init
271};
272
273// Public ==============================================================================================================
274
275POLAR_FUNCTION_INTERNAL OBJC_FUNCTION_CONSTANT polar_internal_type
276polar_sparse_array_get_type( void )
277{
278 static polar_internal_type pt_polar_sparse_array = POLAR_INTERNAL_TYPE_INVALID;
279
280 if( pt_polar_sparse_array != POLAR_INTERNAL_TYPE_INVALID )
281 return pt_polar_sparse_array;
282
283 pt_polar_sparse_array = polar_internal_type_init( POLAR_TYPE_BTREE, &class_polar_sparse_array,
284 &pti_polar_sparse_array) ;
285
286 return pt_polar_sparse_array;
287}
288
289POLAR_FUNCTION_INTERNAL OBJC_RETURNS_VALID_POINTER polar_sparse_array *
290polar_sparse_array_new( void *value_element_empty )
291{
292 polar_sparse_array *result;
293
294 result = (polar_sparse_array *)polar_runtime_object_new(POLAR_TYPE_SPARSE_ARRAY);
295 result->value_element_empty = value_element_empty;
296
297 if( value_element_empty == NULL )
298 ;
299
300 else
301 polar_sparse_array_page_fill_elements( &result->page_empty, value_element_empty );
302
303 return result;
304}
305
306POLAR_FUNCTION_INTERNAL OBJC_FUNCTION_HOTSPOT void *
307polar_sparse_array_get_element( polar_sparse_array *self, intptr_t idx_logical )
308{
309 intptr_t idx_page, idx_element;
310 polar_sparse_array_page *page_target;
311
312 assert( POLAR_IS_SPARSE_ARRAY(self) );
313 assert( idx_logical >= 0 );
314
315 if( idx_logical <= self->idx_logical_max )
316 {
317 idx_page = ( idx_logical >> POLAR_SHIFT_SPARSE_ARRAY );
318 page_target = polar_sparse_array_get_page(self, idx_page);
319
320 idx_element = ( idx_logical & POLAR_MASK_SPARSE_ARRAY );
321 return polar_sparse_array_page_get_element(page_target, idx_element);
322 }
323
324 return self->value_element_empty;
325}
326
327POLAR_FUNCTION_INTERNAL void
328polar_sparse_array_set_element( polar_sparse_array **p_array_target, intptr_t idx_logical, void *value_new )
329{
330 intptr_t idx_page, idx_element;
331 polar_sparse_array *array_target;
332 polar_sparse_array_page *page_target;
333
334 assert( p_array_target != NULL );
335 assert( POLAR_IS_SPARSE_ARRAY(*p_array_target) );
336 assert( idx_logical >= 0 );
337
338 idx_page = ( idx_logical >> POLAR_SHIFT_SPARSE_ARRAY );
339 idx_element = ( idx_logical & POLAR_MASK_SPARSE_ARRAY );
340 array_target = *p_array_target;
341
342 if( idx_logical <= array_target->idx_logical_max )
343 {
344 page_target = polar_sparse_array_get_page(array_target, idx_page);
345
346 if( page_target != &array_target->page_empty )
347 {
348 polar_sparse_array_page_set_element(page_target, idx_element, value_new);
349 return;
350 }
351 }
352
353 if( value_new != array_target->value_element_empty )
354 {
355 page_target = polar_sparse_array_new_page(p_array_target);
356
357 ( (polar_btree_node *)page_target )->node_key = (void *)idx_page;
358 polar_sparse_array_page_set_element(page_target, idx_element, value_new);
359
360 polar_sparse_array_insert_page(*p_array_target, page_target);
361 }
362}
363
364POLAR_FUNCTION_INTERNAL BOOL
365polar_sparse_array_set_element_if_empty( polar_sparse_array **p_array_target, intptr_t idx_logical, void *value_new )
366{
367 assert( p_array_target != NULL );
368 assert( POLAR_IS_SPARSE_ARRAY(*p_array_target) );
369 assert( idx_logical >= 0 );
370
371 if( polar_sparse_array_test_element_empty(*p_array_target, idx_logical) )
372 {
373 polar_sparse_array_set_element(p_array_target, idx_logical, value_new);
374 return YES;
375 }
376
377 return NO;
378}
Definition polar-btree-node.h:25
Definition polar-btree.h:25
Definition polar-internal-type.h:34
Definition polar-runtime-object.h:36
Definition polar-runtime-object.h:31
Definition polar-sparse-array.h:33
Definition polar-sparse-array-page.h:34
Definition polar-sparse-array.h:25