hazelnutek
hazelnutek

Reputation: 323

C++ container of unique enum key and random value

I'm writing a client & server extension for a multiplayer game in C++. On the client side, I've added support for modifying vehicle's data structure in memory, I want to use that on the server side to allow admins to change this data for players. I need to consider that players can join after a vehicle has been already modified, therefore I need to store some sort of list/queue of changes that were done. I could send the entire vehicle data structure as it is, but it's pretty big and it will produce a huge overhead because it's mostly just a few data entries that are modified, such as the max speed etc. The entries can be modified many times in the script, but I only want to keep the most recent modification that was done.

So I need some sort of a container that would allow me to store the values the script has modified, for their unique keys. The keys would be from an enumerator that's used by the script. The enum looks like this

enum eVehicleData
{
    VEH_MAX_SPEED,
    VEH_ACCELERATION,
    // etc
}

The problem also is that the values can be of different types, according to their enum ekys, for example VEH_MAX_SPEED will be a float value, but VEH_GEAR_COUNT will be an integer (or byte, etc).

How could I implement such a thing? I've been reading on std::set and std::pair, but I think I cannot really use std::set as it does some sorting, and my value needs to be always the most recent value, regardless of whether it's smaller or bigger. I could simply go for some vector and check if the key exists with a loop or some another container of used keys and their indexes, but I don't know how to go past the multi-type problem, because the value data types may be different for different keys, and I also need to know the type when reading this data so I know how to process it.

I don't know if I expressed myself correctly, so I'm gonna show a simple pseudo code example of what I mean

uniqueSet<eVehicleData, random_data_type> modifiedKeys;

setVehicleData(veh, VEH_MAX_SPEED, 200.0);
// now modifiedKeys contains [ [VEH_MAX_SPEED, 200.0] ]
setVehicleData(veh, VEH_MAX_SPEED, 190.0);
// now modifiedKeys contains [ [VEH_MAX_SPEED, 190.0] ]
setVehicleData(veh, VEH_GEAR_COUNT, 6);
// now modifiedKeys contains [ [VEH_MAX_SPEED, 190.0], [VEH_GEAR_COUNT, 6] ]

I don't care about any ordering, sorting or anything.

Upvotes: 0

Views: 745

Answers (1)

Pedro LM
Pedro LM

Reputation: 750

You can achieve that with a combination of std::map and std::variant:

std::map<eVehicleData, std::variant<int, float>> modifiedKeys;

This structure uses eVehicleDatas as keys and ints/floats as values. A map can be accessed with the [] operator and it enforces uniqueness of its keys. This should match your desired behavior:

modifiedKeys[VEH_MAX_SPEED] = 200.0f;
// now modifiedKeys contains [ [VEH_MAX_SPEED, 200.0] ]
modifiedKeys[VEH_MAX_SPEED] = 190.0f;
// now modifiedKeys contains [ [VEH_MAX_SPEED, 190.0] ]
modifiedKeys[VEH_GEAR_COUNT] = 6;
// now modifiedKeys contains [ [VEH_MAX_SPEED, 190.0], [VEH_GEAR_COUNT, 6] ]

Later, when you serialize the modified keys, you can inspect the type of each std::variant with std::get_if:

for (auto & pair : modifiedKeys)
{
    eVehicleData key = pair.first;
    cout << "For key " << key << " we have value ";

    if (int * ivalue = std::get_if<int>(&pair.second))
    {
        // Serialize as int
        cout << *ivalue << endl;
    }
    else if (float * fvalue = std::get_if<float>(&pair.second))
    {
        // Serialize as float
        cout << *fvalue << endl;
    }
}

Output:

For key 0 we have value 190
For key 2 we have value 6

Upvotes: 1

Related Questions