Wednesday, August 22, 2012

small integer C++ wrapper

Currently, I'm working on libtins, a library I'm developing with a friend. This library mainly contains classes that abstract PDUs, among other stuff.

Since PDU classes are basically a wrapper over the protocol data units handled by the operating system, getters and setters are provided to enable the user to modify the fields in them. For example, there is a TCP::data_offset method which takes a value of type uint8_t and stores it in the TCP header's data offset field, which is 4 bit wide.

While developing test units for this library, I would use some random number to initialize those fields, and then use the corresponding getter to check that the same number came out of it. A problem that I faced several times is that, there is no way to indicate that, while a setter method takes an uint8_t, the field being set internally is actually 4 bits wide, so any value larger than 15 would overflow, leading to the wrong number being stored. We really want to be able to detect those ugly errors.

One solution would be to, on each setter, check whether the provided value is larger to 2 ** n - 1, where n is the width of the field being set, and raise an exception if this condition is true. This has the drawback that every setter should make the appropriate check, using the appropriate power of 2, and throwing the same exception on each of them. This boilerplate solution already looks nasty.

So I came with a better solution. C++'s implicit conversions can do magic for us. All we need is a class that wraps a value of an arbitrary bit width(up to 64 bits) that performs the corresponding checks while being initialized.

The wrapper class is called small_uint(I thought about providing support for signed integral types, but finally dropped that option. It'd be easy to implement though). The class declaration is this one:

template<size_t n> class small_uint;

The template non-type parameter n indicates the length, in bits, of the field. This class should be optimal, meaning that it should use to smallest integral type that can hold a value of that width.

Internally, a compile time switch is performed to check which is the best underlying type, meaning, the type in which storing the field wastes less space. For example, for 7 bit small_uints, a uint8_t is used, while 11 bit fields will be stored in a member variable of type uint16_t. This underlying type is typedef'ed as the repr_type.

There is a constructor which takes a repr_type and raises an exception if it is larger than the 2 ** n - 1, and a user-defined conversion to repr_type which simply returns the stored value. Since no arithmetic operations are performed with these integers, there are no such operators defined. It don't really know if defining them would make sense. If you wanted to perform such operations, you would just use standard arithmetic types. Only operator== and operator!= have been defined.

I haven't used this class in libtins yet, but setters would probably look like this:

void TCP::data_offset(small_uint<4> value) {
     tcp_header_.data_offset = value;
}

That way, a nice and clean solution can be achieved, avoiding boiler plate code. Note that internally, C++11 features could make a lot of things easier(such as std::numeric_limits<>::max() being constexpr, std::conditional, and constexpr functions), but I wanted to use only C++03 stuff, since the library is intended to work with the latter standard.

The small_uint implementation can be found here.

No comments:

Post a Comment