-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: compressed layout of enum
#3166
Comments
Currently Rust allows code to take references to inner enum fields, so If there's only one bool, it is able to allocate |
What if using anonymous enum Format3 {
Int8( enum { Unsigned, Signed } ), // 0, 1
Int16( enum { Unsigned, Signed }, enum { LittleEndian, BigEndian } ), // 2, 3, 4, 5
// ...
}
// match by reference (however, matching by mutable reference is ill-formed)
match &format {
Format3::Int16 (ref signed, ref big_endian) => {
if mathces!(signed, Format3::Int16::Signed) {
// ...
}
}
// ...
} In alternative, if |
Similar things have been discussed in the past. It basically boils down to that annotation needing to prevent taking references to data in the enum. Which would be fine! We already do something similar with |
this would be one step away from native bitfields (not necessarily compatible with C) in rust 🙂 #[repr(bit_packed)] // = #[repr(compressed)]
struct A {
a: bool,
b: bool,
}
assert_eq!(std::mem::size_of::<A>(), 1);
#[repr(bit_packed)]
enum Format2 {
// 5 bits to represent the whole type:
Int8 { signed: bool }, // 000|b_ (0, 2)
Int16 { signed: bool, big_endian: bool }, // 001|bb (4, 5, 6, 7)
Int32 { signed: bool, big_endian: bool }, // 010|bb (8, 9, 10, 11)
Int64 { signed: bool, big_endian: bool }, // 011|bb (12, 13, 14, 15)
Ieee754Float { big_endian: bool }, // 100|b_ (16, 18)
Ieee754Double { big_endian: bool }, // 101|b_ (20, 22)
Utf16 { big_endian: bool }, // 110|b_ (24, 26)
Utf32 { big_endian: bool }, // 111|b_ (28, 30)
}
assert_eq!(std::mem::size_of::<Format2>(), 1); |
@kennytm Cool! But it seems not working in nightly rustc yet? |
@whjpji 😅 i mean using what Kimundi suggested (prohibiting taking references to a field), someone can file an RFC for the ultra-packed representation, then if it is accepted (which is hard as #205, #314, #1449, #3064 and #3113 will definitely get pulled into the debate), someone else can implement it. |
Adding cross-reference: #311 is an earlier discussion of the same idea as here. |
I have an
enum
like this:It's kind of verbose and needs more codes in pattern matching, so I rewrite it like this:
I implemented
TryFrom<u8>
andInto<u8>
for it, to make sureFormat2
has the same mapping tou8
asFormat
.Everything works fine, except that the rewritten
Format2
occupies 3 bytes, instead of 1.Is there a possibility to add something like
#[repr(compressed)]
to makeFormat2
's memory representation likeFormat
?Currently, rustc can optimize the
enum
to occupy only 1 byte if I comment out all the fields in the discriminants except the first one:I'm not very familiar with rustc, but I can describe a possible algorithm to achieve this:
enum
, and calculate the number of all possible values it could have. Also records the offset start of each discriminant based on a prefix sum. If there are discriminants that:enum
, tuple orstruct
fields, do this recursively;3.have non-
Copy
fields, stop this algorithm.enum
, if it is:0..256
, use 1 byte to represent it;256..65536
, use 2 bytes to represent it;offset..offset + num_of_values
). During pattern match, the discriminants are matched by its value range, and the fields are matched by its subrange. It might not be contiguous, then it can be matched by modulo or bit operations. (The value range can be extended to fit exponent of 2 for faster matching by bit operations, but the user should be able to control it.)For example, for
Int8 { signed: bool }
, there are 2 possible values, and it has offset0
, so its range is0..2
; forInt16 { signed: bool, big_endian: bool }
, there are 2 × 2 = 4 possible values, and it has offset2
, so its range is2..6
. If there is a matchIt can be translated to
The text was updated successfully, but these errors were encountered: