nanovec: Vec-packed-in-an-Integer

Ever felt the need to store a few small integers, but Vec (or even [tinyvec]) takes up more space than you'd like?

nanovec offers both fixed- and variable-length arrays of integers with limited range, all packed within one or two machine registers that you can effortlessly lug around.

This crate:

Two space-saving strategies are offered: bit-packing and radix-packing.

Bit-packed arrays

A wide integer (e.g. u64) can be treated as an array of narrower integers (e.g. 16 x 4-bit or 5 x 12-bit). Given the packed integer type (n bits) and the bit-width of each element (k bits), the capacity can be determined as floor(n / k).

Radix-packed arrays

Generalizing the bit-packing approach, a base-r integer can be treated as an array of integers in the range 0..r. A good example is a decimal (base-10) number --- 12345678 can be treated as an array of [8, 7, 6, 5, 4, 3, 2, 1] (least-significant digit first).

This approach allows you to pack even more elements when the range of each element can be more precisely defined. Especially, when r is only marginally larger than 2.pow(k) but a lot smaller than 2.pow(k + 1), packing in base-r can save a lot of space compared to (effectively) packing in base-2.pow(k + 1).

The main drawback of radix-packing is more expensive computations: mul-div-mod vs. bit operations. For this reason, the bit-packed alternatives are preferred as long as they fit.