[comp.lang.icon] bits -> bytes

goer@ellis.uchicago.edu (Richard L. Goerwitz) (04/04/91)

Perhaps I'm opening a can of worms, like I did with the last such
posting ("terrible code").  Anyway, I just wrote a section of code
for some compression work I'm doing, and I just don't like the
looks of it.  Is there a clearer and/or more efficient way of do-
ing this sort of thing in Icon??

-Richard

(what sort of thing I'm talking about will shortly become clear;
behold the code -)

#
#  outbits() & inbits()
#
#  Pass to outbits(i, len) an integer i, and a length parameter (len),
#  and outbits will suspend byte-sized chunks of i converted to
#  characters (most significant bits first) until there is not enough
#  left of i to fill up an 8-bit character.  The remaining portion is
#  stored in a buffer until outbits() is called again, at which point
#  the buffer is combined with the new i and then output in the same
#  manner as before.  The buffer is flushed by calling outbits() with
#  no i argument.
#
#  A trivial example of how outbits() might be used:
#
#      outtext := open("some.file.name","w")
#      l := [1,2,3,4]
#      every writes(outtext, outbits(!l,3))
#      writes(outtext, outbits(&null,3))           # flush buffer
#
#  List l may be reconstructed with inbits() (see inbits.icn):
#
#      intext := open("some.file.name")
#      l := []
#      while put(l, inbits(intext, 3))
#
#  Note that outbits() is a generator, while inbits() is not.
#

procedure outbits(i, len)

    local old_part, new_part, window, old_byte_mask
    static old_i, old_len, byte_length, byte_mask
    initial {
	old_i := old_len := 0
	byte_length := 8
	byte_mask := (2^byte_length)-1
    }

    old_byte_mask := (0 < 2^old_len - 1) | 0
    window := byte_length - old_len
    old_part := ishift(iand(old_i, old_byte_mask), window)

    # If we have a no-arg invocation, then flush buffer (old_i).
    if /i then {
	old_i := old_len := 0
	return char(old_part)
    } else {
	new_part := ishift(i, window-len)
	len -:= (len >= window) | {
	    old_len +:= len
	    old_i := ior(ishift(old_part, len-window), i)
	    fail
	}
	suspend char(ior(old_part, new_part))
    }

    until len < byte_length do {
	suspend char(iand(ishift(i, byte_length-len), byte_mask))
	len -:= byte_length
    }

    old_len := len
    old_i := i
    fail

end


procedure inbits(f, len)

    local i, byte, old_byte_mask
    static old_byte, old_len, byte_length
    initial {
	old_byte := old_len := 0
	byte_length := 8
    }

    old_byte_mask := (0 < 2^old_len - 1) | 0
    old_byte := iand(old_byte, old_byte_mask)
    i := ishift(old_byte, len-old_len)

    len -:= (len > old_len) | {
	old_len -:= len
	return i
    }
    
    while byte := ord(reads(f)) do {
	i := ior(i, ishift(byte, len-byte_length))
	len -:= (len > byte_length) | {
	    old_len := byte_length-len
	    old_byte := byte
	    return i
	}
    }

end
-- 

   -Richard L. Goerwitz              goer%sophist@uchicago.bitnet
   goer@sophist.uchicago.edu         rutgers!oddjob!gide!sophist!goer