• Facebook
  • Twitter
  • Reddit
  • StumbleUpon
  • Digg
  • email

#! /usr/bin/env python
# ______________________________________________________________________
"""Module ANOIDimension
 
Jonathan Riehl
 
$Id: ANOIDimension.py,v 1.5 2005/01/19 00:42:09 jriehl Exp $
"""
# ______________________________________________________________________
# Module imports
 
import ANOIBaseSpace
import ANOITrie
import ANOITypes
 
# ______________________________________________________________________
# Module data
 
__DEBUG__ = False
 
# ______________________________________________________________________
# Class definition
 
class ANOIDimension (object):
    """Class ANOIDimension
 
    Remember that POS is supposed to be the successor, so POS points to the
    tail, while NEG points to the head.
    """
    # ____________________________________________________________
    def __init__ (self, space, rootNS, uid = None):
        """ANOIDimension.__init__()
        """
        self.space = space
        crossEq = self.space.crossEquals
        self.rootTrie = ANOITrie.getNamespace(space, rootNS)
        self.typeSystem =  ANOITypes.ANOITypeManager(space, rootNS)
        # Get navigational stuff.
        self.posUid = self.typeSystem.getOrCreatePropertyKey("POS")
        self.negUid = self.typeSystem.getOrCreatePropertyKey("NEG")
        self.refUid = self.typeSystem.getOrCreatePropertyKey("REF")
        self.parentUid = self.typeSystem.getOrCreatePropertyKey("PARENT")
        # Get type stuff.
        self.dimensionType = self.rootTrie.getName("ANOIDimensionType")
        # Make sure the environment has the proper stuff.
        if self.dimensionType == ANOIBaseSpace.NIL:
            dType = self.typeSystem.createType("ANOIDimensionType")
            self.dimensionType = dType
            dnType = self.typeSystem.createType("ANOIDimensionNodeType")
            self.dimensionNodeType = dnType
            dSlots = {self.posUid : dnType,
                      self.negUid : dnType}
            self.typeSystem.updateSlots(dType, dSlots)
            dnSlots = {self.parentUid : dType,
                       self.posUid : dnType,
                       self.negUid : dnType,
                       self.refUid : self.typeSystem.atomType}
            self.typeSystem.updateSlots(dnType,dnSlots)
        else:
            self.dimensionNodeType = self.rootTrie.getName(
                "ANOIDimensionNodeType")
            assert self.dimensionNodeType != ANOIBaseSpace.NIL
        # Now see if this is a pre-existing dimension.
        if uid == None:
            # We've been asked to create a new dimension.
            self.uid = self.typeSystem.createInstance(self.dimensionType)
        else:
            self.uid = uid
 
    # ____________________________________________________________
    def append (self, uid):
        """ANOIDimension.append()
        """
        cross = self.space.cross
        crossEq = self.typeSystem.safeCrossEquals
        # Find the tail node
        tailUid = self.getTail()
        # Create the spine node
        retVal = self.typeSystem.createInstance(self.dimensionNodeType)
        crossEq(retVal, self.parentUid, self.uid)
        crossEq(retVal, self.negUid, tailUid)
        crossEq(retVal, self.refUid, uid)
        crossEq(self.uid, self.posUid, retVal)
        # XXX - Shouldn't one check to see if this UID is already in the
        # dimension?  Or can we just be happy with the contained atom
        # referring to only the most recent spine node to reference it?
        crossEq(uid, self.uid, retVal)
        if tailUid == ANOIBaseSpace.NIL:
            crossEq(self.uid, self.negUid, retVal)
        else:
            crossEq(tailUid, self.posUid, retVal)
        return retVal
 
    # ____________________________________________________________
    def remove (self, uid):
        """ANOIDimension.remove()
        NOTE - This method used to free the spine UID by calling
        self.space.freeUid(spineUid).  Currently, management of the unlinked
        spine atom is left to the caller.  Ideally some GC component would
        work here.
        """
        cross = self.space.cross
        crossEq = self.typeSystem.safeCrossEquals
        if cross(uid, self.typeSystem.typeAttr) == self.dimensionNodeType:
            spineUid = uid
            uid = cross(spineUid, self.refUid)
        else:
            spineUid = cross(uid, self.uid)
            assert spineUid != ANOIBaseSpace.NIL, ("UID %d is not in the "
                                                   "dimension." % uid)
        assert cross(spineUid, self.parentUid) == self.uid
        prev = cross(spineUid, self.negUid)
        next = cross(spineUid, self.posUid)
        if prev != ANOIBaseSpace.NIL:
            crossEq(prev, self.posUid, next)
        else:
            crossEq(self.uid, self.negUid, next)
        if next != ANOIBaseSpace.NIL:
            crossEq(next, self.negUid, prev)
        else:
            crossEq(self.uid, self.posUid, prev)
        crossEq(uid, self.uid, ANOIBaseSpace.NIL)
        return spineUid
 
    # ____________________________________________________________
    def getIter (self, start = None):
        """ANOIDimension.getIter()
        """
        if start != None:
            crntUid = start
            # Make sure we're in the right dimension.
            assert self.space.cross(start, self.parentUid) == self.uid
        else:
            crntUid = self.space.cross(self.uid, self.negUid)
        while crntUid != ANOIBaseSpace.NIL:
            yield crntUid
            crntUid = self.space.cross(crntUid, self.posUid)
        raise exceptions.StopIteration
 
    # ____________________________________________________________
    def getHead (self):
        """ANOIDimension.getHead()
        """
        return self.space.cross(self.uid, self.negUid)
 
    # ____________________________________________________________
    def getTail (self):
        """ANOIDimension.getTail()
        """
        return self.space.cross(self.uid, self.posUid)
 
# ______________________________________________________________________
# End of ANOIDimension.py