anchor.diff:    (:use :cl)
     (:export :oid
              :oid-str
  -           :hex-conversion-error
              :get-timestamp
              :get-hostname
              :get-pid
  
positive.code:     ((vectorp id) id)
      ((null id)    (create-new-id))))
  
  (defun oid-str (oid &key downcase)
    "Given a vector ID, convert it to a string."
    (declare (optimize (speed 3) (safety 1))
             (type vector oid))
    (let ((str ""))
      (loop for byte across oid do
        (setf str (concatenate 'string str (format nil "~2,'0X" byte))))
      (if downcase
          (string-downcase str)
          str)))
  
  (defun get-timestamp (oid &key bytes)
    "Grab the timestamp out of a vector oid."
    (let ((timestamp (subseq oid 0 4)))
      (if bytes
          timestamp
          (convert-vector-int timestamp))))
  
  (defun get-hostname (oid &key bytes)
    "Grab the hostname int out of a vector oid."
    (let ((host (subseq oid 4 7)))
      (if bytes
          host
          (convert-vector-int host))))
  
  (defun get-pid (oid &key bytes)
    "Grab the pid out of a vector oid."
    (let ((pid (subseq oid 7 9)))
      (if bytes
          pid
          (convert-vector-int pid))))
  
  (defun get-inc (oid &key bytes)
    "Grab the inc value out of a vector oid."
    (let ((inc (subseq oid 9)))
      (if bytes
          inc
          (convert-vector-int inc))))
  
  (define-condition hex-conversion-error (error) ((str :initarg :str :reader hex-conversion-error-str))
    (:report (lambda (c s)
               (format s "Conversion of hex string to byte array failed: ~a" (hex-conversion-error-str c)))))
  
  (defun convert-hex-vector (str)
    "Takes a hex string, IE 4f2b8096 and converts it into a byte array:
        4f2b8096 -> #(79 43 128 150)
    Hex string *must* have even number of bytes."
    (declare (optimize (speed 3) (safety 1))
             (type string str))
    (when (oddp (length str))
      (error 'hex-conversion-error :str (format nil "Odd-length string given in hex conversion: ~a" str)))
    (let ((vec (make-array 0 :fill-pointer t :adjustable t)))
      (loop for i from 0 to (1- (/ (length str) 2)) do
        (vector-push-extend (read-from-string (format nil "#x~a" (subseq str (* 2 i) (* 2 (1+ i)))) :base 10) vec))
      vec))
  
  (defun convert-vector-int (vec)
    "Convert a byte array to an integer:
        #(79 150 243 81) -> 1335292753"
    (declare (optimize (speed 3) (safety 1))
             (type vector vec))
    (let ((str "#x"))
      (loop for byte across vec do
        (setf str (concatenate 'string str (format nil "~2,'0x" byte))))
      (car (multiple-value-list (read-from-string str :base 10)))))
  
  (defun create-new-id ()
    "Create a brand-spankin-new ObjectId using the current timestamp/inc values,
    along with hostname and process pid."
    (declare (optimize (speed 3) (safety 1)))
    (let ((hostname (get-current-hostname))
          (pid (logand #xFFFF (get-current-pid)))
          (timestamp (logand #xFFFFFFFF (get-current-timestamp)))
  
negative.code:   #+(and cmu unix)
    (unix:unix-getpid)
    #+openmcl
    (ccl::getpid)
    #-(or clisp (and lispworks unix) (and sbcl unix) (and cmu unix) (and openmcl unix) openmcl)
    if-not-exists-return)
  
  