mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-07 17:26:45 +08:00
The documentation is now generated from markdown. Samples are generated from the tutorial pages. Testing is done by a Python script which runs the tests for a large number of compilers. This version is not very developer-friendly - the Python scripts need ways of limiting what compilers they try to run. If you don't have 15 compilers installed, you won't be able to run the tests in this commit. Fix coming soon.
83 lines
2.8 KiB
Markdown
83 lines
2.8 KiB
Markdown
## Representation and alignment
|
|
|
|
Let's go over some of the low-level properties of a Better Enum. This time, we
|
|
will declare a more unusual enum than the ones we have seen.
|
|
|
|
#include <cassert>
|
|
#include <iostream>
|
|
<em>#include <enum.h></em>
|
|
|
|
<em>ENUM(ContentType, short,
|
|
CompressedVideo = 5, PCM = 8, Subtitles = 17, Comment = 44)</em>
|
|
|
|
This is for a hypothetical multimedia container file format. Perhaps the files
|
|
have sections, and each one has a header:
|
|
|
|
<em>struct Header</em> {
|
|
<em>ContentType type</em>;
|
|
short flags;
|
|
int offset;
|
|
};
|
|
|
|
---
|
|
|
|
Here is what we have.
|
|
|
|
int main()
|
|
{
|
|
assert(<em>sizeof(ContentType) == 2</em>);
|
|
|
|
As you can see, `ContentType` behaves just like a `short`[^*], in fact it simply
|
|
wraps one. This makes it possible to lay out structures in a predictable
|
|
fashion:
|
|
|
|
Header header = {ContentType::PCM, 0, 0};
|
|
|
|
assert(<em>sizeof(header) == 8</em>);
|
|
assert((size_t)&<em>header.flags -</em> (size_t)&<em>header.type == 2</em>);
|
|
|
|
---
|
|
|
|
`uint16_t` is called `ContentType`'s *underlying* or *representation* type. If
|
|
you want to know the representation type of any enum you have declared, it is
|
|
available as `::_integral`:
|
|
|
|
<em>ContentType::_integral</em> untrusted_value = 44;
|
|
|
|
Use this if you want a sized field to receive untrusted data, but aren't willing
|
|
to call it `ContentType` yet because you have not validated it. Your validator
|
|
will likely call `::_from_integral_nothrow`, perform any other validation your
|
|
application requires, and then return `ContentType`.
|
|
|
|
ContentType type =
|
|
ContentType::_from_integral(untrusted_value);
|
|
std::cout << type._to_string() << std::endl;
|
|
|
|
---
|
|
|
|
You have probably noticed the initializers on each of the constants in
|
|
`ContentType`. This allows you to declare sparse enums for compatibility with
|
|
external protocols or previous versions of your software. The initializers don't
|
|
need to be literal integers — they can be anything that the compiler would
|
|
accept in a normal `enum` declaration. If there was a macro called
|
|
`BIG_FAT_MACRO` declared above, we could have written
|
|
`Subtitles = BIG_FAT_MACRO`. We could also have written
|
|
`Subtitles = CompressedVideo`.
|
|
|
|
---
|
|
|
|
The in-memory representation of an enum value is simply the number it has been
|
|
assigned by the compiler. You should be safe passing enums to functions like
|
|
`fread` and `fwrite`, and casting memory blocks known to be safe to `struct`
|
|
types containg enums. The enums will behave as expected.
|
|
|
|
---
|
|
|
|
return 0;
|
|
}
|
|
|
|
[^*]: It should properly be a `uint16_t`, and the rest of the header fields
|
|
should also be explicitly sized. However, this code is trying to be
|
|
compatible with $cxx98, where those names aren't available in a portable
|
|
manner.
|