001package com.hammurapi.extract; 002 003import java.lang.reflect.Array; 004import java.util.Arrays; 005import java.util.HashSet; 006import java.util.Map; 007import java.util.Set; 008import java.util.TreeSet; 009 010/** 011 * Extractor which maps arguments to the target extractor. 012 * @author Pavel Vlasov 013 * 014 * @param <T> 015 * @param <V> 016 * @param <C> 017 */ 018public class MappedExtractor<T, V, C> implements FacadeExtractor<T, V, C>, Mappable<T,V,C> { 019 020 private Extractor<T, V, C> target; 021 private int[] map; 022 private TreeSet<Integer> parameterIndices; 023 024 /** 025 * @param target Target extractor 026 * @param map Index map, e.g. if it is {5, 3} then the first argument 027 * of this extractor becomes the sixth argument of the target extractor 028 * and the second argument of this extractor becomes the 4th argument 029 * of the target extractor. 030 */ 031 protected MappedExtractor(Extractor<T, V, C> target, int[] map) { 032 super(); 033 this.target = target; 034 this.map = map; 035 036 parameterIndices = new TreeSet<Integer>(); 037 038 Set<Integer> tpIdx = target.parameterIndices(); 039 for (int i=0; i<map.length; ++i) { 040 if (tpIdx.contains(map[i])) { 041 parameterIndices.add(i); 042 } 043 } 044 } 045 046 @Override 047 public V extract(C context, Map<C, Map<Extractor<T, ? super V, C>, ? super V>> cache, T... obj) { 048 int maxTargetIndex = -1; 049 for (Integer tIdx: target.parameterIndices()) { 050 if (tIdx>maxTargetIndex) { 051 maxTargetIndex=tIdx; 052 } 053 } 054 055 @SuppressWarnings("unchecked") 056 T[] tObj = (T[]) Array.newInstance(obj.getClass().getComponentType(), maxTargetIndex+1); 057 for (int i=0; i<map.length; ++i) { 058 if (parameterIndices.contains(i)) { 059 tObj[map[i]] = obj[i]; 060 } 061 } 062 063 return target.extract(context, cache, tObj); 064 } 065 066 @Override 067 public Set<Integer> parameterIndices() { 068 return parameterIndices; 069 } 070 071 @Override 072 public boolean isContextDependent() { 073 return target.isContextDependent(); 074 } 075 076 @Override 077 public ComparisonResult compareTo(Extractor<T, V, C> other) { 078 ComparisonResult tcr = target.compareTo(other); 079 if (tcr==null) { 080 return null; 081 } 082 if (tcr.isOneToOneMapping()) { 083 // Inverse mapping. 084 int dim = -1; 085 for (int i=0; i<map.length; ++i) { 086 if (parameterIndices.contains(i) && map[i]>dim) { 087 dim = map[i]; 088 } 089 } 090 int[] rmap = new int[dim+1]; 091 Arrays.fill(rmap, -1); 092 for (int i=0; i<map.length; ++i) { 093 if (parameterIndices.contains(i)) { 094 rmap[map[i]] = i; 095 } 096 } 097 return new ComparisonResult(tcr.getType(), rmap); 098 } 099 100 int[] tcrim = tcr.getIndexMap(); 101 int[] cmap = new int[map.length]; 102 Arrays.fill(cmap, -1); 103 for (int i=0; i<map.length; ++i) { 104 if (parameterIndices.contains(i)) { 105 if (tcrim.length>map[i]) { 106 cmap[i] = tcrim[map[i]]; 107 } else { 108 return null; 109 } 110 } 111 } 112 return new ComparisonResult(tcr.getType(), cmap); 113 } 114 115 @Override 116 public String toString() { 117 return "MappedExtractor [target=" + target + ", map=" 118 + Arrays.toString(map) + "]"; 119 } 120 121 @Override 122 public double getCost() { 123 return target.getCost(); 124 } 125 126 127 public static <T,V,C> Extractor<T,V,C> mapExtractor(Extractor<T,V,C> target, int[] map) { 128 if (ComparisonResult.isOneToOneMapping(map)) { 129 return target; 130 } 131 132 // Target is not index-dependent (e.g. constant). 133 if (target.parameterIndices().isEmpty()) { 134 return target; 135 } 136 if (target instanceof Mappable) { 137 @SuppressWarnings("unchecked") 138 Extractor<T, V, C> ret = ((Mappable<T,V,C>) target).map(map); 139 if (ret!=null) { 140 return ret; 141 } 142 } 143 144 return new MappedExtractor<T, V, C>(target, map); 145 } 146 147 @SuppressWarnings("unchecked") 148 @Override 149 public Extractor<T, V, C> map(int[] map) { 150 if (ComparisonResult.isOneToOneMapping(map)) { 151 return this; 152 } 153 154 int[] newMap = new int[map.length]; 155 Arrays.fill(newMap, -1); 156 157 Set<Integer> pi = new HashSet<Integer>(parameterIndices); 158 159 for (int i=0; i<newMap.length; ++i) { 160 if (map[i]!=-1) { 161 if (pi.remove(map[i])) { 162 newMap[i]=this.map[map[i]]; 163 } 164 } 165 } 166 167 if (!pi.isEmpty()) { // Not all indexes were mapped. 168 return null; 169 } 170 171 if (ComparisonResult.isOneToOneMapping(newMap)) { 172 return target; 173 } 174 175 if (this instanceof MappedPredicate) { 176 return (Extractor<T, V, C>) new MappedPredicate<T, C>((Predicate<T, C>) target, newMap); 177 } 178 return new MappedExtractor<T, V, C>(target, newMap); 179 } 180 181 public Extractor<T, V, C> getTarget() { 182 return target; 183 } 184 185 public int[] getMap() { 186 return map; 187 } 188}