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.Nullable; 025 026/** 027 * Funnels for common types. All implementations are serializable. 028 * 029 * @author Dimitris Andreou 030 * @since 11.0 031 */ 032@Beta 033public final class Funnels { 034 private Funnels() {} 035 036 /** 037 * Returns a funnel that extracts the bytes from a {@code byte} array. 038 */ 039 public static Funnel<byte[]> byteArrayFunnel() { 040 return ByteArrayFunnel.INSTANCE; 041 } 042 043 private enum ByteArrayFunnel implements Funnel<byte[]> { 044 INSTANCE; 045 046 public void funnel(byte[] from, PrimitiveSink into) { 047 into.putBytes(from); 048 } 049 050 @Override public String toString() { 051 return "Funnels.byteArrayFunnel()"; 052 } 053 } 054 055 /** 056 * Returns a funnel that extracts the characters from a {@code CharSequence}, a character at a 057 * time, without performing any encoding. If you need to use a specific encoding, use 058 * {@link Funnels#stringFunnel(Charset)} instead. 059 * 060 * @since 15.0 (since 11.0 as {@code Funnels.stringFunnel()}. 061 */ 062 public static Funnel<CharSequence> unencodedCharsFunnel() { 063 return UnencodedCharsFunnel.INSTANCE; 064 } 065 066 private enum UnencodedCharsFunnel implements Funnel<CharSequence> { 067 INSTANCE; 068 069 public void funnel(CharSequence from, PrimitiveSink into) { 070 into.putUnencodedChars(from); 071 } 072 073 @Override 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 public String toString() { 100 return "Funnels.stringFunnel(" + charset.name() + ")"; 101 } 102 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 111 @Override public int hashCode() { 112 return StringCharsetFunnel.class.hashCode() ^ charset.hashCode(); 113 } 114 115 Object writeReplace() { 116 return new SerializedForm(charset); 117 } 118 119 private static class SerializedForm implements Serializable { 120 private final String charsetCanonicalName; 121 122 SerializedForm(Charset charset) { 123 this.charsetCanonicalName = charset.name(); 124 } 125 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 */ 139 public static Funnel<Integer> integerFunnel() { 140 return IntegerFunnel.INSTANCE; 141 } 142 143 private enum IntegerFunnel implements Funnel<Integer> { 144 INSTANCE; 145 146 public void funnel(Integer from, PrimitiveSink into) { 147 into.putInt(from); 148 } 149 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 */ 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 168 SequentialFunnel(Funnel<E> elementFunnel) { 169 this.elementFunnel = Preconditions.checkNotNull(elementFunnel); 170 } 171 172 public void funnel(Iterable<? extends E> from, PrimitiveSink into) { 173 for (E e : from) { 174 elementFunnel.funnel(e, into); 175 } 176 } 177 178 @Override public String toString() { 179 return "Funnels.sequentialFunnel(" + elementFunnel + ")"; 180 } 181 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 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 */ 200 public static Funnel<Long> longFunnel() { 201 return LongFunnel.INSTANCE; 202 } 203 204 private enum LongFunnel implements Funnel<Long> { 205 INSTANCE; 206 207 public void funnel(Long from, PrimitiveSink into) { 208 into.putLong(from); 209 } 210 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 */ 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; 232 SinkAsStream(PrimitiveSink sink) { 233 this.sink = Preconditions.checkNotNull(sink); 234 } 235 236 @Override public void write(int b) { 237 sink.putByte((byte) b); 238 } 239 240 @Override public void write(byte[] bytes) { 241 sink.putBytes(bytes); 242 } 243 244 @Override public void write(byte[] bytes, int off, int len) { 245 sink.putBytes(bytes, off, len); 246 } 247 248 @Override public String toString() { 249 return "Funnels.asOutputStream(" + sink + ")"; 250 } 251 } 252}