cmunique_id.pro 3.37 KB
;+
; NAME:
;   CMUNIQUE_ID
;
; AUTHOR:
;   Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
;   craigm@lheamail.gsfc.nasa.gov
;
; PURPOSE:
;   Return a unique ID string
;
; CALLING SEQUENCE:
;   ID = CMUNIQUE_ID([STRINGVAL])
;
; DESCRIPTION: 
;
;   CMUNIQUE_ID returns a "unique" 8 character identifier.
;   Programmers can use this routine to derive unique strings which
;   can be used to write files, etc.
;
;   Identifiers are "unique" in the sense that it is unlikely that two
;   identifiers in a given IDL session will coincide.  Thus the
;   identifier is useful for constructing temporary filenames and
;   other hash values.  User routines are encouraged to append other
;   identifying information to this string, such as a session id, a
;   hostname, or a process id number.
;
;   The identifier is computed from various sources of random
;   information.  Users may supply additional information to be
;   scrambled into the identifier by passing the FODDER parameter.
;   CMUNIQUE_ID will return a different identifier upon each call,
;   with or without the FODDER keyword.  It maintains an internal
;   sequence counter, and and also scrambles in the system time.
;   These practices should ensure that successive identifiers are
;   different from one another.
;
; INPUTS:
;
;   FODDER - Any scalar string value.  These values are used to
;            additionally scramble the identifier.
;
; KEYWORDS:
;
;   NONE
;
; RETURNS:
;   The 8-character identifier string.
;
; EXAMPLE:
;   
;   Print two distinct identifiers.
;     IDL> print, cmunique_id(), ' ', cmunique_id()
;     29C47600 79061C57
;
; SEE ALSO:
;
;   NONE
;
; MODIFICATION HISTORY:
;   Written, CM, 11 Jan 2001
;
; $Id: cmunique_id.pro,v 1.2 2001/01/13 04:08:30 craigm Exp $
;
;-
; Copyright (C) 2001, Craig Markwardt
; This software is provided as is without any warranty whatsoever.
; Permission to use, copy, modify, and distribute modified or
; unmodified copies is granted, provided this copyright and disclaimer
; are included unchanged.
;-
function cmunique_id, fodder

  ;; Store persistent information in a common block, including the
  ;; random number seed
  COMMON CMUNIQUE_ID_COMMON, RANDOM_SEED, SEQ_COUNTER
  IF N_ELEMENTS(RANDOM_SEED) EQ 0 THEN BEGIN
      RANDOM_VAL  = LONG(SYSTIME(1))
      RR          = RANDOM_VAL
      RANDOM_SEED = LONG(RANDOMU(RR)*DOUBLE(ISHFT(1L,31)))
      RANDOM_SEED = RR
      SEQ_COUNTER = 0L
  ENDIF

  ;; Mix up a few random numbers.  The low-bit behavior of IDL's
  ;; random number generator seems pretty poor.
  rr = random_seed
  hash1 = long(randomu(rr)*double(ishft(1L,31)))
  hash2 = long(randomu(rr)*double(ishft(1L,31)))
  hash = hash1 XOR (ishft(hash2,-16) OR ishft(hash2,+16))
  random_seed = rr

  ;; Include the fodder, which is any unique identifying text string
  if n_elements(fodder) GT 0 then begin
      b = byte(fodder(0))
      n = n_elements(b)
      for i = 0L, n-1 do hash = ishft(hash,2) XOR b(i)
  endif

  ;; Finally add some other entropy terms like the time, and a unique
  ;; counter.  For safety, add these at different bit zones in the
  ;; output hash so they don't overlap (since time and the sequence
  ;; counter are both monotonically increasing, they could counteract
  ;; each other).
  hash = hash XOR long(systime(1)) XOR ishft(SEQ_COUNTER,16)
  seq_counter = seq_counter+1

  ;; Return a hex-string of this hash value
  return, string(abs(hash), format='(Z8.8)')
end