All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
token.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef TF_TOKEN_H
25 #define TF_TOKEN_H
26 
31 
32 #include "pxr/pxr.h"
33 
34 #include "pxr/base/tf/api.h"
35 #include "pxr/base/tf/diagnosticLite.h"
36 #include "pxr/base/tf/hash.h"
37 #include "pxr/base/tf/pointerAndBits.h"
38 #include "pxr/base/tf/traits.h"
39 
40 #include "pxr/base/tf/hashset.h"
41 #include <atomic>
42 #include <iosfwd>
43 #include <string>
44 #include <vector>
45 #include <map>
46 #include <set>
47 
48 PXR_NAMESPACE_OPEN_SCOPE
49 
51 
89 class TfToken
90 {
91 public:
92  enum _ImmortalTag { Immortal };
93 
95  constexpr TfToken() noexcept {}
96 
98  TfToken(TfToken const& rhs) noexcept : _rep(rhs._rep) { _AddRef(); }
99 
101  TfToken(TfToken && rhs) noexcept : _rep(rhs._rep) {
102  rhs._rep = TfPointerAndBits<const _Rep>();
103  }
104 
106  TfToken& operator= (TfToken const& rhs) noexcept {
107  if (&rhs != this) {
108  rhs._AddRef();
109  _RemoveRef();
110  _rep = rhs._rep;
111  }
112  return *this;
113  }
114 
116  TfToken& operator= (TfToken && rhs) noexcept {
117  if (&rhs != this) {
118  _RemoveRef();
119  _rep = rhs._rep;
120  rhs._rep = TfPointerAndBits<const _Rep>();
121  }
122  return *this;
123  }
124 
126  ~TfToken() { _RemoveRef(); }
127 
129  //
130  // This constructor involves a string hash and a lookup in the global
131  // table, and so should not be done more often than necessary. When
132  // possible, create a token once and reuse it many times.
133  TF_API explicit TfToken(std::string const& s);
135  // Create a token for \p s, and make it immortal. If \p s exists in the
136  // token table already and is not immortal, make it immortal. Immortal
137  // tokens are faster to copy than mortal tokens, but they will never expire
138  // and release their memory.
139  TF_API TfToken(std::string const& s, _ImmortalTag);
140 
142  //
143  // This constructor involves a string hash and a lookup in the global
144  // table, and so should not be done more often than necessary. When
145  // possible, create a token once and reuse it many times.
146  TF_API explicit TfToken(char const* s);
148  // Create a token for \p s, and make it immortal. If \p s exists in the
149  // token table already and is not immortal, make it immortal. Immortal
150  // tokens are faster to copy than mortal tokens, but they will never expire
151  // and release their memory.
152  TF_API TfToken(char const* s, _ImmortalTag);
153 
155  //
156  // If a token has previous been created for the given string, this
157  // will return it. Otherwise, the empty token will be returned.
158  TF_API static TfToken Find(std::string const& s);
159 
161  //
162  // The hash is based on the token's storage identity; this is immutable
163  // as long as the token is in use anywhere in the process.
164  //
165  size_t Hash() const { return TfHash()(_rep.Get()); }
166 
168  struct HashFunctor {
169  size_t operator()(TfToken const& token) const { return token.Hash(); }
170  };
171 
177  typedef TfHashSet<TfToken, TfToken::HashFunctor> HashSet;
178 
185  typedef std::set<TfToken, TfTokenFastArbitraryLessThan> Set;
186 
188  size_t size() const {
189  _Rep const *rep = _rep.Get();
190  return rep ? rep->_str.size() : 0;
191  }
192 
198  char const* GetText() const {
199  _Rep const *rep = _rep.Get();
200  return rep ? rep->_str.c_str() : "";
201  }
202 
204  char const *data() const {
205  return GetText();
206  }
207 
209  std::string const& GetString() const {
210  _Rep const *rep = _rep.Get();
211  return rep ? rep->_str : _GetEmptyString();
212  }
213 
215  inline void Swap(TfToken &other) {
216  std::swap(_rep, other._rep);
217  }
218 
220  bool operator==(TfToken const& o) const {
221  // Equal if pointers & bits are equal, or if just pointers are. Done
222  // this way to avoid the bitwise operations for common cases.
223  return _rep.GetLiteral() == o._rep.GetLiteral() ||
224  _rep.Get() == o._rep.Get();
225  }
226 
228  bool operator!=(TfToken const& o) const {
229  return !(*this == o);
230  }
231 
234  TF_API bool operator==(std::string const& o) const;
235 
238  TF_API bool operator==(const char *) const;
239 
241  friend bool operator==(std::string const& o, TfToken const& t) {
242  return t == o;
243  }
244 
246  friend bool operator==(const char *o, TfToken const& t) {
247  return t == o;
248  }
249 
252  bool operator!=(std::string const& o) const {
253  return !(*this == o);
254  }
255 
257  friend bool operator!=(std::string const& o, TfToken const& t) {
258  return !(t == o);
259  }
260 
263  bool operator!=(char const* o) const {
264  return !(*this == o);
265  }
266 
268  friend bool operator!=(char const* o, TfToken const& t) {
269  return !(t == o);
270  }
271 
274  inline bool operator<(TfToken const& r) const {
275  auto ll = _rep.GetLiteral(), rl = r._rep.GetLiteral();
276  if (!ll) {
277  return rl;
278  }
279  if (!rl || ll == rl) {
280  return false;
281  }
282  auto lrep = _rep.Get(), rrep = r._rep.Get();
283  uint64_t lcc = lrep->_compareCode, rcc = rrep->_compareCode;
284  if (lcc < rcc) {
285  return true;
286  }
287  return lcc == rcc && lrep->_str < rrep->_str;
288  }
289 
291  inline bool operator>(TfToken const& o) const {
292  return o < *this;
293  }
294 
297  inline bool operator>=(TfToken const& o) const {
298  return !(*this < o);
299  }
300 
303  inline bool operator<=(TfToken const& o) const {
304  return !(*this > o);
305  }
306 
308  operator std::string const& () const { return GetString(); }
309 
311  bool IsEmpty() const { return _rep.GetLiteral() == 0; }
312 
314  bool IsImmortal() const { return !_rep->_isCounted; }
315 
317  friend TF_API std::ostream &operator <<(std::ostream &stream, TfToken const&);
318 
319 private:
320  // Add global swap overload.
321  friend void swap(TfToken &lhs, TfToken &rhs) {
322  lhs.Swap(rhs);
323  }
324 
325  void _AddRef() const {
326  if (_rep.BitsAs<bool>()) {
327  // We believe this rep is refCounted.
328  if (!_rep->IncrementIfCounted()) {
329  // Our belief is wrong, update our cache of countedness.
330  _rep.SetBits(false);
331  }
332  }
333  }
334 
335  void _RemoveRef() const {
336  if (_rep.BitsAs<bool>()) {
337  // We believe this rep is refCounted.
338  if (_rep->_isCounted) {
339  if (_rep->_refCount.load(std::memory_order_relaxed) == 1) {
340  _PossiblyDestroyRep();
341  }
342  else {
343  /*
344  * This is deliberately racy. It's possible the statement
345  * below drops our count to zero, and we leak the rep
346  * (i.e. we leave it in the table). That's a low
347  * probability event, in exchange for only grabbing the lock
348  * (in _PossiblyDestroyRep()) when the odds are we really do
349  * need to modify the table.
350  *
351  * Note that even if we leak the rep, if we look it up
352  * again, we'll simply repull it from the table and keep
353  * using it. So it's not even necessarily a true leak --
354  * it's just a potential leak.
355  */
356  _rep->_refCount.fetch_sub(1, std::memory_order_relaxed);
357  }
358  } else {
359  // Our belief is wrong, update our cache of countedness.
360  _rep.SetBits(false);
361  }
362  }
363  }
364 
365  void TF_API _PossiblyDestroyRep() const;
366 
367  struct _Rep {
368  _Rep() {}
369  explicit _Rep(char const *s) : _str(s), _cstr(_str.c_str()) {}
370  explicit _Rep(std::string const &s) : _str(s), _cstr(_str.c_str()) {}
371 
372  // Make sure we reacquire _cstr from _str on copy and assignment
373  // to avoid holding on to a dangling pointer. However, if rhs'
374  // _cstr member doesn't come from its _str, just copy it directly
375  // over. This is to support lightweight _Rep objects used for
376  // internal lookups.
377  _Rep(_Rep const &rhs) : _str(rhs._str),
378  _cstr(rhs._str.c_str() != rhs._cstr ?
379  rhs._cstr : _str.c_str()),
380  _compareCode(rhs._compareCode),
381  _refCount(rhs._refCount.load()),
382  _isCounted(rhs._isCounted),
383  _setNum(rhs._setNum) {}
384  _Rep& operator=(_Rep const &rhs) {
385  _str = rhs._str;
386  _cstr = (rhs._str.c_str() != rhs._cstr ? rhs._cstr : _str.c_str());
387  _compareCode = rhs._compareCode;
388  _refCount = rhs._refCount.load();
389  _isCounted = rhs._isCounted;
390  _setNum = rhs._setNum;
391  return *this;
392  }
393 
394  inline bool IncrementIfCounted() const {
395  const bool isCounted = _isCounted;
396  if (isCounted) {
397  _refCount.fetch_add(1, std::memory_order_relaxed);
398  }
399  return isCounted;
400  }
401 
402  std::string _str;
403  char const *_cstr;
404  mutable uint64_t _compareCode;
405  mutable std::atomic_int _refCount;
406  mutable bool _isCounted;
407  mutable unsigned char _setNum;
408  };
409 
410  friend struct TfTokenFastArbitraryLessThan;
411  friend struct Tf_TokenRegistry;
412 
413  TF_API static std::string const& _GetEmptyString();
414 
415  mutable TfPointerAndBits<const _Rep> _rep;
416 };
417 
421  inline bool operator()(TfToken const &lhs, TfToken const &rhs) const {
422  return lhs._rep.Get() < rhs._rep.Get();
423  }
424 };
425 
427 TF_API std::vector<TfToken>
428 TfToTokenVector(const std::vector<std::string> &sv);
429 
431 TF_API std::vector<std::string>
432 TfToStringVector(const std::vector<TfToken> &tv);
433 
435 inline size_t hash_value(const TfToken& x) { return x.Hash(); }
436 
438 typedef std::vector<TfToken> TfTokenVector;
439 
440 PXR_NAMESPACE_CLOSE_SCOPE
441 
442 #endif // TF_TOKEN_H
std::string const & GetString() const
Return the string that this token represents.
Definition: token.h:209
TfToken & operator=(TfToken const &rhs) noexcept
Copy assignment.
Definition: token.h:106
bool operator!=(char const *o) const
Inequality operator for char strings.
Definition: token.h:263
friend TF_API std::ostream & operator<<(std::ostream &stream, TfToken const &)
Stream insertion.
bool operator<(TfToken const &r) const
Less-than operator that compares tokenized strings lexicographically.
Definition: token.h:274
constexpr T * Get() const noexcept
Retrieve the pointer.
bool operator==(TfToken const &o) const
Equality operator.
Definition: token.h:220
static TF_API TfToken Find(std::string const &s)
Find the token for the given string, if one exists.
Fast but non-lexicographical (in fact, arbitrary) less-than comparison for TfTokens.
Definition: token.h:420
size_t size() const
Return the size of the string that this token represents.
Definition: token.h:188
size_t Hash() const
Return a size_t hash for this token.
Definition: token.h:165
bool operator>=(TfToken const &o) const
Greater-than-or-equal operator that compares tokenized strings lexicographically. ...
Definition: token.h:297
TfToken(TfToken const &rhs) noexcept
Copy constructor.
Definition: token.h:98
bool operator!=(TfToken const &o) const
Equality operator.
Definition: token.h:228
Functor to use for hash maps from tokens to other things.
Definition: token.h:168
TF_API std::vector< TfToken > TfToTokenVector(const std::vector< std::string > &sv)
Convert the vector of strings sv into a vector of TfToken.
constexpr uintptr_t GetLiteral() const noexcept
Retrieve the raw underlying value.
friend bool operator!=(std::string const &o, TfToken const &t)
Definition: token.h:257
void SetBits(Integral val) noexcept
Set the stored bits. No static range checking is performed.
Provides hash function on STL string types and other types.
Definition: hash.h:86
bool operator<=(TfToken const &o) const
Less-than-or-equal operator that compares tokenized strings lexicographically.
Definition: token.h:303
TfToken(TfToken &&rhs) noexcept
Move constructor.
Definition: token.h:101
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:89
std::set< TfToken, TfTokenFastArbitraryLessThan > Set
Predefined type for set of tokens, for when faster lookup is desired, without paying the memory or in...
Definition: token.h:185
void swap(UsdStageLoadRules &l, UsdStageLoadRules &r)
Swap the contents of rules l and r.
bool operator!=(std::string const &o) const
Inequality operator for string&#39;s.
Definition: token.h:252
std::vector< TfToken > TfTokenVector
Convenience types.
Definition: token.h:438
bool operator>(TfToken const &o) const
Greater-than operator that compares tokenized strings lexicographically.
Definition: token.h:291
friend bool operator==(std::string const &o, TfToken const &t)
Definition: token.h:241
friend bool operator!=(char const *o, TfToken const &t)
Definition: token.h:268
TF_API std::vector< std::string > TfToStringVector(const std::vector< TfToken > &tv)
Convert the vector of TfToken tv into a vector of strings.
TfHashSet< TfToken, TfToken::HashFunctor > HashSet
Predefined type for TfHashSet of tokens, since it&#39;s so awkward to manually specify.
Definition: token.h:177
bool IsEmpty() const
Returns true iff this token contains the empty string &quot;&quot;.
Definition: token.h:311
constexpr Integral BitsAs() const noexcept
Retrieve the stored bits as the integral type Integral.
~TfToken()
Destructor.
Definition: token.h:126
void Swap(TfToken &other)
Swap this token with another.
Definition: token.h:215
friend bool operator==(const char *o, TfToken const &t)
Definition: token.h:246
constexpr TfToken() noexcept
Create the empty token, containing the empty string.
Definition: token.h:95
char const * data() const
Synonym for GetText().
Definition: token.h:204
bool IsImmortal() const
Returns true iff this is an immortal token.
Definition: token.h:314
char const * GetText() const
Return the text that this token represents.
Definition: token.h:198