Skip to content

Commit

Permalink
Implemeting faster element data search, also optimizing existing code
Browse files Browse the repository at this point in the history
  • Loading branch information
Pirulax committed May 15, 2020
1 parent dcadaa7 commit e11216c
Show file tree
Hide file tree
Showing 15 changed files with 400 additions and 374 deletions.
188 changes: 103 additions & 85 deletions Server/mods/deathmatch/logic/CCustomData.cpp
Expand Up @@ -11,147 +11,165 @@

#include "StdInc.h"

void CCustomData::Copy(CCustomData* pCustomData)
{
map<std::string, SCustomData>::const_iterator iter = pCustomData->IterBegin();
for (; iter != pCustomData->IterEnd(); iter++)
{
Set(iter->first.c_str(), iter->second.Variable);
}
}

SCustomData* CCustomData::Get(const char* szName)
void CCustomData::Copy(const CCustomData* const from)
{
assert(szName);

std::map<std::string, SCustomData>::const_iterator it = m_Data.find(szName);
if (it != m_Data.end())
return (SCustomData*)&it->second;

return NULL;
m_localOrSubMap = from->m_localOrSubMap;
m_broadcastedMap = from->m_broadcastedMap;
}

SCustomData* CCustomData::GetSynced(const char* szName)
SCustomData* CCustomData::Get(const SString& name, element_data_iter* const outIter)
{
assert(szName);
element_data_iter iter = m_localOrSubMap.find(name);
if (iter == m_localOrSubMap.end())
{
iter = m_broadcastedMap.find(name);
if (iter == m_broadcastedMap.end())
return nullptr;
}

std::map<std::string, SCustomData>::const_iterator it = m_SyncedData.find(szName);
if (it != m_SyncedData.end())
return (SCustomData*)&it->second;
if (outIter)
*outIter = iter;

return NULL;
return &iter->second;
}

bool CCustomData::DeleteSynced(const char* szName)
SCustomData* CCustomData::Get(const SString& name, const ESyncType syncType, element_data_iter* const outIter)
{
// Find the item and delete it
std::map<std::string, SCustomData>::iterator iter = m_SyncedData.find(szName);
if (iter != m_SyncedData.end())
element_data_iter iter;
if (syncType == ESyncType::BROADCAST)
{
m_SyncedData.erase(iter);
return true;
iter = m_broadcastedMap.find(name);
if (iter == m_broadcastedMap.end())
return nullptr;
}
else
{
iter = m_localOrSubMap.find(name);
if (iter == m_localOrSubMap.end())
return nullptr;
}

// Didn't exist
return false;
if (outIter)
*outIter = iter;

return &iter->second;
}

void CCustomData::UpdateSynced(const char* szName, const CLuaArgument& Variable, ESyncType syncType)
void CCustomData::Set(const SString& name, const CLuaArgument& var, const ESyncType syncType, SCustomData* const oldData)
{
if (syncType == ESyncType::BROADCAST)
element_data_iter dataIter;
SCustomData* data = Get(name, &dataIter);

if (data)
{
SCustomData* pDataSynced = GetSynced(szName);
if (pDataSynced)
if (data->syncType != syncType)
{
pDataSynced->Variable = Variable;
pDataSynced->syncType = syncType;
// here we can std::move, because it'll be deleted when erased from the map.
if (oldData)
*oldData = std::move(*data);

if (syncType == ESyncType::BROADCAST)
{
// first insert, then erase, because the iterator is invalidated after erasing
m_broadcastedMap.insert(std::move(*dataIter));
m_localOrSubMap.erase(dataIter);
}
else
{
// first insert, then erase, because the iterator is invalidated after erasing
m_localOrSubMap.insert(std::move(*dataIter));
m_broadcastedMap.erase(dataIter);
}
data->syncType = syncType;
}
else
else if (oldData)
{
SCustomData newData;
newData.Variable = Variable;
newData.syncType = syncType;
m_SyncedData[szName] = newData;
*oldData = *data;
}

data->variable = var;
}
else
{
DeleteSynced(szName);
if (syncType == ESyncType::BROADCAST)
m_broadcastedMap[name] = SCustomData(var, syncType);
else
m_localOrSubMap[name] = SCustomData(var, syncType);
}
}

void CCustomData::Set(const char* szName, const CLuaArgument& Variable, ESyncType syncType)
bool CCustomData::Delete(const SString& name)
{
assert(szName);

// Grab the item with the given name
SCustomData* pData = Get(szName);
if (pData)
{
// Update existing
pData->Variable = Variable;
pData->syncType = syncType;
UpdateSynced(szName, Variable, syncType);
}
else
element_data_iter iter;
const SCustomData* const data = Get(name, &iter);
if (data)
{
// Add new
SCustomData newData;
newData.Variable = Variable;
newData.syncType = syncType;
m_Data[szName] = newData;
UpdateSynced(szName, Variable, syncType);
if (data->syncType == ESyncType::BROADCAST)
m_broadcastedMap.erase(iter);
else
m_localOrSubMap.erase(iter);

return true;
}
return false;
}

bool CCustomData::Delete(const char* szName)
bool CCustomData::Delete(const SString& name, const ESyncType syncType)
{
// Find the item and delete it
std::map<std::string, SCustomData>::iterator it = m_Data.find(szName);
if (it != m_Data.end())
element_data_iter iter;
const SCustomData* const data = Get(name, syncType, &iter);
if (data)
{
DeleteSynced(szName);
m_Data.erase(it);
if (data->syncType == ESyncType::BROADCAST)
m_broadcastedMap.erase(iter);
else
m_localOrSubMap.erase(iter);

return true;
}

// Didn't exist
return false;
}

CXMLNode* CCustomData::OutputToXML(CXMLNode* pNode)
{
std::map<std::string, SCustomData>::const_iterator iter = m_Data.begin();
for (; iter != m_Data.end(); iter++)
{
CLuaArgument* arg = (CLuaArgument*)&iter->second.Variable;
element_data_map& map = m_localOrSubMap;

// hack, so we dont need to copy paste code for the other map
redo:

switch (arg->GetType())
for (const auto& pair : map)
{
const CLuaArgument& arg = pair.second.variable;
switch (arg.GetType())
{
case LUA_TSTRING:
{
CXMLAttribute* attr = pNode->GetAttributes().Create(iter->first.c_str());
attr->SetValue(arg->GetString().c_str());
CXMLAttribute* attr = pNode->GetAttributes().Create(pair.first.c_str());
attr->SetValue(arg.GetString().c_str());
break;
}
case LUA_TNUMBER:
{
CXMLAttribute* attr = pNode->GetAttributes().Create(iter->first.c_str());
attr->SetValue((float)arg->GetNumber());
CXMLAttribute* attr = pNode->GetAttributes().Create(pair.first.c_str());

attr->SetValue((float)arg.GetNumber());
break;
}
case LUA_TBOOLEAN:
{
CXMLAttribute* attr = pNode->GetAttributes().Create(iter->first.c_str());
attr->SetValue(arg->GetBoolean());
CXMLAttribute* attr = pNode->GetAttributes().Create(pair.first.c_str());
attr->SetValue(arg.GetBoolean());
break;
}
}
}
return pNode;
}

unsigned short CCustomData::CountOnlySynchronized()
{
return static_cast<unsigned short>(m_SyncedData.size());
if (&map == &m_localOrSubMap)
{
map = m_broadcastedMap;
goto redo;
}

return pNode;
}
83 changes: 66 additions & 17 deletions Server/mods/deathmatch/logic/CCustomData.h
Expand Up @@ -18,6 +18,7 @@

#define MAX_CUSTOMDATA_NAME_LENGTH 128


enum class ESyncType
{
LOCAL,
Expand All @@ -27,35 +28,83 @@ enum class ESyncType

struct SCustomData
{
CLuaArgument Variable;
CLuaArgument variable;
ESyncType syncType;

SCustomData() = default;

SCustomData(const CLuaArgument& var, const ESyncType syncType) noexcept :
variable(var),
syncType(syncType)
{
}

SCustomData(const SCustomData& rhs) noexcept :
variable(rhs.variable),
syncType(rhs.syncType)
{
}

SCustomData(SCustomData&& rhs) noexcept :
variable(std::move(rhs.variable)),
syncType(rhs.syncType)
{
}

SCustomData& operator=(const SCustomData& rhs) noexcept
{
if (this == &rhs)
return *this;

variable = rhs.variable;
syncType = rhs.syncType;
}

SCustomData& operator=(SCustomData&& rhs) noexcept
{
if (this == &rhs)
return *this;

variable = std::move(rhs.variable);
syncType = rhs.syncType;
}
};

// doing 'using' here, because of SCustomData
using element_data_map = CFastHashMap<std::string, SCustomData>;
using element_data_iter = element_data_map::iterator;
using element_data_const_iter = element_data_map::const_iterator;

class CCustomData
{
public:
void Copy(CCustomData* pCustomData);
void Copy(const CCustomData* const from);

SCustomData* Get(const char* szName);
SCustomData* GetSynced(const char* szName);
void Set(const char* szName, const CLuaArgument& Variable, ESyncType syncType = ESyncType::BROADCAST);
const SCustomData* Get(const SString& name) { return Get(name); };
const SCustomData* Get(const SString& name, const ESyncType syncType) { return Get(name, syncType); }

bool Delete(const char* szName);
void Set(const SString& name, const CLuaArgument& var, const ESyncType syncType = ESyncType::BROADCAST, SCustomData* const oldData = nullptr);

unsigned short CountOnlySynchronized();
bool Delete(const SString& name);
bool Delete(const SString& name, const ESyncType syncType);

CXMLNode* OutputToXML(CXMLNode* pNode);
unsigned int GetBroadcastedCount() const { return m_broadcastedMap.size(); }

std::map<std::string, SCustomData>::const_iterator IterBegin() { return m_Data.begin(); }
std::map<std::string, SCustomData>::const_iterator IterEnd() { return m_Data.end(); }
CXMLNode* OutputToXML(CXMLNode* node);

std::map<std::string, SCustomData>::const_iterator SyncedIterBegin() { return m_SyncedData.begin(); }
std::map<std::string, SCustomData>::const_iterator SyncedIterEnd() { return m_SyncedData.end(); }
element_data_const_iter LocalOrSubDataBegin() const { return m_localOrSubMap.begin(); }
element_data_const_iter LocalOrSubDataEnd() const { return m_localOrSubMap.end(); }

private:
bool DeleteSynced(const char* szName);
void UpdateSynced(const char* szName, const CLuaArgument& Variable, ESyncType syncType);
element_data_const_iter BroadcastedBegin() const { return m_broadcastedMap.begin(); }
element_data_const_iter BroadcastedEnd() const { return m_broadcastedMap.end(); }

std::map<std::string, SCustomData> m_Data;
std::map<std::string, SCustomData> m_SyncedData;
private:
// outIter used for returning the position of the data in the appropriate map(m_broadcastedMap if the data's type is BROADCAST, otherwise m_localOrSubMap)
SCustomData* Get(const SString& name, element_data_iter* const outIter);
// This version is used to speed up the search, because we dont need to search two maps, just one. Useful when we know its syncType
SCustomData* Get(const SString& name, const ESyncType syncType, element_data_iter* const outIter);

// ACHTUNG(WARNING): no key can be in both maps at the same time.
element_data_map m_localOrSubMap; // local, and subscribed edata
element_data_map m_broadcastedMap; // broadcasted edata
};

0 comments on commit e11216c

Please sign in to comment.