kiddo 5.3.3

A high-performance, flexible, ergonomic k-d tree library. Ideal for geo- and astro- nearest-neighbour and k-nearest-neighbor queries
Documentation
#![cfg(feature = "rkyv")]

use kiddo::immutable::float::kdtree::{ImmutableKdTree, ImmutableKdTreeRK};
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};

const ALLOCATION_SLOTS: usize = 1024;
static POINTERS: [AtomicUsize; ALLOCATION_SLOTS] =
    [const { AtomicUsize::new(0) }; ALLOCATION_SLOTS];
static SIZES: [AtomicUsize; ALLOCATION_SLOTS] = [const { AtomicUsize::new(0) }; ALLOCATION_SLOTS];
static ALIGNMENTS: [AtomicUsize; ALLOCATION_SLOTS] =
    [const { AtomicUsize::new(0) }; ALLOCATION_SLOTS];
static MISMATCH: [AtomicUsize; 5] = [const { AtomicUsize::new(0) }; 5];

struct TrackingAllocator;

unsafe impl GlobalAlloc for TrackingAllocator {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        let pointer = unsafe { System.alloc(layout) };

        if !pointer.is_null() && layout.align() >= 64 {
            for index in 0..ALLOCATION_SLOTS {
                if POINTERS[index]
                    .compare_exchange(0, pointer as usize, SeqCst, SeqCst)
                    .is_ok()
                {
                    SIZES[index].store(layout.size(), SeqCst);
                    ALIGNMENTS[index].store(layout.align(), SeqCst);
                    break;
                }
            }
        }

        pointer
    }

    unsafe fn dealloc(&self, pointer: *mut u8, layout: Layout) {
        for index in 0..ALLOCATION_SLOTS {
            if POINTERS[index].load(SeqCst) == pointer as usize {
                let allocated_size = SIZES[index].load(SeqCst);
                let allocated_alignment = ALIGNMENTS[index].load(SeqCst);

                if (allocated_size, allocated_alignment) != (layout.size(), layout.align())
                    && MISMATCH[0].load(SeqCst) == 0
                {
                    MISMATCH[1].store(allocated_size, SeqCst);
                    MISMATCH[2].store(allocated_alignment, SeqCst);
                    MISMATCH[3].store(layout.size(), SeqCst);
                    MISMATCH[4].store(layout.align(), SeqCst);
                    MISMATCH[0].store(pointer as usize, SeqCst);
                }

                POINTERS[index].store(usize::MAX, SeqCst);
                break;
            }
        }

        unsafe { System.dealloc(pointer, layout) };
    }
}

#[global_allocator]
static ALLOCATOR: TrackingAllocator = TrackingAllocator;

#[test]
fn converting_to_rkyv_tree_deallocates_stems_with_their_original_layout() {
    let points: Vec<[f64; 3]> = (0..2000)
        .map(|i| [i as f64, (i * 3 % 977) as f64, (i * 7 % 613) as f64])
        .collect();
    let tree: ImmutableKdTree<f64, u32, 3, 32> = ImmutableKdTree::new_from_slice(&points);
    let tree_rk: ImmutableKdTreeRK<f64, u32, 3, 32> = tree.into();
    drop(tree_rk);

    assert_eq!(
        MISMATCH[0].load(SeqCst),
        0,
        "allocation layout mismatch: allocated with size={} align={}, \
         deallocated with size={} align={}",
        MISMATCH[1].load(SeqCst),
        MISMATCH[2].load(SeqCst),
        MISMATCH[3].load(SeqCst),
        MISMATCH[4].load(SeqCst),
    );
}