#ifndef OPAL_SRefAttr_HH #define OPAL_SRefAttr_HH // ------------------------------------------------------------------------ // $RCSfile: SRefAttr.h,v $ // ------------------------------------------------------------------------ // $Revision: 1.2 $ // ------------------------------------------------------------------------ // Copyright: see Copyright.readme // ------------------------------------------------------------------------ // // Template class SRefAttr // // ------------------------------------------------------------------------ // // $Date: 2000/04/07 12:02:54 $ // $Author: opal $ // // ------------------------------------------------------------------------ #include "AbstractObjects/AttributeBase.h" #include "AbstractObjects/OpalData.h" #include "AbstractObjects/Object.h" #include "Expressions/ADeferred.h" #include "Expressions/SValue.h" #include "Utilities/OpalException.h" //#include "Utilities/Options.h" #include "Utilities/Options.h" #include namespace Expressions { // Class SRefAttr // ---------------------------------------------------------------------- /// An attribute defined as a reference to a scalar. // The referred attribute may have values of type real, logical or string. // When a reference is seen, the pointers to the relevant object and // attribute are left zero. When the expression value is required, // the object and the attribute are searched, and the pointers cached. // The reference is registered with the object. If the object referred // to is deleted, it calls the invalidate() method of all reference // expressions referring to it. This resets the pointers to zero, so // that the next evaluation forces to search for a replacement object. template class SRefAttr: public AttributeBase { public: /// Constructor. // Use object name [b]oName[/b] to identify the object containing // the scalar, and [b]aName[/b] to identify the scalar itself. SRefAttr(const std::string &oName, const std::string &aName, int index); SRefAttr(const SRefAttr &); virtual ~SRefAttr(); /// Make clone. virtual SRefAttr *clone() const; /// Evaluate. // Evaluate the reference and return the value. virtual T evaluate() const; /// Return real value. // This function has been added for speed of access. virtual double getReal(); /// Invalidate. // Force re-evaluation of the reference. virtual void invalidate(); /// Print the reference. virtual void print(std::ostream &) const; /// Store new value. // Evaluate the reference and assign to the scalar referred to. virtual void set(const T &) const; private: // Not implemented. SRefAttr(); void operator=(const SRefAttr &); // Fill in the reference. void fill() const; // The name of the type referred to. static const std::string typeName; // The referred object, attribute and index. const std::string obj_name; const std::string att_name; const int itsIndex; // The object and attribute referred to. mutable Object *itsObject; mutable Attribute *itsAttr; }; template inline std::ostream &operator<<(std::ostream &os, const SRefAttr &a) { a.print(os); return os; } // Implementation of class SRefAttr. // ------------------------------------------------------------------------ template SRefAttr::SRefAttr (const std::string &oName, const std::string &aName, int index): obj_name(oName), att_name(aName), itsIndex(index), itsObject(0), itsAttr(0) {} template SRefAttr::SRefAttr(const SRefAttr &rhs): obj_name(rhs.obj_name), att_name(rhs.att_name), itsIndex(rhs.itsIndex), itsObject(rhs.itsObject), itsAttr(rhs.itsAttr) {} template SRefAttr::~SRefAttr() { if(itsObject) itsObject->unregisterReference(this); } template SRefAttr *SRefAttr::clone() const { return new SRefAttr(*this); } template T SRefAttr::evaluate() const { fill(); if(AttributeBase *base = &itsAttr->getBase()) { if(itsIndex) { if(ADeferred *value = dynamic_cast*>(base)) { std::vector array = value->evaluate(); if(itsIndex > int(array.size())) { throw OpalException("SRefAttr::evaluate()", "Reference \"" + getImage() + "\" has index out of range."); } else { return array[itsIndex - 1]; } } else { throw OpalException("SRefAttr::evaluate()", "Reference \"" + getImage() + "\" is not an array."); } } else { if(SValue *value = dynamic_cast *>(base)) { return value->evaluate(); } else { throw OpalException("SRefAttr::evaluate()", getImage() + "\" is of the wrong type."); } } } return T(0); } template double SRefAttr::getReal() { throw OpalException("SValue::getReal()", "Attribute is not of real type."); } template <> inline double SRefAttr::getReal() { return evaluate(); } template void SRefAttr::print(std::ostream &os) const { os << obj_name; if(! att_name.empty()) os << "->" << att_name; if(itsIndex != 0) os << '[' << itsIndex << ']'; return; } template void SRefAttr::invalidate() { itsObject = 0; itsAttr = 0; } template void SRefAttr::set(const T &value) const { fill(); if(AttributeBase *base = &itsAttr->getBase()) { if(dynamic_cast *>(base)) { return itsAttr->set(new SValue(value)); } else { throw OpalException("Real::get()", "Attribute \"" + itsAttr->getName() + "\" is of the wrong type."); } } } template void SRefAttr::fill() const { if(itsObject == 0) { itsObject = OpalData::getInstance()->find(obj_name); if(itsObject == 0) { if(att_name.empty() && itsIndex <= 0) { static Object *variable = OpalData::getInstance()->find("REAL_VARIABLE"); itsObject = variable->clone(obj_name); OpalData::getInstance()->define(itsObject); if(Options::verify) { std::cerr << "\nThe \"" << obj_name << "\" is unknown, created with zero value.\n" << std::endl; } } else { throw OpalException("SRefAttr::fill()", "Object \"" + obj_name + "\" is unknown."); } } // Register the reference with the object, to allow invalidation // when the object is deleted. itsObject->registerReference(const_cast*>(this)); if(att_name.empty()) { itsAttr = itsObject->findAttribute("VALUE"); if(itsAttr == 0) { throw OpalException("SRefAttr::fill()", "Object \"" + obj_name + "\" is not a variable, constant or vector."); } } else { itsAttr = itsObject->findAttribute(att_name); if(itsAttr == 0) { throw OpalException("SRefAttr::fill()", "Attribute \"" + obj_name + "->" + att_name + "\" is unknown."); } } } } } #endif // OPAL_SRefAttr_HH