HDK
 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 terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_TF_TOKEN_H
8 #define PXR_BASE_TF_TOKEN_H
9 
10 /// \file tf/token.h
11 ///
12 /// \c TfToken class for efficient string referencing and hashing, plus
13 /// conversions to and from stl string containers.
14 
15 #include "pxr/pxr.h"
16 
17 #include "pxr/base/tf/api.h"
19 #include "pxr/base/tf/hash.h"
20 #include "pxr/base/tf/hashset.h"
22 
23 #include <atomic>
24 #include <iosfwd>
25 #include <string>
26 #include <vector>
27 #include <set>
28 
30 
32 
33 /// \class TfToken
34 /// \ingroup group_tf_String
35 ///
36 /// Token for efficient comparison, assignment, and hashing of known strings.
37 ///
38 /// A TfToken is a handle for a registered string, and can be compared,
39 /// assigned, and hashed in constant time. It is useful when a bounded number
40 /// of strings are used as fixed symbols (but never modified).
41 ///
42 /// For example, the set of avar names in a shot is large but bounded, and
43 /// once an avar name is discovered, it is never manipulated. If these names
44 /// were passed around as strings, every comparison and hash would be linear
45 /// in the number of characters. (String assignment itself is sometimes a
46 /// constant time operation, but it is sometimes linear in the length of the
47 /// string as well as requiring a memory allocation.)
48 ///
49 /// To use TfToken, simply create an instance from a string or const char*.
50 /// If the string hasn't been seen before, a copy of it is added to a global
51 /// table. The resulting TfToken is simply a wrapper around an string*,
52 /// pointing that canonical copy of the string. Thus, operations on the token
53 /// are very fast. (The string's hash is simply the address of the canonical
54 /// copy, so hashing the string is constant time.)
55 ///
56 /// The free functions \c TfToTokenVector() and \c TfToStringVector() provide
57 /// conversions to and from vectors of \c string.
58 ///
59 /// Note: Access to the global table is protected by a mutex. This is a good
60 /// idea as long as clients do not construct tokens from strings too
61 /// frequently. Construct tokens only as often as you must (for example, as
62 /// you read data files), and <i>never</i> in inner loops. Of course, once
63 /// you have a token, feel free to compare, assign, and hash it as often as
64 /// you like. (That's what it's for.) In order to help prevent tokens from
65 /// being re-created over and over, auto type conversion from \c string and \c
66 /// char* to \c TfToken is disabled (you must use the explicit \c TfToken
67 /// constructors). However, auto conversion from \c TfToken to \c string and
68 /// \c char* is provided.
69 ///
70 class TfToken
71 {
72 public:
74 
75  /// Create the empty token, containing the empty string.
76  constexpr TfToken() noexcept = default;
77 
78  /// Copy constructor.
79  TfToken(TfToken const& rhs) noexcept : _rep(rhs._rep) { _AddRef(); }
80 
81  /// Move constructor.
82  TfToken(TfToken && rhs) noexcept : _rep(rhs._rep) {
83  rhs._rep = TfPointerAndBits<const _Rep>();
84  }
85 
86  /// Copy assignment.
87  TfToken& operator= (TfToken const& rhs) noexcept {
88  if (&rhs != this) {
89  rhs._AddRef();
90  _RemoveRef();
91  _rep = rhs._rep;
92  }
93  return *this;
94  }
95 
96  /// Move assignment.
97  TfToken& operator= (TfToken && rhs) noexcept {
98  if (&rhs != this) {
99  _RemoveRef();
100  _rep = rhs._rep;
101  rhs._rep = TfPointerAndBits<const _Rep>();
102  }
103  return *this;
104  }
105 
106  /// Destructor.
107  ~TfToken() { _RemoveRef(); }
108 
109  /// Acquire a token for the given string.
110  //
111  // This constructor involves a string hash and a lookup in the global
112  // table, and so should not be done more often than necessary. When
113  // possible, create a token once and reuse it many times.
114  TF_API explicit TfToken(std::string const& s);
115  /// \overload
116  // Create a token for \p s, and make it immortal. If \p s exists in the
117  // token table already and is not immortal, make it immortal. Immortal
118  // tokens are faster to copy than mortal tokens, but they will never expire
119  // and release their memory.
120  TF_API TfToken(std::string const& s, _ImmortalTag);
121 
122  /// Acquire a token for the given string.
123  //
124  // This constructor involves a string hash and a lookup in the global
125  // table, and so should not be done more often than necessary. When
126  // possible, create a token once and reuse it many times.
127  TF_API explicit TfToken(char const* s);
128  /// \overload
129  // Create a token for \p s, and make it immortal. If \p s exists in the
130  // token table already and is not immortal, make it immortal. Immortal
131  // tokens are faster to copy than mortal tokens, but they will never expire
132  // and release their memory.
133  TF_API TfToken(char const* s, _ImmortalTag);
134 
135  /// Find the token for the given string, if one exists.
136  //
137  // If a token has previous been created for the given string, this
138  // will return it. Otherwise, the empty token will be returned.
139  TF_API static TfToken Find(std::string const& s);
140 
141  /// Return a size_t hash for this token.
142  //
143  // The hash is based on the token's storage identity; this is immutable
144  // as long as the token is in use anywhere in the process.
145  //
146  inline size_t Hash() const;
147 
148  /// Functor to use for hash maps from tokens to other things.
149  struct HashFunctor {
150  size_t operator()(TfToken const& token) const { return token.Hash(); }
151  };
152 
153  /// \typedef TfHashSet<TfToken, TfToken::HashFunctor> HashSet;
154  ///
155  /// Predefined type for TfHashSet of tokens, since it's so awkward to
156  /// manually specify.
157  ///
159 
160  /// \typedef std::set<TfToken, TfTokenFastArbitraryLessThan> Set;
161  ///
162  /// Predefined type for set of tokens, for when faster lookup is
163  /// desired, without paying the memory or initialization cost of a
164  /// TfHashSet.
165  ///
166  typedef std::set<TfToken, TfTokenFastArbitraryLessThan> Set;
167 
168  /// Return the size of the string that this token represents.
169  size_t size() const {
170  _Rep const *rep = _rep.Get();
171  return rep ? rep->_str.size() : 0;
172  }
173 
174  /// Return the text that this token represents.
175  ///
176  /// \note The returned pointer value is not valid after this TfToken
177  /// object has been destroyed.
178  ///
179  char const* GetText() const {
180  _Rep const *rep = _rep.Get();
181  return rep ? rep->_str.c_str() : "";
182  }
183 
184  /// Synonym for GetText().
185  char const *data() const {
186  return GetText();
187  }
188 
189  /// Return the string that this token represents.
190  std::string const& GetString() const {
191  _Rep const *rep = _rep.Get();
192  return rep ? rep->_str : _GetEmptyString();
193  }
194 
195  /// Swap this token with another.
196  inline void Swap(TfToken &other) {
197  std::swap(_rep, other._rep);
198  }
199 
200  /// Equality operator
201  bool operator==(TfToken const& o) const {
202  // Equal if pointers & bits are equal, or if just pointers are.
203  return _rep.Get() == o._rep.Get();
204  }
205 
206  /// Equality operator
207  bool operator!=(TfToken const& o) const {
208  return !(*this == o);
209  }
210 
211  /// Equality operator for \c char strings. Not as fast as direct
212  /// token to token equality testing
213  TF_API bool operator==(std::string const& o) const;
214 
215  /// Equality operator for \c char strings. Not as fast as direct
216  /// token to token equality testing
217  TF_API bool operator==(const char *) const;
218 
219  /// \overload
220  friend bool operator==(std::string const& o, TfToken const& t) {
221  return t == o;
222  }
223 
224  /// \overload
225  friend bool operator==(const char *o, TfToken const& t) {
226  return t == o;
227  }
228 
229  /// Inequality operator for \c string's. Not as fast as direct
230  /// token to token equality testing
231  bool operator!=(std::string const& o) const {
232  return !(*this == o);
233  }
234 
235  /// \overload
236  friend bool operator!=(std::string const& o, TfToken const& t) {
237  return !(t == o);
238  }
239 
240  /// Inequality operator for \c char strings. Not as fast as direct
241  /// token to token equality testing
242  bool operator!=(char const* o) const {
243  return !(*this == o);
244  }
245 
246  /// \overload
247  friend bool operator!=(char const* o, TfToken const& t) {
248  return !(t == o);
249  }
250 
251  /// Less-than operator that compares tokenized strings lexicographically.
252  /// Allows \c TfToken to be used in \c std::set
253  inline bool operator<(TfToken const& r) const {
254  auto ll = _rep.GetLiteral(), rl = r._rep.GetLiteral();
255  if (!ll || !rl) {
256  // One or both are zero -- return true if ll is zero and rl is not.
257  return !ll && rl;
258  }
259  if (ll == rl) {
260  return false;
261  }
262  auto lrep = _rep.Get(), rrep = r._rep.Get();
263  uint64_t lcc = lrep->_compareCode, rcc = rrep->_compareCode;
264  return lcc < rcc || (lcc == rcc && lrep->_str < rrep->_str);
265  }
266 
267  /// Greater-than operator that compares tokenized strings lexicographically.
268  inline bool operator>(TfToken const& o) const {
269  return o < *this;
270  }
271 
272  /// Greater-than-or-equal operator that compares tokenized strings
273  /// lexicographically.
274  inline bool operator>=(TfToken const& o) const {
275  return !(*this < o);
276  }
277 
278  /// Less-than-or-equal operator that compares tokenized strings
279  /// lexicographically.
280  inline bool operator<=(TfToken const& o) const {
281  return !(*this > o);
282  }
283 
284  /// Allow \c TfToken to be auto-converted to \c string
285  operator std::string const& () const { return GetString(); }
286 
287  /// Returns \c true iff this token contains the empty string \c ""
288  bool IsEmpty() const { return _rep.GetLiteral() == 0; }
289 
290  /// Returns \c true iff this is an immortal token. Note that a return of \c
291  /// false could be instantly stale if another thread races to immortalize
292  /// this token. A return of \c true is always valid since tokens cannot
293  /// lose immortality.
294  bool IsImmortal() const {
295  if (!_rep.BitsAs<bool>()) {
296  return true;
297  }
298  // There is no synchronization or ordering constraints between this read
299  // and other reads/writes, so relaxed memory order suffices.
300  bool immortal = !(_rep->_refCount.load(std::memory_order_relaxed) & 1);
301  if (immortal) {
302  // Our belief is wrong, update our cache of countedness.
303  _rep.SetBits(false);
304  }
305  return immortal;
306  }
307 
308  /// Stream insertion.
309  friend TF_API std::ostream &operator <<(std::ostream &stream, TfToken const&);
310 
311  /// TfHash support.
312  template <class HashState>
313  friend void
314  TfHashAppend(HashState &h, TfToken const &token) {
315  h.Append(token._rep.Get());
316  }
317 
318 private:
319  // Add global swap overload.
320  friend void swap(TfToken &lhs, TfToken &rhs) {
321  lhs.Swap(rhs);
322  }
323 
324  void _AddRef() const {
325  if (!_rep.BitsAs<bool>()) {
326  // Not counted, do nothing.
327  return;
328  }
329  // We believe this rep is refCounted.
330  if (!_rep->IncrementAndCheckCounted()) {
331  // Our belief is wrong, update our cache of countedness.
332  _rep.SetBits(false);
333  }
334  }
335 
336  void _RemoveRef() const {
337  if (!_rep.BitsAs<bool>()) {
338  // Not counted, do nothing.
339  return;
340  }
341  // Decrement the refcount.
342  _rep->Decrement();
343  }
344 
345  struct _Rep {
346  _Rep() = default;
347 
348  explicit _Rep(std::string &&str,
349  unsigned setNum,
350  uint64_t compareCode)
351  : _setNum(setNum)
352  , _compareCode(compareCode)
353  , _str(std::move(str))
354  , _cstr(_str.c_str()) {}
355 
356  explicit _Rep(std::string const &str,
357  unsigned setNum,
358  uint64_t compareCode)
359  : _Rep(std::string(str), setNum, compareCode) {}
360 
361  explicit _Rep(char const *str,
362  unsigned setNum,
363  uint64_t compareCode)
364  : _Rep(std::string(str), setNum, compareCode) {}
365 
366  // Make sure we reacquire _cstr from _str on copy and assignment
367  // to avoid holding on to a dangling pointer. However, if rhs'
368  // _cstr member doesn't come from its _str, just copy it directly
369  // over. This is to support lightweight _Rep objects used for
370  // internal lookups.
371  _Rep(_Rep const &rhs)
372  : _refCount(rhs._refCount.load(std::memory_order_relaxed))
373  , _setNum(rhs._setNum)
374  , _compareCode(rhs._compareCode)
375  , _str(rhs._str)
376  , _cstr(rhs._str.c_str() == rhs._cstr ? _str.c_str() : rhs._cstr) {}
377 
378  _Rep &operator=(_Rep const &rhs) {
379  _refCount = rhs._refCount.load(std::memory_order_relaxed);
380  _setNum = rhs._setNum;
381  _compareCode = rhs._compareCode;
382  _str = rhs._str;
383  _cstr = (rhs._str.c_str() == rhs._cstr ? _str.c_str() : rhs._cstr);
384  return *this;
385  }
386 
387  inline bool IncrementAndCheckCounted() const {
388  // Refcounts are manipulated by add/sub 2, since the lowest-order
389  // bit indicates whether or not the rep is counted.
390  return _refCount.fetch_add(2, std::memory_order_relaxed) & 1;
391  }
392 
393  inline void Decrement() const {
394  // Refcounts are manipulated by add/sub 2, since the lowest-order
395  // bit indicates whether or not the rep is counted.
396  _refCount.fetch_sub(2, std::memory_order_release);
397  }
398 
399  mutable std::atomic_uint _refCount;
400  unsigned _setNum;
401  uint64_t _compareCode;
402  std::string _str;
403  char const *_cstr;
404  };
405 
407  friend struct Tf_TokenRegistry;
408 
409  TF_API static std::string const& _GetEmptyString();
410 
411  mutable TfPointerAndBits<const _Rep> _rep;
412 };
413 
414 inline size_t
416 {
417  return TfHash()(*this);
418 }
419 
420 /// Fast but non-lexicographical (in fact, arbitrary) less-than comparison for
421 /// TfTokens. Should only be used in performance-critical cases.
423  inline bool operator()(TfToken const &lhs, TfToken const &rhs) const {
424  return lhs._rep.Get() < rhs._rep.Get();
425  }
426 };
427 
428 /// Convert the vector of strings \p sv into a vector of \c TfToken
429 TF_API std::vector<TfToken>
430 TfToTokenVector(const std::vector<std::string> &sv);
431 
432 /// Convert the vector of \c TfToken \p tv into a vector of strings
433 TF_API std::vector<std::string>
434 TfToStringVector(const std::vector<TfToken> &tv);
435 
436 /// Overload hash_value for TfToken.
437 inline size_t hash_value(const TfToken& x) { return x.Hash(); }
438 
439 /// Convenience types.
440 typedef std::vector<TfToken> TfTokenVector;
441 
443 
444 #endif // PXR_BASE_TF_TOKEN_H
GLuint GLuint stream
Definition: glcorearb.h:1832
friend void TfHashAppend(HashState &h, TfToken const &token)
TfHash support.
Definition: token.h:314
void Swap(TfToken &other)
Swap this token with another.
Definition: token.h:196
friend TF_API std::ostream & operator<<(std::ostream &stream, TfToken const &)
Stream insertion.
_ImmortalTag
Definition: token.h:73
#define TF_API
Definition: api.h:23
void swap(UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &a, UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &b)
Definition: UT_ArraySet.h:1699
void SetBits(Integral val) noexcept
Set the stored bits. No static range checking is performed.
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
bool IsImmortal() const
Definition: token.h:294
std::string const & GetString() const
Return the string that this token represents.
Definition: token.h:190
GLdouble s
Definition: glad.h:3009
Functor to use for hash maps from tokens to other things.
Definition: token.h:149
TF_API std::vector< TfToken > TfToTokenVector(const std::vector< std::string > &sv)
Convert the vector of strings sv into a vector of TfToken.
TfToken & operator=(TfToken const &rhs) noexcept
Copy assignment.
Definition: token.h:87
friend bool operator!=(std::string const &o, TfToken const &t)
Definition: token.h:236
bool operator()(TfToken const &lhs, TfToken const &rhs) const
Definition: token.h:423
size_t size() const
Return the size of the string that this token represents.
Definition: token.h:169
constexpr T * Get() const noexcept
Retrieve the pointer.
TfHashSet< TfToken, TfToken::HashFunctor > HashSet
Definition: token.h:158
Definition: hash.h:472
bool operator<=(TfToken const &o) const
Definition: token.h:280
bool operator!=(char const *o) const
Definition: token.h:242
Definition: token.h:70
constexpr uintptr_t GetLiteral() const noexcept
size_t operator()(TfToken const &token) const
Definition: token.h:150
size_t hash_value(const TfToken &x)
Overload hash_value for TfToken.
Definition: token.h:437
TfToken(TfToken &&rhs) noexcept
Move constructor.
Definition: token.h:82
char const * data() const
Synonym for GetText().
Definition: token.h:185
friend void swap(TfToken &lhs, TfToken &rhs)
Definition: token.h:320
constexpr Integral BitsAs() const noexcept
Retrieve the stored bits as the integral type Integral.
bool operator>(TfToken const &o) const
Greater-than operator that compares tokenized strings lexicographically.
Definition: token.h:268
std::vector< TfToken > TfTokenVector
Convenience types.
Definition: token.h:440
friend bool operator==(std::string const &o, TfToken const &t)
Definition: token.h:220
GLint GLenum GLint x
Definition: glcorearb.h:409
friend bool operator!=(char const *o, TfToken const &t)
Definition: token.h:247
char const * GetText() const
Definition: token.h:179
bool operator!=(std::string const &o) const
Definition: token.h:231
GLdouble t
Definition: glad.h:2397
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:2002
bool operator!=(TfToken const &o) const
Equality operator.
Definition: token.h:207
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
static TF_API TfToken Find(std::string const &s)
Find the token for the given string, if one exists.
TF_API std::vector< std::string > TfToStringVector(const std::vector< TfToken > &tv)
Convert the vector of TfToken tv into a vector of strings.
~TfToken()
Destructor.
Definition: token.h:107
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
friend struct Tf_TokenRegistry
Definition: token.h:407
OIIO_UTIL_API const char * c_str(string_view str)
constexpr TfToken() noexcept=default
Create the empty token, containing the empty string.
bool operator==(TfToken const &o) const
Equality operator.
Definition: token.h:201
bool operator<(TfToken const &r) const
Definition: token.h:253
GLboolean r
Definition: glcorearb.h:1222
friend bool operator==(const char *o, TfToken const &t)
Definition: token.h:225
size_t Hash() const
Return a size_t hash for this token.
Definition: token.h:415
bool operator>=(TfToken const &o) const
Definition: token.h:274
std::set< TfToken, TfTokenFastArbitraryLessThan > Set
Definition: token.h:166
bool IsEmpty() const
Returns true iff this token contains the empty string "".
Definition: token.h:288