Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- * A class for bit fields. A bit fields is simply an array of bits
- * The bits are packed into bytes
- * and there is an integer for the total number of bits
- * Further documentation on how it works -> See unit test at the bottom
- class lcl_bit_field definition.
- public section.
- data: gv_bytes type xstring read-only,
- gv_bits type i read-only value 0. " Total number of bits
- methods:
- constructor
- importing iv_data type xsequence optional
- iv_bits type i default -1,
- shift_right
- importing iv_bits type i
- returning value(eo_bits) type ref to lcl_bit_field,
- append
- importing
- io_bit_field type ref to lcl_bit_field,
- append_bits
- importing
- iv_data type xsequence
- iv_bits type i default -1,
- append_int2
- importing
- iv_int2 type i,
- clear.
- private section.
- constants:
- * Powers of 2, needed for right-shift operation
- gc_pow2 type x length 8 value
- '0102040810204080',
- * Powers of 2, indexed reversely, needed for right-shift operation
- gc_pow2_reverse type x length 9 value
- '008040201008040201',
- * Masking the final byte to the top N significant bits
- gc_bitmask type x length 9 value
- '0080C0E0F0F8FCFEFF'.
- endclass.
- class lcl_bit_field implementation.
- method constructor.
- data: lv_last_byte(1) type x,
- lv_last_bits type i,
- lv_bytes type xstring.
- if iv_bits eq -1.
- * Default: Take complete xstring, no bit remainder
- if iv_data is supplied.
- gv_bytes = iv_data.
- endif.
- gv_bits = 8 * xstrlen( gv_bytes ).
- elseif iv_bits > 0.
- gv_bits = iv_bits.
- * Bits specified: Compute bytes and bit remainder
- lv_bytes = iv_bits div 8.
- lv_last_bits = iv_bits mod 8.
- * Is there a remainder?
- if lv_last_bits > 0.
- * Yes: Mask the top n significant bits of the last byte
- lv_last_byte = iv_data+lv_bytes(1).
- lv_last_byte = lv_last_byte bit-and gc_bitmask+lv_last_bits(1).
- if lv_bytes > 0.
- gv_bytes = iv_data(lv_bytes) && lv_last_byte.
- else.
- gv_bytes = lv_last_byte.
- endif.
- else.
- * No: Take the full number iv_bits/8 of bytes
- gv_bytes = iv_data(lv_bytes).
- endif.
- endif.
- endmethod.
- method shift_right.
- data: lv_bytes type xstring,
- lv_shift_bytes type i,
- lv_shift_bits type i,
- lv_last type x,
- lv_off type i,
- lv_div type x,
- lv_mod type x.
- field-symbols: <lv_bytes> type xstring.
- if iv_bits > 0.
- * Real change: Shift by iv_bits bits
- assign lv_bytes to <lv_bytes>.
- * Compute number of bytes and remainder
- lv_shift_bytes = iv_bits div 8.
- lv_shift_bits = iv_bits mod 8.
- * Shift each original byte by lv_shift_bits bits
- do xstrlen( gv_bytes ) times.
- lv_off = sy-index - 1.
- * Split byte at the position given by lv_shift_bits.
- lv_div = gv_bytes+lv_off(1) div gc_pow2+lv_shift_bits(1).
- lv_mod = gv_bytes+lv_off(1) mod gc_pow2+lv_shift_bits(1).
- * Make upper part of current byte to lower part of last byte:
- lv_last = lv_last bit-or lv_div.
- lv_bytes = lv_bytes && lv_last.
- * Make lower part of current byte to lower part of next byte
- lv_last = lv_mod * gc_pow2_reverse+lv_shift_bits(1).
- enddo.
- lv_bytes = lv_bytes && lv_last.
- do lv_shift_bytes times.
- lv_bytes = '00' && lv_bytes.
- enddo.
- else.
- * Identical Operation: Shift by 0 bits
- assign gv_bytes to <lv_bytes>.
- endif.
- eo_bits = new lcl_bit_field( iv_data = <lv_bytes>
- iv_bits = gv_bits + iv_bits ).
- endmethod.
- method append.
- if gv_bits mod 8 = 0.
- gv_bytes = gv_bytes && io_bit_field->gv_bytes.
- else.
- data(lo_bit_field) = io_bit_field->shift_right( gv_bits mod 8 ).
- data(lv_offset_last) = gv_bits div 8.
- data: lv_byte(1) type x.
- if lv_offset_last > 0.
- lv_byte = gv_bytes+lv_offset_last(1).
- gv_bytes = gv_bytes(lv_offset_last).
- else.
- lv_byte = gv_bytes.
- clear gv_bytes.
- endif.
- lv_byte = lv_byte bit-or io_bit_field->gv_bytes(1).
- gv_bytes = gv_bytes && lv_byte.
- if xstrlen( io_bit_field->gv_bytes ) > 1.
- gv_bytes = gv_bytes && io_bit_field->gv_bytes+1.
- endif.
- endif.
- gv_bits = gv_bits + io_bit_field->gv_bits.
- endmethod.
- method append_bits.
- data(lo_bits) = new lcl_bit_field( iv_data = iv_data iv_bits = iv_bits ).
- append( lo_bits ).
- endmethod.
- method append_int2.
- data: lv_int2(2) type x.
- assert iv_int2 < 65536.
- * Little Endian
- lv_int2(1) = iv_int2 mod 256.
- lv_int2+1(1) = iv_int2 div 256.
- append_bits( lv_int2 ).
- endmethod.
- method clear.
- clear: gv_bytes, gv_bits.
- endmethod.
- endclass.
- * ---------------------------------------------------------------------------
- * U N I T T E S T S F O R B I T F I E L D
- * ---------------------------------------------------------------------------
- class lcl_test_bit_field definition for testing
- risk level harmless
- duration short.
- private section.
- methods:
- test_void for testing,
- test_simple for testing,
- test_shift for testing,
- test_append for testing.
- endclass.
- class lcl_assert definition for testing.
- public section.
- class-methods:
- equals
- importing
- exp type any
- act type any
- msg type csequence optional.
- endclass.
- class lcl_test_bit_field implementation.
- method test_simple.
- data: lo_bits type ref to lcl_bit_field.
- lo_bits = new #( iv_data = '80' iv_bits = 1 ).
- lcl_assert=>equals( act = lo_bits->gv_bytes
- exp = '80' ).
- lcl_assert=>equals( act = lo_bits->gv_bits
- exp = 1 ).
- lo_bits = new #( iv_data = 'B0' iv_bits = 3 ).
- lcl_assert=>equals( act = lo_bits->gv_bytes
- exp = 'A0' ).
- lcl_assert=>equals( act = lo_bits->gv_bits
- exp = 3 ).
- lo_bits = new #( iv_data = 'FFFF' iv_bits = 9 ).
- lcl_assert=>equals( act = lo_bits->gv_bytes
- exp = 'FF80' ).
- lcl_assert=>equals( act = lo_bits->gv_bits
- exp = 9 ).
- endmethod.
- method test_void.
- data: lo_bits type ref to lcl_bit_field.
- lo_bits = new #( iv_data = 'FFFF' iv_bits = 0 ).
- lcl_assert=>equals( act = xstrlen( lo_bits->gv_bytes )
- exp = 0 ).
- lcl_assert=>equals( act = lo_bits->gv_bits
- exp = 0 ).
- lo_bits->append_bits( 'FF' ).
- lcl_assert=>equals( act = lo_bits->gv_bytes
- exp = 'FF' ).
- lo_bits->clear( ).
- lcl_assert=>equals( act = xstrlen( lo_bits->gv_bytes )
- exp = 0 ).
- lcl_assert=>equals( act = lo_bits->gv_bits
- exp = 0 ).
- lo_bits = new #( ).
- lcl_assert=>equals( act = xstrlen( lo_bits->gv_bytes )
- exp = 0 ).
- endmethod.
- method test_append.
- data: lo_bf1 type ref to lcl_bit_field,
- lo_bf2 type ref to lcl_bit_field.
- lo_bf1 = new #( iv_data = 'A5A5' iv_bits = 9 ).
- lo_bf2 = new #( iv_data = '7A5A' iv_bits = 10 ).
- lo_bf1->append( lo_bf2 ).
- lcl_assert=>equals( act = lo_bf1->gv_bytes
- exp = 'A5FA40' ).
- lcl_assert=>equals( act = lo_bf1->gv_bits
- exp = 19 ).
- endmethod.
- method test_shift.
- data(lo_bits) = new lcl_bit_field( iv_data = 'AFC34B2F' iv_bits = 28 ).
- lcl_assert=>equals( act = lo_bits->shift_right( 0 )->gv_bytes
- exp = lo_bits->gv_bytes ).
- lcl_assert=>equals( act = lo_bits->shift_right( 0 )->gv_bits
- exp = lo_bits->gv_bits ).
- lcl_assert=>equals( act = lo_bits->shift_right( 3 )->gv_bytes
- exp = '15F86964' ).
- lcl_assert=>equals( act = lo_bits->shift_right( 20 )->gv_bytes
- exp = '00000AFC34B2' ).
- endmethod.
- endclass.
- class lcl_assert implementation.
- method equals.
- data: lv_act type string,
- lv_exp type string,
- lv_type type c.
- field-symbols: <lv_act> type any,
- <lv_exp> type any.
- describe field act type lv_type.
- if lv_type ca 'Xy'.
- lv_act = act.
- lv_exp = exp.
- assign lv_act to <lv_act>.
- assign lv_exp to <lv_exp>.
- else.
- assign act to <lv_act>.
- assign exp to <lv_exp>.
- endif.
- call method cl_aunit_assert=>assert_equals
- exporting
- exp = <lv_exp>
- act = <lv_act>
- msg = msg.
- endmethod.
- endclass.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement