-
Notifications
You must be signed in to change notification settings - Fork 56
/
Copy pathbinfile.m
126 lines (101 loc) · 3.7 KB
/
binfile.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2019 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%---------------------------------------------------------------------------%
%
% File: binfile.m
% Main author: Mark Brown
%
% "Random" number generator that reads numbers from a binary file.
%
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- module binfile.
:- interface.
:- import_module io.
:- import_module random.
%---------------------------------------------------------------------------%
:- type binfile.
:- instance urandom(binfile, io).
% Open a binfile generator from a filename. This should be closed
% when no longer needed.
%
:- pred open(string, io.res(binfile), io, io).
:- mode open(in, out, di, uo) is det.
% Close a binfile generator.
%
:- pred close(binfile, io, io).
:- mode close(in, di, uo) is det.
%---------------------------------------------------------------------------%
% Generate an unsigned integer of 8, 16, 32 or 64 bits, reespectively.
% This reads the required number of bytes from the file and interprets
% them as an unsigned, big-endian integer.
%
% Throws an exception if the end-of-file is reached.
%
:- pred generate_uint8(binfile::in, uint8::out, io::di, io::uo) is det.
:- pred generate_uint16(binfile::in, uint16::out, io::di, io::uo) is det.
:- pred generate_uint32(binfile::in, uint32::out, io::di, io::uo) is det.
:- pred generate_uint64(binfile::in, uint64::out, io::di, io::uo) is det.
%---------------------------------------------------------------------------%
:- implementation.
:- import_module require.
:- import_module uint64.
%---------------------------------------------------------------------------%
:- type binfile
---> binfile(binary_input_stream).
:- instance urandom(binfile, io) where [
pred(generate_uint8/4) is binfile.generate_uint8,
pred(generate_uint16/4) is binfile.generate_uint16,
pred(generate_uint32/4) is binfile.generate_uint32,
pred(generate_uint64/4) is binfile.generate_uint64
].
%---------------------------------------------------------------------------%
open(Filename, Res, !IO) :-
io.open_binary_input(Filename, Res0, !IO),
(
Res0 = ok(Stream),
Res = ok(binfile(Stream))
;
Res0 = error(E),
Res = error(E)
).
close(binfile(Stream), !IO) :-
io.close_binary_input(Stream, !IO).
%---------------------------------------------------------------------------%
generate_uint8(binfile(Stream), N, !IO) :-
io.read_binary_uint8(Stream, Res, !IO),
(
Res = ok(N)
;
Res = eof,
unexpected($pred, "end of file")
;
Res = error(E),
unexpected($pred, io.error_message(E))
).
generate_uint16(binfile(Stream), N, !IO) :-
io.read_binary_uint16_be(Stream, Res, !IO),
handle_res(Res, N).
generate_uint32(binfile(Stream), N, !IO) :-
io.read_binary_uint32_be(Stream, Res, !IO),
handle_res(Res, N).
generate_uint64(binfile(Stream), N, !IO) :-
io.read_binary_uint64_be(Stream, Res, !IO),
handle_res(Res, N).
:- pred handle_res(maybe_incomplete_result(T)::in, T::out) is det.
handle_res(Res, N) :-
(
Res = ok(N)
;
( Res = eof
; Res = incomplete(_)
),
unexpected($pred, "end of file")
;
Res = error(E),
unexpected($pred, io.error_message(E))
).
%---------------------------------------------------------------------------%