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