(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))))