forked from standardml/cmlib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bytestring.sml
executable file
·148 lines (112 loc) · 3.61 KB
/
bytestring.sml
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
structure Bytestring :> BYTESTRING =
struct
type string = Word8Vector.vector
type byte = Word8.word
type char = byte
structure V = Word8Vector
val maxSize = V.maxLen
val size = V.length
val sub = V.sub
fun substring (s, start, len) =
Word8VectorSlice.vector (Word8VectorSlice.slice (s, start, SOME len))
fun extract (s, start, leno) =
Word8VectorSlice.vector (Word8VectorSlice.slice (s, start, leno))
fun isEmpty str = V.length str = 0
fun op ^ (s1, s2) = V.concat [s1, s2]
val concat = V.concat
val null = V.fromList []
fun str b = V.fromList [b]
val implode = V.fromList
fun explode s = V.foldr (op ::) nil s
fun map f s = V.map f s
fun map2 f (s1, s2) =
if V.length s1 <> V.length s2 then
raise ListPair.UnequalLengths
else
V.mapi (fn (i, b1) => f (b1, V.sub (s2, i))) s1
fun rev s =
let
val len = size s
in
V.tabulate (size s, (fn i => V.sub (s, len-i-1)))
end
fun eq (s1, s2) =
let
val len = size s1
fun loop i =
if i >= len then
true
else
V.sub (s1, i) = V.sub (s2,i) andalso loop (i+1)
in
size s2 = len andalso loop 0
end
fun compare (s1, s2) =
let
val len1 = size s1
val len2 = size s2
fun loop i =
if i >= len1 then
if i >= len2 then
EQUAL
else
LESS
else
if i >= len2 then
GREATER
else
(case Word8.compare (V.sub (s1, i), V.sub (s2, i)) of
EQUAL =>
loop (i+1)
| x => x)
in
loop 0
end
fun fromWord8Vector s = s
fun toWord8Vector s = s
val fromString = Byte.stringToBytes
val toString = Byte.bytesToString
fun fromStringHex str =
let
val len = String.size str
fun loop acc i =
if i = len then
SOME (V.fromList (List.rev acc))
else if i + 2 > len then
NONE
else
(case FromString.scanSubstringAll (Word8.scan StringCvt.HEX) (Substring.substring (str, i, 2)) of
NONE => NONE
| SOME b =>
loop (b :: acc) (i+2))
in
loop [] 0
end
val ch0 = Char.ord #"0"
val cha = Char.ord #"a" - 10
fun nibblestr (n:byte) =
if n <= 0w9 then
String.str (Char.chr (Word8.toInt n + ch0))
else
String.str (Char.chr (Word8.toInt n + cha))
fun toStringHex' sep s =
if V.length s = 0 then
""
else
let
val b = Word8Vector.sub (s, 0)
in
String.concat
(nibblestr (Word8.>> (b, 0w4))
:: nibblestr (Word8.andb (b, 0wxf))
:: Word8VectorSlice.foldr
(fn (b, l) =>
sep
:: nibblestr (Word8.>> (b, 0w4))
:: nibblestr (Word8.andb (b, 0wxf))
:: l)
[]
(Word8VectorSlice.slice (s, 1, NONE)))
end
val toStringHex = toStringHex' ""
end