Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ mod cabi {
impl<T> Array for RVec<T> {
type Element = T;

fn iter<'i>(&'i self) -> Box<dyn Iterator<Item = &T> + 'i> {
fn iter<'i>(&'i self) -> Box<dyn Iterator<Item = &'i T> + 'i> {
Box::new(<[T]>::iter(self))
}

Expand Down
172 changes: 89 additions & 83 deletions src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ pub trait BaseGenerator {
any(target_arch = "x86_64", target_arch = "x86"),
))]
unsafe fn write_str_simd(&mut self, string: &mut &[u8]) -> io::Result<()> {
write_str_simd_fastest(self.get_writer(), string)
unsafe { write_str_simd_fastest(self.get_writer(), string) }
}
#[cfg(all(target_feature = "avx2", not(feature = "runtime-detection")))]
#[inline]
Expand All @@ -215,7 +215,7 @@ pub trait BaseGenerator {
/// # Errors
/// if the write fails
unsafe fn write_str_simd(&mut self, string: &mut &[u8]) -> io::Result<()> {
write_str_simd_sse42(self.get_writer(), string)
write_str_simd_sse2(self.get_writer(), string)
}

#[cfg(not(any(
Expand All @@ -225,7 +225,7 @@ pub trait BaseGenerator {
),
feature = "portable",
target_feature = "avx2",
target_feature = "sse4.2",
target_feature = "sse2",
target_feature = "simd128",
target_arch = "aarch64",
)))]
Expand Down Expand Up @@ -395,7 +395,7 @@ where
// if std::is_x86_feature_detected!("avx2") {
// write_str_simd_avx2
// } else if std::is_x86_feature_detected!("sse4.2") {
// write_str_simd_sse42
// write_str_simd_sse2
// } else {
// write_str_simd_rust
// }
Expand All @@ -415,9 +415,9 @@ where
// mem::transmute::<FnRaw, WriteStrFn>(fun)(writer, string)

if std::is_x86_feature_detected!("avx2") {
write_str_simd_avx2(writer, string)
} else if std::is_x86_feature_detected!("sse4.2") {
write_str_simd_sse42(writer, string)
unsafe { write_str_simd_avx2(writer, string) }
} else if std::is_x86_feature_detected!("sse2") {
unsafe { write_str_simd_sse2(writer, string) }
} else {
#[cfg(not(feature = "portable"))]
return write_string_rust(writer, string);
Expand Down Expand Up @@ -536,60 +536,63 @@ where
_mm256_or_si256, _mm256_set1_epi8, _mm256_xor_si256,
};

let mut idx = 0;
let zero = _mm256_set1_epi8(0);
let lower_quote_range = _mm256_set1_epi8(0x1F_i8);
#[allow(clippy::cast_possible_wrap)] // it's a const, it's fine
let quote = _mm256_set1_epi8(b'"' as i8);
#[allow(clippy::cast_possible_wrap)] // it's a const, it's fine
let backslash = _mm256_set1_epi8(b'\\' as i8);
while string.len() - idx >= 32 {
// Load 32 bytes of data; _mm256_loadu_si256 does not require alignment
#[allow(clippy::cast_ptr_alignment)]
let data: __m256i = _mm256_loadu_si256(string.as_ptr().add(idx).cast::<__m256i>());
// Test the data against being backslash and quote.
let bs_or_quote = _mm256_or_si256(
_mm256_cmpeq_epi8(data, backslash),
_mm256_cmpeq_epi8(data, quote),
);
// Now mask the data with the quote range (0x1F).
let in_quote_range = _mm256_and_si256(data, lower_quote_range);
// then test of the data is unchanged. aka: xor it with the
// Any field that was inside the quote range it will be zero
// now.
let is_unchanged = _mm256_xor_si256(data, in_quote_range);
let in_range = _mm256_cmpeq_epi8(is_unchanged, zero);
let quote_bits = _mm256_movemask_epi8(_mm256_or_si256(bs_or_quote, in_range));
if quote_bits == 0 {
idx += 32;
} else {
let quote_dist = quote_bits.trailing_zeros() as usize;
stry!(writer.write_all(string.get_unchecked(0..idx + quote_dist)));
unsafe {
let mut idx = 0;
let zero = _mm256_set1_epi8(0);
let lower_quote_range = _mm256_set1_epi8(0x1F_i8);
#[allow(clippy::cast_possible_wrap)] // it's a const, it's fine
let quote = _mm256_set1_epi8(b'"' as i8);
#[allow(clippy::cast_possible_wrap)] // it's a const, it's fine
let backslash = _mm256_set1_epi8(b'\\' as i8);
while string.len() - idx >= 32 {
// Load 32 bytes of data; _mm256_loadu_si256 does not require alignment
#[allow(clippy::cast_ptr_alignment)]
let data: __m256i = _mm256_loadu_si256(string.as_ptr().add(idx).cast::<__m256i>());
// Test the data against being backslash and quote.
let bs_or_quote = _mm256_or_si256(
_mm256_cmpeq_epi8(data, backslash),
_mm256_cmpeq_epi8(data, quote),
);
// Now mask the data with the quote range (0x1F).
let in_quote_range = _mm256_and_si256(data, lower_quote_range);
// then test of the data is unchanged. aka: xor it with the
// Any field that was inside the quote range it will be zero
// now.
let is_unchanged = _mm256_xor_si256(data, in_quote_range);
let in_range = _mm256_cmpeq_epi8(is_unchanged, zero);
let quote_bits = _mm256_movemask_epi8(_mm256_or_si256(bs_or_quote, in_range));
if quote_bits == 0 {
idx += 32;
} else {
let quote_dist = quote_bits.trailing_zeros() as usize;
stry!(writer.write_all(string.get_unchecked(0..idx + quote_dist)));

let ch = string[idx + quote_dist];
match ESCAPED[ch as usize] {
b'u' => stry!(u_encode(writer, ch)),
escape => stry!(writer.write_all(&[b'\\', escape])),
};
let ch = string[idx + quote_dist];
match ESCAPED[ch as usize] {
b'u' => stry!(u_encode(writer, ch)),
escape => stry!(writer.write_all(&[b'\\', escape])),
}

*string = string.get_unchecked(idx + quote_dist + 1..);
idx = 0;
*string = string.get_unchecked(idx + quote_dist + 1..);
idx = 0;
}
}
stry!(writer.write_all(&string[0..idx]));
*string = string.get_unchecked(idx..);
}
stry!(writer.write_all(&string[0..idx]));
*string = string.get_unchecked(idx..);

Ok(())
}

#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
#[target_feature(enable = "sse4.2")]
#[target_feature(enable = "sse2")]
#[inline]
/// Writes a string with simd-acceleration
/// # Safety
/// This function is unsafe because it uses simd instructions
/// # Errors
/// if the write fails
unsafe fn write_str_simd_sse42<W>(writer: &mut W, string: &mut &[u8]) -> io::Result<()>
unsafe fn write_str_simd_sse2<W>(writer: &mut W, string: &mut &[u8]) -> io::Result<()>
where
W: Write,
{
Expand All @@ -604,46 +607,49 @@ where
_mm_set1_epi8, _mm_xor_si128,
};

let mut idx = 0;
let zero = _mm_set1_epi8(0);
let lower_quote_range = _mm_set1_epi8(0x1F_i8);
#[allow(clippy::cast_possible_wrap)] // it's a const, it's fine
let quote = _mm_set1_epi8(b'"' as i8);
#[allow(clippy::cast_possible_wrap)] // it's a const, it's fine
let backslash = _mm_set1_epi8(b'\\' as i8);
while string.len() - idx > 16 {
// Load 16 bytes of data; _mm_loadu_si128 does not require alignment
#[allow(clippy::cast_ptr_alignment)]
let data: __m128i = _mm_loadu_si128(string.as_ptr().add(idx).cast::<__m128i>());
// Test the data against being backslash and quote.
let bs_or_quote =
_mm_or_si128(_mm_cmpeq_epi8(data, backslash), _mm_cmpeq_epi8(data, quote));
// Now mask the data with the quote range (0x1F).
let in_quote_range = _mm_and_si128(data, lower_quote_range);
// then test of the data is unchanged. aka: xor it with the
// Any field that was inside the quote range it will be zero
// now.
let is_unchanged = _mm_xor_si128(data, in_quote_range);
let in_range = _mm_cmpeq_epi8(is_unchanged, zero);
let quote_bits = _mm_movemask_epi8(_mm_or_si128(bs_or_quote, in_range));
if quote_bits == 0 {
idx += 16;
} else {
let quote_dist = quote_bits.trailing_zeros() as usize;
stry!(writer.write_all(&string[0..idx + quote_dist]));
unsafe {
let mut idx = 0;
let zero = _mm_set1_epi8(0);
let lower_quote_range = _mm_set1_epi8(0x1F_i8);
#[allow(clippy::cast_possible_wrap)] // it's a const, it's fine
let quote = _mm_set1_epi8(b'"' as i8);
#[allow(clippy::cast_possible_wrap)] // it's a const, it's fine
let backslash = _mm_set1_epi8(b'\\' as i8);
while string.len() - idx > 16 {
// Load 16 bytes of data; _mm_loadu_si128 does not require alignment
#[allow(clippy::cast_ptr_alignment)]
let data: __m128i = _mm_loadu_si128(string.as_ptr().add(idx).cast::<__m128i>());
// Test the data against being backslash and quote.
let bs_or_quote =
_mm_or_si128(_mm_cmpeq_epi8(data, backslash), _mm_cmpeq_epi8(data, quote));
// Now mask the data with the quote range (0x1F).
let in_quote_range = _mm_and_si128(data, lower_quote_range);
// then test of the data is unchanged. aka: xor it with the
// Any field that was inside the quote range it will be zero
// now.
let is_unchanged = _mm_xor_si128(data, in_quote_range);
let in_range = _mm_cmpeq_epi8(is_unchanged, zero);
let quote_bits = _mm_movemask_epi8(_mm_or_si128(bs_or_quote, in_range));
if quote_bits == 0 {
idx += 16;
} else {
let quote_dist = quote_bits.trailing_zeros() as usize;
stry!(writer.write_all(&string[0..idx + quote_dist]));

let ch = string[idx + quote_dist];
match ESCAPED[ch as usize] {
b'u' => stry!(u_encode(writer, ch)),
escape => stry!(writer.write_all(&[b'\\', escape])),
}
let ch = string[idx + quote_dist];
match ESCAPED[ch as usize] {
b'u' => stry!(u_encode(writer, ch)),
escape => stry!(writer.write_all(&[b'\\', escape])),
}

*string = &string[idx + quote_dist + 1..];
idx = 0;
*string = &string[idx + quote_dist + 1..];
idx = 0;
}
}
stry!(writer.write_all(&string[0..idx]));
*string = &string[idx..];
}
stry!(writer.write_all(&string[0..idx]));
*string = &string[idx..];

Ok(())
}

Expand Down
18 changes: 4 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl fmt::Display for AccessError {
impl std::error::Error for AccessError {}

/// Extended types that have no native representation in JSON
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ExtendedValueType {
/// A 32 bit signed integer value
I32,
Expand All @@ -94,15 +94,10 @@ pub enum ExtendedValueType {
/// A single utf-8 character
Char,
/// Not a value at all
#[default]
None,
}

impl Default for ExtendedValueType {
fn default() -> Self {
Self::None
}
}

impl fmt::Display for ExtendedValueType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expand All @@ -121,9 +116,10 @@ impl fmt::Display for ExtendedValueType {
}

/// Types of JSON values
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
pub enum ValueType {
/// null
#[default]
Null,
/// a boolean
Bool,
Expand Down Expand Up @@ -169,12 +165,6 @@ impl fmt::Display for ValueType {
}
}

impl Default for ValueType {
fn default() -> Self {
Self::Null
}
}

#[allow(clippy::trait_duplication_in_bounds)] // This is a bug From<()> is counted as duplicate
/// Support of builder methods for traits.
pub trait ValueBuilder<'input>:
Expand Down
14 changes: 2 additions & 12 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ mod cmp;
mod from;

/// Static tape node
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Default)]
#[cfg_attr(feature = "ordered-float", derive(Eq))]
#[cfg_attr(feature = "c-abi", repr(C))]
#[cfg_attr(feature = "c-abi", derive(abi_stable::StableAbi))]
Expand All @@ -38,6 +38,7 @@ pub enum StaticNode {
/// A boolean value
Bool(bool),
/// The null value
#[default]
Null,
}

Expand Down Expand Up @@ -128,7 +129,6 @@ impl ValueAsScalar for StaticNode {

#[cfg(feature = "128bit")]
#[inline]
#[must_use]
fn as_i64(&self) -> Option<i64> {
match self {
Self::I64(i) => Some(*i),
Expand All @@ -141,7 +141,6 @@ impl ValueAsScalar for StaticNode {

#[cfg(feature = "128bit")]
#[inline]
#[must_use]
fn as_i128(&self) -> Option<i128> {
match self {
Self::I128(i) => Some(*i),
Expand All @@ -164,7 +163,6 @@ impl ValueAsScalar for StaticNode {

#[cfg(feature = "128bit")]
#[inline]
#[must_use]
fn as_u64(&self) -> Option<u64> {
match self {
Self::I64(i) => u64::try_from(*i).ok(),
Expand All @@ -176,7 +174,6 @@ impl ValueAsScalar for StaticNode {
}
#[cfg(feature = "128bit")]
#[inline]
#[must_use]
fn as_u128(&self) -> Option<u128> {
match self {
Self::U128(i) => Some(*i),
Expand Down Expand Up @@ -283,7 +280,6 @@ impl PartialEq for StaticNode {

#[cfg(feature = "128bit")]
#[inline]
#[must_use]
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Null, Self::Null) => true,
Expand Down Expand Up @@ -316,9 +312,3 @@ impl PartialEq for StaticNode {
}
}
}

impl Default for StaticNode {
fn default() -> Self {
Self::Null
}
}
2 changes: 0 additions & 2 deletions src/node/from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ impl From<i64> for StaticNode {
#[cfg(feature = "128bit")]
impl From<i128> for StaticNode {
#[inline]
#[must_use]
fn from(i: i128) -> Self {
Self::I128(i)
}
Expand Down Expand Up @@ -88,7 +87,6 @@ impl From<u64> for StaticNode {
#[cfg(feature = "128bit")]
impl From<u128> for StaticNode {
#[inline]
#[must_use]
fn from(i: u128) -> Self {
Self::U128(i)
}
Expand Down
Loading