Skip to content

Commit deb728c

Browse files
authored
perf(gamemessage): Replace GameMessageArgument linked lists with vectors (TheSuperHackers#2700)
1 parent f334383 commit deb728c

8 files changed

Lines changed: 53 additions & 141 deletions

File tree

Core/GameEngine/Include/GameNetwork/NetCommandMsg.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "GameNetwork/NetPacketStructs.h"
3434
#include "Common/UnicodeString.h"
3535

36+
class GameMessageArgument;
3637
class NetCommandRef;
3738

3839
//-----------------------------------------------------------------------------
@@ -179,10 +180,8 @@ class NetGameCommandMsg : public NetCommandMsgT<NetPacketGameCommand, SmallNetPa
179180
virtual Select getSmallNetPacketSelect() const override;
180181

181182
protected:
182-
Int m_numArgs;
183-
Int m_argSize;
184183
GameMessage::Type m_type;
185-
GameMessageArgument *m_argList, *m_argTail;
184+
std::vector<GameMessageArgument*> m_argList;
186185
};
187186

188187
//-----------------------------------------------------------------------------

Core/GameEngine/Source/GameNetwork/NetCommandMsg.cpp

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,8 @@ Int NetCommandMsg::getSortNumber() const {
8888
* Constructor with no argument, sets everything to default values.
8989
*/
9090
NetGameCommandMsg::NetGameCommandMsg() {
91-
m_argSize = 0;
92-
m_numArgs = 0;
9391
m_type = (GameMessage::Type)0;
9492
m_commandType = NETCOMMANDTYPE_GAMECOMMAND;
95-
m_argList = nullptr;
96-
m_argTail = nullptr;
9793
}
9894

9995
/**
@@ -102,23 +98,24 @@ NetGameCommandMsg::NetGameCommandMsg() {
10298
*/
10399
NetGameCommandMsg::NetGameCommandMsg(GameMessage *msg) {
104100
m_commandType = NETCOMMANDTYPE_GAMECOMMAND;
105-
106101
m_type = msg->getType();
107-
Int count = msg->getArgumentCount();
108-
for (Int i = 0; i < count; ++i) {
109-
addArgument(msg->getArgumentDataType(i), *(msg->getArgument(i)));
102+
103+
const size_t argsCount = msg->getArgumentCount();
104+
m_argList.reserve(argsCount);
105+
106+
for (size_t i = 0; i < argsCount; ++i) {
107+
GameMessageArgumentDataType argType = msg->getArgumentDataType(i);
108+
const GameMessageArgumentType* arg = msg->getArgument(i);
109+
addArgument(argType, *arg);
110110
}
111111
}
112112

113113
/**
114114
* Destructor
115115
*/
116116
NetGameCommandMsg::~NetGameCommandMsg() {
117-
GameMessageArgument *arg = m_argList;
118-
while (arg != nullptr) {
119-
m_argList = m_argList->m_next;
120-
deleteInstance(arg);
121-
arg = m_argList;
117+
for (size_t i = 0; i < m_argList.size(); ++i) {
118+
deleteInstance(m_argList[i]);
122119
}
123120
}
124121

@@ -127,21 +124,10 @@ NetGameCommandMsg::~NetGameCommandMsg() {
127124
*/
128125
void NetGameCommandMsg::addArgument(const GameMessageArgumentDataType type, GameMessageArgumentType arg)
129126
{
130-
if (m_argTail == nullptr) {
131-
m_argList = newInstance(GameMessageArgument);
132-
m_argTail = m_argList;
133-
m_argList->m_data = arg;
134-
m_argList->m_type = type;
135-
m_argList->m_next = nullptr;
136-
return;
137-
}
138-
139127
GameMessageArgument *newArg = newInstance(GameMessageArgument);
140128
newArg->m_data = arg;
141129
newArg->m_type = type;
142-
newArg->m_next = nullptr;
143-
m_argTail->m_next = newArg;
144-
m_argTail = newArg;
130+
m_argList.push_back(newArg);
145131
}
146132

147133
// here's where we figure out which slot corresponds to which player
@@ -171,9 +157,8 @@ GameMessage *NetGameCommandMsg::constructGameMessage() const
171157
name.format("player%d", getPlayerID());
172158
retval->friend_setPlayerIndex( ThePlayerList->findPlayerWithNameKey(TheNameKeyGenerator->nameToKey(name))->getPlayerIndex());
173159

174-
GameMessageArgument *arg = m_argList;
175-
while (arg != nullptr) {
176-
160+
for (size_t i = 0; i < m_argList.size(); ++i) {
161+
const GameMessageArgument* arg = m_argList[i];
177162
switch (arg->m_type) {
178163

179164
case ARGUMENTDATATYPE_INTEGER:
@@ -211,8 +196,6 @@ GameMessage *NetGameCommandMsg::constructGameMessage() const
211196
break;
212197

213198
}
214-
215-
arg = arg->m_next;
216199
}
217200
return retval;
218201
}

Generals/Code/GameEngine/Include/Common/MessageStream.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ class GameMessageArgument : public MemoryPoolObject
8282
{
8383
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(GameMessageArgument, "GameMessageArgument")
8484
public:
85-
GameMessageArgument* m_next; ///< The next argument
8685
GameMessageArgumentType m_data; ///< The data storage of an argument
8786
GameMessageArgumentDataType m_type; ///< The type of the argument.
8887
};
@@ -637,7 +636,6 @@ class GameMessage : public MemoryPoolObject
637636
GameMessage *prev() { return m_prev; } ///< Return prev message in the stream
638637

639638
Type getType() const { return m_type; } ///< Return the message type
640-
UnsignedByte getArgumentCount() const { return m_argCount; } ///< Return the number of arguments for this msg
641639

642640
const char *getCommandAsString() const; ///< returns a string representation of the command type.
643641
static const char *getCommandTypeAsString(GameMessage::Type t);
@@ -660,8 +658,8 @@ class GameMessage : public MemoryPoolObject
660658

661659
/**
662660
* Return the given argument union.
663-
* @todo This should be a more list-like interface. Very inefficient.
664661
*/
662+
UnsignedByte getArgumentCount() const { return static_cast<UnsignedByte>(m_argList.size()); }
665663
const GameMessageArgumentType *getArgument( Int argIndex ) const;
666664
GameMessageArgumentDataType getArgumentDataType( Int argIndex ) const;
667665

@@ -681,10 +679,7 @@ class GameMessage : public MemoryPoolObject
681679

682680
Int m_playerIndex; ///< The Player who issued the command
683681

684-
/// @todo If a GameMessage needs more than 255 arguments, it needs to be split up into multiple GameMessage's.
685-
UnsignedByte m_argCount; ///< The number of arguments of this message
686-
687-
GameMessageArgument *m_argList, *m_argTail; ///< This message's arguments
682+
std::vector<GameMessageArgument*> m_argList; ///< This message's arguments
688683

689684
/// allocate a new argument, add it to list, return pointer to its data
690685
GameMessageArgument *allocArg();

Generals/Code/GameEngine/Source/Common/MessageStream.cpp

Lines changed: 11 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,6 @@ GameMessage::GameMessage( GameMessage::Type type )
5656
{
5757
m_playerIndex = ThePlayerList->getLocalPlayer()->getPlayerIndex();
5858
m_type = type;
59-
m_argList = nullptr;
60-
m_argTail = nullptr;
61-
m_argCount = 0;
6259
m_list = nullptr;
6360
}
6461

@@ -69,12 +66,8 @@ GameMessage::GameMessage( GameMessage::Type type )
6966
GameMessage::~GameMessage()
7067
{
7168
// free all arguments
72-
GameMessageArgument *arg, *nextArg;
73-
74-
for( arg = m_argList; arg; arg=nextArg )
75-
{
76-
nextArg = arg->m_next;
77-
deleteInstance(arg);
69+
for( size_t i = 0; i < m_argList.size(); ++i ) {
70+
deleteInstance(m_argList[i]);
7871
}
7972

8073
// detach message from list
@@ -84,14 +77,11 @@ GameMessage::~GameMessage()
8477

8578
/**
8679
* Return the given argument union.
87-
* @todo This should be a more list-like interface. Very inefficient.
8880
*/
8981
const GameMessageArgumentType *GameMessage::getArgument( Int argIndex ) const
9082
{
91-
int i=0;
92-
for( GameMessageArgument *a = m_argList; a; a=a->m_next, i++ )
93-
if (i == argIndex)
94-
return &a->m_data;
83+
if (static_cast<size_t>(argIndex) < m_argList.size())
84+
return &m_argList[argIndex]->m_data;
9585

9686
DEBUG_CRASH(("argument not found"));
9787
static const GameMessageArgumentType zero = { 0 };
@@ -103,17 +93,9 @@ const GameMessageArgumentType *GameMessage::getArgument( Int argIndex ) const
10393
*/
10494
GameMessageArgumentDataType GameMessage::getArgumentDataType( Int argIndex ) const
10595
{
106-
if (argIndex >= m_argCount) {
107-
return ARGUMENTDATATYPE_UNKNOWN;
108-
}
109-
int i=0;
110-
GameMessageArgument *a = m_argList;
111-
for (; a && (i < argIndex); a=a->m_next, ++i );
96+
if (static_cast<size_t>(argIndex) < m_argList.size())
97+
return m_argList[argIndex]->m_type;
11298

113-
if (a != nullptr)
114-
{
115-
return a->m_type;
116-
}
11799
return ARGUMENTDATATYPE_UNKNOWN;
118100
}
119101

@@ -124,21 +106,12 @@ GameMessageArgument *GameMessage::allocArg()
124106
{
125107
// allocate a new argument
126108
GameMessageArgument *arg = newInstance(GameMessageArgument);
109+
m_argList.push_back(arg);
127110

128-
// add to end of argument list
129-
if (m_argTail)
130-
m_argTail->m_next = arg;
131-
else
132-
{
133-
m_argList = arg;
134-
m_argTail = arg;
135-
}
136-
137-
arg->m_next = nullptr;
138-
m_argTail = arg;
139-
140-
m_argCount++;
141-
111+
DEBUG_ASSERTCRASH(
112+
m_argList.size() <= 255,
113+
("If a GameMessage needs more than 255 arguments, it needs to be split up into multiple GameMessage's.")
114+
);
142115
return arg;
143116
}
144117

Generals/Code/GameEngine/Source/Common/Recorder.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -785,15 +785,12 @@ void RecorderClass::writeToFile(GameMessage * msg) {
785785
argType = argType->getNext();
786786
}
787787

788-
// UnsignedByte lasttype = (UnsignedByte)ARGUMENTDATATYPE_UNKNOWN;
789-
Int numArgs = msg->getArgumentCount();
790-
for (Int i = 0; i < numArgs; ++i) {
791-
// UnsignedByte type = (UnsignedByte)(msg->getArgumentDataType(i));
792-
// if (lasttype != type) {
793-
// fwrite(&type, sizeof(type), 1, m_file);
794-
// lasttype = type;
795-
// }
796-
writeArgument(msg->getArgumentDataType(i), *(msg->getArgument(i)));
788+
const size_t argsCount = msg->getArgumentCount();
789+
790+
for (size_t i = 0; i < argsCount; ++i) {
791+
GameMessageArgumentDataType argType = msg->getArgumentDataType(i);
792+
const GameMessageArgumentType* arg = msg->getArgument(i);
793+
writeArgument(argType, *arg);
797794
}
798795

799796
deleteInstance(parser);

GeneralsMD/Code/GameEngine/Include/Common/MessageStream.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ class GameMessageArgument : public MemoryPoolObject
8282
{
8383
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(GameMessageArgument, "GameMessageArgument")
8484
public:
85-
GameMessageArgument* m_next; ///< The next argument
8685
GameMessageArgumentType m_data; ///< The data storage of an argument
8786
GameMessageArgumentDataType m_type; ///< The type of the argument.
8887
};
@@ -637,7 +636,6 @@ class GameMessage : public MemoryPoolObject
637636
GameMessage *prev() { return m_prev; } ///< Return prev message in the stream
638637

639638
Type getType() const { return m_type; } ///< Return the message type
640-
UnsignedByte getArgumentCount() const { return m_argCount; } ///< Return the number of arguments for this msg
641639

642640
const char *getCommandAsString() const; ///< returns a string representation of the command type.
643641
static const char *getCommandTypeAsString(GameMessage::Type t);
@@ -660,8 +658,8 @@ class GameMessage : public MemoryPoolObject
660658

661659
/**
662660
* Return the given argument union.
663-
* @todo This should be a more list-like interface. Very inefficient.
664661
*/
662+
UnsignedByte getArgumentCount() const { return static_cast<UnsignedByte>(m_argList.size()); }
665663
const GameMessageArgumentType *getArgument( Int argIndex ) const;
666664
GameMessageArgumentDataType getArgumentDataType( Int argIndex ) const;
667665

@@ -681,10 +679,7 @@ class GameMessage : public MemoryPoolObject
681679

682680
Int m_playerIndex; ///< The Player who issued the command
683681

684-
/// @todo If a GameMessage needs more than 255 arguments, it needs to be split up into multiple GameMessage's.
685-
UnsignedByte m_argCount; ///< The number of arguments of this message
686-
687-
GameMessageArgument *m_argList, *m_argTail; ///< This message's arguments
682+
std::vector<GameMessageArgument*> m_argList; ///< This message's arguments
688683

689684
/// allocate a new argument, add it to list, return pointer to its data
690685
GameMessageArgument *allocArg();

GeneralsMD/Code/GameEngine/Source/Common/MessageStream.cpp

Lines changed: 11 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,6 @@ GameMessage::GameMessage( GameMessage::Type type )
5656
{
5757
m_playerIndex = ThePlayerList->getLocalPlayer()->getPlayerIndex();
5858
m_type = type;
59-
m_argList = nullptr;
60-
m_argTail = nullptr;
61-
m_argCount = 0;
6259
m_list = nullptr;
6360
}
6461

@@ -69,12 +66,8 @@ GameMessage::GameMessage( GameMessage::Type type )
6966
GameMessage::~GameMessage()
7067
{
7168
// free all arguments
72-
GameMessageArgument *arg, *nextArg;
73-
74-
for( arg = m_argList; arg; arg=nextArg )
75-
{
76-
nextArg = arg->m_next;
77-
deleteInstance(arg);
69+
for( size_t i = 0; i < m_argList.size(); ++i ) {
70+
deleteInstance(m_argList[i]);
7871
}
7972

8073
// detach message from list
@@ -84,14 +77,11 @@ GameMessage::~GameMessage()
8477

8578
/**
8679
* Return the given argument union.
87-
* @todo This should be a more list-like interface. Very inefficient.
8880
*/
8981
const GameMessageArgumentType *GameMessage::getArgument( Int argIndex ) const
9082
{
91-
int i=0;
92-
for( GameMessageArgument *a = m_argList; a; a=a->m_next, i++ )
93-
if (i == argIndex)
94-
return &a->m_data;
83+
if (static_cast<size_t>(argIndex) < m_argList.size())
84+
return &m_argList[argIndex]->m_data;
9585

9686
DEBUG_CRASH(("argument not found"));
9787
static const GameMessageArgumentType zero = { 0 };
@@ -103,17 +93,9 @@ const GameMessageArgumentType *GameMessage::getArgument( Int argIndex ) const
10393
*/
10494
GameMessageArgumentDataType GameMessage::getArgumentDataType( Int argIndex ) const
10595
{
106-
if (argIndex >= m_argCount) {
107-
return ARGUMENTDATATYPE_UNKNOWN;
108-
}
109-
int i=0;
110-
GameMessageArgument *a = m_argList;
111-
for (; a && (i < argIndex); a=a->m_next, ++i );
96+
if (static_cast<size_t>(argIndex) < m_argList.size())
97+
return m_argList[argIndex]->m_type;
11298

113-
if (a != nullptr)
114-
{
115-
return a->m_type;
116-
}
11799
return ARGUMENTDATATYPE_UNKNOWN;
118100
}
119101

@@ -124,21 +106,12 @@ GameMessageArgument *GameMessage::allocArg()
124106
{
125107
// allocate a new argument
126108
GameMessageArgument *arg = newInstance(GameMessageArgument);
109+
m_argList.push_back(arg);
127110

128-
// add to end of argument list
129-
if (m_argTail)
130-
m_argTail->m_next = arg;
131-
else
132-
{
133-
m_argList = arg;
134-
m_argTail = arg;
135-
}
136-
137-
arg->m_next = nullptr;
138-
m_argTail = arg;
139-
140-
m_argCount++;
141-
111+
DEBUG_ASSERTCRASH(
112+
m_argList.size() <= 255,
113+
("If a GameMessage needs more than 255 arguments, it needs to be split up into multiple GameMessage's.")
114+
);
142115
return arg;
143116
}
144117

0 commit comments

Comments
 (0)