Does boost have an "compact optional" where presence is encoded by special value of type?

Viewed 319

I am looking for space efficient implementation of optional (sizeof small_optional<T> == sizeof (T)). So the emptiness is encoded using some special value of T, for example

small_optional<int, -1> 

requires that I never store -1 in the small_optional so -1 can be used as magic value to determine if optional is empty or not.

1 Answers

The markable lib was created for this sole purpose:

Markable 1.0.0

An alternative to boost::optional<T> which does not store an additional bool flag, but encodes the 'empty' state inside T using a special indicated value.

Usage

Do you want to store a possibly missing int? Can you spare value -1? You can use it like this:

using namespace ak_toolkit;
typedef markable<mark_int<int, -1>> opt_int;

opt_int oi;
opt_int o2 (2);

assert (!oi.has_value());
assert (o2.has_value());
assert (o2.value() == 2);

static_assert (sizeof(opt_int) == sizeof(int), "");

Do you want to store a possibly missing std::string, where 'missing' != 'empty'? Can you spare some string values that contain a null character inside, like std::string("\0\0", 2)? This is how you do it:

struct string_marked_value                           // a policy which defines the representaioion of the
  : ak_toolkit::markable_type<std::string>           // 'marked' (special) std::string value
{               
  static std::string marked_value() {                // create the marked value
    return std::string("\0\0", 2);
  }
  static bool is_marked_value(const std::string& v) { // test if a given value is considered marked
    return v.compare(0, v.npos, "\0\0", 2) == 0;
  }
};

typedef ak_toolkit::markable<string_marked_value> opt_str;
opt_str os, oE(std::string(""));

assert (!os.has_value());
assert (oE.has_value());
assert (oE.value() == "");

static_assert (sizeof(opt_str) == sizeof(std::string), "");

Albeit not a Boost library, markable is licensed under Boost Software License, Version 1.0., and is even referred to from the Performance Considerations section of Boosts own optional type:

Performance considerations

[...]

Controlling the size

[...] Therefore, if the size of the objects is critical for your application (e.g., because you want to utilize your CPU cache in order to gain performance) and you have determined you are willing to trade the code clarity, it is recommended that you simply go with type int and use some 'magic value' to represent not-an-int, or use something like markable library.


The background and thought process of the lib is explained in the following blog post from the lib's author:

Related