• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.common.hash;
16 
17 import com.google.common.annotations.Beta;
18 import com.google.common.base.Preconditions;
19 import java.io.InvalidObjectException;
20 import java.io.ObjectInputStream;
21 import java.io.OutputStream;
22 import java.io.Serializable;
23 import java.nio.charset.Charset;
24 import javax.annotation.CheckForNull;
25 import org.checkerframework.checker.nullness.qual.Nullable;
26 
27 /**
28  * Funnels for common types. All implementations are serializable.
29  *
30  * @author Dimitris Andreou
31  * @since 11.0
32  */
33 @Beta
34 @ElementTypesAreNonnullByDefault
35 public final class Funnels {
Funnels()36   private Funnels() {}
37 
38   /** Returns a funnel that extracts the bytes from a {@code byte} array. */
byteArrayFunnel()39   public static Funnel<byte[]> byteArrayFunnel() {
40     return ByteArrayFunnel.INSTANCE;
41   }
42 
43   private enum ByteArrayFunnel implements Funnel<byte[]> {
44     INSTANCE;
45 
46     @Override
funnel(byte[] from, PrimitiveSink into)47     public void funnel(byte[] from, PrimitiveSink into) {
48       into.putBytes(from);
49     }
50 
51     @Override
toString()52     public String toString() {
53       return "Funnels.byteArrayFunnel()";
54     }
55   }
56 
57   /**
58    * Returns a funnel that extracts the characters from a {@code CharSequence}, a character at a
59    * time, without performing any encoding. If you need to use a specific encoding, use {@link
60    * Funnels#stringFunnel(Charset)} instead.
61    *
62    * @since 15.0 (since 11.0 as {@code Funnels.stringFunnel()}.
63    */
unencodedCharsFunnel()64   public static Funnel<CharSequence> unencodedCharsFunnel() {
65     return UnencodedCharsFunnel.INSTANCE;
66   }
67 
68   private enum UnencodedCharsFunnel implements Funnel<CharSequence> {
69     INSTANCE;
70 
71     @Override
funnel(CharSequence from, PrimitiveSink into)72     public void funnel(CharSequence from, PrimitiveSink into) {
73       into.putUnencodedChars(from);
74     }
75 
76     @Override
toString()77     public String toString() {
78       return "Funnels.unencodedCharsFunnel()";
79     }
80   }
81 
82   /**
83    * Returns a funnel that encodes the characters of a {@code CharSequence} with the specified
84    * {@code Charset}.
85    *
86    * @since 15.0
87    */
stringFunnel(Charset charset)88   public static Funnel<CharSequence> stringFunnel(Charset charset) {
89     return new StringCharsetFunnel(charset);
90   }
91 
92   private static class StringCharsetFunnel implements Funnel<CharSequence>, Serializable {
93     private final Charset charset;
94 
StringCharsetFunnel(Charset charset)95     StringCharsetFunnel(Charset charset) {
96       this.charset = Preconditions.checkNotNull(charset);
97     }
98 
99     @Override
funnel(CharSequence from, PrimitiveSink into)100     public void funnel(CharSequence from, PrimitiveSink into) {
101       into.putString(from, charset);
102     }
103 
104     @Override
toString()105     public String toString() {
106       return "Funnels.stringFunnel(" + charset.name() + ")";
107     }
108 
109     @Override
equals(@heckForNull Object o)110     public boolean equals(@CheckForNull Object o) {
111       if (o instanceof StringCharsetFunnel) {
112         StringCharsetFunnel funnel = (StringCharsetFunnel) o;
113         return this.charset.equals(funnel.charset);
114       }
115       return false;
116     }
117 
118     @Override
hashCode()119     public int hashCode() {
120       return StringCharsetFunnel.class.hashCode() ^ charset.hashCode();
121     }
122 
writeReplace()123     Object writeReplace() {
124       return new SerializedForm(charset);
125     }
126 
readObject(ObjectInputStream stream)127     private void readObject(ObjectInputStream stream) throws InvalidObjectException {
128       throw new InvalidObjectException("Use SerializedForm");
129     }
130 
131     private static class SerializedForm implements Serializable {
132       private final String charsetCanonicalName;
133 
SerializedForm(Charset charset)134       SerializedForm(Charset charset) {
135         this.charsetCanonicalName = charset.name();
136       }
137 
readResolve()138       private Object readResolve() {
139         return stringFunnel(Charset.forName(charsetCanonicalName));
140       }
141 
142       private static final long serialVersionUID = 0;
143     }
144   }
145 
146   /**
147    * Returns a funnel for integers.
148    *
149    * @since 13.0
150    */
integerFunnel()151   public static Funnel<Integer> integerFunnel() {
152     return IntegerFunnel.INSTANCE;
153   }
154 
155   private enum IntegerFunnel implements Funnel<Integer> {
156     INSTANCE;
157 
158     @Override
funnel(Integer from, PrimitiveSink into)159     public void funnel(Integer from, PrimitiveSink into) {
160       into.putInt(from);
161     }
162 
163     @Override
toString()164     public String toString() {
165       return "Funnels.integerFunnel()";
166     }
167   }
168 
169   /**
170    * Returns a funnel that processes an {@code Iterable} by funneling its elements in iteration
171    * order with the specified funnel. No separators are added between the elements.
172    *
173    * @since 15.0
174    */
sequentialFunnel( Funnel<E> elementFunnel)175   public static <E extends @Nullable Object> Funnel<Iterable<? extends E>> sequentialFunnel(
176       Funnel<E> elementFunnel) {
177     return new SequentialFunnel<>(elementFunnel);
178   }
179 
180   private static class SequentialFunnel<E extends @Nullable Object>
181       implements Funnel<Iterable<? extends E>>, Serializable {
182     private final Funnel<E> elementFunnel;
183 
SequentialFunnel(Funnel<E> elementFunnel)184     SequentialFunnel(Funnel<E> elementFunnel) {
185       this.elementFunnel = Preconditions.checkNotNull(elementFunnel);
186     }
187 
188     @Override
funnel(Iterable<? extends E> from, PrimitiveSink into)189     public void funnel(Iterable<? extends E> from, PrimitiveSink into) {
190       for (E e : from) {
191         elementFunnel.funnel(e, into);
192       }
193     }
194 
195     @Override
toString()196     public String toString() {
197       return "Funnels.sequentialFunnel(" + elementFunnel + ")";
198     }
199 
200     @Override
equals(@heckForNull Object o)201     public boolean equals(@CheckForNull Object o) {
202       if (o instanceof SequentialFunnel) {
203         SequentialFunnel<?> funnel = (SequentialFunnel<?>) o;
204         return elementFunnel.equals(funnel.elementFunnel);
205       }
206       return false;
207     }
208 
209     @Override
hashCode()210     public int hashCode() {
211       return SequentialFunnel.class.hashCode() ^ elementFunnel.hashCode();
212     }
213   }
214 
215   /**
216    * Returns a funnel for longs.
217    *
218    * @since 13.0
219    */
longFunnel()220   public static Funnel<Long> longFunnel() {
221     return LongFunnel.INSTANCE;
222   }
223 
224   private enum LongFunnel implements Funnel<Long> {
225     INSTANCE;
226 
227     @Override
funnel(Long from, PrimitiveSink into)228     public void funnel(Long from, PrimitiveSink into) {
229       into.putLong(from);
230     }
231 
232     @Override
toString()233     public String toString() {
234       return "Funnels.longFunnel()";
235     }
236   }
237 
238   /**
239    * Wraps a {@code PrimitiveSink} as an {@link OutputStream}, so it is easy to {@link Funnel#funnel
240    * funnel} an object to a {@code PrimitiveSink} if there is already a way to write the contents of
241    * the object to an {@code OutputStream}.
242    *
243    * <p>The {@code close} and {@code flush} methods of the returned {@code OutputStream} do nothing,
244    * and no method throws {@code IOException}.
245    *
246    * @since 13.0
247    */
asOutputStream(PrimitiveSink sink)248   public static OutputStream asOutputStream(PrimitiveSink sink) {
249     return new SinkAsStream(sink);
250   }
251 
252   private static class SinkAsStream extends OutputStream {
253     final PrimitiveSink sink;
254 
SinkAsStream(PrimitiveSink sink)255     SinkAsStream(PrimitiveSink sink) {
256       this.sink = Preconditions.checkNotNull(sink);
257     }
258 
259     @Override
write(int b)260     public void write(int b) {
261       sink.putByte((byte) b);
262     }
263 
264     @Override
write(byte[] bytes)265     public void write(byte[] bytes) {
266       sink.putBytes(bytes);
267     }
268 
269     @Override
write(byte[] bytes, int off, int len)270     public void write(byte[] bytes, int off, int len) {
271       sink.putBytes(bytes, off, len);
272     }
273 
274     @Override
toString()275     public String toString() {
276       return "Funnels.asOutputStream(" + sink + ")";
277     }
278   }
279 }
280