Thread overview
Packing enums
Jun 29, 2015
qznc
Jun 30, 2015
Nicholas Wilson
Jul 01, 2015
ketmar
June 29, 2015
I stumbled upon this interesting programming challenge [0], which imho should be possible to implement in D. Maybe someone here wants to try.

Task: Given two enums with less than 256 states, pack them into one byte and provide convenient accessor functions.

Something like this:

enum X { A, B, C };
enum Y { foo, bar, baz };
alias both = TwoEnums!(X,Y);
static assert(both.sizeof == 1);
both z;
z.X = B;
z.Y = bar;

Of course, you can generalize to "n enums packed into a minimal number of bytes".


[0] https://news.ycombinator.com/item?id=9800231
June 30, 2015
On Monday, 29 June 2015 at 22:05:47 UTC, qznc wrote:
> I stumbled upon this interesting programming challenge [0], which imho should be possible to implement in D. Maybe someone here wants to try.
>
> Task: Given two enums with less than 256 states, pack them into one byte and provide convenient accessor functions.
>
> Something like this:
>
> enum X { A, B, C };
> enum Y { foo, bar, baz };
> alias both = TwoEnums!(X,Y);
> static assert(both.sizeof == 1);
> both z;
> z.X = B;
> z.Y = bar;
>
> Of course, you can generalize to "n enums packed into a minimal number of bytes".
>
>
> [0] https://news.ycombinator.com/item?id=9800231

Have you tried using bitfields?

 enum X : byte { A, B, C };
 enum Y : byte { foo, bar, baz };


mixin(bitfields!(
        X, "x",    3,
        Y,  "y",    3,
        uint, "",  2));



July 01, 2015
On Monday, 29 June 2015 at 22:05:47 UTC, qznc wrote:

> Something like this:
>
> enum X { A, B, C };
> enum Y { foo, bar, baz };
> alias both = TwoEnums!(X,Y);
> static assert(both.sizeof == 1);
> both z;
> z.X = B;
> z.Y = bar;

that's so easy that it's not even funny...

enum X { A, B, C };
enum Y { foo, bar, baz };


align(1) struct TwoEnums(E0, E1) if (is(E0 == enum) && is(E1 == enum)) {
  private import std.string : format;
  static assert(E0.min >= 0 && E1.min >= 0 && E0.max < 256 && E1.max < 256 && E0.max+E1.max < 256, "enums can't be packed");
  static assert(E0.max > 0 && E1.max > 0, "can't pack dummy enums");
align(1):
  ubyte v_;
  template opDispatch(string mt) {
    static if (mt == E0.stringof) {
      @property E0 implE0 () { return cast(E0)(v_%E0.max); }
      @property void implE0 (E0 nv) { v_ = cast(ubyte)((v_/E0.max)*E0.max+cast(ubyte)nv); }
      alias opDispatch = implE0;
    } else static if (mt == E1.stringof) {
      @property E1 implE1 () { return cast(E1)(v_/E0.max); }
      @property void implE1 (E1 nv) { v_ = cast(ubyte)((v_%E0.max)+cast(ubyte)nv*E0.max); }
      alias opDispatch = implE1;
    } else {
      static assert(0);
    }
  }
}

alias both = TwoEnums!(X, Y);
static assert(both.sizeof == 1);

void main () {
  import std.stdio;
  both z;
  writeln(z.X, " ; ", z.Y, "; v_=", z.v_); // A ; foo; v_=0

  z.X = X.B;
  writeln(z.X, " ; ", z.Y, "; v_=", z.v_); // B ; foo; v_=1

  z.Y = Y.bar;
  writeln(z.X, " ; ", z.Y, "; v_=", z.v_); // B ; bar; v_=3
}