001 /* 002 * Copyright (c) 2007-2014 Concurrent, Inc. All Rights Reserved. 003 * 004 * Project and contact information: http://www.cascading.org/ 005 * 006 * This file is part of the Cascading project. 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020 021 package cascading.tuple.util; 022 023 import java.util.Comparator; 024 import java.util.List; 025 026 import cascading.flow.stream.MemorySpliceGate; 027 import cascading.tuple.Fields; 028 import cascading.tuple.Hasher; 029 import cascading.tuple.Tuple; 030 import org.slf4j.Logger; 031 import org.slf4j.LoggerFactory; 032 033 /** 034 * 035 */ 036 public class TupleHasher 037 { 038 private static final Logger LOG = LoggerFactory.getLogger( MemorySpliceGate.class ); 039 040 private static Hasher DEFAULT = new ObjectHasher(); 041 private Hasher[] hashers; 042 043 public TupleHasher() 044 { 045 } 046 047 public TupleHasher( Comparator defaultComparator, Comparator[] comparators ) 048 { 049 initialize( defaultComparator, comparators ); 050 } 051 052 public static Comparator[] merge( Fields[] keyFields ) 053 { 054 Comparator[] comparators = new Comparator[ keyFields[ 0 ].size() ]; 055 056 for( Fields keyField : keyFields ) 057 { 058 if( keyField == null ) 059 continue; 060 061 for( int i = 0; i < keyField.getComparators().length; i++ ) 062 { 063 Comparator comparator = keyField.getComparators()[ i ]; 064 065 if( !( comparator instanceof Hasher ) ) 066 continue; 067 068 if( comparators[ i ] != null && !comparators[ i ].equals( comparator ) ) 069 LOG.warn( "two unequal Hasher instances for the same key field position found: {}, and: {}", comparators[ i ], comparator ); 070 071 comparators[ i ] = comparator; 072 } 073 } 074 075 return comparators; 076 } 077 078 public static boolean isNull( Comparator[] comparators ) 079 { 080 int count = 0; 081 082 for( Comparator comparator : comparators ) 083 { 084 if( comparator == null ) 085 count++; 086 } 087 088 if( count == comparators.length ) 089 return true; 090 091 return false; 092 } 093 094 protected void initialize( Comparator defaultComparator, Comparator[] comparators ) 095 { 096 Hasher defaultHasher = DEFAULT; 097 098 if( defaultComparator instanceof Hasher ) 099 defaultHasher = (Hasher) defaultComparator; 100 101 hashers = new Hasher[ comparators.length ]; 102 103 for( int i = 0; i < comparators.length; i++ ) 104 { 105 Comparator comparator = comparators[ i ]; 106 107 if( comparator instanceof Hasher ) 108 hashers[ i ] = (Hasher) comparator; 109 else 110 hashers[ i ] = defaultHasher; 111 } 112 } 113 114 public final int hashCode( Tuple tuple ) 115 { 116 int hash = 1; 117 118 List<Object> elements = Tuple.elements( tuple ); 119 120 for( int i = 0; i < elements.size(); i++ ) 121 { 122 Object element = elements.get( i ); 123 124 hash = 31 * hash + ( element != null ? hashers[ i % hashers.length ].hashCode( element ) : 0 ); 125 } 126 127 return hash; 128 } 129 130 private static class ObjectHasher implements Hasher<Object> 131 { 132 @Override 133 public int hashCode( Object value ) 134 { 135 return value.hashCode(); 136 } 137 } 138 }