Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package python.multiplatform.ref

import android.os.Build
import android.os.Build.VERSION.SDK_INT
import python.multiplatform.currentPlatform
import python.native.ffi.NativePointer
import java.lang.ref.Cleaner
import java.lang.ref.PhantomReference
import java.lang.ref.ReferenceQueue
import java.util.concurrent.ConcurrentHashMap


actual abstract class PyAutoCloseable actual constructor(pointer: NativePointer): AutoCloseable {
private val cleaner: Cleaner?
private val cleanable: Cleaner.Cleanable?
private var phantomRef: PhantomCleanupReference?

companion object {
private val referenceQueue = ReferenceQueue<PyAutoCloseable>()
// TODO: activeReferences가 계속 커질 위험이 있음
// TODO: 성능 오버헤드: 모든 객체마다 HashMap 엔트리 생성
// TODO: 여러 이유로 TIRAMISU 미만 버전에서는 이 방법 말고 다른 방법으로 객체 소멸을 감지해야할 듯
private val activeReferences = ConcurrentHashMap<PhantomCleanupReference, () -> Unit>()

init {
Thread {
while (true) {
try {
val ref = referenceQueue.remove() as? PhantomCleanupReference
ref?.let {
activeReferences.remove(it)?.invoke()
}
} catch (e: InterruptedException) {
Thread.currentThread().interrupt()
break
}
}
}.apply {
isDaemon = true
name = "PyAutoCloseable-Cleaner"
}.start()
}
}

init {
if (SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
cleaner = Cleaner.create()
cleanable = cleaner.register(this) {
clean()
}
phantomRef = null
} else {
cleaner = null
cleanable = null
phantomRef = PhantomCleanupReference(this, referenceQueue).also {
ref -> activeReferences[ref] = { clean() }
}
}
}

actual abstract fun clean()

override fun close() {
if (SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
cleanable?.clean()
} else {
phantomRef?.let {
ref -> activeReferences.remove(ref)
clean()
}
phantomRef = null
}
}

private class PhantomCleanupReference(
referent: PyAutoCloseable,
queue: ReferenceQueue<PyAutoCloseable>
): PhantomReference<PyAutoCloseable>(referent, queue)
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,32 +1,44 @@
package python.multiplatform.ffi

import python.multiplatform.ffi.exceptions.PyException
import python.multiplatform.ref.PyAutoCloseable
import python.native.ffi.NativePointer


expect open class PyObject(pointer: NativePointer, borrowed: Boolean) {
val pointer: NativePointer
}
/*
//init {
// if (!borrowed) {
//PyIncRef(pointer)
import python.native.ffi.PyErr_Occurred
import python.native.ffi.PyLong_AsLongLong
import python.native.ffi.PyLong_FromLongLong
import python.native.ffi.PyObject_DelAttrString
import python.native.ffi.PyObject_GetAttrString
import python.native.ffi.PyObject_SetAttrString
import python.native.ffi.PyObject_Str
import python.native.ffi.PyObject_Type
import python.native.ffi.PyUnicode_AsUTF8
import python.native.ffi.Py_DecRef
import python.native.ffi.Py_IncRef
import python.native.ffi.memScoped

// TODO: !!IMPORTANT!! We need to check the case where the pointer is null one more time. (PyObject, PyType, PyException)
open class PyObject(val pointer: NativePointer, borrowed: Boolean): PyAutoCloseable(pointer) {

init {
if (borrowed) {
Py_IncRef(pointer)
// TODO: PyIncRef을 사용하는게 적절한 선택일까?
// }
//}
// TODO: Temporary commented due to the error: Expected declaration cannot have a body.
// TODO: Move this to the actual implementation.
}
}

val pointer: NativePointer
protected val typePointer: NativePointer = lazy { PyType_GetType(this.pointer) }
val Type: PyType = lazy { PyType(typePointer!!) }
// @Throws(PyException::class)
protected val type: PyType by lazy {
val typePointer: NativePointer? = PyObject_Type(pointer)
// throw PyException("Failed to get pointer of type")
PyType.getInstance(typePointer!!)
}

fun incRef() {
println("hi")
protected fun incRef() {
Py_IncRef(pointer)
}

fun decRef() {
println("hi")
protected fun decRef() {
Py_DecRef(pointer)
}

@Throws(PyException::class)
Expand All @@ -51,7 +63,7 @@ expect open class PyObject(pointer: NativePointer, borrowed: Boolean) {
}

fun setAttrOrNull(name: String, value: PyObject?) {
PyObject_SetAttrString(pointer, name, value?.pointer)
value?.pointer?.let { PyObject_SetAttrString(pointer, name, it) }
}

@Throws(PyException::class)
Expand All @@ -66,7 +78,9 @@ expect open class PyObject(pointer: NativePointer, borrowed: Boolean) {
}

override fun toString(): String {
return PyObject_GetStr(pointer)
// TODO: null check
return PyUnicode_AsUTF8(PyObject_Str(pointer)!!)!!
// return PyObject_GetStr(pointer)
}

override fun hashCode(): Int {
Expand All @@ -81,23 +95,31 @@ expect open class PyObject(pointer: NativePointer, borrowed: Boolean) {
return false
}

operator fun invoke(arg0: PyObject): PyObject {
return PyObject_CallObject(pointer, arg0)
}

operator fun invoke(arg0: PyObject, arg1: PyObject): PyObject {
return PyObject_CallObject(pointer, arg0, arg1)
override fun clean() {
type.decRef()
}

//...
// TODO: 밑에 세 함수 수정 (return type 불일치 등)
// operator fun invoke(arg0: PyObject): PyObject {
// return PyObject_CallObject(pointer, arg0)
// }
//
// operator fun invoke(arg0: PyObject, arg1: PyObject): PyObject {
// return PyObject_CallObject(pointer, arg0, arg1)
// }
//
// //...
//
// operator fun invoke(vararg args: PyObject): PyObject {
// return PyObject_CallObject(pointer, args) // TODO: 이거는 변수 하나로 잡히던가? 아님 여러개인가?
// // 리스트로 들어오는 거였던가?
// }

operator fun invoke(vararg args: PyObject): PyObject {
return PyObject_CallObject(pointer, args) // TODO: 이거는 변수 하나로 잡히던가? 아님 여러개인가?
// 리스트로 들어오는 거였던가?
}// actual fun pyLongFromLong(arg0: Long): Long {
// if (!isInitialized) return -1
// actual fun pyLongFromLong(arg0: Long): Long {
// if (!Python3.isInitialized) return -1
// memScoped {
// val pyLong = PyLong_FromLong(arg0)
//// val pyLong = PyLong_FromLong(arg0) // TODO: PyLong_FromLong을 PyLong_FromLongLong으로 교체
// val pyLong = PyLong_FromLongLong(arg0)
// if (pyLong == null) {
// throw IllegalStateException("Python long from long failed")
// }
Expand All @@ -106,15 +128,15 @@ expect open class PyObject(pointer: NativePointer, borrowed: Boolean) {
// }
//
// actual fun pyLongAsLong(arg0: Long): Long {
// if (!isInitialized) return -1
// if (!Python3.isInitialized) return -1
// memScoped {
// val restoredPyObj: CValuesRef<_object>? = arg0.toCPointer()
// val ktLong = PyLong_AsLong(restoredPyObj)
//// val ktLong = PyLong_AsLong(restoredPyObj) // TODO: PyLong_AsLong을 PyLong_AsLongLong으로 교체
// val ktLong = PyLong_AsLongLong(restoredPyObj)
// if (ktLong == -1L && PyErr_Occurred() != null) {
// throw IllegalStateException("Python long as long failed")
// }
// return ktLong
// }
// }
}
*/
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,148 @@
package python.multiplatform.ffi

class PyType {
import python.multiplatform.ffi.exceptions.PyException
import python.multiplatform.ffi.types.collections.PyDict
import python.multiplatform.ffi.types.iteration.PyIterator
import python.native.ffi.NativePointer
import python.native.ffi.PyLong_AsInt
import python.native.ffi.PyLong_AsLongLong
import python.native.ffi.PyObject_CallNoArgs
import python.native.ffi.PyObject_GetAttr
import python.native.ffi.PyObject_GetAttrString
import python.native.ffi.PyObject_Type
import python.native.ffi.PyTuple_GetItem
import python.native.ffi.PyTuple_Size
import python.native.ffi.PyType_GetName
import python.native.ffi.PyUnicode_AsUTF8
import python.native.ffi.Py_DecRef


class PyType private constructor(pointer: NativePointer): PyObject(pointer, false) {
companion object {
private val cachedObjects: MutableMap<NativePointer, PyType> = mutableMapOf()
fun getInstance(pointer: NativePointer): PyType = cachedObjects.getOrPut(pointer) { PyType(pointer) }
}

val name: String by lazy {
val namePtr: NativePointer? = PyType_GetName(pointer)
if (namePtr == null) throw PyException("Failed to get pointer of name")

val nameStr: String? = PyUnicode_AsUTF8(namePtr)
if (nameStr == null) throw PyException("Failed to get String of name")

nameStr
}

val baseType: PyType by lazy {
val attrPtr: NativePointer? = PyObject_GetAttrString(pointer, "__base__")
if (attrPtr == null) throw PyException("Failed to get __base__")

PyType(attrPtr)
}

private var cachedBaseTypes: List<PyType>? = null
private var cachedBaseTypesPointer: NativePointer? = null
val baseTypes: List<PyType>
get() {
// TODO: 에러 발생 여부 확인이 필요한건가?
val bases = PyObject_GetAttrString(pointer, "__bases__") // tuple object
if (bases != null) {

} else {
// TODO: 에러? 아니면 항상 성공 보장?
}
val baseTypes = cachedBaseTypes
val baseTypesPointer = cachedBaseTypesPointer
if (baseTypesPointer != null && bases?.address == baseTypesPointer.address) {
return baseTypes ?: listOf()
} else {
// TODO: Do null check
val lenFunc = PyObject_GetAttrString(pointer, "__len__")
val lenObj = PyObject_CallNoArgs(lenFunc!!)
val size = PyLong_AsInt(lenObj!!)


val list: MutableList<PyType> = let {
val temp: MutableList<PyType> = mutableListOf()
for (i in 0 until size) {
temp[i] = getInstance(PyTuple_GetItem(bases!!, i.toLong())!!)
}
temp
}


return list.toList()
}
}

// val mro: List<PyType>
val dict: PyDict by lazy {
// TODO: Add null check for PyObject_GetAttrString. And you should replace PyObject_GetAttrString to PyType_GetDict().
PyDict(PyObject_GetAttrString(pointer, "__dict__")!!, false)
}

init {
if (!isPyTypeObject()) throw PyException("Object is not a type")

var temp: MutableList<PyType> = mutableListOf<PyType>()
// TODO: PyObject_GetAttrString return값이 Tuple인지도 확인 해야할까?
val basesPyObject: NativePointer = PyObject_GetAttrString(pointer, "__bases__").let {it ?: throw PyException("Failed to get base types")}
val basesSize: Long = PyTuple_Size(basesPyObject).let {
if (it == -1L) throw PyException("Failed to get base types size")
else it
}
for (i in 0 until basesSize) {
// TODO: type check 필요
// temp.add(PyType(PyTuple_GetItem(basesPyObject, i)!!, true))
}
}

// fun isSubtypeOf(other: PyType): Boolean {
// // TODO: PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b) 사용
// }
//
// fun cast(obj: PyObject): PyObject {
//
// }
//
// fun isInstance(obj: PyObject): Boolean {
// // TODO: PyObject_IsInstance 이용
// }
//
// fun getIterator(): PyIterator {
//
// }
//
// operator fun invoke(args: Array<>): PyObject {
//
// }
//
// fun __new__(): PyObject {
//
// }
//
// fun __init__(obj: PyObject, args: Array<>) {
//
// }

private fun isPyTypeObject(): Boolean {
val pyTypeObject: NativePointer? = PyObject_Type(pointer)
val typeNamePyObject: NativePointer? = PyObject_GetAttrString(pointer, "__name__")

if (pyTypeObject != null && typeNamePyObject != null) {
val typeName: String = PyUnicode_AsUTF8(typeNamePyObject).let {it ?: throw PyException("Failed to get type name") }
val result: Boolean = typeName == "type"

Py_DecRef(typeNamePyObject)
Py_DecRef(pyTypeObject)

return result
}

return false
}

override fun hashCode(): Int {
return super.hashCode()
}
}
Loading