This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,5 @@
_build/
*.native
*.byte
*.install
.merlin

View file

@ -0,0 +1,20 @@
language: c
install: wget https://raw.githubusercontent.com/ocaml/ocaml-ci-scripts/master/.travis-docker.sh
script: bash -ex .travis-docker.sh
sudo: false
services:
- docker
env:
global:
- DISTRO=alpine
- TESTS=true
- PACKAGE="duration"
matrix:
- OCAML_VERSION=4.09
- OCAML_VERSION=4.08
- OCAML_VERSION=4.07
- OCAML_VERSION=4.06
- OCAML_VERSION=4.05
- OCAML_VERSION=4.04
notifications:
email: false

View file

@ -0,0 +1,28 @@
## v0.2.1 (2022-10-11)
* Duration.pp: microseconds suffix is now "μs" instead of "us" (#8 by @MisterDA)
## 0.2.0 (2021-08-04)
* 32 bit compatibility:
* Provide of_us_64, of_ms_64, of_sec_64 that take an int64 as input
* Provide to_us_64, to_ms_64, to_sec_64 that produce an int64 as output
* Revise Duration.pp to print in a more concise way
## 0.1.3 (2019-10-26)
* Duration.pp: don't emit trailing space
## 0.1.2 (2019-02-16)
* move build system to dune
## 0.1.1 (2017-11-18)
* test 4.05 and 4.06
* alcotest 0.8.1 compatibility (#2 by @yomimono)
* Don't ship with -warn-error +A, but use it in `./build`
## 0.1.0 (2016-07-28)
* initial

View file

@ -0,0 +1,16 @@
(*
* Copyright (c) 2016 Hannes Mehnert <hannes@mehnert.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*)

View file

@ -0,0 +1,13 @@
## Duration - conversions to various time units
v0.2.1
A duration is represented in nanoseconds as an unsigned 64 bit integer. This
has a range of up to 584 years. Functions provided check the input and raise
on negative or out of bound input.
## Documentation
[![Build Status](https://travis-ci.org/hannesm/duration.svg?branch=master)](https://travis-ci.org/hannesm/duration)
[API Documentation](https://hannesm.github.io/duration/doc/) is available online.

View file

@ -0,0 +1,9 @@
(library
(name duration)
(public_name duration)
(modules duration))
(test
(name tests)
(modules tests)
(libraries alcotest duration))

View file

@ -0,0 +1,3 @@
(lang dune 1.0)
(name duration)
(version v0.2.1)

View file

@ -0,0 +1,159 @@
type t = int64
let of_us_64 m =
if m < 0L then
invalid_arg "negative" ;
if Int64.compare m 0x4189374BC6A7EDL = 1 then
invalid_arg "out of range" ;
Int64.mul 1_000L m
let of_us m = of_us_64 (Int64.of_int m)
let of_ms_64 m =
if m < 0L then
invalid_arg "negative" ;
if Int64.compare m 0x10C6F7A0B5EDL = 1 then
invalid_arg "out of range" ;
Int64.mul 1_000_000L m
let of_ms m = of_ms_64 (Int64.of_int m)
let of_sec_64 s =
if s < 0L then
invalid_arg "negative" ;
if Int64.compare s 0x44B82FA09L = 1 then
invalid_arg "out of range" ;
Int64.mul 1_000_000_000L s
let of_sec m = of_sec_64 (Int64.of_int m)
let of_min m =
if m < 0 then
invalid_arg "negative" ;
let m = Int64.of_int m in
if Int64.compare m 0x12533FE6L = 1 then
invalid_arg "out of range" ;
Int64.mul 60_000_000_000L m
let hour = 3600_000_000_000L
let of_hour h =
if h < 0 then
invalid_arg "negative" ;
let h = Int64.of_int h in
if Int64.compare h 0x4E2FFFL = 1 then
invalid_arg "out of range" ;
Int64.mul hour h
let day = Int64.mul 24L hour
let of_day d =
if d < 0 then
invalid_arg "negative" ;
let d = Int64.of_int d in
if Int64.compare d 0x341FFL = 1 then
invalid_arg "out of range" ;
Int64.mul day d
let year = Int64.mul 8766L hour
let of_year y =
if y < 0 then
invalid_arg "negative" ;
let y = Int64.of_int y in
if Int64.compare y 0x248L = 1 then
invalid_arg "out of range" ;
Int64.mul year y
let of_f f =
if f < 0. then
invalid_arg "negative" ;
if f > 18446744073.709549 then
invalid_arg "out of range" ;
let s = Int64.of_float f in
let rem = f -. (Int64.to_float s) in
let ns = Int64.of_float (rem *. 1_000_000_000.) in
Int64.(add (mul 1_000_000_000L s) ns)
let to_f t =
let pl =
if t >= 0L then
0.
else
abs_float (2. *. (Int64.to_float 0x8000000000000000L))
in
let ns = Int64.to_float t in
(ns +. pl) /. 1_000_000_000.
let to_int64 t d =
let f c = Int64.div c d in
if t < 0L then
Int64.(add (f (Int64.add t Int64.min_int)) (add (f Int64.max_int) 1L))
else
f t
let to_int t d =
let r = to_int64 t d in
if r > Int64.of_int max_int then
invalid_arg "value too big for this platform" ;
Int64.to_int r
let to_us_64 t = to_int64 t 1_000L
let to_us t = to_int t 1_000L
let to_ms_64 t = to_int64 t 1_000_000L
let to_ms t = to_int t 1_000_000L
let to_sec_64 t = to_int64 t 1_000_000_000L
let to_sec t = to_int t 1_000_000_000L
let to_min t = to_int t 60_000_000_000L
let to_hour t = to_int t hour
let to_day t = to_int t day
let to_year t = to_int t year
let fields t =
let sec = to_sec_64 t in
let left = Int64.sub t (of_sec_64 sec) in
let ms = to_ms_64 left in
let left = Int64.sub left (of_ms_64 ms) in
let us = to_us_64 left in
let ns = Int64.(sub left (of_us_64 us)) in
(sec, ms, us, ns)
let pp ppf t =
let min = to_min t in
if min > 0 then
let y = to_year t in
let left = Int64.rem t year in
let d = to_day left in
let left = Int64.rem left day in
if y > 0 then
Format.fprintf ppf "%da%dd" y d
else
let h = to_hour left in
let left = Int64.rem left hour in
if d > 0 then
Format.fprintf ppf "%dd%02dh" d h
else
let min = to_min left in
let left = Int64.sub t (of_min min) in
let sec = to_sec left in
if h > 0 then
Format.fprintf ppf "%dh%02dm" h min
else (* if m > 0 then *)
Format.fprintf ppf "%dm%02ds" min sec
else (* below one minute *)
let s, ms, us, ns = fields t in
if s > 0L then
Format.fprintf ppf "%Ld.%03Lds" s ms
else if ms > 0L then
Format.fprintf ppf "%Ld.%03Ldms" ms us
else (* if us > 0 then *)
Format.fprintf ppf "%Ld.%03Ldμs" us ns

View file

@ -0,0 +1,86 @@
(** Duration - conversions to various time units
A duration is represented in nanoseconds as an unsigned 64 bit integer.
This has a range of up to 584 years, or 213503 days, or 5124095 hours, or
307445734 minutes, or 18446744073 seconds, or 18446744073709 milliseconds,
or 18446744073709549 microseconds.
All functions converting to [t] raise [Invalid_argument] on out of bound
or negative input.
{e v0.2.1 - {{:https://github.com/hannesm/duration }homepage}}
*)
(** The type for a duration, exposed as an int64 to provide interoperability. *)
type t = int64
(** [pp ppf t] prints the duration in a concise way. *)
val pp : Format.formatter -> t -> unit
(** [of_us us] are the microseconds in nanoseconds. *)
val of_us : int -> t
(** [of_us_64 us] are the microseconds in nanoseconds. *)
val of_us_64 : int64 -> t
(** [of_ms ms] are the milliseconds in nanoseconds. *)
val of_ms : int -> t
(** [of_ms_64 ms] are the milliseconds in nanoseconds. *)
val of_ms_64 : int64 -> t
(** [of_sec s] are the seconds in nanoseconds. *)
val of_sec : int -> t
(** [of_sec_64 s] are the seconds in nanoseconds. *)
val of_sec_64 : int64 -> t
(** [of_min m] are the minutes in nanoseconds. *)
val of_min : int -> t
(** [of_hour h] are the hours in nanoseconds. *)
val of_hour : int -> t
(** [of_day d] are the days in nanoseconds. *)
val of_day : int -> t
(** [of_year y] are the years in nanoseconds. *)
val of_year : int -> t
(** [of_f f] is the floating point seconds in nanoseconds. *)
val of_f : float -> t
(** [to_us t] are the microseconds of [t]. *)
val to_us : t -> int
(** [to_us_64 t] are the microseconds of [t]. *)
val to_us_64 : t -> int64
(** [to_ms t] are the milliseconds of [t]. *)
val to_ms : t -> int
(** [to_ms_64 t] are the milliseconds of [t]. *)
val to_ms_64 : t -> int64
(** [to_sec t] are the seconds of [t]. *)
val to_sec : t -> int
(** [to_sec_64 t] are the seconds of [t]. *)
val to_sec_64 : t -> int64
(** [to_min t] are the minutes of [t]. *)
val to_min : t -> int
(** [to_hour t] are the hours of [t]. *)
val to_hour : t -> int
(** [to_day t] are the days of [t]. *)
val to_day : t -> int
(** [to_year t] are the years of [t]. *)
val to_year : t -> int
(** [to_f t] is the floating point representation of [t]. *)
val to_f : t -> float

View file

@ -0,0 +1,25 @@
version: "0.2.1"
opam-version: "2.0"
maintainer: "Hannes Mehnert <hannes@mehnert.org>"
authors: "Hannes Mehnert <hannes@mehnert.org>"
license: "ISC"
homepage: "https://github.com/hannesm/duration"
doc: "https://hannesm.github.io/duration/doc"
bug-reports: "https://github.com/hannesm/duration/issues"
depends: [
"ocaml" {>= "4.04.2"}
"dune" {>= "1.0"}
"alcotest" {with-test & >= "0.8.1"}
]
build: [
["dune" "subst"] {dev}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
dev-repo: "git+https://github.com/hannesm/duration.git"
synopsis: "Conversions to various time units"
description: """
A duration is represented in nanoseconds as an unsigned 64 bit integer. This
has a range of up to 584 years. Functions provided check the input and raise
on negative or out of bound input.
"""

View file

@ -0,0 +1,162 @@
open Duration
let test_f f s factor upper upperv () =
List.iter (fun v ->
Alcotest.(check int64 (s ^ " works" ^ string_of_int v)
Int64.(mul (of_int v) factor)
(f v)))
[ 0 ; 1 ; 100 ] ;
Alcotest.(check_raises (s ^ " raises") (Invalid_argument "negative")
(fun () -> ignore (f (-1)))) ;
Alcotest.(check int64 ("upper bound " ^ s ^ " good")
upperv (f upper)) ;
Alcotest.(check_raises ("upper bound + 1 " ^ s ^ " raises")
(Invalid_argument "out of range")
(fun () -> ignore (f (succ upper))))
let test_g g s factor upper upperv () =
List.iter (fun (e, v) ->
Alcotest.(check int (s ^ " works " ^ Int64.to_string v)
e (g v)))
[ 0, 0L ; 1, factor ] ;
Alcotest.(check int ("upper bound " ^ s ^ " good")
upper (g upperv))
let test_inv f g s upper () =
Alcotest.(check int ("inverse 0 " ^ s) 0 (g (f 0))) ;
Alcotest.(check int ("inverse 1 " ^ s) 1 (g (f 1))) ;
Alcotest.(check int ("inverse 10 " ^ s) 10 (g (f 10))) ;
Alcotest.(check int "inverse upper" upper (g (f upper)))
let test_one f g s fa m mv = [
"of" ^ s ^ " is good", `Quick, test_f f ("of" ^ s) fa m mv ;
"to" ^ s ^ " is good", `Quick, test_g g ("to" ^ s) fa m mv ;
"inverse of/to" ^ s, `Quick, test_inv f g s m
]
let test_f_64 f s factor upper upperv () =
List.iter (fun v ->
Alcotest.(check int64 (s ^ " works" ^ Int64.to_string v)
Int64.(mul v factor)
(f v)))
[ 0L ; 1L ; 100L ] ;
Alcotest.(check_raises (s ^ " raises") (Invalid_argument "negative")
(fun () -> ignore (f (-1L)))) ;
Alcotest.(check int64 ("upper bound " ^ s ^ " good")
upperv (f upper)) ;
Alcotest.(check_raises ("upper bound + 1 " ^ s ^ " raises")
(Invalid_argument "out of range")
(fun () -> ignore (f (Int64.succ upper))))
let test_g_64 g s factor upper upperv () =
List.iter (fun (e, v) ->
Alcotest.(check int64 (s ^ " works " ^ Int64.to_string v)
e (g v)))
[ 0L, 0L ; 1L, factor ] ;
Alcotest.(check int64 ("upper bound " ^ s ^ " good")
upper (g upperv))
let test_inv_64 f g s upper () =
Alcotest.(check int64 ("inverse 0 " ^ s) 0L (g (f 0L))) ;
Alcotest.(check int64 ("inverse 1 " ^ s) 1L (g (f 1L))) ;
Alcotest.(check int64 ("inverse 10 " ^ s) 10L (g (f 10L))) ;
Alcotest.(check int64 "inverse upper" upper (g (f upper)))
let test_one_64 f g s fa m mv = [
"of" ^ s ^ " is good", `Quick, test_f_64 f ("of" ^ s) fa m mv ;
"to" ^ s ^ " is good", `Quick, test_g_64 g ("to" ^ s) fa m mv ;
"inverse of/to" ^ s, `Quick, test_inv_64 f g s m
]
let test_of_us =
let a, b = 18446744073709549L, 0xFFFFFFFFFFFFF5C8L in
test_one_64 of_us_64 to_us_64 "_us" 1_000L a b @
if Sys.word_size = 64 then
test_one of_us to_us "_us" 1_000L (Int64.to_int a) b
else
[]
let test_of_ms =
let a, b = 18446744073709L, 0xFFFFFFFFFFF79540L in
test_one_64 of_ms_64 to_ms_64 "_ms" 1_000_000L a b @
if Sys.word_size = 64 then
test_one of_ms to_ms "_ms" 1_000_000L (Int64.to_int a) b
else
[]
let test_of_sec =
let a, b = 18446744073L, 0xFFFFFFFFD5B51A00L in
test_one_64 of_sec_64 to_sec_64 "_sec" 1_000_000_000L a b @
if Sys.word_size = 64 then
test_one of_sec to_sec "_sec" 1_000_000_000L (Int64.to_int a) b
else
[]
let test_of_min =
test_one of_min to_min "_min" 60_000_000_000L 307445734 0xFFFFFFF826C11000L
let test_of_hour =
test_one of_hour to_hour "_hour" 3600_000_000_000L 5124095 0xFFFFFE1D2D476000L
let test_of_day =
let d_in_ns = Int64.mul 24L 3600_000_000_000L in
test_one of_day to_day "_day" d_in_ns 213503 0xFFFFB2CECCB10000L
let test_of_year =
let y_in_ns = Int64.mul 8766L 3600_000_000_000L in
test_one of_year to_year "_year" y_in_ns 584 0xFFC33A7AFAE60000L
let test_of_f () =
List.iter (fun v ->
Alcotest.(check int64 ("of_f works " ^ string_of_float v)
(Int64.of_float (v *. 1_000_000_000.))
(of_f v)))
[ 0. ; 1. ; 2. ; 0.000000001 ] ;
Alcotest.(check_raises ("of_f raises") (Invalid_argument "negative")
(fun () -> ignore (of_f (-1.)))) ;
Alcotest.(check int64 ("upper bound of_f good")
0xFFFFFFFFFFFFF596L (of_f 18446744073.709549)) ;
Alcotest.(check_raises ("upper bound + 1 of_f raises")
(Invalid_argument "out of range")
(fun () -> ignore (of_f 18446744073.709551)))
let test_to_f () =
List.iter (fun (e, v) ->
Alcotest.(check (float 0.) ("to_f works " ^ Int64.to_string v)
e (to_f v)))
[ 0., 0L ; 1., 1000000000L ; 2., 2000000000L ; 0.000000001, 1L ] ;
Alcotest.(check (float 0.) ("upper bound to_f good")
18446744073.709549 (to_f 0xFFFFFFFFFFFFF596L))
let test_inv_f () =
Alcotest.(check (float 0.) "inverse 0 to/of_f" 0. (to_f (of_f 0.))) ;
Alcotest.(check (float 0.) "inverse 1 to/of_f" 1. (to_f (of_f 1.))) ;
Alcotest.(check (float 0.) "inverse 10 to/of_f" 10. (to_f (of_f 10.))) ;
Alcotest.(check (float 0.) "inverse 3.5 to/of_f" 3.5 (to_f (of_f 3.5))) ;
Alcotest.(check (float 0.) "inverse upper" 18446744073.709549 (to_f (of_f 18446744073.709549)))
let test_float = [
"of_f is good", `Quick, test_of_f ;
"to_f is good", `Quick, test_to_f ;
"inverse of/to_f", `Quick, test_inv_f
]
let dur_tests =
List.flatten [
test_of_us ;
test_of_ms ;
test_of_sec ;
test_of_min ;
test_of_hour ;
test_of_day ;
test_of_year ;
test_float
]
let tests = [
"Duration", dur_tests
]
let () = Alcotest.run "Duration tests" tests