Posted to tcl by GPS at Tue Oct 09 02:54:57 GMT 2007view raw
- #This is my solution using memoize from the Wiki...
- if {0} {
- memoize
- A package that can be used to cache, load and save the values of expensive pure function calls.
- HISTORY
- DDG 2004-06-03: A fix to memoize::save for handling strings with spaces
- DDG 2004-06-04: Adding memoize::unload to unset the Memo array or parts of it instead of directly manipulating it via array unset memoize::Memo
- SEE ALSO
- memoizing, Perl Memoize Package [1]
- }
- ##############################################################################
- # AUTHOR: Dr. Detlef Groth
- # Copyright (c) Get it, use it, share it, improve it, but don't blame me.
- package provide memoize 0.1
- namespace eval ::memoize {
- variable Memo
- }
- proc ::memoize::memoize {} {
- variable Memo
- set cmd [info level -1]
- if {[info level] > 2 && [lindex [info level -2] 0] eq "memoize::memoize"} return
- if { ! [info exists Memo($cmd)]} {set Memo($cmd) [eval $cmd]}
- return -code return $Memo($cmd)
- }
- proc ::memoize::save {file {cmd ""}} {
- variable Memo
- set names [array names Memo -glob $cmd*]
- if [catch { set out [open $file w 0600] }] {
- error "Could not open $file!"
- } else {
- foreach name $names {
- puts $out "set {memoize::Memo($name)} {$Memo($name)}"
- }
- }
- close $out
- }
- proc ::memoize::load {file} {
- variable Memo
- if {[file readable $file]} {
- source $file
- }
- }
- proc ::memoize::unload {{cmd ""}} {
- variable Memo
- array unset Memo "$cmd*"
- }
- # testing actually longer than the code itself
- if {0} {
- # RS example
- proc memoize {} {
- global memo
- set cmd [info level -1]
- if {[info level] > 2 && [lindex [info level -2] 0] eq "memoize"} return
- if { ! [info exists memo($cmd)]} {set memo($cmd) [eval $cmd]}
- return -code return $memo($cmd)
- }
- proc fib x {expr {$x <=1? 1 : [fib [expr {$x-1}]] + [fib [expr {$x-2}]]}}
- proc fibm x {memoize; expr {$x <=1? 1 : [fibm [expr {$x-1}]] + [fibm [expr {$x-2}]]}}
- proc fibmp x {memoize::memoize; expr {$x <=1? 1 : [fibm [expr {$x-1}]] + [fibm [expr {$x-2}]]}}
- fib 20 ;#= 10946
- fibm 20 ;#= 10946
- fibmp 20 ;#= 10946
- time {fib 32} ;#= 7757279 microseconds per iteration
- time {fib 32} ;#= 7763364 microseconds per iteration
- time {fib 32} ;#= 7927045 microseconds per iteration
- array unset memo
- time {fibm 32} ;#= 1365 microseconds per iteration
- time {fibm 32} ;#= 27 microseconds per iteration
- time {fibm 32} ;#= 28 microseconds per iteration
- memoize::unload
- time {fibmp 32} ;#= 97 microseconds per iteration
- time {fibmp 32} ;#= 29 microseconds per iteration
- time {fibmp 32} ;#= 28 microseconds per iteration
- memoize::save test.tmf
- memoize::unload
- memoize::load test.tmf
- time {fibmp 32} ;#= 33 microseconds per iteration
- time {fibmp 32} ;#= 29 microseconds per iteration
- time {fibmp 32} ;#= 28 microseconds per iteration
- }
- set key "012345678912345678"
- set subject "DUKE NUKEM FOREVER"
- set iterations 1000000
- proc xor {subject key} {
- binary scan $subject c[string length $subject] subject
- binary scan $key c[string length $key] key
- set destbuffer [list]
- foreach s $subject k $key {
- lappend destbuffer [expr {$s^$k}]
- }
- return [binary format c* $destbuffer]
- }
- puts BASE:[time {xor $subject $key}]
- proc xor2 {subject key} {
- memoize::memoize
- set result {}
- foreach s [split $subject ""] k [split $key ""] {
- append result [format %c [expr {[scan $s %c] ^ [scan $k %c]}]]
- }
- return $result
- }
- puts ONCE:[time {xor2 $subject $key}]
- puts TWICE:[time {xor2 $subject $key}]
- puts THRICE:[time {xor2 $subject $key}]
- set iterations [expr $iterations*2]
- for {set i 0} {$i < $iterations} {incr i} {
- set subject [xor2 $subject $key]
- #puts $subject
- }
- puts "after: $subject"