This kata complements Clean Code: Advanced TDD, Ep. 20 and Clean Code: Advanced TDD, Ep. 21.
This repository contains two exercises designed to improve your skills in test-driven development.
We will work on a telemetry system for a remote control car project. Bandwidth in the telemetry system is at a premium and you have been asked to implement a message protocol for communicating telemetry data.
Data is transmitted in a buffer (byte array). When integers are sent, the size of the buffer is reduced by employing the protocol described below.
Each value should be represented in the smallest possible C integral type
(types of char
and unsigned char
are not included as the saving would be
trivial):
From | To | Type |
---|---|---|
4'294'967'296 | 9'223'372'036'854'775'807 | long |
2'147'483'648 | 4'294'967'295 | unsigned int |
65'536 | 2'147'483'647 | int |
0 | 65'535 | unsigned short |
-32'768 | -1 | short |
-2'147'483'648 | -32'769 | int |
-9'223'372'036'854'775'808 | -2'147'483'649 | long |
The value should be converted to the appropriate number of bytes for its assigned type. The complete internal 9-byte buffer comprises three parts:
- prefix byte: a byte indicating the number of the payload bytes in the buffer;
- payload bytes: the bytes holding the integer;
- trailing bytes: the zero-fill bytes to complete the buffer.
To distinguish between signed and unsigned types, the protocol introduces a
little trick: for signed types, their prefix byte value is 256
minus the
number of payload bytes in the buffer.
Implement the static method TelemetryBuffer.to_buffer()
to encode a buffer
taking an integer value passed to the method.
// Type: unsigned short, bytes: 2, signed: no, prefix byte: 2
TelemetryBuffer::to_buffer(5);
// => {0x2, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
// Type: int, bytes: 4, signed: yes, prefix byte: 256 - 4
TelemetryBuffer::to_buffer(2'147'483'647);
// => {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0}
Hint
The
BitConverter
class provides a convenient way of converting integer types to and from arrays of bytes.
Implement the static method TelemetryBuffer.from_buffer()
to decode the
buffer received, and return the value in the form of an integer.
TelemetryBuffer::from_buffer({0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0});
// => 2'147'483'647
If the prefix byte is of unexpected value, then return 0
.
Note
For type sizes, we assume a typical 64-bit system.
The C language provides a number of types that represent integers, each with its own range of values. The ranges are determined by the storage width of the type as allocated by the system:
Type | Width | Minimum | Maximum |
---|---|---|---|
char |
8 bit | -128 | +127 |
short |
16 bit | -32'768 | +32'767 |
int |
32 bit | -2'147'483'648 | +2'147'483'647 |
long |
64 bit | -9'223'372'036'854'775'808 | +9'223'372'036'854'775'807 |
unsigned char |
8 bit | 0 | +255 |
unsigned short |
16 bit | 0 | +65'535 |
unsigned int |
32 bit | 0 | +4'294'967'295 |
unsigned long |
64 bit | 0 | +18'446'744'073'709'551'615 |
You can import this project into Replit, and it will handle all dependencies automatically.
make build
make run
make test