简体   繁体   中英

Accessing vector index using bitset

I'm trying to code my own Entity Component System, and I want a fast (constant time where possible) but also memory efficient way of accessing a component of an entity.

A global map is used ( std::unordered_map ) that maps each entity to a sorted vector which contains their components:

Key        Value
---        -----
EntityA -> Sorted vector of components 
EntityB -> Sorted vector of components
[..]    -> [..]

Each entity has a bitset that indicates what components the entity has ie. :

|C0 |C1 |C2 |C3 |C4 |C5
 0   0   1   0   1   1

and on the map:
Key        Value
---        -----
EntityA -> [C2,C4,C5]

As components get added rarely I can afford the cost of a sorted insertion, but I definitely want fast access.

Now I know from the bitset that C4 is the second element set(counting from the left) so it should be at the second vector index.

How can I write that into a method that will return the component of an entity given the ID of that component type? eg.

Component* getComponent(ComponentID id){ // component id of C5 should be 6 since it occupies the 6th position of the bitset
return [..];
}

Suppose our members are:

std::bitset<6> bits;
std::vector<Component> comps;

Then:

Component* getComponent(int id) {
    // we need to find how many bits are set for ids < id
    // first, make sure this one is set:
    if (!bits[id]) return nullptr;

    // then, let's count
    int idx = 0;
    for (int i = 0; i < id; ++i) {
        if (bits[i]) ++idx;
    }

    // now, just return the right pointer
    return &comps[idx];
}

You could also use std::bitset::test instead of the index operator if you want to do bounds checking.

A quicker solution might be something like this:

Component* getComponent(int id) {
    if (!bits[id]) return nullptr;

    // flip id and get a mask
    // if we have C0 .. C5, and we pass in 4
    // we want the mask 0x111100
    unsigned long mask = (1 << (bits.size() - id)) - 1;
    mask = ~mask;

    // apply the mask to the bitset
    // so from 0x001011, we get 0x001000
    unsigned long new_bits = bits.to_ulong() & mask;

    // count how many bits are set there
    unsigned int popcnt = __builtin_popcount(new_bits);

    // and there we have it
    return &comps[popcnt];
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM