src/types/IntegerDataTypeReader.h
branchv_0
changeset 45 24a506eb97b5
parent 42 3442e0d6caec
child 46 12c329f5524f
equal deleted inserted replaced
44:bcff4ebca71d 45:24a506eb97b5
    36 
    36 
    37 using namespace relpipe::protocol;
    37 using namespace relpipe::protocol;
    38 using namespace relpipe::reader;
    38 using namespace relpipe::reader;
    39 
    39 
    40 /**
    40 /**
    41  * The prototype does not have various integer and other numeric data types,
    41  * Unsigned variable-length integer.
    42  * it just works with one type of integer.
    42  * ULEB128
    43  * But this integer has variable length -- smaller values occupy only one byte, bigger ones, more bytes 1,2,4,8 + first byte (contains length signalization).
       
    44  * In the real implementation of relational pipes, there will be DataTypes for particular numeric types.
       
    45  * 
       
    46  * TODO: support also big endian architectures.
       
    47  * TODO: throw exception if a value was stored in bigger type than needed (while reading – there should be only one supported way how to encode a single value)
       
    48  * 
       
    49  * Example of encoded values:
       
    50  * -------------------------------------------------------------------------------------------------
       
    51  * $ for n in 0 1 10 250 251 252 65535 65536 4294967295 4294967296 18446744073709551615; do printf '%20s = ' $n; dist/Debug/GNU-Linux/rp-prototype write integer $n | hd | head -n 1; done
       
    52  *                    0 = 00000000  00                                                |.|
       
    53  *                    1 = 00000000  01                                                |.|
       
    54  *                   10 = 00000000  0a                                                |.|
       
    55  *                  250 = 00000000  fa                                                |.|
       
    56  *                  251 = 00000000  fb fb                                             |..|
       
    57  *                  252 = 00000000  fb fc                                             |..|
       
    58  *                65535 = 00000000  fc ff ff                                          |...|
       
    59  *                65536 = 00000000  fd 00 00 01 00                                    |.....|
       
    60  *           4294967295 = 00000000  fd ff ff ff ff                                    |.....|
       
    61  *           4294967296 = 00000000  fe 00 00 00 00 01 00 00  00                       |.........|
       
    62  * 18446744073709551615 = 00000000  fe ff ff ff ff ff ff ff  ff                       |.........|
       
    63  * -------------------------------------------------------------------------------------------------
       
    64  * 
       
    65  * Example of decoded values:
       
    66  * -------------------------------------------------------------------------------------------------
       
    67  * $ for n in 0 1 10 250 251 252 65535 65536 4294967295 4294967296 18446744073709551615; do dist/Debug/GNU-Linux/rp-prototype write integer $n | dist/Debug/GNU-Linux/rp-prototype read integer; done;
       
    68  * 0
       
    69  * 1
       
    70  * 10
       
    71  * 250
       
    72  * 251
       
    73  * 252
       
    74  * 65535
       
    75  * 65536
       
    76  * 4294967295
       
    77  * 4294967296
       
    78  * 18446744073709551615
       
    79  * -------------------------------------------------------------------------------------------------
       
    80  * 
       
    81  * Note: similar format as original idea: https://en.wikipedia.org/wiki/X.690#Length_octets
       
    82  * 
       
    83  */
    43  */
    84 class IntegerDataTypeReader : public DataTypeReader<integer_t> {
    44 class IntegerDataTypeReader : public DataTypeReader<integer_t> {
    85 private:
    45 private:
    86 	static const uint8_t INTEGER_TYPE_UINT8 = 251;
       
    87 	static const uint8_t INTEGER_TYPE_UINT16 = 252;
       
    88 	static const uint8_t INTEGER_TYPE_UINT32 = 253;
       
    89 	static const uint8_t INTEGER_TYPE_UINT64 = 254;
       
    90 	static const uint8_t INTEGER_TYPE_RESERVED = 255;
       
    91 
    46 
    92 	template<typename T> integer_t read(std::istream &input) {
    47 	uint8_t readNextOctet(std::istream &input) {
    93 		T value = 0;
    48 		uint8_t value = input.get();
    94 		input.read(reinterpret_cast<char *> (&value), sizeof (value));
    49 		if (input.good()) return value;
    95 		return value;
    50 		else throw RelpipeReaderException(L"Unable to read next octet of the integer.");
    96 	}
    51 	}
    97 
    52 
    98 public:
    53 public:
    99 
    54 
   100 	IntegerDataTypeReader() : DataTypeReader<integer_t>(TypeId::INTEGER, DATA_TYPE_CODE_INTEGER) {
    55 	IntegerDataTypeReader() : DataTypeReader<integer_t>(TypeId::INTEGER, DATA_TYPE_CODE_INTEGER) {
   101 	}
    56 	}
   102 
    57 
   103 	integer_t readValue(std::istream &input) override {
    58 	integer_t readValue(std::istream &input) override {
   104 		uint8_t first;
    59 		integer_t value = 0;
   105 		input.read(reinterpret_cast<char *> (&first), sizeof (first));
    60 		integer_t shift = 0;
   106 		if (input.good()) {
    61 		octet_t octet;
   107 
    62 		do {
   108 			if (first < INTEGER_TYPE_UINT8) return first;
    63 			octet = readNextOctet(input);
   109 			else if (first == INTEGER_TYPE_UINT8) return read<uint8_t>(input);
    64 			value += integer_t(octet & 0x7F) << shift;
   110 			else if (first == INTEGER_TYPE_UINT16) return read<uint16_t>(input);
    65 			shift += 7;
   111 			else if (first == INTEGER_TYPE_UINT32) return read<uint32_t>(input);
    66 		} while (octet >= 128);
   112 			else if (first == INTEGER_TYPE_UINT64) return read<uint64_t>(input);
    67 		return value;
   113 			else throw RelpipeReaderException(L"Error while parsing integer type: unsupported type");
       
   114 		} else {
       
   115 			throw RelpipeReaderException(L"Error while reading integer from the stream.");
       
   116 		}
       
   117 	}
    68 	}
   118 
    69 
   119 	string_t toString(const integer_t &value) override {
    70 	string_t toString(const integer_t &value) override {
   120 		return std::to_wstring(value);
    71 		return std::to_wstring(value);
   121 	}
    72 	}