(set! *unchecked-math* true)

(defn grep-n-chunk [^long n f coll]
  (lazy-seq
   (when-let [s (seq coll)]
     (if (and (chunked-seq? coll) (> (count (chunk-first coll)) (+ 1 (* 2 n)))) ;; :(
       (let [fchunk (chunk-first coll)
             c (count fchunk)
             pred (chunk-buffer n)
             matches (chunk-buffer c)
             after (chunk-buffer n)]
         (loop [i 0 last-match-idx nil]
           (if (< i c)
             (let [x (nth fchunk i)]
               (if (and last-match-idx (<= i (+ n last-match-idx)))
                 (do (chunk-append after x) (recur (inc i) last-match-idx))
                 (if (f x)
                   (do (chunk-append matches x)
                       (dotimes [step n]
                         (let [pred-match (nth fchunk (dec (- i step)) ::nil)]
                           (when (not= pred-match ::nil)
                             (chunk-append pred pred-match))))
                       (recur (inc i) i))
                   (recur (inc i) last-match-idx))))))
         (->> (grep-n-chunk n f (chunk-rest coll))
              (chunk-cons (chunk after))
              (chunk-cons (chunk matches))
              (chunk-cons (chunk pred))))
       (let [p (take-while (complement f) (take n s))
             n-till-first-match (count p)
             matches (take-while f (nthrest s n-till-first-match))]
         (if (seq matches)
           (let [n-till-last-match (+ (count p) (count matches))
                 a (take n (nthrest s n-till-last-match))]
             (if (some f a)
               (concat p matches (grep-n-chunk n f (nthrest s n-till-last-match)))
               (concat p matches a (grep-n-chunk n f (nthrest s (+ n-till-last-match (count a)))))))
           (grep-n-chunk n f (rest s))))))))
          
          
(defn sample [] (doall (grep-n-chunk 2 #(.get #{1 1111 1111111} %) (range 100000000))))
(time (sample))