| [bf8da66] | 1 | ## Flag Enums ## | 
|---|
|  | 2 |  | 
|---|
|  | 3 | A common programming problem is to represent a value from a set of boolean flags, each of which can be either on or off. C already has enums and bitfields, which can be naturally used to represent the individual flags, but are un-ergonomic to combine together. This proposal introduces "flag enums", a variant of the usual enums specialized to represent flags in a more ergonomic way. | 
|---|
|  | 4 |  | 
|---|
|  | 5 | As an example, a flag enum for the TCP control bits could be defined as follows: | 
|---|
|  | 6 |  | 
|---|
|  | 7 | ``` | 
|---|
|  | 8 | enum TCP_Flags { | 
|---|
|  | 9 | FIN, | 
|---|
|  | 10 | SYN, | 
|---|
|  | 11 | RST, | 
|---|
|  | 12 | PSH, | 
|---|
|  | 13 | ACK, | 
|---|
|  | 14 | URG, | 
|---|
|  | 15 | ECE, | 
|---|
|  | 16 | CWR, | 
|---|
|  | 17 | NS | 
|---|
|  | 18 | } __attribute__((flag)); | 
|---|
|  | 19 | ``` | 
|---|
|  | 20 |  | 
|---|
|  | 21 | The `__attribute__` syntax is ugly, but represents the smallest backwards compatibility break; a new SUE for enum flags (e.g. `flag enum TCP_Flags { ... };` or even `flag TCP_Flags { ... };`) might also be reasonable. | 
|---|
|  | 22 |  | 
|---|
|  | 23 | A flag enum would be different than a normal enum in two ways: it would auto-generate discriminant values differently, and it would have a number of bitwise operators defined on it by default. | 
|---|
|  | 24 |  | 
|---|
|  | 25 | Normal enums generate their discriminant values sequentially starting at zero (`0, 1, 2, 3, ...`), while a flag enum would generate its discriminant values as successive powers of two starting at `1`. E.g. the `TCP_Flags` declaration above would codegen to an enum like below: | 
|---|
|  | 26 |  | 
|---|
|  | 27 | ``` | 
|---|
|  | 28 | enum TCP_Flags { | 
|---|
|  | 29 | FIN = 0x1, | 
|---|
|  | 30 | SYN = 0x2, | 
|---|
|  | 31 | RST = 0x4, | 
|---|
|  | 32 | PSH = 0x8, | 
|---|
|  | 33 | ACK = 0x10, | 
|---|
|  | 34 | URG = 0x20, | 
|---|
|  | 35 | ECE = 0x40, | 
|---|
|  | 36 | CWR = 0x80, | 
|---|
|  | 37 | NS = 0x100 | 
|---|
|  | 38 | }; | 
|---|
|  | 39 | ``` | 
|---|
|  | 40 |  | 
|---|
|  | 41 | The precise rule used would be that if no enum discriminant is given, the discriminant is the smallest power of two larger than the previous discriminant (`1` if there is no previous discriminant). This would allow some flexibility for cases like these: | 
|---|
|  | 42 |  | 
|---|
|  | 43 | ``` | 
|---|
|  | 44 | enum FunFlags { | 
|---|
|  | 45 | NONE = 0,           // Named empty value | 
|---|
|  | 46 | FOO,  // == 0x1 | 
|---|
|  | 47 | BAZ = 0x6,          // Multi-bit flag: 0x4 | 0x2 | 
|---|
|  | 48 | BAR,  // == 0x8 | 
|---|
|  | 49 | FOOBAR = FOO | BAR  // Named combination flag | 
|---|
|  | 50 | } __attribute__((flag)); | 
|---|
|  | 51 | ``` | 
|---|
|  | 52 |  | 
|---|
|  | 53 | Secondly, we would auto-generate a number of useful operators for any flag enum, as follows: | 
|---|
|  | 54 | * The default constructor for any flag enum would be defined, and would produce a flag with an underlying value of 0. | 
|---|
|  | 55 | * Assignment from and equality/inequality to `zero_t` should also be defined based on the underlying enum value. | 
|---|
|  | 56 | * The bitwise operators `?&?, ?|?, ?^?, ~?` and their assignment variants `?&=?, ?|=?, ?^=?` shall be defined with the semantics of the underlying enum value; `?-?` and `?-=?` should also be defined such that `a - b == a & ~b` (a set difference operation). | 
|---|
|  | 57 |  | 
|---|
|  | 58 | With these operations defined, flag enums would support a full set of useful flag operations, using existing, known syntax, as follows: | 
|---|
|  | 59 |  | 
|---|
|  | 60 | ``` | 
|---|
|  | 61 | FunFlags f = some_val(); | 
|---|
| [200fcb3] | 62 | if ( f ) { sout | "f has some flag(s) set"; } | 
|---|
|  | 63 | if ( f & FOO ) { sout | "f has FOO set"; } | 
|---|
| [bf8da66] | 64 | f |= FOO; // set FOO | 
|---|
|  | 65 | f -= FOO; // unset FOO | 
|---|
|  | 66 | f ^= FOO; // toggle FOO | 
|---|
|  | 67 | ``` | 
|---|
|  | 68 |  | 
|---|
|  | 69 | In each of the cases above, `FOO` could be replaced by `(BAR | BAZ)` to do the same operation or test on multiple flags at once. | 
|---|
|  | 70 |  | 
|---|
| [17df48e] | 71 | ### Alternative/Additional Features ### | 
|---|
|  | 72 |  | 
|---|
|  | 73 | #### User-defined enum discriminant iterator #### | 
|---|
|  | 74 | It may be useful to provide a more general method for changing the enum discriminant assignment function, e.g. the flag enum discriminants could be defined by something like the following: | 
|---|
|  | 75 |  | 
|---|
|  | 76 | ``` | 
|---|
|  | 77 | enum(@ << 1) TCP_Flags {  // each discriminant is left-shifted by 1 from the previous | 
|---|
|  | 78 | FIN = 0x1,  // first flag is 1 | 
|---|
|  | 79 | SYN, | 
|---|
|  | 80 | ACK, | 
|---|
|  | 81 | ... | 
|---|
|  | 82 | } | 
|---|
|  | 83 | ``` | 
|---|
|  | 84 |  | 
|---|
|  | 85 | #### Member expression for enums #### | 
|---|
|  | 86 | As a more ergonomic way to set and unset enum flags, we could define a member expression for flags enums. Since only unions and structs can have member expressions now, this change would be backwards compatible. Basically, given a `FunFlags f`, `f.FOO` would return a proxy object which could be implicitly converted to `bool` (with semantics `f & FOO`, i.e. "check if `FOO` is set on `f`"), as well as having `bool` assigned to it (with semantics `f |= FOO` on true or `f -= FOO` on false, i.e. "set or unset `FOO` on `f` as appropriate"). With this member function, the operations above can be expressed as follows (possibly more ergonomically): | 
|---|
|  | 87 |  | 
|---|
|  | 88 | ``` | 
|---|
|  | 89 | FunFlags f = some_val(); | 
|---|
| [200fcb3] | 90 | if ( f.FOO ) { sout | "f has FOO set"; } | 
|---|
| [17df48e] | 91 | f.FOO = true;    // set FOO | 
|---|
|  | 92 | f.FOO = false;   // unset FOO | 
|---|
|  | 93 | f.FOO = ! f.FOO; // toggle FOO | 
|---|
|  | 94 | ``` | 
|---|
|  | 95 |  | 
|---|
| [bf8da66] | 96 | ### Related Work ### | 
|---|
|  | 97 | C# has the [`[Flags]`][1] enum attribute, but their proposal does not go as far; specifically, the flag discriminants must be manually specified, and they do not automatically implement the bitwise operators on the flags. | 
|---|
|  | 98 |  | 
|---|
|  | 99 | Java has [`EnumSet`][2] which represents the set of flags for a given enum (C++ [`bitset`][3] can be used similarly). The main disadvantage of applying this approach to Cforall is that C enum types already implicitly convert to int, and the bitwise operators already have interpretations on enums with `int` results based on this conversion. As such, all flags need to be wrapped in a set to be used type-safely with the bitwise operators. | 
|---|
|  | 100 |  | 
|---|
|  | 101 | [1]: https://msdn.microsoft.com/en-us/library/system.enum.hasflag(v=vs.110).aspx | 
|---|
|  | 102 | [2]: http://docs.oracle.com/javase/7/docs/api/java/util/EnumSet.html | 
|---|
|  | 103 | [3]: http://en.cppreference.com/w/cpp/utility/bitset | 
|---|