HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GA_BlobContainer.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: GA_BlobContainer.h ( GA Library, C++)
7  *
8  */
9 
10 #ifndef __GA_BlobContainer__
11 #define __GA_BlobContainer__
12 
13 #include "GA_API.h"
14 #include "GA_BlobData.h"
15 
16 #include <UT/UT_IndexedHashMapT.h>
17 #include <UT/UT_VectorTypes.h>
18 
19 #include <SYS/SYS_Types.h>
20 
21 
22 template <typename T> class UT_Array;
23 template <typename T> class UT_ValArray;
25 
26 
28 #define GA_INVALID_BLOB_INDEX GA_BlobIndex(-1)
29 
30 
31 /// @brief Container to store blobs of arbitrary data for attributes
32 ///
33 /// The geometry library can store blobs of binary data for each object
34 /// element. It does this by storing a shared reference count. Blobs are
35 /// added to the blob container and accessed by integer handle (index).
36 ///
37 /// As a developer, the semantics of: @code
38 /// handle = container.addBlob(blob);
39 /// @endcode
40 /// are that the container will create a @b copy of the blob. It will
41 /// associate an integer index with that blob and return the index.
42 ///
43 /// To test whether a blob is in the container, you can call: @code
44 /// handle = container.getIndex(blob);
45 /// @endcode
46 /// This will not add a blob to the container.
47 ///
48 /// You get the blob back out of the container by calling: @code
49 /// blob = container.getBlob(handle);
50 /// @endcode
51 /// It's important to realize that the blob you get back from the container is
52 /// immutable. If you need to change the blob, you need to make a copy and
53 /// store the modifed version in the container.
54 ///
55 /// Blobs are deleted from the container by calling: @code
56 /// container.freeBlob(handle);
57 /// @endcode
58 /// You should call @c freeBlob() for each blob you stored calling @addBlob()
59 ///
60 /// @note
61 /// Blobs are stored using UT_COW. This enforces the fact that the blobs are
62 /// immutable once they have been stored in the container. The container only
63 /// provides read-pointers when you get blobs out of the container.
64 ///
65 /// An example of how you might store a blob: @code
66 /// GA_BlobRef bref(new MyBlobSubClass());
67 /// handle = container.addBlob( bref );
68 /// @endcode
69 ///
70 
72 {
73 public:
76 
77  /// Report approximate memory usage (*including* storage for blobs)
78  /// @note Not thread safe
79  int64 getMemoryUsage(bool inclusive) const;
80 
81  /// Count memory usage using a UT_MemoryCounter in order to count
82  /// shared memory correctly.
83  /// If inclusive is true, the size of this object is counted,
84  /// else only memory owned by this object is counted.
85  /// If this is pointed to by the calling object, inclusive should be true.
86  /// If this is contained in the calling object, inclusive should be false.
87  /// (Its memory was already counted in the size of the calling object.)
88  /// @note Not thread safe
89  void countMemory(UT_MemoryCounter &counter, bool inclusive) const;
90 
91  /// Allocated size of the container
92  /// @note Not thread safe
93  int capacity() const
94  { return myMap.getItemIdUpperBound()+1; }
95  /// Occupied size of the container
96  /// @note Not thread safe
97  int entries() const
98  { return myMap.entries(); }
99 
100  /// Get occupancy of the map which can be used to determine whether
101  /// compaction is required.
102  /// @note Not thread safe
104  {
105  return myMap.getOccupancy();
106  }
107 
108  /// Return the blob for a given handle. If the handle isn't valid,
109  /// a NULL ptr will be returned.
110  /// @note This method is thread safe
113  {
114  const MapItem *item = myMap[handle];
115  return item ? item->getKey().getBlob() : GA_BlobRef();
116  }
117 
118  /// Return the blob for a given handle. If the handle isn't valid,
119  /// a NULL ptr will be returned.
120  /// @note This method is thread safe
122  const GA_BlobData *getRawBlob(GA_BlobIndex handle) const
123  {
124  const MapItem *item = myMap[handle];
125  return item ? item->getKey().getBlob().get() : nullptr;
126  }
127 
128  /// Return the n'th blob given in an ordered list of blobs. This method
129  /// may be significantly more expensive than looking up by @c GA_BlobIndex
130  /// or extracting all items at one time. For example: @code
131  /// for (exint i = 0; ; ++i)
132  /// {
133  /// GA_BlobRef blob = blobcontainer.getOrderedBlob(i);
134  /// if (!blob)
135  /// break;
136  /// }
137  /// @note This method is @b not thread safe
138  GA_BlobRef getOrderedBlob(exint index) const
139  {
140  const MapItem *item;
141  item = myMap.getOrderedItem(index);
142  return item ? item->getKey().getBlob()
143  : GA_BlobRef();
144  }
145 
146  /// @{
147  /// Look up an index for a given blob. If the blob isn't in the container,
148  /// the return code will be -1.
149  /// @note This method is thread safe
150  GA_BlobIndex getIndex(const GA_BlobRef &blob) const
151  { return myMap.findId(blob); }
152  /// @}
153 
154  /// Blobs are stored in a sparse array. When looping over all valid
155  /// offsets, this method will "validate" the handle. That is, if there's
156  /// no blob stored at the location, it will map it to -1.
157  /// @note This method is thread safe
158  GA_BlobIndex validateIndex(GA_BlobIndex index) const;
159 
160  /// @{
161  /// Replace the blob for the given index with a new blob. The new index
162  /// will be returned. This is equivalent to: @code
163  /// freeBlob(prevhandle);
164  /// return addBlob(blob);
165  /// @endcode
166  /// @note This method is thread safe
168  const GA_BlobRef &blob)
169  { return myMap.replaceItem(prevhandle, blob); }
170  /// @}
171 
172 #if 0
173  /// Replace the blob for the given index with a new blob. The new index
174  /// will be returned. This is equivalent to: @code
175  /// return replaceBlob(prevhandle, GA_BlobRef(getBlob(newhandle)));
176  /// @endcode
177  /// @note This method is thread safe
178  GA_BlobIndex replaceBlob(GA_BlobIndex prevhandle,
179  GA_BlobIndex newhandle);
180 #endif
181 
182  /// @{
183  /// Allocate a new blob and return the index to the blob.
184  /// @note This method is thread safe
185  GA_BlobIndex addBlob(const GA_BlobRef &blob);
186  /// @}
187 
188  /// Add a reference to the blob given by the index.
189  /// This is equivalent to: @code
190  /// addBlob( getBlob(handle) );
191  /// @endcode
192  /// @note This method is thread safe
193  /// @note inc must be positive.
194  /// @{
195  void addIndexReference(GA_BlobIndex handle, int inc)
196  { myMap.addReference(handle, inc); }
198  { addIndexReference(handle, 1); }
199  /// @}
200 
201  /// For debugging purposes, this returns the number of references
202  /// to this blob index in this map.
204  {
205  return myMap.getReferenceCount(handle);
206  }
207 
208  /// Free the blob (de-reference) given by the handle
209  /// @note This method is thread safe
210  bool freeBlob(GA_BlobIndex handle)
211  { return myMap.remove(handle); }
212 
213  /// @{
214  /// Free the given blob (de-reference) by blob pointer. This is equivalent
215  /// to: @code
216  /// freeBlob( getIndex(blob) );
217  /// @endcode
218  /// @note This method is thread safe
219  bool freeBlob(const GA_BlobRef &blob)
220  { return myMap.remove(MapKey(blob)); }
221  /// @}
222 
223  /// This will forcibly clear out all blobs, regardless of whether they have
224  /// references. Use this with caution.
225  /// @note Not thread safe
226  void clear() { myMap.clear(); }
227 
228  /// Extract the blobs into two arrays.
229  /// - The array of blobs is the list of unique blobs in the container.
230  /// - The handles are the corresponding integer handles
231  /// The return code is the largest handle in the list (or -1 if there are
232  /// no blobs in the container).
233  /// @warning The maximum handle value may be is @b less than the number of
234  /// blobs stored in the container. There may also be integer handles which
235  /// aren't valid handles between 0 and the maximum.
236  /// @note Not thread safe
237  GA_BlobIndex extractBlobs(UT_Array<GA_BlobRef> &array,
238  UT_IntArray &handles) const;
239  GA_BlobIndex extractBlobs(UT_Array<GA_BlobRef> &array,
240  UT_IntArray &handles, exint maxblobs) const;
241 
242  /// Return the maximum index number used. If the maximum index is less
243  /// than zero, there are no blobs in the container.
244  /// @warning The maximum index value may be is @b greater than the number of
245  /// blobs stored in the container. There may also be values which aren't
246  /// bound to a blob between 0 and the maximum.
247  /// @note Not thread safe
249  { return myMap.getItemIdUpperBound(); }
250 
251  /// Compact blobs can be called to "shrink" the index list (i.e. remove
252  /// all vacancies in the index list). Since this will change the index
253  /// values, a mapping array is returned which can be used to map the
254  /// existing handle value to the new handle value. For example: @code
255  /// UT_ValArray<GA_BlobIndex> map;
256  /// GA_Range range(...);
257  /// if (myBlobData.compactStrings(map)) {
258  /// for (GA_Iterator it(range); !it.atEnd(); ++it)
259  /// attribute_data[it.getOffset()] =
260  /// map(attribute_data[it.getOffset()]);
261  /// }
262  /// @endcode
263  /// @note Not thread safe
264  bool compactBlobs(UT_ValArray<GA_BlobIndex> &map);
265 
266  /// Replaces the content of this with the content of src.
267  void replace(const GA_BlobContainer &src);
268 
269 private:
270  class MapKey
271  {
272  public:
273  MapKey(const GA_BlobRef &blob)
274  : myBlob(blob)
275  {}
276  MapKey(const MapKey &src)
277  : myBlob(src.myBlob)
278  {
279  }
280  uint hash() const
281  {
282  return myBlob ? myBlob->hash() : 123456789;
283  }
284  bool isEqual(const MapKey &src) const
285  {
286  if (!myBlob || !src.myBlob)
287  return (myBlob && src.myBlob);
288  return myBlob->isEqual(*src.myBlob);
289  }
290 
292  const GA_BlobRef &getBlob() const
293  { return myBlob; }
294  bool operator<(const MapKey &src) const
295  { return myBlob.get() < src.myBlob.get(); }
296 
297  int64 getMemoryUsage(bool inclusive) const
298  {
299  int64 mem = inclusive ? sizeof(*this) : 0;
300  mem += myBlob->getMemoryUsage(true);
301  return mem;
302  }
303 
304  void countMemory(UT_MemoryCounter &counter, bool inclusive) const;
305 
306  private:
307  GA_BlobRef myBlob;
308  };
311 
313 };
314 
315 #endif
void addIndexReference(GA_BlobIndex handle, int inc)
GA_BlobIndex getMaximumIndex() const
#define GA_API
Definition: GA_API.h:12
A thread-safe hash map which stores indexed shared items.
long long int64
Definition: SYS_Types.h:107
void addIndexReference(GA_BlobIndex handle)
exint getIndexReferenceCount(GA_BlobIndex handle) const
UT_IndexedHashMapItemId GA_BlobIndex
int64 exint
Definition: SYS_Types.h:116
int capacity() const
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
bool operator<(const GU_TetrahedronFacet &a, const GU_TetrahedronFacet &b)
UT_IntrusivePtr< GA_BlobData > GA_BlobRef
Definition: GA_BlobData.h:82
unsigned int uint
Definition: SYS_Types.h:40
bool freeBlob(GA_BlobIndex handle)
int entries() const
SYS_FORCE_INLINE const GA_BlobData * getRawBlob(GA_BlobIndex handle) const
double fpreal
Definition: SYS_Types.h:270
SYS_FORCE_INLINE GA_BlobRef getBlob(GA_BlobIndex handle) const
GLuint index
Definition: glcorearb.h:785
GA_BlobIndex replaceBlob(GA_BlobIndex prevhandle, const GA_BlobRef &blob)
int UT_IndexedHashMapItemId
Each item in the shared map is assigned a unique id.
Container to store blobs of arbitrary data for attributes.
bool freeBlob(const GA_BlobRef &blob)
GLenum src
Definition: glcorearb.h:1792
fpreal getOccupancy() const