#! /usr/bin/env python
# ______________________________________________________________________
"""Module ANOICSpace
Ctypes-based OO wrapper for the ANOI C space implementation.
Jonathan Riehl
$Id: ANOICSpace.py 6 2008-06-20 22:08:55Z jriehl $
"""
# ______________________________________________________________________
# Module imports
import ctypes
import ANOIBaseSpace
# ______________________________________________________________________
# Module data
# This assumes that libANOI is in your library path!
try:
_anoic = ctypes.CDLL("libANOI.so")
except OSError:
_anoic = ctypes.CDLL("libANOI.dll")
# TODO: Add ctypes type checking wrappers for the C API.
# ______________________________________________________________________
# Class definitions
class CUID (ctypes.Structure):
# ____________________________________________________________
_fields_ = [("size", ctypes.c_int),
("data", ctypes.c_void_p)]
# ____________________________________________________________
def getUid (self):
"""CUID.getUid()
"""
ret_val = 0L
if self.size > ctypes.sizeof(ctypes.c_void_p):
raise NotImplemented("FIXME")
elif self.data is not None:
ret_val = int(self.data)
return ret_val
# ____________________________________________________________
def setUid (self, pyuid):
# XXX Truncation pinch point. Fix this!
_anoic.ANOIUidLoadValue(ctypes.byref(self), pyuid)
CUIDPtr = ctypes.POINTER(CUID)
# ______________________________________________________________________
class CATOM (ctypes.Structure):
# ____________________________________________________________
_fields_ = [("uid", CUID),
("relations", ctypes.c_void_p),
("length", ctypes.c_long),
("offset", ctypes.c_long)]
# ____________________________________________________________
def getKeys (self):
"""CATOM.getKeys()
"""
key_count = _anoic.ANOIAtomGetKeyCount(ctypes.byref(self))
keys = (CUID * key_count)()
assert key_count == _anoic.ANOIAtomGetKeys(ctypes.byref(self),
ctypes.byref(keys))
return [cuid.getUid() for cuid in keys]
CATOMPtr = ctypes.POINTER(CATOM)
# ______________________________________________________________________
class CUIDVEC (ctypes.Structure):
# ____________________________________________________________
_fields_ = [("size", ctypes.c_int),
("uids", CUIDPtr)]
# ____________________________________________________________
def getUids (self):
"""CUIDVEC.getUids()
"""
ret_val = []
for index in xrange(self.size):
ret_val.append(self.uids[index].getUid())
return ret_val
CUIDVECPtr = ctypes.POINTER(CUIDVEC)
# ______________________________________________________________________
class ANOICUid (object):
"""Class ANOICUid
"""
# ____________________________________________________________
def __init__ (self, pyuid = 0):
"""ANOIUid.__init__()
Constructor for the ANOICUid class."""
self._cuid = _anoic.ANOINewUid(None)
assert self._cuid is not None
self._as_parameter_ = self._cuid
# XXX: This is NOT going to work for arbitrarily large
# numbers! Will need to detect native word size, and then use
# a combination of ANOIUidLoadValue and ANOIUidShiftValue.
_anoic.ANOIUidLoadValue(self, ctypes.c_int(pyuid))
self._ptr = ctypes.cast(self._cuid, CUIDPtr)
self._obj = self._ptr.contents
# ____________________________________________________________
def __del__ (self):
"""ANOIUid.__del__()
Destructor for the ANOICUid class. Frees the underlying C
data structure."""
if self._cuid is not None:
_anoic.ANOIFreeUid(self)
# ____________________________________________________________
def set (self, pyuid):
"""ANOIUid.set()
Set the contained C UID object to the given value."""
assert self._cuid is not None
self._obj.setUid(pyuid)
# ____________________________________________________________
def get (self):
"""ANOIUid.get()
Get a Python number for the contained C UID object."""
assert self._cuid is not None
return self._obj.getUid()
# ______________________________________________________________________
class ANOICUidVec (object):
# ____________________________________________________________
def __init__ (self, size = 0):
self._cuidvec = _anoic.ANOINewUidVec(size)
assert self._cuidvec is not None
self._as_parameter_ = self._cuidvec
self._ptr = ctypes.cast(self._cuidvec, CUIDVECPtr)
self._obj = self._ptr.contents
# ____________________________________________________________
def __del__ (self):
if self._cuidvec is not None:
_anoic.ANOIFreeUidVec(self)
# ____________________________________________________________
def clear (self):
assert self._cuidvec is not None
assert 0 == _anoic.ANOIDelUidVec(self)
# ____________________________________________________________
def setVec (self, uids):
size = len(uids)
assert _anoic.ANOIInitUidVec(self, size) == 0
for index in xrange(size):
_anoic.ANOIUidLoadValue(ctypes.byref(self._obj.uids[index]),
uids[index])
# ____________________________________________________________
def getVec (self):
return self._obj.getUids()
# ______________________________________________________________________
class ANOICSpace (ANOIBaseSpace.ANOIBaseSpace):
"""Class ANOICSpace
"""
# ____________________________________________________________
def __init__ (self, fd = None):
"""ANOICSpace.__init__()
Constructor for the ANOI C space wrapper object."""
self._file = None
if fd is None:
# FIXME: Go find a "safe" temporary file name generator and use
# that; can't use stdout since the C space uses seek() to keep
# atom content...might want to change that.
self._file = open("space.dat", "w")
fd = self._file.fileno()
self._space = _anoic.ANOINewSpace(fd)
assert self._space is not None
self._as_parameter_ = self._space
# Scratch C UID's (avoid construction and destruction costs).
self.uid0 = ANOICUid()
self.uid1 = ANOICUid()
self.uid2 = ANOICUid()
self.vec = ANOICUidVec()
# ____________________________________________________________
def __del__ (self):
"""ANOICSpace.__del__()
Be sure to tidy up the C data when the Python object is collected.
"""
if self._space is not None:
_anoic.ANOIFreeSpace(self)
del self.uid0
del self.uid1
del self.uid2
del self.vec
if self._file is not None:
self._file.close()
# ____________________________________________________________
def cross (self, uid0, uid1):
"""ANOICSpace.cross()
Supposed to return UID0 x UID1.
"""
self.uid0.set(uid0)
self.uid1.set(uid1)
# XXX This is not uniform; would expect 0 for success.
cross_result = _anoic.ANOICross(self, self.uid0, self.uid1, self.uid2)
assert cross_result >= 0
return self.uid2.get()
# ____________________________________________________________
def crossEquals (self, uid0, uid1, uid2):
"""ANOICSpace.crossEquals()
Supposed to set UID0 x UID1 = UID2.
"""
self.uid0.set(uid0)
self.uid1.set(uid1)
self.uid2.set(uid2)
return _anoic.ANOICrossEquals(self, self.uid0, self.uid1, self.uid2)
# ____________________________________________________________
def getUid (self):
"""ANOICSpace.getUid()
Supposed to return a free UID, allocating any needed records
for it."""
atom_ptr = ctypes.cast(_anoic.ANOISpaceGetAtom(self), CATOMPtr)
return atom_ptr.contents.uid.getUid()
# ____________________________________________________________
def freeUid (self, uid):
"""ANOICSpace.freeUid()
Mark the UID passed as being free, removing any records for
it. It is implementation specific how this is done; the space
may implement garbage collection, reference counting, or take
it on faith that nothing else references the passed UID."""
self.uid0.set(uid)
return _anoic.ANOISpaceFreeAtom(self, self.uid0)
# ____________________________________________________________
def getUidContent (self, uid):
"""ANOICSpace.getUidContent()
Return a UID vector associated with the given UID."""
self.uid0.set(uid)
assert _anoic.ANOISpaceGetUidContent(self, self.uid0, self.vec) == 0
return self.vec.getVec()
# ____________________________________________________________
def setUidContent (self, uid, contentVector):
"""ANOICSpace.setUidContent()
Associate the passed UID vector with the UID. Destroys previous
content."""
self.uid0.set(uid)
self.vec.setVec(contentVector)
assert _anoic.ANOISpaceSetUidContent(self, self.uid0, self.vec) == 0
# ____________________________________________________________
def isValidUid (self, uid):
"""ANOICSpace.isValidUid()
Return a true value if the UID is defined in the space, false
otherwise."""
self.uid0.set(uid)
return _anoic.ANOISpaceFindAtom(self, self.uid0) is not None
# ____________________________________________________________
def getUidKeys (self, uid):
"""ANOICSpace.getUidKeys()
Return a vector of valid right hand cross product operands for the
given UID."""
ret_val = []
self.uid0.set(uid)
atom_ptr = ctypes.cast(_anoic.ANOISpaceFindAtom(self, self.uid0),
CATOMPtr)
return atom_ptr.contents.getKeys()
# ______________________________________________________________________
# Main (test) routine
def main ():
import ANOInit
cspace = ANOICSpace()
ANOInit.createSpace(cspace, "basicSpace.py")
del cspace
# ______________________________________________________________________
if __name__ == "__main__":
main()
# ______________________________________________________________________
# End of ANOICSpace.py