polylane 0.15.0

Portable and versatile SIMD.
Documentation
// Copyright 2025 Gabriel Bjørnager Jensen.
//
// This Source Code Form is subject to the terms of
// the Mozilla Public License, v. 2.0. If a copy of
// the MPL was not distributed with this file, you
// can obtain one at:
// <https://mozilla.org/MPL/2.0/>.

use crate::{simd, ValidLayout};
use crate::mask::{Mask, MaskLayout};
use crate::num::{SimdInt, SimdUint};
use crate::ptr::SimdConstPtr;
use crate::simd::{Simd, SimdLayout, SimdScalar};

use core::ptr;

impl<T, const N: usize> crate::ptr::seal::SimdConstPtr for Simd<*const T, N>
where
	T: Sized,

	SimdLayout<*const T, N>: ValidLayout,

	SimdLayout<usize, N>: ValidLayout,
	{}

impl<T, const N: usize> SimdConstPtr<T, N> for Simd<*const T, N>
where
	T: Sized,

	SimdLayout<*const T, N>: ValidLayout,

	SimdLayout<usize, N>: ValidLayout,
{
	#[inline(always)]
	fn null() -> Self {
		simd![ptr::null(); N]
	}

	#[inline]
	fn dangling() -> Self {
		simd![ptr::dangling(); N]
	}

	#[inline]
	fn with_exposed_provenance(addr: Simd<usize, N>) -> Self
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		addr.map(ptr::with_exposed_provenance)
	}

	#[inline(always)]
	fn without_provenance(addr: Simd<usize, N>) -> Self
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		unsafe { addr.transmute() }
	}

	#[inline]
	#[track_caller]
	unsafe fn offset(self, count: Simd<isize, N>) -> Self
	where
		SimdLayout<isize, N>: ValidLayout,
	{
		self.wrapping_offset(count)
	}

	#[inline]
	#[track_caller]
	unsafe fn byte_offset(self, count: Simd<isize, N>) -> Self
	where
		SimdLayout<isize, N>: ValidLayout,
	{
		self.wrapping_byte_offset(count)
	}

	#[inline]
	#[track_caller]
	unsafe fn add(self, count: Simd<usize, N>) -> Self
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		self.wrapping_add(count)
	}

	#[inline]
	#[track_caller]
	unsafe fn byte_add(self, count: Simd<usize, N>) -> Self
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		self.wrapping_byte_add(count)
	}

	#[inline]
	#[track_caller]
	unsafe fn sub(self, count: Simd<usize, N>) -> Self
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		self.wrapping_sub(count)
	}

	#[inline]
	#[track_caller]
	unsafe fn byte_sub(self, count: Simd<usize, N>) -> Self
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		self.wrapping_byte_sub(count)
	}

	#[inline]
	#[track_caller]
	fn wrapping_offset(self, mut count: Simd<isize, N>) -> Self
	where
		SimdLayout<isize, N>: ValidLayout,
	{
		count = unsafe { count.unchecked_mul(simd![size_of::<T>().cast_signed(); N]) };
		let addr = self.expose_provenance().wrapping_add_signed(count);
		Self::with_exposed_provenance(addr)
	}

	#[inline]
	#[track_caller]
	fn wrapping_byte_offset(self, count: Simd<isize, N>) -> Self
	where
		SimdLayout<isize, N>: ValidLayout,
	{
		let addr = self.expose_provenance().wrapping_add_signed(count);
		Self::with_exposed_provenance(addr)
	}

	#[inline]
	#[track_caller]
	fn wrapping_add(self, mut count: Simd<usize, N>) -> Self
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		count = unsafe { count.unchecked_mul(simd![size_of::<T>(); N]) };
		let addr = self.expose_provenance().wrapping_add(count);
		Self::with_exposed_provenance(addr)
	}

	#[inline]
	#[track_caller]
	fn wrapping_byte_add(self, count: Simd<usize, N>) -> Self
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		let addr = self.expose_provenance().wrapping_add(count);
		Self::with_exposed_provenance(addr)
	}

	#[inline]
	#[track_caller]
	fn wrapping_sub(self, mut count: Simd<usize, N>) -> Self
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		count = unsafe { count.unchecked_mul(simd![size_of::<T>(); N]) };
		let addr = self.expose_provenance().wrapping_sub(count);
		Self::with_exposed_provenance(addr)
	}

	#[inline]
	#[track_caller]
	fn wrapping_byte_sub(self, count: Simd<usize, N>) -> Self
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		let addr = self.expose_provenance().wrapping_sub(count);
		Self::with_exposed_provenance(addr)
	}

	#[inline]
	#[track_caller]
	fn map_addr<F>(self, op: F) -> Self
	where
		F: FnMut(usize) -> usize,

		SimdLayout<usize, N>: ValidLayout,
	{
		let addr = self.expose_provenance().map(op);
		Self::with_exposed_provenance(addr)
	}

	#[inline]
	#[track_caller]
	unsafe fn read(self) -> Simd<T, N>
	where
		T: SimdScalar,

		SimdLayout<T, N>: ValidLayout,
	{
		self.map(|p| unsafe { p.read() })
	}

	#[inline]
	#[track_caller]
	unsafe fn read_volatile(self) -> Simd<T, N>
	where
		T: SimdScalar,

		SimdLayout<T, N>: ValidLayout,
	{
		self.map(|p| unsafe { p.read_volatile() })
	}

	#[inline]
	#[track_caller]
	unsafe fn read_unaligned(self) -> Simd<T, N>
	where
		T: SimdScalar,

		SimdLayout<T, N>: ValidLayout,
	{
		self.map(|p| unsafe { p.read_unaligned() })
	}

	#[inline]
	#[track_caller]
	fn addr(self) -> Simd<usize, N>
	where
		SimdLayout<usize,  N>: ValidLayout,
	{
		// SAFETY: This method cannot be called under
		// `const` evaluation.
		unsafe { self.transmute() }
	}

	#[inline]
	#[track_caller]
	fn align_offset(self, align: Simd<usize, N>) -> Simd<usize, N>
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		self.zip_with(align, <*const T>::align_offset)
	}

	#[inline]
	#[track_caller]
	fn is_null(self) -> Mask<N>
	where
		MaskLayout<N>: ValidLayout,
	{
		self.to_array().map(<*const T>::is_null).into()
	}

	#[inline]
	#[track_caller]
	fn is_aligned(self) -> Mask<N>
	where
		MaskLayout<N>: ValidLayout,
	{
		self.to_array().map(<*const T>::is_aligned).into()
	}

	#[inline]
	#[track_caller]
	fn with_addr(self, addr: Simd<usize, N>) -> Self
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		let offset = addr.wrapping_sub(self.addr());
		self.wrapping_byte_add(offset)
	}

	#[inline]
	#[track_caller]
	fn cast<U>(self) -> Simd<*const U, N>
	where
		U: Sized,

		SimdLayout<*const U, N>: ValidLayout,
	{
		self.map(<*const T>::cast)
	}

	#[inline]
	#[track_caller]
	fn cast_mut(self) -> Simd<*mut T, N>
	where
		SimdLayout<*mut T, N>: ValidLayout,
	{
		self.map(<*const T>::cast_mut)
	}

	#[inline]
	#[track_caller]
	fn expose_provenance(self) -> Simd<usize, N>
	where
		SimdLayout<usize, N>: ValidLayout,
	{
		self.map(<*const T>::expose_provenance)
	}
}