llvm-native-core 0.1.16

LLVM-native core semantic engine — IR, CodeGen, X86 MC, Clang frontend pipeline
//! LLVM ArrayRef<T> — non-owning reference to a contiguous array.
//!
//! Clean-room behavioral reconstruction.
//! @llvm_behavior: ArrayRef is a thin wrapper around a pointer+length,
//!   providing safe access to a contiguous sequence of T without owning it.
//!   Equivalent to Rust's &[T] with LLVM-specific behavioral semantics.

use std::ops;

/// A non-owning reference to a contiguous array of T.
///
/// ArrayRef does not own its data. It is the primary way to pass
/// arrays/vectors to functions without copying.
#[derive(Clone, Copy)]
pub struct ArrayRef<'a, T> {
    data: &'a [T],
}

impl<'a, T> ArrayRef<'a, T> {
    /// Construct an ArrayRef from a slice.
    #[inline]
    pub fn new(data: &'a [T]) -> Self {
        Self { data }
    }

    /// An empty ArrayRef.
    #[inline]
    pub fn empty() -> Self {
        Self { data: &[] }
    }

    /// Number of elements.
    #[inline]
    pub fn size(&self) -> usize {
        self.data.len()
    }

    /// Number of elements (alias).
    #[inline]
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// True if empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    /// Get element at index.
    #[inline]
    pub fn get(&self, index: usize) -> Option<&T> {
        self.data.get(index)
    }

    /// Reference to first element.
    #[inline]
    pub fn front(&self) -> Option<&T> {
        self.data.first()
    }

    /// Reference to last element.
    #[inline]
    pub fn back(&self) -> Option<&T> {
        self.data.last()
    }

    /// Get a sub-array from start..start+N.
    /// @llvm_behavior: slice(Start, N) — clamps to available length.
    #[inline]
    pub fn slice(&self, start: usize, n: usize) -> ArrayRef<'a, T> {
        if start >= self.data.len() {
            return ArrayRef::empty();
        }
        let end = (start + n).min(self.data.len());
        ArrayRef::new(&self.data[start..end])
    }

    /// Drop the first N elements.
    #[inline]
    pub fn drop_front(&self, n: usize) -> ArrayRef<'a, T> {
        let start = n.min(self.data.len());
        ArrayRef::new(&self.data[start..])
    }

    /// Drop the last N elements.
    #[inline]
    pub fn drop_back(&self, n: usize) -> ArrayRef<'a, T> {
        let n = n.min(self.data.len());
        ArrayRef::new(&self.data[..self.data.len() - n])
    }

    /// Take the first N elements.
    #[inline]
    pub fn take_front(&self, n: usize) -> ArrayRef<'a, T> {
        let end = n.min(self.data.len());
        ArrayRef::new(&self.data[..end])
    }

    /// Take the last N elements.
    #[inline]
    pub fn take_back(&self, n: usize) -> ArrayRef<'a, T> {
        let n = n.min(self.data.len());
        ArrayRef::new(&self.data[self.data.len() - n..])
    }

    /// Returns a pointer to the start of the data.
    #[inline]
    pub fn data_ptr(&self) -> *const T {
        self.data.as_ptr()
    }

    /// Returns true if this ArrayRef equals another.
    #[inline]
    pub fn equals(&self, other: &[T]) -> bool
    where
        T: PartialEq,
    {
        self.data == other
    }

    /// Iterator over elements.
    #[inline]
    pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
        self.data.iter()
    }

    /// Convert to a native Rust slice.
    #[inline]
    pub fn as_slice(&self) -> &'a [T] {
        self.data
    }
}

// === Trait Implementations ===

impl<'a, T> ops::Index<usize> for ArrayRef<'a, T> {
    type Output = T;

    fn index(&self, index: usize) -> &Self::Output {
        &self.data[index]
    }
}

impl<'a, T: PartialEq> PartialEq for ArrayRef<'a, T> {
    fn eq(&self, other: &Self) -> bool {
        self.data == other.data
    }
}

impl<'a, T: Eq> Eq for ArrayRef<'a, T> {}

impl<'a, T: fmt::Debug> fmt::Debug for ArrayRef<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.data.fmt(f)
    }
}

impl<'a, T> From<&'a [T]> for ArrayRef<'a, T> {
    fn from(data: &'a [T]) -> Self {
        ArrayRef::new(data)
    }
}

impl<'a, T, const N: usize> From<&'a [T; N]> for ArrayRef<'a, T> {
    fn from(data: &'a [T; N]) -> Self {
        ArrayRef::new(data.as_slice())
    }
}

impl<'a, T> IntoIterator for ArrayRef<'a, T> {
    type Item = &'a T;
    type IntoIter = std::slice::Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.data.iter()
    }
}

use std::fmt;