From: <wme...@us...> - 2009-09-02 07:20:45
|
Revision: 6743 http://jython.svn.sourceforge.net/jython/?rev=6743&view=rev Author: wmeissner Date: 2009-09-02 07:20:36 +0000 (Wed, 02 Sep 2009) Log Message: ----------- Implement structs with simple (non-bitfield) scalar members Modified Paths: -------------- branches/ctypes-jffi/CoreExposed.includes branches/ctypes-jffi/Lib/ctypes/__init__.py branches/ctypes-jffi/src/org/python/modules/jffi/CData.java branches/ctypes-jffi/src/org/python/modules/jffi/CType.java branches/ctypes-jffi/src/org/python/modules/jffi/DefaultInvokerFactory.java branches/ctypes-jffi/src/org/python/modules/jffi/MemoryOp.java branches/ctypes-jffi/src/org/python/modules/jffi/jffi.java Added Paths: ----------- branches/ctypes-jffi/src/org/python/modules/jffi/StructLayout.java branches/ctypes-jffi/src/org/python/modules/jffi/Structure.java Modified: branches/ctypes-jffi/CoreExposed.includes =================================================================== --- branches/ctypes-jffi/CoreExposed.includes 2009-09-01 14:27:33 UTC (rev 6742) +++ branches/ctypes-jffi/CoreExposed.includes 2009-09-02 07:20:36 UTC (rev 6743) @@ -60,7 +60,11 @@ org/python/modules/jffi/DynamicLibrary$Symbol.class org/python/modules/jffi/Function.class org/python/modules/jffi/PointerCData.class +org/python/modules/jffi/Structure.class org/python/modules/jffi/ScalarCData.class +org/python/modules/jffi/StructLayout.class +org/python/modules/jffi/StructLayout$Field.class +org/python/modules/jffi/StructLayout$ScalarField.class org/python/modules/_threading/Condition.class org/python/modules/_threading/Lock.class org/python/modules/_weakref/CallableProxyType.class Modified: branches/ctypes-jffi/Lib/ctypes/__init__.py =================================================================== --- branches/ctypes-jffi/Lib/ctypes/__init__.py 2009-09-01 14:27:33 UTC (rev 6742) +++ branches/ctypes-jffi/Lib/ctypes/__init__.py 2009-09-02 07:20:36 UTC (rev 6743) @@ -24,6 +24,70 @@ def __len__(self): return self._jffi_type.length +class _StructLayoutBuilder(object): + def __init__(self, union = False): + self.size = 0 + self.offset = 0 + self.fields = [] + self.union = union + + def align(self, offset, align): + return align + ((offset - 1) & ~(align - 1)); + + def add_fields(self, fields): + for f in fields: + self.add_field(f) + return self + + def add_field(self, f): + if not issubclass(f[1], _ScalarCData): + raise RuntimeError("non-scalar fields not supported") + + if len(f) != 2: + raise RuntimeError("structs with bitfields not supported") + + self.offset = self.align(self.offset, alignment(f[1])) + self.fields.append(jffi.StructLayout.ScalarField(f[0], f[1], self.offset)) + if not self.union: + self.offset += sizeof(f[1]) + self.size = max(self.offset, sizeof(f[1])) + + return self + + def build(self): + return jffi.StructLayout(fields = self.fields, union = self.union) + +class _StructMetaClass(type): + def __new__(cls, name, bases, dict): + try: + layout = dict['_jffi_type'] = _StructLayoutBuilder().add_fields(dict['_fields_']).build() + # make all fields accessible via .foo + for f in dict['_fields_']: + dict[f[0]] = layout[f[0]] + except: + pass + + return type.__new__(cls, name, bases, dict) + +class _UnionMetaClass(type): + def __new__(cls, name, bases, dict): + try: + layout = dict['_jffi_type'] = _StructLayoutBuilder().add_fields(dict['_fields_'], union = True).build() + # make all fields accessible via .foo + for f in dict['_fields_']: + dict[f[0]] = layout[f[0]] + except: + pass + + + return type.__new__(cls, name, bases, dict) + +class Structure(jffi.Structure): + __metaclass__ = _StructMetaClass + +class Union(jffi.Structure): + __metaclass__ = _UnionMetaClass + def sizeof(type): return type._jffi_type.size @@ -34,7 +98,7 @@ return cdata.byref() def pointer(cdata): - return cdata.pointer() + return cdata.pointer(POINTER(cdata.__class__)) _pointer_type_cache = {} def POINTER(ctype): @@ -170,14 +234,3 @@ return self._dlltype(name) cdll = LibraryLoader(CDLL) - -# -#class _StructMetaClass(type): -# def __new__(cls, name, bases, dict): -# for attr in dict: -# if attr == '_fields_': -# print "%s has attr %s" % (name, attr) -# return type.__new__(cls, name, bases, dict) -# -#class Structure: -# __metaclass__ = _StructMetaClass Modified: branches/ctypes-jffi/src/org/python/modules/jffi/CData.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/CData.java 2009-09-01 14:27:33 UTC (rev 6742) +++ branches/ctypes-jffi/src/org/python/modules/jffi/CData.java 2009-09-02 07:20:36 UTC (rev 6743) @@ -23,11 +23,20 @@ this.referenceMemory = null; } - @ExposedMethod(names= { "byref", "pointer" }) + @ExposedMethod(names= { "byref" }) public PyObject byref() { - return new PointerCData(type, getReferenceMemory(), memoryOp); + return new PointerCData(PointerCData.TYPE, type, getReferenceMemory(), memoryOp); } + @ExposedMethod(names= { "pointer" }) + public PyObject pointer(PyObject pytype) { + if (!(pytype instanceof PyType)) { + throw Py.TypeError("expected type"); + } + + return new PointerCData((PyType) pytype, type, getReferenceMemory(), memoryOp); + } + final boolean hasReferenceMemory() { return referenceMemory != null; } Modified: branches/ctypes-jffi/src/org/python/modules/jffi/CType.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/CType.java 2009-09-01 14:27:33 UTC (rev 6742) +++ branches/ctypes-jffi/src/org/python/modules/jffi/CType.java 2009-09-02 07:20:36 UTC (rev 6743) @@ -152,12 +152,14 @@ final MemoryOp componentMemoryOp; Pointer(PyType subtype, PyType pyComponentType, CType componentType) { - super(NativeType.POINTER, com.kenai.jffi.Type.POINTER, MemoryOp.POINTER); + super(NativeType.POINTER, com.kenai.jffi.Type.POINTER, new MemoryOp.PointerOp(subtype, CType.POINTER)); this.pyComponentType = pyComponentType; this.componentType = componentType; if (pyComponentType.isSubType(ScalarCData.TYPE)) { - this.componentMemoryOp = new ScalarOp(MemoryOp.getMemoryOp(componentType.getNativeType()), pyComponentType); + this.componentMemoryOp = new ScalarOp(componentType.getMemoryOp(), pyComponentType); + } else if (pyComponentType.isSubType(Structure.TYPE)) { + this.componentMemoryOp = new MemoryOp.StructOp(pyComponentType); } else { throw Py.TypeError("pointer only supported for scalar types"); } @@ -168,15 +170,15 @@ public static PyObject Pointer_new(PyNewWrapper new_, boolean init, PyType subtype, PyObject[] args, String[] keywords) { + if (args.length != 1) { + throw Py.TypeError(String.format("__init__() takes exactly 1 argument (%d given)", args.length)); + } + Pointer p = typeCache.get(args[0]); if (p != null) { return p; } - if (args.length != 1) { - throw Py.TypeError(String.format("__init__() takes exactly 1 argument (%d given)", args.length)); - } - if (!(args[0] instanceof PyType)) { throw Py.TypeError("expected ctypes class"); } @@ -217,5 +219,7 @@ return result; } } + + } } Modified: branches/ctypes-jffi/src/org/python/modules/jffi/DefaultInvokerFactory.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/DefaultInvokerFactory.java 2009-09-01 14:27:33 UTC (rev 6742) +++ branches/ctypes-jffi/src/org/python/modules/jffi/DefaultInvokerFactory.java 2009-09-02 07:20:36 UTC (rev 6743) @@ -430,6 +430,8 @@ public void marshal(HeapInvocationBuffer buffer, PyObject parameter) { if (parameter instanceof Pointer) { buffer.putAddress(((Pointer) parameter).getAddress()); + } else if (parameter == Py.None) { + buffer.putAddress(0); } else { throw Py.TypeError("expected pointer argument"); } Modified: branches/ctypes-jffi/src/org/python/modules/jffi/MemoryOp.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/MemoryOp.java 2009-09-01 14:27:33 UTC (rev 6742) +++ branches/ctypes-jffi/src/org/python/modules/jffi/MemoryOp.java 2009-09-02 07:20:36 UTC (rev 6743) @@ -3,6 +3,7 @@ import org.python.core.Py; import org.python.core.PyObject; +import org.python.core.PyType; /** * Defines memory operations for a primitive type @@ -20,7 +21,7 @@ public static final MemoryOp UINT64 = new Unsigned64(); public static final MemoryOp FLOAT = new Float32(); public static final MemoryOp DOUBLE = new Float64(); - public static final MemoryOp POINTER = new PointerOp(); + public static final MemoryOp POINTER = new PointerOp(PointerCData.TYPE, CType.POINTER); public static final MemoryOp STRING = new StringOp(); public static final MemoryOp getMemoryOp(NativeType type) { @@ -175,7 +176,15 @@ return Py.newFloat(mem.getDouble(offset)); } } - private static final class PointerOp extends MemoryOp { + static final class PointerOp extends MemoryOp { + private final PyType pytype; + private final CType ctype; + + public PointerOp(PyType pytype, CType ctype) { + this.pytype = pytype; + this.ctype = ctype; + } + public final void put(Memory mem, long offset, PyObject value) { if (value instanceof Pointer) { mem.putAddress(offset, ((Pointer) value).getAddress()); @@ -186,9 +195,10 @@ public final PyObject get(Memory mem, long offset) { DirectMemory dm = new NativeMemory(mem.getAddress(offset)); - return new PointerCData(CType.POINTER, dm, INVALID); + return new PointerCData(pytype, ctype, dm, INVALID); } } + private static final class StringOp extends MemoryOp { public final void put(Memory mem, long offset, PyObject value) { throw Py.NotImplementedError("Cannot set String"); @@ -198,4 +208,32 @@ throw Py.NotImplementedError("Cannot get String"); } } + + static final class StructOp extends MemoryOp { + + private final PyType type; + private final StructLayout layout; + + public StructOp(PyType type) { + this.type = type; + PyObject l = type.__getattr__("_jffi_type"); + if (!(l instanceof StructLayout)) { + throw Py.TypeError("invalid _jffi_type for " + type.fastGetName() + "; should be instance of jffi.StructLayout"); + } + this.layout = (StructLayout) l; + } + + public StructOp(PyType type, StructLayout layout) { + this.type = type; + this.layout = layout; + } + + public final void put(Memory mem, long offset, PyObject value) { + throw Py.NotImplementedError("not implemented"); + } + + public final PyObject get(Memory mem, long offset) { + return new Structure(type, layout, mem.slice(offset)); + } + } } Added: branches/ctypes-jffi/src/org/python/modules/jffi/StructLayout.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/StructLayout.java (rev 0) +++ branches/ctypes-jffi/src/org/python/modules/jffi/StructLayout.java 2009-09-02 07:20:36 UTC (rev 6743) @@ -0,0 +1,160 @@ + +package org.python.modules.jffi; + +import java.util.HashMap; +import java.util.Map; +import org.python.core.ArgParser; +import org.python.core.Py; +import org.python.core.PyList; +import org.python.core.PyNewWrapper; +import org.python.core.PyObject; +import org.python.core.PyType; +import org.python.expose.ExposedGet; +import org.python.expose.ExposedMethod; +import org.python.expose.ExposedNew; +import org.python.expose.ExposedType; + +@ExposedType(name = "jffi.StructLayout", base = CType.class) +public class StructLayout extends CType { + public static final PyType TYPE = PyType.fromClass(StructLayout.class); + static { + TYPE.fastGetDict().__setitem__("Field", Field.TYPE); + TYPE.fastGetDict().__setitem__("ScalarField", ScalarField.TYPE); + } + + private final Map<PyObject, Field> fieldMap; + + StructLayout(Field[] fields, com.kenai.jffi.Type struct, MemoryOp op) { + super(NativeType.STRUCT, struct, op); + Map<PyObject, Field> m = new HashMap<PyObject, Field>(fields.length); + for (Field f : fields) { + m.put(f.name, f); + } + this.fieldMap = m; + } + + @ExposedType(name = "jffi.StructLayout.Field", base = PyObject.class) + public static class Field extends PyObject { + public static final PyType TYPE = PyType.fromClass(Field.class); + @ExposedGet + final CType ctype; + + @ExposedGet + final int offset; + + final PyObject name; + + final MemoryOp op; + + Field(PyObject name, CType ctype, int offset, MemoryOp op) { + this.name = name; + this.ctype = ctype; + this.offset = offset; + this.op = op; + } + + Field(PyObject name, CType ctype, int offset) { + this(name, ctype, offset, ctype.getMemoryOp()); + } + + private static org.python.modules.jffi.Pointer asPointer(PyObject obj) { + if (!(obj instanceof org.python.modules.jffi.Pointer)) { + throw Py.TypeError("expected pointer"); + } + + return (org.python.modules.jffi.Pointer) obj; + } + + @Override + public PyObject __get__(PyObject obj, PyObject type) { + return Field___get__(obj, type); + } + + @Override + public void __set__(PyObject obj, PyObject value) { + Field___set__(obj, value); + } + + @ExposedMethod + public PyObject Field___get__(PyObject obj, PyObject type) { + return op.get(asPointer(obj).getMemory(), offset); + } + + @ExposedMethod + public void Field___set__(PyObject obj, PyObject value) { + op.put(asPointer(obj).getMemory(), offset, value); + } + + + @ExposedMethod(names={"get" }) + PyObject get(PyObject obj) { + return op.get(asPointer(obj).getMemory(), offset); + } + + @ExposedMethod(names={"set"}) + PyObject set(PyObject obj, PyObject value) { + + op.put(asPointer(obj).getMemory(), offset, value); + + return value; + } + } + + @ExposedNew + public static PyObject StructLayout_new(PyNewWrapper new_, boolean init, PyType subtype, + PyObject[] args, String[] keywords) { + + ArgParser ap = new ArgParser("__init__", args, keywords, new String[] { "fields", "union" }, 1); + + if (!(ap.getPyObject(0) instanceof PyList)) { + throw Py.TypeError("expected list of jffi.StructLayout.Field"); + } + + PyList pyFields = (PyList) ap.getPyObject(0); + com.kenai.jffi.Type[] fieldTypes = new com.kenai.jffi.Type[pyFields.size()]; + Field[] fields = new Field[pyFields.size()]; + + for (int i = 0; i < fields.length; ++i) { + PyObject pyField = pyFields.pyget(i); + if (!(pyField instanceof Field)) { + throw Py.TypeError(String.format("element %d of field list is not an instance of jffi.StructLayout.Field", i)); + } + Field f = (Field) pyField; + fields[i] = f; + fieldTypes[i] = f.ctype.jffiType; + } + + com.kenai.jffi.Type jffiType = ap.getPyObject(1, Py.False).__nonzero__() + ? new com.kenai.jffi.Union(fieldTypes) + : new com.kenai.jffi.Struct(fieldTypes); + + return new StructLayout(fields, jffiType, MemoryOp.INVALID); + } + + @ExposedType(name = "jffi.StructLayout.ScalarField", base = Field.class) + public static class ScalarField extends Field { + public static final PyType TYPE = PyType.fromClass(ScalarField.class); + + public ScalarField(PyObject name, CType ctype, int offset) { + super(name, ctype, offset); + } + + @ExposedNew + public static PyObject ScalarField_new(PyNewWrapper new_, boolean init, PyType subtype, + PyObject[] args, String[] keywords) { + ArgParser ap = new ArgParser("__init__", args, keywords, new String[] { "name", "type", "offset"}); + + return new ScalarField(ap.getPyObject(0), CType.typeOf(ap.getPyObject(1)), ap.getInt(2)); + } + } + + Field getField(PyObject name) { + return fieldMap.get(name); + } + + @Override + public PyObject __getitem__(PyObject key) { + StructLayout.Field f = getField(key); + return f != null ? f : Py.None; + } +} Added: branches/ctypes-jffi/src/org/python/modules/jffi/Structure.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/Structure.java (rev 0) +++ branches/ctypes-jffi/src/org/python/modules/jffi/Structure.java 2009-09-02 07:20:36 UTC (rev 6743) @@ -0,0 +1,71 @@ + +package org.python.modules.jffi; + +import org.python.core.Py; +import org.python.core.PyNewWrapper; +import org.python.core.PyObject; +import org.python.core.PyType; +import org.python.expose.ExposedNew; +import org.python.expose.ExposedType; + +@ExposedType(name = "jffi.Structure", base = CData.class) +public class Structure extends CData implements Pointer { + public static final PyType TYPE = PyType.fromClass(Structure.class); + + private final StructLayout layout; + + Structure(PyType pyType, StructLayout layout) { + this(pyType, layout, AllocatedNativeMemory.allocate(layout.size(), true)); + } + + Structure(PyType pyType, StructLayout layout, Memory m) { + super(pyType, layout, new MemoryOp.StructOp(pyType, layout)); + this.layout = layout; + setReferenceMemory(m); + } + + @ExposedNew + public static PyObject Structure_new(PyNewWrapper new_, boolean init, PyType subtype, + PyObject[] args, String[] keywords) { + + PyObject layout = subtype.__getattr__("_jffi_type"); + if (!(layout instanceof StructLayout)) { + throw Py.TypeError("invalid _jffi_type for " + subtype.fastGetName() + "; should be instance of jffi.StructLayout"); + } + + return new Structure(subtype, (StructLayout) layout); + } + + protected final void initReferenceMemory(Memory m) { + throw Py.RuntimeError("reference memory already initialized"); + } + + StructLayout.Field getField(PyObject key) { + StructLayout.Field f = layout.getField(key); + if (f == null) { + throw Py.NameError(String.format("struct %s has no field '%s'", getType().fastGetName(), key.toString())); + } + return f; + } + + @Override + public PyObject __getitem__(PyObject key) { + StructLayout.Field f = getField(key); + return f.op.get(getReferenceMemory(), f.offset); + } + + @Override + public void __setitem__(PyObject key, PyObject value) { + StructLayout.Field f = getField(key); + f.op.put(getReferenceMemory(), f.offset, value); + } + + public long getAddress() { + return getMemory().getAddress(); + } + + public DirectMemory getMemory() { + return getReferenceMemory(); + } + +} Modified: branches/ctypes-jffi/src/org/python/modules/jffi/jffi.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/jffi.java 2009-09-01 14:27:33 UTC (rev 6742) +++ branches/ctypes-jffi/src/org/python/modules/jffi/jffi.java 2009-09-02 07:20:36 UTC (rev 6743) @@ -22,6 +22,8 @@ dict.__setitem__("Function", Function.TYPE); dict.__setitem__("PointerCData", PointerCData.TYPE); dict.__setitem__("ScalarCData", ScalarCData.TYPE); + dict.__setitem__("Structure", Structure.TYPE); + dict.__setitem__("StructLayout", StructLayout.TYPE); dict.__setitem__("FUNCFLAG_STDCALL", Py.newInteger(FUNCFLAG_STDCALL)); dict.__setitem__("FUNCFLAG_CDECL", Py.newInteger(FUNCFLAG_CDECL)); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |