11#include <daw/daw_cpp_feature_check.h>
13#define DAW_JSON_HAS_NEON_SIMD 1
22namespace daw::simd_impl::neon {
24 [[nodiscard]]
inline std::uint64_t
25 to_bits( uint8x16_t comparison )
noexcept {
26 alignas( 16 )
static constexpr std::uint8_t bit_values[16] = { 0x01,
42 auto const bits = vandq_u8( comparison, vld1q_u8( bit_values ) );
43 auto const pairs = vpaddlq_u8( bits );
44 auto const quads = vpaddlq_u16( pairs );
45 auto const octets = vpaddlq_u32( quads );
46 return vgetq_lane_u64( octets, 0 ) |
47 ( vgetq_lane_u64( octets, 1 ) << 8U );
55 explicit mask( uint8x16_t value ) noexcept
58 [[nodiscard]] std::uint64_t to_ullong( )
const noexcept {
59 return details::to_bits( m_value );
62 [[nodiscard]] std::uint64_t to_ullong_sparse( )
const noexcept {
64 vorr_u8( vget_low_u8( m_value ), vget_high_u8( m_value ) );
65 reduced = vpmax_u8( reduced, reduced );
66 reduced = vpmax_u8( reduced, reduced );
67 reduced = vpmax_u8( reduced, reduced );
68 if( vget_lane_u8( reduced, 0 ) == 0 ) {
71 return details::to_bits( m_value );
74 [[nodiscard]]
friend mask operator|( mask lhs, mask rhs )
noexcept {
75 return mask( vorrq_u8( lhs.m_value, rhs.m_value ) );
78 [[nodiscard]]
friend mask operator&( mask lhs, mask rhs )
noexcept {
79 return mask( vandq_u8( lhs.m_value, rhs.m_value ) );
82 [[nodiscard]]
friend mask operator!( mask value )
noexcept {
83 return mask( vmvnq_u8( value.m_value ) );
87 template<
typename T, std::size_t = 16U>
89 static_assert(
sizeof( T ) == 1,
90 "The NEON JSON SIMD implementation supports byte types" );
92 std::is_integral_v<T>,
93 "The NEON JSON SIMD implementation requires an integral type" );
97 template<
typename U, std::
size_t MaximumSize>
100 template<
typename Simd,
typename Range,
typename Flag>
101 friend Simd unchecked_load( Range values, Flag );
103 template<
typename Simd,
typename Range,
typename Flag>
104 friend Simd partial_load( Range values, Flag );
106 explicit vec( uint8x16_t value ) noexcept
107 : m_value( value ) {}
110 using value_type = T;
111 using mask_type = mask;
113 explicit vec( value_type value ) noexcept
114 : m_value( vdupq_n_u8(
static_cast<std::uint8_t
>( value ) ) ) {}
116 [[nodiscard]]
static constexpr std::size_t size( )
noexcept {
120 [[nodiscard]]
friend mask operator==( vec lhs, vec rhs )
noexcept {
121 return mask( vceqq_u8( lhs.m_value, rhs.m_value ) );
124 [[nodiscard]]
friend mask operator>=( vec lhs, vec rhs )
noexcept {
125 return mask( vcgeq_u8( lhs.m_value, rhs.m_value ) );
128 [[nodiscard]]
friend mask operator<=( vec lhs, vec rhs )
noexcept {
129 return mask( vcleq_u8( lhs.m_value, rhs.m_value ) );
133 struct flag_default_t {};
134 struct flag_convert_t {};
136 inline constexpr flag_default_t flag_default = { };
137 inline constexpr flag_convert_t flag_convert = { };
139 template<
typename Simd,
typename Range,
typename Flag = flag_default_t>
140 [[nodiscard]]
inline Simd unchecked_load( Range values,
141 Flag = flag_default ) {
142 static_assert( Simd::size( ) == 16 );
144 vld1q_u8(
reinterpret_cast<std::uint8_t
const *
>( values.data( ) ) ) );
147 template<
typename Simd,
typename Range,
typename Flag = flag_default_t>
148 [[nodiscard]]
inline Simd partial_load( Range values, Flag = flag_default ) {
149 static_assert( Simd::size( ) == 16 );
150 auto result = vdupq_n_u8( 0 );
151 std::memcpy( &result, values.data( ), values.size( ) );
152 return Simd( result );