Add myrddin implementation (the whole point of this project)
[fpmath-consensus.git] / impl-myrddin / impl-myrddin.myr
blob8b6f6fde3a1cf602591bb9ad4db3002ea27025c7
1 use std
3 use math
5 type Fn_flt__flt = struct
6         f32 : (f : flt32 -> flt32)
7         f64 : (f : flt64 -> flt64)
8 ;;
10 type fn_desc = struct
11         name : byte[:]
12         f : union
13                 `Flt__flt Fn_flt__flt
14         ;;
17 type flt_prec = union
18         `Single
19         `Double
22 var available_fns : fn_desc[:] = [][:]
24 generic id : (a : @a -> @a) = {x; -> x}
26 const main = {args : byte[:][:]
27         available_fns = [
28                 [.name = "id",    .f = `Flt__flt [ .f32 = id,         .f64 = id]],
29                 [.name = "trunc", .f = `Flt__flt [ .f32 = math.trunc, .f64 = id]],
30         ][:]
32         var p : flt_prec = `Single
33         var f : fn_desc = available_fns[0]
34         var n : std.size = 0
36         (p, f, n) = read_args(args)
38         io_loop(p, f, n)
41 const read_args = {args : byte[:][:]
42         var p : flt_prec = `Single
43         var n : std.size = 0
44         var fname : byte[:] = ""
45         var fn : fn_desc = available_fns[0]
46         var cmd = std.optparse(args, &[
47                 .argdesc = "",
48                 .opts = [
49                         [.opt = 's', .desc = "use single precision (default)"],
50                         [.opt = 'd', .desc = "use double precision"],
51                         [.opt = 'n', .arg = "N", .desc = "read/write ‘N’ entries at a time"],
52                         [.opt = 'f', .arg = "func", .desc = "use function ‘f’"],
53                 ][:]
54         ])
56         for opt : cmd.opts
57                 match opt
58                 | ('s', _): p = `Single
59                 | ('d', _): p = `Double
60                 | ('n', ns):
61                         match std.intparse(ns)
62                         | `std.Some np: n = np
63                         | `std.None:
64                                 std.put("impl-myrddin: unparsable number “{}”\n", ns)
65                                 std.exit(1)
66                         ;;
67                 | ('f', fs): fname = fs
68                 | _ : std.die("impl-myrddin: impossible\n")
69                 ;;
70         ;;
72         var good_fn : bool = false
73         for f : available_fns
74                 if std.eq(f.name, fname)
75                         fn = f
76                         good_fn = true
77                         break
78                 ;;
79         ;;
81         if !good_fn
82                 std.put("impl-myrddin: unknown function “{}”\n", fname)
83                 std.exit(1)
84         ;;
86         if n <= 0
87                 std.put("impl-myrddin: positive number of entries required\n")
88                 std.exit(1)
89         ;;
91         -> (p, fn, n)
95 const io_loop = {p : flt_prec, fn : fn_desc, n : std.size
96         var input_sz : std.size = 0
97         var output_sz : std.size = 0
98         var in_buf : byte[:] = [][:]
99         var out_buf : byte[:] = [][:]
100         var w = prec_width(p)
102         (input_sz, output_sz) = io_widths(p, fn)
104         if (((input_sz * n) / input_sz) != n) || (((output_sz * n) / output_sz) != n)
105                 std.put("impl-myrddin: overflow in i/o buffer size\n")
106                 std.exit(1)
107         ;;
109         in_buf = std.slalloc(input_sz * n)
110         out_buf = std.slalloc(output_sz * n)
112         while true
113                 match std.readall(0, in_buf)
114                 | `std.Ok _:
115                 | `std.Err e:
116                         std.put("impl-myrddin: std.readall(): {}\n", e)
117                         std.exit(1)
118                 ;;
120                 match (p, fn.f)
121                 | (`Single, `Flt__flt f):
122                         for var j = 0; j < n; ++j
123                                 var ib : byte[:] = in_buf[j * w:(j + 1) * w]
124                                 var ob : byte[:] = out_buf[j * w:(j + 1) * w]
125                                 var x : flt32 = std.flt32frombits(std.getle32(ib))
126                                 std.putle32(ob, std.flt32bits(f.f32(x)))
127                         ;;
128                 | (`Double, `Flt__flt f):
129                         for var j = 0; j < n; ++j
130                                 var ib : byte[:] = in_buf[j * w:(j + 1) * w]
131                                 var ob : byte[:] = out_buf[j * w:(j + 1) * w]
132                                 var x : flt64 = std.flt64frombits(std.getle64(ib))
133                                 std.putle64(ob, std.flt64bits(f.f64(x)))
134                         ;;
135                 ;;
137                 match std.writeall(1, out_buf)
138                 | (_, `std.None):
139                 | (_, `std.Some e):
140                         std.put("impl-myrddin: std.writeall(): {}\n", e)
141                         std.exit(1)
142                 ;;
143         ;;
146 const prec_width = {p : flt_prec
147         match p
148         | `Single: -> 4
149         | `Double: -> 8
150         ;;
153 const io_widths = {p : flt_prec, fn : fn_desc
154         var w : std.size = prec_width(p)
156         match fn.f
157         | `Flt__flt _ : -> (w, w)
158         ;;