From 32fd75a4ae33093146641e0c225effac43fc5b64 Mon Sep 17 00:00:00 2001 From: Juan Aguilar Santillana Date: Thu, 2 Jul 2020 07:35:30 +0000 Subject: [PATCH 1/2] Remove `BytesMut` in favor of `buf-min::Buffer` trait --- v_escape/Cargo.toml | 10 ++++- v_escape/build.rs | 13 ++++++ v_escape/src/chars.rs | 8 ++-- v_escape/src/lib.rs | 85 +++++++++++++++++--------------------- v_escape/src/ranges/mod.rs | 2 +- v_escape/src/scalar.rs | 2 +- v_htmlescape/Cargo.toml | 8 +++- v_jsonescape/Cargo.toml | 8 +++- v_latexescape/Cargo.toml | 8 +++- 9 files changed, 84 insertions(+), 60 deletions(-) create mode 100644 v_escape/build.rs diff --git a/v_escape/Cargo.toml b/v_escape/Cargo.toml index 64313e8..d24f552 100644 --- a/v_escape/Cargo.toml +++ b/v_escape/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "v_escape" -version = "0.11.3" +version = "0.12.0" authors = ["Juan Aguilar Santillana "] description = "The simd optimized escaping code" documentation = "https://docs.rs/v_escape" @@ -15,6 +15,14 @@ workspace = ".." travis-ci = { repository = "botika/v_escape", branch = "master" } maintenance = { status = "actively-developed" } +[features] +default = ["bytes-buf"] +bytes-buf = ["buf-min/bytes-buf"] + [dependencies] v_escape_derive = { version = "0.8", path = "../v_escape_derive" } +buf-min = "0.1" + +[dev-dependencies] bytes = "0.5" +buf-min = { version = "0.1", features = ["bytes-buf"] } diff --git a/v_escape/build.rs b/v_escape/build.rs new file mode 100644 index 0000000..cfaf743 --- /dev/null +++ b/v_escape/build.rs @@ -0,0 +1,13 @@ +fn main() { + enable_simd_optimizations(); +} + +fn enable_simd_optimizations() { + if is_x86_feature_detected!("sse2") { + println!("cargo:rustc-cfg=v_escape_sse"); + } + + if is_x86_feature_detected!("avx2") { + println!("cargo:rustc-cfg=v_escape_avx"); + } +} diff --git a/v_escape/src/chars.rs b/v_escape/src/chars.rs index 466b444..5f56179 100644 --- a/v_escape/src/chars.rs +++ b/v_escape/src/chars.rs @@ -75,7 +75,7 @@ macro_rules! _v_escape_escape_char_ptr { #[doc(hidden)] macro_rules! _v_escape_escape_char_bytes { ($($t:tt)+) => { - pub unsafe fn b_escape_char(c: char, buf: &mut v_escape::BytesMut) { + pub unsafe fn b_escape_char(c: char, buf: &mut B) { let len = c.len_utf8(); buf.reserve(len); if len == 1 { @@ -97,11 +97,11 @@ macro_rules! _v_escape_escape_char_bytes { } _inside!(impl $($t)+); - *buf.as_mut_ptr().add(buf.len()) = c as u8; + *buf.buf_ptr() = c as u8; } else { - c.encode_utf8(std::slice::from_raw_parts_mut(buf.as_mut_ptr().add(buf.len()), len)); + c.encode_utf8(std::slice::from_raw_parts_mut(buf.buf_ptr(), len)); } - v_escape::BufMut::advance_mut(buf, len); + buf.advance(len); } }; } diff --git a/v_escape/src/lib.rs b/v_escape/src/lib.rs index 1b8ff72..c2bfd72 100644 --- a/v_escape/src/lib.rs +++ b/v_escape/src/lib.rs @@ -106,6 +106,8 @@ //! #![allow(unused_imports)] +pub use buf_min::Buffer; + use v_escape_derive::Escape; #[macro_use] @@ -117,8 +119,6 @@ mod ranges; #[macro_use] mod chars; -pub use bytes::{BufMut, BytesMut}; - #[macro_export] /// Generates struct `$name` with escaping functionality at `fmt` /// @@ -271,16 +271,24 @@ macro_rules! _v_escape_escape_new { } } + /// Escape byte slice to `buf-min::Buffer` + /// + /// # SIGILL + /// Can produce **SIGILL** if compile with `sse2` or `avx2` and execute without they + /// Because not exist way to build multiple static allocations by type + /// And it's very expensive check it in runtime + /// https://github.com/rust-lang/rust/issues/57775 #[inline] - pub fn b_escape(s: &[u8], buf: &mut v_escape::BytesMut) { + pub fn b_escape(s: &[u8], buf: &mut B) { #[allow(unused_unsafe)] unsafe { _b_escape(s, buf) } } + /// Escape char to `buf-min::Buffer` #[inline] - pub fn b_escape_char(s: char, buf: &mut v_escape::BytesMut) { + pub fn b_escape_char(s: char, buf: &mut B) { #[allow(unused_unsafe)] unsafe { chars::b_escape_char(s, buf) @@ -309,7 +317,7 @@ macro_rules! _v_escape_cfg_escape { let fun = _v_escape_cfg_escape!(if $($t)+); let slot = unsafe { &*(&FN as *const _ as *const AtomicUsize) }; - slot.store(fun as usize, Ordering::Relaxed); + slot.store(fun, Ordering::Relaxed); unsafe { mem::transmute:: fmt::Result>(fun)( bytes, fmt, @@ -334,7 +342,7 @@ macro_rules! _v_escape_cfg_escape { } }; (if true) => { - if cfg!(not(v_escape_noavx)) && is_x86_feature_detected!("avx2") { + if is_x86_feature_detected!("avx2") { ranges::avx::escape as usize } else if is_x86_feature_detected!("sse2") { ranges::sse::escape as usize @@ -372,7 +380,7 @@ macro_rules! _v_escape_cfg_escape_ptr { let fun = _v_escape_cfg_escape_ptr!(if $($t)+); let slot = unsafe { &*(&FN as *const _ as *const AtomicUsize) }; - slot.store(fun as usize, Ordering::Relaxed); + slot.store(fun, Ordering::Relaxed); unsafe { mem::transmute::]) -> Option>(fun)( bytes, buf, @@ -397,7 +405,7 @@ macro_rules! _v_escape_cfg_escape_ptr { } }; (if true) => { - if cfg!(not(v_escape_noavx)) && is_x86_feature_detected!("avx2") { + if is_x86_feature_detected!("avx2") { ranges::avx::f_escape as usize } else if is_x86_feature_detected!("sse2") { ranges::sse::f_escape as usize @@ -424,30 +432,8 @@ macro_rules! _v_escape_cfg_escape_bytes { (true, $($t:tt)+) => { #[cfg(all(target_arch = "x86_64", not(v_escape_nosimd)))] #[inline(always)] - #[allow(unreachable_code)] - // https://github.com/BurntSushi/rust-memchr/blob/master/src/x86/mod.rs#L9-L29 - pub unsafe fn _b_escape(bytes: &[u8], buf: &mut v_escape::BytesMut) { - use std::mem; - use std::sync::atomic::{AtomicUsize, Ordering}; - static mut FN: fn(&[u8], &mut v_escape::BytesMut) = detect; - - fn detect(bytes: &[u8], buf: &mut v_escape::BytesMut) { - let fun = _v_escape_cfg_escape_bytes!(if $($t)+); - - let slot = unsafe { &*(&FN as *const _ as *const AtomicUsize) }; - slot.store(fun as usize, Ordering::Relaxed); - unsafe { - mem::transmute::(fun)( - bytes, buf, - ) - } - } - - unsafe { - let slot = &*(&FN as *const _ as *const AtomicUsize); - let fun = slot.load(Ordering::Relaxed); - mem::transmute::(fun)(bytes, buf) - } + pub unsafe fn _b_escape(bytes: &[u8], buf: &mut B) { + _v_escape_cfg_escape_bytes!(if $($t)+, bytes, buf) } #[cfg(not(all(target_arch = "x86_64", not(b_escape_nosimd))))] @@ -455,24 +441,29 @@ macro_rules! _v_escape_cfg_escape_bytes { }; (fn) => { #[inline(always)] - pub unsafe fn _b_escape(bytes: &[u8], buf: &mut v_escape::BytesMut) { + pub unsafe fn _b_escape(bytes: &[u8], buf: &mut B) { scalar::b_escape(bytes, buf) } }; - (if true) => { - if cfg!(not(b_escape_noavx)) && is_x86_feature_detected!("avx2") { - ranges::avx::b_escape as usize - } else if is_x86_feature_detected!("sse2") { - ranges::sse::b_escape as usize - } else { - scalar::b_escape as usize + (if true, $bytes:ident, $buf:ident) => {{ + #[cfg(not(v_escape_avx))] { + #[cfg(not(v_escape_sse))] { + scalar::b_escape($bytes, $buf) + } + #[cfg(v_escape_sse)] { + ranges::sse::b_escape($bytes, $buf) + } } - }; - (if false) => { - if is_x86_feature_detected!("sse2") { - ranges::sse::b_escape as usize - } else { - scalar::b_escape as usize + #[cfg(v_escape_avx)] { + ranges::avx::b_escape($bytes, $buf) } - }; + }}; + (if false, $bytes:ident, $buf:ident) => {{ + #[cfg(not(v_escape_sse))] { + scalar::b_escape($bytes, $buf) + } + #[cfg(v_escape_sse)] { + ranges::sse::b_escape($bytes, $buf) + } + }}; } diff --git a/v_escape/src/ranges/mod.rs b/v_escape/src/ranges/mod.rs index 599d704..1218f48 100644 --- a/v_escape/src/ranges/mod.rs +++ b/v_escape/src/ranges/mod.rs @@ -305,7 +305,7 @@ macro_rules! _v_escape_escape_ranges_bytes { _v_escape_escape_ranges_bytes!(impl loop_range_switch_sse2 for $($t)+); }; (impl $loops:ident for ($T:ident, $Q:ident, $Q_LEN:ident) $($t:tt)+) => { - pub unsafe fn b_escape(bytes: &[u8], buf: &mut v_escape::BytesMut) { + pub unsafe fn b_escape(bytes: &[u8], buf: &mut B) { let len = bytes.len(); let start_ptr = bytes.as_ptr(); let end_ptr = bytes[len..].as_ptr(); diff --git a/v_escape/src/scalar.rs b/v_escape/src/scalar.rs index ad5bec4..4f41703 100644 --- a/v_escape/src/scalar.rs +++ b/v_escape/src/scalar.rs @@ -115,7 +115,7 @@ macro_rules! _v_escape_escape_scalar_ptr { macro_rules! _v_escape_escape_scalar_bytes { ($($t:tt)+) => { #[inline] - pub unsafe fn b_escape(bytes: &[u8], buf: &mut v_escape::BytesMut) { + pub unsafe fn b_escape(bytes: &[u8], buf: &mut B) { let mut start = 0; for (i, b) in bytes.iter().enumerate() { diff --git a/v_htmlescape/Cargo.toml b/v_htmlescape/Cargo.toml index 8982af3..6d71ab4 100644 --- a/v_htmlescape/Cargo.toml +++ b/v_htmlescape/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "v_htmlescape" -version = "0.9.1" +version = "0.10.0" authors = ["Juan Aguilar Santillana "] description = "The simd optimized HTML escaping code" documentation = "https://docs.rs/v_htmlescape" @@ -15,6 +15,10 @@ workspace = ".." travis-ci = { repository = "botika/v_escape", branch = "master" } maintenance = { status = "actively-developed" } +[features] +default = ["bytes-buf"] +bytes-buf = ["v_escape/bytes-buf"] + [dependencies] -v_escape = { version = "0.11", path = "../v_escape" } +v_escape = { version = "0.12", path = "../v_escape", default-features = false } cfg-if = "0.1" diff --git a/v_jsonescape/Cargo.toml b/v_jsonescape/Cargo.toml index 612d731..8e6cc2b 100644 --- a/v_jsonescape/Cargo.toml +++ b/v_jsonescape/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "v_jsonescape" -version = "0.1.0" +version = "0.2.0" authors = ["Juan Aguilar Santillana "] description = "The simd optimized JSON escaping code" documentation = "https://docs.rs/v_jsonescape" @@ -15,6 +15,10 @@ workspace = ".." travis-ci = { repository = "botika/v_escape", branch = "master" } maintenance = { status = "actively-developed" } +[features] +default = ["bytes-buf"] +bytes-buf = ["v_escape/bytes-buf"] + [dependencies] -v_escape = { version = "0.11", path = "../v_escape" } +v_escape = { version = "0.12", path = "../v_escape", default-features = false } cfg-if = "0.1" diff --git a/v_latexescape/Cargo.toml b/v_latexescape/Cargo.toml index 5beaaa9..51620b7 100644 --- a/v_latexescape/Cargo.toml +++ b/v_latexescape/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "v_latexescape" -version = "0.8.0" +version = "0.9.0" authors = ["Juan Aguilar Santillana "] description = "The simd optimized LaTeX escaping code" documentation = "https://docs.rs/v_latexescape" @@ -15,6 +15,10 @@ workspace = ".." travis-ci = { repository = "botika/v_escape", branch = "master" } maintenance = { status = "actively-developed" } +[features] +default = ["bytes-buf"] +bytes-buf = ["v_escape/bytes-buf"] + [dependencies] -v_escape = { version = "0.11", path = "../v_escape" } +v_escape = { version = "0.12", path = "../v_escape", default-features = false } cfg-if = "0.1" From c3fc70d809ea95eb4c1e337305be0f0f7d0cae54 Mon Sep 17 00:00:00 2001 From: Juan Aguilar Santillana Date: Thu, 2 Jul 2020 07:55:32 +0000 Subject: [PATCH 2/2] Update CI --- .github/workflows/linux.yml | 2 +- .github/workflows/osx.yml | 2 +- .travis.yml | 2 +- appveyor.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 43bb404..3bf1a22 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -51,7 +51,7 @@ jobs: timeout-minutes: 40 with: command: test - args: --all --all-features --no-fail-fast -- --nocapture + args: --all --no-fail-fast -- --nocapture - name: Install cargo-cache continue-on-error: true diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 6d9ffa2..4224c71 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -48,7 +48,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --all --all-features --no-fail-fast -- --nocapture + args: --all --no-fail-fast -- --nocapture - name: Clear the cargo caches run: | diff --git a/.travis.yml b/.travis.yml index 8b51bf5..5e36468 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,4 +33,4 @@ script: cargo fmt -- --check fi - cargo check --all - - cargo test --all-features --all -- --nocapture + - cargo test --all -- --nocapture diff --git a/appveyor.yml b/appveyor.yml index 1fb7f27..f0083d2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -59,4 +59,4 @@ build: false test_script: - cargo clean - cargo check --all - - cargo test --all-features --all -- --nocapture + - cargo test --all -- --nocapture