1 /*
2  * Copyright (C) 2020 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 com.android.server.soundtrigger_middleware;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 
22 import java.lang.reflect.Array;
23 import java.util.Collection;
24 import java.util.Map;
25 
26 /**
27  * A collection of pretty-print utilities for data objects.
28  */
29 class ObjectPrinter {
30     /** Default maximum elements to print in a collection. */
31     static public final int kDefaultMaxCollectionLength = 16;
32 
33     /**
34      * Pretty-prints an object.
35      *
36      * @param obj                 The object to print.
37      * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
38      *                            print.
39      * @return A string representing the object.
40      */
print(@ullable Object obj, int maxCollectionLength)41     static String print(@Nullable Object obj, int maxCollectionLength) {
42         StringBuilder builder = new StringBuilder();
43         print(builder, obj, maxCollectionLength);
44         return builder.toString();
45     }
46 
47     /**
48      * Same as {@link #print(StringBuilder, Object, int)} with default max length.
49      *
50      * @param builder             StringBuilder to print into.
51      * @param obj                 The object to print.
52      */
print(@onNull StringBuilder builder, @Nullable Object obj)53     static void print(@NonNull StringBuilder builder, @Nullable Object obj) {
54         print(builder, obj, kDefaultMaxCollectionLength);
55     }
56 
57     /**
58      * A version of {@link #print(Object, int)} that uses a {@link StringBuilder}.
59      *
60      * @param builder             StringBuilder to print into.
61      * @param obj                 The object to print.
62      * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
63      *                            print.
64      */
print(@onNull StringBuilder builder, @Nullable Object obj, int maxCollectionLength)65     static void print(@NonNull StringBuilder builder, @Nullable Object obj,
66             int maxCollectionLength) {
67         try {
68             if (obj == null) {
69                 builder.append("null");
70                 return;
71             }
72             if (obj instanceof Boolean) {
73                 builder.append(obj);
74                 return;
75             }
76             if (obj instanceof Number) {
77                 builder.append(obj);
78                 return;
79             }
80             if (obj instanceof Character) {
81                 builder.append('\'');
82                 builder.append(obj);
83                 builder.append('\'');
84                 return;
85             }
86             if (obj instanceof String) {
87                 builder.append('"');
88                 builder.append(obj.toString());
89                 builder.append('"');
90                 return;
91             }
92 
93             Class cls = obj.getClass();
94 
95             if (Collection.class.isAssignableFrom(cls)) {
96                 Collection collection = (Collection) obj;
97                 builder.append("[ ");
98                 int length = collection.size();
99                 boolean isLong = false;
100                 int i = 0;
101                 for (Object child : collection) {
102                     if (i > 0) {
103                         builder.append(", ");
104                     }
105                     if (i >= maxCollectionLength) {
106                         isLong = true;
107                         break;
108                     }
109                     print(builder, child, maxCollectionLength);
110                     ++i;
111                 }
112                 if (isLong) {
113                     builder.append("... (+");
114                     builder.append(length - maxCollectionLength);
115                     builder.append(" entries)");
116                 }
117                 builder.append(" ]");
118                 return;
119             }
120 
121             if (Map.class.isAssignableFrom(cls)) {
122                 Map<?, ?> map = (Map<?, ?>) obj;
123                 builder.append("< ");
124                 int length = map.size();
125                 boolean isLong = false;
126                 int i = 0;
127                 for (Map.Entry<?, ?> child : map.entrySet()) {
128                     if (i > 0) {
129                         builder.append(", ");
130                     }
131                     if (i >= maxCollectionLength) {
132                         isLong = true;
133                         break;
134                     }
135                     print(builder, child.getKey(), maxCollectionLength);
136                     builder.append(": ");
137                     print(builder, child.getValue(), maxCollectionLength);
138                     ++i;
139                 }
140                 if (isLong) {
141                     builder.append("... (+");
142                     builder.append(length - maxCollectionLength);
143                     builder.append(" entries)");
144                 }
145                 builder.append(" >");
146                 return;
147             }
148 
149             if (cls.isArray()) {
150                 builder.append("[ ");
151                 int length = Array.getLength(obj);
152                 boolean isLong = false;
153                 for (int i = 0; i < length; ++i) {
154                     if (i > 0) {
155                         builder.append(", ");
156                     }
157                     if (i >= maxCollectionLength) {
158                         isLong = true;
159                         break;
160                     }
161                     print(builder, Array.get(obj, i), maxCollectionLength);
162                 }
163                 if (isLong) {
164                     builder.append("... (+");
165                     builder.append(length - maxCollectionLength);
166                     builder.append(" entries)");
167                 }
168                 builder.append(" ]");
169                 return;
170             }
171 
172             builder.append(obj);
173         } catch (Exception e) {
174             throw new RuntimeException(e);
175         }
176     }
177 }
178