Source: OmNode.h


Annotated List
Files
Globals
Hierarchy
Index
#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.