Skip to main content

v_escape_base/arch/x86_64/
mod.rs

1/// A module for AVX escape functions
2pub mod avx;
3
4/// A module for SSE escape functions
5pub mod sse;
6
7/// A macro for creating a escape functions
8///
9/// # Parameters
10/// - `$name`: The name of the function.
11/// - `$writer_builder`: The function to use for the builder.
12/// - `$builder`: The type of the builder.
13/// - `$buffer`: The type of the buffer.
14#[doc(hidden)]
15#[macro_export]
16macro_rules! ifun {
17    (
18        $name:ident,
19        $writer_builder:path,
20        $builder:ty,
21        $buffer:ty
22        $(,$retty:ty)?
23    ) => {
24        pub fn $name(haystack: &str, buffer: &mut $buffer) $(-> $retty)? {
25            use core::sync::atomic::{AtomicPtr, Ordering};
26
27            type Fn = *mut ();
28            type RealFn = fn(haystack: &str, buffer: &mut $buffer) $(-> $retty)?;
29            static FN: AtomicPtr<()> = AtomicPtr::new(detect as Fn);
30
31            #[cfg(target_feature = "sse2")]
32            #[target_feature(enable = "sse2", enable = "avx2")]
33            $writer_builder!(escape_avx2, $crate::arch::x86_64::avx::escape, escape, $builder);
34
35            #[cfg(target_feature = "sse2")]
36            #[target_feature(enable = "sse2")]
37            $writer_builder!(escape_sse2, $crate::arch::x86_64::sse::escape, escape, $builder);
38
39            $writer_builder!(escape_fallback, $crate::arch::fallback::escape_fallback, escape_fallback, $builder);
40
41            unsafe fn detect(haystack: &str, buffer: &mut $buffer) $(-> $retty)? {
42                let fun = {
43                    #[cfg(not(target_feature = "sse2"))]
44                    {
45                        escape_fallback
46                    }
47                    #[cfg(target_feature = "sse2")]
48                    {
49                        if $crate::arch::x86_64::avx::is_available() {
50                            escape_avx2
51                        } else if $crate::arch::x86_64::sse::is_available() {
52                            escape_sse2
53                        } else {
54                            escape_fallback
55                        }
56                    }
57                };
58                FN.store(fun as Fn, Ordering::Relaxed);
59                // SAFETY: The only thing we need to uphold here is the
60                // `#[target_feature]` requirements. Since we check is_available
61                // above before using the corresponding implementation, we are
62                // guaranteed to only call code that is supported on the current
63                // CPU.
64                fun(haystack, buffer)
65            }
66
67            // SAFETY: By virtue of the caller contract, RealFn is a function
68            // pointer, which is always safe to transmute with a *mut (). Also,
69            // since we use $memchrty::is_available, it is guaranteed to be safe
70            // to call $memchrty::$memchrfind.
71            unsafe {
72                let fun = FN.load(Ordering::Relaxed);
73                core::mem::transmute::<Fn, RealFn>(fun)(
74                    haystack,
75                    buffer
76                )
77            }
78        }
79    };
80}
81
82/// A macro for creating a escape functions
83///
84/// # Parameters
85/// - `$builder`: The type [`crate::EscapesBuilder`] of the builder
86#[macro_export]
87macro_rules! escape_builder {
88    ($builder:ty) => {
89        $crate::struct_display!(
90            escape_fmt,
91            escape_fmt_internal,
92            $crate::ifun!(
93                escape_fmt_internal,
94                $crate::builder_fmt,
95                $builder,
96                core::fmt::Formatter<'_>,
97                core::fmt::Result
98            ),
99            $builder
100        );
101
102        $crate::struct_string!($crate::ifun!(
103            escape_string,
104            $crate::builder_string,
105            $builder,
106            String
107        ));
108
109        $crate::struct_bytes!($crate::ifun!(
110            escape_bytes,
111            $crate::builder_bytes,
112            $builder,
113            Vec<u8>
114        ));
115    };
116}