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