OpenVDB  1.2.0
ValueTransformer.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2013 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
30 //
48 
49 #ifndef OPENVDB_TOOLS_VALUETRANSFORMER_HAS_BEEN_INCLUDED
50 #define OPENVDB_TOOLS_VALUETRANSFORMER_HAS_BEEN_INCLUDED
51 
52 #include <tbb/parallel_for.h>
53 #include <tbb/parallel_reduce.h>
54 #include <openvdb/Types.h>
55 #include <openvdb/Grid.h>
56 
57 
58 namespace openvdb {
60 namespace OPENVDB_VERSION_NAME {
61 namespace tools {
62 
106 template<typename IterT, typename XformOp>
107 inline void foreach(const IterT& iter, XformOp& op,
108  bool threaded = true, bool shareOp = true);
109 
110 template<typename IterT, typename XformOp>
111 inline void foreach(const IterT& iter, const XformOp& op,
112  bool threaded = true, bool shareOp = true);
113 
114 
154 template<typename InIterT, typename OutGridT, typename XformOp>
155 inline void transformValues(const InIterT& inIter, OutGridT& outGrid,
156  XformOp& op, bool threaded = true, bool shareOp = true);
157 
158 #ifndef _MSC_VER
159 template<typename InIterT, typename OutGridT, typename XformOp>
160 inline void transformValues(const InIterT& inIter, OutGridT& outGrid,
161  const XformOp& op, bool threaded = true, bool shareOp = true);
162 #endif
163 
164 
209 template<typename IterT, typename XformOp>
210 inline void accumulate(const IterT& iter, XformOp& op, bool threaded = true);
211 
212 
214 
215 
216 namespace valxform {
217 
218 template<typename IterT, typename OpT>
220 {
221 public:
223 
224  SharedOpApplier(const IterT& iter, OpT& op): mIter(iter), mOp(op) {}
225 
226  void process(bool threaded = true)
227  {
228  IterRange range(mIter);
229  if (threaded) {
230  tbb::parallel_for(range, *this);
231  } else {
232  (*this)(range);
233  }
234  }
235 
236  void operator()(IterRange& r) const { for ( ; r; ++r) mOp(r.iterator()); }
237 
238 private:
239  IterT mIter;
240  OpT& mOp;
241 };
242 
243 
244 template<typename IterT, typename OpT>
246 {
247 public:
249 
250  CopyableOpApplier(const IterT& iter, const OpT& op): mIter(iter), mOp(op), mOrigOp(&op) {}
251 
252  // When splitting this task, give the subtask a copy of the original functor,
253  // not of this task's functor, which might have been modified arbitrarily.
255  mIter(other.mIter), mOp(*other.mOrigOp), mOrigOp(other.mOrigOp) {}
256 
257  void process(bool threaded = true)
258  {
259  IterRange range(mIter);
260  if (threaded) {
261  tbb::parallel_for(range, *this);
262  } else {
263  (*this)(range);
264  }
265  }
266 
267  void operator()(IterRange& r) const { for ( ; r; ++r) mOp(r.iterator()); }
268 
269 private:
270  IterT mIter;
271  OpT mOp; // copy of original functor
272  OpT const * const mOrigOp; // pointer to original functor
273 };
274 
275 } // namespace valxform
276 
277 
278 template<typename IterT, typename XformOp>
279 inline void
280 foreach(const IterT& iter, XformOp& op, bool threaded, bool shared)
281 {
282  if (shared) {
283  typename valxform::SharedOpApplier<IterT, XformOp> proc(iter, op);
284  proc.process(threaded);
285  } else {
286  typedef typename valxform::CopyableOpApplier<IterT, XformOp> Processor;
287  Processor proc(iter, op);
288  proc.process(threaded);
289  }
290 }
291 
292 template<typename IterT, typename XformOp>
293 inline void
294 foreach(const IterT& iter, const XformOp& op, bool threaded, bool /*shared*/)
295 {
296  // Const ops are shared across threads, not copied.
297  typename valxform::SharedOpApplier<IterT, const XformOp> proc(iter, op);
298  proc.process(threaded);
299 }
300 
301 
303 
304 
305 namespace valxform {
306 
307 template<typename InIterT, typename OutTreeT, typename OpT>
309 {
310 public:
311  typedef typename InIterT::TreeT InTreeT;
313  typedef typename OutTreeT::ValueType OutValueT;
314 
315  SharedOpTransformer(const InIterT& inIter, OutTreeT& outTree, OpT& op):
316  mIsRoot(true),
317  mInputIter(inIter),
318  mInputTree(inIter.getTree()),
319  mOutputTree(&outTree),
320  mOp(op)
321  {
322  if (static_cast<const void*>(mInputTree) == static_cast<void*>(mOutputTree)) {
323  OPENVDB_LOG_INFO("use tools::foreach(), not transformValues(),"
324  " to transform a grid in place");
325  }
326  }
327 
330  mIsRoot(false),
331  mInputIter(other.mInputIter),
332  mInputTree(other.mInputTree),
333  mOutputTree(new OutTreeT(zeroVal<OutValueT>())),
334  mOp(other.mOp)
335  {}
336 
338  {
339  // Delete the output tree only if it was allocated locally
340  // (the top-level output tree was supplied by the caller).
341  if (!mIsRoot) {
342  delete mOutputTree;
343  mOutputTree = NULL;
344  }
345  }
346 
347  void process(bool threaded = true)
348  {
349  if (!mInputTree || !mOutputTree) return;
350 
351  IterRange range(mInputIter);
352 
353  // Independently transform elements in the iterator range,
354  // either in parallel or serially.
355  if (threaded) {
356  tbb::parallel_reduce(range, *this);
357  } else {
358  (*this)(range);
359  }
360  }
361 
363  void operator()(IterRange& range) const
364  {
365  if (!mOutputTree) return;
366  typename tree::ValueAccessor<OutTreeT> outAccessor(*mOutputTree);
367  for ( ; range; ++range) {
368  mOp(range.iterator(), outAccessor);
369  }
370  }
371 
372  void join(const SharedOpTransformer& other)
373  {
374  if (mOutputTree && other.mOutputTree) {
375  mOutputTree->merge(*other.mOutputTree);
376  }
377  }
378 
379 private:
380  bool mIsRoot;
381  InIterT mInputIter;
382  const InTreeT* mInputTree;
383  OutTreeT* mOutputTree;
384  OpT& mOp;
385 }; // class SharedOpTransformer
386 
387 
388 template<typename InIterT, typename OutTreeT, typename OpT>
390 {
391 public:
392  typedef typename InIterT::TreeT InTreeT;
394  typedef typename OutTreeT::ValueType OutValueT;
395 
396  CopyableOpTransformer(const InIterT& inIter, OutTreeT& outTree, const OpT& op):
397  mIsRoot(true),
398  mInputIter(inIter),
399  mInputTree(inIter.getTree()),
400  mOutputTree(&outTree),
401  mOp(op),
402  mOrigOp(&op)
403  {
404  if (static_cast<const void*>(mInputTree) == static_cast<void*>(mOutputTree)) {
405  OPENVDB_LOG_INFO("use tools::foreach(), not transformValues(),"
406  " to transform a grid in place");
407  }
408  }
409 
410  // When splitting this task, give the subtask a copy of the original functor,
411  // not of this task's functor, which might have been modified arbitrarily.
413  mIsRoot(false),
414  mInputIter(other.mInputIter),
415  mInputTree(other.mInputTree),
416  mOutputTree(new OutTreeT(zeroVal<OutValueT>())),
417  mOp(*other.mOrigOp),
418  mOrigOp(other.mOrigOp)
419  {}
420 
422  {
423  // Delete the output tree only if it was allocated locally
424  // (the top-level output tree was supplied by the caller).
425  if (!mIsRoot) {
426  delete mOutputTree;
427  mOutputTree = NULL;
428  }
429  }
430 
431  void process(bool threaded = true)
432  {
433  if (!mInputTree || !mOutputTree) return;
434 
435  IterRange range(mInputIter);
436 
437  // Independently transform elements in the iterator range,
438  // either in parallel or serially.
439  if (threaded) {
440  tbb::parallel_reduce(range, *this);
441  } else {
442  (*this)(range);
443  }
444  }
445 
447  void operator()(IterRange& range)
448  {
449  if (!mOutputTree) return;
450  typename tree::ValueAccessor<OutTreeT> outAccessor(*mOutputTree);
451  for ( ; range; ++range) {
452  mOp(range.iterator(), outAccessor);
453  }
454  }
455 
456  void join(const CopyableOpTransformer& other)
457  {
458  if (mOutputTree && other.mOutputTree) {
459  mOutputTree->merge(*other.mOutputTree);
460  }
461  }
462 
463 private:
464  bool mIsRoot;
465  InIterT mInputIter;
466  const InTreeT* mInputTree;
467  OutTreeT* mOutputTree;
468  OpT mOp; // copy of original functor
469  OpT const * const mOrigOp; // pointer to original functor
470 }; // class CopyableOpTransformer
471 
472 } // namespace valxform
473 
474 
476 
477 
478 template<typename InIterT, typename OutGridT, typename XformOp>
479 inline void
480 transformValues(const InIterT& inIter, OutGridT& outGrid, XformOp& op,
481  bool threaded, bool shared)
482 {
483  typedef TreeAdapter<OutGridT> Adapter;
484  typedef typename Adapter::TreeType OutTreeT;
485  if (shared) {
487  Processor proc(inIter, Adapter::tree(outGrid), op);
488  proc.process(threaded);
489  } else {
491  Processor proc(inIter, Adapter::tree(outGrid), op);
492  proc.process(threaded);
493  }
494 }
495 
496 #ifndef _MSC_VER
497 template<typename InIterT, typename OutGridT, typename XformOp>
498 inline void
499 transformValues(const InIterT& inIter, OutGridT& outGrid, const XformOp& op,
500  bool threaded, bool /*share*/)
501 {
502  typedef TreeAdapter<OutGridT> Adapter;
503  typedef typename Adapter::TreeType OutTreeT;
504  // Const ops are shared across threads, not copied.
506  Processor proc(inIter, Adapter::tree(outGrid), op);
507  proc.process(threaded);
508 }
509 #endif
510 
511 
513 
514 
515 namespace valxform {
516 
517 template<typename IterT, typename OpT>
519 {
520 public:
522 
523  // The root task makes a const copy of the original functor (mOrigOp)
524  // and keeps a pointer to the original functor (mOp), which it then modifies.
525  // Each subtask keeps a const pointer to the root task's mOrigOp
526  // and makes and then modifies a non-const copy (mOp) of it.
527  OpAccumulator(const IterT& iter, OpT& op):
528  mIsRoot(true),
529  mIter(iter),
530  mOp(&op),
531  mOrigOp(new OpT(op))
532  {}
533 
534  // When splitting this task, give the subtask a copy of the original functor,
535  // not of this task's functor, which might have been modified arbitrarily.
536  OpAccumulator(OpAccumulator& other, tbb::split):
537  mIsRoot(false),
538  mIter(other.mIter),
539  mOp(new OpT(*other.mOrigOp)),
540  mOrigOp(other.mOrigOp)
541  {}
542 
543  ~OpAccumulator() { if (mIsRoot) delete mOrigOp; else delete mOp; }
544 
545  void process(bool threaded = true)
546  {
547  IterRange range(mIter);
548  if (threaded) {
549  tbb::parallel_reduce(range, *this);
550  } else {
551  (*this)(range);
552  }
553  }
554 
555  void operator()(IterRange& r) { for ( ; r; ++r) (*mOp)(r.iterator()); }
556 
557  void join(OpAccumulator& other) { mOp->join(*other.mOp); }
558 
559 private:
560  bool mIsRoot;
561  IterT mIter;
562  OpT* mOp; // pointer to original functor, which might get modified
563  OpT const * const mOrigOp; // const copy of original functor
564 }; // class OpAccumulator
565 
566 } // namespace valxform
567 
568 
570 
571 
572 template<typename IterT, typename XformOp>
573 inline void
574 accumulate(const IterT& iter, XformOp& op, bool threaded)
575 {
576  typename valxform::OpAccumulator<IterT, XformOp> proc(iter, op);
577  proc.process(threaded);
578 }
579 
580 } // namespace tools
581 } // namespace OPENVDB_VERSION_NAME
582 } // namespace openvdb
583 
584 #endif // OPENVDB_TOOLS_VALUETRANSFORMER_HAS_BEEN_INCLUDED
585 
586 // Copyright (c) 2012-2013 DreamWorks Animation LLC
587 // All rights reserved. This software is distributed under the
588 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )