You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
8.9 KiB
C++
277 lines
8.9 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkCompositeDataSetNodeReference.h
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=========================================================================*/
|
|
|
|
#ifndef vtkCompositeDataSetNodeReference_h
|
|
#define vtkCompositeDataSetNodeReference_h
|
|
|
|
#include "vtkCompositeDataIterator.h"
|
|
#include "vtkCompositeDataSet.h"
|
|
#include "vtkWeakPointer.h"
|
|
|
|
#include <cassert>
|
|
#include <type_traits>
|
|
|
|
#ifndef __VTK_WRAP__
|
|
|
|
namespace vtk
|
|
{
|
|
|
|
namespace detail
|
|
{
|
|
|
|
//------------------------------------------------------------------------------
|
|
// MTimeWatcher:
|
|
// operator() return true if the MTime of its argument is less than or equal
|
|
// to the MTime of the object used to construct it.
|
|
//
|
|
// Create/reset using `mtime_watcher = MTimeWatcher{obj};`
|
|
//
|
|
// Test using `bool cacheIsValid = mtime_watcher(obj);`
|
|
//
|
|
// There are two variants of this:
|
|
// - MTimeWatcher can be used to ALWAYS check for valid mtimes.
|
|
// - DebugMTimeWatcher can be used to check mtimes ONLY in debugging builds,
|
|
// and is defined as an empty, transparent no-op object in optimized builds.
|
|
// The optimized version will always return true from operator().
|
|
struct MTimeWatcher
|
|
{
|
|
vtkMTimeType MTime{ 0 };
|
|
|
|
MTimeWatcher() {}
|
|
explicit MTimeWatcher(vtkObject* o)
|
|
: MTime{ o->GetMTime() }
|
|
{
|
|
}
|
|
bool operator()(vtkObject* o) const { return o->GetMTime() <= this->MTime; }
|
|
void Reset(vtkObject* o) { this->MTime = o->GetMTime(); }
|
|
bool MTimeIsValid(vtkObject* o) const { return o->GetMTime() <= this->MTime; }
|
|
};
|
|
|
|
// empty, transparent, does nothing. operator() always returns true.
|
|
struct NoOpMTimeWatcher
|
|
{
|
|
NoOpMTimeWatcher() {}
|
|
explicit NoOpMTimeWatcher(vtkObject*) {}
|
|
bool operator()(vtkObject*) const { return true; }
|
|
void Reset(vtkObject*) {}
|
|
bool MTimeIsValid(vtkObject*) const { return true; }
|
|
};
|
|
|
|
// Debug-dependent version:
|
|
#ifndef _NDEBUG
|
|
using DebugMTimeWatcher = MTimeWatcher;
|
|
#else
|
|
using DebugMTimeWatcher = NoOpMTimeWatcher;
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
// DebugWeakPointer: Defined to vtkWeakPointer on debugging builds, T* on
|
|
// non-debugging builds.
|
|
#ifndef _NDEBUG
|
|
template <class ObjectType>
|
|
using DebugWeakPointer = vtkWeakPointer<ObjectType>;
|
|
#else
|
|
template <class ObjectType>
|
|
using DebugWeakPointer = ObjectType*;
|
|
#endif
|
|
|
|
} // end namespace detail
|
|
|
|
/**
|
|
* A reference proxy into a vtkCompositeDataSet, obtained by dereferencing an
|
|
* iterator from the vtk::Range(vtkCompositeDataSet*) overloads.
|
|
*
|
|
* This proxy may be used as a pointer, in which case it will forward the
|
|
* currently pointed-to vtkDataObject*. This means that the following code is
|
|
* legal:
|
|
*
|
|
* ```cpp
|
|
* for (auto node : vtk::Range(cds))
|
|
* { // decltype(node) == CompositeDataSetNodeReference
|
|
* if (node) // same as: if (node.GetDataObject() != nullptr)
|
|
* {
|
|
* assert(node->IsA("vtkDataObject")); // node.GetDataObject()->IsA(...)
|
|
* node = nullptr; // node.SetDataObject(nullptr)
|
|
* }
|
|
* }
|
|
*
|
|
* for (vtkDataObject *dObj : vtk::Range(cds))
|
|
* {
|
|
* // Work with dObj
|
|
* }
|
|
* ```
|
|
*
|
|
* This allows for simple access to the objects in the composite dataset. If
|
|
* more advanced operations are required, the CompositeDataSetNodeReference can:
|
|
*
|
|
* - Access the current vtkDataObject*:
|
|
* - `vtkDataObject* NodeReference::GetDataObject() const`
|
|
* - `NodeReference::operator vtkDataObject* () const` (implicit conversion)
|
|
* - `vtkDataObject* NodeReference::operator->() const` (arrow operator)
|
|
* - Replace the current vtkDataObject* in the composite dataset:
|
|
* - `void NodeReference::SetDataObject(vtkDataObject*)`
|
|
* - `NodeReference& NodeReference::operator=(vtkDataObject*)` (assignment)
|
|
* - SetGet the vtkDataObject at the same position in another composite dataset
|
|
* - `void NodeReference::SetDataObject(vtkCompositeDataSet*, vtkDataObject*)`
|
|
* - `vtkDataObject* NodeReference::GetDataObject(vtkCompositeDataSet*) const`
|
|
* - Check and access node metadata (if any):
|
|
* - `bool NodeReference::HasMetaData() const`
|
|
* - `vtkInformation* NodeReference::GetMetaData() const`
|
|
* - Get the current flat index within the parent range:
|
|
* - `unsigned int NodeReference::GetFlatIndex() const`
|
|
*
|
|
* Assigning one reference to another assigns the vtkDataObject* pointer to the
|
|
* target reference. Assigning to non-leaf nodes invalidates all iterators /
|
|
* references.
|
|
*
|
|
* Equality testing compares each reference's DataObject and FlatIndex.
|
|
*
|
|
* @warning The NodeReference shares state with the OwnerType iterator that
|
|
* generates it. Incrementing or destroying the parent iterator will invalidate
|
|
* the reference. In debugging builds, these misuses will be caught via runtime
|
|
* assertions.
|
|
*/
|
|
template <typename IteratorType,
|
|
typename OwnerType>
|
|
class CompositeDataSetNodeReference
|
|
: private detail::DebugMTimeWatcher // empty-base optimization when NDEBUG
|
|
{
|
|
static_assert(std::is_base_of<vtkCompositeDataIterator, IteratorType>::value,
|
|
"CompositeDataSetNodeReference's IteratorType must be a "
|
|
"subclass of vtkCompositeDataIterator.");
|
|
|
|
// Either a vtkWeakPointer (debug builds) or raw pointer (non-debug builds)
|
|
mutable detail::DebugWeakPointer<IteratorType> Iterator{ nullptr };
|
|
|
|
// Check that the reference has not been invalidated by having the
|
|
// borrowed internal iterator modified.
|
|
void AssertValid() const
|
|
{
|
|
|
|
// Test that the weak pointer hasn't been cleared
|
|
assert(
|
|
"Invalid CompositeDataNodeReference accessed (iterator freed)." && this->Iterator != nullptr);
|
|
// Check MTime:
|
|
assert("Invalid CompositeDataNodeReference accessed (iterator modified)." &&
|
|
this->MTimeIsValid(this->Iterator));
|
|
}
|
|
|
|
protected:
|
|
explicit CompositeDataSetNodeReference(IteratorType* iterator)
|
|
: detail::DebugMTimeWatcher(iterator)
|
|
, Iterator(iterator)
|
|
{
|
|
}
|
|
|
|
public:
|
|
friend OwnerType; // To allow access to protected methods/base class
|
|
|
|
CompositeDataSetNodeReference() = delete;
|
|
CompositeDataSetNodeReference(const CompositeDataSetNodeReference& src) = default;
|
|
CompositeDataSetNodeReference(CompositeDataSetNodeReference&&) noexcept = default;
|
|
~CompositeDataSetNodeReference() = default;
|
|
|
|
// Assigns the DataObject from src to this:
|
|
CompositeDataSetNodeReference& operator=(const CompositeDataSetNodeReference& src)
|
|
{
|
|
this->SetDataObject(src.GetDataObject());
|
|
return *this;
|
|
}
|
|
|
|
// Compares data object and flat index:
|
|
friend bool operator==(
|
|
const CompositeDataSetNodeReference& lhs, const CompositeDataSetNodeReference& rhs)
|
|
{
|
|
return lhs.GetDataObject() == rhs.GetDataObject() && lhs.GetFlatIndex() == rhs.GetFlatIndex();
|
|
}
|
|
|
|
// Compares data object and flat index:
|
|
friend bool operator!=(
|
|
const CompositeDataSetNodeReference& lhs, const CompositeDataSetNodeReference& rhs)
|
|
{
|
|
return lhs != rhs;
|
|
}
|
|
|
|
vtkDataObject* GetDataObject() const
|
|
{
|
|
this->AssertValid();
|
|
// GetCurrentDataObject is buggy -- the iterator caches the current dataset
|
|
// internally, so if the object has changed since the iterator was
|
|
// incremented, the changes will not be visible through the iterator's
|
|
// API. See VTK issue #17529.
|
|
// Instead, look it up in the dataset. It's a bit slower, but will always be
|
|
// correct.
|
|
// return this->Iterator->GetCurrentDataObject();
|
|
return this->Iterator->GetDataSet()->GetDataSet(this->Iterator);
|
|
}
|
|
|
|
vtkDataObject* GetDataObject(vtkCompositeDataSet* other)
|
|
{
|
|
this->AssertValid();
|
|
return other->GetDataSet(this->Iterator);
|
|
}
|
|
|
|
operator bool() const { return this->GetDataObject() != nullptr; }
|
|
|
|
operator vtkDataObject*() const { return this->GetDataObject(); }
|
|
|
|
vtkDataObject* operator->() const { return this->GetDataObject(); }
|
|
|
|
void SetDataObject(vtkDataObject* obj)
|
|
{
|
|
this->AssertValid();
|
|
vtkCompositeDataSet* cds = this->Iterator->GetDataSet();
|
|
cds->SetDataSet(this->Iterator, obj);
|
|
}
|
|
|
|
void SetDataObject(vtkCompositeDataSet* other, vtkDataObject* dObj)
|
|
{
|
|
this->AssertValid();
|
|
other->SetDataSet(this->Iterator, dObj);
|
|
}
|
|
|
|
CompositeDataSetNodeReference& operator=(vtkDataObject* obj)
|
|
{
|
|
this->SetDataObject(obj);
|
|
return *this;
|
|
}
|
|
|
|
unsigned int GetFlatIndex() const
|
|
{
|
|
this->AssertValid();
|
|
return this->Iterator->GetCurrentFlatIndex();
|
|
}
|
|
|
|
bool HasMetaData() const
|
|
{
|
|
this->AssertValid();
|
|
return this->Iterator->HasCurrentMetaData() != 0;
|
|
}
|
|
|
|
vtkInformation* GetMetaData() const
|
|
{
|
|
this->AssertValid();
|
|
return this->Iterator->GetCurrentMetaData();
|
|
}
|
|
};
|
|
|
|
} // end namespace vtk
|
|
|
|
#endif // __VTK_WRAP__
|
|
|
|
#endif // vtkCompositeDataSetNodeReference_h
|
|
|
|
// VTK-HeaderTest-Exclude: vtkCompositeDataSetNodeReference.h
|