use std::{ffi::c_void, ptr::NonNull};
use shared::OwnedPtr;
use crate::dlkr::DLAllocator;
impl fromsoftware_shared_stl::StlAllocator for &'static DLAllocator {
unsafe fn allocate_raw(&self, size: usize, align: usize) -> *mut c_void {
let allocation = (self.vftable.allocate_aligned)(self, size, align);
if allocation.is_null() {
panic!("DLAllocator returned null pointer")
}
allocation as _
}
unsafe fn deallocate_raw(&self, ptr: *mut c_void) {
(self.vftable.deallocate)(self, ptr as _);
}
}
pub type DLList<T> = fromsoftware_shared_stl::List<T, &'static DLAllocator>;
pub type DLVector<T> = fromsoftware_shared_stl::Vector<T, &'static DLAllocator>;
pub type DLMap<K, V> = fromsoftware_shared_stl::Map<K, V, &'static DLAllocator>;
pub type DLMultiMap<K, V> = fromsoftware_shared_stl::MultiMap<K, V, &'static DLAllocator>;
pub type DLSet<V> = fromsoftware_shared_stl::Set<V, &'static DLAllocator>;
pub type DLMultiSet<V> = fromsoftware_shared_stl::MultiSet<V, &'static DLAllocator>;
pub type UnkDLTree<V> =
fromsoftware_shared_stl::RbTree<V, &'static DLAllocator, fromsoftware_shared_stl::Less>;
#[repr(C)]
pub struct ChainingMap<K: Ord, V> {
base: DLMap<K, NonNull<ChainingMapBucketEntry<V>>>,
buckets: OwnedPtr<ArrayWithHeader<ChainingMapBucketEntry<V>>>,
}
impl<K: Ord, V> ChainingMap<K, V> {
pub fn len(&self) -> usize {
self.base.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
self.base.iter().flat_map(|pair| {
let key = &pair.first;
let bucket = unsafe { pair.second.as_ref() };
bucket.iter().map(move |value| (key, value))
})
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
self.base.iter_mut().flat_map(|pair| {
let key = &pair.first;
let bucket = unsafe { pair.second.as_mut() };
bucket.iter_mut().map(move |value| (key, value))
})
}
pub fn iter_chains(&self) -> impl Iterator<Item = (&K, &ChainingMapBucketEntry<V>)> {
self.base
.iter()
.map(|pair| (&pair.first, unsafe { pair.second.as_ref() }))
}
pub fn iter_chains_mut(
&mut self,
) -> impl Iterator<Item = (&K, &mut ChainingMapBucketEntry<V>)> {
self.base
.iter_mut()
.map(|pair| (&pair.first, unsafe { pair.second.as_mut() }))
}
pub fn buckets(&self) -> &[ChainingMapBucketEntry<V>] {
unsafe { self.buckets.as_slice() }
}
}
#[repr(C)]
pub struct ChainingMapBucketEntry<T> {
pub data: T,
pub next: Option<NonNull<ChainingMapBucketEntry<T>>>,
}
impl<T> ChainingMapBucketEntry<T> {
pub fn chain_len(&self) -> usize {
self.iter().count()
}
pub fn is_singleton(&self) -> bool {
self.next.is_none()
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
let mut current = Some(NonNull::from(self));
std::iter::from_fn(move || {
let node = current?;
unsafe {
let node_ref = node.as_ref();
current = node_ref.next;
Some(&node_ref.data)
}
})
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
let mut current = Some(NonNull::from(self));
std::iter::from_fn(move || {
let mut node = current?;
unsafe {
let node_ref = node.as_mut();
current = node_ref.next;
Some(&mut node_ref.data)
}
})
}
}
#[repr(C)]
pub struct CSFixedList<T, const N: usize>
where
T: Sized,
{
vftable: usize,
pub data: [CSFixedListEntry<T>; N],
unk1: u32,
unk2: u32,
pub head_ptr: OwnedPtr<CSFixedListEntry<T>>,
pub head: CSFixedListEntry<T>,
}
#[repr(C)]
pub struct CSFixedListEntry<T> {
pub data: T,
pub next: Option<NonNull<CSFixedListEntry<T>>>,
pub previous: Option<NonNull<CSFixedListEntry<T>>>,
index: usize,
}
#[repr(C)]
pub struct ArrayWithHeader<T> {
first_item: T,
}
impl<T> ArrayWithHeader<T> {
pub unsafe fn as_slice(&self) -> &[T] {
unsafe { std::slice::from_raw_parts(&self.first_item as *const T, self.len()) }
}
pub unsafe fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { std::slice::from_raw_parts_mut(&mut self.first_item as *mut T, self.len()) }
}
pub unsafe fn header(&self) -> &AllocationHeader {
unsafe {
let header_ptr = (self as *const Self as *const u8)
.sub(std::mem::size_of::<AllocationHeader>())
as *const AllocationHeader;
&*header_ptr
}
}
pub unsafe fn is_valid(&self) -> bool {
unsafe { self.header().is_valid() }
}
pub unsafe fn len(&self) -> usize {
unsafe { self.header().count }
}
pub unsafe fn is_empty(&self) -> bool {
unsafe { self.len() == 0 }
}
}
#[repr(C)]
pub struct AllocationHeader {
pub self_ptr: NonNull<AllocationHeader>,
pub count: usize,
}
impl AllocationHeader {
pub fn is_valid(&self) -> bool {
std::ptr::eq(self.self_ptr.as_ptr(), self)
}
}