September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
|
|
@ -19,3 +19,4 @@ nine (or more) bits long.
|
|||
|
||||
* Limits in the maximum number of bits that can be written/read in a single read/write operation are allowed.
|
||||
* Errors handling is not mandatory
|
||||
<br><br>
|
||||
|
|
|
|||
140
Task/Bitwise-IO/Common-Lisp/bitwise-io-1.lisp
Normal file
140
Task/Bitwise-IO/Common-Lisp/bitwise-io-1.lisp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
(defpackage :rosetta.bitwise-i/o
|
||||
(:use :common-lisp)
|
||||
(:export :bitwise-i/o-demo))
|
||||
(in-package :rosetta.bitwise-i/o)
|
||||
|
||||
(defun byte->bit-vector (byte byte-bits)
|
||||
"Convert one BYTE into a bit-vector of BYTE-BITS length."
|
||||
(let ((vector (make-array byte-bits :element-type 'bit))
|
||||
(bit-value 1))
|
||||
(declare (optimize (speed 3)))
|
||||
(dotimes (bit-index byte-bits vector)
|
||||
(setf (aref vector bit-index)
|
||||
(if (plusp (logand byte (the (unsigned-byte 8) bit-value)))
|
||||
1 0))
|
||||
(setq bit-value (ash bit-value 1)))))
|
||||
|
||||
(defun bytes->bit-vector (byte-vector byte-bits)
|
||||
"Convert a BYTE-VECTOR into a bit-vector, with each byte taking BYTE-BITS.
|
||||
|
||||
For optimization's sake, I limit the size of the vector to (FLOOR
|
||||
MOST-POSITIVE-FIXNUM BYTE-BITS), which is somewhat ridiculously long,
|
||||
but allows the compiler to trust that indices will fit in a FIXNUM."
|
||||
(reduce (lambda (a b) (concatenate 'bit-vector a b))
|
||||
(map 'list (lambda (byte) (byte->bit-vector byte byte-bits)) byte-vector)))
|
||||
|
||||
(defun ascii-char-p (char)
|
||||
"True if CHAR is an ASCII character"
|
||||
(< (char-code char) #x80))
|
||||
|
||||
(defun assert-ascii-string (string)
|
||||
"`ASSERT' that STRING is an ASCII string."
|
||||
(assert (every #'ascii-char-p string)
|
||||
(string)
|
||||
"STRING must contain only ASCII (7-bit) characters;~%“~a”
|
||||
…contains non-ASCII character~p~:*: ~{~% • ~c ~:*— ~@c ~}"
|
||||
string (coerce (remove-duplicates (remove-if #'ascii-char-p string)
|
||||
:test #'char=)
|
||||
'list)))
|
||||
|
||||
(defun ascii-string->bit-vector (string)
|
||||
"Convert a STRING consisting only of characters in the ASCII \(7-bit)
|
||||
range into a bit-vector of 7 bits per character.
|
||||
|
||||
This assumes \(as is now, in 2017, I believe universally the case) that
|
||||
the local character code system \(as for `CHAR-CODE' and `CODE-CHAR') is
|
||||
Unicode, or at least, a superset of ASCII \(eg: ISO-8859-*)
|
||||
"
|
||||
(check-type string simple-string)
|
||||
(assert-ascii-string string)
|
||||
(bytes->bit-vector (map 'vector #'char-code string) 7))
|
||||
|
||||
(defun pad-bit-vector-to-8 (vector)
|
||||
"Ensure that VECTOR is a multiple of 8 bits in length."
|
||||
(adjust-array vector (* 8 (ceiling (length vector) 8))))
|
||||
|
||||
(defun bit-vector->byte (vector)
|
||||
"Convert VECTOR into a single byte."
|
||||
(declare (optimize (speed 3)))
|
||||
(check-type vector bit-vector)
|
||||
(assert (<= (length vector) 8))
|
||||
(reduce (lambda (x y)
|
||||
(logior (the (unsigned-byte 8)
|
||||
(ash (the (unsigned-byte 8) x) 1))
|
||||
(the bit y)))
|
||||
(reverse vector) :initial-value 0))
|
||||
|
||||
(defun bit-vector->bytes (vector byte-size &key (truncatep nil))
|
||||
"Convert a bit vector VECTOR into a vector of bytes of BYTE-SIZE bits each.
|
||||
|
||||
If TRUNCATEP, then discard any trailing bits."
|
||||
(let* ((out-length (funcall (if truncatep 'floor 'ceiling)
|
||||
(length vector)
|
||||
byte-size))
|
||||
(output (make-array out-length
|
||||
:element-type (list 'unsigned-byte byte-size))))
|
||||
(loop for byte from 0 below out-length
|
||||
for start-bit = 0 then end-bit
|
||||
for end-bit = byte-size then (min (+ byte-size end-bit)
|
||||
(length vector))
|
||||
do (setf (aref output byte)
|
||||
(bit-vector->byte (subseq vector start-bit end-bit))))
|
||||
output))
|
||||
|
||||
(defun ascii-pack-to-8-bit (string)
|
||||
"Pack an ASCII STRING into 8-bit bytes (7→8 bit packing)"
|
||||
(bit-vector->bytes (ascii-string->bit-vector string)
|
||||
8))
|
||||
|
||||
(defun unpack-ascii-from-8-bits (byte-vector)
|
||||
"Convert an 8-bit BYTE-VECTOR into an array of (unpacked) 7-bit bytes."
|
||||
(map 'string #'code-char
|
||||
(bit-vector->bytes
|
||||
(pad-bit-vector-to-8 (bytes->bit-vector byte-vector 8))
|
||||
7
|
||||
:truncatep t)))
|
||||
|
||||
(defun write-7->8-bit-string-to-file (string pathname)
|
||||
"Given a string of 7-bit character STRING, create a new file at PATHNAME
|
||||
with the contents of that string packed into 8-bit bytes."
|
||||
(format *trace-output* "~&Writing string to ~a in packed 7→8 bits…~%“~a”"
|
||||
pathname string)
|
||||
(assert-ascii-string string)
|
||||
(with-open-file (output pathname
|
||||
:direction :output
|
||||
:if-exists :supersede
|
||||
:element-type '(unsigned-byte 8))
|
||||
(write-sequence (ascii-pack-to-8-bit string) output)
|
||||
(finish-output output)
|
||||
(let ((expected-length (ceiling (* (length string) 7) 8)))
|
||||
(assert (= (file-length output) expected-length) ()
|
||||
"The file written was ~:d byte~:p in length, ~
|
||||
but the string supplied should have written ~:d byte~:p."
|
||||
(file-length output) expected-length))))
|
||||
|
||||
(defun read-file-into-byte-array (pathname)
|
||||
"Read a binary file into a byte array"
|
||||
(with-open-file (input pathname
|
||||
:direction :input
|
||||
:if-does-not-exist :error
|
||||
:element-type '(unsigned-byte 8))
|
||||
(let ((buffer (make-array (file-length input)
|
||||
:element-type '(unsigned-byte 8))))
|
||||
(read-sequence buffer input)
|
||||
buffer)))
|
||||
|
||||
(defun read-8->7-bit-string-from-file (pathname)
|
||||
"Read 8-bit packed data from PATHNAME and return it as
|
||||
a 7-bit string."
|
||||
(unpack-ascii-from-8-bits (read-file-into-byte-array pathname)))
|
||||
|
||||
(defun bitwise-i/o-demo (&key (string "Hello, World.")
|
||||
(pathname #p"/tmp/demo.bin"))
|
||||
"Writes STRING to PATHNAME after 7→8 bit packing, then reads it back
|
||||
to validate."
|
||||
(write-7->8-bit-string-to-file string pathname)
|
||||
(let ((read-back (read-8->7-bit-string-from-file pathname)))
|
||||
(assert (equal string read-back) ()
|
||||
"Reading back string got:~%“~a”~%…expected:~%“~a”" read-back string)
|
||||
(format *trace-output* "~&String read back matches:~%“~a”" read-back))
|
||||
(finish-output *trace-output*))
|
||||
26
Task/Bitwise-IO/Common-Lisp/bitwise-io-2.lisp
Normal file
26
Task/Bitwise-IO/Common-Lisp/bitwise-io-2.lisp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
BITWISE-I/O> (bitwise-i/o-demo)
|
||||
|
||||
Writing string to /tmp/demo.bin in packed 7→8 bits…
|
||||
“Hello, World.”
|
||||
String read back matches:
|
||||
“Hello, World.”
|
||||
NIL
|
||||
BITWISE-I/O> (bitwise-i/o-demo :string "It doesn't, however, do UTF-7. So, no ☠ or 🙋")
|
||||
Writing string to /tmp/demo.bin in packed 7→8 bits…
|
||||
“It doesn't, however, do UTF-7. So, no ☠ or 🙋”
|
||||
|
||||
STRING must contain only ASCII (7-bit) characters;
|
||||
“It doesn't, however, do UTF-7. So, no ☠ or 🙋”
|
||||
…contains non-ASCII characters:
|
||||
• ☠ — #\SKULL_AND_CROSSBONES
|
||||
• 🙋 — #\HAPPY_PERSON_RAISING_ONE_HAND
|
||||
[Condition of type SIMPLE-ERROR]
|
||||
|
||||
|
||||
Restarts:
|
||||
0: [CONTINUE] Retry assertion with new value for STRING.
|
||||
1: [RETRY] Retry SLIME REPL evaluation request.
|
||||
2: [*ABORT] Return to SLIME's top level.
|
||||
3: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {10152E8033}>)
|
||||
|
||||
⇒ ABORT
|
||||
94
Task/Bitwise-IO/Nim/bitwise-io.nim
Normal file
94
Task/Bitwise-IO/Nim/bitwise-io.nim
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
type
|
||||
BitWriter * = tuple
|
||||
file: File
|
||||
bits: uint8
|
||||
nRemain: int
|
||||
|
||||
BitReader * = tuple
|
||||
file: File
|
||||
bits: uint8
|
||||
nRemain: int
|
||||
nRead: int
|
||||
|
||||
proc newBitWriter * (file: File) : ref BitWriter =
|
||||
result = new BitWriter
|
||||
result.file = file
|
||||
result.bits = 0
|
||||
result.nRemain = 8
|
||||
|
||||
proc flushBits (stream : ref BitWriter) =
|
||||
discard stream.file.writeBuffer(stream.bits.addr, 1)
|
||||
stream.nRemain = 8
|
||||
stream.bits = 0
|
||||
|
||||
proc write * (stream: ref BitWriter, bits: uint8, nBits: int) =
|
||||
assert(nBits <= 8)
|
||||
|
||||
for ii in countdown((nBits - 1), 0) :
|
||||
stream.bits = (stream.bits shl 1) or ((bits shr ii) and 1)
|
||||
stream.nRemain.dec(1)
|
||||
if stream.nRemain == 0:
|
||||
stream.flushBits
|
||||
|
||||
proc flush * (stream: ref BitWriter) =
|
||||
if stream.nRemain < 8:
|
||||
stream.bits = stream.bits shl stream.nRemain
|
||||
stream.flushBits
|
||||
|
||||
proc newBitReader * (file: File) : ref BitReader =
|
||||
result = new BitReader
|
||||
result.file = file
|
||||
result.bits = 0
|
||||
result.nRemain = 0
|
||||
result.nRead = 0
|
||||
|
||||
proc read * (stream: ref BitReader, nBits: int) : uint8 =
|
||||
assert(nBits <= 8)
|
||||
|
||||
result = 0
|
||||
for ii in 0 .. < nBits :
|
||||
if stream.nRemain == 0:
|
||||
stream.nRead = stream.file.readBuffer(stream.bits.addr, 1)
|
||||
if stream.nRead == 0:
|
||||
break
|
||||
stream.nRemain = 8
|
||||
|
||||
result = (result shl 1) or ((stream.bits shr 7) and 1)
|
||||
|
||||
stream.bits = stream.bits shl 1
|
||||
stream.nRemain.dec(1)
|
||||
|
||||
|
||||
when isMainModule:
|
||||
var
|
||||
file: File
|
||||
writer: ref BitWriter
|
||||
reader: ref BitReader
|
||||
|
||||
file = open("testfile.dat", fmWrite)
|
||||
writer = newBitWriter(file)
|
||||
|
||||
for ii in 0 .. 255:
|
||||
writer.write(ii.uint8, 7)
|
||||
|
||||
writer.flush
|
||||
file.close
|
||||
|
||||
var dataCtr = 0
|
||||
|
||||
file = open("testfile.dat", fmRead)
|
||||
reader = newBitReader(file)
|
||||
|
||||
while true:
|
||||
let aByte = reader.read(7)
|
||||
|
||||
if reader.nRead == 0:
|
||||
break
|
||||
|
||||
assert((dataCtr and 0x7f).uint8 == aByte)
|
||||
|
||||
assert(dataCtr == 256)
|
||||
|
||||
file.close
|
||||
|
||||
echo "OK"
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
sub encode-ascii(Str $s) {
|
||||
my @b = $s.ords».fmt("%07b")».comb;
|
||||
my @b = flat $s.ords».fmt("%07b")».comb;
|
||||
@b.push(0) until @b %% 8; # padding
|
||||
Buf.new: gather while @b { take reduce * *2+*, (@b.pop for ^8) }
|
||||
}
|
||||
|
||||
sub decode-ascii(Buf $b) {
|
||||
my @b = $b.list».fmt("%08b")».comb;
|
||||
my @b = flat $b.list».fmt("%08b")».comb;
|
||||
@b.shift until @b %% 7; # remove padding
|
||||
@b = gather while @b { take reduce * *2+*, (@b.pop for ^7) }
|
||||
return [~] @b».chr;
|
||||
|
|
|
|||
15
Task/Bitwise-IO/REXX/bitwise-io-2.rexx
Normal file
15
Task/Bitwise-IO/REXX/bitwise-io-2.rexx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*REXX pgm encodes/decodes/displays ASCII character strings as (7─bits) binary string.*/
|
||||
parse arg $; if $=='' then $='STRING' /*get optional argument; Use default ? */
|
||||
say ' input string=' $ /*display the input string to terminal.*/
|
||||
out=comp($); say ' encoded string=' out /*encode─► 7─bit binary string; display*/
|
||||
ori=dcomp(out); say ' decoded string=' ori /*decode─► 8─bit char " ; " */
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
comp: parse arg x; z=; do j=1 for length(x) /*convert─►right-justified 7-bit binary*/
|
||||
z=z || right( x2b( c2x( substr(x, j, 1) )), 7)
|
||||
end /*j*/; return left(z,length(z)+(8-length(z)//8)//8,0)
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
dcomp: parse arg x; z=; do k=1 by 7 to length(x); _=substr(x, k, 7)
|
||||
if right(_, 1)==' ' then leave
|
||||
z=z || x2c( b2x(0 || _) )
|
||||
end /*k*/; return z
|
||||
13
Task/Bitwise-IO/Zkl/bitwise-io-1.zkl
Normal file
13
Task/Bitwise-IO/Zkl/bitwise-io-1.zkl
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// stream of numBits sized ints to bytes, numBits<8
|
||||
fcn toBytes(n,[(numBits,acc,bitsSoFar)]state){
|
||||
acc=acc.shiftLeft(numBits) + n; bitsSoFar+=numBits;
|
||||
reg r;
|
||||
if(bitsSoFar>=8){
|
||||
bitsSoFar-=8;
|
||||
r=acc.shiftRight(bitsSoFar);
|
||||
acc=acc.bitAnd((-1).shiftLeft(bitsSoFar).bitNot());
|
||||
}
|
||||
else r=Void.Skip; // need more bits to make a byte
|
||||
state.clear(numBits,acc,bitsSoFar);
|
||||
r
|
||||
}
|
||||
7
Task/Bitwise-IO/Zkl/bitwise-io-2.zkl
Normal file
7
Task/Bitwise-IO/Zkl/bitwise-io-2.zkl
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
ns:="THIS IS A TEST".pump(List,"toAsc",'-(0x20));
|
||||
ns.println(ns.len());
|
||||
|
||||
state:=L(6,0,0,L()); // input is six bits wide
|
||||
cns:=ns.pump(List,toBytes.fp1(state)); // List could be a file or socket or ...
|
||||
if(state[2]) cns+=toBytes(0,state); // flush
|
||||
cns.println(cns.len());
|
||||
12
Task/Bitwise-IO/Zkl/bitwise-io-3.zkl
Normal file
12
Task/Bitwise-IO/Zkl/bitwise-io-3.zkl
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// stream of bytes to numBits sized ints, 1<numBits<32
|
||||
fcn fromBytes(n,[(numBits,acc,bitsSoFar,buf)]state){
|
||||
acc=acc.shiftLeft(8) + n; bitsSoFar+=8;
|
||||
buf.clear();
|
||||
while(bitsSoFar>=numBits){
|
||||
bitsSoFar-=numBits;
|
||||
buf.append(acc.shiftRight(bitsSoFar));
|
||||
acc=acc.bitAnd((-1).shiftLeft(bitsSoFar).bitNot());
|
||||
}
|
||||
state.clear(numBits,acc,bitsSoFar,buf);
|
||||
return(Void.Write,Void.Write,buf); // append contents of buf to result
|
||||
}
|
||||
4
Task/Bitwise-IO/Zkl/bitwise-io-4.zkl
Normal file
4
Task/Bitwise-IO/Zkl/bitwise-io-4.zkl
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
state:=L(6,0,0,L()); // output is six bits wide
|
||||
r:=cns.pump(List,fromBytes.fp1(state)); // cns could be a file or ...
|
||||
r.println(r.len());
|
||||
r.pump(String,'+(0x20),"toChar").println();
|
||||
Loading…
Add table
Add a link
Reference in a new issue