Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
CStrIntern.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include "CStrIntern.h"
21 
22 #include "lib/fnv_hash.h"
23 #include "ps/CLogger.h"
24 
25 #include <boost/unordered_map.hpp>
26 
28 {
29 public:
30  CStrInternInternals(const char* str, size_t len)
31  : data(str, str+len), hash(fnv_hash(str, len))
32  {
33 // LOGWARNING(L"New interned string '%hs'", data.c_str());
34  }
35 
36  bool operator==(const CStrInternInternals& b) const
37  {
38  // Compare hash first for quick rejection of inequal strings
39  return (hash == b.hash && data == b.data);
40  }
41 
42  const std::string data;
43  const u32 hash; // fnv_hash of data
44 
45 private:
47 };
48 
49 // Interned strings are stored in a hash table, indexed by string:
50 
51 typedef std::string StringsKey;
52 
54 {
55  size_t operator()(const StringsKey& key) const
56  {
57  return fnv_hash(key.c_str(), key.length());
58  }
59 };
60 
61 // To avoid std::string memory allocations when GetString does lookups in the
62 // hash table of interned strings, we make use of boost::unordered_map's ability
63 // to do lookups with a functionally equivalent proxy object:
64 
66 {
67  const char* str;
68  size_t len;
69 };
70 
72 {
73  size_t operator()(const StringsKeyProxy& key) const
74  {
75  return fnv_hash(key.str, key.len);
76  }
77 };
78 
80 {
81  bool operator()(const StringsKeyProxy& proxy, const StringsKey& key) const
82  {
83  return (proxy.len == key.length() && memcmp(proxy.str, key.c_str(), proxy.len) == 0);
84  }
85 };
86 
87 static boost::unordered_map<StringsKey, shared_ptr<CStrInternInternals>, StringsKeyHash> g_Strings;
88 
89 #define X(id) CStrIntern str_##id(#id);
90 #define X2(id, str) CStrIntern str_##id(str);
91 #include "CStrInternStatic.h"
92 #undef X
93 #undef X2
94 
95 static CStrInternInternals* GetString(const char* str, size_t len)
96 {
97  // g_Strings is not thread-safe, so complain if anyone is using this
98  // type in non-main threads. (If that's desired, g_Strings should be changed
99  // to be thread-safe, preferably without sacrificing performance.)
101 
102 #if BOOST_VERSION >= 104200
103  StringsKeyProxy proxy = { str, len };
104  boost::unordered_map<StringsKey, shared_ptr<CStrInternInternals> >::iterator it =
106 #else
107  // Boost <= 1.41 doesn't support the new find(), so do a slightly less efficient lookup
108  boost::unordered_map<StringsKey, shared_ptr<CStrInternInternals> >::iterator it =
109  g_Strings.find(str);
110 #endif
111 
112  if (it != g_Strings.end())
113  return it->second.get();
114 
115  shared_ptr<CStrInternInternals> internals(new CStrInternInternals(str, len));
116  g_Strings.insert(std::make_pair(internals->data, internals));
117  return internals.get();
118 }
119 
121 {
122  *this = str__emptystring;
123 }
124 
125 CStrIntern::CStrIntern(const char* str)
126 {
127  m = GetString(str, strlen(str));
128 }
129 
130 CStrIntern::CStrIntern(const std::string& str)
131 {
132  m = GetString(str.c_str(), str.length());
133 }
134 
136 {
137  return m->hash;
138 }
139 
140 const char* CStrIntern::c_str() const
141 {
142  return m->data.c_str();
143 }
144 
145 size_t CStrIntern::length() const
146 {
147  return m->data.length();
148 }
149 
150 const std::string& CStrIntern::string() const
151 {
152  return m->data;
153 }
bool operator==(const CStrInternInternals &b) const
Definition: CStrIntern.cpp:36
CStrInternInternals & operator=(const CStrInternInternals &)
const std::string & string() const
Returns as std::string.
Definition: CStrIntern.cpp:150
size_t length() const
Returns length of string in bytes.
Definition: CStrIntern.cpp:145
static boost::unordered_map< StringsKey, shared_ptr< CStrInternInternals >, StringsKeyHash > g_Strings
Definition: CStrIntern.cpp:87
u32 GetHash() const
Returns cached FNV1-A hash of the string.
Definition: CStrIntern.cpp:135
const char * c_str() const
Returns null-terminated string.
Definition: CStrIntern.cpp:140
CStrInternInternals * m
Definition: CStrIntern.h:83
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
const std::string data
Definition: CStrIntern.cpp:42
pthread_key_t key
Definition: wpthread.cpp:140
static CStrInternInternals * GetString(const char *str, size_t len)
Definition: CStrIntern.cpp:95
CStrInternInternals(const char *str, size_t len)
Definition: CStrIntern.cpp:30
size_t operator()(const StringsKey &key) const
Definition: CStrIntern.cpp:55
size_t operator()(const StringsKeyProxy &key) const
Definition: CStrIntern.cpp:73
u32 fnv_hash(const void *buf, size_t len)
rationale: this algorithm was chosen because it delivers &#39;good&#39; results for string data and is relati...
Definition: fnv_hash.cpp:33
std::string StringsKey
Definition: CStrIntern.cpp:51
#define u32
Definition: types.h:41
const char * str
Definition: CStrIntern.cpp:67
bool IsMainThread()
Returns whether the current thread is the &#39;main&#39; thread (i.e.
Definition: ThreadUtil.cpp:25
bool operator()(const StringsKeyProxy &proxy, const StringsKey &key) const
Definition: CStrIntern.cpp:81