1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 package org.apache.thrift;
19 
20 import java.io.Serializable;
21 import java.nio.ByteBuffer;
22 import java.util.Comparator;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.SortedMap;
28 import java.util.TreeMap;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.Collections;
33 
34 public final class TBaseHelper {
35 
TBaseHelper()36   private TBaseHelper(){}
37 
38   private static final Comparator comparator = new NestedStructureComparator();
39 
compareTo(Object o1, Object o2)40   public static int compareTo(Object o1, Object o2) {
41     if (o1 instanceof Comparable) {
42       return compareTo((Comparable)o1, (Comparable)o2);
43     } else if (o1 instanceof List) {
44       return compareTo((List)o1, (List)o2);
45     } else if (o1 instanceof Set) {
46       return compareTo((Set)o1, (Set)o2);
47     } else if (o1 instanceof Map) {
48       return compareTo((Map)o1, (Map)o2);
49     } else if (o1 instanceof byte[]) {
50       return compareTo((byte[])o1, (byte[])o2);
51     } else {
52       throw new IllegalArgumentException("Cannot compare objects of type " + o1.getClass());
53     }
54   }
55 
compareTo(boolean a, boolean b)56   public static int compareTo(boolean a, boolean b) {
57     return Boolean.compare(a, b);
58   }
59 
compareTo(byte a, byte b)60   public static int compareTo(byte a, byte b) {
61     return Byte.compare(a, b);
62   }
63 
compareTo(short a, short b)64   public static int compareTo(short a, short b) {
65     return Short.compare(a,b);
66   }
67 
compareTo(int a, int b)68   public static int compareTo(int a, int b) {
69     return Integer.compare(a, b);
70   }
71 
compareTo(long a, long b)72   public static int compareTo(long a, long b) {
73     return Long.compare(a, b);
74   }
75 
compareTo(double a, double b)76   public static int compareTo(double a, double b) {
77     return Double.compare(a, b);
78   }
79 
compareTo(String a, String b)80   public static int compareTo(String a, String b) {
81     return a.compareTo(b);
82   }
83 
compareTo(byte[] a, byte[] b)84   public static int compareTo(byte[] a, byte[] b) {
85     int compare = compareTo(a.length, b.length);
86     if (compare == 0) {
87       for (int i = 0; i < a.length; i++) {
88         compare = compareTo(a[i], b[i]);
89         if (compare != 0) {
90           break;
91         }
92       }
93     }
94     return compare;
95   }
96 
compareTo(Comparable a, Comparable b)97   public static int compareTo(Comparable a, Comparable b) {
98     return a.compareTo(b);
99   }
100 
compareTo(List a, List b)101   public static int compareTo(List a, List b) {
102     int compare = compareTo(a.size(), b.size());
103     if (compare == 0) {
104       for (int i = 0; i < a.size(); i++) {
105         compare = comparator.compare(a.get(i), b.get(i));
106         if (compare != 0) {
107           break;
108         }
109       }
110     }
111     return compare;
112   }
113 
compareTo(Set a, Set b)114   public static int compareTo(Set a, Set b) {
115     int compare = compareTo(a.size(), b.size());
116     if (compare == 0) {
117       ArrayList sortedA = new ArrayList(a);
118       ArrayList sortedB = new ArrayList(b);
119 
120       Collections.sort(sortedA, comparator);
121       Collections.sort(sortedB, comparator);
122 
123       Iterator iterA = sortedA.iterator();
124       Iterator iterB = sortedB.iterator();
125 
126       // Compare each item.
127       while (iterA.hasNext() && iterB.hasNext()) {
128         compare = comparator.compare(iterA.next(), iterB.next());
129         if (compare != 0) {
130           break;
131         }
132       }
133     }
134     return compare;
135   }
136 
compareTo(Map a, Map b)137   public static int compareTo(Map a, Map b) {
138     int lastComparison = compareTo(a.size(), b.size());
139     if (lastComparison != 0) {
140       return lastComparison;
141     }
142 
143     // Sort a and b so we can compare them.
144     SortedMap sortedA = new TreeMap(comparator);
145     sortedA.putAll(a);
146     Iterator<Map.Entry> iterA = sortedA.entrySet().iterator();
147     SortedMap sortedB = new TreeMap(comparator);
148     sortedB.putAll(b);
149     Iterator<Map.Entry> iterB = sortedB.entrySet().iterator();
150 
151     // Compare each item.
152     while (iterA.hasNext() && iterB.hasNext()) {
153       Map.Entry entryA = iterA.next();
154       Map.Entry entryB = iterB.next();
155       lastComparison = comparator.compare(entryA.getKey(), entryB.getKey());
156       if (lastComparison != 0) {
157         return lastComparison;
158       }
159       lastComparison = comparator.compare(entryA.getValue(), entryB.getValue());
160       if (lastComparison != 0) {
161         return lastComparison;
162       }
163     }
164 
165     return 0;
166   }
167 
168   /**
169    * Comparator to compare items inside a structure (e.g. a list, set, or map).
170    */
171   private static class NestedStructureComparator implements Comparator, Serializable {
compare(Object oA, Object oB)172     public int compare(Object oA, Object oB) {
173       if (oA == null && oB == null) {
174         return 0;
175       } else if (oA == null) {
176         return -1;
177       } else if (oB == null) {
178         return 1;
179       } else if (oA instanceof List) {
180         return compareTo((List)oA, (List)oB);
181       } else if (oA instanceof Set) {
182         return compareTo((Set)oA, (Set)oB);
183       } else if (oA instanceof Map) {
184         return compareTo((Map)oA, (Map)oB);
185       } else if (oA instanceof byte[]) {
186         return compareTo((byte[])oA, (byte[])oB);
187       } else {
188         return compareTo((Comparable)oA, (Comparable)oB);
189       }
190     }
191   }
192 
toString(Collection<ByteBuffer> bbs, StringBuilder sb)193   public static void toString(Collection<ByteBuffer> bbs, StringBuilder sb) {
194     Iterator<ByteBuffer> it = bbs.iterator();
195     if (!it.hasNext()) {
196       sb.append("[]");
197     } else {
198       sb.append("[");
199       while (true) {
200         ByteBuffer bb = it.next();
201         org.apache.thrift.TBaseHelper.toString(bb, sb);
202         if (!it.hasNext()) {
203           sb.append("]");
204           return;
205         } else {
206           sb.append(", ");
207         }
208       }
209     }
210   }
211 
toString(ByteBuffer bb, StringBuilder sb)212   public static void toString(ByteBuffer bb, StringBuilder sb) {
213     byte[] buf = bb.array();
214 
215     int arrayOffset = bb.arrayOffset();
216     int offset = arrayOffset + bb.position();
217     int origLimit = arrayOffset + bb.limit();
218     int limit = (origLimit - offset > 128) ? offset + 128 : origLimit;
219 
220     for (int i = offset; i < limit; i++) {
221       if (i > offset) {
222         sb.append(" ");
223       }
224       sb.append(paddedByteString(buf[i]));
225     }
226     if (origLimit != limit) {
227       sb.append("...");
228     }
229   }
230 
paddedByteString(byte b)231   public static String paddedByteString(byte b) {
232     int extended = (b | 0x100) & 0x1ff;
233     return Integer.toHexString(extended).toUpperCase().substring(1);
234   }
235 
byteBufferToByteArray(ByteBuffer byteBuffer)236   public static byte[] byteBufferToByteArray(ByteBuffer byteBuffer) {
237     if (wrapsFullArray(byteBuffer)) {
238       return byteBuffer.array();
239     }
240     byte[] target = new byte[byteBuffer.remaining()];
241     byteBufferToByteArray(byteBuffer, target, 0);
242     return target;
243   }
244 
wrapsFullArray(ByteBuffer byteBuffer)245   public static boolean wrapsFullArray(ByteBuffer byteBuffer) {
246     return byteBuffer.hasArray()
247       && byteBuffer.position() == 0
248       && byteBuffer.arrayOffset() == 0
249       && byteBuffer.remaining() == byteBuffer.capacity();
250   }
251 
byteBufferToByteArray(ByteBuffer byteBuffer, byte[] target, int offset)252   public static int byteBufferToByteArray(ByteBuffer byteBuffer, byte[] target, int offset) {
253     int remaining = byteBuffer.remaining();
254     System.arraycopy(byteBuffer.array(),
255         byteBuffer.arrayOffset() + byteBuffer.position(),
256         target,
257         offset,
258         remaining);
259     return remaining;
260   }
261 
rightSize(ByteBuffer in)262   public static ByteBuffer rightSize(ByteBuffer in) {
263     if (in == null) {
264       return null;
265     }
266     if (wrapsFullArray(in)) {
267       return in;
268     }
269     return ByteBuffer.wrap(byteBufferToByteArray(in));
270   }
271 
copyBinary(final ByteBuffer orig)272   public static ByteBuffer copyBinary(final ByteBuffer orig) {
273     if (orig == null) {
274       return null;
275     }
276     ByteBuffer copy = ByteBuffer.wrap(new byte[orig.remaining()]);
277     if (orig.hasArray()) {
278       System.arraycopy(orig.array(), orig.arrayOffset() + orig.position(), copy.array(), 0, orig.remaining());
279     } else {
280       orig.slice().get(copy.array());
281     }
282 
283     return copy;
284   }
285 
copyBinary(final byte[] orig)286   public static byte[] copyBinary(final byte[] orig) {
287     return (orig == null) ? null : Arrays.copyOf(orig, orig.length);
288   }
289 
hashCode(long value)290   public static int hashCode(long value) {
291     return Long.hashCode(value);
292   }
293 
hashCode(double value)294   public static int hashCode(double value) {
295     return Double.hashCode(value);
296   }
297 }
298