Skip to content

Commit c292cbb

Browse files
committed
Add code. Tests pass.
1 parent 0283f81 commit c292cbb

File tree

5 files changed

+399
-0
lines changed

5 files changed

+399
-0
lines changed

.gitignore

+10
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,13 @@ pom.xml
44
/classes/
55
/targets/
66
.lein-deps-sum
7+
/target
8+
/checkouts
9+
*.jar
10+
*.class
11+
*.dll
12+
*.pdb
13+
*.exe
14+
.lein-deps-sum
15+
.lein-failures
16+
.lein-plugins

doc/intro.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Introduction to clojure.data.generators
2+
3+
TODO: write [great documentation](http://jacobian.org/writing/great-documentation/what-to-write/)

project.clj

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
(defproject clojure.tools.nrepl "0.1.0-SNAPSHOT"
2+
:description "FIXME: write description"
3+
:url "http://example.com/FIXME"
4+
:license {:name "Eclipse Public License"
5+
:url "http://www.eclipse.org/legal/epl-v10.html"}
6+
:dependencies []
7+
:min-lein-version "2.0.0"
8+
:plugins [[lein-clr "0.2.0"]]
9+
:clr {:cmd-templates {:clj-exe [#_"mono" [CLJCLR15_40 %1]]
10+
:clj-dep [#_"mono" ["target/clr/clj/Debug 4.0" %1]]
11+
:clj-url "https://github.com/downloads/clojure/clojure-clr/clojure-clr-1.4.0-Debug-4.0.zip"
12+
:clj-zip "clojure-clr-1.4.0-Debug-4.0.zip"
13+
:curl ["curl" "--insecure" "-f" "-L" "-o" %1 %2]
14+
:nuget-ver [#_"mono" [*PATH "nuget.exe"] "install" %1 "-Version" %2]
15+
:nuget-any [#_"mono" [*PATH "nuget.exe"] "install" %1]
16+
:unzip ["unzip" "-d" %1 %2]
17+
:wget ["wget" "--no-check-certificate" "--no-clobber" "-O" %1 %2]}
18+
;; for automatic download/unzip of ClojureCLR,
19+
;; 1. make sure you have curl or wget installed and on PATH,
20+
;; 2. uncomment deps in :deps-cmds, and
21+
;; 3. use :clj-dep instead of :clj-exe in :main-cmd and :compile-cmd
22+
:deps-cmds [; [:wget :clj-zip :clj-url] ; edit to use :curl instead of :wget
23+
; [:unzip "../clj" :clj-zip]
24+
]
25+
:main-cmd [:clj-exe "Clojure.Main.exe"]
26+
:compile-cmd [:clj-exe "Clojure.Compile.exe"]})

src/clojure/data/generators.clj

+339
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
; Copyright (c) Rich Hickey, Stuart Halloway, and contributors.
2+
; All rights reserved.
3+
; The use and distribution terms for this software are covered by the
4+
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
5+
; which can be found in the file epl-v10.html at the root of this distribution.
6+
; By using this software in any fashion, you are agreeing to be bound by
7+
; the terms of this license.
8+
; You must not remove this notice, or any other, from this software.
9+
10+
(ns ^{:author "Stuart Halloway, modified for ClojureCLR by David Miller"
11+
:doc "Data generators for Clojure."}
12+
clojure.data.generators
13+
(:refer-clojure :exclude [byte char long int short float double boolean string symbol keyword list vec set hash-map name rand-nth byte-array boolean-array short-array char-array int-array long-array float-array double-array shuffle ulong uint ushort sbyte])
14+
(:require [clojure.core :as core]))
15+
16+
(def ^:dynamic ^System.Random ;;; ^java.util.Random
17+
*rnd*
18+
"Random instance for use in generators. By consistently using this
19+
instance you can get a repeatable basis for tests."
20+
(System.Random. 42)) ;;; (java.util.Random. 42))
21+
22+
(defn- call-through
23+
"Recursively call x until it doesn't return a function."
24+
[x]
25+
(if (fn? x)
26+
(recur (x))
27+
x))
28+
29+
(defn reps
30+
"Returns sizer repetitions of f (or (f) if f is a fn)."
31+
[sizer f]
32+
(let [count (call-through sizer)]
33+
(if (fn? f)
34+
(repeatedly count f)
35+
(repeat count f))))
36+
37+
(defn geometric
38+
"Geometric distribution with mean 1/p."
39+
^long [p]
40+
(core/long (Math/Ceiling (/ (Math/Log (.NextDouble *rnd*)) ;;; Math/ceil Math/log .nextDouble
41+
(Math/Log (- 1.0 p)))))) ;;; Math/Log
42+
(declare next-long) ;;; added
43+
(defn uniform
44+
"Uniform distribution from lo (inclusive) to high (exclusive).
45+
Defaults to range of Java long."
46+
(^long [] (next-long *rnd*)) ;;; .nextLong
47+
(^long[lo hi] {:pre [(< lo hi)]}
48+
(clojure.core/long (Math/Floor (+ lo (* (.NextDouble *rnd*) (- hi lo))))))) ;;; Math/floor .nextDouble
49+
50+
(defn float
51+
"Generate af float between 0 and 1 based on *rnd*"
52+
^double []
53+
(core/float (.NextDouble *rnd*))) ;;; (.nextFloat *rnd*))
54+
55+
(defn double
56+
"Generate a double between 0 and 1 based on *rnd*."
57+
^double []
58+
(.NextDouble *rnd*)) ;;; .nextDouble
59+
60+
(defn rand-nth
61+
"Replacement of core/rand-nth that allows control of the
62+
randomization basis (through binding *rnd*)."
63+
[coll]
64+
(nth coll (uniform 0 (count coll))))
65+
66+
(defn tuple
67+
"Generate a tuple with one element from each generator."
68+
[& generators]
69+
(into [] (map #(%) generators)))
70+
71+
(defn weighted
72+
"Given a map of generators and weights, return a value from one of
73+
the generators, selecting generator based on weights."
74+
[m]
75+
(let [weights (reductions + (vals m))
76+
total (last weights)
77+
choices (map vector (keys m) weights)]
78+
(let [choice (uniform 0 total)]
79+
(loop [[[c w] & more] choices]
80+
(when w
81+
(if (< choice w)
82+
(call-through c)
83+
(recur more)))))))
84+
85+
(defn one-of
86+
"Generates one of the specs passed in, with equal probability."
87+
([& specs]
88+
(weighted (zipmap specs (repeat 1)))))
89+
90+
(def long
91+
"Returns a long based on *rnd*. Same as uniform."
92+
uniform)
93+
94+
(defn int
95+
[]
96+
"Returns a long based on *rnd* in the int range."
97+
(uniform Int32/MinValue (inc Int32/MaxValue))) ;;; Integer/MIN_VALUE Integer/Max_VALUE
98+
99+
(defn short
100+
[]
101+
"Returns a long based on *rnd* in the short range."
102+
(uniform Int16/MinValue (inc (core/long Int16/MaxValue)))) ;;; Short/MIN_VALUE Short/MAX_VALUE
103+
104+
(defn byte
105+
"Returns a long based on *rnd* in the byte range."
106+
^long []
107+
(uniform Byte/MinValue (inc (core/int Byte/MaxValue)))) ;;; Byte/MIN_VALUE Byte/MAX_VALUE
108+
109+
(defn boolean
110+
"Returns a bool based on *rnd*."
111+
[]
112+
(zero? (.Next *rnd* 0 2))) ;;; (.nextBoolean *rnd*))
113+
114+
(defn printable-ascii-char
115+
"Returns a char based on *rnd* in the printable ascii range."
116+
[]
117+
(core/char (uniform 32 127)))
118+
119+
(defn char
120+
"Returns a character based on *rnd* in the range 0-65536."
121+
[]
122+
(core/char (uniform 0 65536)))
123+
124+
(defn default-sizer
125+
"Default sizer used to run tests. If you want a specific distribution,
126+
create your own and pass it to a fn that wants a sizer."
127+
[]
128+
(dec (geometric 0.02)))
129+
130+
(defn list
131+
"Create a list with elements from f and sized from sizer."
132+
([f] (list f default-sizer))
133+
([f sizer]
134+
(reps sizer f)))
135+
136+
(defmacro primitive-array
137+
[type]
138+
(let [fn-name (core/symbol (str type "-array"))
139+
factory-name (core/symbol (str "core/" fn-name))
140+
cast-name (core/symbol (str "core/" type))]
141+
`(defn ~fn-name
142+
"Create an array with elements from f and sized from sizer."
143+
([~'f]
144+
(~fn-name ~'f default-sizer))
145+
([~'f ~'sizer]
146+
(let [~'arr (~factory-name (call-through ~'sizer))]
147+
(dotimes [~'i (count ~'arr)]
148+
(aset ~'arr ~'i (~cast-name (call-through ~'f))))
149+
~'arr)))))
150+
151+
(defmacro primitive-arrays
152+
[types]
153+
`(do ~@(map (fn [type] `(primitive-array ~type)) types)))
154+
155+
(primitive-arrays ["byte" "short" "long" "char" "double" "float" "int" "boolean"])
156+
157+
#_(defn byte-array
158+
([f]
159+
(byte-array f default-sizer))
160+
([f sizer]
161+
(let [arr (core/byte-array (call-through default-sizer))]
162+
(dotimes [i (count arr)]
163+
(aset arr i (core/byte (call-through f))))
164+
arr)))
165+
166+
(defn vec
167+
"Create a vec with elements from f and sized from sizer."
168+
([f] (vec f default-sizer))
169+
([f sizer]
170+
(into [] (reps sizer f))))
171+
172+
(defn set
173+
"Create a set with elements from f and sized from sizer."
174+
([f] (set f default-sizer))
175+
([f sizer]
176+
(into #{} (reps sizer f))))
177+
178+
(defn hash-map
179+
"Create a hash-map with keys from fk, vals from fv, and
180+
sized from sizer."
181+
([fk fv] (hash-map fk fv default-sizer))
182+
([fk fv sizer]
183+
(into {}
184+
(zipmap (reps sizer fk)
185+
(reps sizer fv)))))
186+
187+
(defn string
188+
"Create a string with chars from v and sized from sizer."
189+
([] (string printable-ascii-char))
190+
([f] (string f default-sizer))
191+
([f sizer] (apply str (reps sizer f))))
192+
193+
(def ^:private ascii-alpha
194+
(concat (range 65 (+ 65 26))
195+
(range 97 (+ 97 26))))
196+
197+
(def ^:private symbol-start
198+
(-> (concat ascii-alpha [\* \+ \! \- \_ \?])
199+
core/vec))
200+
201+
(def ^:private symbol-char
202+
(into symbol-start [\1 \2 \3 \4 \5 \6 \7 \8 \9 \0]))
203+
204+
;; cannot generate every legal prefix, but at least avoids
205+
;; the illegal "-1"
206+
(defn- name-prefix
207+
[]
208+
(str (rand-nth [(core/char (rand-nth symbol-start)) ""])
209+
(core/char (rand-nth ascii-alpha))))
210+
211+
(defn- name-body
212+
[sizer]
213+
(string #(core/char (rand-nth symbol-char)) sizer))
214+
215+
(defn- name
216+
([] (name default-sizer))
217+
([sizer]
218+
(str (name-prefix)
219+
(name-body sizer))))
220+
221+
(defn symbol
222+
"Create a symbol sized from sizer."
223+
([] (core/symbol (name)))
224+
([sizer]
225+
(core/symbol (name sizer))))
226+
227+
(defn keyword
228+
"Create a keyword sized from sizer."
229+
([] (core/keyword (name)))
230+
([sizer]
231+
(core/keyword (name sizer))))
232+
233+
(def scalars
234+
[(constantly nil)
235+
byte
236+
long
237+
boolean
238+
printable-ascii-char
239+
string
240+
symbol
241+
keyword])
242+
243+
(defn scalar
244+
"Returns a scalar based on *rnd*."
245+
[]
246+
(call-through (rand-nth scalars)))
247+
248+
(def collections
249+
[[vec [scalars]]
250+
[set [scalars]]
251+
[hash-map [scalars scalars]]])
252+
253+
(defn collection
254+
"Returns a collection of scalar elements based on *rnd*."
255+
[]
256+
(let [[coll args] (rand-nth collections)]
257+
(apply coll (map rand-nth args))))
258+
259+
(defn anything
260+
"Returns a scalar or collection based on *rnd*."
261+
[]
262+
(one-of scalar collection))
263+
264+
(defn ^:private fisher-yates
265+
"http://en.wikipedia.org/wiki/Fisher–Yates_shuffle#The_modern_algorithm"
266+
[coll]
267+
(let [as (object-array coll)]
268+
(loop [i (dec (count as))]
269+
(if (<= 1 i)
270+
(let [j (uniform 0 (inc i))
271+
t (aget as i)]
272+
(aset as i (aget as j))
273+
(aset as j t)
274+
(recur (dec i)))
275+
(into (empty coll) (seq as))))))
276+
277+
(defn shuffle
278+
"Shuffle coll based on *rnd*"
279+
[coll]
280+
;; using our own fischer-yates instead of core/shuffle so that
281+
;; we'll get the same shuffle, given the same *rnd*.
282+
(fisher-yates coll))
283+
284+
(defn reservoir-sample
285+
"Reservoir sample ct items from coll, using *rnd*."
286+
[ct coll]
287+
(loop [result (transient (core/vec (take ct coll)))
288+
n ct
289+
coll (drop ct coll)]
290+
(if (seq coll)
291+
(let [pos (uniform 0 n)]
292+
(recur (if (< pos ct)
293+
(assoc! result pos (first coll))
294+
result)
295+
(inc n)
296+
(rest coll)))
297+
(persistent! result))))
298+
299+
;;; Added
300+
301+
(defn- next-long
302+
"Generate a random 64-bit integer"
303+
^long [^System.Random rnd]
304+
(let [buffer (core/byte-array 8)]
305+
(.NextBytes rnd buffer)
306+
(BitConverter/ToInt64 buffer 0)))
307+
308+
(defn- next-ulong
309+
"Generate a random 64-bit integer"
310+
^long [^System.Random rnd]
311+
(let [buffer (core/byte-array 8)]
312+
(.NextBytes rnd buffer)
313+
(long (BitConverter/ToUInt64 buffer 0))))
314+
315+
;;; TODO: Come back to this, need gvec to define
316+
;;;(primitive-arrays ["sbyte" "ushort" "ulong" "uint"])
317+
318+
(defn uint
319+
[]
320+
"Returns a long based on *rnd* in the uint range."
321+
(uniform UInt32/MinValue (inc UInt32/MaxValue)))
322+
323+
(defn ushort
324+
[]
325+
"Returns a long based on *rnd* in the ushort range."
326+
(uniform UInt16/MinValue (inc UInt16/MaxValue)))
327+
328+
(defn sbyte
329+
[]
330+
"Returns a long based on *rnd* in the sbyte range."
331+
(uniform SByte/MinValue (inc SByte/MaxValue)))
332+
333+
(defn ulong
334+
[]
335+
"Returns a long based on *rnd* in the ulong range."
336+
(uniform UInt64/MinValue (inc UInt64/MaxValue)))
337+
338+
339+

0 commit comments

Comments
 (0)