/*========================================================================= Program: Visualization Toolkit Module: vtkExecutive.cxx 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. =========================================================================*/ #include "vtkExecutive.h" #include "vtkAlgorithm.h" #include "vtkAlgorithmOutput.h" #include "vtkDataObject.h" #include "vtkGarbageCollector.h" #include "vtkInformation.h" #include "vtkInformationExecutivePortKey.h" #include "vtkInformationExecutivePortVectorKey.h" #include "vtkInformationIntegerKey.h" #include "vtkInformationIterator.h" #include "vtkInformationKeyVectorKey.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkSmartPointer.h" #include #include #include "vtkCompositeDataPipeline.h" vtkInformationKeyMacro(vtkExecutive, ALGORITHM_AFTER_FORWARD, Integer); vtkInformationKeyMacro(vtkExecutive, ALGORITHM_BEFORE_FORWARD, Integer); vtkInformationKeyMacro(vtkExecutive, ALGORITHM_DIRECTION, Integer); vtkInformationKeyMacro(vtkExecutive, CONSUMERS, ExecutivePortVector); vtkInformationKeyMacro(vtkExecutive, FORWARD_DIRECTION, Integer); vtkInformationKeyMacro(vtkExecutive, FROM_OUTPUT_PORT, Integer); vtkInformationKeyMacro(vtkExecutive, KEYS_TO_COPY, KeyVector); vtkInformationKeyMacro(vtkExecutive, PRODUCER, ExecutivePort); //------------------------------------------------------------------------------ class vtkExecutiveInternals { public: std::vector InputInformation; vtkExecutiveInternals(); ~vtkExecutiveInternals(); vtkInformationVector** GetInputInformation(int newNumberOfPorts); }; //------------------------------------------------------------------------------ vtkExecutiveInternals::vtkExecutiveInternals() = default; //------------------------------------------------------------------------------ vtkExecutiveInternals::~vtkExecutiveInternals() { // Delete all the input information vectors. for (std::vector::iterator i = this->InputInformation.begin(); i != this->InputInformation.end(); ++i) { if (vtkInformationVector* v = *i) { v->Delete(); } } } //------------------------------------------------------------------------------ vtkInformationVector** vtkExecutiveInternals::GetInputInformation(int newNumberOfPorts) { // Adjust the number of vectors. int oldNumberOfPorts = static_cast(this->InputInformation.size()); if (newNumberOfPorts > oldNumberOfPorts) { // Create new vectors. this->InputInformation.resize(newNumberOfPorts, nullptr); for (int i = oldNumberOfPorts; i < newNumberOfPorts; ++i) { this->InputInformation[i] = vtkInformationVector::New(); } } else if (newNumberOfPorts < oldNumberOfPorts) { // Delete old vectors. for (int i = newNumberOfPorts; i < oldNumberOfPorts; ++i) { if (vtkInformationVector* v = this->InputInformation[i]) { // Set the pointer to nullptr first to avoid reporting of the // entry if deleting the vector causes a garbage collection // reference walk. this->InputInformation[i] = nullptr; v->Delete(); } } this->InputInformation.resize(newNumberOfPorts); } // Return the array of information vector pointers. if (newNumberOfPorts > 0) { return &this->InputInformation[0]; } else { return nullptr; } } //------------------------------------------------------------------------------ vtkExecutive::vtkExecutive() { this->ExecutiveInternal = new vtkExecutiveInternals; this->OutputInformation = vtkInformationVector::New(); this->Algorithm = nullptr; this->InAlgorithm = 0; this->SharedInputInformation = nullptr; this->SharedOutputInformation = nullptr; } //------------------------------------------------------------------------------ vtkExecutive::~vtkExecutive() { this->SetAlgorithm(nullptr); if (this->OutputInformation) { this->OutputInformation->Delete(); } delete this->ExecutiveInternal; } //------------------------------------------------------------------------------ void vtkExecutive::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); if (this->Algorithm) { os << indent << "Algorithm: " << this->Algorithm << "\n"; } else { os << indent << "Algorithm: (none)\n"; } } //------------------------------------------------------------------------------ void vtkExecutive::SetAlgorithm(vtkAlgorithm* newAlgorithm) { vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting Algorithm to " << newAlgorithm); vtkAlgorithm* oldAlgorithm = this->Algorithm; if (oldAlgorithm != newAlgorithm) { if (newAlgorithm) { newAlgorithm->Register(this); } this->Algorithm = newAlgorithm; if (oldAlgorithm) { oldAlgorithm->UnRegister(this); } this->Modified(); } } //------------------------------------------------------------------------------ vtkAlgorithm* vtkExecutive::GetAlgorithm() { return this->Algorithm; } //------------------------------------------------------------------------------ vtkInformationVector** vtkExecutive::GetInputInformation() { // Use the shared input information vector if any is set. if (this->SharedInputInformation) { return this->SharedInputInformation; } // Use this executive's input information vector. if (this->Algorithm) { int numPorts = this->Algorithm->GetNumberOfInputPorts(); return this->ExecutiveInternal->GetInputInformation(numPorts); } else { return this->ExecutiveInternal->GetInputInformation(0); } } //------------------------------------------------------------------------------ vtkInformation* vtkExecutive::GetInputInformation(int port, int connection) { if (!this->InputPortIndexInRange(port, "get connected input information from")) { return nullptr; } vtkInformationVector* inVector = this->GetInputInformation()[port]; return inVector->GetInformationObject(connection); } //------------------------------------------------------------------------------ vtkInformationVector* vtkExecutive::GetInputInformation(int port) { if (!this->InputPortIndexInRange(port, "get input information vector from")) { return nullptr; } return this->GetInputInformation()[port]; } //------------------------------------------------------------------------------ vtkInformationVector* vtkExecutive::GetOutputInformation() { // Use the shared output information vector if any is set. if (this->SharedOutputInformation) { return this->SharedOutputInformation; } // Use this executive's output information vector. if (!this->Algorithm) { return nullptr; } // Set the length of the vector to match the number of ports. int oldNumberOfPorts = this->OutputInformation->GetNumberOfInformationObjects(); this->OutputInformation->SetNumberOfInformationObjects(this->GetNumberOfOutputPorts()); // For any new information obects, set the executive pointer and // port number on the information object to tell it what produces // it. int nop = this->Algorithm->GetNumberOfOutputPorts(); for (int i = oldNumberOfPorts; i < nop; ++i) { vtkInformation* info = this->OutputInformation->GetInformationObject(i); vtkExecutive::PRODUCER()->Set(info, this, i); } return this->OutputInformation; } //------------------------------------------------------------------------------ vtkInformation* vtkExecutive::GetOutputInformation(int port) { return this->GetOutputInformation()->GetInformationObject(port); } //------------------------------------------------------------------------------ vtkExecutive* vtkExecutive::GetInputExecutive(int port, int index) { if (index < 0 || index >= this->GetNumberOfInputConnections(port)) { vtkErrorMacro("Attempt to get executive for connection index " << index << " on input port " << port << " of algorithm " << this->Algorithm->GetObjectDescription() << ", which has " << this->GetNumberOfInputConnections(port) << " connections."); return nullptr; } if (vtkAlgorithmOutput* input = this->Algorithm->GetInputConnection(port, index)) { return input->GetProducer()->GetExecutive(); } return nullptr; } //------------------------------------------------------------------------------ void vtkExecutive::ReportReferences(vtkGarbageCollector* collector) { // Report reference to our algorithm. vtkGarbageCollectorReport(collector, this->Algorithm, "Algorithm"); for (int i = 0; i < int(this->ExecutiveInternal->InputInformation.size()); ++i) { vtkGarbageCollectorReport( collector, this->ExecutiveInternal->InputInformation[i], "Input Information Vector"); } vtkGarbageCollectorReport(collector, this->OutputInformation, "Output Information Vector"); this->Superclass::ReportReferences(collector); } //------------------------------------------------------------------------------ vtkTypeBool vtkExecutive::Update() { if (this->Algorithm->GetNumberOfOutputPorts()) { return this->Update(0); } return this->Update(-1); } //------------------------------------------------------------------------------ vtkTypeBool vtkExecutive::Update(int) { vtkErrorMacro("This class does not implement Update."); return 0; } //------------------------------------------------------------------------------ int vtkExecutive::GetNumberOfInputPorts() { if (this->Algorithm) { return this->Algorithm->GetNumberOfInputPorts(); } return 0; } //------------------------------------------------------------------------------ int vtkExecutive::GetNumberOfOutputPorts() { if (this->Algorithm) { return this->Algorithm->GetNumberOfOutputPorts(); } return 0; } //------------------------------------------------------------------------------ int vtkExecutive::GetNumberOfInputConnections(int port) { vtkInformationVector* inputs = this->GetInputInformation(port); if (inputs) { return inputs->GetNumberOfInformationObjects(); } return 0; } //------------------------------------------------------------------------------ int vtkExecutive::InputPortIndexInRange(int port, const char* action) { // Make sure the algorithm is set. if (!this->Algorithm) { vtkErrorMacro("Attempt to " << (action ? action : "access") << " input port index " << port << " with no algorithm set."); return 0; } // Make sure the index of the input port is in range. if (port < 0 || port >= this->Algorithm->GetNumberOfInputPorts()) { vtkErrorMacro("Attempt to " << (action ? action : "access") << " input port index " << port << " for algorithm " << this->Algorithm->GetObjectDescription() << ", which has " << this->Algorithm->GetNumberOfInputPorts() << " input ports."); return 0; } return 1; } //------------------------------------------------------------------------------ int vtkExecutive::OutputPortIndexInRange(int port, const char* action) { // Make sure the algorithm is set. if (!this->Algorithm) { vtkErrorMacro("Attempt to " << (action ? action : "access") << " output port index " << port << " with no algorithm set."); return 0; } // Make sure the index of the output port is in range. if (port < 0 || port >= this->Algorithm->GetNumberOfOutputPorts()) { vtkErrorMacro("Attempt to " << (action ? action : "access") << " output port index " << port << " for algorithm " << this->Algorithm->GetObjectDescription() << ", which has " << this->Algorithm->GetNumberOfOutputPorts() << " output ports."); return 0; } return 1; } //------------------------------------------------------------------------------ // vtkAlgorithmOutput* vtkExecutive::GetProducerPort(vtkDataObject* d) // { // if (!this->Algorithm) // { // return 0; // } // int numPorts = this->GetNumberOfOutputPorts(); // for (int i=0; iGetOutputInformation(i); // if (info->Has(vtkDataObject::DATA_OBJECT()) && // info->Get(vtkDataObject::DATA_OBJECT()) == d) // { // return this->Algorithm->GetOutputPort(port); // } // } // return 0; // } //------------------------------------------------------------------------------ void vtkExecutive::SetSharedInputInformation(vtkInformationVector** inInfoVec) { this->SharedInputInformation = inInfoVec; } //------------------------------------------------------------------------------ void vtkExecutive::SetSharedOutputInformation(vtkInformationVector* outInfoVec) { this->SharedOutputInformation = outInfoVec; } //------------------------------------------------------------------------------ vtkDataObject* vtkExecutive::GetOutputData(int port) { if (!this->OutputPortIndexInRange(port, "get data for")) { return nullptr; } vtkInformation* info = this->GetOutputInformation(port); if (!info) { return nullptr; } // for backward compatibility we bring Outputs up to date if they do not // already exist if (!this->InAlgorithm && !info->Has(vtkDataObject::DATA_OBJECT())) { // Bring the data object up to date only if it isn't already there this->UpdateDataObject(); } // Return the data object. return info->Get(vtkDataObject::DATA_OBJECT()); } //------------------------------------------------------------------------------ void vtkExecutive::SetOutputData(int newPort, vtkDataObject* newOutput) { vtkInformation* info = this->GetOutputInformation(newPort); this->SetOutputData(newPort, newOutput, info); } //------------------------------------------------------------------------------ void vtkExecutive::SetOutputData(int newPort, vtkDataObject* newOutput, vtkInformation* info) { if (info) { vtkDataObject* currentOutput = info->Get(vtkDataObject::DATA_OBJECT()); if (newOutput != currentOutput) { info->Set(vtkDataObject::DATA_OBJECT(), newOutput); // Output has changed. Reset the pipeline information. this->ResetPipelineInformation(newPort, info); } } else { vtkErrorMacro("Could not set output on port " << newPort << "."); } } //------------------------------------------------------------------------------ vtkDataObject* vtkExecutive::GetInputData(int port, int index) { if (index < 0 || index >= this->GetNumberOfInputConnections(port)) { return nullptr; } vtkInformationVector* inVector = this->GetInputInformation()[port]; vtkInformation* info = inVector->GetInformationObject(index); vtkExecutive* e; int producerPort; vtkExecutive::PRODUCER()->Get(info, e, producerPort); if (e) { return e->GetOutputData(producerPort); } else { return nullptr; } } //------------------------------------------------------------------------------ vtkDataObject* vtkExecutive::GetInputData(int port, int index, vtkInformationVector** inInfoVec) { if (!inInfoVec[port]) { return nullptr; } vtkInformation* info = inInfoVec[port]->GetInformationObject(index); if (!info) { return nullptr; } return info->Get(vtkDataObject::DATA_OBJECT()); } //------------------------------------------------------------------------------ vtkTypeBool vtkExecutive::ProcessRequest( vtkInformation* request, vtkInformationVector** inInfo, vtkInformationVector* outInfo) { if (request->Has(FORWARD_DIRECTION())) { // Request will be forwarded. if (request->Get(FORWARD_DIRECTION()) == vtkExecutive::RequestUpstream) { if (this->Algorithm && request->Get(ALGORITHM_BEFORE_FORWARD())) { if (!this->CallAlgorithm(request, vtkExecutive::RequestUpstream, inInfo, outInfo)) { return 0; } } if (!this->ForwardUpstream(request)) { return 0; } if (this->Algorithm && request->Get(ALGORITHM_AFTER_FORWARD())) { if (!this->CallAlgorithm(request, vtkExecutive::RequestDownstream, inInfo, outInfo)) { return 0; } } } if (request->Get(FORWARD_DIRECTION()) == vtkExecutive::RequestDownstream) { vtkErrorMacro("Downstream forwarding not yet implemented."); return 0; } } else { // Request will not be forwarded. vtkErrorMacro("Non-forwarded requests are not yet implemented."); return 0; } return 1; } //------------------------------------------------------------------------------ int vtkExecutive::ComputePipelineMTime( vtkInformation*, vtkInformationVector**, vtkInformationVector*, int, vtkMTimeType*) { // Demand-driven executives that use this request should implement // this method. vtkErrorMacro("ComputePipelineMTime not implemented for this executive."); return 0; } //------------------------------------------------------------------------------ int vtkExecutive::ForwardDownstream(vtkInformation*) { // Do not forward downstream if the output is shared with another // executive. if (this->SharedOutputInformation) { return 1; } // Forwarding downstream is not yet implemented. vtkErrorMacro("ForwardDownstream not yet implemented."); return 0; } //------------------------------------------------------------------------------ int vtkExecutive::ForwardUpstream(vtkInformation* request) { // Do not forward upstream if the input is shared with another // executive. if (this->SharedInputInformation) { return 1; } if (!this->Algorithm->ModifyRequest(request, BeforeForward)) { return 0; } // Forward the request upstream through all input connections. int result = 1; for (int i = 0; i < this->GetNumberOfInputPorts(); ++i) { int nic = this->Algorithm->GetNumberOfInputConnections(i); vtkInformationVector* inVector = this->GetInputInformation()[i]; for (int j = 0; j < nic; ++j) { vtkInformation* info = inVector->GetInformationObject(j); // Get the executive producing this input. If there is none, then // it is a nullptr input. vtkExecutive* e; int producerPort; vtkExecutive::PRODUCER()->Get(info, e, producerPort); if (e) { int port = request->Get(FROM_OUTPUT_PORT()); request->Set(FROM_OUTPUT_PORT(), producerPort); if (!e->ProcessRequest(request, e->GetInputInformation(), e->GetOutputInformation())) { result = 0; } request->Set(FROM_OUTPUT_PORT(), port); } } } if (!this->Algorithm->ModifyRequest(request, AfterForward)) { return 0; } return result; } //------------------------------------------------------------------------------ void vtkExecutive::CopyDefaultInformation(vtkInformation* request, int direction, vtkInformationVector** inInfoVec, vtkInformationVector* outInfoVec) { if (direction == vtkExecutive::RequestDownstream) { // Copy information from the first input to all outputs. if (this->GetNumberOfInputPorts() > 0 && inInfoVec[0]->GetNumberOfInformationObjects() > 0) { vtkInformationKey** keys = request->Get(KEYS_TO_COPY()); int length = request->Length(KEYS_TO_COPY()); vtkInformation* inInfo = inInfoVec[0]->GetInformationObject(0); vtkSmartPointer infoIter = vtkSmartPointer::New(); infoIter->SetInformationWeak(inInfo); int oiobj = outInfoVec->GetNumberOfInformationObjects(); for (int i = 0; i < oiobj; ++i) { vtkInformation* outInfo = outInfoVec->GetInformationObject(i); for (int j = 0; j < length; ++j) { // Copy the entry. outInfo->CopyEntry(inInfo, keys[j]); // If the entry is a key vector, copy all the keys listed. if (vtkInformationKeyVectorKey* vkey = vtkInformationKeyVectorKey::SafeDownCast(keys[j])) { outInfo->CopyEntries(inInfo, vkey); } } // Give the keys an opportunity to copy themselves. infoIter->InitTraversal(); while (!infoIter->IsDoneWithTraversal()) { vtkInformationKey* key = infoIter->GetCurrentKey(); key->CopyDefaultInformation(request, inInfo, outInfo); infoIter->GoToNextItem(); } } } } else { // Get the output port from which the request was made. Use zero // if output port was not specified. int outputPort = 0; if (request->Has(FROM_OUTPUT_PORT())) { outputPort = request->Get(FROM_OUTPUT_PORT()); outputPort = outputPort == -1 ? 0 : outputPort; } // Copy information from the requesting output to all inputs. if (outputPort >= 0 && outputPort < outInfoVec->GetNumberOfInformationObjects()) { vtkInformationKey** keys = request->Get(KEYS_TO_COPY()); int length = request->Length(KEYS_TO_COPY()); vtkInformation* outInfo = outInfoVec->GetInformationObject(outputPort); vtkSmartPointer infoIter = vtkSmartPointer::New(); infoIter->SetInformationWeak(outInfo); for (int i = 0; i < this->GetNumberOfInputPorts(); ++i) { for (int j = 0; j < inInfoVec[i]->GetNumberOfInformationObjects(); ++j) { vtkInformation* inInfo = inInfoVec[i]->GetInformationObject(j); for (int k = 0; k < length; ++k) { // Copy the entry. inInfo->CopyEntry(outInfo, keys[k]); // If the entry is a key vector, copy all the keys listed. if (vtkInformationKeyVectorKey* vkey = vtkInformationKeyVectorKey::SafeDownCast(keys[k])) { inInfo->CopyEntries(outInfo, vkey); } } // Give the keys an opportunity to copy themselves. infoIter->InitTraversal(); while (!infoIter->IsDoneWithTraversal()) { vtkInformationKey* key = infoIter->GetCurrentKey(); key->CopyDefaultInformation(request, outInfo, inInfo); infoIter->GoToNextItem(); } } } } } } //------------------------------------------------------------------------------ int vtkExecutive::CallAlgorithm(vtkInformation* request, int direction, vtkInformationVector** inInfo, vtkInformationVector* outInfo) { // Copy default information in the direction of information flow. this->CopyDefaultInformation(request, direction, inInfo, outInfo); // Invoke the request on the algorithm. this->InAlgorithm = 1; int result = this->Algorithm->ProcessRequest(request, inInfo, outInfo); this->InAlgorithm = 0; // If the algorithm failed report it now. if (!result) { vtkErrorMacro("Algorithm " << this->Algorithm->GetObjectDescription() << " returned failure for request: " << *request); } return result; } //------------------------------------------------------------------------------ int vtkExecutive::CheckAlgorithm(const char* method, vtkInformation* request) { if (this->InAlgorithm) { if (request) { std::ostringstream rqmsg; request->Print(rqmsg); vtkErrorMacro(<< method << " invoked during another request. " "Returning failure to algorithm " << this->Algorithm->GetObjectDescription() << " for the recursive request:\n" << rqmsg.str().c_str()); } else { vtkErrorMacro(<< method << " invoked during another request. " "Returning failure to algorithm " << this->Algorithm->GetObjectDescription() << "."); } // Tests should fail when this happens because there is a bug in // the code. if (getenv("DASHBOARD_TEST_FROM_CTEST") || getenv("DART_TEST_FROM_DART")) { abort(); } return 0; } return 1; }