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