Remix.run Logo
judofyr 4 days ago

Is there a specific reason to store the key + value as an `uint64_t` instead of just using a struct like this?

    struct slot {
      uint32_t key;
      uint32_t value;
    }
nitnelave 4 days ago | parent | next [-]

The alignment constraint is different, which they use to be able to load both as a 64-bit integer and compare to 0 (the empty slot).

You could work around that with a union or casts with explicit alignment constraints, but this is the shortest way to express that.

Asooka 4 days ago | parent | next [-]

In that case you can use bit fields in a union:

    union slot {
        uint64_t keyvalue;
        struct {
            uint64_t key: 32;
            uint64_t value: 32;
        };
    };
Since both members of the union are effectively the exact same type, there is no issue. C99: "If the member used to access the contents of a union is not the same as the member last used to store a value, the object representation of the value that was stored is reinterpreted as an object representation of the new type". Meaning, you can initialise keyvalue and that will initialise both key and value, so writing "union slot s{0}" initialises everything to 0. One issue is that the exact layout for bit fields is implementation defined, so if you absolutely need to know where key and value are in memory, you will have to read GCC's manual (or just experiment). Another is that you cannot take the address of key or value individually, but if your code was already using uint64_t, you probably don't need to.

Edit: Note also that you can cast a pointer to slot to a pointer to uint64_t and that does not break strict aliasing rules.

nitnelave 4 days ago | parent [-]

You can probably get away with just a union between a 64 bit and 2 32 bit integers.

crest 3 days ago | parent | prev | next [-]

C has finally gained `alignas` so you can avoid the union hack or you could just rely on malloc to alway return the maximum alignment anyway.

4 days ago | parent | prev [-]
[deleted]
zimpenfish 4 days ago | parent | prev | next [-]

Maybe trying to avoid struct padding? Although having done a quick test on {arm64, amd64} {gcc, clang}, they all give the same `sizeof` for a struct with 2x`uint32_t`, a struct with a single `uint64_t`, or a bare `uint64_t`.

simonask 4 days ago | parent [-]

In any struct where all fields have the same size (and no field type requires higher alignment than its size), it is guaranteed on every (relevant) ABI that there is no padding bytes.

zimpenfish 3 days ago | parent [-]

TIL! Thanks!

loeg 3 days ago | parent | prev | next [-]

No real reason. Slightly terser to compare with zero to find an empty slot.

mwkaufma 3 days ago | parent | prev [-]

Or better, just store keys and values in separate arrays, so you can have compact cache lines of just keys when probing.