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.