[ADT] Add SmallVectorWithFlags with packed user flags
Structures that hold a SmallVector followed by a bool or a couple of
flag bits pay up to eight bytes of padding for those bits, and there is
no padding inside the vector to reuse: the header is exactly a pointer
and two 32-bit fields, and the inline storage of pointer-sized elements
is a multiple of eight bytes. SmallVectorWithFlags stores one to four
user flag bits in the high bits of the capacity field, so it has the
same size and inline capacity as SmallVector.
The capacity field is the one header field not read on the hot path:
the buffer pointer's free low bits depend on the element alignment and
are read on every element access, and the size is read by size() and
end(). Only capacity() masks the flags out, which costs one extra `and`
in the growth check of push_back; begin(), end(), and size() are
untouched. The cost is a maximum capacity divided by 2^FlagBits, which
with the 32-bit size type and four flag bits is 268 million elements.
The SmallVector implementation layers take a FlagBits template
parameter. For zero flags, SmallVectorHeader aliases SmallVectorBase
directly, preserving the unmasked storage and growth path. Only flagged
vectors instantiate the masking header, avoiding an extra constructor
and growth wrappers for ordinary SmallVector users. The out-of-line
growth routines stay in SmallVectorBase and remain instantiated once per
size type, with masked variants taking the capacity mask at run time.
The extra template argument and detail::SmallVectorImplBase layer
increase debug metadata. In an X86 clang RelWithDebInfo build with Clang
22.1.0, uncompressed .debug_info grows from 545,020,545 to 548,899,795
bytes (+0.71%). All 329 existing SmallVector and SmallVectorWithFlags
tests pass.
The trade-off versus a composed { SmallVector, uint8_t Flags } is that
the flagged container is not a SmallVectorImpl<T>: use ArrayRef<T> for
read-only interfaces and SmallVectorWithFlagsImpl<T, FlagBits> for
output parameters. A flagged vector can be moved into a plain
SmallVector<T, N>, dropping the flags, since the element algorithms
never depend on the flag bits of the header.
The flags are part of the vector's value. Element operations preserve
them; copy, move, and swap transfer them along with the elements, also
through SmallVectorWithFlagsImpl, and moving leaves the source flags
unchanged. Constructors taking the flag mask before an iterator range
or a vector to move from set them directly. Equality compares flags and
elements, and ordering compares elements before flags. Comparison
against ArrayRef is intentionally not provided; convert explicitly for
an element-only comparison.
The ProgrammersManual sentence suggesting SmallVectorHeader as a better
name for SmallVectorImpl is removed, as that name is now taken by the
header-selection alias.
Assisted-by: Codex
Assisted-by: Claude Code