-
Notifications
You must be signed in to change notification settings - Fork 167
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
Use StructLayout for reduced memory usage #54
Comments
I haven't used StructLayout before, so I don't know what all the ramifications of this would be... It's basically saying reuse the location for each of the variables? Does this dynamically size depending on the largest type used? e.g. if you use a decimal it will reserve 12bytes? The Byte performance for _index thing sounds a bit worrying - if you are working in such a memory-challenged, CPU rich situation, it might be worth having a fork of OneOf specifically for that... |
Yep.
Yep. It's how you can generate true C/C++-style
Feel free to disregard my changing of |
Well if you're happy to submit a pull request, we can give it a go (not much spare time here unfortunately). Needs to be done via the linqpad script - apologies if you're not on windows (I need to update that to a |
It appears like this is not currently possible in the runtime (see dotnet/runtime#43486) Trying it out throws an exception:
Even if it were possible, I don't think it would be making its way back to the versions of the framework that this library supports. |
I'm wondering, if this could be done without generics using only source generators. For example: [OneOf(typeof(string), "Text")]
[OneOf(typeof(int), "Number")]
partial struct StringOrNumber { } would generate: partial struct StringOrNumber
{
[FieldOffset( offset: 0 )]
readonly int _index;
[FieldOffset( offset: 4 )]
readonly string _text; // value0
[FieldOffset( offset: 4 )]
readonly int _number; // value1
...
} Additional benefit of this approach would be that |
There's a restriction with explicit struct layout that the source generator would have to adhere to: As an example: [StructLayout(LayoutKind.Explicit)]
public readonly record struct OneOfOptimized
{
[FieldOffset(0)]
readonly int _index;
[FieldOffset(4)]
readonly int _value0;
[FieldOffset(4)]
readonly string _value1;
} Compiles, but at runtime loading the type will throw a
It's possible, however, to have multiple reference types at the same memory: [StructLayout(LayoutKind.Explicit)]
public readonly record struct OneOfOptimized
{
[FieldOffset(0)]
readonly int _index;
[FieldOffset(4)]
readonly int _value0;
[FieldOffset(4)]
readonly byte _value2;
[FieldOffset(8)]
readonly string _value1;
[FieldOffset(8)]
readonly object _value3;
} This example works, and |
When
OneOf
is used with many value-type arguments the value itself can get quite large.For example, this
Integer
type below is 34 bytes big.This can be improved by using struct packing.
For example:
And now,
sizeof(Integer) == 9
.Using a
Byte
for_index
helps - but may harm performance owing to not being native-word-aligned anymore.Thoughts?
The text was updated successfully, but these errors were encountered: