blob: 4721508fa5a2feeb22b3b4a21cd42d51c3c59792 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tools.idea.editors.gfxtrace.schema;
import com.android.tools.rpclib.binary.Decoder;
import com.android.tools.idea.editors.gfxtrace.rpc.AtomInfo;
import com.android.tools.idea.editors.gfxtrace.rpc.AtomStream;
import com.android.tools.idea.editors.gfxtrace.rpc.ParameterInfo;
import com.android.tools.idea.editors.gfxtrace.rpc.Schema;
import gnu.trove.TIntIntHashMap;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* A random-access reader of {@link Atom}s.
* </p>
* The {@link AtomReader} holds the entire collection of atoms in binary
* packed form, and to reduce memory overhead, only unpacks these to Java
* structures on {@link #read}.
*/
public class AtomReader {
private final Schema mSchema;
private final byte[] mData;
private final List<Segment> mAtomSegments;
private final TIntIntHashMap atomTypeToIndex;
public AtomReader(AtomStream stream, Schema schema) throws IOException {
mSchema = schema;
mData = stream.getData();
mAtomSegments = new ArrayList<Segment>();
atomTypeToIndex = new TIntIntHashMap(schema.getAtoms().length);
AtomInfo[] atomInfos = schema.getAtoms();
for (int i = 0; i < atomInfos.length; ++i) {
assert !atomTypeToIndex.containsValue(i); // Make sure there are no duplicates.
atomTypeToIndex.put(atomInfos[i].getType(), i);
}
calculateAtomInfos();
}
/**
* @return the number of atoms in the collection.
*/
public int count() {
return mAtomSegments.size();
}
private Atom unpack(Decoder decoder) throws IOException {
short type = decoder.uint16();
int contextId = decoder.int32();
assert (contextId >= 0); // Sanity check.
if (!atomTypeToIndex.containsKey(type)) {
throw new RuntimeException("Atom type " + type + " not found in schema.");
}
AtomInfo atomInfo = mSchema.getAtoms()[atomTypeToIndex.get(type)];
Parameter[] parameters = new Parameter[atomInfo.getParameters().length];
for (int i = 0; i < parameters.length; i++) {
ParameterInfo parameterInfo = atomInfo.getParameters()[i];
Object value = Unpack.Type(atomInfo.getParameters()[i].getType(), decoder);
parameters[i] = new Parameter(parameterInfo, value);
}
return new Atom(contextId, atomInfo, parameters);
}
/**
* Unpack and return a single atom with the specified index.
*
* @param index the index of the atom.
* @return the unpacked atom structure.
*/
public Atom read(long index) throws IOException {
assert (index <= Integer.MAX_VALUE);
Segment segment = mAtomSegments.get((int)index);
ByteArrayInputStream stream = new ByteArrayInputStream(mData, segment.mOffset, segment.mSize);
Decoder decoder = new Decoder(stream);
return unpack(decoder);
}
private void calculateAtomInfos() throws IOException {
ByteArrayInputStream stream = new ByteArrayInputStream(mData);
Decoder decoder = new Decoder(stream);
int total = stream.available();
long count = decoder.uint32();
for (int i = 0; i < count; i++) {
int remains = stream.available();
int offset = total - remains;
unpack(decoder);
int size = remains - stream.available();
mAtomSegments.add(new Segment(offset, size));
}
}
private static class Segment {
private final int mOffset;
private final int mSize;
private Segment(int offset, int size) {
mOffset = offset;
mSize = size;
}
}
}