`KotlinLocalVirtualFile`: decrease the complexity of `findChild` from O(log(N)) to O(1) by using map instead of binary search

According to the IntelliJ performance profile, the compiler spends around 1% of time on `binarySearchBy`
diff --git a/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/common/localfs/KotlinLocalVirtualFile.kt b/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/common/localfs/KotlinLocalVirtualFile.kt
index d4da433..193ad18 100644
--- a/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/common/localfs/KotlinLocalVirtualFile.kt
+++ b/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/common/localfs/KotlinLocalVirtualFile.kt
@@ -22,7 +22,12 @@
     private var _name: String? = null
     private var _parent: KotlinLocalVirtualFile? = parent
 
-    private var _children: Array<VirtualFile>? = null
+    private val _children: Pair<Array<KotlinLocalVirtualFile>, Map<String, KotlinLocalVirtualFile>> by lazy(LazyThreadSafetyMode.PUBLICATION) {
+        val fileChildren = file.listFiles() ?: emptyArray()
+        val array = fileChildren.map { KotlinLocalVirtualFile(it, _fileSystem, parent = this) }.toTypedArray()
+        val map = array.associateBy { it.name }
+        array to map
+    }
 
     private var _isDirectory: Boolean = file.isDirectory
     private val _timeStamp = file.lastModified()
@@ -60,46 +65,9 @@
         }
     }
 
-    override fun getChildren(): Array<VirtualFile> {
-        _children?.let { return it }
-        val fileChildren = file.listFiles() ?: emptyArray()
+    override fun getChildren(): Array<KotlinLocalVirtualFile> = _children.first
 
-        _children = fileChildren
-            .map { KotlinLocalVirtualFile(it, _fileSystem, parent = this) }
-            .sortedBy { it.name }
-            .toTypedArray<VirtualFile>()
-
-        return _children!!
-    }
-
-    override fun findChild(name: String): VirtualFile? = children.binarySearchBy(name) { it.name }
-
-    /**
-     * The implementation is copied from [List.binarySearch] and changed to fit our needs.
-     *
-     * We cannot use [binarySearchBy][kotlin.collections.binarySearchBy] here because we need to search in an array. And we cannot use
-     * [Arrays.binarySearch][java.util.Arrays.binarySearch] because it doesn't support searching by a key instead of the whole element.
-     */
-    private inline fun <T, K : Comparable<K>> Array<T>.binarySearchBy(key: K, selector: (T) -> K): T? {
-        var low = 0
-        var high = size - 1
-
-        while (low <= high) {
-            val mid = (low + high).ushr(1) // safe from overflows
-            val midVal = get(mid)
-            val cmp = compareValues(selector(midVal), key)
-
-            if (cmp < 0) {
-                low = mid + 1
-            } else if (cmp > 0) {
-                high = mid - 1
-            } else {
-                return midVal
-            }
-        }
-
-        return null
-    }
+    override fun findChild(name: String): VirtualFile? = _children.second[name]
 
     override fun getOutputStream(requestor: Any?, newModificationStamp: Long, newTimeStamp: Long): OutputStream {
         shouldNotBeCalled()