Description
Inspired by this question, write a program/function to encode a number and a program (possibly the same as the first) to decode a bitstream in variable-length encoding as follows (taken from that question's answer, slightly modified):
Represent the string x using the following encoding:
$$0, x_k, \dots, 0, x_2, 0, x_1, 1, x_0$$
where \$x_0\$ is just \$x\$, then \$x_{i+1} = \mathrm{len}(x_i)\$ is a binary representation of the length of \$x_i\$ in bits (namely, \$\mathrm{len}(x_i)=\mathrm{ceil}(\log_2 x_i)\$, for \$i \ge 1\$), and \$k\$ is the smallest \$k \ge 1\$ such that \$x_k \le 3\$.
In particular, you always encode \$x_k\$ with 2 bits, and encode \$x_i\$ with \$x_{i+1}\$ bits.
Some example encodings:
Decimal | Encoded |
---|---|
0 | 00110 |
1 | 00111 |
2 | 010110 |
3 | 010111 |
4 | 0111100 |
8 | 011010011000 |
127 | 011011111111111 |
Note that based on this encoding, the first bit is always 0, and the next 2 bits afterwards always encode the length of the next part.
Input/Output
For the encoder, it will take as input a list of non-negative integers, which may be empty (in any list representation you like), and output the string as per the encoding above. When encoding multiple numbers, simply concatenate the encoding. If the input is an empty list, output empty string.
For the decoder, it will take as input a (possibly invalid encoding, but always consists only of 0 and 1) bit string, and output a list of integers it encodes (in the same representation as the input to your encoder). If the string is an invalid encoding, you can output anything that cannot be misconstrued as a valid list of integers. For example, you can just output "INVALID" as the whole output, or you output "X" after outputting partially decoded list of integers (e.g., when the first part of the string is valid, but the later one isn't). As long as your invalid output cannot be read as a list of integers as a whole (in the same representation you use for the encoder input), it's fine. This includes terminating with an exception or a non-zero exit code (since it's also not a valid input to the encoder).
Scoring
This is code golf, the score of an answer is the sum of the number of bytes in both programs. If your program can do both in the same program, the length of that program is the score. Lowest score wins. Standard code golf rules apply.
Test Cases
Some test cases (input, then output on the next line, separated by a blank line):
Encoder
2 010110 1 5 3 001110111101010111 0 0 1 001100011000111 8 127 512 987654321 0110100110000110111111111110110100010101100000000001101010111101111010110111100110100010110001
The last test case is an empty list as input, and empty string as output
Decoder
010110 2 001110111101010111 1 5 3 001100011000111 0 0 1 00111011110010111 Invalid (a new number starts with 1) 1 Invalid (a new number starts with 1) 0011000110001 Invalid (not complete) 001100011001101001100 Invalid (not complete) 0011000110011010 Invalid (not complete) 0110100110000110111111111110110100010101100000000001101010111101111010110111100110100010110001 8 127 512 987654321
The last test case is an empty string, outputting empty list (which is empty string in this case, but it depends on your list representation)
0-3
as100
,101
,110
and111
? \$\endgroup\$3
wasn't encoded as111
... shame.) \$\endgroup\$