2
// Copyright 2016 Pixar
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:
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.
14
// You may obtain a copy of the Apache License at
16
// http://www.apache.org/licenses/LICENSE-2.0
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.
24
#ifndef USD_PRIMFLAGS_H
25
#define USD_PRIMFLAGS_H
29
/// \anchor Usd_PrimFlags
31
/// Provides terms for UsdPrim flags that can be combined to form either a
32
/// conjunction (via &&) or a disjunction (via ||). The result is a
33
/// predicate functor object that tests those flags on the passed prim.
34
/// Currently UsdPrim::GetFilteredChildren(), UsdPrim::GetNextFilteredSibling(),
35
/// UsdPrim::GetFilteredDescendants(), and UsdTreeIterator() accept these
36
/// predicates to filter out unwanted prims.
40
/// // Get only loaded model children.
41
/// prim.GetFilteredChildren(UsdPrimIsModel and UsdPrimIsLoaded)
44
/// For performance, these predicates are implemented by a bitwise test, so
45
/// arbitrary boolean expressions cannot be represented. The set of boolean
46
/// expressions that can be represented are conjunctions with possibly negated
47
/// terms (or disjunctions, by De Morgan's law). Here are some examples of
48
/// valid expressions:
50
/// // simple conjunction.
51
/// (UsdPrimIsLoaded && UsdPrimIsGroup)
52
/// // conjunction with negated term.
53
/// (UsdPrimIsDefined && !UsdPrimIsAbstract)
54
/// // disjunction with negated term.
55
/// (!UsdPrimIsDefined || !UsdPrimIsActive)
56
/// // negated conjunction gives a disjunction.
57
/// !(UsdPrimIsLoaded && UsdPrimIsModel)
58
/// // negated conjunction gives a disjunction, which is further extended.
59
/// (!(UsdPrimIsLoaded && UsdPrimIsModel) || UsdPrimIsAbstract)
60
/// // equivalent to above.
61
/// (!UsdPrimIsLoaded || !UsdPrimIsModel || UsdPrimIsAbstract)
63
/// Here are some examples of invalid expressions:
65
/// // error: cannot || a term with a conjunction.
66
/// (UsdPrimIsLoaded && UsdPrimIsModel) || UsdPrimIsAbstract
67
/// // error: cannot && disjunctions.
68
/// (!UsdPrimIsDefined || UsdPrimIsAbstract) && (UsdPrimIsModel || !UsdPrimIsActive)
72
/// The following variables provide the clauses that can be combined and
73
/// negated to produce predicates:
75
#include "pxr/base/arch/hints.h"
76
#include "pxr/base/tf/bitUtils.h"
78
#include <boost/functional/hash.hpp>
82
// Enum for cached flags on prims.
90
Usd_PrimHasDefiningSpecifierFlag,
98
typedef std::bitset<Usd_PrimNumFlags> Usd_PrimFlagBits;
100
// Term class. This class exists merely to allow building up conjunctions or
101
// disjunctions of terms. See Usd_PrimFlagsPredicate, Usd_PrimFlagsConjunction,
102
// Usd_PrimFlagsDisjunction which provide the logcial operators.
104
Usd_Term(Usd_PrimFlags flag) : flag(flag), negated(false) {}
105
Usd_Term(Usd_PrimFlags flag, bool negated) : flag(flag), negated(negated) {}
106
Usd_Term operator!() const { return Usd_Term(flag, !negated); }
107
bool operator==(Usd_Term other) const {
108
return flag == other.flag and negated == other.negated;
110
bool operator!=(Usd_Term other) const {
111
return !(*this == other);
118
operator!(Usd_PrimFlags flag) {
119
return Usd_Term(flag, /*negated=*/true);
124
/// Tests UsdPrim::IsActive()
125
extern unspecified UsdPrimIsActive;
126
/// Tests UsdPrim::IsLoaded()
127
extern unspecified UsdPrimIsLoaded;
128
/// Tests UsdPrim::IsModel()
129
extern unspecified UsdPrimIsModel;
130
/// Tests UsdPrim::IsGroup()
131
extern unspecified UsdPrimIsGroup;
132
/// Tests UsdPrim::IsAbstract()
133
extern unspecified UsdPrimIsAbstract;
134
/// Tests UsdPrim::IsDefined()
135
extern unspecified UsdPrimIsDefined;
136
/// Tests UsdPrim::IsInstance()
137
extern unspecified UsdPrimIsInstance;
138
/// Tests UsdPrim::HasDefiningSpecifier()
139
extern unspecified UsdPrimHasDefiningSpecifier;
142
static const Usd_PrimFlags UsdPrimIsActive = Usd_PrimActiveFlag;
143
static const Usd_PrimFlags UsdPrimIsLoaded = Usd_PrimLoadedFlag;
144
static const Usd_PrimFlags UsdPrimIsModel = Usd_PrimModelFlag;
145
static const Usd_PrimFlags UsdPrimIsGroup = Usd_PrimGroupFlag;
146
static const Usd_PrimFlags UsdPrimIsAbstract = Usd_PrimAbstractFlag;
147
static const Usd_PrimFlags UsdPrimIsDefined = Usd_PrimDefinedFlag;
148
static const Usd_PrimFlags UsdPrimIsInstance = Usd_PrimInstanceFlag;
149
static const Usd_PrimFlags UsdPrimHasDefiningSpecifier
150
= Usd_PrimHasDefiningSpecifierFlag;
154
// Predicate functor class that tests a prim's flags against desired values.
155
class Usd_PrimFlagsPredicate
158
// Functor result type.
159
typedef bool result_type;
161
// Default ctor produces a tautology.
162
Usd_PrimFlagsPredicate() : _negate(false) {}
164
Usd_PrimFlagsPredicate(Usd_PrimFlags flag)
167
_values[flag] = true;
170
// Implicit conversion from a single term.
171
Usd_PrimFlagsPredicate(Usd_Term term)
173
_mask[term.flag] = 1;
174
_values[term.flag] = not term.negated;
177
// Convenience to produce a tautological predicate. Returns a
178
// default-constructed predicate.
179
static Usd_PrimFlagsPredicate Tautology() {
180
return Usd_PrimFlagsPredicate();
183
// Convenience to produce a contradictory predicate. Returns a negated
184
// default-constructed predicate.
185
static Usd_PrimFlagsPredicate Contradiction() {
186
return Usd_PrimFlagsPredicate()._Negate();
189
// Invoke boolean predicate on \p prim.
190
template <class PrimPtr>
191
bool operator()(const PrimPtr &prim) const {
192
// Mask the prim's flags, compare to desired values, then optionally
193
// negate the result.
194
return ((prim->_GetFlags() & _mask) == _values) ^ _negate;
197
// Invoke boolean predicate on UsdPrim \p prim.
198
bool operator()(const class UsdPrim &prim) const;
202
// Return true if this predicate is a tautology, false otherwise.
203
bool _IsTautology() const { return *this == Tautology(); }
205
// Set this predicate to be a tautology.
206
void _MakeTautology() { *this = Tautology(); }
208
// Return true if this predicate is a contradiction, false otherwise.
209
bool _IsContradiction() const { return *this == Contradiction(); }
211
// Set this predicate to be a contradiction.
212
void _MakeContradiction() { *this = Contradiction(); }
214
// Negate this predicate.
215
Usd_PrimFlagsPredicate &_Negate() {
216
_negate = not _negate;
220
// Return a negated copy of this predicate.
221
Usd_PrimFlagsPredicate _GetNegated() const {
222
return Usd_PrimFlagsPredicate(*this)._Negate();
225
// Mask indicating which flags are of interest.
226
Usd_PrimFlagBits _mask;
228
// Desired values for prim flags.
229
Usd_PrimFlagBits _values;
232
// Equality comparison.
234
operator==(const Usd_PrimFlagsPredicate &lhs,
235
const Usd_PrimFlagsPredicate &rhs) {
236
return lhs._mask == rhs._mask and
237
lhs._values == rhs._values and
238
lhs._negate == rhs._negate;
240
// Inequality comparison.
242
operator!=(const Usd_PrimFlagsPredicate &lhs,
243
const Usd_PrimFlagsPredicate &rhs) {
244
return not (lhs == rhs);
248
friend size_t hash_value(const Usd_PrimFlagsPredicate &p) {
249
size_t hash = p._mask.to_ulong();
250
boost::hash_combine(hash, p._values.to_ulong());
251
boost::hash_combine(hash, p._negate);
255
// Whether or not to negate the predicate's result.
261
/// Conjunction of prim flag predicate terms.
263
/// Usually clients will implicitly create conjunctions by &&-ing together flag
264
/// predicate terms. For example:
266
/// // Get all loaded model children.
267
/// prim.GetFilteredChildren(UsdPrimIsModel and UsdPrimIsLoaded)
270
/// See primFlags.h for more details.
271
class Usd_PrimFlagsConjunction : public Usd_PrimFlagsPredicate {
273
/// Default constructed conjunction is a tautology.
274
Usd_PrimFlagsConjunction() {};
276
/// Construct with a term.
277
explicit Usd_PrimFlagsConjunction(Usd_Term term) {
281
/// Add an additional term to this conjunction.
282
Usd_PrimFlagsConjunction &operator&=(Usd_Term term) {
283
// If this conjunction is a contradiction, do nothing.
284
if (ARCH_UNLIKELY(_IsContradiction()))
287
// If we don't have the bit, set it in _mask and _values (if needed).
288
if (not _mask[term.flag]) {
289
_mask[term.flag] = 1;
290
_values[term.flag] = not term.negated;
291
} else if (_values[term.flag] != not term.negated) {
292
// If we do have the bit and the values disagree, then this entire
293
// conjunction becomes a contradiction. If the values agree, it's
294
// redundant and we do nothing.
295
_MakeContradiction();
300
/// Negate this conjunction, producing a disjunction by De Morgan's law.
304
/// not (UsdPrimIsLoaded and UsdPrimIsModel)
307
/// Will negate the conjunction in parens to produce a disjunction
311
/// (not UsdPrimIsLoaded or not UsdPrimIsModel)
314
/// Every expression may be formulated as either a disjunction or a
315
/// conjuction, but allowing both affords increased expressiveness.
317
class Usd_PrimFlagsDisjunction operator!() const;
321
// Let Usd_PrimFlagsDisjunction produce conjunctions when negated
322
friend class Usd_PrimFlagsDisjunction;
323
Usd_PrimFlagsConjunction(const Usd_PrimFlagsPredicate &base) :
324
Usd_PrimFlagsPredicate(base) {}
326
/// Combine two terms to make a conjunction.
327
friend Usd_PrimFlagsConjunction
328
operator&&(Usd_Term lhs, Usd_Term rhs);
330
/// Create a new conjunction with the term \p rhs added.
331
friend Usd_PrimFlagsConjunction
332
operator&&(const Usd_PrimFlagsConjunction &conjunction, Usd_Term rhs);
334
/// Create a new conjunction with the term \p lhs added.
335
friend Usd_PrimFlagsConjunction
336
operator&&(Usd_Term lhs, const Usd_PrimFlagsConjunction &conjunction);
339
inline Usd_PrimFlagsConjunction
340
operator&&(Usd_Term lhs, Usd_Term rhs) {
341
// Apparently gcc 4.8.x doesn't like this as:
342
// return (Usd_PrimFlagsConjunction() && lhs) && rhs;
343
Usd_PrimFlagsConjunction tmp;
344
return (tmp && lhs) && rhs;
347
inline Usd_PrimFlagsConjunction
348
operator&&(const Usd_PrimFlagsConjunction &conjunction, Usd_Term rhs) {
349
return Usd_PrimFlagsConjunction(conjunction) &= rhs;
352
inline Usd_PrimFlagsConjunction
353
operator&&(Usd_Term lhs, const Usd_PrimFlagsConjunction &conjunction) {
354
return Usd_PrimFlagsConjunction(conjunction) &= lhs;
357
inline Usd_PrimFlagsConjunction
358
operator&&(Usd_PrimFlags lhs, Usd_PrimFlags rhs) {
359
return Usd_Term(lhs) && Usd_Term(rhs);
363
/// Disjunction of prim flag predicate terms.
365
/// Usually clients will implicitly create disjunctions by ||-ing together flag
366
/// predicate terms. For example:
368
/// // Get all deactivated or undefined children.
369
/// prim.GetFilteredChildren(not UsdPrimIsActive or not UsdPrimIsDefined)
372
/// See primFlags.h for more details.
373
class Usd_PrimFlagsDisjunction : public Usd_PrimFlagsPredicate {
375
// Default constructed disjunction is a contradiction.
376
Usd_PrimFlagsDisjunction() { _Negate(); };
378
// Construct with a term.
379
explicit Usd_PrimFlagsDisjunction(Usd_Term term) {
384
/// Add an additional term to this disjunction.
385
Usd_PrimFlagsDisjunction &operator|=(Usd_Term term) {
386
// If this disjunction is a tautology, do nothing.
387
if (ARCH_UNLIKELY(_IsTautology()))
390
// If we don't have the bit, set it in _mask and _values (if needed).
391
if (not _mask[term.flag]) {
392
_mask[term.flag] = 1;
393
_values[term.flag] = term.negated;
394
} else if (_values[term.flag] != term.negated) {
395
// If we do have the bit and the values disagree, then this entire
396
// disjunction becomes a tautology. If the values agree, it's
397
// redundant and we do nothing.
403
/// Negate this disjunction, producing a disjunction by De Morgan's law.
407
/// not (UsdPrimIsLoaded or UsdPrimIsModel)
410
/// Will negate the disjunction in parens to produce a conjunction
414
/// (not UsdPrimIsLoaded and not UsdPrimIsModel)
417
/// Every expression may be formulated as either a disjunction or a
418
/// conjuction, but allowing both affords increased expressiveness.
420
class Usd_PrimFlagsConjunction operator!() const;
424
// Let Usd_PrimFlagsDisjunction produce conjunctions when negated.
425
friend class Usd_PrimFlagsConjunction;
426
Usd_PrimFlagsDisjunction(const Usd_PrimFlagsPredicate &base) :
427
Usd_PrimFlagsPredicate(base) {}
429
/// Combine two terms to make a disjunction.
430
friend Usd_PrimFlagsDisjunction operator||(Usd_Term lhs, Usd_Term rhs);
432
/// Create a new disjunction with the term \p rhs added.
433
friend Usd_PrimFlagsDisjunction
434
operator||(const Usd_PrimFlagsDisjunction &disjunction, Usd_Term rhs);
436
/// Create a new disjunction with the term \p lhs added.
437
friend Usd_PrimFlagsDisjunction
438
operator||(Usd_Term lhs, const Usd_PrimFlagsDisjunction &disjunction);
441
inline Usd_PrimFlagsDisjunction
442
operator||(Usd_Term lhs, Usd_Term rhs) {
443
return (Usd_PrimFlagsDisjunction() || lhs) || rhs;
446
inline Usd_PrimFlagsDisjunction
447
operator||(const Usd_PrimFlagsDisjunction &disjunction, Usd_Term rhs) {
448
return Usd_PrimFlagsDisjunction(disjunction) |= rhs;
451
inline Usd_PrimFlagsDisjunction
452
operator||(Usd_Term lhs, const Usd_PrimFlagsDisjunction &disjunction) {
453
return Usd_PrimFlagsDisjunction(disjunction) |= lhs;
456
inline Usd_PrimFlagsDisjunction
457
operator||(Usd_PrimFlags lhs, Usd_PrimFlags rhs) {
458
return Usd_Term(lhs) || Usd_Term(rhs);
462
#endif // USD_PRIMFLAGS_H