Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
rust: [1.56.0, stable, nightly]
rust: [1.59.0, stable, nightly]
features: ["+avx2", "+sse2"]
env:
RUSTFLAGS: "-C target-feature=${{matrix.features}}"
Expand All @@ -34,18 +34,25 @@ jobs:
cargo test --verbose --release --features "$FEATURES"

build_aarch64:
runs-on: ubuntu-latest
runs-on: macos-14
strategy:
matrix:
rust: [1.56.0, stable, nightly]
rust: [1.59.0, stable, nightly]
features: ["+neon"]
env:
RUSTFLAGS: "-C target-feature=${{matrix.features}}"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
target: aarch64-unknown-linux-gnu
target: aarch64-apple-darwin
toolchain: ${{ matrix.rust }}
- name: Tests (aarch64)
run: cargo check --target aarch64-unknown-linux-gnu
run: |
cargo test -v --no-default-features --tests --lib &&
cargo build --verbose --features "$FEATURES" &&
cargo test --verbose --features "$FEATURES" &&
cargo test --verbose --release --features "$FEATURES"

# Use clippy to lint for code smells
clippy:
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.5.4"
authors = ["bluss"]
license = "MIT OR Apache-2.0"
readme = "README.md"
rust-version = "1.56"
rust-version = "1.59"
edition = "2021"

description = "FixedBitSet is a simple bitset collection"
Expand Down
7 changes: 7 additions & 0 deletions src/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ use core::hash::{Hash, Hasher};
not(target_arch = "wasm32"),
not(target_feature = "sse2"),
not(target_feature = "avx2"),
not(target_feature = "neon"),
))]
mod default;
#[cfg(all(
not(target_arch = "wasm32"),
not(target_feature = "sse2"),
not(target_feature = "avx2"),
not(target_feature = "neon"),
))]
pub use self::default::*;

Expand All @@ -32,6 +34,11 @@ mod avx2;
#[cfg(all(not(target_arch = "wasm32"), target_feature = "avx2",))]
pub use self::avx2::*;

#[cfg(all(not(target_arch = "wasm32"), target_feature = "neon",))]
mod neon;
#[cfg(all(not(target_arch = "wasm32"), target_feature = "neon",))]
pub use self::neon::*;

#[cfg(target_arch = "wasm32")]
mod wasm32;
#[cfg(target_arch = "wasm32")]
Expand Down
108 changes: 108 additions & 0 deletions src/block/neon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#[cfg(target_arch = "aarch64")]
use core::arch::aarch64::*;
use core::{
cmp::Ordering,
hash::{Hash, Hasher},
iter::Iterator,
ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not},
};

#[derive(Copy, Clone, Debug)]
#[repr(transparent)]
pub struct Block(pub uint8x16_t);

impl Block {
pub const USIZE_COUNT: usize = core::mem::size_of::<Self>() / core::mem::size_of::<usize>();
pub const NONE: Self = Self::from_usize_array([0; Self::USIZE_COUNT]);
pub const ALL: Self = Self::from_usize_array([core::usize::MAX; Self::USIZE_COUNT]);
pub const BITS: usize = core::mem::size_of::<Self>() * 8;

#[inline]
pub fn into_usize_array(self) -> [usize; Self::USIZE_COUNT] {
unsafe { core::mem::transmute(self.0) }
}

#[inline]
pub const fn from_usize_array(array: [usize; Self::USIZE_COUNT]) -> Self {
Self(unsafe { core::mem::transmute(array) })
}

#[inline]
pub fn is_empty(self) -> bool {
unsafe { vmaxvq_u8(self.0) == 0 }
}

#[inline]
pub fn andnot(self, other: Self) -> Self {
Self(unsafe { vbicq_u8(self.0, other.0) })
}
}

impl Not for Block {
type Output = Block;
#[inline]
fn not(self) -> Self::Output {
Self(unsafe { vmvnq_u8(self.0) })
}
}

impl BitAnd for Block {
type Output = Block;
#[inline]
fn bitand(self, other: Self) -> Self::Output {
Self(unsafe { vandq_u8(self.0, other.0) })
}
}

impl BitAndAssign for Block {
#[inline]
fn bitand_assign(&mut self, other: Self) {
unsafe {
self.0 = vandq_u8(self.0, other.0);
}
}
}

impl BitOr for Block {
type Output = Block;
#[inline]
fn bitor(self, other: Self) -> Self::Output {
Self(unsafe { vorrq_u8(self.0, other.0) })
}
}

impl BitOrAssign for Block {
#[inline]
fn bitor_assign(&mut self, other: Self) {
unsafe {
self.0 = vorrq_u8(self.0, other.0);
}
}
}

impl BitXor for Block {
type Output = Block;
#[inline]
fn bitxor(self, other: Self) -> Self::Output {
Self(unsafe { veorq_u8(self.0, other.0) })
}
}

impl BitXorAssign for Block {
#[inline]
fn bitxor_assign(&mut self, other: Self) {
unsafe {
self.0 = veorq_u8(self.0, other.0);
}
}
}

impl PartialEq for Block {
#[inline]
fn eq(&self, other: &Self) -> bool {
unsafe {
let eq = vceqq_u8(self.0, other.0);
vminvq_u8(eq) == 0xff
}
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//! When SIMD is not available on the target, the crate will gracefully fallback to a default implementation. It is intended to add support for other SIMD architectures
//! once they appear in stable Rust.
//!
//! Currently only SSE2/AVX2 on x86/x86_64 and wasm32 SIMD are supported as this is what stable Rust supports.
//! Currently only SSE2/AVX2 on x86/x86_64, NEON on aarch64, and wasm32 SIMD are supported as this is what stable Rust supports.
#![no_std]
#![deny(clippy::undocumented_unsafe_blocks)]

Expand Down