Skip to content

Commit 6888702

Browse files
authored
Merge branch 'master' into fixed-max-length
2 parents dcbdec4 + e77f8eb commit 6888702

File tree

5 files changed

+144
-20
lines changed

5 files changed

+144
-20
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22
- fixed negative `max_length` on JavaScript platform
3+
- new function `random` (much faster than `init n (fun _ -> Random.bool ())`
4+
- new in-place bitwise operations (contribution by Mathieu Barbin)
35
- fixed division by zero in rotations of 0-length vectors
46
(reported by Nikolaus Huber)
57
- fixed integer overflows in bound tests in `fill`, `blit`, `sub`

bench.ml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33

44
open Bitv
55

6+
let () = Random.self_init ()
67
let n = int_of_string Sys.argv.(1)
7-
let v = init n (fun i -> i mod 5 = 0)
8-
let r = ref 0
9-
let add i = r := !r + i
10-
let () = iteri_true add v
11-
let () = Format.printf "%d@." !r
8+
(* let v = init n (fun _ -> Random.bool ()) *)
9+
let v = random n (* much faster *)
1210

1311

bitv.ml

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,20 @@ let init n f =
9494
for i = 0 to pred n do unsafe_set v i (f i) done;
9595
v
9696

97+
let random n =
98+
let v = create n false in
99+
let b = v.bits in
100+
let n = Bytes.length b in
101+
for i = 0 to n / 3 do let j = 3 * i in
102+
let bits = Random.bits () in
103+
set_byte b j (bits land 0xFF);
104+
set_byte b (j+1) ((bits lsr 8) land 0xFF);
105+
set_byte b (j+2) ((bits lsr 16) land 0xFF)
106+
done;
107+
for i = 3 * (n / 3) to n - 1 do set_byte b i (Random.int 256) done;
108+
normalize v;
109+
v
110+
97111
let fill v ofs len b =
98112
if ofs < 0 || len < 0 || ofs > v.length - len then invalid_arg "Bitv.fill";
99113
if len > 0 then (
@@ -216,52 +230,96 @@ let pop v =
216230
However, one has to take care of normalizing the result of [bwnot]
217231
which introduces ones in highest significant positions. *)
218232

233+
let[@inline always] bw_and_in_place_internal ~dest ~n b1 b2 =
234+
for i = 0 to n - 1 do
235+
set_byte dest i ((byte b1 i) land (byte b2 i))
236+
done
237+
238+
let bw_and_in_place ~dest v1 v2 =
239+
let l = v1.length in
240+
if l <> v2.length || l <> dest.length then invalid_arg "Bitv.bw_and_in_place";
241+
let b1 = v1.bits
242+
and b2 = v2.bits in
243+
let n = Bytes.length b1 in
244+
bw_and_in_place_internal ~dest:dest.bits ~n b1 b2
245+
219246
let bw_and v1 v2 =
220247
let l = v1.length in
221248
if l <> v2.length then invalid_arg "Bitv.bw_and";
222249
let b1 = v1.bits
223250
and b2 = v2.bits in
224251
let n = Bytes.length b1 in
225252
let a = Bytes.make n (Char.chr 0) in
226-
for i = 0 to n - 1 do
227-
set_byte a i ((byte b1 i) land (byte b2 i))
228-
done;
253+
bw_and_in_place_internal ~dest:a ~n b1 b2;
229254
{ length = l; bits = a }
230255

256+
let[@inline always] bw_or_in_place_internal ~dest ~n b1 b2 =
257+
for i = 0 to n - 1 do
258+
set_byte dest i ((byte b1 i) lor (byte b2 i))
259+
done
260+
261+
let bw_or_in_place ~dest v1 v2 =
262+
let l = v1.length in
263+
if l <> v2.length || l <> dest.length then invalid_arg "Bitv.bw_or_in_place";
264+
let b1 = v1.bits
265+
and b2 = v2.bits in
266+
let n = Bytes.length b1 in
267+
bw_or_in_place_internal ~dest:dest.bits ~n b1 b2
268+
231269
let bw_or v1 v2 =
232270
let l = v1.length in
233271
if l <> v2.length then invalid_arg "Bitv.bw_or";
234272
let b1 = v1.bits
235273
and b2 = v2.bits in
236274
let n = Bytes.length b1 in
237275
let a = Bytes.make n (Char.chr 0) in
238-
for i = 0 to n - 1 do
239-
set_byte a i ((byte b1 i) lor (byte b2 i))
240-
done;
276+
bw_or_in_place_internal ~dest:a ~n b1 b2;
241277
{ length = l; bits = a }
242278

279+
let[@inline always] bw_xor_in_place_internal ~dest ~n b1 b2 =
280+
for i = 0 to n - 1 do
281+
set_byte dest i ((byte b1 i) lxor (byte b2 i))
282+
done
283+
284+
let bw_xor_in_place ~dest v1 v2 =
285+
let l = v1.length in
286+
if l <> v2.length || l <> dest.length then invalid_arg "Bitv.bw_xor_in_place";
287+
let b1 = v1.bits
288+
and b2 = v2.bits in
289+
let n = Bytes.length b1 in
290+
bw_xor_in_place_internal ~dest:dest.bits ~n b1 b2
291+
243292
let bw_xor v1 v2 =
244293
let l = v1.length in
245-
if l <> v2.length then invalid_arg "Bitv.bw_or";
294+
if l <> v2.length then invalid_arg "Bitv.bw_xor";
246295
let b1 = v1.bits
247296
and b2 = v2.bits in
248297
let n = Bytes.length b1 in
249298
let a = Bytes.make n (Char.chr 0) in
299+
bw_xor_in_place_internal ~dest:a ~n b1 b2;
300+
{ length = l; bits = a }
301+
302+
let[@inline always] bw_not_in_place_internal ~dest ~n b =
303+
let a = dest.bits in
250304
for i = 0 to n - 1 do
251-
set_byte a i ((byte b1 i) lxor (byte b2 i))
305+
set_byte a i (255 land (lnot (byte b i)))
252306
done;
253-
{ length = l; bits = a }
307+
normalize dest
308+
309+
let bw_not_in_place ~dest v =
310+
let l = v.length in
311+
if l <> dest.length then invalid_arg "Bitv.bw_not_in_place";
312+
let b = v.bits in
313+
let n = Bytes.length b in
314+
bw_not_in_place_internal ~dest ~n b
254315

255316
let bw_not v =
256317
let b = v.bits in
257318
let n = Bytes.length b in
258319
let a = Bytes.make n (Char.chr 0) in
259-
for i = 0 to n - 1 do
260-
set_byte a i (255 land (lnot (byte b i)))
261-
done;
262-
let r = { length = v.length; bits = a } in
263-
normalize r;
264-
r
320+
let dest = { length = v.length; bits = a } in
321+
bw_not_in_place_internal ~dest ~n b;
322+
dest
265323

266324
(* Coercions to/from lists of integers *)
267325

bitv.mli

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ val init : int -> (int -> bool) -> t
3333
(** [(Bitv.init n f)] returns a fresh vector of length [n],
3434
with bit number [i] initialized to the result of [(f i)]. *)
3535

36+
val random: int -> t
37+
(** [Bitv.random n] returns a fresh vector of length [n] with random bits.
38+
This is equivalent to [Bitv.init n (fun _ -> Random.bool ())],
39+
but much faster. *)
40+
3641
val set : t -> int -> bool -> unit
3742
(** [(Bitv.set v n b)] sets the [n]th bit of [v] to the value [b]. *)
3843

@@ -177,6 +182,34 @@ val rotatel : t -> int -> t
177182
val rotater : t -> int -> t
178183
(** moves bits from most to least significant with wraparound *)
179184

185+
(** {3 Bitwise in place operations.}
186+
187+
This part of the API extends some bitwise operations by making them operate
188+
in place, that is mutating a destination bit vector supplied as a labeled
189+
argument [dest], rather than returning a fresh one.
190+
191+
These in place operations support being called with [dest] being one of the
192+
operands supplied to the function call.
193+
194+
For example [bw_and_in_place ~dest:a a b] will store in [a] the result of
195+
the operation [bw_and a b]. *)
196+
197+
val bw_and_in_place : dest:t -> t -> t -> unit
198+
(** bitwise AND in place into [dest];
199+
raises [Invalid_argument] if the three vectors do not have the same length *)
200+
201+
val bw_or_in_place : dest:t -> t -> t -> unit
202+
(** bitwise OR in place into [dest];
203+
raises [Invalid_argument] if the three vectors do not have the same length *)
204+
205+
val bw_xor_in_place : dest:t -> t -> t -> unit
206+
(** bitwise XOR in place into [dest];
207+
raises [Invalid_argument] if the three vectors do not have the same length *)
208+
209+
val bw_not_in_place : dest:t -> t -> unit
210+
(** bitwise NOT in place into [dest];
211+
raises [Invalid_argument] if the two vectors do not have the same length *)
212+
180213
(** {2 Test functions} *)
181214

182215
val all_zeros : t -> bool

test.ml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,35 @@ let s = sub v 2 4
4545
let () = assert (equal (bw_not (bw_not s)) s)
4646
let () = assert (equal (bw_and e e) e)
4747

48+
(* bitwise in place operations *)
49+
let va = init 10 (fun i -> i mod 2 = 0)
50+
let vb = init 10 (fun i -> i mod 4 = 0)
51+
let vc = create 10 false
52+
let ve = create 3 false
53+
let () =
54+
assert (to_string va = "0101010101");
55+
assert (to_string vb = "0100010001");
56+
bw_and_in_place ~dest:vc va vb;
57+
assert (equal vc (bw_and va vb));
58+
assert (equal vc vb);
59+
(try bw_and_in_place ~dest:ve va vb; assert false
60+
with Invalid_argument msg -> assert (msg = "Bitv.bw_and_in_place"));
61+
bw_or_in_place ~dest:vc va vb;
62+
assert (equal vc (bw_or va vb));
63+
assert (equal vc va);
64+
(try bw_or_in_place ~dest:ve va vb; assert false
65+
with Invalid_argument msg -> assert (msg = "Bitv.bw_or_in_place"));
66+
bw_xor_in_place ~dest:vc va vb;
67+
assert (equal vc (bw_xor va vb));
68+
assert (to_string vc = "0001000100");
69+
(try bw_xor_in_place ~dest:ve va vb; assert false
70+
with Invalid_argument msg -> assert (msg = "Bitv.bw_xor_in_place"));
71+
bw_not_in_place ~dest:vc va;
72+
assert (to_string vc = "1010101010");
73+
(try bw_not_in_place ~dest:ve va; assert false
74+
with Invalid_argument msg -> assert (msg = "Bitv.bw_not_in_place"));
75+
()
76+
4877
(* Tanimoto score *)
4978
let () =
5079
let b0 = create 10 false in
@@ -235,6 +264,10 @@ let () = assert (equal (bw_or v ones) ones)
235264
let () = assert (equal (bw_and v ones) v)
236265
let () = assert (equal (bw_xor v zeros) v)
237266
let () = assert (equal (bw_xor v ones) (bw_not v))
267+
let () =
268+
let dest = create 30 false in
269+
bw_not_in_place ~dest v;
270+
assert (equal (bw_xor v ones) dest)
238271

239272
(* fill overflow *)
240273
let () =

0 commit comments

Comments
 (0)