generate_uuid(3f) - [M_uuid] generate a UUID (Universally Unique IDentifier) string per RFC 4122
(LICENSE:BSD-4-Clause)
function generate_uuid(version) result(uuid)
integer, intent(in), optional :: version
character(len=36) :: uuid
A universally unique identifier (UUID) is a 128-bit number used to
identify information in computer systems. When generated according
to standard methods UUIDs are for practical purposes unique.
generate_uuid(3f) converts the UUID to a standard string format
per RFC 4122.
based on previous work from Alberto Garcia & Jon Wakelin, 2003-2004.
RNG routines from Scott Ladd <scott.ladd@coyotegulch.com>, and
the libFoX library( Toby White <tow@uszla.me.uk>, Gen-Tao Chiang
<gtc25@cam.ac.uk>, Andrew Walker <a.walker@ucl.ac.uk>).
version Indicates which standard method as described in RFC 4122
is used to generate the string. Versions 0,1, and 4 are supported.
0. Nil UUID (ie. '00000000-0000-0000-0000-000000000000')
1. time-based UUID
2. Not implemented
3. Not implemented
4. pseudo-RNG(Random Number Generator) based
5. Not implemented
Sample usage:
program demo_generate_uuid
use M_uuid, only : generate_uuid
implicit none
character(len=36) :: uuid
!
uuid=generate_uuid(1) ! version 1 (time-based UUID)
write(*,'(a36)')uuid
!
uuid=generate_uuid(4) ! version 4 (pseudo-RNG-based), default
!
! RFC 4122 defines a Uniform Resource Name (URN) namespace for UUIDs.
write(*,'("urn:uuid:",a36)')uuid
!
! a good scratch file name
open(file='/tmp/scratch_'//uuid,unit=10)
!
end program demo_generate_uuid
Typical output:
e769adf4-4af7-11e8-7421-3c9dfbfe9aab
urn:uuid:5b0946b8-0eb4-4966-619d-047b7f7e2056
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
integer, | intent(in), | optional | :: | version |
function generate_uuid(version) result(uuid)
! ident_2="@(#) M_uuid generate_uuid(3f) generate(approximately) a UUID (Universally Unique IDentifier) string per RFC 4122"
integer, intent(in), optional :: version
character(len=36) :: uuid
integer(kind=i8b) :: timestamp, node
integer(kind=i4b) :: clock_sequence
integer(kind=i4b) :: time_low, time_mid, time_hi_and_version
integer(kind=i4b) :: clk_seq_hi_res, clk_seq_low
integer :: values(8) ! must be default for date_and_time
integer(kind=i4b) :: variant, v
if (.not.initialized) then
! Use the current date and time to init mtprng but this gives limited variability, so mix the result up.
! Can we do better? In any case, this gets passed through a quick generator inside mtprng_init.
call date_and_time(values=values)
values(7) = values(7)*1000+values(5)*100+values(3)*10+values(1)
values(8) = values(2)*1000+values(4)*100+values(6)*10+values(8)
call mtprng_init(int(values(7)*10000+values(8), i4b), rng_state)
clock_seq = int(mtprng_rand64(rng_state), i4b)
initialized = .true.
endif
variant = 1
if (present(version)) then
v = version
else
v = 4
endif
select case (v)
case (0)
uuid='00000000-0000-0000-0000-000000000000' ! Nil UUID
return
case(1) ! version 1(time-based)
call date_and_time(values=values)
! In case of too-frequent requests, we will replace time_low with the count below ...
if (all(values==values_save)) then
hires_count = hires_count + 1
else
hires_count = 0
endif
timestamp = get_utc_since_1582(values)
clock_sequence = clock_seq ! clock sequence (14 bits)
node = ior(mtprng_rand64(rng_state), ishft(mtprng_rand64(rng_state), 16)) ! node ( 48 bits)
! No MAC address accessible - see section 4.5 !FIXME
case(2-3,5) ! Unimplemented
uuid = ''
return
case(4) ! version 4 (pseudo-RNG-based)
timestamp = ior(mtprng_rand64(rng_state), ishft(mtprng_rand64(rng_state), 28))
clock_sequence = int(mtprng_rand64(rng_state), i4b) ! clock sequence (14 bits)
node = ior(mtprng_rand64(rng_state), ishft(mtprng_rand64(rng_state), 16)) ! node ( 48 bits)
case default ! Unspecified
uuid = ''
return
end select
time_low = ibits(timestamp, 0, 32)
time_mid = ibits(timestamp, 32, 16)
if (hires_count==0) then
time_hi_and_version = ior(int(ibits(timestamp, 48, 12), i4b), ishft(v, 12))
else
time_hi_and_version = ior(hires_count, ishft(v, 12))
endif
clk_seq_low = ibits(clock_sequence, 0, 8)
clk_seq_hi_res = ior(ibits(clock_sequence, 8, 6), ishft(variant, 6))
uuid = int32ToHexOctets(time_low, 4)//"-"// &
int32ToHexOctets(time_mid, 2)//"-"// &
int32ToHexOctets(time_hi_and_version, 2)//"-"// &
int32ToHexOctets(clk_seq_hi_res, 1)// &
int32ToHexOctets(clk_seq_low, 1)//"-"// &
int64ToHexOctets(node, 6)
contains
!==================================================================================================================================!
function int32ToHexOctets(b, n) result(s)
integer(i4b), intent(in) :: b
integer, intent(in) :: n ! number of octets to print
character(len=2*n) :: s
character, parameter :: hexdigits(0:15) = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
integer :: i
do i = 0, 2*n-1
s(2*n-i:2*n-i) = hexdigits(ibits(b, i*4, 4))
enddo
end function int32ToHexOctets
!==================================================================================================================================!
function int64ToHexOctets(b, n) result(s)
integer(i8b), intent(in) :: b
integer, intent(in) :: n ! number of octets to print
character(len=2*n) :: s
character, parameter :: hexdigits(0:15) = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
integer :: i
do i = 0, 2*n-1
s(2*n-i:2*n-i) = hexdigits(ibits(b, i*4, 4))
enddo
end function int64ToHexOctets
!==================================================================================================================================!
end function generate_uuid