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.
c++
|
show 1 more comment
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++
3
Maybe I misunderstood the question, but it sounds like you are looking forstd::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
|
show 1 more comment
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++
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++
c++
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 forstd::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
|
show 1 more comment
3
Maybe I misunderstood the question, but it sounds like you are looking forstd::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
|
show 1 more comment
1 Answer
1
active
oldest
votes
You can achieve that with a combination of std::map
and std::variant
:
std::map<eVehicleData, std::variant<int, float>> modifiedKeys;
This structure uses eVehicleData
s as keys and int
s/float
s 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
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
You can achieve that with a combination of std::map
and std::variant
:
std::map<eVehicleData, std::variant<int, float>> modifiedKeys;
This structure uses eVehicleData
s as keys and int
s/float
s 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
add a comment |
You can achieve that with a combination of std::map
and std::variant
:
std::map<eVehicleData, std::variant<int, float>> modifiedKeys;
This structure uses eVehicleData
s as keys and int
s/float
s 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
add a comment |
You can achieve that with a combination of std::map
and std::variant
:
std::map<eVehicleData, std::variant<int, float>> modifiedKeys;
This structure uses eVehicleData
s as keys and int
s/float
s 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
You can achieve that with a combination of std::map
and std::variant
:
std::map<eVehicleData, std::variant<int, float>> modifiedKeys;
This structure uses eVehicleData
s as keys and int
s/float
s 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
answered Nov 15 '18 at 20:43
Pedro LMPedro LM
674310
674310
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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