Allow mapping TStringId from string literals, avoiding std::string allocation

feature/pre-code-move
kaetemi 5 years ago committed by Jan Boon
parent 761770d4eb
commit e1c48be4ba

@ -1,6 +1,9 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This source file has been modified by the following contributors:
// Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
@ -65,7 +68,23 @@ class CStringMapper
class CCharComp
{
public:
bool operator()(std::string *x, std::string *y) const
#ifdef NL_CPP14
// https://www.fluentcpp.com/2017/06/09/search-set-another-type-key/
using is_transparent = void;
bool operator()(const std::string *x, const char *y) const
{
return strcmp(x->c_str(), y) < 0;
}
bool operator()(const char *x, const std::string *y) const
{
return strcmp(x, y->c_str()) < 0;
}
#endif
bool operator()(const std::string *x, const std::string *y) const
{
return (*x) < (*y);
}
@ -73,53 +92,70 @@ class CStringMapper
class CAutoFastMutex
{
CFastMutex *_Mutex;
CFastMutex *m_Mutex;
public:
CAutoFastMutex(CFastMutex *mtx) : _Mutex(mtx) {_Mutex->enter();}
~CAutoFastMutex() {_Mutex->leave();}
CAutoFastMutex(CFastMutex *mtx)
: m_Mutex(mtx)
{
m_Mutex->enter();
}
~CAutoFastMutex() { m_Mutex->leave(); }
};
// Local Data
std::set<std::string*,CCharComp> _StringTable;
std::string* _EmptyId;
CFastMutex _Mutex; // Must be thread-safe (Called by CPortal/CCluster, each of them called by CInstanceGroup)
typedef std::set<const std::string *, CCharComp> TStringTable;
TStringTable m_StringTable;
std::string *m_EmptyId;
CFastMutex m_Mutex; // Must be thread-safe (Called by CPortal/CCluster, each of them called by CInstanceGroup)
// The 'singleton' for static methods
static CStringMapper _GlobalMapper;
static CStringMapper s_GlobalMapper;
// private constructor.
CStringMapper();
public:
~CStringMapper()
{
localClear();
delete m_EmptyId;
}
/// Globaly map a string into a unique Id. ** This method IS Thread-Safe **
static TStringId map(const std::string &str) { return _GlobalMapper.localMap(str); }
static TStringId map(const std::string &str) { return s_GlobalMapper.localMap(str); }
/// Globaly map a string into a unique Id. ** This method IS Thread-Safe **
static TStringId map(const char *str) { return s_GlobalMapper.localMap(str); }
/// Globaly unmap a string. ** This method IS Thread-Safe **
static const std::string &unmap(const TStringId &stringId) { return _GlobalMapper.localUnmap(stringId); }
static const std::string &unmap(const TStringId &stringId) { return s_GlobalMapper.localUnmap(stringId); }
/// Globaly helper to serial a string id. ** This method IS Thread-Safe **
static void serialString(NLMISC::IStream &f, TStringId &id) {_GlobalMapper.localSerialString(f, id);}
static void serialString(NLMISC::IStream &f, TStringId &id) { s_GlobalMapper.localSerialString(f, id); }
/// Return the global id for the empty string (helper function). NB: Works with every instance of CStringMapper
static TStringId emptyId() { return 0; }
static TStringId emptyId() { return NULL; }
// ** This method IS Thread-Safe **
static void clear() { _GlobalMapper.localClear(); }
static void clear() { s_GlobalMapper.localClear(); }
/// Create a local mapper. You can dispose of it by deleting it.
static CStringMapper * createLocalMapper();
static CStringMapper *createLocalMapper();
/// Localy map a string into a unique Id
TStringId localMap(const std::string &str);
#ifdef NL_CPP14
/**
\brief Localy map a string into a unique Id.
Lookup in string mapper using `const char *`
to avoid an std::string allocation when using literals.
\author Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
\date 2019
*/
TStringId localMap(const char *str);
#endif
/// Localy unmap a string
const std::string &localUnmap(const TStringId &stringId) { return (stringId==0)?*_EmptyId:*((std::string*)stringId); }
const std::string &localUnmap(const TStringId &stringId) const { return (stringId == NULL) ? *m_EmptyId : *((const std::string *)stringId); }
/// Localy helper to serial a string id
void localSerialString(NLMISC::IStream &f, TStringId &id);
void localClear();
};
// linear from 0 (0 is empty string) (The TSStringId returned by CStaticStringMapper

@ -70,7 +70,13 @@
# endif
# ifdef _MSC_VER
# define NL_COMP_VC
# if _MSC_VER >= 1900
# if _MSC_VER >= 1920
# define NL_COMP_VC14
# define NL_COMP_VC_VERSION 142
# elif _MSC_VER >= 1910
# define NL_COMP_VC14
# define NL_COMP_VC_VERSION 141
# elif _MSC_VER >= 1900
# define NL_COMP_VC14
# define NL_COMP_VC_VERSION 140
# elif _MSC_VER >= 1800
@ -176,6 +182,16 @@
# define NL_NO_EXCEPTION_SPECS
#endif
// https://docs.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=vs-2019
// https://gcc.gnu.org/projects/cxx-status.html
#if (defined(_MSC_VER) && (_MSC_VER >= 1910)) || (defined(__GNUC__ ) && (__GNUC__ >= 8))
# define NL_CPP17
#endif
#if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || (defined(__GNUC__ ) && (__GNUC__ >= 6))
# define NL_CPP14
#endif
#if defined(NL_COMP_VC) && (NL_COMP_VC_VERSION >= 140)
#define nlmove(v) std::move(v)
#else

@ -27,13 +27,12 @@ using namespace std;
namespace NLMISC
{
CStringMapper CStringMapper::_GlobalMapper;
CStringMapper CStringMapper::s_GlobalMapper;
// ****************************************************************************
CStringMapper::CStringMapper()
{
_EmptyId = new string();
m_EmptyId = new string();
}
// ****************************************************************************
@ -46,39 +45,54 @@ CStringMapper *CStringMapper::createLocalMapper()
TStringId CStringMapper::localMap(const std::string &str)
{
if (str.empty())
return 0;
CAutoFastMutex automutex(&_Mutex);
return NULL;
string *pStr = new string;
*pStr = str;
CAutoFastMutex autoMutex(&m_Mutex);
std::set<string*,CCharComp>::iterator it = _StringTable.find(pStr);
TStringTable::const_iterator it = m_StringTable.find((const std::string *)&str);
if (it == _StringTable.end())
if (it == m_StringTable.end())
{
_StringTable.insert(pStr);
string *pStr = new string(str);
m_StringTable.insert(pStr);
return pStr;
}
else
return (TStringId)(*it);
}
#ifdef NL_CPP14
// ****************************************************************************
TStringId CStringMapper::localMap(const char *str)
{
if (!str[0])
return NULL;
CAutoFastMutex autoMutex(&m_Mutex);
TStringTable::const_iterator it = m_StringTable.find(str);
if (it == m_StringTable.end())
{
delete pStr;
pStr = (*it);
string *pStr = new string(str);
m_StringTable.insert(pStr);
return pStr;
}
return (TStringId)pStr;
return (TStringId)(*it);
}
#endif
// ***************************************************************************
void CStringMapper::localSerialString(NLMISC::IStream &f, TStringId &id)
{
std::string str;
if(f.isReading())
if (f.isReading())
{
f.serial(str);
id= localMap(str);
id = localMap(str);
}
else
{
str= localUnmap(id);
str = localUnmap(id);
f.serial(str);
}
}
@ -86,17 +100,16 @@ void CStringMapper::localSerialString(NLMISC::IStream &f, TStringId &id)
// ****************************************************************************
void CStringMapper::localClear()
{
CAutoFastMutex automutex(&_Mutex);
CAutoFastMutex autoMutex(&m_Mutex);
std::set<string*,CCharComp>::iterator it = _StringTable.begin();
while (it != _StringTable.end())
TStringTable::iterator it = m_StringTable.begin();
while (it != m_StringTable.end())
{
string *ptrTmp = (*it);
const std::string *ptrTmp = (*it);
delete ptrTmp;
it++;
}
_StringTable.clear();
delete _EmptyId;
m_StringTable.clear();
}
// ****************************************************************************

Loading…
Cancel
Save