fix(editor): various improvements related to tree sitter code analysis

- Integrate the 'language-treesitter' module from sora-editor into the IDE itself for better control and customization of the tree sitter analysis.

- Invalidate line span generator when tree is edited - This is required because TSTree instances are not thread-safe and the spans generator tries to query the tree after it is edited.
 This results in SEGV_MAPERR errors in native code because the TSNodes are invalidatd after TSTree.edit() calls and the cursor tries to query those invalidated nodes.

- Recycle and reuse TS* instances - When analyzing the source code using Tree Sitter, a huge number of objects are created and deleted. This results in an increased of times the garbage
 collector is invoked.
This commit is contained in:
Akash Yadav
2023-10-15 17:55:11 +05:30
parent 971fc605ff
commit d5910c6fc0
52 changed files with 3132 additions and 1202 deletions
+1
View File
@@ -25,6 +25,7 @@ android {
}
dependencies {
api(libs.androidide.ts)
api(projects.lsp.api)
api(projects.lsp.models)
@@ -0,0 +1,60 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock
/**
* @author Akash Yadav
*/
internal class DefaultSynchronized(
// disabled by default
private val isEnabled: Boolean = false
) : TSSynchronized {
private val lock = ReentrantLock()
override fun lock(timeout: Long, unit: TimeUnit): Boolean {
return if (isEnabled) {
require(timeout > 0) { "Timeout must be greater than 0" }
lock.tryLock() || lock.tryLock(timeout, unit)
} else {
false
}
}
override fun unlock() {
if (isEnabled) {
lock.unlock()
}
}
override fun <T> withLock(timeout: Long, unit: TimeUnit, action: () -> T): T {
if (!isEnabled) {
return action()
}
check(lock(timeout, unit)) { "Failed to acquire lock" }
try {
return action()
} finally {
unlock()
}
}
}
@@ -0,0 +1,54 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import java.util.concurrent.TimeUnit
/**
* Synchronization for tree sitter objects.
*
* @author Akash Yadav
*/
interface TSSynchronized {
/**
* Acquires the lock. Throws an [IllegalStateException] if the lock can not be acquired within
* the given [timeout].
*
* @param timeout The timeout duration.
* @param unit The time unit for the timeout duration.
* @return Whether the lock was held or not.
*/
fun lock(timeout: Long = 3, unit: TimeUnit = TimeUnit.SECONDS): Boolean
/**
* Releases the lock.
*/
fun unlock()
/**
* Execute the given [action] with the lock. The lock will be held before executing the action
* and finally released. Throws an [IllegalStateException] if the lock can not be acquired within
* * the given [timeout].
*
* @param timeout The timeout duration.
* @param unit The time unit for the timeout duration.
* @param action The action to perform.
*/
fun <T : Any?> withLock(timeout: Long = 3, unit: TimeUnit = TimeUnit.SECONDS, action: () -> T): T
}
@@ -0,0 +1,71 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSInputEdit
import com.itsaky.androidide.treesitter.TSPoint
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
class TreeSitterInputEdit @JvmOverloads internal constructor(
startByte: Int = 0,
oldEndByte: Int = 0,
newEndByte: Int = 0,
startPoint: TSPoint? = null,
oldEndPoint: TSPoint? = null,
newEndPoint: TSPoint? = null
) : TSInputEdit(startByte, oldEndByte, newEndByte, startPoint, oldEndPoint, newEndPoint),
RecyclableObjectPool.Recyclable by DefaultRecyclable(), TSSynchronized by DefaultSynchronized() {
companion object {
/**
* Obtain an instance of [TreeSitterInputEdit].
*/
@JvmStatic
fun obtain(startByte: Int,
oldEndByte: Int,
newEndByte: Int,
startPoint: TSPoint?,
oldEndPoint: TSPoint?,
newEndPoint: TSPoint?): TreeSitterInputEdit {
return obtainFromPool<TreeSitterInputEdit>().apply {
this.startByte = startByte
this.oldEndByte = oldEndByte
this.newEndByte = newEndByte
this.startPoint = startPoint
this.oldEndPoint = oldEndPoint
this.newEndPoint = newEndPoint
}
}
}
override fun recycle() {
withLock {
this.startByte = 0
this.oldEndByte = 0
this.newEndByte = 0
this.startPoint = null
this.oldEndPoint = null
this.newEndPoint = null
returnToPool()
}
}
}
@@ -0,0 +1,90 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSLanguage
import com.itsaky.androidide.treesitter.TSLookaheadIterator
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterLookaheadIterator @JvmOverloads internal constructor(pointer: Long = 0) :
TSLookaheadIterator(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable(),
TSSynchronized by DefaultSynchronized() {
companion object {
@JvmStatic
fun obtain(pointer: Long): TreeSitterLookaheadIterator {
return obtainFromPool<TreeSitterLookaheadIterator>().apply {
nativeObject = pointer
}
}
}
override fun next(): Boolean {
return withLock {
super.next()
}
}
override fun getCurrentSymbol(): Short {
return withLock {
super.getCurrentSymbol()
}
}
override fun getCurrentSymbolName(): String {
return withLock {
super.getCurrentSymbolName()
}
}
override fun resetState(stateId: Short): Boolean {
return withLock {
super.resetState(stateId)
}
}
override fun reset(language: TSLanguage?, stateId: Short): Boolean {
return withLock {
super.reset(language, stateId)
}
}
override fun getLanguage(): TSLanguage {
return withLock {
super.getLanguage()
}
}
override fun close() {
withLock {
super.close()
recycle()
}
}
override fun recycle() {
this.nativeObject = 0
this.langName = null
returnToPool()
}
}
@@ -0,0 +1,55 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSLanguage
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterNativeLanguage @JvmOverloads internal constructor(
name: String? = null,
pointers: LongArray? = longArrayOf(0, 0)
) : TSLanguage(name, pointers), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(name: String?, pointers: LongArray?): TreeSitterNativeLanguage {
return obtainFromPool<TreeSitterNativeLanguage>().apply {
this.name = name
this.nativeObject = pointers?.get(0) ?: 0
this.libHandle = pointers?.get(1) ?: 0
}
}
}
override fun close() {
super.close()
recycle()
}
override fun recycle() {
this.nativeObject = 0
this.name = null
this.libHandle = 0
returnToPool()
}
}
@@ -0,0 +1,226 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSNode
import com.itsaky.androidide.treesitter.TSPoint
import com.itsaky.androidide.treesitter.TSTree
import com.itsaky.androidide.treesitter.TSTreeCursor
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterNode @JvmOverloads internal constructor(
context0: Int = 0,
context1: Int = 0,
context2: Int = 0,
context3: Int = 0,
id: Long = 0,
tree: Long = 0
) : TSNode(context0, context1, context2, context3, id, tree),
RecyclableObjectPool.Recyclable by DefaultRecyclable(), TSSynchronized by DefaultSynchronized() {
companion object {
@JvmStatic
fun obtain(
context0: Int, context1: Int, context2: Int, context3: Int, id: Long, tree: Long
): TreeSitterNode {
return obtainFromPool<TreeSitterNode>().apply {
this.context0 = context0
this.context1 = context1
this.context2 = context2
this.context3 = context3
this.id = id
this.tree = tree
}
}
}
override fun getTree(): TSTree {
return withLock { super.getTree() }
}
override fun getChild(index: Int): TSNode {
return withLock { super.getChild(index) }
}
override fun getNamedChild(index: Int): TSNode {
return withLock { super.getNamedChild(index) }
}
override fun getChildByFieldName(fieldName: String?): TSNode {
return withLock { super.getChildByFieldName(fieldName) }
}
override fun walk(): TSTreeCursor {
return withLock { super.walk() }
}
override fun findNodeWithType(type: String?, namedOnly: Boolean): TSNode {
return withLock { super.findNodeWithType(type, namedOnly) }
}
override fun findChildrenWithType(type: String?, reverseSearch: Boolean,
namedOnly: Boolean): MutableList<TSNode> {
return withLock { super.findChildrenWithType(type, reverseSearch, namedOnly) }
}
override fun findChildrenWithTypeReverse(type: String?, namedOnly: Boolean): MutableList<TSNode> {
return withLock { super.findChildrenWithTypeReverse(type, namedOnly) }
}
override fun getParent(): TSNode {
return withLock { super.getParent() }
}
override fun getFieldNameForChild(p0: Int): String {
return withLock { super.getFieldNameForChild(p0) }
}
override fun getChildByFieldId(p0: Int): TSNode {
return withLock { super.getChildByFieldId(p0) }
}
override fun getNextSibling(): TSNode {
return withLock { super.getNextSibling() }
}
override fun getPreviousSibling(): TSNode {
return withLock { super.getPreviousSibling() }
}
override fun getNextNamedSibling(): TSNode {
return withLock { super.getNextNamedSibling() }
}
override fun getPreviousNamedSibling(): TSNode {
return withLock { super.getPreviousNamedSibling() }
}
override fun getFirstChildForByte(p0: Int): TSNode {
return withLock { super.getFirstChildForByte(p0) }
}
override fun getFirstNamedChildForByte(p0: Int): TSNode {
return withLock { super.getFirstNamedChildForByte(p0) }
}
override fun getDescendantForByteRange(p0: Int, p1: Int): TSNode {
return withLock { super.getDescendantForByteRange(p0, p1) }
}
override fun getDescendantForPointRange(p0: TSPoint?, p1: TSPoint?): TSNode {
return withLock { super.getDescendantForPointRange(p0, p1) }
}
override fun getNamedDescendantForByteRange(p0: Int, p1: Int): TSNode {
return withLock { super.getNamedDescendantForByteRange(p0, p1) }
}
override fun getNamedDescendantForPointRange(p0: TSPoint?, p1: TSPoint?): TSNode? {
return withLock { super.getNamedDescendantForPointRange(p0, p1) }
}
override fun isEqualTo(p0: TSNode?): Boolean {
return withLock { super.isEqualTo(p0) }
}
override fun getChildCount(): Int {
return withLock { super.getChildCount() }
}
override fun getNamedChildCount(): Int {
return withLock { super.getNamedChildCount() }
}
override fun getNodeString(): String {
return withLock { super.getNodeString() }
}
override fun getStartByte(): Int {
return withLock { super.getStartByte() }
}
override fun getEndByte(): Int {
return withLock { super.getEndByte() }
}
override fun getStartPoint(): TSPoint {
return withLock { super.getStartPoint() }
}
override fun getEndPoint(): TSPoint {
return withLock { super.getEndPoint() }
}
override fun getType(): String {
return withLock { super.getType() }
}
override fun getSymbol(): Int {
return withLock { super.getSymbol() }
}
override fun isNull(): Boolean {
return withLock { super.isNull() }
}
override fun isNamed(): Boolean {
return withLock { super.isNamed() }
}
override fun isExtra(): Boolean {
return withLock { super.isExtra() }
}
override fun isMissing(): Boolean {
return withLock { super.isMissing() }
}
override fun hasChanges(): Boolean {
return withLock { super.hasChanges() }
}
override fun hasErrors(): Boolean {
return withLock { super.hasErrors() }
}
override fun isError(): Boolean {
return withLock { super.isError() }
}
override fun getParseState(): Short {
return withLock { super.getParseState() }
}
override fun recycle() {
withLock {
this.context0 = 0
this.context1 = 0
this.context2 = 0
this.context3 = 0
this.id = 0
this.tree = 0
this.mTree = null
returnToPool()
}
}
}
@@ -0,0 +1,127 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSInputEdit
import com.itsaky.androidide.treesitter.TSLanguage
import com.itsaky.androidide.treesitter.TSLookaheadIterator
import com.itsaky.androidide.treesitter.TSNode
import com.itsaky.androidide.treesitter.TSParser
import com.itsaky.androidide.treesitter.TSPoint
import com.itsaky.androidide.treesitter.TSQuery
import com.itsaky.androidide.treesitter.TSQueryCapture
import com.itsaky.androidide.treesitter.TSQueryCursor
import com.itsaky.androidide.treesitter.TSQueryMatch
import com.itsaky.androidide.treesitter.TSQueryPredicateStep
import com.itsaky.androidide.treesitter.TSRange
import com.itsaky.androidide.treesitter.TSTree
import com.itsaky.androidide.treesitter.TSTreeCursor
import com.itsaky.androidide.treesitter.TSTreeCursorNode
import com.itsaky.androidide.treesitter.util.TSObjectFactory
/**
* [TSObjectFactory] implementation for AndroidIDE.
*
* @author Akash Yadav
*/
class TreeSitterObjectFactory : TSObjectFactory {
override fun createInputEdit(startByte: Int, oldEndByte: Int, newEndByte: Int,
startPoint: TSPoint?, oldEndPoint: TSPoint?, newEndPoint: TSPoint?): TSInputEdit {
return TreeSitterInputEdit.obtain(
startByte,
oldEndByte,
newEndByte,
startPoint,
oldEndPoint,
newEndPoint
)
}
override fun createParser(parserPointer: Long): TSParser {
return TreeSitterParser.obtain(parserPointer)
}
override fun createQuery(queryPointer: Long): TSQuery {
return TreeSitterQuery.obtain(queryPointer)
}
override fun createQueryCursor(pointer: Long): TSQueryCursor {
return TreeSitterQueryCursor.obtain(pointer)
}
override fun createPoint(row: Int, column: Int): TSPoint {
return TreeSitterPoint.obtain(row, column)
}
override fun createRange(startByte: Int, endByte: Int, startPoint: TSPoint,
endPoint: TSPoint?): TSRange {
return TreeSitterRange.obtain(startByte, endByte, startPoint, endPoint)
}
override fun createRangeArr(size: Int): Array<TSRange?> {
return arrayOfNulls(size)
}
override fun createTree(pointer: Long): TSTree {
return TreeSitterTree.obtain(pointer)
}
override fun createTreeCursor(pointer: Long): TSTreeCursor {
return TreeSitterTreeCursor.obtain(pointer)
}
override fun createNode(context0: Int, context1: Int, context2: Int, context3: Int, id: Long,
treePointer: Long): TSNode {
return TreeSitterNode.obtain(context0, context1, context2, context3, id, treePointer)
}
override fun createQueryCapture(node: TSNode?, index: Int): TSQueryCapture {
return TreeSitterQueryCapture.obtain(node, index)
}
override fun createQueryMatch(id: Int, patternIndex: Int,
captures: Array<TSQueryCapture?>?): TSQueryMatch {
return TreeSitterQueryMatch.obtain(id, patternIndex, captures)
}
override fun createQueryPredicateStep(type: Int, valueId: Int): TSQueryPredicateStep {
return TreeSitterQueryPredicateStep.obtain(type, valueId)
}
override fun createQueryPredicateStepArr(size: Int): Array<TSQueryPredicateStep?> {
return arrayOfNulls(size)
}
override fun createTreeCursorNode(
type: String?,
name: String?,
startByte: Int,
endByte: Int
): TSTreeCursorNode {
return TreeSitterTreeCursorNode.obtain(type, name, startByte, endByte)
}
override fun createLookaheadIterator(pointer: Long): TSLookaheadIterator {
return TreeSitterLookaheadIterator.obtain(pointer)
}
override fun createLanguage(name: String?, pointers: LongArray?): TSLanguage {
return TreeSitterNativeLanguage.obtain(name, pointers)
}
}
@@ -0,0 +1,90 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.utils.RecyclableObjectPool
import com.itsaky.androidide.utils.RecyclableObjectPool.Companion.CAPACITY_DEFAULT
import com.itsaky.androidide.utils.RecyclableObjectPool.Companion.CAPACITY_MINI
import com.itsaky.androidide.utils.newRecyclableObjectPool
import com.itsaky.androidide.utils.uncheckedCast
import java.util.concurrent.ConcurrentHashMap
/**
* Provides instances of [RecyclableObjectPool] for tree sitter objects.
*
* @author Akash Yadav
*/
internal object TreeSitterObjectPoolProvider {
private val caches = ConcurrentHashMap<Class<out RecyclableObjectPool.Recyclable>, RecyclableObjectPool<*>>()
init {
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterInputEdit)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterLookaheadIterator)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterNativeLanguage)
putPool(capacity = 1_00_000, fillFirst = 1000, factory = ::TreeSitterNode)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterParser)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterPoint)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterQuery)
putPool(capacity = 1_00_000, fillFirst = 1000, factory = ::TreeSitterQueryCapture)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterQueryCursor)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterQueryMatch)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterQueryPredicateStep)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterRange)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterTree)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterTreeCursor)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterTreeCursorNode)
}
fun logMetrics() {
caches.forEach { (_, pool) ->
pool.logMetrics()
}
}
inline fun <reified T : RecyclableObjectPool.Recyclable> getPool(): RecyclableObjectPool<T>? {
return getPool(T::class.java)
}
inline fun <reified T : RecyclableObjectPool.Recyclable> requirePool(): RecyclableObjectPool<T> {
return requireNotNull(getPool())
}
fun <T : RecyclableObjectPool.Recyclable> getPool(klass: Class<T>): RecyclableObjectPool<T>? {
return caches[klass]?.let { uncheckedCast(it) }
}
fun <T : RecyclableObjectPool.Recyclable> requirePool(klass: Class<T>): RecyclableObjectPool<T> {
return requireNotNull(getPool(klass))
}
private inline fun <reified T : RecyclableObjectPool.Recyclable> putPool(
capacity: Int = CAPACITY_DEFAULT,
fillFirst: Int = 0,
factory: RecyclableObjectPool.Factory<T>
) {
if (caches[T::class.java] != null) {
throw IllegalArgumentException("Attempt to replace object pool for ${T::class.java}")
}
// disable metrics logging for tree sitter objects
// this is required because the log views also use tree sitter to highlight the lines
// if we enable metrics, it would result in an infite loop and 'analyze and log' in some cases
caches[T::class.java] = newRecyclableObjectPool(capacity, fillFirst, false, factory)
}
}
@@ -0,0 +1,87 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSLanguage
import com.itsaky.androidide.treesitter.TSParser
import com.itsaky.androidide.treesitter.TSRange
import com.itsaky.androidide.treesitter.TSTree
import com.itsaky.androidide.treesitter.string.UTF16String
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterParser @JvmOverloads internal constructor(
pointer: Long = 0
) : TSParser(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable(),
TSSynchronized by DefaultSynchronized() {
companion object {
@JvmStatic
fun obtain(
pointer: Long
): TreeSitterParser {
return obtainFromPool<TreeSitterParser>().apply {
this.nativeObject = pointer
}
}
}
override fun close() {
withLock {
super.close()
recycle()
}
}
override fun setLanguage(language: TSLanguage?) {
withLock { super.setLanguage(language) }
}
override fun parseString(oldTree: TSTree?, source: UTF16String?): TSTree {
return withLock { super.parseString(oldTree, source) }
}
override fun setTimeout(microseconds: Long) {
withLock { super.setTimeout(microseconds) }
}
override fun getTimeout(): Long {
return withLock { super.getTimeout() }
}
override fun setIncludedRanges(ranges: Array<out TSRange>?): Boolean {
return withLock { super.setIncludedRanges(ranges) }
}
override fun getIncludedRanges(): Array<TSRange> {
return withLock { super.getIncludedRanges() }
}
override fun reset() {
withLock { super.reset() }
}
override fun recycle() {
this.nativeObject = 0
returnToPool()
}
}
@@ -0,0 +1,48 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSPoint
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterPoint @JvmOverloads internal constructor(
row: Int = 0,
column: Int = 0
) : TSPoint(row, column), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(row: Int, column: Int): TreeSitterPoint {
return obtainFromPool<TreeSitterPoint>().apply {
this.row = row
this.column = column
}
}
}
override fun recycle() {
this.row = 0
this.column = 0
returnToPool()
}
}
@@ -0,0 +1,106 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSQuantifier
import com.itsaky.androidide.treesitter.TSQuery
import com.itsaky.androidide.treesitter.TSQueryPredicateStep
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterQuery @JvmOverloads internal constructor(
pointer: Long = 0
) : TSQuery(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable(),
TSSynchronized by DefaultSynchronized() {
companion object {
@JvmStatic
fun obtain(pointer: Long): TreeSitterQuery {
return obtainFromPool<TreeSitterQuery>().apply {
this.nativeObject = pointer
}
}
}
override fun getCaptureCount(): Int {
return withLock { super.getCaptureCount() }
}
override fun getPatternCount(): Int {
return withLock { super.getPatternCount() }
}
override fun getStringCount(): Int {
return withLock { super.getStringCount() }
}
override fun getCaptureNames(): Array<String> {
return withLock { super.getCaptureNames() }
}
override fun getStartByteForPattern(pattern: Int): Int {
return withLock { super.getStartByteForPattern(pattern) }
}
override fun getPredicatesForPattern(pattern: Int): Array<TSQueryPredicateStep> {
return withLock { super.getPredicatesForPattern(pattern) }
}
override fun isPatternRooted(pattern: Int): Boolean {
return withLock { super.isPatternRooted(pattern) }
}
override fun isPatternNonLocal(pattern: Int): Boolean {
return withLock { super.isPatternNonLocal(pattern) }
}
override fun isPatternGuaranteedAtStep(offset: Int): Boolean {
return withLock { super.isPatternGuaranteedAtStep(offset) }
}
override fun getCaptureNameForId(id: Int): String {
return withLock { super.getCaptureNameForId(id) }
}
override fun getStringValueForId(id: Int): String {
return withLock { super.getStringValueForId(id) }
}
override fun getCaptureQuantifierForId(pattern: Int, capture: Int): TSQuantifier {
return withLock { super.getCaptureQuantifierForId(pattern, capture) }
}
override fun close() {
withLock {
super.close()
recycle()
}
}
override fun recycle() {
this.nativeObject = 0
this.captureNames = null
this.errorOffset = 0
this.errorType = 0
returnToPool()
}
}
@@ -0,0 +1,50 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSNode
import com.itsaky.androidide.treesitter.TSQueryCapture
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterQueryCapture @JvmOverloads internal constructor(
node: TSNode? = null,
index: Int = 0
) : TSQueryCapture(node, index), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(node: TSNode?, index: Int): TreeSitterQueryCapture {
return obtainFromPool<TreeSitterQueryCapture>().apply {
this.node = node
this.index = index
}
}
}
override fun recycle() {
(this.node as? TreeSitterNode?)?.recycle()
this.index = 0
this.node = null
returnToPool()
}
}
@@ -0,0 +1,89 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSNode
import com.itsaky.androidide.treesitter.TSPoint
import com.itsaky.androidide.treesitter.TSQuery
import com.itsaky.androidide.treesitter.TSQueryCursor
import com.itsaky.androidide.treesitter.TSQueryMatch
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterQueryCursor(
pointer: Long = 0
) : TSQueryCursor(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable(),
TSSynchronized by DefaultSynchronized() {
companion object {
@JvmStatic
fun obtain(pointer: Long): TreeSitterQueryCursor {
return obtainFromPool<TreeSitterQueryCursor>().apply {
this.nativeObject = pointer
}
}
}
override fun exec(query: TSQuery?, node: TSNode?) {
withLock { super.exec(query, node) }
}
override fun didExceedMatchLimit(): Boolean {
return withLock { super.didExceedMatchLimit() }
}
override fun getMatchLimit(): Int {
return withLock { super.getMatchLimit() }
}
override fun setMatchLimit(newLimit: Int) {
withLock { super.setMatchLimit(newLimit) }
}
override fun setByteRange(start: Int, end: Int) {
withLock { super.setByteRange(start, end) }
}
override fun setPointRange(start: TSPoint?, end: TSPoint?) {
withLock { super.setPointRange(start, end) }
}
override fun nextMatch(): TSQueryMatch? {
return withLock { super.nextMatch() }
}
override fun removeMatch(id: Int) {
withLock { super.removeMatch(id) }
}
override fun close() {
withLock {
super.close()
recycle()
}
}
override fun recycle() {
this.nativeObject = 0
returnToPool()
}
}
@@ -0,0 +1,54 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSQueryCapture
import com.itsaky.androidide.treesitter.TSQueryMatch
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterQueryMatch @JvmOverloads internal constructor(
id: Int = 0,
patternIndex: Int = 0,
captures: Array<out TSQueryCapture?>? = null
) : TSQueryMatch(id, patternIndex, captures),
RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(id: Int, patternIndex: Int,
captures: Array<out TSQueryCapture?>?): TreeSitterQueryMatch {
return obtainFromPool<TreeSitterQueryMatch>().apply {
this.id = id
this.patternIndex = patternIndex
this.captures = captures
}
}
}
override fun recycle() {
this.id = 0
this.patternIndex = 0
this.captures = null
returnToPool()
}
}
@@ -0,0 +1,49 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSQueryPredicateStep
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterQueryPredicateStep @JvmOverloads internal constructor(
type: Int = 0,
valueId: Int = 0
) : TSQueryPredicateStep(type, valueId), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(type: Int, valueId: Int): TreeSitterQueryPredicateStep {
return obtainFromPool<TreeSitterQueryPredicateStep>().apply {
this.type = type
this.valueId = valueId
}
}
}
override fun recycle() {
this.type = 0
this.valueId = 0
this.cachedType = null
returnToPool()
}
}
@@ -0,0 +1,60 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSPoint
import com.itsaky.androidide.treesitter.TSRange
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterRange @JvmOverloads internal constructor(
startByte: Int = 0,
endByte: Int = 0,
startPoint: TSPoint? = null,
endPoint: TSPoint? = null
) : TSRange(startByte, endByte, startPoint, endPoint),
RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(startByte: Int, endByte: Int, startPoint: TSPoint?,
endPoint: TSPoint?): TreeSitterRange {
return obtainFromPool<TreeSitterRange>().apply {
this.startByte = startByte
this.endByte = endByte
this.startPoint = startPoint
this.endPoint = endPoint
}
}
}
override fun recycle() {
(this.startPoint as? TreeSitterPoint?)?.recycle()
(this.endPoint as? TreeSitterPoint?)?.recycle()
this.startByte = 0
this.endByte = 0
this.startPoint = null
this.endPoint = null
returnToPool()
}
}
@@ -0,0 +1,94 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSInputEdit
import com.itsaky.androidide.treesitter.TSLanguage
import com.itsaky.androidide.treesitter.TSNode
import com.itsaky.androidide.treesitter.TSRange
import com.itsaky.androidide.treesitter.TSTree
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
import java.util.concurrent.TimeUnit
/**
* @author Akash Yadav
*/
class TreeSitterTree @JvmOverloads internal constructor(
pointer: Long = 0,
private val synchronized: DefaultSynchronized = DefaultSynchronized()
) : TSTree(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable(),
TSSynchronized by synchronized {
private var ownerThread: Thread? = null
companion object {
@JvmStatic
fun obtain(pointer: Long): TreeSitterTree {
return obtainFromPool<TreeSitterTree>().apply {
this.nativeObject = pointer
this.ownerThread = Thread.currentThread()
}
}
}
override fun getRootNode(): TSNode {
return withLock { super.getRootNode() }
}
override fun getChangedRanges(oldTree: TSTree?): Array<TSRange> {
return withLock { super.getChangedRanges(oldTree) }
}
override fun copy(): TSTree {
return withLock { super.copy() }
}
override fun edit(edit: TSInputEdit?) {
withLock { super.edit(edit) }
}
override fun getLanguage(): TSLanguage {
return withLock { super.getLanguage() }
}
override fun <T> withLock(timeout: Long, unit: TimeUnit, action: () -> T): T {
// check(ownerThread != null && Thread.currentThread() == ownerThread) {
// "TSTree instances are not thread-safe. Copy the tree if you need to use it on multiple threads." +
// "currentThread=${Thread.currentThread()} initialThread=$ownerThread"
// }
return synchronized.withLock(timeout, unit, action)
}
override fun close() {
withLock {
super.close()
this.nativeObject = 0
recycle()
}
}
override fun recycle() {
this.ownerThread = null
if (!canAccess()) {
returnToPool()
}
}
}
@@ -0,0 +1,128 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSNode
import com.itsaky.androidide.treesitter.TSPoint
import com.itsaky.androidide.treesitter.TSTreeCursor
import com.itsaky.androidide.treesitter.TSTreeCursorNode
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterTreeCursor @JvmOverloads internal constructor(
pointer: Long = 0
) : TSTreeCursor(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable(),
TSSynchronized by DefaultSynchronized() {
companion object {
@JvmStatic
fun obtain(pointer: Long): TreeSitterTreeCursor {
return obtainFromPool<TreeSitterTreeCursor>().apply {
this.nativeObject = pointer
}
}
}
override fun getCurrentNode(): TSNode {
return withLock { super.getCurrentNode() }
}
override fun getCurrentFieldName(): String {
return withLock { super.getCurrentFieldName() }
}
override fun getCurrentFieldId(): Short {
return withLock { super.getCurrentFieldId() }
}
override fun getCurrentTreeCursorNode(): TSTreeCursorNode {
return withLock { super.getCurrentTreeCursorNode() }
}
override fun gotoFirstChild(): Boolean {
return withLock { super.gotoFirstChild() }
}
override fun gotoFirstChildForByte(byteIndex: Int): Long {
return withLock { super.gotoFirstChildForByte(byteIndex) }
}
override fun gotoFirstChildForPoint(point: TSPoint?): Boolean {
return withLock { super.gotoFirstChildForPoint(point) }
}
override fun gotoLastChild(): Boolean {
return withLock { super.gotoLastChild() }
}
override fun gotoNextSibling(): Boolean {
return withLock { super.gotoNextSibling() }
}
override fun gotoPreviousSibling(): Boolean {
return withLock { super.gotoPreviousSibling() }
}
override fun gotoParent(): Boolean {
return withLock { super.gotoParent() }
}
override fun gotoDescendant(descendantIndex: Int) {
withLock { super.gotoDescendant(descendantIndex) }
}
override fun getCurrentDescendantIndex(): Int {
return withLock { super.getCurrentDescendantIndex() }
}
override fun getDepth(): Int {
return withLock { super.getDepth() }
}
override fun reset(node: TSNode?) {
withLock { super.reset(node) }
}
override fun resetTo(another: TSTreeCursor?) {
withLock { super.resetTo(another) }
}
override fun copy(): TSTreeCursor {
return withLock { super.copy() }
}
override fun close() {
withLock {
super.close()
recycle()
}
}
override fun recycle() {
this.nativeObject = 0
this.context0 = 0
this.context1 = 0
this.id = 0
this.tree = 0
returnToPool()
}
}
@@ -0,0 +1,56 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSTreeCursorNode
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterTreeCursorNode @JvmOverloads internal constructor(
type: String? = null,
name: String? = null,
startByte: Int = 0,
endByte: Int = 0
) : TSTreeCursorNode(type, name, startByte, endByte),
RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(type: String?, name: String?, startByte: Int,
endByte: Int): TreeSitterTreeCursorNode {
return obtainFromPool<TreeSitterTreeCursorNode>().apply {
this.type = type
this.name = name
this.startByte = startByte
this.endByte = endByte
}
}
}
override fun recycle() {
this.type = null
this.name = null
this.startByte = 0
this.endByte = 0
returnToPool()
}
}
@@ -0,0 +1,38 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* Returns this [RecyclableObjectPool.Recyclable] object to the pool from the [TreeSitterObjectPoolProvider].
*
* @see TreeSitterObjectPoolProvider.requirePool
*/
internal inline fun <reified T : RecyclableObjectPool.Recyclable> T.returnToPool() {
TreeSitterObjectPoolProvider.requirePool<T>().recycle(this)
}
/**
* Get an instance of [T] from the [RecyclableObjectPool] using [TreeSitterObjectPoolProvider].
*
* @see TreeSitterObjectPoolProvider.requirePool
*/
internal inline fun <reified T : RecyclableObjectPool.Recyclable> obtainFromPool(): T {
return TreeSitterObjectPoolProvider.requirePool<T>().obtain()
}