2009-02-12 18:44:43 -05:00
|
|
|
! Copyright (C) 2009 Doug Coleman.
|
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2009-05-14 16:44:57 -04:00
|
|
|
USING: accessors alien.accessors assocs byte-arrays combinators
|
2009-06-13 19:47:19 -04:00
|
|
|
destructors fry io io.binary io.encodings.binary io.streams.byte-array
|
|
|
|
kernel locals macros math math.ranges multiline sequences
|
|
|
|
sequences.private vectors byte-vectors combinators.short-circuit
|
|
|
|
math.bitwise ;
|
2009-02-12 18:44:43 -05:00
|
|
|
IN: bitstreams
|
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
TUPLE: widthed { bits integer read-only } { #bits integer read-only } ;
|
2009-02-12 18:44:43 -05:00
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
ERROR: invalid-widthed bits #bits ;
|
2009-02-12 18:44:43 -05:00
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
: check-widthed ( bits #bits -- bits #bits )
|
|
|
|
dup 0 < [ invalid-widthed ] when
|
|
|
|
2dup { [ nip 0 = ] [ drop 0 = not ] } 2&& [ invalid-widthed ] when
|
|
|
|
over 0 = [
|
|
|
|
2dup [ dup 0 < [ neg ] when log2 1 + ] dip > [ invalid-widthed ] when
|
|
|
|
] unless ;
|
2009-02-12 18:44:43 -05:00
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
: <widthed> ( bits #bits -- widthed )
|
|
|
|
check-widthed
|
|
|
|
widthed boa ;
|
2009-02-12 18:44:43 -05:00
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
: zero-widthed ( -- widthed ) 0 0 <widthed> ;
|
2009-05-15 00:33:00 -04:00
|
|
|
: zero-widthed? ( widthed -- ? ) zero-widthed = ;
|
2009-02-12 18:44:43 -05:00
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
TUPLE: bit-reader
|
|
|
|
{ bytes byte-array }
|
|
|
|
{ byte-pos array-capacity initial: 0 }
|
|
|
|
{ bit-pos array-capacity initial: 0 } ;
|
2009-02-12 18:44:43 -05:00
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
TUPLE: bit-writer
|
|
|
|
{ bytes byte-vector }
|
|
|
|
{ widthed widthed } ;
|
2009-02-12 18:44:43 -05:00
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
TUPLE: msb0-bit-reader < bit-reader ;
|
|
|
|
TUPLE: lsb0-bit-reader < bit-reader ;
|
2009-06-13 19:47:19 -04:00
|
|
|
|
|
|
|
: <msb0-bit-reader> ( bytes -- bs )
|
|
|
|
msb0-bit-reader new swap >>bytes ; inline
|
|
|
|
|
|
|
|
: <lsb0-bit-reader> ( bytes -- bs )
|
|
|
|
lsb0-bit-reader new swap >>bytes ; inline
|
2009-02-12 18:44:43 -05:00
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
TUPLE: msb0-bit-writer < bit-writer ;
|
|
|
|
TUPLE: lsb0-bit-writer < bit-writer ;
|
|
|
|
|
2009-05-15 00:33:00 -04:00
|
|
|
: new-bit-writer ( class -- bs )
|
|
|
|
new
|
|
|
|
BV{ } clone >>bytes
|
|
|
|
0 0 <widthed> >>widthed ; inline
|
|
|
|
|
|
|
|
: <msb0-bit-writer> ( -- bs )
|
|
|
|
msb0-bit-writer new-bit-writer ;
|
|
|
|
|
|
|
|
: <lsb0-bit-writer> ( -- bs )
|
|
|
|
lsb0-bit-writer new-bit-writer ;
|
2009-05-14 16:44:57 -04:00
|
|
|
|
|
|
|
GENERIC: peek ( n bitstream -- value )
|
|
|
|
GENERIC: poke ( value n bitstream -- )
|
|
|
|
|
2009-06-05 06:26:50 -04:00
|
|
|
: get-abp ( bitstream -- abp )
|
|
|
|
[ byte-pos>> 8 * ] [ bit-pos>> + ] bi ; inline
|
|
|
|
|
|
|
|
: set-abp ( abp bitstream -- )
|
|
|
|
[ 8 /mod ] dip [ (>>bit-pos) ] [ (>>byte-pos) ] bi ; inline
|
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
: seek ( n bitstream -- )
|
2009-06-05 06:26:50 -04:00
|
|
|
[ get-abp + ] [ set-abp ] bi ; inline
|
|
|
|
|
|
|
|
: (align) ( n m -- n' )
|
2009-08-13 20:21:44 -04:00
|
|
|
[ /mod 0 > [ 1 + ] when ] [ * ] bi ; inline
|
2009-06-05 06:26:50 -04:00
|
|
|
|
|
|
|
: align ( n bitstream -- )
|
|
|
|
[ get-abp swap (align) ] [ set-abp ] bi ; inline
|
2009-05-14 16:44:57 -04:00
|
|
|
|
|
|
|
: read ( n bitstream -- value )
|
|
|
|
[ peek ] [ seek ] 2bi ; inline
|
|
|
|
|
|
|
|
<PRIVATE
|
|
|
|
|
|
|
|
ERROR: not-enough-bits widthed n ;
|
|
|
|
|
|
|
|
: widthed-bits ( widthed n -- bits )
|
|
|
|
dup 0 < [ not-enough-bits ] when
|
|
|
|
2dup [ #bits>> ] dip < [ not-enough-bits ] when
|
|
|
|
[ [ bits>> ] [ #bits>> ] bi ] dip
|
|
|
|
[ - neg shift ] keep <widthed> ;
|
|
|
|
|
|
|
|
: split-widthed ( widthed n -- widthed1 widthed2 )
|
|
|
|
2dup [ #bits>> ] dip < [
|
|
|
|
drop zero-widthed
|
2009-02-12 18:44:43 -05:00
|
|
|
] [
|
2009-05-14 16:44:57 -04:00
|
|
|
[ widthed-bits ]
|
|
|
|
[ [ [ bits>> ] [ #bits>> ] bi ] dip - [ bits ] keep <widthed> ] 2bi
|
2009-02-12 18:44:43 -05:00
|
|
|
] if ;
|
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
: widthed>bytes ( widthed -- bytes widthed )
|
|
|
|
[ 8 split-widthed dup zero-widthed? not ]
|
|
|
|
[ swap bits>> ] B{ } produce-as nip swap ;
|
|
|
|
|
2009-05-15 00:33:00 -04:00
|
|
|
:: |widthed ( widthed1 widthed2 -- widthed3 )
|
|
|
|
widthed1 bits>> :> bits1
|
|
|
|
widthed1 #bits>> :> #bits1
|
|
|
|
widthed2 bits>> :> bits2
|
|
|
|
widthed2 #bits>> :> #bits2
|
|
|
|
bits1 #bits2 shift bits2 bitor
|
|
|
|
#bits1 #bits2 + <widthed> ;
|
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
PRIVATE>
|
2009-02-12 18:44:43 -05:00
|
|
|
|
2009-05-14 16:44:57 -04:00
|
|
|
M:: lsb0-bit-writer poke ( value n bs -- )
|
|
|
|
value n <widthed> :> widthed
|
|
|
|
widthed
|
|
|
|
bs widthed>> #bits>> 8 swap - split-widthed :> remainder :> byte
|
2009-05-15 00:33:00 -04:00
|
|
|
byte bs widthed>> |widthed :> new-byte
|
2009-05-15 15:59:26 -04:00
|
|
|
new-byte #bits>> 8 = [
|
2009-05-15 00:33:00 -04:00
|
|
|
new-byte bits>> bs bytes>> push
|
2009-05-14 16:44:57 -04:00
|
|
|
zero-widthed bs (>>widthed)
|
|
|
|
remainder widthed>bytes
|
2009-05-15 00:33:00 -04:00
|
|
|
[ bs bytes>> push-all ] [ bs (>>widthed) ] bi*
|
2009-05-14 16:44:57 -04:00
|
|
|
] [
|
|
|
|
byte bs (>>widthed)
|
|
|
|
] if ;
|
2009-05-15 00:33:00 -04:00
|
|
|
|
|
|
|
: enough-bits? ( n bs -- ? )
|
|
|
|
[ bytes>> length ]
|
|
|
|
[ byte-pos>> - 8 * ]
|
|
|
|
[ bit-pos>> - ] tri <= ;
|
|
|
|
|
|
|
|
ERROR: not-enough-bits n bit-reader ;
|
|
|
|
|
|
|
|
: #bits>#bytes ( #bits -- #bytes )
|
|
|
|
8 /mod 0 = [ 1 + ] unless ; inline
|
|
|
|
|
2009-05-15 15:08:56 -04:00
|
|
|
:: subseq>bits-le ( bignum n bs -- bits )
|
|
|
|
bignum bs bit-pos>> neg shift n bits ;
|
|
|
|
|
|
|
|
:: subseq>bits-be ( bignum n bs -- bits )
|
2009-05-15 00:33:00 -04:00
|
|
|
bignum
|
|
|
|
8 bs bit-pos>> - n - 8 mod dup 0 < [ 8 + ] when
|
|
|
|
neg shift n bits ;
|
|
|
|
|
|
|
|
:: adjust-bits ( n bs -- )
|
|
|
|
n 8 /mod :> #bits :> #bytes
|
|
|
|
bs [ #bytes + ] change-byte-pos
|
|
|
|
bit-pos>> #bits + dup 8 >= [
|
|
|
|
8 - bs (>>bit-pos)
|
|
|
|
bs [ 1 + ] change-byte-pos drop
|
|
|
|
] [
|
|
|
|
bs (>>bit-pos)
|
|
|
|
] if ;
|
|
|
|
|
2009-05-15 15:08:56 -04:00
|
|
|
:: (peek) ( n bs endian> subseq-endian -- bits )
|
2009-05-15 00:33:00 -04:00
|
|
|
n bs enough-bits? [ n bs not-enough-bits ] unless
|
|
|
|
bs [ byte-pos>> ] [ bit-pos>> n + ] bi #bits>#bytes dupd +
|
2009-05-15 15:08:56 -04:00
|
|
|
bs bytes>> subseq endian> execute( seq -- x ) :> bignum
|
|
|
|
bignum n bs subseq-endian execute( bignum n bs -- bits ) ;
|
2009-05-15 00:33:00 -04:00
|
|
|
|
2009-05-15 15:08:56 -04:00
|
|
|
M: lsb0-bit-reader peek ( n bs -- bits ) \ le> \ subseq>bits-le (peek) ;
|
2009-05-15 00:33:00 -04:00
|
|
|
|
2009-05-15 15:08:56 -04:00
|
|
|
M: msb0-bit-reader peek ( n bs -- bits ) \ be> \ subseq>bits-be (peek) ;
|
2009-05-15 00:33:00 -04:00
|
|
|
|
|
|
|
:: bit-writer-bytes ( writer -- bytes )
|
|
|
|
writer widthed>> #bits>> :> n
|
|
|
|
n 0 = [
|
|
|
|
writer widthed>> bits>> 8 n - shift
|
|
|
|
writer bytes>> swap push
|
|
|
|
] unless
|
|
|
|
writer bytes>> ;
|
2009-06-03 22:21:51 -04:00
|
|
|
|
|
|
|
:: byte-array-n>seq ( byte-array n -- seq )
|
|
|
|
byte-array length 8 * n / iota
|
|
|
|
byte-array <msb0-bit-reader> '[
|
|
|
|
drop n _ read
|
|
|
|
] { } map-as ;
|