001/* 002 * Copyright (C) 2011 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.hash; 016 017import com.google.common.annotations.Beta; 018import com.google.common.base.Preconditions; 019 020import java.io.OutputStream; 021import java.io.Serializable; 022import java.nio.charset.Charset; 023 024import javax.annotation.CheckReturnValue; 025import javax.annotation.Nullable; 026 027/** 028 * Funnels for common types. All implementations are serializable. 029 * 030 * @author Dimitris Andreou 031 * @since 11.0 032 */ 033@Beta 034@CheckReturnValue 035public final class Funnels { 036 private Funnels() {} 037 038 /** 039 * Returns a funnel that extracts the bytes from a {@code byte} array. 040 */ 041 public static Funnel<byte[]> byteArrayFunnel() { 042 return ByteArrayFunnel.INSTANCE; 043 } 044 045 private enum ByteArrayFunnel implements Funnel<byte[]> { 046 INSTANCE; 047 048 public void funnel(byte[] from, PrimitiveSink into) { 049 into.putBytes(from); 050 } 051 052 @Override 053 public String toString() { 054 return "Funnels.byteArrayFunnel()"; 055 } 056 } 057 058 /** 059 * Returns a funnel that extracts the characters from a {@code CharSequence}, a character at a 060 * time, without performing any encoding. If you need to use a specific encoding, use 061 * {@link Funnels#stringFunnel(Charset)} instead. 062 * 063 * @since 15.0 (since 11.0 as {@code Funnels.stringFunnel()}. 064 */ 065 public static Funnel<CharSequence> unencodedCharsFunnel() { 066 return UnencodedCharsFunnel.INSTANCE; 067 } 068 069 private enum UnencodedCharsFunnel implements Funnel<CharSequence> { 070 INSTANCE; 071 072 public void funnel(CharSequence from, PrimitiveSink into) { 073 into.putUnencodedChars(from); 074 } 075 076 @Override 077 public String toString() { 078 return "Funnels.unencodedCharsFunnel()"; 079 } 080 } 081 082 /** 083 * Returns a funnel that encodes the characters of a {@code CharSequence} with the specified 084 * {@code Charset}. 085 * 086 * @since 15.0 087 */ 088 public static Funnel<CharSequence> stringFunnel(Charset charset) { 089 return new StringCharsetFunnel(charset); 090 } 091 092 private static class StringCharsetFunnel implements Funnel<CharSequence>, Serializable { 093 private final Charset charset; 094 095 StringCharsetFunnel(Charset charset) { 096 this.charset = Preconditions.checkNotNull(charset); 097 } 098 099 public void funnel(CharSequence from, PrimitiveSink into) { 100 into.putString(from, charset); 101 } 102 103 @Override 104 public String toString() { 105 return "Funnels.stringFunnel(" + charset.name() + ")"; 106 } 107 108 @Override 109 public boolean equals(@Nullable Object o) { 110 if (o instanceof StringCharsetFunnel) { 111 StringCharsetFunnel funnel = (StringCharsetFunnel) o; 112 return this.charset.equals(funnel.charset); 113 } 114 return false; 115 } 116 117 @Override 118 public int hashCode() { 119 return StringCharsetFunnel.class.hashCode() ^ charset.hashCode(); 120 } 121 122 Object writeReplace() { 123 return new SerializedForm(charset); 124 } 125 126 private static class SerializedForm implements Serializable { 127 private final String charsetCanonicalName; 128 129 SerializedForm(Charset charset) { 130 this.charsetCanonicalName = charset.name(); 131 } 132 133 private Object readResolve() { 134 return stringFunnel(Charset.forName(charsetCanonicalName)); 135 } 136 137 private static final long serialVersionUID = 0; 138 } 139 } 140 141 /** 142 * Returns a funnel for integers. 143 * 144 * @since 13.0 145 */ 146 public static Funnel<Integer> integerFunnel() { 147 return IntegerFunnel.INSTANCE; 148 } 149 150 private enum IntegerFunnel implements Funnel<Integer> { 151 INSTANCE; 152 153 public void funnel(Integer from, PrimitiveSink into) { 154 into.putInt(from); 155 } 156 157 @Override 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 */ 169 public static <E> Funnel<Iterable<? extends E>> sequentialFunnel(Funnel<E> elementFunnel) { 170 return new SequentialFunnel<E>(elementFunnel); 171 } 172 173 private static class SequentialFunnel<E> implements Funnel<Iterable<? extends E>>, Serializable { 174 private final Funnel<E> elementFunnel; 175 176 SequentialFunnel(Funnel<E> elementFunnel) { 177 this.elementFunnel = Preconditions.checkNotNull(elementFunnel); 178 } 179 180 public void funnel(Iterable<? extends E> from, PrimitiveSink into) { 181 for (E e : from) { 182 elementFunnel.funnel(e, into); 183 } 184 } 185 186 @Override 187 public String toString() { 188 return "Funnels.sequentialFunnel(" + elementFunnel + ")"; 189 } 190 191 @Override 192 public boolean equals(@Nullable Object o) { 193 if (o instanceof SequentialFunnel) { 194 SequentialFunnel<?> funnel = (SequentialFunnel<?>) o; 195 return elementFunnel.equals(funnel.elementFunnel); 196 } 197 return false; 198 } 199 200 @Override 201 public int hashCode() { 202 return SequentialFunnel.class.hashCode() ^ elementFunnel.hashCode(); 203 } 204 } 205 206 /** 207 * Returns a funnel for longs. 208 * 209 * @since 13.0 210 */ 211 public static Funnel<Long> longFunnel() { 212 return LongFunnel.INSTANCE; 213 } 214 215 private enum LongFunnel implements Funnel<Long> { 216 INSTANCE; 217 218 public void funnel(Long from, PrimitiveSink into) { 219 into.putLong(from); 220 } 221 222 @Override 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 230 * {@link Funnel#funnel funnel} an object to a {@code PrimitiveSink} 231 * if there is already a way to write the contents of the object to an {@code OutputStream}. 232 * 233 * <p>The {@code close} and {@code flush} methods of the returned {@code OutputStream} 234 * do nothing, and no method throws {@code IOException}. 235 * 236 * @since 13.0 237 */ 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 245 SinkAsStream(PrimitiveSink sink) { 246 this.sink = Preconditions.checkNotNull(sink); 247 } 248 249 @Override 250 public void write(int b) { 251 sink.putByte((byte) b); 252 } 253 254 @Override 255 public void write(byte[] bytes) { 256 sink.putBytes(bytes); 257 } 258 259 @Override 260 public void write(byte[] bytes, int off, int len) { 261 sink.putBytes(bytes, off, len); 262 } 263 264 @Override 265 public String toString() { 266 return "Funnels.asOutputStream(" + sink + ")"; 267 } 268 } 269}