So, much of the pain involved in handling UUID's correctly on the JVM
relates to the fact that there is no primitive unsigned numeric type
that can represent the full range of possible values of the msb and lsb.
Ie., we need to always deal with the unpleasant "am I negative?" approach to
reading (writing) that 64th bit.  To avoid the complexity of all the 
edge cases, we encapsulate the basic primitives of working with
unsigned numbers entirely within the abstraction of "mask" and
"mask offset".  Using these, we built the two fundamental bitwise operations
that are used for most of the UUID calculation: ldb (load-byte) and
dpb (deposit-byte).

This scrap of code from my clj-uuid.bitmop library is extremely useful for 
working 
with "unsigned" long/binary values (analogously to how one might using the 
common-lisp
functions by the same name).  And, it has been "good enough" to do pretty 
well
so far in terms of performance.  But I'm sure that there are gifted 
binariticians
in the audience that can improve this. (Note, the namespace uses 
ztellman/primitive-math
which changes the semantics of some arithmetic operations and some type 
hinting.  Also
some of the 'let's are there for that reason. It may be helpful to refer to 
the link.

;;; https://github.com/danlentz/clj-uuid/blob/master/src/clj_uuid/bitmop.clj


(defn ^long expt2 [^long pow]
  (bit-set 0 pow))

(defn ^long mask [^long width ^long offset]
  (if (< (+ width offset) 64)
    (bit-shift-left (dec (bit-shift-left 1 width)) offset)
    (let [x (expt2 offset)]
      (bit-and-not -1 (dec ^long x)))))

(declare ^long mask-offset ^long mask-width)

(defn ^long mask-offset [^long m]
  (cond
    (zero? m) 0
    (neg?  m) (- 64 ^long (mask-width m))
    :else     (loop [c 0]
                (if (pos? (bit-and 1 (bit-shift-right m c)))
                  c
                  (recur (inc c))))))

(defn ^long mask-width [^long m]
  (if (neg? m)
    (let [x (mask-width (- (inc m)))]
      (- 64  ^long x))
    (loop [m (bit-shift-right m (mask-offset m)) c 0]
      (if (zero? (bit-and 1 (bit-shift-right m c)))
        c
        (recur m (inc c))))))

(defn ^long ldb
  "Load Byte"
  [^long bitmask ^long num]
  (let [off (mask-offset bitmask)]
    (bit-and (>>> bitmask ^long off)
      (bit-shift-right num off))))

(defn ^long dpb
  "Deposit Byte"
  [^long bitmask ^long num ^long value]
  (bit-or (bit-and-not num bitmask)
    (bit-and bitmask
      (bit-shift-left value (mask-offset bitmask)))))

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to