<commit_before>#ifndef VPP_FAST9_DETECTOR_HPP_
# define VPP_FAST9_DETECTOR_HPP_

#ifdef __ARM_NEON__
#  include <arm_neon.h>
#endif

#if defined(__SSE4_1__) || defined(__AVX2__)
# include "immintrin.h"
#endif

# include <omp.h>
# include <bitset>
# include <thread>
# include <vpp/vpp.hh>

namespace vpp
{

  namespace FAST_internals
  {

    inline bool fast9_check_code(uint code32)
    {
      // Thanks Arkanosis (https://github.com/Arkanosis) for the idea.
      uint64_t code48 = code32;
      code48 |= code48 << 32;
      code48 &= code48 << 8;
      code48 &= code48 << 4;
      code48 &= code48 << 2;
      return (code48 & (code48 << 2));
    }

    template <typename N>
    inline
    int fast9_score(const N& nbh,
                    int th)
    {
      typedef typename N::value_type V;
      V v = nbh(0, 0);
      int sum_inf = 0;
      int sum_sup = 0;

      auto f = [&] (V a) -> int {
        int diff = v - a;
        if (diff < -th) sum_inf -= diff;
        else if (diff > th) sum_sup += diff;
      };

      f(nbh(-3, -1));
      f(nbh(-3,  0));
      f(nbh(-3,  1));

      f(nbh(-2,  2));

      f(nbh(-1, 3));
      f(nbh( 0, 3));
      f(nbh( 1, 3));

      f(nbh(2,  2));

      f(nbh(3, +1));
      f(nbh(3,  0));
      f(nbh(3, -1));

      f(nbh( 2, -2));

      f(nbh( 1, -3));
      f(nbh( 0, -3));
      f(nbh(-1, -3));

      f(nbh(-2, -2));

      return std::max(sum_sup, sum_inf);
    }

    template <typename N>
    bool is_fast9_keypoint(const N& n, int th)
    {
      typedef typename N::value_type V;

      V v = n(0, 0);
      
      auto f = [&] (V a) -> int { return ((a > v + th) << 1) ^ (a < v - th); };

      uint x  =
        (f(n(3, -1)) << 20) +
        (f(n(3,  0)) << 18) +
        (f(n(3, +1)) << 16) +

        (f(n( 2, -2)) << 22) +
        (f(n(2,  2)) << 14) +

        (f(n( 1, -3)) << 24) +
        (f(n( 1, 3)) << 12) +
        (f(n( 0, -3)) << 26) +
        (f(n( 0, 3)) << 10) +

        (f(n(-1, -3)) << 28) +
        (f(n(-1, 3)) << 8) +

        (f(n(-2, -2)) << 30) +
        (f(n(-2,  2)) << 6) +

        f(n(-3, -1)) +
        (f(n(-3,  0)) << 2) +
        (f(n(-3,  1)) << 4);
  
      return fast9_check_code(x);
    }

#ifdef __AVX2__
    struct fast9_simd
    {
      typedef __m256i V;
      enum { size = 32, size_in_bits = 256 };

      static V check(V x, V hi, V lo)
      {
        __m256i _1 = _mm256_set1_epi8(1);
        __m256i a = _mm256_min_epu8(_1, _mm256_subs_epu8(x, hi));
        __m256i b = _mm256_min_epu8(_1, _mm256_subs_epu8(lo, x));        
        return _mm256_slli_epi16(a, 4) | b;
      };

      static V u_subs(V a, V b) { return _mm256_subs_epu8(a, b); }
      static V u_adds(V a, V b) { return _mm256_adds_epu8(a, b); }
      static bool all_equal_zero(V a) {return _mm256_testz_si256(a, _mm256_set1_epi8(255)) == 1;}
      static V repeat(int v) { return _mm256_set1_epi8(v); }
      static V load(const void* ptr) { return _mm256_load_si256((const __m256i*) (ptr)); }
      static V loadu(const void* ptr) { return _mm256_loadu_si256((const __m256i*) (ptr)); }
      static void storeu(void* ptr, V x) { _mm256_storeu_si256((__m256i*) (ptr), x); }
    };
#else

#  ifdef __SSE4_1__
    struct fast9_simd // SSE4 version
    {
      typedef __m128i V;
      enum { size = 16, size_in_bits = 128 };

      static V check(V x, V hi, V lo)
      {
        V _1 = _mm_set1_epi8(1);
        V a = _mm_min_epu8(_1, _mm_subs_epu8(x, hi));
        V b = _mm_min_epu8(_1, _mm_subs_epu8(lo, x));
        return _mm_slli_epi16(a, 4) | b;
      };

      static V u_subs(V a, V b) { return _mm_subs_epu8(a, b); }
      static V u_adds(V a, V b) { return _mm_adds_epu8(a, b); }
      static bool all_equal_zero(V a) { return _mm_testz_si128(a, _mm_set1_epi8(255)) == 1; }
      static V repeat(int v) { return _mm_set1_epi8(v); }
      static V load(const void* ptr) { return _mm_load_si128((const V*) (ptr)); }
      static V loadu(const void* ptr) { return _mm_loadu_si128((const V*) (ptr)); }
      static void storeu(void* ptr, V x) { _mm_storeu_si128((V*) (ptr), x); }
    };

#  else

#    ifdef __ARM_NEON__
#    include <arm_neon.h>
    struct fast9_simd // ARM NEON version
    {
      typedef uint16x8_t V;
      enum { size = 16, size_in_bits = 128 };

      static V check(V x, V hi, V lo)
      {
        V _1 = _mm_set1_epi8(1);
        V a = vminq_u16(_1, _mm_subs_epu8(x, hi));
        V b = vminq_u16(_1, _mm_subs_epu8(lo, x));
        return vshlq_n_u16(a, 4) | b;
      };

      static V u_subs(V a, V b) { return vqsubq_u16(a, b); }
      static V u_adds(V a, V b) { return vqaddq_u16(a, b); }
      static bool all_equal_zero(V a) { return _mm_testz_si128(a, _mm_set1_epi8(255)) == 1; }
      static V repeat(int v) { return _mm_set1_epi8(v); }
      static V load(const void* ptr) { return vld1q_u16((const uint16_t*) (ptr)); }
      static V loadu(const void* ptr) { return vld1q_u16((const uint16_t*) (ptr)); }
      static void storeu(void* ptr, V x) { vst1q_u16((uint16_t*) (ptr), x); }
    };

#    else

    struct fast9_simd // Fallback version
    {
      typedef unsigned char V;
      enum { size = 1, size_in_bits = 8 };

      static V check(V x, V hi, V lo) { return ((x > hi) << 4) | (x < lo); };
      static V u_subs(V a, V b) { return a > b ? a - b : 0; }
      static V u_adds(V a, V b) 
      {
        int s = a + b;
        return s > 255 ? 255 : s;
      }
      static bool all_equal_zero(V a) { return a == 0; }
      static V repeat(int v) { return v; }<commit_msg>Fast keypoint detector on arm neon.<commit_after>#ifndef VPP_FAST9_DETECTOR_HPP_
# define VPP_FAST9_DETECTOR_HPP_

#ifdef __ARM_NEON__
#  include <arm_neon.h>
#endif

#if defined(__SSE4_1__) || defined(__AVX2__)
# include "immintrin.h"
#endif

# include <omp.h>
# include <bitset>
# include <thread>
# include <vpp/vpp.hh>

namespace vpp
{

  namespace FAST_internals
  {

    inline bool fast9_check_code(uint code32)
    {
      // Thanks Arkanosis (https://github.com/Arkanosis) for the idea.
      uint64_t code48 = code32;
      code48 |= code48 << 32;
      code48 &= code48 << 8;
      code48 &= code48 << 4;
      code48 &= code48 << 2;
      return (code48 & (code48 << 2));
    }

    template <typename N>
    inline
    int fast9_score(const N& nbh,
                    int th)
    {
      typedef typename N::value_type V;
      V v = nbh(0, 0);
      int sum_inf = 0;
      int sum_sup = 0;

      auto f = [&] (V a) -> int {
        int diff = v - a;
        if (diff < -th) sum_inf -= diff;
        else if (diff > th) sum_sup += diff;
      };

      f(nbh(-3, -1));
      f(nbh(-3,  0));
      f(nbh(-3,  1));

      f(nbh(-2,  2));

      f(nbh(-1, 3));
      f(nbh( 0, 3));
      f(nbh( 1, 3));

      f(nbh(2,  2));

      f(nbh(3, +1));
      f(nbh(3,  0));
      f(nbh(3, -1));

      f(nbh( 2, -2));

      f(nbh( 1, -3));
      f(nbh( 0, -3));
      f(nbh(-1, -3));

      f(nbh(-2, -2));

      return std::max(sum_sup, sum_inf);
    }

    template <typename N>
    bool is_fast9_keypoint(const N& n, int th)
    {
      typedef typename N::value_type V;

      V v = n(0, 0);
      
      auto f = [&] (V a) -> int { return ((a > v + th) << 1) ^ (a < v - th); };

      uint x  =
        (f(n(3, -1)) << 20) +
        (f(n(3,  0)) << 18) +
        (f(n(3, +1)) << 16) +

        (f(n( 2, -2)) << 22) +
        (f(n(2,  2)) << 14) +

        (f(n( 1, -3)) << 24) +
        (f(n( 1, 3)) << 12) +
        (f(n( 0, -3)) << 26) +
        (f(n( 0, 3)) << 10) +

        (f(n(-1, -3)) << 28) +
        (f(n(-1, 3)) << 8) +

        (f(n(-2, -2)) << 30) +
        (f(n(-2,  2)) << 6) +

        f(n(-3, -1)) +
        (f(n(-3,  0)) << 2) +
        (f(n(-3,  1)) << 4);
  
      return fast9_check_code(x);
    }

#ifdef __AVX2__
    struct fast9_simd
    {
      typedef __m256i V;
      enum { size = 32, size_in_bits = 256 };

      static V check(V x, V hi, V lo)
      {
        __m256i _1 = _mm256_set1_epi8(1);
        __m256i a = _mm256_min_epu8(_1, _mm256_subs_epu8(x, hi));
        __m256i b = _mm256_min_epu8(_1, _mm256_subs_epu8(lo, x));        
        return _mm256_slli_epi16(a, 4) | b;
      };

      static V u_subs(V a, V b) { return _mm256_subs_epu8(a, b); }
      static V u_adds(V a, V b) { return _mm256_adds_epu8(a, b); }
      static bool all_equal_zero(V a) {return _mm256_testz_si256(a, _mm256_set1_epi8(255)) == 1;}
      static V repeat(int v) { return _mm256_set1_epi8(v); }
      static V load(const void* ptr) { return _mm256_load_si256((const __m256i*) (ptr)); }
      static V loadu(const void* ptr) { return _mm256_loadu_si256((const __m256i*) (ptr)); }
      static void storeu(void* ptr, V x) { _mm256_storeu_si256((__m256i*) (ptr), x); }
    };
#else

#  ifdef __SSE4_1__
    struct fast9_simd // SSE4 version
    {
      typedef __m128i V;
      enum { size = 16, size_in_bits = 128 };

      static V check(V x, V hi, V lo)
      {
        V _1 = _mm_set1_epi8(1);
        V a = _mm_min_epu8(_1, _mm_subs_epu8(x, hi));
        V b = _mm_min_epu8(_1, _mm_subs_epu8(lo, x));
        return _mm_slli_epi16(a, 4) | b;
      };

      static V u_subs(V a, V b) { return _mm_subs_epu8(a, b); }
      static V u_adds(V a, V b) { return _mm_adds_epu8(a, b); }
      static bool all_equal_zero(V a) { return _mm_testz_si128(a, _mm_set1_epi8(255)) == 1; }
      static V repeat(int v) { return _mm_set1_epi8(v); }
      static V load(const void* ptr) { return _mm_load_si128((const V*) (ptr)); }
      static V loadu(const void* ptr) { return _mm_loadu_si128((const V*) (ptr)); }
      static void storeu(void* ptr, V x) { _mm_storeu_si128((V*) (ptr), x); }
    };

#  else

#    ifdef __ARM_NEON__
#    include <arm_neon.h>

    // struct fast9_simd // Fallback version
    // {
    //   typedef unsigned char V;
    //   enum { size = 1, size_in_bits = 8 };

    //   static V check(V x, V hi, V lo) { return ((x > hi) << 4) | (x < lo); };
    //   static V u_subs(V a, V b) { return a > b ? a - b : 0; }
    //   static V u_adds(V a, V b) 
    //   {
    //     int s = a + b;
    //     return s > 255 ? 255 : s;
    //   }
    //   static bool all_equal_zero(V a) { return a == 0; }
    //   static V repeat(int v) { return v; }
    //   static V load(const void* ptr) { return *(const V*) (ptr); }
    //   static V loadu(const void* ptr) { return *(const V*) (ptr); }
    //   static void storeu(void* ptr, V x) { (*(V*) (ptr)) = x; }
    // };
    
    struct fast9_simd // ARM NEON version
    {
      typedef uint16x8_t V;
      enum { size = 16, size_in_bits = 128 };

      static V check(V x, V hi, V lo)
      {
        V _1 = vdupq_n_u16(1);
        V a = vminq_u16(_1, vqsubq_u16(x, hi));
        V b = vminq_u16(_1, vqsubq_u16(lo, x));
        return vshlq_n_u16(a, 4) | b;
      };

      static V u_subs(V a, V b) { return vqsubq_u16(a, b); }
      static V u_adds(V a, V b) { return vqaddq_u16(a, b); }
      static bool all_equal_zero(V a) {

        V tmp;
        int res;
        asm("VTST.16     %q[tmp], %q[in], %q[in]\n\t"
            "VQADD.u16   %q[tmp], %q[tmp]\n\t"
            "VMRS        %[out],FPSCR"
            : [out] "=r" (res), [tmp] "=w" (tmp)
            : [in] "w" (a)
          );

        return !(res & (1 << 27));
        // uint64x2_t v0 = vreinterpretq_u64_u16(a);
        // uint64x1_t v0or = vorr_u64(vget_high_u64(v0), vget_low_u64(v0));

        // uint32x2_t v1 = vreinterpret_u32_u64 (v0or);
        // uint32_t r = vget_lane_u32(v1, 0) | vget_lane_u32(v1, 1); 
        //return r == 0;
      }
      static V repeat(int v) { return vdupq_n_u16(v); }
      static V load(const void* ptr) {
        V res;
        asm("VLD1.16 {%q[out]}, [%[in]:128]"
            : [out] "=w" (res)
            : [in]"r" (ptr)
          );
        return res;
        // return vld1q_u16((const uint16_t*) (ptr));
      }
      static V loadu(const void* ptr) { return vld1q_u16((const uint16_t*) (ptr)); }
      static void storeu(void* ptr, V x) { vst1q_u16((uint16_t*) (ptr), x); }
    };

#    else

    struct fast9_simd // Fallback version
    {
      typedef unsigned char V;
      enum { size = 1, size_in_bits = 8 };

      static V check(V x, V hi, V lo) { return ((x > hi) << 4) | (x < lo); };
      static V u_subs(V a, V b) { return a > b ? a - b : 0; }
      static V u_adds(V a, V b) 
      {
        int s = a + b;
        return s > 255 ? 255 : s;
      }
      static bool all_equal_zero(V a) { return a == 0; }
      static V repeat(int v) { return v; }
{'fraction_non_alphanumeric': 0.1668805132317562, 'fraction_numerical': 0.06206896551724138, 'mean_word_length': 1.9785048961069978, 'pattern_counts': {'":': 0, '<': 118, '<?xml version=': 0, '>': 36, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4610673', 'n_tokens_mistral': 5784, 'n_tokens_neox': 5278, 'n_words': 1335}