LCOV - code coverage report
Current view: top level - source/specialized/array_adaptive_map.c (source / functions) Coverage Total Hit
Test: CCC Test Suite Coverage Report Lines: 97.0 % 636 617
Test Date: 2026-08-22 15:52:04 Functions: 100.0 % 73 73

            Line data    Source code
       1              : /** Copyright 2025 Alexander G. Lopez
       2              : 
       3              : Licensed under the Apache License, Version 2.0 (the "License");
       4              : you may not use this file except in compliance with the License.
       5              : You may obtain a copy of the License at
       6              : 
       7              :    http://www.apache.org/licenses/LICENSE-2.0
       8              : 
       9              : Unless required by applicable law or agreed to in writing, software
      10              : distributed under the License is distributed on an "AS IS" BASIS,
      11              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12              : See the License for the specific language governing permissions and
      13              : limitations under the License.
      14              : 
      15              : This file implements a splay tree that does not support duplicates.
      16              : The code to support a splay tree that does not allow duplicates is much simpler
      17              : than the code to support a multimap implementation. This implementation is
      18              : based on the following source.
      19              : 
      20              :     1. Daniel Sleator, Carnegie Mellon University. Sleator's implementation of a
      21              :        topdown splay tree was instrumental in starting things off, but required
      22              :        extensive modification. I had to update parent and child tracking, and
      23              :        unite the left and right cases for fun. See the code for a generalizable
      24              :        strategy to eliminate symmetric left and right cases for any binary tree
      25              :        code. https://www.link.cs.cmu.edu/splay/
      26              : 
      27              : Because this is a self-optimizing data structure it may benefit from many
      28              : constant time queries for frequently accessed elements. It is also in a Struct
      29              : of Arrays layout to improve memory alignment and reduce wasted space. While
      30              : it is recommended that the user reserve space for the needed nodes ahead of
      31              : time, the amortized O(log(N)) run times of a Splay Tree remain the same in
      32              : the dynamic resizing case. */
      33              : /** C23 provided headers. */
      34              : #include <stdalign.h>
      35              : #include <stddef.h>
      36              : #include <stdint.h>
      37              : 
      38              : /** CCC provided headers. */
      39              : #include "ccc/configuration.h" /* IWYU pragma: keep */
      40              : #include "ccc/specialized/array_adaptive_map.h"
      41              : #include "ccc/specialized/private/private_array_adaptive_map.h"
      42              : #include "ccc/types.h"
      43              : #include "source/compiler_utilities.h"
      44              : 
      45              : /*==========================  Type Declarations   ===========================*/
      46              : 
      47              : /** @internal */
      48              : enum : uint8_t {
      49              :     LR = 2,
      50              : };
      51              : 
      52              : /** @internal */
      53              : enum Branch : uint8_t {
      54              :     L = 0,
      55              :     R,
      56              : };
      57              : 
      58              : #define INORDER R
      59              : #define INORDER_REVERSE L
      60              : 
      61              : enum : uint8_t {
      62              :     /** 0th slot is sentinel. Count will be 2 when inserting new root. */
      63              :     INSERT_ROOT_NODE_COUNT = 2,
      64              : };
      65              : 
      66              : /*========================   Data Alignment Test   ==========================*/
      67              : 
      68              : enum : size_t {
      69              :     /** @internal Test capacity. */
      70              :     TCAP = 3,
      71              :     /** @internal Alignment of node type. */
      72              :     ALIGNOF_NODE = alignof(struct CCC_Array_adaptive_map_node),
      73              :     /** @internal Size of node type. */
      74              :     SIZEOF_NODE = sizeof(struct CCC_Array_adaptive_map_node),
      75              : };
      76              : /** @internal This is a static fixed size map exclusive to this translation unit
      77              : used to ensure assumptions about data layout are correct. The following static
      78              : asserts must be true in order to support the Struct of Array style layout we
      79              : use for the data and nodes. It is important that in our user code when we set
      80              : the positions of the node pointer relative to the data pointer the positions are
      81              : correct regardless of backing storage as a fixed map or heap allocation.
      82              : 
      83              : Use an int because that will force the nodes array to be wary of
      84              : where to start. The nodes are 8 byte aligned but an int is 4. This means the
      85              : nodes need to start after a 4 byte buffer of padding at end of data array. */
      86              : [[maybe_unused]] static __auto_type const static_data_nodes_layout_test
      87              :     = CCC_array_adaptive_map_storage_for((int const[TCAP]){});
      88              : /** Some assumptions in the code assume that nodes array is last so ensure that
      89              : is the case here. Also good to assume user data comes first. */
      90              : static_assert(
      91              :     offsetof(typeof(static_data_nodes_layout_test), data)
      92              :         < offsetof(typeof(static_data_nodes_layout_test), nodes),
      93              :     "The order of the arrays in a Struct of Arrays map is data, then "
      94              :     "nodes."
      95              : );
      96              : /** We don't care about the alignment or padding after the nodes array because
      97              : we never need to set or move any pointers to that position. The alignment is
      98              : important for the nodes pointer to be set to the correct aligned position and
      99              : so that we allocate enough bytes for our single allocation if the map is dynamic
     100              : and not a fixed type. */
     101              : static_assert(
     102              :     offsetof(typeof(static_data_nodes_layout_test), nodes[TCAP])
     103              :             - offsetof(typeof(static_data_nodes_layout_test), data[0])
     104              :         == CCC_roundup(
     105              :                (sizeof(*static_data_nodes_layout_test.data) * TCAP),
     106              :                ALIGNOF_NODE
     107              :            ) + (SIZEOF_NODE * TCAP),
     108              :     "The pointer difference in bytes between end of the nodes array and start "
     109              :     "of user data array must be the same as the total bytes we assume to be "
     110              :     "stored in that range. Alignment of user data must be considered."
     111              : );
     112              : static_assert(
     113              :     offsetof(typeof(static_data_nodes_layout_test), data)
     114              :             + CCC_roundup(
     115              :                 (sizeof(*static_data_nodes_layout_test.data) * TCAP),
     116              :                 ALIGNOF_NODE
     117              :             )
     118              :         == offsetof(typeof(static_data_nodes_layout_test), nodes),
     119              :     "The start of the nodes array must begin at the next aligned "
     120              :     "byte given alignment of a node."
     121              : );
     122              : 
     123              : /*==============================  Prototypes   ==============================*/
     124              : 
     125              : static size_t splay(struct CCC_Array_adaptive_map *, size_t, void const *);
     126              : static struct CCC_Array_adaptive_map_node *
     127              : node_at(struct CCC_Array_adaptive_map const *, size_t);
     128              : static void *data_at(struct CCC_Array_adaptive_map const *, size_t);
     129              : static struct CCC_Array_adaptive_map_handle
     130              : handle(struct CCC_Array_adaptive_map *, void const *);
     131              : static size_t erase(struct CCC_Array_adaptive_map *, void const *);
     132              : static size_t maybe_allocate_insert(
     133              :     struct CCC_Array_adaptive_map *, void const *, CCC_Allocator const *
     134              : );
     135              : static CCC_Result
     136              : resize(struct CCC_Array_adaptive_map *, size_t, CCC_Allocator const *);
     137              : static void
     138              : resize_struct_of_arrays(struct CCC_Array_adaptive_map const *, void *, size_t);
     139              : static size_t data_bytes(size_t, size_t);
     140              : static size_t nodes_bytes(size_t);
     141              : static struct CCC_Array_adaptive_map_node *
     142              : nodes_base_address(size_t, void const *, size_t);
     143              : static size_t find(struct CCC_Array_adaptive_map *, void const *);
     144              : static void
     145              : connect_new_root(struct CCC_Array_adaptive_map *, size_t, CCC_Order);
     146              : static void insert(struct CCC_Array_adaptive_map *, size_t n);
     147              : static void *key_in_slot(struct CCC_Array_adaptive_map const *, void const *);
     148              : static size_t
     149              : allocate_slot(struct CCC_Array_adaptive_map *, CCC_Allocator const *);
     150              : static CCC_Tribool checked_total_bytes(size_t *, size_t, size_t);
     151              : static CCC_Handle_range equal_range(
     152              :     struct CCC_Array_adaptive_map *, void const *, void const *, enum Branch
     153              : );
     154              : static void *key_at(struct CCC_Array_adaptive_map const *, size_t);
     155              : static CCC_Order
     156              : order_nodes(struct CCC_Array_adaptive_map const *, void const *, size_t);
     157              : static size_t remove_from_tree(struct CCC_Array_adaptive_map *, size_t);
     158              : static size_t
     159              : min_max_from(struct CCC_Array_adaptive_map const *, size_t, enum Branch);
     160              : static size_t next(struct CCC_Array_adaptive_map const *, size_t, enum Branch);
     161              : static size_t
     162              : branch_index(struct CCC_Array_adaptive_map const *, size_t, enum Branch);
     163              : static size_t parent_index(struct CCC_Array_adaptive_map const *, size_t);
     164              : static size_t *
     165              : branch_pointer(struct CCC_Array_adaptive_map const *, size_t, enum Branch);
     166              : static size_t *parent_pointer(struct CCC_Array_adaptive_map const *, size_t);
     167              : static CCC_Tribool validate(struct CCC_Array_adaptive_map const *);
     168              : static void init_node(struct CCC_Array_adaptive_map const *, size_t);
     169              : static void swap(void *, size_t, void *, void *);
     170              : static void link(struct CCC_Array_adaptive_map *, size_t, enum Branch, size_t);
     171              : static void
     172              : delete_nodes(struct CCC_Array_adaptive_map const *, CCC_Destructor const *);
     173              : 
     174              : /*==============================  Interface    ==============================*/
     175              : 
     176              : void *
     177        16735 : CCC_array_adaptive_map_at(
     178              :     CCC_Array_adaptive_map const *const map, CCC_Handle_index const index
     179              : ) {
     180        16735 :     if (!map || !index) {
     181           13 :         return NULL;
     182              :     }
     183        16722 :     return data_at(map, index);
     184        16735 : }
     185              : 
     186              : CCC_Tribool
     187           66 : CCC_array_adaptive_map_contains(
     188              :     CCC_Array_adaptive_map *const map, void const *const key
     189              : ) {
     190           66 :     if (!map || !key) {
     191            2 :         return CCC_TRIBOOL_ERROR;
     192              :     }
     193           64 :     map->root = splay(map, map->root, key);
     194           64 :     return order_nodes(map, key, map->root) == CCC_ORDER_EQUAL;
     195           66 : }
     196              : 
     197              : CCC_Handle_index
     198         2017 : CCC_array_adaptive_map_get_key_value(
     199              :     CCC_Array_adaptive_map *const map, void const *const key
     200              : ) {
     201         2017 :     if (!map || !key) {
     202            2 :         return 0;
     203              :     }
     204         2015 :     return find(map, key);
     205         2017 : }
     206              : 
     207              : CCC_Array_adaptive_map_handle
     208        13044 : CCC_array_adaptive_map_handle(
     209              :     CCC_Array_adaptive_map *const map, void const *const key
     210              : ) {
     211        13044 :     if (!map || !key) {
     212            2 :         return (CCC_Array_adaptive_map_handle){
     213              :             .status = CCC_ENTRY_ARGUMENT_ERROR,
     214              :         };
     215              :     }
     216        13042 :     return handle(map, key);
     217        13044 : }
     218              : 
     219              : CCC_Handle_index
     220         8381 : CCC_array_adaptive_map_insert_handle(
     221              :     CCC_Array_adaptive_map_handle const *const handle,
     222              :     void const *const key_val_type,
     223              :     CCC_Allocator const *const allocator
     224              : ) {
     225         8381 :     if (!handle || !key_val_type || !allocator) {
     226            3 :         return 0;
     227              :     }
     228         8378 :     if (handle->status == CCC_ENTRY_OCCUPIED) {
     229         3105 :         void *const ret = data_at(handle->map, handle->index);
     230         3105 :         if (key_val_type != ret) {
     231         3105 :             (void)memcpy(ret, key_val_type, handle->map->sizeof_type);
     232         3105 :         }
     233         3105 :         return handle->index;
     234         3105 :     }
     235         5273 :     return maybe_allocate_insert(handle->map, key_val_type, allocator);
     236         8381 : }
     237              : 
     238              : CCC_Array_adaptive_map_handle *
     239          112 : CCC_array_adaptive_map_and_modify(
     240              :     CCC_Array_adaptive_map_handle *const handle,
     241              :     CCC_Modifier const *const modifier
     242              : ) {
     243          112 :     if (!handle || !modifier) {
     244            2 :         return NULL;
     245              :     }
     246          110 :     if (modifier->modify && handle->status & CCC_ENTRY_OCCUPIED) {
     247          168 :         modifier->modify((CCC_Arguments){
     248           56 :             .type = data_at(handle->map, handle->index),
     249           56 :             .context = modifier->context,
     250              :         });
     251           56 :     }
     252          110 :     return handle;
     253          112 : }
     254              : 
     255              : CCC_Handle_index
     256          262 : CCC_array_adaptive_map_or_insert(
     257              :     CCC_Array_adaptive_map_handle const *const handle,
     258              :     void const *const key_val_type,
     259              :     CCC_Allocator const *const allocator
     260              : ) {
     261          262 :     if (!handle || !key_val_type || !allocator) {
     262            3 :         return 0;
     263              :     }
     264          259 :     if (handle->status & CCC_ENTRY_OCCUPIED) {
     265          153 :         return handle->index;
     266              :     }
     267          106 :     return maybe_allocate_insert(handle->map, key_val_type, allocator);
     268          262 : }
     269              : 
     270              : CCC_Handle
     271         1565 : CCC_array_adaptive_map_swap_handle(
     272              :     CCC_Array_adaptive_map *const map,
     273              :     void *const type_output,
     274              :     CCC_Allocator const *const allocator
     275              : ) {
     276         1565 :     if (!map || !type_output || !allocator) {
     277            3 :         return (CCC_Handle){.status = CCC_ENTRY_ARGUMENT_ERROR};
     278              :     }
     279         1562 :     size_t const found = find(map, key_in_slot(map, type_output));
     280         1562 :     if (found) {
     281          107 :         assert(map->root);
     282          107 :         void *const ret = data_at(map, map->root);
     283          107 :         void *const temp = data_at(map, 0);
     284          107 :         swap(temp, map->sizeof_type, type_output, ret);
     285          214 :         return (CCC_Handle){
     286          107 :             .index = found,
     287              :             .status = CCC_ENTRY_OCCUPIED,
     288              :         };
     289          107 :     }
     290         1455 :     size_t const inserted = maybe_allocate_insert(map, type_output, allocator);
     291         1455 :     if (!inserted) {
     292            1 :         return (CCC_Handle){
     293              :             .index = 0,
     294              :             .status = CCC_ENTRY_INSERT_ERROR,
     295              :         };
     296              :     }
     297         2908 :     return (CCC_Handle){
     298         1454 :         .index = inserted,
     299              :         .status = CCC_ENTRY_VACANT,
     300              :     };
     301         1565 : }
     302              : 
     303              : CCC_Handle
     304         1224 : CCC_array_adaptive_map_try_insert(
     305              :     CCC_Array_adaptive_map *const map,
     306              :     void const *const key_val_type,
     307              :     CCC_Allocator const *const allocator
     308              : ) {
     309         1224 :     if (!map || !key_val_type || !allocator) {
     310            3 :         return (CCC_Handle){.status = CCC_ENTRY_ARGUMENT_ERROR};
     311              :     }
     312         1221 :     size_t const found = find(map, key_in_slot(map, key_val_type));
     313         1221 :     if (found) {
     314          423 :         assert(map->root);
     315          846 :         return (CCC_Handle){
     316          423 :             .index = found,
     317              :             .status = CCC_ENTRY_OCCUPIED,
     318              :         };
     319              :     }
     320          798 :     size_t const inserted = maybe_allocate_insert(map, key_val_type, allocator);
     321          798 :     if (!inserted) {
     322            1 :         return (CCC_Handle){
     323              :             .index = 0,
     324              :             .status = CCC_ENTRY_INSERT_ERROR,
     325              :         };
     326              :     }
     327         1594 :     return (CCC_Handle){
     328          797 :         .index = inserted,
     329              :         .status = CCC_ENTRY_VACANT,
     330              :     };
     331         1224 : }
     332              : 
     333              : CCC_Handle
     334         3022 : CCC_array_adaptive_map_insert_or_assign(
     335              :     CCC_Array_adaptive_map *const map,
     336              :     void const *const key_val_type,
     337              :     CCC_Allocator const *const allocator
     338              : ) {
     339         3022 :     if (!map || !key_val_type || !allocator) {
     340            3 :         return (CCC_Handle){.status = CCC_ENTRY_ARGUMENT_ERROR};
     341              :     }
     342         3019 :     size_t const found = find(map, key_in_slot(map, key_val_type));
     343         3019 :     if (found) {
     344          383 :         assert(map->root);
     345          383 :         void *const f_base = data_at(map, found);
     346          383 :         if (key_val_type != f_base) {
     347          383 :             memcpy(f_base, key_val_type, map->sizeof_type);
     348          383 :         }
     349          766 :         return (CCC_Handle){
     350          383 :             .index = found,
     351              :             .status = CCC_ENTRY_OCCUPIED,
     352              :         };
     353          383 :     }
     354         2636 :     size_t const inserted = maybe_allocate_insert(map, key_val_type, allocator);
     355         2636 :     if (!inserted) {
     356            3 :         return (CCC_Handle){
     357              :             .index = 0,
     358              :             .status = CCC_ENTRY_INSERT_ERROR,
     359              :         };
     360              :     }
     361         5266 :     return (CCC_Handle){
     362         2633 :         .index = inserted,
     363              :         .status = CCC_ENTRY_VACANT,
     364              :     };
     365         3022 : }
     366              : 
     367              : CCC_Handle
     368         2280 : CCC_array_adaptive_map_remove_key_value(
     369              :     CCC_Array_adaptive_map *const map, void *const type_output
     370              : ) {
     371         2280 :     if (!map || !type_output) {
     372            2 :         return (CCC_Handle){.status = CCC_ENTRY_ARGUMENT_ERROR};
     373              :     }
     374         2278 :     size_t const removed = erase(map, key_in_slot(map, type_output));
     375         2278 :     if (!removed) {
     376            3 :         return (CCC_Handle){
     377              :             .index = 0,
     378              :             .status = CCC_ENTRY_VACANT,
     379              :         };
     380              :     }
     381         2275 :     assert(removed);
     382         2275 :     void const *const r = data_at(map, removed);
     383         2275 :     if (type_output != r) {
     384         2275 :         (void)memcpy(type_output, r, map->sizeof_type);
     385         2275 :     }
     386         2275 :     return (CCC_Handle){
     387              :         .index = 0,
     388              :         .status = CCC_ENTRY_OCCUPIED,
     389              :     };
     390         2280 : }
     391              : 
     392              : CCC_Handle
     393           55 : CCC_array_adaptive_map_remove_handle(
     394              :     CCC_Array_adaptive_map_handle *const handle
     395              : ) {
     396           55 :     if (!handle) {
     397            1 :         return (CCC_Handle){.status = CCC_ENTRY_ARGUMENT_ERROR};
     398              :     }
     399           54 :     if (handle->status == CCC_ENTRY_OCCUPIED) {
     400           88 :         size_t const erased
     401           44 :             = erase(handle->map, key_at(handle->map, handle->index));
     402           44 :         assert(erased);
     403           88 :         return (CCC_Handle){
     404           44 :             .index = erased,
     405              :             .status = CCC_ENTRY_OCCUPIED,
     406              :         };
     407           44 :     }
     408           10 :     return (CCC_Handle){
     409              :         .index = 0,
     410              :         .status = CCC_ENTRY_VACANT,
     411              :     };
     412           55 : }
     413              : 
     414              : CCC_Handle_index
     415           16 : CCC_array_adaptive_map_unwrap(
     416              :     CCC_Array_adaptive_map_handle const *const handle
     417              : ) {
     418           16 :     if (!handle) {
     419            1 :         return 0;
     420              :     }
     421           15 :     return handle->status == CCC_ENTRY_OCCUPIED ? handle->index : 0;
     422           16 : }
     423              : 
     424              : CCC_Tribool
     425            3 : CCC_array_adaptive_map_insert_error(
     426              :     CCC_Array_adaptive_map_handle const *const handle
     427              : ) {
     428            3 :     if (!handle) {
     429            2 :         return CCC_TRIBOOL_ERROR;
     430              :     }
     431            1 :     return (handle->status & CCC_ENTRY_INSERT_ERROR) != 0;
     432            3 : }
     433              : 
     434              : CCC_Tribool
     435           84 : CCC_array_adaptive_map_occupied(
     436              :     CCC_Array_adaptive_map_handle const *const handle
     437              : ) {
     438           84 :     if (!handle) {
     439            1 :         return CCC_TRIBOOL_ERROR;
     440              :     }
     441           83 :     return (handle->status & CCC_ENTRY_OCCUPIED) != 0;
     442           84 : }
     443              : 
     444              : CCC_Handle_status
     445            2 : CCC_array_adaptive_map_handle_status(
     446              :     CCC_Array_adaptive_map_handle const *const handle
     447              : ) {
     448            2 :     return handle ? handle->status : CCC_ENTRY_ARGUMENT_ERROR;
     449              : }
     450              : 
     451              : CCC_Tribool
     452         2353 : CCC_array_adaptive_map_is_empty(CCC_Array_adaptive_map const *const map) {
     453         2353 :     if (!map) {
     454            1 :         return CCC_TRIBOOL_ERROR;
     455              :     }
     456         2352 :     return !CCC_array_adaptive_map_count(map).count;
     457         2353 : }
     458              : 
     459              : CCC_Count
     460         2506 : CCC_array_adaptive_map_count(CCC_Array_adaptive_map const *const map) {
     461         2506 :     if (!map) {
     462            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
     463              :     }
     464         5010 :     return (CCC_Count){
     465         2505 :         .count = map->count ? map->count - 1 : 0,
     466              :     };
     467         2506 : }
     468              : 
     469              : CCC_Count
     470           12 : CCC_array_adaptive_map_capacity(CCC_Array_adaptive_map const *const map) {
     471           12 :     if (!map) {
     472            1 :         return (CCC_Count){.error = CCC_RESULT_ARGUMENT_ERROR};
     473              :     }
     474           11 :     return (CCC_Count){.count = map->capacity};
     475           12 : }
     476              : 
     477              : CCC_Handle_index
     478           16 : CCC_array_adaptive_map_begin(CCC_Array_adaptive_map const *const map) {
     479           16 :     if (!map || !map->capacity) {
     480            3 :         return 0;
     481              :     }
     482           13 :     size_t const n = min_max_from(map, map->root, L);
     483           13 :     return n;
     484           16 : }
     485              : 
     486              : CCC_Handle_index
     487            3 : CCC_array_adaptive_map_reverse_begin(CCC_Array_adaptive_map const *const map) {
     488            3 :     if (!map || !map->capacity) {
     489            1 :         return 0;
     490              :     }
     491            2 :     size_t const n = min_max_from(map, map->root, R);
     492            2 :     return n;
     493            3 : }
     494              : 
     495              : CCC_Handle_index
     496         2942 : CCC_array_adaptive_map_next(
     497              :     CCC_Array_adaptive_map const *const map, CCC_Handle_index const iterator
     498              : ) {
     499         2942 :     if (!map || !map->capacity) {
     500            1 :         return 0;
     501              :     }
     502         2941 :     size_t const n = next(map, iterator, INORDER);
     503         2941 :     return n;
     504         2942 : }
     505              : 
     506              : CCC_Handle_index
     507         1265 : CCC_array_adaptive_map_reverse_next(
     508              :     CCC_Array_adaptive_map const *const map, CCC_Handle_index const iterator
     509              : ) {
     510         1265 :     if (!map || !iterator || !map->capacity) {
     511            1 :         return 0;
     512              :     }
     513         1264 :     size_t const n = next(map, iterator, INORDER_REVERSE);
     514         1264 :     return n;
     515         1265 : }
     516              : 
     517              : CCC_Handle_index
     518         4184 : CCC_array_adaptive_map_end(CCC_Array_adaptive_map const *const) {
     519         4184 :     return 0;
     520              : }
     521              : 
     522              : CCC_Handle_index
     523            4 : CCC_array_adaptive_map_reverse_end(CCC_Array_adaptive_map const *const) {
     524            4 :     return 0;
     525              : }
     526              : 
     527              : CCC_Handle_range
     528            8 : CCC_array_adaptive_map_equal_range(
     529              :     CCC_Array_adaptive_map *const map,
     530              :     void const *const begin_key,
     531              :     void const *const end_key
     532              : ) {
     533            8 :     if (!map || !begin_key || !end_key) {
     534            3 :         return (CCC_Handle_range){};
     535              :     }
     536            5 :     return equal_range(map, begin_key, end_key, INORDER);
     537            8 : }
     538              : 
     539              : CCC_Handle_range_reverse
     540            8 : CCC_array_adaptive_map_equal_range_reverse(
     541              :     CCC_Array_adaptive_map *const map,
     542              :     void const *const reverse_begin_key,
     543              :     void const *const reverse_end_key
     544              : )
     545              : 
     546              : {
     547            8 :     if (!map || !reverse_begin_key || !reverse_end_key) {
     548            3 :         return (CCC_Handle_range_reverse){};
     549              :     }
     550            5 :     CCC_Handle_range const range
     551            5 :         = equal_range(map, reverse_begin_key, reverse_end_key, INORDER_REVERSE);
     552           15 :     return (CCC_Handle_range_reverse){
     553            5 :         .reverse_begin = range.begin,
     554            5 :         .reverse_end = range.end,
     555              :     };
     556            8 : }
     557              : 
     558              : CCC_Result
     559           15 : CCC_array_adaptive_map_reserve(
     560              :     CCC_Array_adaptive_map *const map,
     561              :     size_t const to_add,
     562              :     CCC_Allocator const *const allocator
     563              : ) {
     564           15 :     if (!map || !to_add || !allocator || !allocator->allocate) {
     565            3 :         return CCC_RESULT_ARGUMENT_ERROR;
     566              :     }
     567           12 :     size_t const needed = map->count + to_add + (map->count == 0);
     568           12 :     if (needed <= map->capacity) {
     569            1 :         return CCC_RESULT_OK;
     570              :     }
     571           11 :     size_t const old_count = map->count;
     572           11 :     size_t old_cap = map->capacity;
     573           11 :     CCC_Result const r = resize(map, needed, allocator);
     574           11 :     if (r != CCC_RESULT_OK) {
     575            1 :         return r;
     576              :     }
     577           10 :     if (!old_cap) {
     578           10 :         map->count = 1;
     579           10 :     }
     580           10 :     old_cap = old_count ? old_cap : 0;
     581           10 :     size_t const new_cap = map->capacity;
     582           10 :     size_t prev = 0;
     583           10 :     size_t i = new_cap;
     584         1445 :     while (i--) {
     585         1445 :         if (i <= old_cap) {
     586           10 :             break;
     587              :         }
     588         1435 :         node_at(map, i)->next_free = prev;
     589         1435 :         prev = i;
     590              :     }
     591           10 :     if (!map->free_list) {
     592           10 :         map->free_list = prev;
     593           10 :     }
     594           10 :     return CCC_RESULT_OK;
     595           15 : }
     596              : 
     597              : CCC_Result
     598            7 : CCC_array_adaptive_map_copy(
     599              :     CCC_Array_adaptive_map *const destination,
     600              :     CCC_Array_adaptive_map const *const source,
     601              :     CCC_Allocator const *const allocator
     602              : ) {
     603            7 :     if (!destination || !source || !allocator || source == destination
     604            7 :         || (destination->capacity < source->capacity && !allocator->allocate)) {
     605            2 :         return CCC_RESULT_ARGUMENT_ERROR;
     606              :     }
     607            5 :     if (!source->capacity) {
     608            1 :         return CCC_RESULT_OK;
     609              :     }
     610            4 :     if (destination->capacity < source->capacity) {
     611            3 :         CCC_Result const r = resize(destination, source->capacity, allocator);
     612            3 :         if (r != CCC_RESULT_OK) {
     613            1 :             return r;
     614              :         }
     615            3 :     } else {
     616              :         /* Might not be necessary but not worth finding out. Do every time. */
     617            1 :         destination->nodes = nodes_base_address(
     618            1 :             destination->sizeof_type, destination->data, destination->capacity
     619              :         );
     620              :     }
     621            3 :     if (!destination->data || !source->data) {
     622            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     623              :     }
     624            2 :     resize_struct_of_arrays(source, destination->data, destination->capacity);
     625            2 :     destination->free_list = source->free_list;
     626            2 :     destination->root = source->root;
     627            2 :     destination->count = source->count;
     628            2 :     destination->comparator = source->comparator;
     629            2 :     destination->sizeof_type = source->sizeof_type;
     630            2 :     destination->key_offset = source->key_offset;
     631            2 :     return CCC_RESULT_OK;
     632            7 : }
     633              : 
     634              : CCC_Result
     635            2 : CCC_array_adaptive_map_clear(
     636              :     CCC_Array_adaptive_map *const map, CCC_Destructor const *const destructor
     637              : ) {
     638            2 :     if (!map || !destructor) {
     639            1 :         return CCC_RESULT_ARGUMENT_ERROR;
     640              :     }
     641            1 :     if (destructor->destroy) {
     642            1 :         delete_nodes(map, destructor);
     643            1 :     }
     644            1 :     map->count = 1;
     645            1 :     map->root = 0;
     646            1 :     return CCC_RESULT_OK;
     647            2 : }
     648              : 
     649              : CCC_Result
     650           20 : CCC_array_adaptive_map_clear_and_free(
     651              :     CCC_Array_adaptive_map *const map,
     652              :     CCC_Destructor const *const destructor,
     653              :     CCC_Allocator const *const allocator
     654              : ) {
     655           20 :     if (!map || !destructor || !allocator || !allocator->allocate) {
     656            4 :         return CCC_RESULT_ARGUMENT_ERROR;
     657              :     }
     658           16 :     if (destructor->destroy) {
     659            1 :         delete_nodes(map, destructor);
     660            1 :     }
     661           16 :     map->root = 0;
     662           16 :     map->count = 0;
     663           16 :     map->capacity = 0;
     664           64 :     (void)allocator->allocate((CCC_Allocator_arguments){
     665           16 :         .input = map->data,
     666              :         .bytes = 0,
     667           16 :         .alignment = CCC_max(ALIGNOF_NODE, map->alignof_type),
     668           16 :         .context = allocator->context,
     669              :     });
     670           16 :     map->data = NULL;
     671           16 :     map->nodes = NULL;
     672           16 :     return CCC_RESULT_OK;
     673           20 : }
     674              : 
     675              : CCC_Tribool
     676         9866 : CCC_array_adaptive_map_validate(CCC_Array_adaptive_map const *const map) {
     677         9866 :     if (!map) {
     678            1 :         return CCC_TRIBOOL_ERROR;
     679              :     }
     680         9865 :     return validate(map);
     681         9866 : }
     682              : 
     683              : /*===========================   Private Interface ===========================*/
     684              : 
     685              : void
     686          144 : CCC_private_array_adaptive_map_insert(
     687              :     struct CCC_Array_adaptive_map *const map, size_t const elem_i
     688              : ) {
     689          144 :     insert(map, elem_i);
     690          144 : }
     691              : 
     692              : struct CCC_Array_adaptive_map_handle
     693           48 : CCC_private_array_adaptive_map_handle(
     694              :     struct CCC_Array_adaptive_map *const map, void const *const key
     695              : ) {
     696           48 :     return handle(map, key);
     697           48 : }
     698              : 
     699              : void *
     700           36 : CCC_private_array_adaptive_map_key_at(
     701              :     struct CCC_Array_adaptive_map const *const map, size_t const slot
     702              : ) {
     703           36 :     return key_at(map, slot);
     704              : }
     705              : 
     706              : void *
     707         2207 : CCC_private_array_adaptive_map_data_at(
     708              :     struct CCC_Array_adaptive_map const *const map, size_t const slot
     709              : ) {
     710         2207 :     return data_at(map, slot);
     711              : }
     712              : 
     713              : size_t
     714          146 : CCC_private_array_adaptive_map_allocate_slot(
     715              :     struct CCC_Array_adaptive_map *const map,
     716              :     CCC_Allocator const *const allocator
     717              : ) {
     718          146 :     return allocate_slot(map, allocator);
     719              : }
     720              : 
     721              : /*===========================   Static Helpers    ===========================*/
     722              : 
     723              : static CCC_Handle_range
     724           10 : equal_range(
     725              :     struct CCC_Array_adaptive_map *const t,
     726              :     void const *const begin_key,
     727              :     void const *const end_key,
     728              :     enum Branch const traversal
     729              : ) {
     730           10 :     if (CCC_array_adaptive_map_is_empty(t)) {
     731            2 :         return (CCC_Handle_range){};
     732              :     }
     733              :     /* As with most BST code the cases are perfectly symmetrical. If we
     734              :        are seeking an increasing or decreasing range we need to make sure
     735              :        we follow the [inclusive, exclusive) range rule. This means double
     736              :        checking we don't need to progress to the next greatest or next
     737              :        lesser element depending on the direction we are traversing. */
     738            8 :     CCC_Order const les_or_grt[2] = {CCC_ORDER_LESSER, CCC_ORDER_GREATER};
     739            8 :     size_t b = splay(t, t->root, begin_key);
     740            8 :     if (order_nodes(t, begin_key, b) == les_or_grt[traversal]) {
     741            2 :         b = next(t, b, traversal);
     742            2 :     }
     743            8 :     size_t e = splay(t, t->root, end_key);
     744            8 :     if (order_nodes(t, end_key, e) != les_or_grt[!traversal]) {
     745            5 :         e = next(t, e, traversal);
     746            5 :     }
     747           24 :     return (CCC_Handle_range){
     748            8 :         .begin = b,
     749            8 :         .end = e,
     750              :     };
     751           10 : }
     752              : 
     753              : static struct CCC_Array_adaptive_map_handle
     754        13090 : handle(struct CCC_Array_adaptive_map *const map, void const *const key) {
     755        13090 :     size_t const found = find(map, key);
     756        13090 :     if (found) {
     757        22542 :         return (struct CCC_Array_adaptive_map_handle){
     758         7514 :             .map = map,
     759         7514 :             .index = found,
     760              :             .status = CCC_ENTRY_OCCUPIED,
     761              :         };
     762              :     }
     763        11152 :     return (struct CCC_Array_adaptive_map_handle){
     764         5576 :         .map = map,
     765              :         .index = 0,
     766              :         .status = CCC_ENTRY_VACANT,
     767              :     };
     768        13090 : }
     769              : 
     770              : static size_t
     771        10268 : maybe_allocate_insert(
     772              :     struct CCC_Array_adaptive_map *const map,
     773              :     void const *const user_type,
     774              :     CCC_Allocator const *const allocator
     775              : ) {
     776        10268 :     size_t const node = allocate_slot(map, allocator);
     777        10268 :     if (!node) {
     778            8 :         return 0;
     779              :     }
     780        10260 :     (void)memcpy(data_at(map, node), user_type, map->sizeof_type);
     781        10260 :     insert(map, node);
     782        10260 :     return node;
     783        10268 : }
     784              : 
     785              : static size_t
     786        10414 : allocate_slot(
     787              :     struct CCC_Array_adaptive_map *const map,
     788              :     CCC_Allocator const *const allocator
     789              : ) {
     790              :     /* The end sentinel node will always be at 0. This also means once
     791              :        initialized the internal size for implementer is always at least 1. */
     792        10414 :     size_t const old_count = map->count;
     793        10414 :     size_t old_cap = map->capacity;
     794        10414 :     if (!old_count || old_count == old_cap) {
     795           94 :         assert(!map->free_list);
     796           94 :         if (old_count == old_cap) {
     797           49 :             size_t new_cap = 0;
     798           49 :             if (ckd_mul(&new_cap, old_cap, 2)) {
     799            0 :                 return 0;
     800              :             }
     801           49 :             if (resize(map, CCC_max(new_cap, 8U), allocator) != CCC_RESULT_OK) {
     802           10 :                 return 0;
     803              :             }
     804           49 :         } else {
     805           45 :             map->nodes = nodes_base_address(
     806           45 :                 map->sizeof_type, map->data, map->capacity
     807              :             );
     808              :         }
     809           84 :         old_cap = old_count ? old_cap : 1;
     810           84 :         size_t const new_cap = map->capacity;
     811           84 :         size_t prev = 0;
     812        16980 :         for (size_t i = new_cap - 1; i >= old_cap; prev = i, --i) {
     813        16896 :             node_at(map, i)->next_free = prev;
     814        16896 :         }
     815           84 :         map->free_list = prev;
     816           84 :         map->count = CCC_max(old_count, 1U);
     817           84 :     }
     818        10404 :     assert(map->free_list);
     819        10404 :     ++map->count;
     820        10404 :     size_t const slot = map->free_list;
     821        10404 :     map->free_list = node_at(map, slot)->next_free;
     822        10404 :     return slot;
     823        10414 : }
     824              : 
     825              : static CCC_Result
     826           63 : resize(
     827              :     struct CCC_Array_adaptive_map *const map,
     828              :     size_t const new_capacity,
     829              :     CCC_Allocator const *const allocator
     830              : ) {
     831           63 :     if (!allocator->allocate) {
     832            9 :         return CCC_RESULT_NO_ALLOCATION_FUNCTION;
     833              :     }
     834           54 :     size_t new_bytes = 0;
     835           54 :     if (checked_total_bytes(&new_bytes, map->sizeof_type, new_capacity)) {
     836            0 :         return CCC_RESULT_ALLOCATOR_ERROR;
     837              :     }
     838          216 :     void *const new_data = allocator->allocate((CCC_Allocator_arguments){
     839              :         .input = NULL,
     840           54 :         .bytes = new_bytes,
     841           54 :         .alignment = CCC_max(ALIGNOF_NODE, map->alignof_type),
     842           54 :         .context = allocator->context,
     843              :     });
     844           54 :     if (!new_data) {
     845            3 :         return CCC_RESULT_ALLOCATOR_ERROR;
     846              :     }
     847           51 :     resize_struct_of_arrays(map, new_data, new_capacity);
     848           51 :     map->nodes = nodes_base_address(map->sizeof_type, new_data, new_capacity);
     849          204 :     allocator->allocate((CCC_Allocator_arguments){
     850           51 :         .input = map->data,
     851              :         .bytes = 0,
     852           51 :         .alignment = CCC_max(ALIGNOF_NODE, map->alignof_type),
     853           51 :         .context = allocator->context,
     854              :     });
     855           51 :     map->data = new_data;
     856           51 :     map->capacity = new_capacity;
     857           51 :     return CCC_RESULT_OK;
     858           63 : }
     859              : 
     860              : static void
     861        10404 : insert(struct CCC_Array_adaptive_map *const map, size_t const n) {
     862        10404 :     init_node(map, n);
     863        10404 :     if (map->count == INSERT_ROOT_NODE_COUNT) {
     864           60 :         map->root = n;
     865           60 :         return;
     866              :     }
     867        10344 :     void const *const key = key_at(map, n);
     868        10344 :     map->root = splay(map, map->root, key);
     869        10344 :     CCC_Order const root_order = order_nodes(map, key, map->root);
     870        10344 :     if (CCC_ORDER_EQUAL == root_order) {
     871            0 :         return;
     872              :     }
     873        10344 :     connect_new_root(map, n, root_order);
     874        20748 : }
     875              : 
     876              : static void
     877        10344 : connect_new_root(
     878              :     struct CCC_Array_adaptive_map *const map,
     879              :     size_t const new_root,
     880              :     CCC_Order const order_result
     881              : ) {
     882        10344 :     enum Branch const dir = CCC_ORDER_GREATER == order_result;
     883        10344 :     link(map, new_root, dir, branch_index(map, map->root, dir));
     884        10344 :     link(map, new_root, !dir, map->root);
     885        10344 :     *branch_pointer(map, map->root, dir) = 0;
     886        10344 :     map->root = new_root;
     887        10344 :     *parent_pointer(map, map->root) = 0;
     888        10344 : }
     889              : 
     890              : static size_t
     891         2322 : erase(struct CCC_Array_adaptive_map *const map, void const *const key) {
     892         2322 :     if (CCC_array_adaptive_map_is_empty(map)) {
     893            1 :         return 0;
     894              :     }
     895         2321 :     size_t const ret = splay(map, map->root, key);
     896         2321 :     CCC_Order const found = order_nodes(map, key, ret);
     897         2321 :     if (found != CCC_ORDER_EQUAL) {
     898            2 :         return 0;
     899              :     }
     900         2319 :     return remove_from_tree(map, ret);
     901         2322 : }
     902              : 
     903              : static size_t
     904         2319 : remove_from_tree(struct CCC_Array_adaptive_map *const map, size_t const ret) {
     905         2319 :     if (!branch_index(map, ret, L)) {
     906          361 :         map->root = branch_index(map, ret, R);
     907          361 :         *parent_pointer(map, map->root) = 0;
     908          361 :     } else {
     909         1958 :         map->root = splay(map, branch_index(map, ret, L), key_at(map, ret));
     910         1958 :         link(map, map->root, R, branch_index(map, ret, R));
     911              :     }
     912         2319 :     node_at(map, ret)->next_free = map->free_list;
     913         2319 :     map->free_list = ret;
     914         2319 :     --map->count;
     915         2319 :     return ret;
     916              : }
     917              : 
     918              : static size_t
     919        20907 : find(struct CCC_Array_adaptive_map *const map, void const *const key) {
     920        20907 :     if (!map->root) {
     921           77 :         return 0;
     922              :     }
     923        20830 :     map->root = splay(map, map->root, key);
     924        20830 :     return order_nodes(map, key, map->root) == CCC_ORDER_EQUAL ? map->root : 0;
     925        20907 : }
     926              : 
     927              : /** Adopts D. Sleator technique for splaying. Notable to this method is the
     928              : general improvement to the tree that occurs because we always splay the key
     929              : to the root, OR the next closest value to the key to the root. This has
     930              : interesting performance implications for real data sets.
     931              : 
     932              : This implementation has been modified to unite the left and right symmetries
     933              : and manage the parent pointers. Parent pointers are not usual for splay trees
     934              : but are necessary for a clean iteration API. */
     935              : static size_t
     936        35533 : splay(
     937              :     struct CCC_Array_adaptive_map *const map, size_t root, void const *const key
     938              : ) {
     939        35533 :     assert(root);
     940              :     /* Splaying brings the key element up to the root. The zigzag fixes of
     941              :        splaying repair the tree and we remember the roots of these changes in
     942              :        this helper tree. At the end, make the root pick up these modified left
     943              :        and right helpers. The nil node should NULL initialized to start. */
     944        35533 :     struct CCC_Array_adaptive_map_node *const nil = node_at(map, 0);
     945        35533 :     nil->branch[L] = nil->branch[R] = nil->parent = 0;
     946        35533 :     size_t left_right_subtrees[LR] = {0, 0};
     947       156439 :     for (;;) {
     948       156439 :         CCC_Order const root_order = order_nodes(map, key, root);
     949       156439 :         enum Branch const order_link = CCC_ORDER_GREATER == root_order;
     950       156439 :         size_t const child = branch_index(map, root, order_link);
     951       156439 :         if (CCC_ORDER_EQUAL == root_order || !child) {
     952        26872 :             break;
     953              :         }
     954       259134 :         CCC_Order const child_order
     955       129567 :             = order_nodes(map, key, branch_index(map, root, order_link));
     956       129567 :         enum Branch const child_order_link = CCC_ORDER_GREATER == child_order;
     957              :         /* A straight line has formed from root->child->grandchild. An
     958              :            opportunity to splay and heal the tree arises. */
     959       129567 :         if (CCC_ORDER_EQUAL != child_order && order_link == child_order_link) {
     960        82722 :             link(map, root, order_link, branch_index(map, child, !order_link));
     961        82722 :             link(map, child, !order_link, root);
     962        82722 :             root = child;
     963        82722 :             if (!branch_index(map, root, order_link)) {
     964         8661 :                 break;
     965              :             }
     966        74061 :         }
     967       120906 :         link(map, left_right_subtrees[!order_link], order_link, root);
     968       120906 :         left_right_subtrees[!order_link] = root;
     969       120906 :         root = branch_index(map, root, order_link);
     970       156439 :     }
     971        35533 :     link(map, left_right_subtrees[L], R, branch_index(map, root, L));
     972        35533 :     link(map, left_right_subtrees[R], L, branch_index(map, root, R));
     973        35533 :     link(map, root, L, nil->branch[R]);
     974        35533 :     link(map, root, R, nil->branch[L]);
     975        35533 :     map->root = root;
     976        35533 :     *parent_pointer(map, map->root) = 0;
     977        71066 :     return root;
     978        35533 : }
     979              : 
     980              : /** Links the parent node to node starting at subtree root via direction dir.
     981              : updates the parent of the child being picked up by the new parent as well. */
     982              : static inline void
     983       451128 : link(
     984              :     struct CCC_Array_adaptive_map *const map,
     985              :     size_t const parent,
     986              :     enum Branch const dir,
     987              :     size_t const subtree
     988              : ) {
     989       451128 :     *branch_pointer(map, parent, dir) = subtree;
     990       451128 :     *parent_pointer(map, subtree) = parent;
     991       451128 : }
     992              : 
     993              : static size_t
     994           15 : min_max_from(
     995              :     struct CCC_Array_adaptive_map const *const map,
     996              :     size_t start,
     997              :     enum Branch const dir
     998              : ) {
     999           15 :     if (!start) {
    1000            1 :         return 0;
    1001              :     }
    1002          114 :     for (; branch_index(map, start, dir);
    1003          100 :          start = branch_index(map, start, dir)) {}
    1004           14 :     return start;
    1005           15 : }
    1006              : 
    1007              : static size_t
    1008         4212 : next(
    1009              :     struct CCC_Array_adaptive_map const *const map,
    1010              :     size_t n,
    1011              :     enum Branch const traversal
    1012              : ) {
    1013         4212 :     if (!n) {
    1014            0 :         return 0;
    1015              :     }
    1016         4212 :     assert(!parent_index(map, map->root));
    1017         4212 :     if (branch_index(map, n, traversal)) {
    1018         4441 :         for (n = branch_index(map, n, traversal);
    1019         4441 :              branch_index(map, n, !traversal);
    1020         2363 :              n = branch_index(map, n, !traversal)) {}
    1021         2078 :         return n;
    1022              :     }
    1023         2134 :     size_t p = parent_index(map, n);
    1024         3827 :     for (; p && branch_index(map, p, !traversal) != n;
    1025         1693 :          n = p, p = parent_index(map, p)) {}
    1026         2134 :     return p;
    1027         4212 : }
    1028              : 
    1029              : /** Deletes all nodes in the tree by calling destructor function on them in
    1030              : linear time and constant space. This function modifies nodes as it deletes the
    1031              : tree elements. Assumes the destructor function is non-null.
    1032              : 
    1033              : This function does not update any count or capacity fields of the map, it
    1034              : simply calls the destructor on each node and removes the nodes references to
    1035              : other tree elements. */
    1036              : static void
    1037            2 : delete_nodes(
    1038              :     struct CCC_Array_adaptive_map const *const map,
    1039              :     CCC_Destructor const *const destructor
    1040              : ) {
    1041            2 :     size_t node = map->root;
    1042           31 :     while (node) {
    1043           29 :         struct CCC_Array_adaptive_map_node *const e = node_at(map, node);
    1044           29 :         if (e->branch[L]) {
    1045           14 :             size_t const left = e->branch[L];
    1046           14 :             e->branch[L] = node_at(map, left)->branch[R];
    1047           14 :             node_at(map, left)->branch[R] = node;
    1048           14 :             node = left;
    1049              :             continue;
    1050           14 :         }
    1051           15 :         size_t const next = e->branch[R];
    1052           15 :         e->branch[L] = e->branch[R] = 0;
    1053           15 :         e->parent = 0;
    1054           45 :         destructor->destroy((CCC_Arguments){
    1055           15 :             .type = data_at(map, node),
    1056           15 :             .context = destructor->context,
    1057              :         });
    1058           15 :         node = next;
    1059           29 :     }
    1060            2 : }
    1061              : 
    1062              : static inline CCC_Order
    1063      6744691 : order_nodes(
    1064              :     struct CCC_Array_adaptive_map const *const map,
    1065              :     void const *const key,
    1066              :     size_t const node
    1067              : ) {
    1068     26978764 :     return map->comparator.compare((CCC_Key_comparator_arguments){
    1069      6744691 :         .key_left = key,
    1070      6744691 :         .type_right = data_at(map, node),
    1071      6744691 :         .context = map->comparator.context,
    1072              :     });
    1073              : }
    1074              : 
    1075              : static inline void
    1076        10404 : init_node(struct CCC_Array_adaptive_map const *const map, size_t const node) {
    1077        10404 :     struct CCC_Array_adaptive_map_node *const e = node_at(map, node);
    1078        10404 :     e->branch[L] = e->branch[R] = e->parent = 0;
    1079        10404 : }
    1080              : 
    1081              : /** Calculates the number of bytes needed for user data INCLUDING any bytes we
    1082              : need to add to the end of the array such that the following nodes array starts
    1083              : on an aligned byte boundary given the alignment requirements of a node. This
    1084              : means the value returned from this function may or may not be slightly larger
    1085              : then the raw size of just user elements if rounding up must occur. */
    1086              : static inline size_t
    1087          205 : data_bytes(size_t const sizeof_type, size_t const capacity) {
    1088          205 :     return CCC_roundup(sizeof_type * capacity, ALIGNOF_NODE);
    1089              : }
    1090              : 
    1091              : /** Calculates the number of bytes needed for the nodes array without any
    1092              : consideration for end padding as no arrays follow. */
    1093              : static inline size_t
    1094           36 : nodes_bytes(size_t const capacity) {
    1095           36 :     return SIZEOF_NODE * capacity;
    1096              : }
    1097              : 
    1098              : /** Calculates the number of bytes needed for all arrays in the Struct of Arrays
    1099              : map design INCLUDING any extra padding bytes that need to be added between the
    1100              : data and node arrays and the node and parity arrays. Padding might be needed if
    1101              : the alignment of the type in next array that follows a preceding array is
    1102              : different from the preceding array. In that case it is the preceding array's
    1103              : responsibility to add padding bytes to its end such that the next array begins
    1104              : on an aligned byte boundary for its own type. This means that the bytes returned
    1105              : by this function may be greater than summing the (sizeof(type) * capacity) for
    1106              : each array in the conceptual struct.
    1107              : 
    1108              : This functions checks for overflow at every step of calculating the size of
    1109              : this contiguous allocation and returns CCC_TRUE if overflow occured, otherwise
    1110              : CCC_FALSE. This function should be used when capacity is accepted from an
    1111              : external source such as user input. */
    1112              : static inline CCC_Tribool
    1113           54 : checked_total_bytes(
    1114              :     size_t *const result, size_t const sizeof_type, size_t const capacity
    1115              : ) {
    1116           54 :     size_t node_byte_count = 0;
    1117           54 :     if (ckd_mul(&node_byte_count, capacity, (size_t)SIZEOF_NODE)) {
    1118            0 :         return CCC_TRUE;
    1119              :     }
    1120           54 :     *result = 0;
    1121           54 :     if (ckd_mul(result, sizeof_type, capacity)) {
    1122            0 :         return CCC_TRUE;
    1123              :     }
    1124           54 :     if (CCC_checked_roundup(result, *result, ALIGNOF_NODE)) {
    1125            0 :         return CCC_TRUE;
    1126              :     }
    1127           54 :     if (ckd_add(result, *result, node_byte_count)) {
    1128            0 :         return CCC_TRUE;
    1129              :     }
    1130           54 :     return CCC_FALSE;
    1131           54 : }
    1132              : 
    1133              : /** Returns the base of the node array relative to the data base pointer. This
    1134              : positions is guaranteed to be the first aligned byte given the alignment of the
    1135              : node type after the data array. The data array has added any necessary padding
    1136              : after it to ensure that the base of the node array is aligned for its type. */
    1137              : static inline struct CCC_Array_adaptive_map_node *
    1138          169 : nodes_base_address(
    1139              :     size_t const sizeof_type, void const *const data, size_t const capacity
    1140              : ) {
    1141          338 :     return (struct CCC_Array_adaptive_map_node *)((char *)data
    1142          169 :                                                   + data_bytes(
    1143          169 :                                                       sizeof_type, capacity
    1144              :                                                   ));
    1145              : }
    1146              : 
    1147              : /** Copies over the Struct of Arrays contained within the one contiguous
    1148              : allocation of the map to the new memory provided. Assumes the new_data pointer
    1149              : points to the base of an allocation that has been allocated with sufficient
    1150              : bytes to support the user data, nodes, and parity arrays for the provided new
    1151              : capacity. */
    1152              : static inline void
    1153           53 : resize_struct_of_arrays(
    1154              :     struct CCC_Array_adaptive_map const *const source,
    1155              :     void *const destination_data_base,
    1156              :     size_t const destination_capacity
    1157              : ) {
    1158           53 :     if (!source->data) {
    1159           17 :         return;
    1160              :     }
    1161           36 :     assert(destination_capacity >= source->capacity);
    1162           36 :     size_t const sizeof_type = source->sizeof_type;
    1163              :     /* Each section of the allocation "grows" when we re-size so one copy would
    1164              :        not work. Instead each component is copied over allowing each to grow. */
    1165           36 :     (void)memcpy(
    1166           36 :         destination_data_base,
    1167           36 :         source->data,
    1168           36 :         data_bytes(sizeof_type, source->capacity)
    1169              :     );
    1170           36 :     (void)memcpy(
    1171           36 :         nodes_base_address(
    1172           36 :             sizeof_type, destination_data_base, destination_capacity
    1173              :         ),
    1174           36 :         nodes_base_address(sizeof_type, source->data, source->capacity),
    1175           36 :         nodes_bytes(source->capacity)
    1176              :     );
    1177           89 : }
    1178              : 
    1179              : static inline void
    1180          107 : swap(void *const temp, size_t const sizeof_type, void *const a, void *const b) {
    1181          107 :     if (a == b) {
    1182            0 :         return;
    1183              :     }
    1184          107 :     (void)memcpy(temp, a, sizeof_type);
    1185          107 :     (void)memcpy(a, b, sizeof_type);
    1186          107 :     (void)memcpy(b, temp, sizeof_type);
    1187          214 : }
    1188              : 
    1189              : static inline struct CCC_Array_adaptive_map_node *
    1190     30461595 : node_at(struct CCC_Array_adaptive_map const *const map, size_t const i) {
    1191     30461595 :     return &map->nodes[i];
    1192              : }
    1193              : 
    1194              : static inline void *
    1195     13217420 : data_at(struct CCC_Array_adaptive_map const *const map, size_t const i) {
    1196     13217420 :     return (char *)map->data + (i * map->sizeof_type);
    1197              : }
    1198              : 
    1199              : static inline size_t
    1200     21520597 : branch_index(
    1201              :     struct CCC_Array_adaptive_map const *const map,
    1202              :     size_t const parent,
    1203              :     enum Branch const dir
    1204              : ) {
    1205     21520597 :     return node_at(map, parent)->branch[dir];
    1206              : }
    1207              : 
    1208              : static inline size_t
    1209      3481892 : parent_index(
    1210              :     struct CCC_Array_adaptive_map const *const map, size_t const child
    1211              : ) {
    1212      3481892 :     return node_at(map, child)->parent;
    1213              : }
    1214              : 
    1215              : static inline size_t *
    1216       461472 : branch_pointer(
    1217              :     struct CCC_Array_adaptive_map const *const map,
    1218              :     size_t const node,
    1219              :     enum Branch const branch
    1220              : ) {
    1221       461472 :     return &node_at(map, node)->branch[branch];
    1222              : }
    1223              : 
    1224              : static inline size_t *
    1225       497366 : parent_pointer(
    1226              :     struct CCC_Array_adaptive_map const *const map, size_t const node
    1227              : ) {
    1228       497366 :     return &node_at(map, node)->parent;
    1229              : }
    1230              : 
    1231              : static inline void *
    1232      6437492 : key_at(struct CCC_Array_adaptive_map const *const map, size_t const i) {
    1233      6437492 :     return (char *)data_at(map, i) + map->key_offset;
    1234              : }
    1235              : 
    1236              : static void *
    1237         8080 : key_in_slot(
    1238              :     struct CCC_Array_adaptive_map const *map, void const *const user_struct
    1239              : ) {
    1240         8080 :     return (char *)user_struct + map->key_offset;
    1241              : }
    1242              : 
    1243              : /*===========================   Validation   ===============================*/
    1244              : 
    1245              : /* NOLINTBEGIN(*misc-no-recursion) */
    1246              : 
    1247              : /** @internal */
    1248              : struct Tree_range {
    1249              :     size_t low;
    1250              :     size_t root;
    1251              :     size_t high;
    1252              : };
    1253              : 
    1254              : static size_t
    1255      6957561 : recursive_count(
    1256              :     struct CCC_Array_adaptive_map const *const map, size_t const r
    1257              : ) {
    1258      6957561 :     if (!r) {
    1259      3483708 :         return 0;
    1260              :     }
    1261      6947706 :     return 1 + recursive_count(map, branch_index(map, r, R))
    1262      3473853 :          + recursive_count(map, branch_index(map, r, L));
    1263      6957561 : }
    1264              : 
    1265              : static CCC_Tribool
    1266      6957561 : are_subtrees_valid(
    1267              :     struct CCC_Array_adaptive_map const *map, struct Tree_range const r
    1268              : ) {
    1269      6957561 :     if (!r.root) {
    1270      3483708 :         return CCC_TRUE;
    1271              :     }
    1272      3473853 :     if (r.low
    1273      3473853 :         && order_nodes(map, key_at(map, r.low), r.root) != CCC_ORDER_LESSER) {
    1274            0 :         return CCC_FALSE;
    1275              :     }
    1276      3473853 :     if (r.high
    1277      3473853 :         && order_nodes(map, key_at(map, r.high), r.root) != CCC_ORDER_GREATER) {
    1278            0 :         return CCC_FALSE;
    1279              :     }
    1280      6947706 :     return are_subtrees_valid(
    1281      3473853 :                map,
    1282     13895412 :                (struct Tree_range){
    1283      3473853 :                    .low = r.low,
    1284      3473853 :                    .root = branch_index(map, r.root, L),
    1285      3473853 :                    .high = r.root,
    1286              :                }
    1287              :            )
    1288      3473853 :         && are_subtrees_valid(
    1289      3473853 :                map,
    1290     13895412 :                (struct Tree_range){
    1291      3473853 :                    .low = r.root,
    1292      3473853 :                    .root = branch_index(map, r.root, R),
    1293      3473853 :                    .high = r.high,
    1294              :                }
    1295              :         );
    1296      6957561 : }
    1297              : 
    1298              : static CCC_Tribool
    1299      6957561 : is_storing_parent(
    1300              :     struct CCC_Array_adaptive_map const *const map,
    1301              :     size_t const p,
    1302              :     size_t const root
    1303              : ) {
    1304      6957561 :     if (!root) {
    1305      3483708 :         return CCC_TRUE;
    1306              :     }
    1307      3473853 :     if (parent_index(map, root) != p) {
    1308            0 :         return CCC_FALSE;
    1309              :     }
    1310      6947706 :     return is_storing_parent(map, root, branch_index(map, root, L))
    1311      3473853 :         && is_storing_parent(map, root, branch_index(map, root, R));
    1312      6957561 : }
    1313              : 
    1314              : static CCC_Tribool
    1315         9855 : is_free_list_valid(struct CCC_Array_adaptive_map const *const map) {
    1316         9855 :     if (!map->count) {
    1317            0 :         return CCC_TRUE;
    1318              :     }
    1319         9855 :     size_t cur_free_index = map->free_list;
    1320         9855 :     size_t list_count = 0;
    1321      4433075 :     while (cur_free_index && list_count < map->capacity) {
    1322      4423220 :         cur_free_index = node_at(map, cur_free_index)->next_free;
    1323      4423220 :         ++list_count;
    1324              :     }
    1325         9855 :     if (cur_free_index) {
    1326            0 :         return CCC_FALSE;
    1327              :     }
    1328         9855 :     if (list_count + map->count != map->capacity) {
    1329            0 :         return CCC_FALSE;
    1330              :     }
    1331         9855 :     return CCC_TRUE;
    1332         9855 : }
    1333              : 
    1334              : static CCC_Tribool
    1335         9865 : validate(struct CCC_Array_adaptive_map const *const map) {
    1336         9865 :     if (!map->count) {
    1337           10 :         return CCC_TRUE;
    1338              :     }
    1339         9855 :     if (!are_subtrees_valid(map, (struct Tree_range){.root = map->root})) {
    1340            0 :         return CCC_FALSE;
    1341              :     }
    1342         9855 :     size_t const size = recursive_count(map, map->root);
    1343         9855 :     if (size && size != map->count - 1) {
    1344            0 :         return CCC_FALSE;
    1345              :     }
    1346         9855 :     if (!is_storing_parent(map, 0, map->root)) {
    1347            0 :         return CCC_FALSE;
    1348              :     }
    1349         9855 :     if (!is_free_list_valid(map)) {
    1350            0 :         return CCC_FALSE;
    1351              :     }
    1352         9855 :     return CCC_TRUE;
    1353         9865 : }
    1354              : 
    1355              : /* NOLINTEND(*misc-no-recursion) */
        

Generated by: LCOV version 2.4-beta