| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright Contributors to the OpenVDB Project | ||
| 2 | // SPDX-License-Identifier: MPL-2.0 | ||
| 3 | |||
| 4 | /// @file points/AttributeSet.h | ||
| 5 | /// | ||
| 6 | /// @authors Dan Bailey, Mihai Alden | ||
| 7 | /// | ||
| 8 | /// @brief Set of Attribute Arrays which tracks metadata about each array. | ||
| 9 | |||
| 10 | #ifndef OPENVDB_POINTS_ATTRIBUTE_SET_HAS_BEEN_INCLUDED | ||
| 11 | #define OPENVDB_POINTS_ATTRIBUTE_SET_HAS_BEEN_INCLUDED | ||
| 12 | |||
| 13 | #include "AttributeArray.h" | ||
| 14 | #include <openvdb/version.h> | ||
| 15 | #include <openvdb/MetaMap.h> | ||
| 16 | |||
| 17 | #include <limits> | ||
| 18 | #include <memory> | ||
| 19 | #include <vector> | ||
| 20 | |||
| 21 | |||
| 22 | class TestAttributeSet; | ||
| 23 | |||
| 24 | |||
| 25 | namespace openvdb { | ||
| 26 | OPENVDB_USE_VERSION_NAMESPACE | ||
| 27 | namespace OPENVDB_VERSION_NAME { | ||
| 28 | namespace points { | ||
| 29 | |||
| 30 | |||
| 31 | using GroupType = uint8_t; | ||
| 32 | |||
| 33 | |||
| 34 | //////////////////////////////////////// | ||
| 35 | |||
| 36 | |||
| 37 | /// Ordered collection of uniquely-named attribute arrays | ||
| 38 | class OPENVDB_API AttributeSet | ||
| 39 | { | ||
| 40 | public: | ||
| 41 | enum { INVALID_POS = std::numeric_limits<size_t>::max() }; | ||
| 42 | |||
| 43 | using Ptr = std::shared_ptr<AttributeSet>; | ||
| 44 | using ConstPtr = std::shared_ptr<const AttributeSet>; | ||
| 45 | using UniquePtr = std::unique_ptr<AttributeSet>; | ||
| 46 | |||
| 47 | class Descriptor; | ||
| 48 | |||
| 49 | using DescriptorPtr = std::shared_ptr<Descriptor>; | ||
| 50 | using DescriptorConstPtr = std::shared_ptr<const Descriptor>; | ||
| 51 | |||
| 52 | ////////// | ||
| 53 | |||
| 54 | struct Util | ||
| 55 | { | ||
| 56 | /// Attribute and type name pair. | ||
| 57 | 67248 | struct NameAndType { | |
| 58 | 54992 | NameAndType(const std::string& n, const NamePair& t, const Index s = 1) | |
| 59 |
1/2✓ Branch 2 taken 54992 times.
✗ Branch 3 not taken.
|
54992 | : name(n), type(t), stride(s) {} |
| 60 | Name name; | ||
| 61 | NamePair type; | ||
| 62 | Index stride; | ||
| 63 | }; | ||
| 64 | |||
| 65 | using NameAndTypeVec = std::vector<NameAndType>; | ||
| 66 | using NameToPosMap = std::map<std::string, size_t>; | ||
| 67 | using GroupIndex = std::pair<size_t, uint8_t>; | ||
| 68 | }; | ||
| 69 | |||
| 70 | ////////// | ||
| 71 | |||
| 72 | AttributeSet(); | ||
| 73 | |||
| 74 | /// Construct a new AttributeSet from the given AttributeSet. | ||
| 75 | /// @param attributeSet the old attribute set | ||
| 76 | /// @param arrayLength the desired length of the arrays in the new AttributeSet | ||
| 77 | /// @param lock an optional scoped registry lock to avoid contention | ||
| 78 | /// @note This constructor is typically used to resize an existing AttributeSet as | ||
| 79 | /// it transfers attribute metadata such as hidden and transient flags | ||
| 80 | AttributeSet(const AttributeSet& attributeSet, Index arrayLength, | ||
| 81 | const AttributeArray::ScopedRegistryLock* lock = nullptr); | ||
| 82 | |||
| 83 | /// Construct a new AttributeSet from the given Descriptor. | ||
| 84 | /// @param descriptor stored in the new AttributeSet and used in construction | ||
| 85 | /// @param arrayLength the desired length of the arrays in the new AttributeSet | ||
| 86 | /// @param lock an optional scoped registry lock to avoid contention | ||
| 87 | /// @note Descriptors do not store attribute metadata such as hidden and transient flags | ||
| 88 | /// which live on the AttributeArrays, so for constructing from an existing AttributeSet | ||
| 89 | /// use the AttributeSet(const AttributeSet&, Index) constructor instead | ||
| 90 | AttributeSet(const DescriptorPtr& descriptor, Index arrayLength = 1, | ||
| 91 | const AttributeArray::ScopedRegistryLock* lock = nullptr); | ||
| 92 | |||
| 93 | /// Shallow copy constructor, the descriptor and attribute arrays will be shared. | ||
| 94 | AttributeSet(const AttributeSet&); | ||
| 95 | |||
| 96 | /// Disallow copy assignment, since it wouldn't be obvious whether the copy is deep or shallow. | ||
| 97 | AttributeSet& operator=(const AttributeSet&) = delete; | ||
| 98 | |||
| 99 | //@{ | ||
| 100 | /// @brief Return a reference to this attribute set's descriptor, which might | ||
| 101 | /// be shared with other sets. | ||
| 102 | Descriptor& descriptor() { return *mDescr; } | ||
| 103 | const Descriptor& descriptor() const { return *mDescr; } | ||
| 104 | //@} | ||
| 105 | |||
| 106 | /// @brief Return a pointer to this attribute set's descriptor, which might be | ||
| 107 | /// shared with other sets | ||
| 108 | DescriptorPtr descriptorPtr() const { return mDescr; } | ||
| 109 | |||
| 110 | /// Return the number of attributes in this set. | ||
| 111 | size_t size() const { return mAttrs.size(); } | ||
| 112 | |||
| 113 | /// Return the number of bytes of memory used by this attribute set. | ||
| 114 | size_t memUsage() const; | ||
| 115 | |||
| 116 | #if OPENVDB_ABI_VERSION_NUMBER >= 10 | ||
| 117 | /// Return the number of bytes of memory used by this attribute set once it | ||
| 118 | /// has been deserialized (this may be different to memUsage() if delay-loading | ||
| 119 | /// is in use). | ||
| 120 | size_t memUsageIfLoaded() const; | ||
| 121 | #endif | ||
| 122 | |||
| 123 | /// @brief Return the position of the attribute array whose name is @a name, | ||
| 124 | /// or @c INVALID_POS if no match is found. | ||
| 125 | size_t find(const std::string& name) const; | ||
| 126 | |||
| 127 | /// @brief Replace the attribute array whose name is @a name. | ||
| 128 | /// @return The position of the updated attribute array or @c INVALID_POS | ||
| 129 | /// if the given name does not exist or if the replacement failed because | ||
| 130 | /// the new array type does not comply with the descriptor. | ||
| 131 | size_t replace(const std::string& name, const AttributeArray::Ptr&); | ||
| 132 | |||
| 133 | /// @brief Replace the attribute array stored at position @a pos in this container. | ||
| 134 | /// @return The position of the updated attribute array or @c INVALID_POS | ||
| 135 | /// if replacement failed because the new array type does not comply with | ||
| 136 | /// the descriptor. | ||
| 137 | size_t replace(size_t pos, const AttributeArray::Ptr&); | ||
| 138 | |||
| 139 | //@{ | ||
| 140 | /// @brief Return a pointer to the attribute array whose name is @a name or | ||
| 141 | /// a null pointer if no match is found. | ||
| 142 | const AttributeArray* getConst(const std::string& name) const; | ||
| 143 | const AttributeArray* get(const std::string& name) const; | ||
| 144 | AttributeArray* get(const std::string& name); | ||
| 145 | //@} | ||
| 146 | |||
| 147 | //@{ | ||
| 148 | /// @brief Return a pointer to the attribute array stored at position @a pos | ||
| 149 | /// in this set. | ||
| 150 | const AttributeArray* getConst(size_t pos) const; | ||
| 151 | const AttributeArray* get(size_t pos) const; | ||
| 152 | AttributeArray* get(size_t pos); | ||
| 153 | //@} | ||
| 154 | |||
| 155 | //@{ | ||
| 156 | /// @brief Return the group offset from the name or index of the group | ||
| 157 | /// A group attribute array is a single byte (8-bit), each bit of which | ||
| 158 | /// can denote a group. The group offset is the position of the bit that | ||
| 159 | /// denotes the requested group if all group attribute arrays in the set | ||
| 160 | /// (and only attribute arrays marked as group) were to be laid out linearly | ||
| 161 | /// according to their order in the set. | ||
| 162 | size_t groupOffset(const Name& groupName) const; | ||
| 163 | size_t groupOffset(const Util::GroupIndex& index) const; | ||
| 164 | //@} | ||
| 165 | |||
| 166 | /// Return the group index from the name of the group | ||
| 167 | Util::GroupIndex groupIndex(const Name& groupName) const; | ||
| 168 | /// Return the group index from the offset of the group | ||
| 169 | /// @note see offset description for groupOffset() | ||
| 170 | Util::GroupIndex groupIndex(const size_t offset) const; | ||
| 171 | |||
| 172 | /// Return the indices of the attribute arrays which are group attribute arrays | ||
| 173 | std::vector<size_t> groupAttributeIndices() const; | ||
| 174 | |||
| 175 | /// Return true if the attribute array stored at position @a pos is shared. | ||
| 176 | bool isShared(size_t pos) const; | ||
| 177 | /// @brief If the attribute array stored at position @a pos is shared, | ||
| 178 | /// replace the array with a deep copy of itself that is not | ||
| 179 | /// shared with anyone else. | ||
| 180 | void makeUnique(size_t pos); | ||
| 181 | |||
| 182 | /// Append attribute @a attribute (simple method) | ||
| 183 | AttributeArray::Ptr appendAttribute(const Name& name, | ||
| 184 | const NamePair& type, | ||
| 185 | const Index strideOrTotalSize = 1, | ||
| 186 | const bool constantStride = true, | ||
| 187 | const Metadata* defaultValue = nullptr); | ||
| 188 | |||
| 189 | /// Append attribute @a attribute (descriptor-sharing) | ||
| 190 | /// Requires current descriptor to match @a expected | ||
| 191 | /// On append, current descriptor is replaced with @a replacement | ||
| 192 | /// Provide a @a lock object to avoid contention from appending in parallel | ||
| 193 | AttributeArray::Ptr appendAttribute(const Descriptor& expected, DescriptorPtr& replacement, | ||
| 194 | const size_t pos, const Index strideOrTotalSize = 1, | ||
| 195 | const bool constantStride = true, | ||
| 196 | const Metadata* defaultValue = nullptr, | ||
| 197 | const AttributeArray::ScopedRegistryLock* lock = nullptr); | ||
| 198 | |||
| 199 | /// @brief Remove and return an attribute array by name | ||
| 200 | /// @param name the name of the attribute array to release | ||
| 201 | /// @details Detaches the attribute array from this attribute set and returns it, if | ||
| 202 | /// @a name is invalid, returns an empty shared pointer. This also updates the descriptor | ||
| 203 | /// to remove the reference to the attribute array. | ||
| 204 | /// @note AttributeArrays are stored as shared pointers, so they are not guaranteed | ||
| 205 | /// to be unique. Check the reference count before blindly re-using in a new AttributeSet. | ||
| 206 | AttributeArray::Ptr removeAttribute(const Name& name); | ||
| 207 | |||
| 208 | /// @brief Remove and return an attribute array by index | ||
| 209 | /// @param pos the position index of the attribute to release | ||
| 210 | /// @details Detaches the attribute array from this attribute set and returns it, if | ||
| 211 | /// @a pos is invalid, returns an empty shared pointer. This also updates the descriptor | ||
| 212 | /// to remove the reference to the attribute array. | ||
| 213 | /// @note AttributeArrays are stored as shared pointers, so they are not guaranteed | ||
| 214 | /// to be unique. Check the reference count before blindly re-using in a new AttributeSet. | ||
| 215 | AttributeArray::Ptr removeAttribute(const size_t pos); | ||
| 216 | |||
| 217 | /// @brief Remove and return an attribute array by index (unsafe method) | ||
| 218 | /// @param pos the position index of the attribute to release | ||
| 219 | /// @details Detaches the attribute array from this attribute set and returns it, if | ||
| 220 | /// @a pos is invalid, returns an empty shared pointer. | ||
| 221 | /// In cases where the AttributeSet is due to be destroyed, a small performance | ||
| 222 | /// advantage can be gained by leaving the attribute array as a nullptr and not | ||
| 223 | /// updating the descriptor. However, this leaves the AttributeSet in an invalid | ||
| 224 | /// state making it unsafe to call any methods that implicitly derefence the attribute array. | ||
| 225 | /// @note AttributeArrays are stored as shared pointers, so they are not guaranteed | ||
| 226 | /// to be unique. Check the reference count before blindly re-using in a new AttributeSet. | ||
| 227 | /// @warning Only use this method if you're an expert and know the risks of not | ||
| 228 | /// updating the array of attributes or the descriptor. | ||
| 229 | AttributeArray::Ptr removeAttributeUnsafe(const size_t pos); | ||
| 230 | |||
| 231 | /// Drop attributes with @a pos indices (simple method) | ||
| 232 | /// Creates a new descriptor for this attribute set | ||
| 233 | void dropAttributes(const std::vector<size_t>& pos); | ||
| 234 | |||
| 235 | /// Drop attributes with @a pos indices (descriptor-sharing method) | ||
| 236 | /// Requires current descriptor to match @a expected | ||
| 237 | /// On drop, current descriptor is replaced with @a replacement | ||
| 238 | void dropAttributes(const std::vector<size_t>& pos, | ||
| 239 | const Descriptor& expected, DescriptorPtr& replacement); | ||
| 240 | |||
| 241 | /// Re-name attributes in set to match a provided descriptor | ||
| 242 | /// Replaces own descriptor with @a replacement | ||
| 243 | void renameAttributes(const Descriptor& expected, const DescriptorPtr& replacement); | ||
| 244 | |||
| 245 | /// Re order attribute set to match a provided descriptor | ||
| 246 | /// Replaces own descriptor with @a replacement | ||
| 247 | void reorderAttributes(const DescriptorPtr& replacement); | ||
| 248 | |||
| 249 | /// Replace the current descriptor with a @a replacement | ||
| 250 | /// Note the provided Descriptor must be identical to the replacement | ||
| 251 | /// unless @a allowMismatchingDescriptors is true (default is false) | ||
| 252 | void resetDescriptor(const DescriptorPtr& replacement, const bool allowMismatchingDescriptors = false); | ||
| 253 | |||
| 254 | /// Read the entire set from a stream. | ||
| 255 | void read(std::istream&); | ||
| 256 | /// Write the entire set to a stream. | ||
| 257 | /// @param outputTransient if true, write out transient attributes | ||
| 258 | void write(std::ostream&, bool outputTransient = false) const; | ||
| 259 | |||
| 260 | /// This will read the attribute descriptor from a stream. | ||
| 261 | void readDescriptor(std::istream&); | ||
| 262 | /// This will write the attribute descriptor to a stream. | ||
| 263 | /// @param outputTransient if true, write out transient attributes | ||
| 264 | void writeDescriptor(std::ostream&, bool outputTransient = false) const; | ||
| 265 | |||
| 266 | /// This will read the attribute metadata from a stream. | ||
| 267 | void readMetadata(std::istream&); | ||
| 268 | /// This will write the attribute metadata to a stream. | ||
| 269 | /// @param outputTransient if true, write out transient attributes | ||
| 270 | /// @param paged if true, data is written out in pages | ||
| 271 | void writeMetadata(std::ostream&, bool outputTransient = false, bool paged = false) const; | ||
| 272 | |||
| 273 | /// This will read the attribute data from a stream. | ||
| 274 | void readAttributes(std::istream&); | ||
| 275 | /// This will write the attribute data to a stream. | ||
| 276 | /// @param outputTransient if true, write out transient attributes | ||
| 277 | void writeAttributes(std::ostream&, bool outputTransient = false) const; | ||
| 278 | |||
| 279 | /// Compare the descriptors and attribute arrays on the attribute sets | ||
| 280 | /// Exit early if the descriptors do not match | ||
| 281 | bool operator==(const AttributeSet& other) const; | ||
| 282 |
4/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
|
2 | bool operator!=(const AttributeSet& other) const { return !this->operator==(other); } |
| 283 | |||
| 284 | private: | ||
| 285 | using AttrArrayVec = std::vector<AttributeArray::Ptr>; | ||
| 286 | |||
| 287 | DescriptorPtr mDescr; | ||
| 288 | AttrArrayVec mAttrs; | ||
| 289 | }; // class AttributeSet | ||
| 290 | |||
| 291 | //////////////////////////////////////// | ||
| 292 | |||
| 293 | |||
| 294 | /// A container for ABI=5 to help ease introduction of upcoming features | ||
| 295 | namespace future { | ||
| 296 | class Container | ||
| 297 | { | ||
| 298 | class Element { }; | ||
| 299 | std::vector<std::shared_ptr<Element>> mElements; | ||
| 300 | }; | ||
| 301 | } | ||
| 302 | |||
| 303 | |||
| 304 | //////////////////////////////////////// | ||
| 305 | |||
| 306 | |||
| 307 | /// @brief An immutable object that stores name, type and AttributeSet position | ||
| 308 | /// for a constant collection of attribute arrays. | ||
| 309 | /// @note The attribute name is actually mutable, but the attribute type | ||
| 310 | /// and position can not be changed after creation. | ||
| 311 | class OPENVDB_API AttributeSet::Descriptor | ||
| 312 | { | ||
| 313 | public: | ||
| 314 | using Ptr = std::shared_ptr<Descriptor>; | ||
| 315 | |||
| 316 | using NameAndType = Util::NameAndType; | ||
| 317 | using NameAndTypeVec = Util::NameAndTypeVec; | ||
| 318 | using GroupIndex = Util::GroupIndex; | ||
| 319 | using NameToPosMap = Util::NameToPosMap; | ||
| 320 | using ConstIterator = NameToPosMap::const_iterator; | ||
| 321 | |||
| 322 | /// Utility method to construct a NameAndType sequence. | ||
| 323 | 7266 | struct Inserter { | |
| 324 | NameAndTypeVec vec; | ||
| 325 | Inserter& add(const NameAndType& nameAndType) { | ||
| 326 |
1/2✓ Branch 1 taken 7257 times.
✗ Branch 2 not taken.
|
7257 | vec.push_back(nameAndType); return *this; |
| 327 | } | ||
| 328 | Inserter& add(const Name& name, const NamePair& type) { | ||
| 329 |
21/42✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 1 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 1 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 1 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 1 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 1 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 1 times.
✗ Branch 53 not taken.
✓ Branch 55 taken 1 times.
✗ Branch 56 not taken.
✓ Branch 58 taken 1 times.
✗ Branch 59 not taken.
✓ Branch 61 taken 1 times.
✗ Branch 62 not taken.
|
22 | vec.emplace_back(name, type); return *this; |
| 330 | } | ||
| 331 | Inserter& add(const NameAndTypeVec& other) { | ||
| 332 | for (NameAndTypeVec::const_iterator it = other.begin(), itEnd = other.end(); it != itEnd; ++it) { | ||
| 333 | vec.emplace_back(it->name, it->type); | ||
| 334 | } | ||
| 335 | return *this; | ||
| 336 | } | ||
| 337 | }; | ||
| 338 | |||
| 339 | ////////// | ||
| 340 | |||
| 341 | Descriptor(); | ||
| 342 | |||
| 343 | /// Copy constructor | ||
| 344 | Descriptor(const Descriptor&); | ||
| 345 | |||
| 346 | /// Create a new descriptor from a position attribute type and assumes "P" (for convenience). | ||
| 347 | static Ptr create(const NamePair&); | ||
| 348 | |||
| 349 | /// Create a new descriptor as a duplicate with a new attribute appended | ||
| 350 | Ptr duplicateAppend(const Name& name, const NamePair& type) const; | ||
| 351 | |||
| 352 | /// Create a new descriptor as a duplicate with existing attributes dropped | ||
| 353 | Ptr duplicateDrop(const std::vector<size_t>& pos) const; | ||
| 354 | |||
| 355 | /// Return the number of attributes in this descriptor. | ||
| 356 | size_t size() const { return mTypes.size(); } | ||
| 357 | |||
| 358 | /// Return the number of attributes with this attribute type | ||
| 359 | size_t count(const NamePair& type) const; | ||
| 360 | |||
| 361 | /// Return the number of bytes of memory used by this attribute set. | ||
| 362 | size_t memUsage() const; | ||
| 363 | |||
| 364 | /// @brief Return the position of the attribute array whose name is @a name, | ||
| 365 | /// or @c INVALID_POS if no match is found. | ||
| 366 | size_t find(const std::string& name) const; | ||
| 367 | |||
| 368 | /// Rename an attribute array | ||
| 369 | size_t rename(const std::string& fromName, const std::string& toName); | ||
| 370 | |||
| 371 | /// Return the name of the attribute array's type. | ||
| 372 | const Name& valueType(size_t pos) const; | ||
| 373 | /// Return the name of the attribute array's type. | ||
| 374 | const NamePair& type(size_t pos) const; | ||
| 375 | |||
| 376 | /// Retrieve metadata map | ||
| 377 | MetaMap& getMetadata(); | ||
| 378 | const MetaMap& getMetadata() const; | ||
| 379 | |||
| 380 | /// Return true if the attribute has a default value | ||
| 381 | bool hasDefaultValue(const Name& name) const; | ||
| 382 | /// Get a default value for an existing attribute | ||
| 383 | template<typename ValueType> | ||
| 384 | 6 | ValueType getDefaultValue(const Name& name) const | |
| 385 | { | ||
| 386 | 6 | const size_t pos = find(name); | |
| 387 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
6 | if (pos == INVALID_POS) { |
| 388 | ✗ | OPENVDB_THROW(LookupError, "Cannot find attribute name to set default value.") | |
| 389 | } | ||
| 390 | |||
| 391 | 12 | std::stringstream ss; | |
| 392 | ss << "default:" << name; | ||
| 393 | |||
| 394 |
4/6✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
|
12 | auto metadata = mMetadata.getMetadata<TypedMetadata<ValueType>>(ss.str()); |
| 395 | |||
| 396 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
6 | if (metadata) return metadata->value(); |
| 397 | |||
| 398 | return zeroVal<ValueType>(); | ||
| 399 | } | ||
| 400 | /// Set a default value for an existing attribute | ||
| 401 | void setDefaultValue(const Name& name, const Metadata& defaultValue); | ||
| 402 | // Remove the default value if it exists | ||
| 403 | void removeDefaultValue(const Name& name); | ||
| 404 | // Prune any default values for which the key is no longer present | ||
| 405 | void pruneUnusedDefaultValues(); | ||
| 406 | |||
| 407 | /// Return true if this descriptor is equal to the given one. | ||
| 408 | bool operator==(const Descriptor&) const; | ||
| 409 | /// Return true if this descriptor is not equal to the given one. | ||
| 410 |
2/4✓ Branch 1 taken 3950 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
48368 | bool operator!=(const Descriptor& rhs) const { return !this->operator==(rhs); } |
| 411 | /// Return true if this descriptor contains the same attributes | ||
| 412 | /// as the given descriptor, ignoring attribute order | ||
| 413 | bool hasSameAttributes(const Descriptor& rhs) const; | ||
| 414 | |||
| 415 | /// Return a reference to the name-to-position map. | ||
| 416 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const NameToPosMap& map() const { return mNameMap; } |
| 417 | /// Return a reference to the name-to-position group map. | ||
| 418 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const NameToPosMap& groupMap() const { return mGroupMap; } |
| 419 | |||
| 420 | /// Return @c true if group exists | ||
| 421 | bool hasGroup(const Name& group) const; | ||
| 422 | /// @brief Define a group name to offset mapping | ||
| 423 | /// @param group group name | ||
| 424 | /// @param offset group offset | ||
| 425 | /// @param checkValidOffset throws if offset out-of-range or in-use | ||
| 426 | void setGroup(const Name& group, const size_t offset, | ||
| 427 | const bool checkValidOffset = false); | ||
| 428 | /// Drop any mapping keyed by group name | ||
| 429 | void dropGroup(const Name& group); | ||
| 430 | /// Clear all groups | ||
| 431 | void clearGroups(); | ||
| 432 | /// Rename a group | ||
| 433 | size_t renameGroup(const std::string& fromName, const std::string& toName); | ||
| 434 | /// Return a unique name for a group based on given name | ||
| 435 | const Name uniqueGroupName(const Name& name) const; | ||
| 436 | |||
| 437 | //@{ | ||
| 438 | /// @brief Return the group offset from the name or index of the group | ||
| 439 | /// A group attribute array is a single byte (8-bit), each bit of which | ||
| 440 | /// can denote a group. The group offset is the position of the bit that | ||
| 441 | /// denotes the requested group if all group attribute arrays in the set | ||
| 442 | /// (and only attribute arrays marked as group) were to be laid out linearly | ||
| 443 | /// according to their order in the set. | ||
| 444 | size_t groupOffset(const Name& groupName) const; | ||
| 445 | size_t groupOffset(const GroupIndex& index) const; | ||
| 446 | //@} | ||
| 447 | |||
| 448 | /// Return the group index from the name of the group | ||
| 449 | GroupIndex groupIndex(const Name& groupName) const; | ||
| 450 | /// Return the group index from the offset of the group | ||
| 451 | /// @note see offset description for groupOffset() | ||
| 452 | GroupIndex groupIndex(const size_t offset) const; | ||
| 453 | |||
| 454 | /// Return number of bits occupied by a group attribute array | ||
| 455 | static size_t groupBits() { return sizeof(GroupType) * CHAR_BIT; } | ||
| 456 | |||
| 457 | /// Return the total number of available groups | ||
| 458 | /// (group bits * number of group attributes) | ||
| 459 | size_t availableGroups() const; | ||
| 460 | |||
| 461 | /// Return the number of empty group slots which correlates to the number of groups | ||
| 462 | /// that can be stored without increasing the number of group attribute arrays | ||
| 463 | size_t unusedGroups() const; | ||
| 464 | |||
| 465 | /// Return @c true if there are sufficient empty slots to allow compacting | ||
| 466 | bool canCompactGroups() const; | ||
| 467 | |||
| 468 | /// @brief Return a group offset that is not in use | ||
| 469 | /// @param hint if provided, request a specific offset as a hint | ||
| 470 | /// @return index of an offset or size_t max if no available group offsets | ||
| 471 | size_t unusedGroupOffset(size_t hint = std::numeric_limits<size_t>::max()) const; | ||
| 472 | |||
| 473 | /// @brief Determine if a move is required to efficiently compact the data and store the | ||
| 474 | /// source name, offset and the target offset in the input parameters | ||
| 475 | /// @param sourceName source name | ||
| 476 | /// @param sourceOffset source offset | ||
| 477 | /// @param targetOffset target offset | ||
| 478 | /// @return @c true if move is required to compact the data | ||
| 479 | bool requiresGroupMove(Name& sourceName, size_t& sourceOffset, size_t& targetOffset) const; | ||
| 480 | |||
| 481 | /// @brief Test if there are any group names shared by both descriptors which | ||
| 482 | /// have a different index | ||
| 483 | /// @param rhs the descriptor to compare with | ||
| 484 | /// @return @c true if an index collision exists | ||
| 485 | bool groupIndexCollision(const Descriptor& rhs) const; | ||
| 486 | |||
| 487 | /// Return a unique name for an attribute array based on given name | ||
| 488 | const Name uniqueName(const Name& name) const; | ||
| 489 | |||
| 490 | /// Return true if the name is valid | ||
| 491 | static bool validName(const Name& name); | ||
| 492 | |||
| 493 | /// @brief Extract each name from @a nameStr into @a includeNames, or into @a excludeNames | ||
| 494 | /// if the name is prefixed with a caret. | ||
| 495 | /// @param nameStr the input string of names | ||
| 496 | /// @param includeNames on exit, the list of names that are not prefixed with a caret | ||
| 497 | /// @param excludeNames on exit, the list of names that are prefixed with a caret | ||
| 498 | /// @param includeAll on exit, @c true if a "*" wildcard is present in the @a includeNames | ||
| 499 | static void parseNames( std::vector<std::string>& includeNames, | ||
| 500 | std::vector<std::string>& excludeNames, | ||
| 501 | bool& includeAll, | ||
| 502 | const std::string& nameStr); | ||
| 503 | |||
| 504 | /// @brief Extract each name from @a nameStr into @a includeNames, or into @a excludeNames | ||
| 505 | /// if the name is prefixed with a caret. | ||
| 506 | static void parseNames( std::vector<std::string>& includeNames, | ||
| 507 | std::vector<std::string>& excludeNames, | ||
| 508 | const std::string& nameStr); | ||
| 509 | |||
| 510 | /// Serialize this descriptor to the given stream. | ||
| 511 | void write(std::ostream&) const; | ||
| 512 | /// Unserialize this transform from the given stream. | ||
| 513 | void read(std::istream&); | ||
| 514 | |||
| 515 | protected: | ||
| 516 | /// Append to a vector of names and types from this Descriptor in position order | ||
| 517 | void appendTo(NameAndTypeVec& attrs) const; | ||
| 518 | |||
| 519 | /// Create a new descriptor from the given attribute and type name pairs | ||
| 520 | /// and copy the group maps and metamap. | ||
| 521 | static Ptr create(const NameAndTypeVec&, const NameToPosMap&, const MetaMap&); | ||
| 522 | |||
| 523 | size_t insert(const std::string& name, const NamePair& typeName); | ||
| 524 | |||
| 525 | private: | ||
| 526 | friend class ::TestAttributeSet; | ||
| 527 | |||
| 528 | NameToPosMap mNameMap; | ||
| 529 | std::vector<NamePair> mTypes; | ||
| 530 | NameToPosMap mGroupMap; | ||
| 531 | MetaMap mMetadata; | ||
| 532 | // as this change is part of an ABI change, there's no good reason to reduce the reserved | ||
| 533 | // space aside from keeping the memory size of an AttributeSet the same for convenience | ||
| 534 | // (note that this assumes a typical three-pointer implementation for std::vector) | ||
| 535 | future::Container mFutureContainer; // occupies 3 reserved slots | ||
| 536 | int64_t mReserved[5]; // for future use | ||
| 537 | }; // class Descriptor | ||
| 538 | |||
| 539 | } // namespace points | ||
| 540 | } // namespace OPENVDB_VERSION_NAME | ||
| 541 | } // namespace openvdb | ||
| 542 | |||
| 543 | #endif // OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED | ||
| 544 |