|
|
#ifndef OM_NODE_H #define OM_NODE_H /** * Base class for OpenMath nodes. * * This class provides an attributed and ordered hierarchical structure to represent any OpenMath formal object. * As an unbound tree node structure, it specifies some storage managment facilities (OpenMath externalized format), * and also it does an automatic memory managment based on the principle of adoption (all attributes and children * are adopted and are freed with the parent node). Because of this principle however, you should always allocate * your nodes by using the 'new' operator. */ class OmNode { private: typedef list<OmNode *> children_t; typedef vector<pair<OmSymbolNode *, OmNode *> > attributes_t; typedef vector<OmComment *> comments_t; public: /** * This class provides a basic linear iteration process on the children of an OmNode. */ class Iterator { public: /** * Test if iteration is done. */ virtual bool done() const { return it_==node_.children_.end(); } /** * Make a transition to the next state, so that the next child is pointed. * @li Precondition: ~ NotIterating */ virtual void next() { OmException::checkNotIterating(done()); ++it_; } /** * Get the pointed child. * @li Precondition: ~ NotIterating */ virtual OmNode * get() { OmException::checkNotIterating(done()); return *it_; } /** * Get the pointed child, then make a transition to the next state. * @li Precondition: ~ NotIterating */ virtual OmNode * getNext() { OmException::checkNotIterating(done()); return *it_++; } private: Iterator(OmNode & node_in) : node_(node_in), it_(node_in.children_.begin()) {} private: OmNode & node_; children_t::iterator it_; friend class OmNode; }; friend class Iterator; /** * This class provides a basic linear iteration process on the children of a constant OmNode. */ class ConstIterator { public: /** * Test if iteration is done. */ virtual bool done() const { return it_==node_.children_.end(); } /** * Make a transition to the next state, so that the next child is pointed. * @li Precondition: ~ NotIterating */ virtual void next() { OmException::checkNotIterating(done()); ++it_; } /** * Get the pointed constant child. * @li Precondition: ~ NotIterating */ virtual const OmNode * get() const { OmException::checkNotIterating(done()); return *it_; } /** * Get the pointed child, then make a transition to the next state. * @li Precondition: ~ NotIterating */ virtual const OmNode * getNext() { OmException::checkNotIterating(done()); return *it_++; } private: ConstIterator(const OmNode & node_in) : node_(node_in), it_(node_in.children_.begin()) {} private: const OmNode & node_; children_t::const_iterator it_; friend class OmNode; }; friend class ConstIterator; public: /** * Get the concrete type. */ virtual OmType type() const { return typeImp(); } /** * Clone deeply the entire node structure, including the attributes and the adopted subtree. * All the copy constructors should be called from the class hierarchy up to this class. */ virtual OmNode * clone() const { return cloneImp(); } /** * Count the number of children. */ virtual unsigned int count() const { return children_.size(); } /** * Create an iterator on this node. */ virtual Iterator iterate() { return Iterator(*this); } /** * Create a constant iterator on this constant node. */ virtual ConstIterator iterate() const { return ConstIterator(*this); } /** * Append a new child node at the end of the list of children. The child is adopted. * The current (this) node is returned. * @li Precondition: ~ NullPointer(adoption_in) */ virtual OmNode * append(OmNode * adoption_in) { OmException::checkNullPointer(adoption_in); OmException::checkDisabled(adoption_in->type()==OmUnknownType, "Cannot append a node of unknown type"); children_.push_back(adoption_in); return this; } /** * Insert a new child node in the list of children. * The position is determined by the given iterator (which can be done). * The current (this) node is returned. * @li Precondition: ~ NullPointer(adoption_in) */ virtual OmNode * insert(Iterator it_in, OmNode * adoption_in) { OmException::checkNullPointer(adoption_in); OmException::checkDisabled(adoption_in->type()==OmUnknownType, "Cannot insert a node of unknown type"); children_.insert(it_in.it_, adoption_in); return this; } /** * Extract a child node from the list of children. * The position is determined by the given active iterator. * The extracted node is returned as an out parameter, and no memory destruction occurs. * The current (this) node is returned. * @li Precondition: ~ NotIterating(it_in) */ virtual OmNode * extract(Iterator it_in, OmNode *& desadoption_out) { OmException::checkNotIterating(it_in.done()); OmException::checkDisabled(it_in.get()->type()==OmUnknownType, "Cannot extract a node of unknown type"); desadoption_out = it_in.get(); children_.erase(it_in.it_); return this; } /** * Kill a child node in the list of children. * The position is determined by the given active iterator. * The killed node, its attributes, and its adopted subtree are all definitively destroyed from the memory. * The current (this) node is returned. * @li Precondition: ~ NotIterating(it_in) */ virtual OmNode * kill(Iterator it_in) { OmException::checkNotIterating(it_in.done()); OmException::checkDisabled(it_in.get()->type()==OmUnknownType, "Cannot kill a node of unknown type"); delete it_in.get(); children_.erase(it_in.it_); return this; } /** * Count the number of attributes. */ virtual unsigned int countAttributes() const { return attributes_.size(); } /** * Consult an attribute. * The position is determined by the given index. * The consulted attribute is returned as two out parameters. * The current (this) node is returned. * @li Precondition: ~ OutOfRange(index_in) */ virtual OmNode * consultAttribute(unsigned int index_in, OmSymbolNode *& symbol_out, OmNode *& node_out) { OmException::checkOutOfRange(index_in>=countAttributes()); OmException::checkDisabled(type()==OmUnknownType, "Cannot consult attributes on a node of unknown type"); symbol_out = attributes_[index_in].first; node_out = attributes_[index_in].second; return this; } /** * Append a new attribute at the end of the list of attributes. The attribute is adopted. * The current (this) node is returned. * @li Precondition: ~ NullPointer(symbolAdoption_in) and ~ NullPointer(nodeAdoption_in) */ virtual OmNode * appendAttribute(OmSymbolNode * symbolAdoption_in, OmNode * nodeAdoption_in) { OmException::checkNullPointer(symbolAdoption_in); OmException::checkNullPointer(nodeAdoption_in); OmException::checkDisabled(type()==OmUnknownType, "Cannot append attributes to a node of unknown type"); OmException::checkDisabled(nodeAdoption_in->type()==OmUnknownType, "Cannot append an attribute with a node of unknown type"); attributes_.push_back(pair<OmSymbolNode *, OmNode *>(symbolAdoption_in, nodeAdoption_in)); return this; } /** * Insert a new attribute in the list of attributes. * The position is determined by the given index (which can be equal to the number of attributes). * The current (this) node is returned. * @li Precondition: ~ OutOfRange(index_in) and ~ NullPointer(symbolAdoption_in) and ~ NullPointer(nodeAdoption_in) */ virtual OmNode * insertAttribute(unsigned int index_in, OmSymbolNode * symbolAdoption_in, OmNode * nodeAdoption_in) { OmException::checkOutOfRange(index_in>countAttributes()); OmException::checkNullPointer(symbolAdoption_in); OmException::checkNullPointer(nodeAdoption_in); OmException::checkDisabled(type()==OmUnknownType, "Cannot insert attributes to a node of unknown type"); OmException::checkDisabled(nodeAdoption_in->type()==OmUnknownType, "Cannot insert an attribute with a node of unknown type"); attributes_.insert(attributes_.begin()+index_in, pair<OmSymbolNode *, OmNode *>(symbolAdoption_in, nodeAdoption_in)); return this; } /** * Extract an attribute from the list of attributes. * The position is determined by the given index. * The extracted attribute is returned as two out parameters, and no memory destruction occurs. * The current (this) node is returned. * @li Precondition: ~ OutOfRange(index_in) */ virtual OmNode * extractAttribute(unsigned int index_in, OmSymbolNode *& symbolDesadoption_out, OmNode *& nodeDesadoption_out) { OmException::checkOutOfRange(index_in>=countAttributes()); OmException::checkDisabled(type()==OmUnknownType, "Cannot extract attributes of a node of unknown type"); symbolDesadoption_out = attributes_[index_in].first; nodeDesadoption_out = attributes_[index_in].second; attributes_.erase(attributes_.begin()+index_in); return this; } /** * Kill an attribute in the list of attributes. * The position is determined by the given index. * The killed attribute is definitively destroyed from the memory. * The current (this) node is returned. * @li Precondition: ~ OutOfRange(index_in) */ virtual OmNode * killAttribute(unsigned int index_in) { OmException::checkOutOfRange(index_in>=countAttributes()); OmException::checkDisabled(type()==OmUnknownType, "Cannot kill attributes of a node of unknown type"); delete (OmNode *)(attributes_[index_in].first); delete attributes_[index_in].second; attributes_.erase(attributes_.begin()+index_in); return this; } /** * Count the number of comments. */ virtual unsigned int countComments() const { return comments_.size(); } /** * Consult a comment. * The position is determined by the given index. * The consulted comment is returned as an out parameters. * The current (this) node is returned. * @li Precondition: ~ OutOfRange(index_in) */ virtual OmNode * consultComment(unsigned int index_in, OmComment *& comment_out) { OmException::checkOutOfRange(index_in>=countComments()); comment_out = comments_[index_in]; return this; } /** * Append a new comment at the end of the list of comments. The comment is adopted. * The current (this) node is returned. * @li Precondition: ~ NullPointer(adoption_in) */ virtual OmNode * appendComment(OmComment * adoption_in) { OmException::checkNullPointer(adoption_in); comments_.push_back(adoption_in); return this; } /** * Insert a new comment in the list of comment. * The position is determined by the given index (which can be equal to the number of comments). * The current (this) node is returned. * @li Precondition: ~ OutOfRange(index_in) and ~ NullPointer(adoption_in) */ virtual OmNode * insertComment(unsigned int index_in, OmComment * adoption_in) { OmException::checkOutOfRange(index_in>countComments()); OmException::checkNullPointer(adoption_in); comments_.insert(comments_.begin()+index_in, adoption_in); return this; } /** * Extract a comment from the list of comments. * The position is determined by the given index. * The extracted comment is returned as an out parameters, and no memory destruction occurs. * The current (this) node is returned. * @li Precondition: ~ OutOfRange(index_in) */ virtual OmNode * extractComment(unsigned int index_in, OmComment *& desadoption_out) { OmException::checkOutOfRange(index_in>=countComments()); desadoption_out = comments_[index_in]; comments_.erase(comments_.begin()+index_in); return this; } /** * Kill a comment in the list of comments. * The position is determined by the given index. * The killed comment is definitively destroyed from the memory. * The current (this) node is returned. * @li Precondition: ~ OutOfRange(index_in) */ virtual OmNode * killComment(unsigned int index_in) { OmException::checkOutOfRange(index_in>=countComments()); delete comments_[index_in]; comments_.erase(comments_.begin()+index_in); return this; } public: /** * Hibernate a node to an OpenMath output device. The writing follows a Standard OpenMath protocol, so that * the node, its attributes and its adopted subtree are all stored into the device. The attached comments are * all written just before the object (prefix position). * @li Precondition: ~ NullPointer(node_in) */ static void hibernate(OmOutputDevice & output_in, const OmNode * node_in); /** * Resurrect the node from an OpenMath input device. The reading follows a Standard OpenMath protocol, so that * the node, its attributes and its adopted subtree are all restored from the device. * Note comments cannot be read using this method (they do not inherit from OmNode), a comment collector must be called for this. */ static OmNode * resurrect(OmInputDevice & input_in); /** * Dynamically create a new node given its type. However, this virtual constructor here breaks the OCP principle * for OmNode, but on a relatively strong stabilized hierarchy (based on formal specifications). */ static OmNode * create(OmType type_in); protected: /** * Default constructor for OmNode. Every inherited class should provide a default constructor to keep the mechanism, * so that instances conforming to OmNode can be virtually created by calling create(). */ OmNode() {} /** * Copy constructor for OmNode. Every inherited class should provide a copy constructor to keep the mechanism, * so that instances conforming to OmNode can be cloned deeply by calling clone(). */ OmNode(const OmNode & other_in) { for (children_t::const_iterator it=other_in.children_.begin(); it!=other_in.children_.end(); ++it) { children_.push_back((*it)->clone()); } for (attributes_t::const_iterator it=other_in.attributes_.begin(); it!=other_in.attributes_.end(); ++it) { attributes_.push_back(pair<OmSymbolNode *, OmNode *>((OmSymbolNode *)(((OmNode *)(it->first))->clone()), it->second->clone())); } for (comments_t::const_iterator it=other_in.comments_.begin(); it!=other_in.comments_.end(); ++it) { comments_.push_back((*it)->clone()); } } /** * Hidden destructor for dynamic memory allocation only. * Every inherited class should provide an hidden destructor to respect the philosophy. */ virtual ~OmNode() { for (children_t::iterator it=children_.begin(); it!=children_.end(); it++) { delete *it; } for (attributes_t::iterator it=attributes_.begin(); it!=attributes_.end(); ++it) { delete (OmNode *)it->first; delete it->second; } for (comments_t::iterator it=comments_.begin(); it!=comments_.end(); ++it) { delete *it; } } /** * Implement this to return the concrete type of the node. This can be useful to access dynamic type * identification when needed. For compound objects, only the corresponding begin tag should be returned. */ virtual OmType typeImp() const = 0; /** * Implement this to clone deeply a node. The work generally consists in creating a new concrete node by calling * the concrete copy constructor. */ virtual OmNode * cloneImp() const = 0; /** * Implement this to write a node to an output device. Not the attributes nor comments have to be written. * The aim is to execute a minimal polymorphic parsing, so that the specific 'tags' (between < and >) are * written using OmOutputDevice::writeX() and subnodes are written by simply calling hibernate(). */ virtual void writeImp(OmOutputDevice & output_in) const = 0; /** * Implement this to read a node from an input device. The attributes have not to be read. However reading * comments inside the node is required (not before nor after however). * The aim is to execute a minimal polymorphic parsing, so that the specific 'tags' (between < and >) are * read using OmInputDevice::readX() and subnodes are read by simply calling resurrect(). Comments inside * the object must be read using a comment collector. */ virtual void readImp(OmInputDevice & input_in) = 0; private: void operator =(const OmNode &) {} private: children_t children_; attributes_t attributes_; comments_t comments_; friend class OmCommentCollector; }; #endif // OM_NODE_H
Generated by: root@localhost.localdomain on Tue Oct 12 21:02:30 199. |