1 /*
2 * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3 */
4
5 package kotlinx.serialization.json.internal
6
7 import kotlinx.serialization.descriptors.*
8 import kotlin.native.concurrent.*
9
10 private typealias DescriptorData<T> = MutableMap<DescriptorSchemaCache.Key<T>, T>
11
12 /**
13 * A type-safe map for storing custom information (such as format schema), associated with [SerialDescriptor].
14 *
15 * This cache uses ConcurrentHashMap on JVM and regular maps on other platforms.
16 * To be able to work with it from multiple threads in Kotlin/Native, use @[ThreadLocal] in appropriate places.
17 */
18 internal class DescriptorSchemaCache {
19 // 16 is default CHM size, as we do not know number of descriptors in an application (but it's likely not 1)
20 private val map: MutableMap<SerialDescriptor, DescriptorData<Any>> = createMapForCache(16)
21
22 @Suppress("UNCHECKED_CAST")
setnull23 public operator fun <T : Any> set(descriptor: SerialDescriptor, key: Key<T>, value: T) {
24 // Initial capacity = number of known DescriptorSchemaCache.Key instances
25 map.getOrPut(descriptor, { createMapForCache(2) })[key as Key<Any>] = value as Any
26 }
27
getOrPutnull28 public fun <T : Any> getOrPut(descriptor: SerialDescriptor, key: Key<T>, defaultValue: () -> T): T {
29 get(descriptor, key)?.let { return it }
30 val value = defaultValue()
31 set(descriptor, key, value)
32 return value
33 }
34
35 @Suppress("UNCHECKED_CAST")
getnull36 public operator fun <T : Any> get(descriptor: SerialDescriptor, key: Key<T>): T? {
37 return map[descriptor]?.get(key as Key<Any>) as? T
38 }
39
40 /**
41 * A key for associating user data of type [T] with a given [SerialDescriptor].
42 */
43 public class Key<T : Any> {}
44 }
45
46
47 /**
48 * Creates a ConcurrentHashMap on JVM and regular HashMap on other platforms.
49 * To make actual use of cache in Kotlin/Native, mark a top-level object with this map
50 * as a @[ThreadLocal].
51 */
createMapForCachenull52 internal expect fun <K, V> createMapForCache(initialCapacity: Int): MutableMap<K, V>
53