Skip to content

Instantly share code, notes, and snippets.

@joshlemer
Last active April 17, 2022 02:42
Show Gist options
  • Save joshlemer/8305c8447cd98d1c01faa69b9b5077f0 to your computer and use it in GitHub Desktop.
Save joshlemer/8305c8447cd98d1c01faa69b9b5077f0 to your computer and use it in GitHub Desktop.
(ns gen
(:require
[cloroutine.core :refer [cr]]
[criterium.core :as crit]))
(deftype ^:private GenIter [;; The Cloroutine generator function
^:unsynchronized-mutable ^clojure.lang.IFn g
;; Trilean boolean logic:
;; 0 = certainly no more elements, `x` is nil
;; 1 = certainly there are more elemennts, and the next object is stored in `x`
;; 2 = unknown, `x` is nil
^:unsynchronized-mutable ^byte _has-next
^:unsynchronized-mutable ^java.lang.Object x]
java.util.Iterator
(hasNext [_]
(if
(= _has-next (byte 2)) (let [elem (g)]
(if (identical? ::done elem)
(do
(set! _has-next (byte 0))
;; release g for garbage collection
(set! g nil)
false)
(do
(set! _has-next (byte 1))
(set! x elem)
true)))
(= _has-next (byte 1))))
(next [_]
(cond
(= _has-next 1) (let [result x]
;; release x for garbage collection
(set! x nil)
(set! _has-next (byte 2))
result)
(= _has-next 0) (throw (java.util.NoSuchElementException.))
:else (g))))
(defn gen-seq [g]
(iterator-seq (GenIter. g 2 nil)))
(defn yield [x] x)
(defn no-op [])
(defmacro generator [& body]
`(gen-seq (cr {yield no-op} ~@body ::done)))
(defn my-repeat [x]
(generator
(loop []
(yield x)
(recur))))
(defn repeat-l [x]
(lazy-seq
(cons x (repeat-l x))))
(crit/bench (last (take 1000000 (my-repeat :a)))) ;; 128.499834 ms
(crit/bench (last (take 1000000 (repeat-l :a)))) ;; 112.217999 ms
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment