1
1
forked from 0ad/0ad
0ad/source/ps/CStrIntern.cpp
bb 157c6af18e Make the space in 0 A.D. non-breaking throughout the codebase.
Avoid cases of filenames
Update years in terms and other legal(ish) documents
Don't update years in license headers, since change is not meaningful

Will add linter rule in seperate commit

Happy recompiling everyone!

Original Patch By: Nescio
Comment By: Gallaecio
Differential Revision: D2620
This was SVN commit r27786.
2023-07-27 20:54:46 +00:00

152 lines
3.6 KiB
C++

/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "CStrIntern.h"
#include "lib/fnv_hash.h"
#include "ps/CLogger.h"
#include "ps/ThreadUtil.h"
#include <unordered_map>
class CStrInternInternals
{
public:
CStrInternInternals(const char* str, size_t len)
: data(str, str+len), hash(fnv_hash(str, len))
{
// LOGWARNING("New interned string '%s'", data.c_str());
}
bool operator==(const CStrInternInternals& b) const
{
// Compare hash first for quick rejection of inequal strings
return (hash == b.hash && data == b.data);
}
const std::string data;
const u32 hash; // fnv_hash of data
private:
CStrInternInternals& operator=(const CStrInternInternals&);
};
// Interned strings are stored in a hash table, indexed by string:
using StringsKey = std::string;
struct StringsKeyHash
{
size_t operator()(const StringsKey& key) const
{
return fnv_hash(key.c_str(), key.length());
}
};
// To avoid std::string memory allocations when GetString does lookups in the
// hash table of interned strings, we make use of std::unordered_map's ability
// to do lookups with a functionally equivalent proxy object:
struct StringsKeyProxy
{
const char* str;
size_t len;
};
struct StringsKeyProxyHash
{
size_t operator()(const StringsKeyProxy& key) const
{
return fnv_hash(key.str, key.len);
}
};
struct StringsKeyProxyEq
{
bool operator()(const StringsKeyProxy& proxy, const StringsKey& key) const
{
return (proxy.len == key.length() && memcmp(proxy.str, key.c_str(), proxy.len) == 0);
}
};
static std::unordered_map<StringsKey, std::shared_ptr<CStrInternInternals>, StringsKeyHash> g_Strings;
#define X(id) CStrIntern str_##id(#id);
#define X2(id, str) CStrIntern str_##id(str);
#include "CStrInternStatic.h"
#undef X
#undef X2
static CStrInternInternals* GetString(const char* str, size_t len)
{
// g_Strings is not thread-safe, so complain if anyone is using this
// type in non-main threads. (If that's desired, g_Strings should be changed
// to be thread-safe, preferably without sacrificing performance.)
ENSURE(Threading::IsMainThread());
std::unordered_map<StringsKey, std::shared_ptr<CStrInternInternals> >::iterator it = g_Strings.find(str);
if (it != g_Strings.end())
return it->second.get();
std::shared_ptr<CStrInternInternals> internals = std::make_shared<CStrInternInternals>(str, len);
g_Strings.insert(std::make_pair(internals->data, internals));
return internals.get();
}
CStrIntern::CStrIntern()
{
*this = str__emptystring;
}
CStrIntern::CStrIntern(const char* str)
{
m = GetString(str, strlen(str));
}
CStrIntern::CStrIntern(const std::string& str)
{
m = GetString(str.c_str(), str.length());
}
u32 CStrIntern::GetHash() const
{
return m->hash;
}
const char* CStrIntern::c_str() const
{
return m->data.c_str();
}
size_t CStrIntern::length() const
{
return m->data.length();
}
bool CStrIntern::empty() const
{
return m->data.empty();
}
const std::string& CStrIntern::string() const
{
return m->data;
}