From d097d2e779b61e294fb8c2aff80cf6d20029c315 Mon Sep 17 00:00:00 2001 From: Jeremy Yallop Date: Tue, 11 Aug 2015 16:09:41 +0100 Subject: [PATCH 1/7] Add CArray.iter --- src/ctypes/ctypes.mli | 4 ++++ src/ctypes/ctypes_memory.ml | 5 +++++ tests/test-arrays/test_array.ml | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/ctypes/ctypes.mli b/src/ctypes/ctypes.mli index 00fa927b..bd53c379 100644 --- a/src/ctypes/ctypes.mli +++ b/src/ctypes/ctypes.mli @@ -277,6 +277,10 @@ sig element of the list is the result of reading the corresponding element of [a]. *) + val iter : ('a -> unit) -> 'a t -> unit + (** [iter f a] is analogous to [Array.iter f a]: it applies [f] in turn to + all the elements of [a]. *) + val length : 'a t -> int (** Return the number of elements of the given array. *) diff --git a/src/ctypes/ctypes_memory.ml b/src/ctypes/ctypes_memory.ml index 9bace6e0..8aaba5d5 100644 --- a/src/ctypes/ctypes_memory.ml +++ b/src/ctypes/ctypes_memory.ml @@ -212,6 +212,11 @@ struct l := get a i :: !l done; !l + + let iter f a = + for i = 0 to length a - 1 do + f (unsafe_get a i) + done end let make ?finalise s = diff --git a/tests/test-arrays/test_array.ml b/tests/test-arrays/test_array.ml index 74b6d6ef..b82ea42d 100644 --- a/tests/test-arrays/test_array.ml +++ b/tests/test-arrays/test_array.ml @@ -93,6 +93,22 @@ let test_multidimensional_arrays _ = done +(* + Test the CArray.iter function + *) +let test_iter _ = + let r = ref 0 in + let a = CArray.of_list int [1; 2; 3] in + let () = CArray.iter (fun v -> r := !r + v) a in + assert_equal !r 6; + + let r = ref 0 in + let a = CArray.of_list int [] in + let () = CArray.iter (fun _ -> assert false) a in + assert_equal !r 0 + + + (* Test that creating an array initializes all elements appropriately. *) @@ -204,6 +220,9 @@ let suite = "Array tests" >::: ["multidimensional arrays" >:: test_multidimensional_arrays; + "CArray.iter " + >:: test_iter; + "array initialization" >:: test_array_initialiation; From a41059dd717a4cecae07bec7fc34dbe0905a5a95 Mon Sep 17 00:00:00 2001 From: Jeremy Yallop Date: Mon, 28 Sep 2015 16:40:30 +0100 Subject: [PATCH 2/7] Add CArray.map --- src/ctypes/ctypes.mli | 5 +++++ src/ctypes/ctypes_memory.ml | 8 ++++++++ tests/test-arrays/test_array.ml | 15 +++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/ctypes/ctypes.mli b/src/ctypes/ctypes.mli index bd53c379..dab1e25b 100644 --- a/src/ctypes/ctypes.mli +++ b/src/ctypes/ctypes.mli @@ -281,6 +281,11 @@ sig (** [iter f a] is analogous to [Array.iter f a]: it applies [f] in turn to all the elements of [a]. *) + val map : 'b typ -> ('a -> 'b) -> 'a t -> 'b t + (** [map t f a] is analogous to [Array.map f a]: it creates a new array with + element type [t] whose elements are obtained by applying [f] to the + elements of [a]]. *) + val length : 'a t -> int (** Return the number of elements of the given array. *) diff --git a/src/ctypes/ctypes_memory.ml b/src/ctypes/ctypes_memory.ml index 8aaba5d5..6cb11905 100644 --- a/src/ctypes/ctypes_memory.ml +++ b/src/ctypes/ctypes_memory.ml @@ -217,6 +217,14 @@ struct for i = 0 to length a - 1 do f (unsafe_get a i) done + + let map typ f a = + let l = length a in + let r = make typ l in + for i = 0 to l - 1 do + unsafe_set r i (f (unsafe_get a i)) + done; + r end let make ?finalise s = diff --git a/tests/test-arrays/test_array.ml b/tests/test-arrays/test_array.ml index b82ea42d..dc42ea19 100644 --- a/tests/test-arrays/test_array.ml +++ b/tests/test-arrays/test_array.ml @@ -108,6 +108,18 @@ let test_iter _ = assert_equal !r 0 +(* + Test the CArray.map function + *) +let test_map _ = + let a = CArray.of_list int [1; 2; 3] in + let r = CArray.map float float_of_int a in + assert_equal [1.0; 2.0; 3.0] (CArray.to_list r); + + let a = CArray.of_list int [] in + let r = CArray.map string (fun _ -> assert false) a in + assert_equal (CArray.length r) 0 + (* Test that creating an array initializes all elements appropriately. @@ -223,6 +235,9 @@ let suite = "Array tests" >::: "CArray.iter " >:: test_iter; + "CArray.map " + >:: test_map; + "array initialization" >:: test_array_initialiation; From cd8529e8bb0d86e2c69ccff4827b7ffc1bfcaa81 Mon Sep 17 00:00:00 2001 From: Jeremy Yallop Date: Mon, 28 Sep 2015 16:45:44 +0100 Subject: [PATCH 3/7] Add CArray.mapi --- src/ctypes/ctypes.mli | 5 +++++ src/ctypes/ctypes_memory.ml | 8 ++++++++ tests/test-arrays/test_array.ml | 16 ++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/src/ctypes/ctypes.mli b/src/ctypes/ctypes.mli index dab1e25b..27c0b9d8 100644 --- a/src/ctypes/ctypes.mli +++ b/src/ctypes/ctypes.mli @@ -286,6 +286,11 @@ sig element type [t] whose elements are obtained by applying [f] to the elements of [a]]. *) + val mapi : 'b typ -> (int -> 'a -> 'b) -> 'a t -> 'b t + (** [mapi] behaves like {!Array.mapi}, except that it also passes the + index of each element as the first argument to [f] and the element + itself as the second argument. *) + val length : 'a t -> int (** Return the number of elements of the given array. *) diff --git a/src/ctypes/ctypes_memory.ml b/src/ctypes/ctypes_memory.ml index 6cb11905..47feec0b 100644 --- a/src/ctypes/ctypes_memory.ml +++ b/src/ctypes/ctypes_memory.ml @@ -225,6 +225,14 @@ struct unsafe_set r i (f (unsafe_get a i)) done; r + + let mapi typ f a = + let l = length a in + let r = make typ l in + for i = 0 to l - 1 do + unsafe_set r i (f i (unsafe_get a i)) + done; + r end let make ?finalise s = diff --git a/tests/test-arrays/test_array.ml b/tests/test-arrays/test_array.ml index dc42ea19..8cdc1260 100644 --- a/tests/test-arrays/test_array.ml +++ b/tests/test-arrays/test_array.ml @@ -121,6 +121,19 @@ let test_map _ = assert_equal (CArray.length r) 0 +(* + Test the CArray.mapi function + *) +let test_mapi _ = + let a = CArray.of_list int [1; 2; 3] in + let r = CArray.mapi int (+) a in + assert_equal [1; 3; 5] (CArray.to_list r); + + let a = CArray.of_list int [] in + let r = CArray.mapi string (fun _ _ -> assert false) a in + assert_equal (CArray.length r) 0 + + (* Test that creating an array initializes all elements appropriately. *) @@ -238,6 +251,9 @@ let suite = "Array tests" >::: "CArray.map " >:: test_map; + "CArray.mapi " + >:: test_mapi; + "array initialization" >:: test_array_initialiation; From 388a7a8f693be7cd3b2e6f9610e9e72c11458af4 Mon Sep 17 00:00:00 2001 From: Jeremy Yallop Date: Mon, 28 Sep 2015 16:58:03 +0100 Subject: [PATCH 4/7] Add CArray.fold_left --- src/ctypes/ctypes.mli | 5 +++++ src/ctypes/ctypes_memory.ml | 7 +++++++ tests/test-arrays/test_array.ml | 16 ++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/ctypes/ctypes.mli b/src/ctypes/ctypes.mli index 27c0b9d8..b4e21ba7 100644 --- a/src/ctypes/ctypes.mli +++ b/src/ctypes/ctypes.mli @@ -291,6 +291,11 @@ sig index of each element as the first argument to [f] and the element itself as the second argument. *) + val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a + (** [CArray.fold_left (@) x a] computes + [(((x @ a.(0)) @ a.(1)) ...) @ a.(n-1)] + where [n] is the length of the array [a]. *) + val length : 'a t -> int (** Return the number of elements of the given array. *) diff --git a/src/ctypes/ctypes_memory.ml b/src/ctypes/ctypes_memory.ml index 47feec0b..d8adc90c 100644 --- a/src/ctypes/ctypes_memory.ml +++ b/src/ctypes/ctypes_memory.ml @@ -233,6 +233,13 @@ struct unsafe_set r i (f i (unsafe_get a i)) done; r + + let fold_left f x a = + let r = ref x in + for i = 0 to length a - 1 do + r := f !r (unsafe_get a i) + done; + !r end let make ?finalise s = diff --git a/tests/test-arrays/test_array.ml b/tests/test-arrays/test_array.ml index 8cdc1260..0c81ae8a 100644 --- a/tests/test-arrays/test_array.ml +++ b/tests/test-arrays/test_array.ml @@ -134,6 +134,19 @@ let test_mapi _ = assert_equal (CArray.length r) 0 +(* + Test the CArray.fold_left function + *) +let test_fold_left _ = + let a = CArray.of_list int [1; 2; 3] in + let r = CArray.fold_left (Printf.sprintf "%s%d") "." a in + assert_equal ".123" r; + + let a = CArray.of_list int [] in + let r = CArray.fold_left (fun _ -> assert false) [] a in + assert_equal r [] + + (* Test that creating an array initializes all elements appropriately. *) @@ -254,6 +267,9 @@ let suite = "Array tests" >::: "CArray.mapi " >:: test_mapi; + "CArray.fold_left" + >:: test_fold_left; + "array initialization" >:: test_array_initialiation; From 3acdde20a93874cd6395e2537b5f2cb36df8b022 Mon Sep 17 00:00:00 2001 From: Jeremy Yallop Date: Mon, 28 Sep 2015 16:58:09 +0100 Subject: [PATCH 5/7] Add CArray.fold_right --- src/ctypes/ctypes.mli | 5 +++++ src/ctypes/ctypes_memory.ml | 7 +++++++ tests/test-arrays/test_array.ml | 16 ++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/ctypes/ctypes.mli b/src/ctypes/ctypes.mli index b4e21ba7..c1c63f78 100644 --- a/src/ctypes/ctypes.mli +++ b/src/ctypes/ctypes.mli @@ -296,6 +296,11 @@ sig [(((x @ a.(0)) @ a.(1)) ...) @ a.(n-1)] where [n] is the length of the array [a]. *) + val fold_right : ('b -> 'a -> 'a) -> 'b t -> 'a -> 'a + (** [CArray.fold_right f a x] computes + [a.(0) @ (a.(1) @ ( ... (a.(n-1) @ x) ...))] + where [n] is the length of the array [a]. *) + val length : 'a t -> int (** Return the number of elements of the given array. *) diff --git a/src/ctypes/ctypes_memory.ml b/src/ctypes/ctypes_memory.ml index d8adc90c..38a255c2 100644 --- a/src/ctypes/ctypes_memory.ml +++ b/src/ctypes/ctypes_memory.ml @@ -240,6 +240,13 @@ struct r := f !r (unsafe_get a i) done; !r + + let fold_right f a x = + let r = ref x in + for i = length a - 1 downto 0 do + r := f (unsafe_get a i) !r + done; + !r end let make ?finalise s = diff --git a/tests/test-arrays/test_array.ml b/tests/test-arrays/test_array.ml index 0c81ae8a..f02c0067 100644 --- a/tests/test-arrays/test_array.ml +++ b/tests/test-arrays/test_array.ml @@ -147,6 +147,19 @@ let test_fold_left _ = assert_equal r [] +(* + Test the CArray.fold_right function + *) +let test_fold_right _ = + let a = CArray.of_list int [1; 2; 3] in + let r = CArray.fold_right (Printf.sprintf "%d%s") a "." in + assert_equal "123." r; + + let a = CArray.of_list int [] in + let r = CArray.fold_right (fun _ -> assert false) a [] in + assert_equal r [] + + (* Test that creating an array initializes all elements appropriately. *) @@ -270,6 +283,9 @@ let suite = "Array tests" >::: "CArray.fold_left" >:: test_fold_left; + "CArray.fold_right" + >:: test_fold_right; + "array initialization" >:: test_array_initialiation; From 9638eb378bf9066ff37d065012f60e683d602a54 Mon Sep 17 00:00:00 2001 From: Jeremy Yallop Date: Tue, 29 Sep 2015 23:35:42 +0100 Subject: [PATCH 6/7] Add CArray.copy --- src/ctypes/ctypes.mli | 5 ++++- src/ctypes/ctypes_memory.ml | 8 ++++++++ tests/test-arrays/test_array.ml | 21 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/ctypes/ctypes.mli b/src/ctypes/ctypes.mli index c1c63f78..b35eddd0 100644 --- a/src/ctypes/ctypes.mli +++ b/src/ctypes/ctypes.mli @@ -317,8 +317,11 @@ sig used to initialise every element of the array. The argument [?finalise], if present, will be called just before the memory is freed. *) + val copy : 'a t -> 'a t + (** [copy a] creates a fresh array with the same elements as [a]. *) + val element_type : 'a t -> 'a typ -(** Retrieve the element type of an array. *) + (** Retrieve the element type of an array. *) end (** Operations on C arrays. *) diff --git a/src/ctypes/ctypes_memory.ml b/src/ctypes/ctypes_memory.ml index 38a255c2..b6a39e9f 100644 --- a/src/ctypes/ctypes_memory.ml +++ b/src/ctypes/ctypes_memory.ml @@ -199,6 +199,14 @@ struct | None -> arr | Some v -> fill arr v; arr + let copy {astart = CPointer src; alength} = + begin + let reftyp = Fat.reftype src in + let CPointer dst as r = allocate_n reftyp alength in + let () = Stubs.memcpy ~dst ~src ~size:(alength * sizeof reftyp) in + from_ptr r alength + end + let element_type { astart } = reference_type astart let of_list typ list = diff --git a/tests/test-arrays/test_array.ml b/tests/test-arrays/test_array.ml index f02c0067..5a1339b3 100644 --- a/tests/test-arrays/test_array.ml +++ b/tests/test-arrays/test_array.ml @@ -159,6 +159,24 @@ let test_fold_right _ = let r = CArray.fold_right (fun _ -> assert false) a [] in assert_equal r [] +(* + Test the CArray.copy function + *) +let test_copy _ = + let a = CArray.of_list int [1; 2; 3] in + let r = CArray.copy a in + + begin + assert_equal [1; 2; 3] (CArray.to_list a); + assert_equal [1; 2; 3] (CArray.to_list r); + CArray.set r 0 10; + assert_equal [1; 2; 3] (CArray.to_list a); + assert_equal [10; 2; 3] (CArray.to_list r); + CArray.set a 1 20; + assert_equal [1; 20; 3] (CArray.to_list a); + assert_equal [10; 2; 3] (CArray.to_list r); + end + (* Test that creating an array initializes all elements appropriately. @@ -286,6 +304,9 @@ let suite = "Array tests" >::: "CArray.fold_right" >:: test_fold_right; + "CArray.copy" + >:: test_copy; + "array initialization" >:: test_array_initialiation; From ddeb685d327f67066d53c0c2709ca78801b9ce8e Mon Sep 17 00:00:00 2001 From: Jeremy Yallop Date: Tue, 29 Sep 2015 16:18:22 +0100 Subject: [PATCH 7/7] Add CArray.sub --- src/ctypes/ctypes.mli | 7 +++++++ src/ctypes/ctypes_memory.ml | 5 +++++ tests/test-arrays/test_array.ml | 36 +++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/src/ctypes/ctypes.mli b/src/ctypes/ctypes.mli index b35eddd0..54be16f5 100644 --- a/src/ctypes/ctypes.mli +++ b/src/ctypes/ctypes.mli @@ -320,6 +320,13 @@ sig val copy : 'a t -> 'a t (** [copy a] creates a fresh array with the same elements as [a]. *) + val sub : 'a t -> pos:int -> length:int -> 'a t + (** [sub a ~pos ~length] creates a fresh array of length [length] containing + the elements [a.(pos)] to [a.(pos + length - 1)] of [a]. + + Raise [Invalid_argument "CArray.sub"] if [pos] and [length] do not + designate a valid subarray of [a]. *) + val element_type : 'a t -> 'a typ (** Retrieve the element type of an array. *) end diff --git a/src/ctypes/ctypes_memory.ml b/src/ctypes/ctypes_memory.ml index b6a39e9f..6c27e294 100644 --- a/src/ctypes/ctypes_memory.ml +++ b/src/ctypes/ctypes_memory.ml @@ -207,6 +207,11 @@ struct from_ptr r alength end + let sub arr ~pos ~length:len = + if pos < 0 || len < 0 || pos > length arr - len + then invalid_arg "CArray.sub" + else copy { astart = arr.astart +@ pos; alength = len } + let element_type { astart } = reference_type astart let of_list typ list = diff --git a/tests/test-arrays/test_array.ml b/tests/test-arrays/test_array.ml index 5a1339b3..0eccd296 100644 --- a/tests/test-arrays/test_array.ml +++ b/tests/test-arrays/test_array.ml @@ -178,6 +178,39 @@ let test_copy _ = end +(* + Test the CArray.sub function + *) +let test_sub _ = + let a = CArray.of_list int [1; 2; 3] in + + assert_raises (Invalid_argument "CArray.sub") begin fun () -> + CArray.sub a ~pos:(-1) ~length:1 + end; + + assert_raises (Invalid_argument "CArray.sub") begin fun () -> + CArray.sub a ~pos:1 ~length:4 + end; + + assert_raises (Invalid_argument "CArray.sub") begin fun () -> + CArray.sub a ~pos:1 ~length:(-1) + end; + + let r = CArray.sub a ~pos:1 ~length:2 in + assert_equal [2; 3] (CArray.to_list r); + + let r = CArray.sub a ~pos:1 ~length:0 in + assert_equal [] (CArray.to_list r); + + let a = CArray.of_list int [1; 2; 3] in + let r = CArray.sub a ~pos:1 ~length:2 in + begin + CArray.set r 0 10; + assert_equal [1; 2; 3] (CArray.to_list a); + assert_equal [10; 3] (CArray.to_list r); + end + + (* Test that creating an array initializes all elements appropriately. *) @@ -307,6 +340,9 @@ let suite = "Array tests" >::: "CArray.copy" >:: test_copy; + "CArray.sub" + >:: test_sub; + "array initialization" >:: test_array_initialiation;