1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.dex.file;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.AnnotatedOutput;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Collection;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.HashMap;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.TreeMap;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Statistics about the contents of a file.
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic final class Statistics {
2899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} data about each type of item */
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final HashMap<String, Data> dataMap;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance.
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public Statistics() {
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dataMap = new HashMap<String, Data>(50);
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Adds the given item to the statistics.
40de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
4199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param item {@code non-null;} the item to add
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void add(Item item) {
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String typeName = item.typeName();
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Data data = dataMap.get(typeName);
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (data == null) {
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dataMap.put(typeName, new Data(item, typeName));
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            data.add(item);
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Adds the given list of items to the statistics.
56de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
5799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param list {@code non-null;} the list of items to add
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void addAll(Section list) {
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Collection<? extends Item> items = list.items();
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (Item item : items) {
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            add(item);
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Writes the statistics as an annotation.
68de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
6999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param out {@code non-null;} where to write to
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public final void writeAnnotation(AnnotatedOutput out) {
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dataMap.size() == 0) {
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.annotate(0, "\nstatistics:\n");
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (Data data : dataMap.values()) {
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sortedData.put(data.name, data);
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (Data data : sortedData.values()) {
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            data.writeAnnotation(out);
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public String toHuman() {
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StringBuilder sb = new StringBuilder();
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sb.append("Statistics:\n");
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (Data data : dataMap.values()) {
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sortedData.put(data.name, data);
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (Data data : sortedData.values()) {
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sb.append(data.toHuman());
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return sb.toString();
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Statistical data about a particular class.
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static class Data {
11199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code non-null;} name to use as a label */
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private final String name;
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
11499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code >= 0;} number of instances */
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int count;
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
11799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code >= 0;} total size of instances in bytes */
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int totalSize;
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
12099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code >= 0;} largest size of any individual item */
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int largestSize;
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
12399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code >= 0;} smallest size of any individual item */
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int smallestSize;
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Constructs an instance for the given item.
128de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro         *
12999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param item {@code non-null;} item in question
13099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param name {@code non-null;} type name to use
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public Data(Item item, String name) {
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int size = item.writeSize();
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.name = name;
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.count = 1;
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.totalSize = size;
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.largestSize = size;
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.smallestSize = size;
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Incorporates a new item. This assumes the type name matches.
144de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro         *
14599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param item {@code non-null;} item to incorporate
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public void add(Item item) {
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int size = item.writeSize();
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            count++;
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            totalSize += size;
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (size > largestSize) {
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                largestSize = size;
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (size < smallestSize) {
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                smallestSize = size;
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Writes this instance as an annotation.
164de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro         *
16599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param out {@code non-null;} where to write to
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public void writeAnnotation(AnnotatedOutput out) {
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            out.annotate(toHuman());
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Generates a human-readable string for this data item.
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @return string for human consumption.
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String toHuman() {
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            StringBuilder sb = new StringBuilder();
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sb.append("  " + name + ": " +
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                         count + " item" + (count == 1 ? "" : "s") + "; " +
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                         totalSize + " bytes total\n");
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (smallestSize == largestSize) {
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                sb.append("    " + smallestSize + " bytes/item\n");
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int average = totalSize / count;
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                sb.append("    " + smallestSize + ".." + largestSize +
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                             " bytes/item; average " + average + "\n");
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return sb.toString();
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
195