Common Lisp the Language, 2nd Edition

Next: Random Numbers Up: Numbers Previous: Logical Operations on

# 12.8. Byte Manipulation Functions

Several functions are provided for dealing with an arbitrary-width field of contiguous bits appearing anywhere in an integer. Such a contiguous set of bits is called a byte. Here the term byte does not imply some fixed number of bits (such as eight), rather a field of arbitrary and user-specifiable width.

The byte-manipulation functions use objects called byte specifiers to designate a specific byte position within an integer. The representation of a byte specifier is implementation-dependent; in particular, it may or may not be a number. It is sufficient to know that the function `byte` will construct one, and that the byte-manipulation functions will accept them. The function `byte` accepts two integers representing the position and size of the byte and returns a byte specifier. Such a specifier designates a byte whose width is size and whose bits have weights through .

[Function]
`byte size position`

`byte` takes two integers representing the size and position of a byte and returns a byte specifier suitable for use as an argument to byte-manipulation functions.

[Function]
`byte-size bytespec
``byte-position bytespec`

Given a byte specifier, `byte-size` returns the size specified as an integer; `byte-position` similarly returns the position. For example:

    (byte-size (byte j k)) == j
    (byte-position (byte j k)) == k

[Function]
`ldb bytespec integer`

bytespec specifies a byte of integer to be extracted. The result is returned as a non-negative integer. For example:

    (logbitp j (ldb (byte s p) n)) == (and (< j s) (logbitp (+ j p) n))

The name of the function `ldb` means ``load byte.''

Compatibility note: The MacLisp function `haipart` can be implemented in terms of `ldb` as follows:

    (defun haipart (integer count)
      (let ((x (abs integer)))
        (if (minusp count)
            (ldb (byte (- count) 0) x)
            (ldb (byte count (max 0 (- (integer-length x) count)))
                 x))))

If the argument integer is specified by a form that is a place form acceptable to `setf`, then `setf` may be used with `ldb` to modify a byte within the integer that is stored in that place. The effect is to perform a `dpb` operation and then store the result back into the place.

[Function]
`ldb-test bytespec integer`

`ldb-test` is a predicate that is true if any of the bits designated by the byte specifier bytespec are 1's in integer; that is, it is true if the designated field is non-zero.

    (ldb-test bytespec n) == (not (zerop (ldb bytespec n)))

[Function]
`mask-field bytespec integer`

This is similar to `ldb`; however, the result contains the specified byte of integer in the position specified by bytespec, rather than in position 0 as with `ldb`. The result therefore agrees with integer in the byte specified but has zero-bits everywhere else. For example:

    (ldb bs (mask-field bs n)) == (ldb bs n)

    (logbitp j (mask-field (byte s p) n))
       == (and (>= j p) (< j (+ p s)) (logbitp j n))

    (mask-field bs n) == (logand n (dpb -1 bs 0))

If the argument integer is specified by a form that is a place form acceptable to `setf`, then `setf` may be used with `mask-field` to modify a byte within the integer that is stored in that place. The effect is to perform a `deposit-field` operation and then store the result back into the place.

[Function]
`dpb newbyte bytespec integer`

This returns a number that is the same as integer except in the bits specified by bytespec. Let s be the size specified by bytespec; then the low s bits of newbyte appear in the result in the byte specified by bytespec. The integer newbyte is therefore interpreted as being right-justified, as if it were the result of `ldb`. For example:

    (logbitp j (dpb m (byte s p) n))
      == (if (and (>= j p) (< j (+ p s)))
             (logbitp (- j p) m)
             (logbitp j n))

The name of the function `dpb` means ``deposit byte.''

[Function]
`deposit-field newbyte bytespec integer`

This function is to `mask-field` as `dpb` is to `ldb`. The result is an integer that contains the bits of newbyte within the byte specified by bytespec, and elsewhere contains the bits of integer. For example:

    (logbitp j (deposit-field m (byte s p) n))
       == (if (and (>= j p) (< j (+ p s)))
              (logbitp j m)
              (logbitp j n))

Implementation note: If the bytespec is a constant, one may of course construct, at compile time, an equivalent mask m, for example by computing `(deposit-field -1 bytespec 0)`. Given this mask m, one may then compute

    (deposit-field newbyte bytespec integer)

by computing

    (logior (logand newbyte m) (logand integer (lognot m)))

where the result of `(lognot m)` can of course also be computed at compile time. However, the following expression may also be used and may require fewer temporary registers in some situations:

    (logxor integer (logand m (logxor integer newbyte)))

A related, though possibly less useful, trick is that

    (let ((z (logand (logxor x y) m)))
      (setq x (logxor z x))
      (setq y (logxor z y)))

interchanges those bits of `x` and `y` for which the mask `m` is `1`, and leaves alone those bits of `x` and `y` for which `m` is `0`.

Next: Random Numbers Up: Numbers Previous: Logical Operations on