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