HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
staticData.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 PXR_BASE_TF_STATIC_DATA_H
25 #define PXR_BASE_TF_STATIC_DATA_H
26 
27 /// \file tf/staticData.h
28 /// \ingroup group_tf_Initialization
29 
30 #include "pxr/pxr.h"
31 #include "pxr/base/arch/hints.h"
34 
35 #include <atomic>
36 #include <type_traits>
37 
39 
40 /// \class TfStaticData
41 /// \ingroup group_tf_Initialization
42 ///
43 /// Create or return a previously created object instance of global data.
44 ///
45 /// Any form of global data that requires an constructor (even a default
46 /// constructor) is unsafe to declare as global data. By global data we mean
47 /// either a variable defined at file-scope (outside of a function) or a
48 /// static member of a class. This is because the initialization order of
49 /// globals is undefined across translation units.
50 ///
51 /// The only exceptions are constexpr constructors and "plain old data" types
52 /// such as integral or float/double type and pointers. In contrast, \c
53 /// std::string requires construction, as do most \c STL types, and most
54 /// user-defined types as well. Note that static local variables in functions
55 /// are also safe and are initialized in a thread-safe manner the first time
56 /// they're encountered.
57 ///
58 /// One way to handle this problem is to go the singleton route, which can be
59 /// done using the \c TfSingleton pattern. However, a fair amount of coding is
60 /// required for this, and at times, something more lightweight is appropriate.
61 /// For these few cases, the following construct may be employed:
62 ///
63 /// \code
64 /// // source file:
65 ///
66 /// #include <set>
67 /// #include <string>
68 ///
69 /// static TfStaticData<set<string> > Xyz_nameSet;
70 ///
71 /// void XyzAddName(string name) {
72 /// Xyz_nameSet->insert(name);
73 ///
74 /// ...
75 /// }
76 /// \endcode
77 ///
78 /// One uses a \c TfStaticData<T> as if it were a pointer; upon first use
79 /// however, the item is initialized to point at a new object of type \c T. Note
80 /// that the type \c T must have a default constructor; that is, the newly
81 /// created object is created by calling \c "new T".
82 ///
83 /// If you have no need to access the data, but need to make sure it has been
84 /// initialized (for example, if the type's constructor will have some effect
85 /// that you need to be sure has happened), you can call the Touch() method.
86 ///
87 /// Warning: the \c TfStaticData construct relies upon zero-initialization of
88 /// global data: therefore, you can only use this structure for static data
89 /// member of classes or variables declare at file-scope. Do \e not declare
90 /// a \c TfStaticData object as a local variable, as a member of a class or
91 /// structure, or as a function parameter. Use normal static local variable
92 /// initialization inside a function.
93 ///
94 /// One can either call member functions using the "->" operator, or use the
95 /// dereference "*" operator:
96 ///
97 /// \code
98 /// TfStaticData<string> Xyz_curName;
99 ///
100 /// void Xyz_SetLastName(string s) {
101 /// *Xyz_curName = s;
102 ///
103 /// vector<string> v;
104 /// v.push_back(*Xyz_curName);
105 /// }
106 /// \endcode
107 ///
108 template <class T>
110  static T *New() { return new T; }
111 };
112 
113 template <class T, class Factory = Tf_StaticDataDefaultFactory<T> >
115 public:
116  /// Return a pointer to the underlying data object. It is created and
117  /// initialized if necessary.
118  inline T* operator-> () const { return Get(); }
119 
120  /// Member lookup. The underlying data object is created and initialized
121  /// if necessary.
122  inline T& operator* () const { return *Get(); }
123 
124  /// Return a pointer to the underlying object, creating and initializing
125  /// it if necessary.
126  inline T* Get() const {
127  T *p = _data;
128  return ARCH_LIKELY(p) ? p : _TryToCreateData();
129  }
130 
131  /// Return true if the underlying data object is created and initialized.
132  /// Return false otherwise.
133  inline bool IsInitialized() const { return _data.load() != nullptr; }
134 
135 private:
136  T *_TryToCreateData() const {
137  // Allocate an instance.
138  T *tmp = Factory::New();
139 
140  // Try to atomically set the pointer from null to tmp.
141  T *n = nullptr;
142  if (ARCH_LIKELY(_data.compare_exchange_strong(n, tmp)))
143  return tmp;
144 
145  // Another thread won the initialization race.
146  delete tmp;
147  return _data;
148  }
149 
150  mutable std::atomic<T *> _data;
151 };
152 
153 /// Create a static data object, initializing it with code.
154 ///
155 /// The macro takes two arguments. The first is the type of static data, the
156 /// second is the name of the variable. The block of code following the macro
157 /// will be invoked to initialize the static data when it is first used. See
158 /// example usage:
159 ///
160 /// \code
161 /// TF_MAKE_STATIC_DATA(string, myString) { *myString = "hello!"; }
162 ///
163 /// TF_MAKE_STATIC_DATA(vector<string>, someNames) {
164 /// someNames->push_back("hello");
165 /// someNames->push_back("static");
166 /// someNames->push_back("world");
167 /// }
168 ///
169 /// TF_MAKE_STATIC_DATA((map<int, int>), intMap) {
170 /// (*intMap)[1] = 11;
171 /// (*intMap)[2] = 22;
172 /// }
173 /// \endcode
174 ///
175 /// If the type uses commas to separate template arguments you need to enclose
176 /// the type in parentheses as shown in the last example.
177 ///
178 /// If the data does not need to be mutated after initialization, you may
179 /// specify a const type. The underlying data is non-const but the
180 /// TfStaticData accessors only provide const access.
181 ///
182 /// \code
183 /// TF_MAKE_STATIC_DATA(const vector<string>, constNames) {
184 /// constNames->push_back("hello");
185 /// constNames->push_back("static const");
186 /// constNames->push_back("world");
187 /// }
188 /// \endcode
189 ///
190 /// Note that this macro may only be used at namespace scope (not function
191 /// scope).
192 ///
193 /// Also note that in multithreaded code, it is possible for the provided code
194 /// to be invoked more than once (with different target objects) for the same
195 /// static data instance. This is fine as long as the initialization code does
196 /// not have side-effects, but you should be aware of it.
197 ///
198 /// \hideinitializer
199 #define TF_MAKE_STATIC_DATA(Type, Name) \
200  static void TF_PP_CAT(Name,_Tf_StaticDataFactoryImpl)( \
201  std::remove_const_t<TF_PP_EAT_PARENS(Type)> *); \
202  namespace { \
203  struct TF_PP_CAT(Name,_Tf_StaticDataFactory) { \
204  static TF_PP_EAT_PARENS(Type) *New() { \
205  auto *p = new std::remove_const_t<TF_PP_EAT_PARENS(Type)>; \
206  TF_PP_CAT(Name,_Tf_StaticDataFactoryImpl)(p); \
207  return p; \
208  } \
209  }; \
210  } \
211  static TfStaticData< \
212  TF_PP_EAT_PARENS(Type), TF_PP_CAT(Name,_Tf_StaticDataFactory)> Name; \
213  static void TF_PP_CAT(Name,_Tf_StaticDataFactoryImpl)( \
214  std::remove_const_t<TF_PP_EAT_PARENS(Type)> *Name)
215 
217 
218 #endif
#define ARCH_LIKELY(x)
Definition: hints.h:46
T & operator*() const
Definition: staticData.h:122
GLdouble n
Definition: glcorearb.h:2008
T * operator->() const
Definition: staticData.h:118
bool IsInitialized() const
Definition: staticData.h:133
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1441
T * Get() const
Definition: staticData.h:126
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91