Last active
October 7, 2016 12:20
-
-
Save jocelyn/855f400f2d466382902d5cb81cec94ab to your computer and use it in GitHub Desktop.
Proposition to have a byte array solution within Eiffel libs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| note | |
| description: "[ | |
| Representation for byte array (item value between 0 and 255). | |
| Could be useful in protocol, encoding, ... computations. | |
| It provides useful representations as hex, bin, and also generic base N representation ... | |
| ]" | |
| date: "$Date$" | |
| revision: "$Revision$" | |
| class | |
| BYTE_ARRAY | |
| inherit | |
| ITERABLE [NATURAL_8] | |
| READABLE_INDEXABLE [NATURAL_8] | |
| rename | |
| upper as count | |
| end | |
| create | |
| make, | |
| make_from_string, | |
| make_from_hex_string, | |
| make_from_bin_string, | |
| make_from_base_n_string | |
| feature {NONE} -- Initialization | |
| make (nb: INTEGER) | |
| -- Create current byte array with a capacity of `nb' items. | |
| do | |
| create string.make (nb) | |
| end | |
| make_from_string (s: READABLE_STRING_8) | |
| -- Create current byte array from string, i.e an array of character 8 values, i.e from 0 to 255. | |
| do | |
| string := s | |
| end | |
| make_from_hex_string (hex: READABLE_STRING_8) | |
| -- Create Current byte array from hexadecimal representation of byte array `hex'. | |
| -- each item is represented by 2 hexadecimal characters, that represents a byte from 0 to 255 | |
| -- i.e from 00 to FF. | |
| do | |
| make_from_base_n_string (hex, 16, 2) | |
| end | |
| make_from_bin_string (a_bin_string: READABLE_STRING_8) | |
| -- Create Current byte array from binary representation of byte array `a_bin_string'. | |
| -- each item is represented by 8 bin characters, for a value between 0 to 255 | |
| -- i.e from 0000 0000 to 1111 1111. | |
| local | |
| i,j,n: INTEGER | |
| c: CHARACTER_8 | |
| s: STRING | |
| f, v: NATURAL_8 | |
| do | |
| n := a_bin_string.count | |
| create s.make (n // 8) | |
| string := s | |
| from | |
| i := n | |
| until | |
| i <= 0 | |
| loop | |
| v := 0 | |
| from | |
| j := 1 | |
| f := 1 | |
| until | |
| j > 8 or i < 1 | |
| loop | |
| c := a_bin_string [i] | |
| if c = '1' then | |
| v := v + f -- * 1 | |
| end | |
| f := f * 2 -- base = 2 | |
| j := j + 1 | |
| i := i - 1 | |
| end | |
| s.prepend_character (v.to_character_8) | |
| end | |
| end | |
| make_from_base_n_string (a_base_string: READABLE_STRING_8; a_base: NATURAL_8; a_char_len: INTEGER) | |
| -- Create Current byte array from base representation of byte array `a_base_string'. | |
| -- each item is represented by `a_char_len' characters, for a value between 0 to 255 | |
| require | |
| char_len_big_enough: a_char_len >= number_of_characters_required_for_base_n_representation (255, a_base) | |
| local | |
| i,j,n: INTEGER | |
| c: CHARACTER_8 | |
| s: STRING | |
| n8, v: NATURAL_8 | |
| f: NATURAL_8 | |
| do | |
| n := a_base_string.count | |
| create s.make (n // a_char_len) | |
| string := s | |
| from | |
| i := n | |
| until | |
| i <= 0 | |
| loop | |
| v := 0 | |
| from | |
| j := 1 | |
| f := 1 | |
| until | |
| j > a_char_len or i < 1 | |
| loop | |
| c := a_base_string [i] | |
| n8 := base_n_character_to_natural (c) | |
| v := v + n8 * f | |
| f := f * a_base | |
| j := j + 1 | |
| i := i - 1 | |
| end | |
| s.append_character (v.to_character_8) | |
| end | |
| end | |
| feature -- Access | |
| lower: INTEGER = 1 | |
| -- Lower index; | |
| count: INTEGER | |
| -- Count of items. | |
| -- (also knows as upper). | |
| do | |
| Result := string.count | |
| end | |
| natural_8_item, item alias "[]" (i: INTEGER): NATURAL_8 | |
| -- Item at index `i' represented as natural value. | |
| do | |
| Result := string.item_code (i).as_natural_8 | |
| end | |
| string: STRING_8 | |
| -- String representation of Current byte array. | |
| -- Each natural 8 item is represented by the associated character with same code. | |
| feature -- Element change | |
| prepend (a_byte: NATURAL_8) | |
| -- Prepend `a_byte' to Current byte array. | |
| do | |
| string.prepend_character (a_byte.to_character_8) | |
| end | |
| extend (a_byte: NATURAL_8) | |
| -- Extend `a_byte' to Curren byte array. | |
| do | |
| string.append_character (a_byte.to_character_8) | |
| end | |
| insert_byte (a_byte: NATURAL_8; i: INTEGER) | |
| -- Insert `a_byte' at index `i', shifting bytes between ranks | |
| -- `i' and `count' rightwards. | |
| require | |
| valid_insertion_index: 1 <= i and i <= count + 1 | |
| do | |
| string.insert_character (a_byte.to_character_8, i) | |
| end | |
| remove (i: INTEGER) | |
| -- Remove `i'-th byte. | |
| require | |
| valid_index: valid_index (i) | |
| do | |
| string.remove (i) | |
| end | |
| remove_sub_array (start_index, end_index: INTEGER) | |
| -- Remove all bytes from `start_index' to `end_index' inclusive. | |
| require | |
| valid_start_index: 1 <= start_index | |
| valid_end_index: end_index <= count | |
| meaningful_interval: start_index <= end_index + 1 | |
| do | |
| string.remove_substring (start_index, end_index) | |
| end | |
| append (a_byte_array: BYTE_ARRAY) | |
| do | |
| across | |
| a_byte_array as ic | |
| loop | |
| extend (ic.item) | |
| end | |
| end | |
| sub_array (start_index, end_index: INTEGER): like Current | |
| require | |
| valid_start_index: 1 <= start_index | |
| valid_end_index: end_index <= count | |
| meaningful_interval: start_index <= end_index + 1 | |
| do | |
| create Result.make_from_string (string.substring (start_index, end_index)) | |
| end | |
| feature -- Access and item representations. | |
| integer_8_item (i: INTEGER): INTEGER_8 | |
| -- Item at index `i' represented as integer value from -128 to 127. | |
| require | |
| valid_index: valid_index (i) | |
| local | |
| n8: like natural_8_item | |
| do | |
| n8 := natural_8_item (i) | |
| if n8 >= 128 then | |
| Result := (-256 + n8.as_integer_32).to_integer_8 | |
| else | |
| Result := n8.to_integer_8 | |
| end | |
| end | |
| base_n_item (i: INTEGER; a_base: NATURAL_8; a_char_len: INTEGER): STRING_8 | |
| -- Item at index `i' represented with base `a_base' and using `a_char_len' characters. | |
| -- Support base from 2 to 10 (bin to decimal). | |
| require | |
| valid_index: valid_index (i) | |
| accepted_base: 2 <= a_base and then a_base <= 36 | |
| char_len_big_enough: a_char_len >= number_of_characters_required_for_base_n_representation (255, a_base) | |
| local | |
| n8: NATURAL_8 | |
| q8,r8: NATURAL_8 | |
| do | |
| n8 := natural_8_item (i) | |
| create Result.make (a_char_len) | |
| from | |
| until | |
| n8 = 0 | |
| loop | |
| if n8 < a_base then | |
| prepend_based_natural_8_to (n8, a_base, Result) | |
| n8 := 0 | |
| else | |
| q8 := n8 // a_base | |
| r8 := n8 - q8 * a_base | |
| prepend_based_natural_8_to (r8, a_base, Result) | |
| n8 := q8 | |
| end | |
| end | |
| if Result.count < a_char_len then | |
| from | |
| until | |
| Result.count >= a_char_len | |
| loop | |
| Result.prepend_character ('0') | |
| end | |
| end | |
| end | |
| hex_item (i: INTEGER): STRING_8 | |
| -- Item at index `i' represented as hexadecimal value. | |
| require | |
| valid_index: valid_index (i) | |
| do | |
| Result := item (i).to_hex_string | |
| if Result.count = 1 then | |
| Result.prepend_character ('0') | |
| end | |
| end | |
| oct_item (i: INTEGER): STRING_8 | |
| -- Item at index `i' represented as octal value on 3 characters. | |
| require | |
| valid_index: valid_index (i) | |
| do | |
| Result := base_n_item (i, 8, 3) | |
| end | |
| bin_item (i: INTEGER): STRING_8 | |
| -- Item at index `i' represented as binary value on 8 characters. | |
| require | |
| valid_index: valid_index (i) | |
| local | |
| n8: NATURAL_8 | |
| j,v: INTEGER | |
| do | |
| n8 := natural_8_item (i) | |
| create Result.make_filled ('0', 8) | |
| from | |
| j := 8 | |
| v := 128 -- 2 ^ 7 | |
| until | |
| j = 0 | |
| loop | |
| if n8 & v = v then | |
| Result [8 - j + 1] := '1' | |
| else | |
| Result [8 - j + 1] := '0' | |
| end | |
| v := v // 2 | |
| j := j - 1 | |
| end | |
| end | |
| feature -- Status report | |
| valid_index (i: INTEGER): BOOLEAN | |
| -- Is `i' a valid index? | |
| do | |
| Result := 1 <= i and i <= count | |
| end | |
| feature -- Conversion | |
| to_integer_8_array: ARRAY [INTEGER_8] | |
| -- Integer 8 array representation of Current. | |
| -- following format of `integer_8_item'. | |
| local | |
| i,n: INTEGER | |
| do | |
| from | |
| i := 1 | |
| n := count | |
| create Result.make_filled ({INTEGER_8} 0, i, n) | |
| until | |
| i > n | |
| loop | |
| Result[i] := integer_8_item (i) | |
| i := i + 1 | |
| end | |
| end | |
| feature -- Conversion settings | |
| is_lower_case: BOOLEAN | |
| -- Using lower case of string generation (default). | |
| do | |
| Result := not is_upper_case | |
| end | |
| is_upper_case: BOOLEAN | |
| -- Using upper case of string generation. | |
| string_output_item_separator: detachable READABLE_STRING_8 | |
| -- Optional item separator in string output representations. | |
| feature -- Conversion settings change | |
| use_lower_case | |
| -- String generation is using lowercase letters. | |
| -- relevant for encoding with base > 10. | |
| -- Default. | |
| do | |
| is_upper_case := False | |
| end | |
| use_upper_case | |
| -- String generation is using uppercase letters. | |
| -- relevant for encoding with base > 10. | |
| do | |
| is_upper_case := True | |
| end | |
| set_string_output_item_separator (s: detachable READABLE_STRING_8) | |
| -- Set optional item separator in string output representations `string_output_item_separator' to `s'. | |
| do | |
| string_output_item_separator := s | |
| end | |
| feature -- Conversion to string | |
| append_hex_string_to (a_string: STRING_GENERAL) | |
| -- Append to `a_string' the byte array representation with sequence of 2 hexadecimal characters. | |
| local | |
| i,n: INTEGER | |
| s: like string_output_item_separator | |
| do | |
| s := string_output_item_separator | |
| from | |
| i := 1 | |
| n := count | |
| until | |
| i > n | |
| loop | |
| if s /= Void and i > 1 then | |
| a_string.append (s) | |
| end | |
| a_string.append (hex_item (i)) | |
| i := i + 1 | |
| end | |
| end | |
| append_dec_string_to (a_string: STRING_GENERAL) | |
| -- Append to `a_string' the byte array representation with sequence of 3 decimal characters. | |
| do | |
| append_base_n_string_to (a_string, 10, 3) | |
| end | |
| append_oct_string_to (a_string: STRING_GENERAL) | |
| -- Append to `a_string' the byte array representation with sequence of 3 octal characters. | |
| do | |
| append_base_n_string_to (a_string, 8, 3) | |
| end | |
| append_bin_string_to (a_string: STRING_GENERAL) | |
| -- Append to `a_string' the byte array representation with sequence of 8 binary characters. | |
| local | |
| i,n: INTEGER | |
| s: like string_output_item_separator | |
| do | |
| s := string_output_item_separator | |
| from | |
| i := 1 | |
| n := count | |
| until | |
| i > n | |
| loop | |
| if s /= Void and i > 1 then | |
| a_string.append (s) | |
| end | |
| a_string.append (bin_item (i)) | |
| i := i + 1 | |
| end | |
| end | |
| append_base_n_string_to (a_string: STRING_GENERAL; a_base: NATURAL_8; a_char_len: INTEGER) | |
| -- Append to `a_string' the byte array representation with sequence of `a_char_len' characters formatted with base `a_base'. | |
| require | |
| char_len_big_enough: a_char_len >= number_of_characters_required_for_base_n_representation (255, a_base) | |
| accepted_base: 2 <= a_base and then a_base <= 36 | |
| local | |
| i,n: INTEGER | |
| s: like string_output_item_separator | |
| do | |
| s := string_output_item_separator | |
| from | |
| i := 1 | |
| n := count | |
| until | |
| i > n | |
| loop | |
| if s /= Void and i > 1 then | |
| a_string.append (s) | |
| end | |
| a_string.append (base_n_item (i, a_base, a_char_len)) | |
| i := i + 1 | |
| end | |
| end | |
| to_hex_string: STRING_8 | |
| -- Byte array representation with sequence of 2 hexadecimal characters. | |
| do | |
| create Result.make (2 * count) | |
| append_hex_string_to (Result) | |
| end | |
| to_dec_string: STRING_8 | |
| -- Byte array representation with sequence of 3 decimal characters. | |
| do | |
| Result := to_base_n_string (10, 3) | |
| end | |
| to_oct_string: STRING_8 | |
| -- Byte array representation with sequence of 3 octal characters. | |
| do | |
| Result := to_base_n_string (8, 3) | |
| end | |
| to_bin_string: STRING_8 | |
| -- Byte array representation with sequence of 8 binary characters. | |
| do | |
| create Result.make (2 * count) | |
| append_bin_string_to (Result) | |
| ensure | |
| across Result as ic all ic.item = '0' or ic.item = '1' or (attached string_output_item_separator as s and then s.has (ic.item)) end | |
| end | |
| to_base_n_string (a_base: NATURAL_8; a_char_len: INTEGER): STRING_8 | |
| -- Byte array representation with sequence of `a_char_len' characters formatted with base `a_base'. | |
| require | |
| char_len_big_enough: a_char_len >= number_of_characters_required_for_base_n_representation (255, a_base) | |
| accepted_base: 2 <= a_base and then a_base <= 36 | |
| do | |
| create Result.make (a_char_len * count) | |
| append_base_n_string_to (Result, a_base, a_char_len) | |
| end | |
| to_base_n_string_with_separator (a_base: NATURAL_8; a_char_len: INTEGER; sep: READABLE_STRING_8): STRING_8 | |
| -- Byte array representation with sequence of `a_char_len' characters formatted with base `a_base'. | |
| require | |
| char_len_big_enough: a_char_len >= number_of_characters_required_for_base_n_representation (255, a_base) | |
| accepted_base: 2 <= a_base and then a_base <= 36 | |
| local | |
| l_old_sep: like string_output_item_separator | |
| do | |
| l_old_sep := string_output_item_separator | |
| set_string_output_item_separator (sep) | |
| Result := to_base_n_string (a_base, a_char_len) | |
| set_string_output_item_separator (l_old_sep) | |
| end | |
| feature -- Helpers | |
| number_of_characters_required_for_base_n_representation (a_value: NATURAL_8; a_base: NATURAL_8): NATURAL_8 | |
| -- Number of character needed to represent `a_value' using base N `a_base'. | |
| local | |
| v: NATURAL_8 | |
| do | |
| from | |
| v := a_value | |
| until | |
| v = 0 | |
| loop | |
| v := v // a_base | |
| Result := Result + 1 | |
| end | |
| end | |
| feature {NONE} -- Implementation | |
| prepend_based_natural_8_to (a_value: NATURAL_8; a_base: NATURAL_8; a_string: STRING) | |
| -- Prepend `a_value' to a_string using `a_base' encoding. | |
| require | |
| valid_value: a_value < a_base | |
| accepted_base: 2 <= a_base and then a_base <= 36 | |
| do | |
| if a_value < 10 or a_base <= 10 then | |
| a_string.prepend (a_value.out) | |
| elseif is_lower_case then | |
| a_string.prepend_character ('a' + a_value - 10) | |
| else | |
| check is_upper_case end | |
| a_string.prepend_character ('A' + a_value - 10) | |
| end | |
| end | |
| base_n_character_to_natural (c: CHARACTER_8): NATURAL_8 | |
| -- Natural 8 value for base n encoded character `c'. | |
| do | |
| inspect c | |
| when '0' then | |
| Result := {NATURAL_8} 0 | |
| when '1' then | |
| Result := {NATURAL_8} 1 | |
| when '2' then | |
| Result := {NATURAL_8} 2 | |
| when '3' then | |
| Result := {NATURAL_8} 3 | |
| when '4' then | |
| Result := {NATURAL_8} 4 | |
| when '5' then | |
| Result := {NATURAL_8} 5 | |
| when '6' then | |
| Result := {NATURAL_8} 6 | |
| when '7' then | |
| Result := {NATURAL_8} 7 | |
| when '8' then | |
| Result := {NATURAL_8} 8 | |
| when '9' then | |
| Result := {NATURAL_8} 9 | |
| else | |
| if 'a' <= c and c <= 'z' then | |
| Result := ((c.code - ('a').code) + 10).as_natural_8 | |
| elseif 'A' <= c and c <= 'Z' then | |
| Result := ((c.code - ('A').code) + 10).as_natural_8 | |
| else | |
| check is_hexa: False end | |
| end | |
| end | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class TEST_BYTE_ARRAY | |
| create | |
| make | |
| feature -- Initialization | |
| make | |
| do | |
| test | |
| end | |
| test | |
| local | |
| ba, ba2: BYTE_ARRAY | |
| do | |
| create ba.make_from_hex_string ("ABCDEFABCDEF") | |
| print ("HEX " + ba.to_hex_string + "%N") | |
| print ("DEC " + ba.to_dec_string + "%N") | |
| print ("OCT " + ba.to_oct_string + "%N") | |
| print ("BIN " + ba.to_bin_string + "%N") | |
| print ("Base2 " + ba.to_base_n_string_with_separator (2, 8, ",") + "%N") | |
| print ("Base8 " + ba.to_base_n_string_with_separator (8, 3, ",") + "%N") | |
| print ("Base10 " + ba.to_base_n_string_with_separator (10, 3, ",") + "%N") | |
| create ba2.make_from_base_n_string (ba.to_base_n_string (10, 6), 10, 6) | |
| create ba2.make_from_bin_string (ba.to_bin_string) | |
| check ba2.to_hex_string.same_string (ba.to_hex_string) end | |
| print ("#Base2 " + ba2.to_base_n_string_with_separator (2, 8, ":") + "%N") | |
| print ("Base2 " + ba.to_base_n_string_with_separator (2, 8, ":") + "%N") | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment