Advertisement
rplantiko

A class for bit fields

Sep 26th, 2014
742
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
ABAP 8.88 KB | None | 0 0
  1. * A class for bit fields. A bit fields is simply an array of bits
  2. * The bits are packed into bytes
  3. * and there is an integer for the total number of bits
  4. * Further documentation on how it works -> See unit test at the bottom
  5.  
  6. class lcl_bit_field definition.
  7.  
  8.   public section.
  9.  
  10.     data: gv_bytes type xstring read-only,
  11.           gv_bits  type i read-only value 0.  " Total number of bits
  12.  
  13.     methods:
  14.       constructor
  15.         importing iv_data type xsequence optional
  16.                   iv_bits type i default -1,
  17.       shift_right
  18.         importing iv_bits        type i
  19.         returning value(eo_bits) type ref to lcl_bit_field,
  20.       append
  21.         importing
  22.           io_bit_field type ref to lcl_bit_field,
  23.       append_bits
  24.         importing
  25.           iv_data type xsequence
  26.           iv_bits type i default -1,
  27.       append_int2
  28.         importing
  29.           iv_int2 type i,
  30.       clear.
  31.  
  32.   private section.
  33.     constants:
  34. * Powers of 2, needed for right-shift operation
  35.       gc_pow2         type x length 8 value
  36.         '0102040810204080',
  37. * Powers of 2, indexed reversely, needed for right-shift operation
  38.       gc_pow2_reverse type x length 9 value
  39.         '008040201008040201',
  40. * Masking the final byte to the top N significant bits
  41.       gc_bitmask      type x length 9 value
  42.         '0080C0E0F0F8FCFEFF'.
  43.  
  44.  
  45. endclass.
  46.  
  47. class lcl_bit_field implementation.
  48.   method constructor.
  49.     data: lv_last_byte(1) type x,
  50.           lv_last_bits    type i,
  51.           lv_bytes        type xstring.
  52.     if iv_bits eq -1.
  53. * Default: Take complete xstring, no bit remainder
  54.       if iv_data is supplied.
  55.         gv_bytes = iv_data.
  56.       endif.
  57.       gv_bits  = 8 * xstrlen( gv_bytes ).
  58.     elseif iv_bits > 0.
  59.       gv_bits = iv_bits.
  60. * Bits specified: Compute bytes and bit remainder
  61.       lv_bytes     = iv_bits div 8.
  62.       lv_last_bits = iv_bits mod 8.
  63. * Is there a remainder?
  64.       if lv_last_bits > 0.
  65. * Yes: Mask the top n significant bits of the last byte
  66.         lv_last_byte = iv_data+lv_bytes(1).
  67.         lv_last_byte = lv_last_byte bit-and gc_bitmask+lv_last_bits(1).
  68.         if lv_bytes > 0.
  69.           gv_bytes = iv_data(lv_bytes) && lv_last_byte.
  70.         else.
  71.           gv_bytes = lv_last_byte.
  72.         endif.
  73.       else.
  74. * No: Take the full number iv_bits/8 of bytes
  75.         gv_bytes = iv_data(lv_bytes).
  76.       endif.
  77.     endif.
  78.   endmethod.
  79.  
  80.   method shift_right.
  81.  
  82.     data: lv_bytes       type xstring,
  83.           lv_shift_bytes type i,
  84.           lv_shift_bits  type i,
  85.           lv_last        type x,
  86.           lv_off         type i,
  87.           lv_div         type x,
  88.           lv_mod         type x.
  89.  
  90.     field-symbols: <lv_bytes> type xstring.
  91.  
  92.     if iv_bits > 0.
  93.  
  94. * Real change: Shift by iv_bits bits
  95.  
  96.       assign lv_bytes to <lv_bytes>.
  97.  
  98. * Compute number of bytes and remainder
  99.       lv_shift_bytes = iv_bits div 8.
  100.       lv_shift_bits  = iv_bits mod 8.
  101.  
  102. * Shift each original byte by lv_shift_bits bits
  103.       do xstrlen( gv_bytes ) times.
  104.         lv_off = sy-index - 1.
  105. * Split byte at the position given by lv_shift_bits.
  106.         lv_div = gv_bytes+lv_off(1) div gc_pow2+lv_shift_bits(1).
  107.         lv_mod = gv_bytes+lv_off(1) mod gc_pow2+lv_shift_bits(1).
  108. * Make upper part of current byte to lower part of last byte:
  109.         lv_last = lv_last bit-or lv_div.
  110.         lv_bytes = lv_bytes && lv_last.
  111. * Make lower part of current byte to lower part of next byte
  112.         lv_last = lv_mod * gc_pow2_reverse+lv_shift_bits(1).
  113.       enddo.
  114.       lv_bytes = lv_bytes && lv_last.
  115.  
  116.       do lv_shift_bytes times.
  117.         lv_bytes = '00' && lv_bytes.
  118.       enddo.
  119.  
  120.     else.
  121.  
  122. * Identical Operation: Shift by 0 bits
  123.       assign gv_bytes to <lv_bytes>.
  124.  
  125.     endif.
  126.  
  127.     eo_bits = new lcl_bit_field( iv_data = <lv_bytes>
  128.                                  iv_bits = gv_bits + iv_bits ).
  129.  
  130.   endmethod.
  131.   method append.
  132.     if gv_bits mod 8 = 0.
  133.       gv_bytes = gv_bytes && io_bit_field->gv_bytes.
  134.     else.
  135.       data(lo_bit_field) = io_bit_field->shift_right( gv_bits mod 8 ).
  136.       data(lv_offset_last) = gv_bits div 8.
  137.       data: lv_byte(1) type x.
  138.       if lv_offset_last > 0.
  139.         lv_byte = gv_bytes+lv_offset_last(1).
  140.         gv_bytes = gv_bytes(lv_offset_last).
  141.       else.
  142.         lv_byte = gv_bytes.
  143.         clear gv_bytes.
  144.       endif.
  145.       lv_byte = lv_byte bit-or io_bit_field->gv_bytes(1).
  146.       gv_bytes = gv_bytes && lv_byte.
  147.       if xstrlen( io_bit_field->gv_bytes ) > 1.
  148.         gv_bytes = gv_bytes && io_bit_field->gv_bytes+1.
  149.       endif.
  150.     endif.
  151.     gv_bits = gv_bits + io_bit_field->gv_bits.
  152.   endmethod.
  153.   method append_bits.
  154.     data(lo_bits) = new lcl_bit_field( iv_data = iv_data iv_bits = iv_bits ).
  155.     append( lo_bits ).
  156.   endmethod.
  157.   method append_int2.
  158.     data: lv_int2(2) type x.
  159.  
  160.     assert iv_int2 < 65536.
  161.  
  162. * Little Endian
  163.     lv_int2(1)   = iv_int2 mod 256.
  164.     lv_int2+1(1) = iv_int2 div 256.
  165.  
  166.     append_bits( lv_int2 ).
  167.  
  168.   endmethod.
  169.   method clear.
  170.     clear: gv_bytes, gv_bits.
  171.   endmethod.
  172. endclass.
  173.  
  174.  
  175. * ---------------------------------------------------------------------------
  176. * U N I T   T E S T S  F O R  B I T F I E L D
  177. * ---------------------------------------------------------------------------
  178.  
  179. class lcl_test_bit_field definition for testing
  180.   risk level harmless
  181.   duration short.
  182.  
  183.  
  184.   private section.
  185.     methods:
  186.       test_void for testing,
  187.       test_simple for testing,
  188.       test_shift for testing,
  189.       test_append for testing.
  190. endclass.
  191.  
  192. class lcl_assert definition for testing.
  193.   public section.
  194.     class-methods:
  195.       equals
  196.         importing
  197.           exp type any
  198.           act type any
  199.           msg type csequence optional.
  200. endclass.
  201.  
  202. class lcl_test_bit_field implementation.
  203.   method test_simple.
  204.     data: lo_bits type ref to lcl_bit_field.
  205.  
  206.     lo_bits = new #( iv_data = '80' iv_bits = 1 ).
  207.     lcl_assert=>equals( act = lo_bits->gv_bytes
  208.                    exp = '80' ).
  209.     lcl_assert=>equals( act = lo_bits->gv_bits
  210.                    exp = 1 ).
  211.  
  212.     lo_bits = new #( iv_data = 'B0' iv_bits = 3 ).
  213.     lcl_assert=>equals( act = lo_bits->gv_bytes
  214.                    exp = 'A0' ).
  215.     lcl_assert=>equals( act = lo_bits->gv_bits
  216.                    exp = 3 ).
  217.  
  218.     lo_bits = new #( iv_data = 'FFFF' iv_bits = 9 ).
  219.     lcl_assert=>equals( act = lo_bits->gv_bytes
  220.                    exp = 'FF80' ).
  221.     lcl_assert=>equals( act = lo_bits->gv_bits
  222.                    exp = 9 ).
  223.   endmethod.
  224.  
  225.   method test_void.
  226.  
  227.     data: lo_bits type ref to lcl_bit_field.
  228.     lo_bits = new #( iv_data = 'FFFF' iv_bits = 0 ).
  229.  
  230.     lcl_assert=>equals( act = xstrlen( lo_bits->gv_bytes )
  231.                    exp = 0 ).
  232.  
  233.     lcl_assert=>equals( act = lo_bits->gv_bits
  234.                    exp = 0 ).
  235.  
  236.     lo_bits->append_bits( 'FF' ).
  237.     lcl_assert=>equals( act = lo_bits->gv_bytes
  238.                         exp = 'FF' ).
  239.  
  240.     lo_bits->clear( ).
  241.     lcl_assert=>equals( act = xstrlen( lo_bits->gv_bytes )
  242.                         exp = 0 ).
  243.     lcl_assert=>equals( act = lo_bits->gv_bits
  244.                         exp = 0 ).
  245.  
  246.  
  247.     lo_bits = new #( ).
  248.     lcl_assert=>equals( act = xstrlen( lo_bits->gv_bytes )
  249.                         exp = 0 ).
  250.  
  251.   endmethod.
  252.  
  253.   method test_append.
  254.  
  255.     data: lo_bf1 type ref to lcl_bit_field,
  256.           lo_bf2 type ref to lcl_bit_field.
  257.  
  258.     lo_bf1 = new #( iv_data = 'A5A5' iv_bits = 9 ).
  259.     lo_bf2 = new #( iv_data = '7A5A' iv_bits = 10 ).
  260.  
  261.     lo_bf1->append( lo_bf2 ).
  262.  
  263.     lcl_assert=>equals( act = lo_bf1->gv_bytes
  264.                    exp = 'A5FA40' ).
  265.  
  266.     lcl_assert=>equals( act = lo_bf1->gv_bits
  267.                    exp = 19 ).
  268.  
  269.  
  270.  
  271.   endmethod.
  272.  
  273.   method test_shift.
  274.  
  275.     data(lo_bits) = new lcl_bit_field( iv_data = 'AFC34B2F' iv_bits = 28 ).
  276.  
  277.     lcl_assert=>equals( act = lo_bits->shift_right( 0 )->gv_bytes
  278.                    exp = lo_bits->gv_bytes ).
  279.  
  280.     lcl_assert=>equals( act = lo_bits->shift_right( 0 )->gv_bits
  281.                    exp = lo_bits->gv_bits ).
  282.  
  283.     lcl_assert=>equals( act = lo_bits->shift_right( 3 )->gv_bytes
  284.                    exp = '15F86964' ).
  285.  
  286.     lcl_assert=>equals( act = lo_bits->shift_right( 20 )->gv_bytes
  287.                    exp = '00000AFC34B2' ).
  288.  
  289.   endmethod.
  290. endclass.
  291.  
  292. class lcl_assert implementation.
  293.   method equals.
  294.  
  295.     data: lv_act type string,
  296.           lv_exp type string,
  297.           lv_type type c.
  298.  
  299.     field-symbols: <lv_act> type any,
  300.                    <lv_exp> type any.
  301.  
  302.     describe field act type lv_type.
  303.     if lv_type ca 'Xy'.
  304.       lv_act = act.
  305.       lv_exp = exp.
  306.       assign lv_act to <lv_act>.
  307.       assign lv_exp to <lv_exp>.
  308.     else.
  309.       assign act to <lv_act>.
  310.       assign exp to <lv_exp>.
  311.     endif.
  312.  
  313.     call method cl_aunit_assert=>assert_equals
  314.       exporting
  315.         exp              = <lv_exp>
  316.         act              = <lv_act>
  317.         msg              = msg.
  318.  
  319.   endmethod.
  320. endclass.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement