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 25 doDecodeByteArraynull26 protected abstract fun doDecodeByteArray(bytes: ByteArray): InputTypeTrace 27 28 protected abstract fun doParse(input: InputTypeTrace): OutputTypeTrace 29 30 /** 31 * Uses a [ByteArray] to generates a trace 32 * 33 * @param bytes Parsed proto data 34 * @param clearCache If the caching used while parsing the object should be cleared 35 */ 36 open fun parse(bytes: ByteArray, clearCache: Boolean = true): OutputTypeTrace { 37 val input = decodeByteArray(bytes) 38 return parse(input, clearCache) 39 } 40 41 /** 42 * Uses [InputTypeTrace] to generates a trace 43 * 44 * @param input Parsed proto data 45 * @param clearCache If the caching used while parsing the object should be cleared 46 */ parsenull47 open fun parse(input: InputTypeTrace, clearCache: Boolean = true): OutputTypeTrace { 48 return try { 49 doParse(input) 50 } finally { 51 if (clearCache) { 52 Cache.clear() 53 } 54 } 55 } 56 decodeByteArraynull57 protected fun decodeByteArray(input: ByteArray): InputTypeTrace { 58 return doDecodeByteArray(input) 59 } 60 getTimestampsInRangenull61 fun getTimestampsInRange( 62 entries: List<Timestamp>, 63 from: Timestamp, 64 to: Timestamp, 65 addInitialEntry: Boolean, 66 ): Set<Timestamp> { 67 require(from <= to) { "`from` must be smaller or equal to `to` but was $from and $to" } 68 69 return when { 70 entries.isEmpty() -> { 71 emptySet() 72 } 73 to < entries.first() -> { 74 // Slice before all entries 75 emptySet() 76 } 77 entries.last() < from -> { 78 // Slice after all entries 79 if (addInitialEntry) { 80 // Keep the last entry as the start entry of the sliced trace 81 setOf(entries.last()) 82 } else { 83 emptySet() 84 } 85 } 86 else -> { 87 // first entry <= to 88 // last entry >= from 89 // -----|--------|------ 90 // [ to to 91 // from from ] 92 93 var first = entries.indexOfFirst { it >= from } 94 require(first >= 0) { "No match found for first index" } 95 val last = entries.lastIndex - entries.reversed().indexOfFirst { it <= to } 96 require(last >= 0) { "No match found for last index" } 97 98 if (addInitialEntry && first > 0 && entries[first] > from) { 99 // Include previous state since from timestamp is in between the previous 100 // one and first, and the previous state is the state we were still at a 101 // timestamp from. 102 first-- 103 } 104 105 entries.slice(first..last).toSet() 106 } 107 } 108 } 109 } 110