C++ container of unique enum key and random value










0















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.










share|improve this question



















  • 3





    Maybe I misunderstood the question, but it sounds like you are looking for std::map.

    – François Andrieux
    Nov 15 '18 at 19:32











  • std::variant can hold multiple types, its more user-friendly union.

    – Quimby
    Nov 15 '18 at 19:33











  • std::map got me interested, but it is using a comparator. How could I make it that the unique key would be always the one that was inserted as the last? Just always choose the 'right' one rather than the left when comparing? (considering that the new value can be less than the one that's already in the set, it still should be taken as the new value for that key)

    – hazelnutek
    Nov 15 '18 at 19:39







  • 1





    I think I'd rather need a std::unordered_map

    – hazelnutek
    Nov 15 '18 at 19:48












  • why not make a struct to hold the data you wish to pass around between client and server? POD structs are easily serilizeable and deserilizable over the network. just make sure you set your byte order as network when sending with htons for shorts ( 16 bit values) and htonl (32 bit values) and call ntohs and ntohl when receiving them to ensure your values are all in host byte order.

    – Johnathan
    Nov 15 '18 at 19:53















0















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.










share|improve this question



















  • 3





    Maybe I misunderstood the question, but it sounds like you are looking for std::map.

    – François Andrieux
    Nov 15 '18 at 19:32











  • std::variant can hold multiple types, its more user-friendly union.

    – Quimby
    Nov 15 '18 at 19:33











  • std::map got me interested, but it is using a comparator. How could I make it that the unique key would be always the one that was inserted as the last? Just always choose the 'right' one rather than the left when comparing? (considering that the new value can be less than the one that's already in the set, it still should be taken as the new value for that key)

    – hazelnutek
    Nov 15 '18 at 19:39







  • 1





    I think I'd rather need a std::unordered_map

    – hazelnutek
    Nov 15 '18 at 19:48












  • why not make a struct to hold the data you wish to pass around between client and server? POD structs are easily serilizeable and deserilizable over the network. just make sure you set your byte order as network when sending with htons for shorts ( 16 bit values) and htonl (32 bit values) and call ntohs and ntohl when receiving them to ensure your values are all in host byte order.

    – Johnathan
    Nov 15 '18 at 19:53













0












0








0








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.










share|improve this question
















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.







c++






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 15 '18 at 19:33







hazelnutek

















asked Nov 15 '18 at 19:31









hazelnutekhazelnutek

207




207







  • 3





    Maybe I misunderstood the question, but it sounds like you are looking for std::map.

    – François Andrieux
    Nov 15 '18 at 19:32











  • std::variant can hold multiple types, its more user-friendly union.

    – Quimby
    Nov 15 '18 at 19:33











  • std::map got me interested, but it is using a comparator. How could I make it that the unique key would be always the one that was inserted as the last? Just always choose the 'right' one rather than the left when comparing? (considering that the new value can be less than the one that's already in the set, it still should be taken as the new value for that key)

    – hazelnutek
    Nov 15 '18 at 19:39







  • 1





    I think I'd rather need a std::unordered_map

    – hazelnutek
    Nov 15 '18 at 19:48












  • why not make a struct to hold the data you wish to pass around between client and server? POD structs are easily serilizeable and deserilizable over the network. just make sure you set your byte order as network when sending with htons for shorts ( 16 bit values) and htonl (32 bit values) and call ntohs and ntohl when receiving them to ensure your values are all in host byte order.

    – Johnathan
    Nov 15 '18 at 19:53












  • 3





    Maybe I misunderstood the question, but it sounds like you are looking for std::map.

    – François Andrieux
    Nov 15 '18 at 19:32











  • std::variant can hold multiple types, its more user-friendly union.

    – Quimby
    Nov 15 '18 at 19:33











  • std::map got me interested, but it is using a comparator. How could I make it that the unique key would be always the one that was inserted as the last? Just always choose the 'right' one rather than the left when comparing? (considering that the new value can be less than the one that's already in the set, it still should be taken as the new value for that key)

    – hazelnutek
    Nov 15 '18 at 19:39







  • 1





    I think I'd rather need a std::unordered_map

    – hazelnutek
    Nov 15 '18 at 19:48












  • why not make a struct to hold the data you wish to pass around between client and server? POD structs are easily serilizeable and deserilizable over the network. just make sure you set your byte order as network when sending with htons for shorts ( 16 bit values) and htonl (32 bit values) and call ntohs and ntohl when receiving them to ensure your values are all in host byte order.

    – Johnathan
    Nov 15 '18 at 19:53







3




3





Maybe I misunderstood the question, but it sounds like you are looking for std::map.

– François Andrieux
Nov 15 '18 at 19:32





Maybe I misunderstood the question, but it sounds like you are looking for std::map.

– François Andrieux
Nov 15 '18 at 19:32













std::variant can hold multiple types, its more user-friendly union.

– Quimby
Nov 15 '18 at 19:33





std::variant can hold multiple types, its more user-friendly union.

– Quimby
Nov 15 '18 at 19:33













std::map got me interested, but it is using a comparator. How could I make it that the unique key would be always the one that was inserted as the last? Just always choose the 'right' one rather than the left when comparing? (considering that the new value can be less than the one that's already in the set, it still should be taken as the new value for that key)

– hazelnutek
Nov 15 '18 at 19:39






std::map got me interested, but it is using a comparator. How could I make it that the unique key would be always the one that was inserted as the last? Just always choose the 'right' one rather than the left when comparing? (considering that the new value can be less than the one that's already in the set, it still should be taken as the new value for that key)

– hazelnutek
Nov 15 '18 at 19:39





1




1





I think I'd rather need a std::unordered_map

– hazelnutek
Nov 15 '18 at 19:48






I think I'd rather need a std::unordered_map

– hazelnutek
Nov 15 '18 at 19:48














why not make a struct to hold the data you wish to pass around between client and server? POD structs are easily serilizeable and deserilizable over the network. just make sure you set your byte order as network when sending with htons for shorts ( 16 bit values) and htonl (32 bit values) and call ntohs and ntohl when receiving them to ensure your values are all in host byte order.

– Johnathan
Nov 15 '18 at 19:53





why not make a struct to hold the data you wish to pass around between client and server? POD structs are easily serilizeable and deserilizable over the network. just make sure you set your byte order as network when sending with htons for shorts ( 16 bit values) and htonl (32 bit values) and call ntohs and ntohl when receiving them to ensure your values are all in host byte order.

– Johnathan
Nov 15 '18 at 19:53












1 Answer
1






active

oldest

votes


















1














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





share|improve this answer






















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53326708%2fc-container-of-unique-enum-key-and-random-value%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    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





    share|improve this answer



























      1














      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





      share|improve this answer

























        1












        1








        1







        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





        share|improve this answer













        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






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 15 '18 at 20:43









        Pedro LMPedro LM

        674310




        674310





























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53326708%2fc-container-of-unique-enum-key-and-random-value%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Top Tejano songwriter Luis Silva dead of heart attack at 64

            政党

            天津地下鉄3号線