#ifndef LOB_ADDRESS
#define LOB_ADDRESS
#include <OmHeaders.h>
#include <QObject>
#include <QMetaType>
/** \brief A class for indexing into Lob tree structures
*
* To describe the location of one node in a large OpenMath (Lob) tree structure, use a
* LobAddress. It specifies the steps you would need to take from the root node of the
* tree to reach the desired inner Lob. Each such step will either be a step to a child
* node, a step to an attribute key, or a step to an attribute value.
*
* Thus this class provides numSteps() to tell you how many steps are in the address,
* stepType() to query the type of each step (AsChild, AsKey, or AsValue, members of an
* enum in the OmNode class), and stepIndex() to tell you the number of the child or
* attribute into which the step was taken. For instance, an address with types
* AsChild,AsKey,AsChild and indices 0,2,1 has this meaning: "From the root,
* go to child 0, from there to attribute key 2, and from there to child 1."
*
* Newly constructed addresses have no steps, but you can add them with addStep().
* The default copy constructor and assignment operator apply.
*
* Two addresses are equal (operator==()) if they have the same number of steps,
* and all their steps and indices are equal.
* There is an ordering of addresses that corresponds to a view of how such OpenMath
* trees are "laid out." See operator<() for details.
*/
class LobAddress
{
public:
LobAddress();
/** \brief The inverse of toString(), creating LobAddress objects from string notation
*
* Given a string of the form described in toString(), this creates a new LobAddress
* object whose toString() value is \a encoding. If \a encoding is not of the format
* specified, an empty address is returned.
*
* This routine is tested in test_laddress::test_getters().
*/
LobAddress( const QString encoding );
/** \brief The index of the \a i<sup>th</sup> step
*
* If the \a i<sup>th</sup> step is to a child, this is the child's index.
* If it is to an attribute, this is the attribute's index.
*
* This routine is tested in test_laddress::test_getters().
*/
unsigned int stepIndex ( unsigned int i ) const;
/** \brief The type of the \a i<sup>th</sup> step
*
* This is of type OmNode::OwnershipType, which can be None, AsChild, AsKey,
* or AsValue. The None element of the enum has no meaning in this context,
* and should not be used; addStep() actually rejects it, so it is guaranteed
* not to be returned by this function.
*
* This routine is tested in test_laddress::test_getters().
*/
OmNode::OwnershipType stepType ( unsigned int i ) const;
/** \brief How many steps there are in the address
*
* Zero steps indicates an empty address. The address of the root node in a tree
* is empty, meaning no steps are required to get there from the root.
*
* This routine is tested in test_laddress::test_getters().
*/
unsigned int numSteps () const;
/** \brief Append a step to the end of the address
*
* Useful when constructing addresses.
* \param index As you would want returned from stepIndex()
* \param type As you would want returned from stepType(). Note that this function
* ignores any attempt to add a step with type equal to OmNode::None.
*
* This routine is tested in test_laddress::test_order().
*/
void addStep ( unsigned int index, OmNode::OwnershipType type );
/** \brief A copy of the address containing all steps but the last one
*
* This is useful for walking backwards up parent/container chains. For instance,
* <code>exampleLob.index( address.up() )</code> is the Lob that is the parent or
* container of <code>exampleLob.index( address )</code>.
*
* If this address has no steps, then an empty address is returned.
*/
LobAddress up () const;
/** \brief A copy of the address containing all steps but the first one
*
* This is useful for stepping inside a document or dependecy in a LurchEnvironment.
* See documentation for LurchEnvironment::address(Lob)
* and LurchEnvironment::index(LobAddress) for more information.
*
* If this address has no steps, then an empty address is returned.
*/
LobAddress down () const;
/** \brief Create a new address by appending another one to this one
*
* If \a other is the address of Lob A within Lob B, and this object is the address
* of Lob B within Lob C, then you can form the address of Lob A within Lob C by
* adding this address to \a other. The result is a new address whose first steps
* are equal to this address's steps, and whose final steps are equal to the steps
* of \a other, for a total number of steps equal to numSteps() + other.numSteps().
*/
LobAddress operator+ ( const LobAddress& other ) const;
/** \brief Strict ordering of addresses based on the steps in them
*
* It is easier to speak of one position in a tree being less than another, so I
* describe this function that way. It is the transitive closure of the following
* relation.
* <ul>
* <li>The root location in a tree is less than the locations of all its attributes
* and its children.</li>
* <li>The location of any attribute of a node is less than the location of any
* child of that same node.</li>
* <li>The locations of a node's attributes are ordered by index (lesser indices
* giving lesser locations).</li>
* <li>The locations of a node's children are ordered by index (lesser indices
* giving lesser locations).</li>
* <li>In a single attribute, the location of the key is less than the location
* of the value.</li>
* </ul>
* Note that this is a strict order relation, so if <code>addrA == addrB</code>
* then <code>!( addrA < addrB )</code>.
*
* Script authors can access this with the <code>.lessThan()</code> member function
* of LobAddress objects in script.
*
* This routine is tested in test_laddress::test_order()
* and test_laddress::test_lob_methods().
*/
bool operator< ( const LobAddress& other ) const;
/** \brief Whether two addresses have all the same steps
*
* Two addresses are equal if and only if they have the same number of steps, and each
* step in the one address has the same index and type as the corresponding step in
* the other address.
*
* Script authors can access this with the <code>.equals()</code> member function
* of LobAddress objects in script.
*
* This routine is tested in test_laddress::test_order().
*/
bool operator== ( const LobAddress& other ) const;
/** \brief Just the disjunction of operator<() with operator==()
*
* Due to its simplicity, this routine is untested.
*/
bool operator<= ( const LobAddress& other ) const;
/** \brief A simple string representation, for debugging
*
* The string is of the form CNCNCNCN..., where each C is a character indicating
* the step type (c for child, k for key, v for value) and N is an integer indicating
* the index (zero-based).
*
* This routine is partially tested in test_laddress::test_getters().
*/
QString toString () const;
/** \brief Tests whether this address has \a other as a prefix.
*
* Tests to see if the first \a other.numStep() steps of
* this address are the same as the corresponding steps of \a other.
*/
bool hasPrefix ( const LobAddress& other ) const;
/** \brief Returns a copy of this address modified to take into account the insertion of a Lob at \a loc
*
* When a Lob is inserted as a child, addresses of other children of its parent
* change. If an address is intended to be the location of some fixed Lob,
* then whenever a Lob is inserted as a child of one of that Lob's ancestors,
* the address must change.
* This method performs that update when a child is inserted at \a loc.
*
* This routine is tested in test_laddress::test_address_modification().
*/
LobAddress addressInserted ( const LobAddress& loc ) const;
/** \brief Returns a new address modified to take into account the insertion of a lob at \a loc
*
* Whenever a child of a Lob is removed, addresses of other children of its parent
* change. If an address is intended to be the location of some fixed Lob,
* then whenever a child of one of that Lob's ancestors is removed,
* the address must change.
* This method performs that update when a child is removed from \a loc.
*
* This routine is tested in test_laddress::test_address_modification().
*/
LobAddress addressRemoved( const LobAddress& loc ) const;
private:
/** Used internally as the workhorse for computing operator<().
* See the documentation for that function to learn how this one behaves.
*
* This is simply the recursive version, which assumes that steps 0 through i-1
* have been determined equal, and returns a result based only on comparing steps
* i through the end.
*/
bool strictOrderComparison ( const LobAddress& other, unsigned int i ) const;
/** Internal storage of the index of each step in the address.
*/
QList<unsigned int> stepIndices;
/** Internal storage of the type of each step in the address.
*/
QList<OmNode::OwnershipType> stepTypes;
};
Q_DECLARE_METATYPE( LobAddress )
/** \brief A global has function allowing LobAddress objects to be used as indices in a QMap
*
* See documentation on QHash for more information.
*/
uint qHash ( const LobAddress& key );
#endif // LOB_ADDRESS