1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.tools.parsers 18 19 import android.tools.Cache 20 import android.tools.Timestamp 21 22 /** Base parser class */ 23 abstract class AbstractParser<InputTypeTrace, OutputTypeTrace> { 24 protected abstract val traceName: String doDecodeByteArraynull25 protected abstract fun doDecodeByteArray(bytes: ByteArray): InputTypeTrace 26 protected abstract fun doParse(input: InputTypeTrace): OutputTypeTrace 27 28 /** 29 * Uses a [ByteArray] to generates a trace 30 * 31 * @param bytes Parsed proto data 32 * @param clearCache If the caching used while parsing the object should be cleared 33 */ 34 open fun parse(bytes: ByteArray, clearCache: Boolean = true): OutputTypeTrace { 35 val input = decodeByteArray(bytes) 36 return parse(input, clearCache) 37 } 38 39 /** 40 * Uses [InputTypeTrace] to generates a trace 41 * 42 * @param input Parsed proto data 43 * @param clearCache If the caching used while parsing the object should be cleared 44 */ parsenull45 open fun parse(input: InputTypeTrace, clearCache: Boolean = true): OutputTypeTrace { 46 return try { 47 doParse(input) 48 } finally { 49 if (clearCache) { 50 Cache.clear() 51 } 52 } 53 } 54 decodeByteArraynull55 protected fun decodeByteArray(input: ByteArray): InputTypeTrace { 56 return doDecodeByteArray(input) 57 } 58 getTimestampsInRangenull59 fun getTimestampsInRange( 60 entries: List<Timestamp>, 61 from: Timestamp, 62 to: Timestamp, 63 addInitialEntry: Boolean 64 ): Set<Timestamp> { 65 require(from <= to) { "`from` must be smaller or equal to `to` but was $from and $to" } 66 67 return when { 68 entries.isEmpty() -> { 69 emptySet() 70 } 71 to < entries.first() -> { 72 // Slice before all entries 73 emptySet() 74 } 75 entries.last() < from -> { 76 // Slice after all entries 77 if (addInitialEntry) { 78 // Keep the last entry as the start entry of the sliced trace 79 setOf(entries.last()) 80 } else { 81 emptySet() 82 } 83 } 84 else -> { 85 // first entry <= to 86 // last entry >= from 87 // -----|--------|------ 88 // [ to to 89 // from from ] 90 91 var first = entries.indexOfFirst { it >= from } 92 require(first >= 0) { "No match found for first index" } 93 val last = entries.lastIndex - entries.reversed().indexOfFirst { it <= to } 94 require(last >= 0) { "No match found for last index" } 95 96 if (addInitialEntry && first > 0 && entries[first] > from) { 97 // Include previous state since from timestamp is in between the previous 98 // one and first, and the previous state is the state we were still at a 99 // timestamp from. 100 first-- 101 } 102 103 entries.slice(first..last).toSet() 104 } 105 } 106 } 107 } 108