/* generated from expression

MEMMEM(n,nsize,end,c1,c2,size) = at_ptr(end) {return NULL;}
                               | char(c1) char(c2) { MATCH_REST }


*/
#define SSE2
#ifdef SSE2
#include "sse2.h"
#define MEMMEM memmem_sse2
#elif AVX2
#include "avx2.h"
#define MEMMEM memmem_avx2
#else
#include "arithmetic.h"
#define MEMMEM memmem_arithmetic
#endif

#include <string.h>
#include "strstr_hash.h"
#define MATCH_REST int j;for(j=2;j<nsize && n[j]==p[j];j++); \
if (j==nsize) return p; \
size+=j; \
if ((long) size>2*(p-s)) return strstr_hash(p, end-p , n, nsize);

static inline char * MEMMEM(char *s ,char *n,char *nsize,char *end,char *c1,char *c2,char *size )
{
  int i;
  char *p;
  MBTYPE e0;
  MBTYPE e1;
  MBTYPE e2;
  MBTYPE e3;
  MBTYPE e4;
  MBTYPE e5;
  MBTYPE e6;
  MBTYPE e7;
  MBTYPE m0=byte_at(1<<7,((long)end) & (BYTES_AT_ONCE-1));
  MBTYPE m1=make_mask(0,0);
  MBTYPE m2=make_mask((char) c1,0);
  MBTYPE m3=make_mask((char) c2,1);
  char *s2=s;
  int offset=((long)(s))%BYTES_AT_ONCE;
  s2-=offset;
  MBTYPE eo=LOAD(s2);
  e0=( (long)s2 == (((long)end) & ~((long) BYTES_AT_ONCE-1) ) ) ? m0 : m1;;

  e2=test_eq(eo, m2);
  e3=shift_down(eo,1);
  e4=test_eq(e3, m3);

  e6=AND(e2,e4);
  e7=OR(e0,e6);
  MASKTYPE mask=get_mask(e7);
  mask=forget_bits(mask,offset);
  while (1)
    {
      if(mask)
        {
          for(i=0; i<BYTES_AT_ONCE-1; i++) if (GET_BIT(mask,i))
              {
                if (GET_BIT(get_mask(e0),i))
                  {
                    p=s2+i;
                    return NULL;
                  }
                if (GET_BIT(get_mask(e6),i))
                  {
                    p=s2+i;
                    MATCH_REST
                  }

              }
          if (GET_BIT(get_mask(e0),i))
            {
              p=s2+i;
              return NULL;
            }
          if (GET_BIT(get_mask(e6),i)&& s2[i+1]==c2)
            {
              p=s2+i;
              MATCH_REST
            }

        }
      s2+=BYTES_AT_ONCE;
      eo=LOAD(s2);
      if ((long)s2 == (((long)end) & ~((long) BYTES_AT_ONCE-1) ) )
        {
          e0=m0;
        }
      else
        {
          e0=m1;
        }
      e0=( (long)s2 == (((long)end) & ~((long) BYTES_AT_ONCE-1) ) ) ? m0 : m1;;
      e2=test_eq(eo, m2);
      e3=shift_down(eo,1);
      e4=test_eq(e3, m3);

      e6=AND(e2,e4);
      e7=OR(e0,e6);
      mask=get_mask(e7);
    }
}
char *memmem2(char *s,int s_len,char *n,int n_len)
{
  if (n_len==0) return s;
  if (n_len==1) return strstr_hash(s,s_len,n,1);

  return MEMMEM(s,n,n_len,s+s_len,n[0],n[1],-16);
}
