#<p>
# Efficient byte-level transpositions
#</p>
#<p>
# <b>Author:</b> Steve Wampler (<i>sbw@tapestry.tucson.az.us</i>)
#</p>
#<p>
# This file is in the <i>public domain</i>.
#</p>
package util
import lang
#<p>
# Efficiently rearrange bytes in a string. This is a class so that
# multiple simultaneous rearrangements can be carried out efficiently.
# Use a different class instance for each different rearrangement.
#</p>
#<p>
# Handles any transposition that can be expressed in multiples of
# 256-bytes or less.
#</p>
class MapBytes: Object (inM, inMap, outM, outMap, blkSize)
#<p>
# <[param s string to be transposed by map]>
# <[return a copy of <tt>s</tt> with the bytes rearranged by map]>
#</p>
method mapIn(s:"")
local ns := ""
s ? {
while ns ||:= ::map(outMap, inMap, ::move(*inMap))
while ns ||:= ::map(outM, inM, ::move(*inM))
ns ||:= ::tab(0)
}
return ns
end
#<p>
# Reverse the byte rearrangement
# <[param s string to be transposed by map inverse]>
# <[return a copy of <tt>s</tt> with the bytes rearranged by map inverse]>
#</p>
method mapOut(s:"")
local ns := ""
s ? {
while ns ||:= ::map(inMap, outMap, ::move(*outMap))
while ns ||:= ::map(inM, outM, ::move(*outM))
ns ||:= ::tab(0)
}
return ns
end
#<p>
# Copy one file to another with mapping (leaves files open).
#</p>
method mapInFile(inFile, # Input file (already opened for reading)
outFile, # Output file (already opened for writing)
blockSize # If present, overrides class' blkSize
)
blockSize := adjBlockSize(blockSize)
while ::writes(outFile, mapIn(::reads(inFile, blockSize)))
end
#<p>
# Copy one file to another with reverse mapping (leaves files open)
#</p>
method mapOutFile(inFile, # Input file (already opened for reading)
outFile, # Output file (already opened for writing)
blockSize # If present, overrides class' blkSize
)
blockSize := adjBlockSize(blockSize)
while ::writes(outFile, mapOut(::reads(inFile, blockSize)))
end
#<p>
# Adjust the given blockSize for file reads() to a valid value.
# <[param blockSize desired block size, may be adjusted internally]>
# <[return adjusted block size]>
# <i>Used internally.</i>
#</p>
method adjBlockSize(blockSize)
/blockSize := blkSize;
blockSize <:= *inM # Won't work with less!
return blockSize - (blockSize % (*inM)) # Must be multiple of *inM!
end
#<p>
# Create a class instance suitable for transposing bytes in
# in a string. Efficiently handles large strings.
#</p>
initially(in, # Arrangement of bytes found in input string
out, # Rearrangement of those bytes for output string
blockSize # Default size of file read/write operations (bytes).
# <i>Adjusted automatically to be a multiple of *in</i>.
)
inM := \in | "1"
outM := \out | in # Default is identity mapping
blkSize := 64*1024 # Default is large blocks
blkSize := adjBlockSize(blockSize)
# bootStrap to longest possible transposition strings...
inMap := ::string(&cset)
inMap := inMap[1+:(*inMap - (*inMap % (*inM)))]
outMap := ""
inMap ? while(outMap ||:= ::map(outM, inM, ::move(*inM)))
end
This page produced by UniDoc on 2021/04/15 @ 23:59:43.