Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | |||
4 | /// @file compiler/CustomData.h | ||
5 | /// | ||
6 | /// @authors Nick Avramoussis, Francisco Gochez | ||
7 | /// | ||
8 | /// @brief Access to the CustomData class which can provide custom user | ||
9 | /// user data to the OpenVDB AX Compiler. | ||
10 | /// | ||
11 | |||
12 | #ifndef OPENVDB_AX_COMPILER_CUSTOM_DATA_HAS_BEEN_INCLUDED | ||
13 | #define OPENVDB_AX_COMPILER_CUSTOM_DATA_HAS_BEEN_INCLUDED | ||
14 | |||
15 | #include <openvdb/version.h> | ||
16 | #include <openvdb/Metadata.h> | ||
17 | #include <openvdb/Types.h> | ||
18 | |||
19 | #include <unordered_map> | ||
20 | #include <memory> | ||
21 | |||
22 | namespace openvdb { | ||
23 | OPENVDB_USE_VERSION_NAMESPACE | ||
24 | namespace OPENVDB_VERSION_NAME { | ||
25 | |||
26 | namespace ax { | ||
27 | |||
28 | /// @brief The custom data class is a simple container for named openvdb | ||
29 | /// metadata. Its primary use case is passing arbitrary "external" data to an | ||
30 | /// AX executable object when calling Compiler::compile. For example, it is | ||
31 | /// the mechanism by which we pass data held inside of a parent DCC to | ||
32 | /// executable AX code. | ||
33 | 225 | class CustomData | |
34 | { | ||
35 | public: | ||
36 | |||
37 | using Ptr = std::shared_ptr<CustomData>; | ||
38 | using ConstPtr = std::shared_ptr<const CustomData>; | ||
39 | using UniquePtr = std::unique_ptr<CustomData>; | ||
40 | |||
41 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
225 | CustomData() : mData() {} |
42 | |||
43 | 206 | static UniquePtr create() | |
44 | { | ||
45 | 206 | UniquePtr data(new CustomData); | |
46 | 206 | return data; | |
47 | } | ||
48 | |||
49 | /// @brief Reset the custom data. This will clear and delete all previously | ||
50 | /// added data. This will invalidated any executable which links to this | ||
51 | /// custom data. | ||
52 | inline void reset() | ||
53 | { | ||
54 | mData.clear(); | ||
55 | } | ||
56 | |||
57 | /// @brief Checks whether or not data of given name has been inserted | ||
58 | inline bool | ||
59 | hasData(const Name& name) | ||
60 | { | ||
61 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | const auto iter = mData.find(name); |
62 | return (iter != mData.end()); | ||
63 | } | ||
64 | |||
65 | /// @brief Checks whether or not data of given name and type has been inserted | ||
66 | template <typename TypedDataCacheT> | ||
67 | inline bool | ||
68 | hasData(const Name& name) | ||
69 | { | ||
70 | const auto iter = mData.find(name); | ||
71 | if (iter == mData.end()) return false; | ||
72 | const TypedDataCacheT* const typed = | ||
73 | dynamic_cast<const TypedDataCacheT* const>(iter->second.get()); | ||
74 | return typed != nullptr; | ||
75 | } | ||
76 | |||
77 | /// @brief Retrieves a const pointer to data of given name. If it does not | ||
78 | /// exist, returns nullptr | ||
79 | inline const Metadata::ConstPtr | ||
80 | 104 | getData(const Name& name) const | |
81 | { | ||
82 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 104 times.
|
104 | const auto iter = mData.find(name); |
83 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 104 times.
|
104 | if (iter == mData.end()) return Metadata::ConstPtr(); |
84 | return iter->second; | ||
85 | } | ||
86 | |||
87 | /// @brief Retrieves a const pointer to data of given name and type. | ||
88 | /// If it does not exist, returns nullptr | ||
89 | /// @param name Name of the data entry | ||
90 | /// @returns The metadata. If the type does not match, nullptr is returned. | ||
91 | template <typename TypedDataCacheT> | ||
92 | inline const TypedDataCacheT* | ||
93 | 104 | getData(const Name& name) const | |
94 | { | ||
95 | 104 | Metadata::ConstPtr data = getData(name); | |
96 | 104 | if (!data) return nullptr; | |
97 | 104 | const TypedDataCacheT* const typed = | |
98 | 104 | dynamic_cast<const TypedDataCacheT* const>(data.get()); | |
99 | return typed; | ||
100 | } | ||
101 | |||
102 | /// @brief Retrieves or inserts typed metadata. If the data exists, it is | ||
103 | /// dynamic-casted to the expected type, which may result in a nullptr. If | ||
104 | /// the data does not exist it is guaranteed to be inserted and returned. | ||
105 | /// The value of the inserted data can then be modified | ||
106 | template <typename TypedDataCacheT> | ||
107 | inline TypedDataCacheT* | ||
108 | 78 | getOrInsertData(const Name& name) | |
109 | { | ||
110 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
78 | const auto iter = mData.find(name); |
111 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
78 | if (iter == mData.end()) { |
112 | 1 | Metadata::Ptr data(new TypedDataCacheT()); | |
113 | mData[name] = data; | ||
114 | return static_cast<TypedDataCacheT* const>(data.get()); | ||
115 | } | ||
116 | else { | ||
117 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
77 | return dynamic_cast<TypedDataCacheT* const>(iter->second.get()); |
118 | } | ||
119 | } | ||
120 | |||
121 | /// @brief Inserts data of specified type with given name. | ||
122 | /// @param name Name of the data | ||
123 | /// @param data Shared pointer to the data | ||
124 | /// @note If an entry of the given name already exists, will copy the data | ||
125 | /// into the existing entry rather than overwriting the pointer | ||
126 | template <typename TypedDataCacheT> | ||
127 | inline void | ||
128 | 1 | insertData(const Name& name, | |
129 | const typename TypedDataCacheT::Ptr data) | ||
130 | { | ||
131 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (hasData(name)) { |
132 | ✗ | TypedDataCacheT* const dataToSet = | |
133 | getOrInsertData<TypedDataCacheT>(name); | ||
134 | ✗ | if (!dataToSet) { | |
135 | ✗ | OPENVDB_THROW(TypeError, "Custom data \"" + name + | |
136 | "\" already exists with a different type."); | ||
137 | } | ||
138 | ✗ | dataToSet->value() = data->value(); | |
139 | } | ||
140 | else { | ||
141 | 2 | mData[name] = data->copy(); | |
142 | } | ||
143 | 1 | } | |
144 | |||
145 | /// @brief Inserts data with given name. | ||
146 | /// @param name Name of the data | ||
147 | /// @param data The metadata | ||
148 | /// @note If an entry of the given name already exists, will copy the data | ||
149 | /// into the existing entry rather than overwriting the pointer | ||
150 | inline void | ||
151 | 22 | insertData(const Name& name, | |
152 | const Metadata::Ptr data) | ||
153 | { | ||
154 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | const auto iter = mData.find(name); |
155 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | if (iter == mData.end()) { |
156 | mData[name] = data; | ||
157 | } | ||
158 | else { | ||
159 | ✗ | iter->second->copy(*data); | |
160 | } | ||
161 | 22 | } | |
162 | |||
163 | private: | ||
164 | std::unordered_map<Name, Metadata::Ptr> mData; | ||
165 | }; | ||
166 | |||
167 | // fwd declare the codegen::String and alias deprecated metadata type | ||
168 | namespace codegen { struct String; } | ||
169 | using AXStringMetadata [[deprecated("The ax::AXStringMetadata type has " | ||
170 | "been replaced with openvdb::TypedMetadata<ax::codegen::String>. The " | ||
171 | "new backend string definition can be found in ax/codegen/String.h")]] = | ||
172 | TypedMetadata<ax::codegen::String>; | ||
173 | |||
174 | } // namespace ax | ||
175 | } // namespace OPENVDB_VERSION_NAME | ||
176 | } // namespace openvdb | ||
177 | |||
178 | #endif // OPENVDB_AX_COMPILER_CUSTOM_DATA_HAS_BEEN_INCLUDED | ||
179 | |||
180 |