Skip to content

Commit 83b806e

Browse files
committed
ocaml/libs: List.last and List.head now return options
Previously an exception was raised for last, head is a new function. Also adds a latest_release to datamodel_types that can't fail after the module has been loaded. (the list is populated so it won't fail when the module is loaded either) Signed-off-by: Pau Ruiz Safont <[email protected]>
1 parent 9ed1579 commit 83b806e

File tree

6 files changed

+18
-29
lines changed

6 files changed

+18
-29
lines changed

ocaml/idl/datamodel_types.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,9 @@ let release_order_full =
359359
let release_order =
360360
List.filter (fun x -> x.code_name <> None) release_order_full
361361

362+
let latest_release =
363+
Xapi_stdext_std.Listext.List.last release_order |> Option.get
364+
362365
exception Unknown_release of string
363366

364367
exception UnspecifiedRelease

ocaml/idl/datamodel_types.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ val release_order_full : api_release list
8080

8181
val release_order : api_release list
8282

83+
val latest_release : api_release
84+
8385
exception Unknown_release of string
8486

8587
exception UnspecifiedRelease

ocaml/idl/dm_api.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ let check api emergency_calls =
369369
let are_in_vsn_order ps =
370370
let release_lt x y = release_leq x y && x <> y in
371371
let in_since releases =
372+
let last = code_name_of_release latest_release in
372373
(* been in since the lowest of releases *)
373374
List.fold_left
374375
(fun sofar r ->
@@ -378,8 +379,7 @@ let check api emergency_calls =
378379
| r ->
379380
if release_lt r sofar then r else sofar
380381
)
381-
(Xapi_stdext_std.Listext.List.last release_order |> code_name_of_release)
382-
releases
382+
last releases
383383
in
384384
let rec check_vsns max_release_sofar ps =
385385
match ps with

ocaml/libs/xapi-stdext/lib/xapi-stdext-std/listext.ml

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,9 @@ module List = struct
7575
in
7676
loop 0 list
7777

78-
let rec last = function
79-
| [] ->
80-
invalid_arg "last: empty list"
81-
| [x] ->
82-
x
83-
| _ :: xs ->
84-
last xs
78+
let head = function [] -> None | x :: _ -> Some x
79+
80+
let rec last = function [] -> None | [x] -> Some x | _ :: xs -> last xs
8581

8682
let split_at n list =
8783
let rec loop i acc = function

ocaml/libs/xapi-stdext/lib/xapi-stdext-std/listext.mli

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ module List : sig
3333
element being the rest of elements of the list (or [] if the list is
3434
shorter). The results with negative values of [n] are the same as using 0. *)
3535

36-
val last : 'a list -> 'a
37-
(** [last l] returns the last element of a list or raise Invalid_argument if
38-
the list is empty *)
36+
val head : 'a list -> 'a option
37+
(** [head l] returns the first element of [lst] or None if [lst] is empty *)
38+
39+
val last : 'a list -> 'a option
40+
(** [last lst] returns the last element of [lst] or None if [lst] is empty *)
3941

4042
val rev_mapi : (int -> 'a -> 'b) -> 'a list -> 'b list
4143
(** [rev_map f l] gives the same result as {!Stdlib.List.rev}[ (]

ocaml/libs/xapi-stdext/lib/xapi-stdext-std/listext_test.ml

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
module Listext = Xapi_stdext_std.Listext.List
1515

1616
let test_last_list tested_f (name, case, expected) =
17-
let check () = Alcotest.(check @@ int) name expected (tested_f case) in
17+
let check () = Alcotest.(check @@ option int) name expected (tested_f case) in
1818
(name, `Quick, check)
1919

2020
let test_list tested_f (name, case, expected) =
@@ -31,10 +31,6 @@ let test_split_at_list tested_f (name, case, expected) =
3131
in
3232
(name, `Quick, check)
3333

34-
let test_error tested_f (name, case, expected) =
35-
let check () = Alcotest.check_raises name expected (tested_f case) in
36-
(name, `Quick, check)
37-
3834
let test_iteri_right =
3935
let specs =
4036
[
@@ -114,8 +110,7 @@ let test_drop =
114110
("drop", tests)
115111

116112
let test_last =
117-
let specs = [([1], 0, 1); ([1; 2; 3], 1, 3)] in
118-
let error_specs = [([], -1, Invalid_argument "last: empty list")] in
113+
let specs = [([1], 0, Some 1); ([1; 2; 3], 1, Some 3); ([], -1, None)] in
119114
let test_good (whole, number, expected) =
120115
let name =
121116
Printf.sprintf "get last %i from [%s]" number
@@ -124,16 +119,7 @@ let test_last =
124119
test_last_list Listext.last (name, whole, expected)
125120
in
126121
let tests = List.map test_good specs in
127-
let error_test (whole, number, error) =
128-
let name =
129-
Printf.sprintf "last [%s] with %i fails"
130-
(String.concat "; " (List.map string_of_int whole))
131-
number
132-
in
133-
test_error (fun ls () -> ignore (Listext.last ls)) (name, whole, error)
134-
in
135-
let error_tests = List.map error_test error_specs in
136-
("last", tests @ error_tests)
122+
("last", tests)
137123

138124
let test_split_at =
139125
let specs =

0 commit comments

Comments
 (0)