generate_uuid Function

public function generate_uuid(version) result(uuid)

NAME

generate_uuid(3f) - [M_uuid] generate a UUID (Universally Unique IDentifier) string per RFC 4122
(LICENSE:BSD-4-Clause)

SYNOPSIS

function generate_uuid(version) result(uuid)

 integer, intent(in), optional :: version
 character(len=36) :: uuid

DESCRIPTION

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.

AUTHORS

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>).

OPTIONS

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

EXAMPLE

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

Arguments

Type IntentOptional Attributes Name
integer, intent(in), optional :: version

Return Value character(len=36)


Contents

Source Code


Source Code

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