From e1c48be4ba6b7d1313942bf611c11df4a449b1e8 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Sat, 14 Dec 2019 09:04:54 +0800 Subject: [PATCH] Allow mapping TStringId from string literals, avoiding std::string allocation --- code/nel/include/nel/misc/string_mapper.h | 76 +++++++++++++++++------ code/nel/include/nel/misc/types_nl.h | 18 +++++- code/nel/src/misc/string_mapper.cpp | 63 +++++++++++-------- 3 files changed, 111 insertions(+), 46 deletions(-) diff --git a/code/nel/include/nel/misc/string_mapper.h b/code/nel/include/nel/misc/string_mapper.h index aeaccf959..c2229e746 100644 --- a/code/nel/include/nel/misc/string_mapper.h +++ b/code/nel/include/nel/misc/string_mapper.h @@ -1,6 +1,9 @@ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // +// This source file has been modified by the following contributors: +// Copyright (C) 2019 Jan BOON (Kaetemi) +// // 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 _StringTable; - std::string* _EmptyId; - CFastMutex _Mutex; // Must be thread-safe (Called by CPortal/CCluster, each of them called by CInstanceGroup) + typedef std::set 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); + 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) + \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(); + void localSerialString(NLMISC::IStream &f, TStringId &id); + void localClear(); }; // linear from 0 (0 is empty string) (The TSStringId returned by CStaticStringMapper diff --git a/code/nel/include/nel/misc/types_nl.h b/code/nel/include/nel/misc/types_nl.h index d5a566d89..ff91f36d5 100644 --- a/code/nel/include/nel/misc/types_nl.h +++ b/code/nel/include/nel/misc/types_nl.h @@ -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 diff --git a/code/nel/src/misc/string_mapper.cpp b/code/nel/src/misc/string_mapper.cpp index 39931efd2..8518afa4b 100644 --- a/code/nel/src/misc/string_mapper.cpp +++ b/code/nel/src/misc/string_mapper.cpp @@ -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::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()) + std::string str; + 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::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(); } // ****************************************************************************