1 ! Copyright (C) 2009 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.accessors assocs byte-arrays combinators
4 destructors fry io io.binary io.encodings.binary io.streams.byte-array
5 kernel locals macros math math.ranges multiline sequences
6 sequences.private vectors byte-vectors combinators.short-circuit
10 TUPLE: widthed { bits integer read-only } { #bits integer read-only } ;
12 ERROR: invalid-widthed bits #bits ;
14 : check-widthed ( bits #bits -- bits #bits )
15 dup 0 < [ invalid-widthed ] when
16 2dup { [ nip 0 = ] [ drop 0 = not ] } 2&& [ invalid-widthed ] when
18 2dup [ dup 0 < [ neg ] when log2 1 + ] dip > [ invalid-widthed ] when
21 : <widthed> ( bits #bits -- widthed )
25 : zero-widthed ( -- widthed ) 0 0 <widthed> ;
26 : zero-widthed? ( widthed -- ? ) zero-widthed = ;
30 { byte-pos array-capacity initial: 0 }
31 { bit-pos array-capacity initial: 0 } ;
37 TUPLE: msb0-bit-reader < bit-reader ;
38 TUPLE: lsb0-bit-reader < bit-reader ;
40 : <msb0-bit-reader> ( bytes -- bs )
41 msb0-bit-reader new swap >>bytes ; inline
43 : <lsb0-bit-reader> ( bytes -- bs )
44 lsb0-bit-reader new swap >>bytes ; inline
46 TUPLE: msb0-bit-writer < bit-writer ;
47 TUPLE: lsb0-bit-writer < bit-writer ;
49 : new-bit-writer ( class -- bs )
52 0 0 <widthed> >>widthed ; inline
54 : <msb0-bit-writer> ( -- bs )
55 msb0-bit-writer new-bit-writer ;
57 : <lsb0-bit-writer> ( -- bs )
58 lsb0-bit-writer new-bit-writer ;
60 GENERIC: peek ( n bitstream -- value )
61 GENERIC: poke ( value n bitstream -- )
63 : get-abp ( bitstream -- abp )
64 [ byte-pos>> 8 * ] [ bit-pos>> + ] bi ; inline
66 : set-abp ( abp bitstream -- )
67 [ 8 /mod ] dip [ (>>bit-pos) ] [ (>>byte-pos) ] bi ; inline
69 : seek ( n bitstream -- )
70 [ get-abp + ] [ set-abp ] bi ; inline
72 : (align) ( n m -- n' )
73 [ /mod 0 > [ 1 + ] when ] [ * ] bi ; inline
75 : align ( n bitstream -- )
76 [ get-abp swap (align) ] [ set-abp ] bi ; inline
78 : read ( n bitstream -- value )
79 [ peek ] [ seek ] 2bi ; inline
83 ERROR: not-enough-bits widthed n ;
85 : widthed-bits ( widthed n -- bits )
86 dup 0 < [ not-enough-bits ] when
87 2dup [ #bits>> ] dip < [ not-enough-bits ] when
88 [ [ bits>> ] [ #bits>> ] bi ] dip
89 [ - neg shift ] keep <widthed> ;
91 : split-widthed ( widthed n -- widthed1 widthed2 )
92 2dup [ #bits>> ] dip < [
96 [ [ [ bits>> ] [ #bits>> ] bi ] dip - [ bits ] keep <widthed> ] 2bi
99 : widthed>bytes ( widthed -- bytes widthed )
100 [ 8 split-widthed dup zero-widthed? not ]
101 [ swap bits>> ] B{ } produce-as nip swap ;
103 :: |widthed ( widthed1 widthed2 -- widthed3 )
104 widthed1 bits>> :> bits1
105 widthed1 #bits>> :> #bits1
106 widthed2 bits>> :> bits2
107 widthed2 #bits>> :> #bits2
108 bits1 #bits2 shift bits2 bitor
109 #bits1 #bits2 + <widthed> ;
113 M:: lsb0-bit-writer poke ( value n bs -- )
114 value n <widthed> :> widthed
116 bs widthed>> #bits>> 8 swap - split-widthed :> remainder :> byte
117 byte bs widthed>> |widthed :> new-byte
118 new-byte #bits>> 8 = [
119 new-byte bits>> bs bytes>> push
120 zero-widthed bs (>>widthed)
121 remainder widthed>bytes
122 [ bs bytes>> push-all ] [ bs (>>widthed) ] bi*
127 : enough-bits? ( n bs -- ? )
130 [ bit-pos>> - ] tri <= ;
132 ERROR: not-enough-bits n bit-reader ;
134 : #bits>#bytes ( #bits -- #bytes )
135 8 /mod 0 = [ 1 + ] unless ; inline
137 :: subseq>bits-le ( bignum n bs -- bits )
138 bignum bs bit-pos>> neg shift n bits ;
140 :: subseq>bits-be ( bignum n bs -- bits )
142 8 bs bit-pos>> - n - 8 mod dup 0 < [ 8 + ] when
145 :: adjust-bits ( n bs -- )
146 n 8 /mod :> #bits :> #bytes
147 bs [ #bytes + ] change-byte-pos
148 bit-pos>> #bits + dup 8 >= [
150 bs [ 1 + ] change-byte-pos drop
155 :: (peek) ( n bs endian> subseq-endian -- bits )
156 n bs enough-bits? [ n bs not-enough-bits ] unless
157 bs [ byte-pos>> ] [ bit-pos>> n + ] bi #bits>#bytes dupd +
158 bs bytes>> subseq endian> execute( seq -- x ) :> bignum
159 bignum n bs subseq-endian execute( bignum n bs -- bits ) ;
161 M: lsb0-bit-reader peek ( n bs -- bits ) \ le> \ subseq>bits-le (peek) ;
163 M: msb0-bit-reader peek ( n bs -- bits ) \ be> \ subseq>bits-be (peek) ;
165 :: bit-writer-bytes ( writer -- bytes )
166 writer widthed>> #bits>> :> n
168 writer widthed>> bits>> 8 n - shift
169 writer bytes>> swap push
173 :: byte-array-n>seq ( byte-array n -- seq )
174 byte-array length 8 * n / iota
175 byte-array <msb0-bit-reader> '[