~popey/+junk/usd

« back to all changes in this revision

Viewing changes to USD/pxr/usd/lib/usd/primFlags.h

  • Committer: Alan Pope
  • Date: 2016-09-29 12:05:28 UTC
  • Revision ID: alan@popey.com-20160929120528-32j3uk1x0dgaorip
Initial attempt to snap

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 USD_PRIMFLAGS_H
 
25
#define USD_PRIMFLAGS_H
 
26
 
 
27
/// \file primFlags.h
 
28
///
 
29
/// \anchor Usd_PrimFlags
 
30
///
 
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.
 
37
///
 
38
/// For example:
 
39
/// \code
 
40
/// // Get only loaded model children.
 
41
/// prim.GetFilteredChildren(UsdPrimIsModel and UsdPrimIsLoaded)
 
42
/// \endcode
 
43
///
 
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:
 
49
/// \code
 
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)
 
62
/// \endcode
 
63
/// Here are some examples of invalid expressions:
 
64
/// \code
 
65
/// // error: cannot || a term with a conjunction.
 
66
/// (UsdPrimIsLoaded && UsdPrimIsModel) || UsdPrimIsAbstract
 
67
/// // error: cannot && disjunctions.
 
68
/// (!UsdPrimIsDefined || UsdPrimIsAbstract) && (UsdPrimIsModel || !UsdPrimIsActive)
 
69
/// \endcode
 
70
///
 
71
///
 
72
/// The following variables provide the clauses that can be combined and 
 
73
/// negated to produce predicates:
 
74
 
 
75
#include "pxr/base/arch/hints.h"
 
76
#include "pxr/base/tf/bitUtils.h"
 
77
 
 
78
#include <boost/functional/hash.hpp>
 
79
 
 
80
#include <bitset>
 
81
 
 
82
// Enum for cached flags on prims.
 
83
enum Usd_PrimFlags {
 
84
    Usd_PrimActiveFlag,
 
85
    Usd_PrimLoadedFlag,
 
86
    Usd_PrimModelFlag,
 
87
    Usd_PrimGroupFlag,
 
88
    Usd_PrimAbstractFlag,
 
89
    Usd_PrimDefinedFlag,
 
90
    Usd_PrimHasDefiningSpecifierFlag,
 
91
    Usd_PrimClipsFlag,
 
92
    Usd_PrimDeadFlag,
 
93
    Usd_PrimInstanceFlag,
 
94
    Usd_PrimMasterFlag,
 
95
    Usd_PrimNumFlags
 
96
};
 
97
 
 
98
typedef std::bitset<Usd_PrimNumFlags> Usd_PrimFlagBits;
 
99
 
 
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.
 
103
struct Usd_Term {
 
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;
 
109
    }
 
110
    bool operator!=(Usd_Term other) const {
 
111
        return !(*this == other);
 
112
    }
 
113
    Usd_PrimFlags flag;
 
114
    bool negated;
 
115
};
 
116
 
 
117
inline Usd_Term
 
118
operator!(Usd_PrimFlags flag) {
 
119
    return Usd_Term(flag, /*negated=*/true);
 
120
}
 
121
 
 
122
#ifdef doxygen
 
123
 
 
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;
 
140
#else
 
141
 
 
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;
 
151
 
 
152
#endif // doxygen
 
153
 
 
154
// Predicate functor class that tests a prim's flags against desired values.
 
155
class Usd_PrimFlagsPredicate
 
156
{
 
157
public:
 
158
    // Functor result type.
 
159
    typedef bool result_type;
 
160
 
 
161
    // Default ctor produces a tautology.
 
162
    Usd_PrimFlagsPredicate() : _negate(false) {}
 
163
 
 
164
    Usd_PrimFlagsPredicate(Usd_PrimFlags flag)
 
165
        : _negate(false) {
 
166
        _mask[flag] = 1;
 
167
        _values[flag] = true;
 
168
    }
 
169
 
 
170
    // Implicit conversion from a single term.
 
171
    Usd_PrimFlagsPredicate(Usd_Term term)
 
172
        : _negate(false) {
 
173
        _mask[term.flag] = 1;
 
174
        _values[term.flag] = not term.negated;
 
175
    }
 
176
 
 
177
    // Convenience to produce a tautological predicate.  Returns a
 
178
    // default-constructed predicate.
 
179
    static Usd_PrimFlagsPredicate Tautology() {
 
180
        return Usd_PrimFlagsPredicate();
 
181
    }
 
182
 
 
183
    // Convenience to produce a contradictory predicate.  Returns a negated
 
184
    // default-constructed predicate.
 
185
    static Usd_PrimFlagsPredicate Contradiction() {
 
186
        return Usd_PrimFlagsPredicate()._Negate();
 
187
    }
 
188
 
 
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;
 
195
    }
 
196
 
 
197
    // Invoke boolean predicate on UsdPrim \p prim.
 
198
    bool operator()(const class UsdPrim &prim) const;
 
199
 
 
200
protected:
 
201
 
 
202
    // Return true if this predicate is a tautology, false otherwise.
 
203
    bool _IsTautology() const { return *this == Tautology(); }
 
204
 
 
205
    // Set this predicate to be a tautology.
 
206
    void _MakeTautology() { *this = Tautology(); }
 
207
 
 
208
    // Return true if this predicate is a contradiction, false otherwise.
 
209
    bool _IsContradiction() const { return *this == Contradiction(); }
 
210
 
 
211
    // Set this predicate to be a contradiction.
 
212
    void _MakeContradiction() { *this = Contradiction(); }
 
213
 
 
214
    // Negate this predicate.
 
215
    Usd_PrimFlagsPredicate &_Negate() {
 
216
        _negate = not _negate;
 
217
        return *this;
 
218
    }
 
219
 
 
220
    // Return a negated copy of this predicate.
 
221
    Usd_PrimFlagsPredicate _GetNegated() const {
 
222
        return Usd_PrimFlagsPredicate(*this)._Negate();
 
223
    }
 
224
 
 
225
    // Mask indicating which flags are of interest.
 
226
    Usd_PrimFlagBits _mask;
 
227
 
 
228
    // Desired values for prim flags.
 
229
    Usd_PrimFlagBits _values;
 
230
 
 
231
private:
 
232
    // Equality comparison.
 
233
    friend bool
 
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;
 
239
    }
 
240
    // Inequality comparison.
 
241
    friend bool
 
242
    operator!=(const Usd_PrimFlagsPredicate &lhs,
 
243
               const Usd_PrimFlagsPredicate &rhs) {
 
244
        return not (lhs == rhs);
 
245
    }
 
246
 
 
247
    // hash overload.
 
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);
 
252
        return hash;
 
253
    }
 
254
 
 
255
    // Whether or not to negate the predicate's result.
 
256
    bool _negate;
 
257
 
 
258
};
 
259
 
 
260
 
 
261
/// Conjunction of prim flag predicate terms.
 
262
///
 
263
/// Usually clients will implicitly create conjunctions by &&-ing together flag
 
264
/// predicate terms.  For example:
 
265
/// \code
 
266
/// // Get all loaded model children.
 
267
/// prim.GetFilteredChildren(UsdPrimIsModel and UsdPrimIsLoaded)
 
268
/// \endcode
 
269
///
 
270
/// See primFlags.h for more details.
 
271
class Usd_PrimFlagsConjunction : public Usd_PrimFlagsPredicate {
 
272
public:
 
273
    /// Default constructed conjunction is a tautology.
 
274
    Usd_PrimFlagsConjunction() {};
 
275
 
 
276
    /// Construct with a term.
 
277
    explicit Usd_PrimFlagsConjunction(Usd_Term term) {
 
278
        *this &= term;
 
279
    }
 
280
 
 
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()))
 
285
            return *this;
 
286
 
 
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();
 
296
        }
 
297
        return *this;
 
298
    }
 
299
 
 
300
    /// Negate this conjunction, producing a disjunction by De Morgan's law.
 
301
    /// For instance:
 
302
    ///
 
303
    /// \code
 
304
    /// not (UsdPrimIsLoaded and UsdPrimIsModel)
 
305
    /// \endcode
 
306
    ///
 
307
    /// Will negate the conjunction in parens to produce a disjunction
 
308
    /// equivalent to:
 
309
    ///
 
310
    /// \code
 
311
    /// (not UsdPrimIsLoaded or not UsdPrimIsModel)
 
312
    /// \endcode
 
313
    ///
 
314
    /// Every expression may be formulated as either a disjunction or a
 
315
    /// conjuction, but allowing both affords increased expressiveness.
 
316
    ///
 
317
    class Usd_PrimFlagsDisjunction operator!() const;
 
318
 
 
319
private:
 
320
 
 
321
    // Let Usd_PrimFlagsDisjunction produce conjunctions when negated
 
322
    friend class Usd_PrimFlagsDisjunction;
 
323
    Usd_PrimFlagsConjunction(const Usd_PrimFlagsPredicate &base) :
 
324
        Usd_PrimFlagsPredicate(base) {}
 
325
 
 
326
    /// Combine two terms to make a conjunction.
 
327
    friend Usd_PrimFlagsConjunction
 
328
    operator&&(Usd_Term lhs, Usd_Term rhs);
 
329
 
 
330
    /// Create a new conjunction with the term \p rhs added.
 
331
    friend Usd_PrimFlagsConjunction
 
332
    operator&&(const Usd_PrimFlagsConjunction &conjunction, Usd_Term rhs);
 
333
 
 
334
    /// Create a new conjunction with the term \p lhs added.
 
335
    friend Usd_PrimFlagsConjunction
 
336
    operator&&(Usd_Term lhs, const Usd_PrimFlagsConjunction &conjunction);
 
337
};
 
338
 
 
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;
 
345
}
 
346
 
 
347
inline Usd_PrimFlagsConjunction
 
348
operator&&(const Usd_PrimFlagsConjunction &conjunction, Usd_Term rhs) {
 
349
    return Usd_PrimFlagsConjunction(conjunction) &= rhs;
 
350
}
 
351
 
 
352
inline Usd_PrimFlagsConjunction
 
353
operator&&(Usd_Term lhs, const Usd_PrimFlagsConjunction &conjunction) {
 
354
    return Usd_PrimFlagsConjunction(conjunction) &= lhs;
 
355
}
 
356
 
 
357
inline Usd_PrimFlagsConjunction
 
358
operator&&(Usd_PrimFlags lhs, Usd_PrimFlags rhs) {
 
359
    return Usd_Term(lhs) && Usd_Term(rhs);
 
360
}
 
361
 
 
362
 
 
363
/// Disjunction of prim flag predicate terms.
 
364
///
 
365
/// Usually clients will implicitly create disjunctions by ||-ing together flag
 
366
/// predicate terms.  For example:
 
367
/// \code
 
368
/// // Get all deactivated or undefined children.
 
369
/// prim.GetFilteredChildren(not UsdPrimIsActive or not UsdPrimIsDefined)
 
370
/// \endcode
 
371
///
 
372
/// See primFlags.h for more details.
 
373
class Usd_PrimFlagsDisjunction : public Usd_PrimFlagsPredicate {
 
374
public:
 
375
    // Default constructed disjunction is a contradiction.
 
376
    Usd_PrimFlagsDisjunction() { _Negate(); };
 
377
 
 
378
    // Construct with a term.
 
379
    explicit Usd_PrimFlagsDisjunction(Usd_Term term) {
 
380
        _Negate();
 
381
        *this |= term;
 
382
    }
 
383
 
 
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()))
 
388
            return *this;
 
389
 
 
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.
 
398
            _MakeTautology();
 
399
        }
 
400
        return *this;
 
401
    }
 
402
 
 
403
    /// Negate this disjunction, producing a disjunction by De Morgan's law.
 
404
    /// For instance:
 
405
    ///
 
406
    /// \code
 
407
    /// not (UsdPrimIsLoaded or UsdPrimIsModel)
 
408
    /// \endcode
 
409
    ///
 
410
    /// Will negate the disjunction in parens to produce a conjunction
 
411
    /// equivalent to:
 
412
    ///
 
413
    /// \code
 
414
    /// (not UsdPrimIsLoaded and not UsdPrimIsModel)
 
415
    /// \endcode
 
416
    ///
 
417
    /// Every expression may be formulated as either a disjunction or a
 
418
    /// conjuction, but allowing both affords increased expressiveness.
 
419
    ///
 
420
    class Usd_PrimFlagsConjunction operator!() const;
 
421
 
 
422
private:
 
423
 
 
424
    // Let Usd_PrimFlagsDisjunction produce conjunctions when negated.
 
425
    friend class Usd_PrimFlagsConjunction;
 
426
    Usd_PrimFlagsDisjunction(const Usd_PrimFlagsPredicate &base) :
 
427
        Usd_PrimFlagsPredicate(base) {}
 
428
 
 
429
    /// Combine two terms to make a disjunction.
 
430
    friend Usd_PrimFlagsDisjunction operator||(Usd_Term lhs, Usd_Term rhs);
 
431
 
 
432
    /// Create a new disjunction with the term \p rhs added.
 
433
    friend Usd_PrimFlagsDisjunction
 
434
    operator||(const Usd_PrimFlagsDisjunction &disjunction, Usd_Term rhs);
 
435
 
 
436
    /// Create a new disjunction with the term \p lhs added.
 
437
    friend Usd_PrimFlagsDisjunction
 
438
    operator||(Usd_Term lhs, const Usd_PrimFlagsDisjunction &disjunction);
 
439
};
 
440
 
 
441
inline Usd_PrimFlagsDisjunction
 
442
operator||(Usd_Term lhs, Usd_Term rhs) {
 
443
    return (Usd_PrimFlagsDisjunction() || lhs) || rhs;
 
444
}
 
445
 
 
446
inline Usd_PrimFlagsDisjunction
 
447
operator||(const Usd_PrimFlagsDisjunction &disjunction, Usd_Term rhs) {
 
448
    return Usd_PrimFlagsDisjunction(disjunction) |= rhs;
 
449
}
 
450
 
 
451
inline Usd_PrimFlagsDisjunction
 
452
operator||(Usd_Term lhs, const Usd_PrimFlagsDisjunction &disjunction) {
 
453
    return Usd_PrimFlagsDisjunction(disjunction) |= lhs;
 
454
}
 
455
 
 
456
inline Usd_PrimFlagsDisjunction
 
457
operator||(Usd_PrimFlags lhs, Usd_PrimFlags rhs) {
 
458
    return Usd_Term(lhs) || Usd_Term(rhs);
 
459
}
 
460
 
 
461
 
 
462
#endif // USD_PRIMFLAGS_H