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; 019import java.io.OutputStream; 020import java.io.Serializable; 021import java.nio.charset.Charset; 022import javax.annotation.Nullable; 023 024/** 025 * Funnels for common types. All implementations are serializable. 026 * 027 * @author Dimitris Andreou 028 * @since 11.0 029 */ 030@Beta 031public final class Funnels { 032 private Funnels() {} 033 034 /** 035 * Returns a funnel that extracts the bytes from a {@code byte} array. 036 */ 037 public static Funnel<byte[]> byteArrayFunnel() { 038 return ByteArrayFunnel.INSTANCE; 039 } 040 041 private enum ByteArrayFunnel implements Funnel<byte[]> { 042 INSTANCE; 043 044 public void funnel(byte[] from, PrimitiveSink into) { 045 into.putBytes(from); 046 } 047 048 @Override 049 public String toString() { 050 return "Funnels.byteArrayFunnel()"; 051 } 052 } 053 054 /** 055 * Returns a funnel that extracts the characters from a {@code CharSequence}, a character at a 056 * time, without performing any encoding. If you need to use a specific encoding, use 057 * {@link Funnels#stringFunnel(Charset)} instead. 058 * 059 * @since 15.0 (since 11.0 as {@code Funnels.stringFunnel()}. 060 */ 061 public static Funnel<CharSequence> unencodedCharsFunnel() { 062 return UnencodedCharsFunnel.INSTANCE; 063 } 064 065 private enum UnencodedCharsFunnel implements Funnel<CharSequence> { 066 INSTANCE; 067 068 public void funnel(CharSequence from, PrimitiveSink into) { 069 into.putUnencodedChars(from); 070 } 071 072 @Override 073 public String toString() { 074 return "Funnels.unencodedCharsFunnel()"; 075 } 076 } 077 078 /** 079 * Returns a funnel that encodes the characters of a {@code CharSequence} with the specified 080 * {@code Charset}. 081 * 082 * @since 15.0 083 */ 084 public static Funnel<CharSequence> stringFunnel(Charset charset) { 085 return new StringCharsetFunnel(charset); 086 } 087 088 private static class StringCharsetFunnel implements Funnel<CharSequence>, Serializable { 089 private final Charset charset; 090 091 StringCharsetFunnel(Charset charset) { 092 this.charset = Preconditions.checkNotNull(charset); 093 } 094 095 public void funnel(CharSequence from, PrimitiveSink into) { 096 into.putString(from, charset); 097 } 098 099 @Override 100 public String toString() { 101 return "Funnels.stringFunnel(" + charset.name() + ")"; 102 } 103 104 @Override 105 public boolean equals(@Nullable Object o) { 106 if (o instanceof StringCharsetFunnel) { 107 StringCharsetFunnel funnel = (StringCharsetFunnel) o; 108 return this.charset.equals(funnel.charset); 109 } 110 return false; 111 } 112 113 @Override 114 public int hashCode() { 115 return StringCharsetFunnel.class.hashCode() ^ charset.hashCode(); 116 } 117 118 Object writeReplace() { 119 return new SerializedForm(charset); 120 } 121 122 private static class SerializedForm implements Serializable { 123 private final String charsetCanonicalName; 124 125 SerializedForm(Charset charset) { 126 this.charsetCanonicalName = charset.name(); 127 } 128 129 private Object readResolve() { 130 return stringFunnel(Charset.forName(charsetCanonicalName)); 131 } 132 133 private static final long serialVersionUID = 0; 134 } 135 } 136 137 /** 138 * Returns a funnel for integers. 139 * 140 * @since 13.0 141 */ 142 public static Funnel<Integer> integerFunnel() { 143 return IntegerFunnel.INSTANCE; 144 } 145 146 private enum IntegerFunnel implements Funnel<Integer> { 147 INSTANCE; 148 149 public void funnel(Integer from, PrimitiveSink into) { 150 into.putInt(from); 151 } 152 153 @Override 154 public String toString() { 155 return "Funnels.integerFunnel()"; 156 } 157 } 158 159 /** 160 * Returns a funnel that processes an {@code Iterable} by funneling its elements in iteration 161 * order with the specified funnel. No separators are added between the elements. 162 * 163 * @since 15.0 164 */ 165 public static <E> Funnel<Iterable<? extends E>> sequentialFunnel(Funnel<E> elementFunnel) { 166 return new SequentialFunnel<E>(elementFunnel); 167 } 168 169 private static class SequentialFunnel<E> implements Funnel<Iterable<? extends E>>, Serializable { 170 private final Funnel<E> elementFunnel; 171 172 SequentialFunnel(Funnel<E> elementFunnel) { 173 this.elementFunnel = Preconditions.checkNotNull(elementFunnel); 174 } 175 176 public void funnel(Iterable<? extends E> from, PrimitiveSink into) { 177 for (E e : from) { 178 elementFunnel.funnel(e, into); 179 } 180 } 181 182 @Override 183 public String toString() { 184 return "Funnels.sequentialFunnel(" + elementFunnel + ")"; 185 } 186 187 @Override 188 public boolean equals(@Nullable Object o) { 189 if (o instanceof SequentialFunnel) { 190 SequentialFunnel<?> funnel = (SequentialFunnel<?>) o; 191 return elementFunnel.equals(funnel.elementFunnel); 192 } 193 return false; 194 } 195 196 @Override 197 public int hashCode() { 198 return SequentialFunnel.class.hashCode() ^ elementFunnel.hashCode(); 199 } 200 } 201 202 /** 203 * Returns a funnel for longs. 204 * 205 * @since 13.0 206 */ 207 public static Funnel<Long> longFunnel() { 208 return LongFunnel.INSTANCE; 209 } 210 211 private enum LongFunnel implements Funnel<Long> { 212 INSTANCE; 213 214 public void funnel(Long from, PrimitiveSink into) { 215 into.putLong(from); 216 } 217 218 @Override 219 public String toString() { 220 return "Funnels.longFunnel()"; 221 } 222 } 223 224 /** 225 * Wraps a {@code PrimitiveSink} as an {@link OutputStream}, so it is easy to {@link Funnel#funnel 226 * funnel} an object to a {@code PrimitiveSink} if there is already a way to write the contents of 227 * the object to an {@code OutputStream}. 228 * 229 * <p>The {@code close} and {@code flush} methods of the returned {@code OutputStream} do nothing, 230 * and no method throws {@code IOException}. 231 * 232 * @since 13.0 233 */ 234 public static OutputStream asOutputStream(PrimitiveSink sink) { 235 return new SinkAsStream(sink); 236 } 237 238 private static class SinkAsStream extends OutputStream { 239 final PrimitiveSink sink; 240 241 SinkAsStream(PrimitiveSink sink) { 242 this.sink = Preconditions.checkNotNull(sink); 243 } 244 245 @Override 246 public void write(int b) { 247 sink.putByte((byte) b); 248 } 249 250 @Override 251 public void write(byte[] bytes) { 252 sink.putBytes(bytes); 253 } 254 255 @Override 256 public void write(byte[] bytes, int off, int len) { 257 sink.putBytes(bytes, off, len); 258 } 259 260 @Override 261 public String toString() { 262 return "Funnels.asOutputStream(" + sink + ")"; 263 } 264 } 265}