Posted to tcl by patthoyts at Mon Aug 18 13:34:19 GMT 2008view pretty

# An example of a coroutine based RLE decoder
# Reads data a character at a time. If the input is \xff then the next byte
# is the number of repetitions of the following byte.
# Each call to the coroutine will return 1 byte.

load /opt/tcl/site-lib/Memchan2.2.2/memchan222.dll
package require Memchan

namespace path ::tcl::unsupported
variable uid 0

# A factory procedure that returns a lambda-based coroutine to decode
# our RLE encoded channel. When the lambda exits, it will clean
# up the decoder procedure automatically.
# The proc returns the name of the created decoder, each call to this
# new command will return one character from the data stream or -1 when
# the stream has been emptied.
proc make-decompressor {channel} {
    variable uid
    set lambda [list {chan} {
        yield
        while {1} {
            set c [read $chan 1]
            if {[eof $chan]} {
                return -1
            }
            if {[scan $c %c] == 0xff} {
                set len [scan [read $chan 1] %c]
                set c [read $chan 1]
                while {$len} {
                    incr len -1
                    yield $c
                }
            } else {
                yield $c
            }
        }
    }]
    set name rle[incr uid]
    coroutine $name ::apply $lambda $channel
    return $name
}

# Create a channel with some sample RLE encoded data.
set mem [memchan]
puts -nonewline $mem "\x31\x32\x33\xff\x06\x34\x35"
seek $mem 0

# Create a coroutine reader that will return one char per call from the
# compressed channel data.
set getchar [make-decompressor $mem]

# Prove that the decoder exists as a command
puts "$getchar exists? [llength [info commands $getchar]]"

# Nice simple reader code...
set n 0
while {[set c [$getchar]] != -1} {
    puts "$n '$c'"
    incr n
}

close $mem

# Prove the decoder was automatically garbage collected.
puts "$getchar exists? [llength [info commands $getchar]]"

Comments

Posted by miguel at Mon Aug 18 13:40:29 GMT 2008 [text] [code]

Nice! If the lambda were defined as a literal instead of using [list], decompressors for all channels would use the same lambda and bytecodes, the compilation would be done just once.