001package com.hammurapi.extract; 002 003import java.io.Serializable; 004import java.util.ArrayList; 005import java.util.Collections; 006import java.util.List; 007import java.util.Map; 008import java.util.Set; 009import java.util.TreeSet; 010import java.util.concurrent.TimeUnit; 011 012 013/** 014 * Non-commutative AND. 015 * @author Pavel Vlasov. 016 * 017 * @param <T> 018 */ 019public class And<T, C> extends ExtractorBase<T, Boolean, C> implements CompositePredicate<T, List<Predicate<T, C>>, C, And<T,C>>, Serializable, Cloneable { 020 021 private List<Predicate<T, C>> parts = new ArrayList<Predicate<T, C>>(); 022 023 public And(double initialCost, TimeUnit costUnit) { 024 super(initialCost, costUnit); 025 } 026 027 public And(double initialCost, TimeUnit costUnit, Predicate<T,C>... parts) { 028 super(initialCost, costUnit); 029 for (Predicate<T,C> part: parts) { 030 addPart(part); 031 } 032 } 033 034 public And(double initialCost, TimeUnit costUnit, Iterable<Predicate<T,C>> parts) { 035 super(initialCost, costUnit); 036 for (Predicate<T,C> part: parts) { 037 addPart(part); 038 } 039 } 040 041 private void addPart(Predicate<T, C> part) { 042 if (part instanceof And) { 043 for (Predicate<T, C> pp: ((And<T, C>) part).getParts()) { 044 addPart(pp); 045 } 046 } else { 047 parts.add(part); 048 } 049 } 050 051 public List<Predicate<T, C>> getParts() { 052 return Collections.unmodifiableList(parts); 053 } 054 055 @Override 056 @SuppressWarnings("unchecked") 057 public ComparisonResult compareTo(Extractor<T, Boolean, C> otherPredicate) { 058 if (getParts().isEmpty()) { 059 return True.getInstance().compareTo((Extractor<Object, Boolean, Object>) otherPredicate); 060 } 061 062 if (otherPredicate instanceof And && parts.equals(((And) otherPredicate).parts)) { 063 return ComparisonResult.EQUAL_NM; 064 } 065 066 boolean isTrue = true; 067 boolean isFalse = false; 068 for (Predicate<T, C> part: getParts()) { 069 ComparisonResult pcr = part.compareTo((Predicate<T, C>) False.getInstance()); 070 if (pcr.getType().equals(ComparisonResult.Type.EQUAL)) { 071 isFalse = true; 072 isTrue = false; 073 break; 074 } else if (!pcr.getType().equals(ComparisonResult.Type.OPPOSITE)) { 075 isTrue = false; 076 } 077 } 078 079 if (isTrue) { 080 return otherPredicate.compareTo((Predicate<T, C>) True.getInstance()); 081 } 082 083 if (isFalse) { 084 return otherPredicate.compareTo((Predicate<T, C>) False.getInstance()); 085 } 086 087 if (getParts().size()==1) { 088 return getParts().get(0).compareTo(otherPredicate); 089 } 090 for (Predicate<T, C> part: getParts()) { 091 ComparisonResult pcr = part.compareTo(otherPredicate); 092 if (pcr.isOneToOneMapping()) { 093 switch (pcr.getType()) { 094 case EQUAL: 095 case MORE_RESTRICTIVE: 096 return ComparisonResult.MORE_RESTRICTIVE_NM; 097// case OPPOSITE: 098// case OPPOSITE_MORE_RESTRICTIVE: 099// return ComparisonResult.OPPOSITE_MORE_RESTRICTIVE_NM; 100 } 101 } 102 } 103 104 return super.compareTo(otherPredicate); 105 } 106 107 protected Boolean extractInternal(C context, Map<C, Map<Extractor<T, ? super Boolean, C>, ? super Boolean>> cache, T... obj) { 108 for (Predicate<T, C> part: parts) { 109 if (!part.extract(context, cache, obj)) { 110 return false; 111 } 112 } 113 return true; 114 } 115 116 public Set<Integer> parameterIndices() { 117 Set<Integer> ret = new TreeSet<Integer>(); 118 for (Predicate<T, C> part: parts) { 119 ret.addAll(part.parameterIndices()); 120 } 121 return ret; 122 } 123 124 @SuppressWarnings("unchecked") 125 public Predicate<T, C> remove(Predicate<T, C> part) { 126 if (!parts.contains(part)) { 127 return this; 128 } 129 try { 130 And<T, C> ret = (And<T, C>) clone(); 131 ret.parts.remove(part); 132 return ret.parts.size()==1 ? ret.parts.get(0) : ret; 133 } catch (CloneNotSupportedException e) { 134 throw new ExtractorException(e); 135 } 136 } 137 138 @SuppressWarnings("unchecked") 139 public Predicate<T, C> normalize() { 140 if (getParts().isEmpty()) { 141 return True.getInstance(); 142 } 143 if (getParts().size()==1) { 144 Predicate<T, C> ret = getParts().get(0); 145 if (ret instanceof CompositePredicate) { 146 ((CompositePredicate) ret).normalize(); 147 } 148 return ret; 149 } 150 ComparisonResult cr = compareTo((Predicate<T, C>) True.getInstance()); 151 if (cr.getType().equals(ComparisonResult.Type.EQUAL)) { 152 return True.getInstance(); 153 } 154 if (cr.getType().equals(ComparisonResult.Type.OPPOSITE)) { 155 return False.getInstance(); 156 } 157 158 Predicate<T, C>[] pa = getParts().toArray(new Predicate[getParts().size()]); 159 Z: for (int i=0; i<pa.length; ++i) { 160 for (int j=0; j<pa.length; ++j) { 161 if (j!=i && pa[i]!=null && pa[j]!=null) { 162 ComparisonResult pcr1 = pa[i].compareTo(pa[j]); 163 if (pcr1.isOneToOneMapping()) { 164 switch (pcr1.getType()) { 165 case EQUAL: 166 case LESS_RESTRICTIVE: 167 pa[j]=null; 168 continue; 169 case OPPOSITE: 170 case OPPOSITE_LESS_RESTRICTIVE: 171 return False.getInstance(); 172 } 173 } 174 175 ComparisonResult pcr2 = pa[j].compareTo(pa[i]); 176 if (pcr2.isOneToOneMapping()) { 177 switch (pcr2.getType()) { 178 case EQUAL: 179 case LESS_RESTRICTIVE: 180 pa[i]=null; 181 continue Z; 182 case OPPOSITE: 183 case OPPOSITE_LESS_RESTRICTIVE: 184 return False.getInstance(); 185 } 186 } 187 } 188 } 189 } 190 191 int pc = 0; 192 for (Predicate<T, C> part: pa) { 193 if (part!=null) { 194 ++pc; 195 } 196 } 197 198 if (pc==0) { 199 return True.getInstance(); 200 } 201 202 if (pc==1) { 203 for (Predicate<T, C> part: pa) { 204 if (part!=null) { 205 if (part instanceof CompositePredicate) { 206 ((CompositePredicate) part).normalize(); 207 } 208 return part; 209 } 210 } 211 } 212 213 if (pc!=pa.length) { 214 And<T, C> ret = new And<T, C>(cost, costUnit); 215 for (Predicate<T, C> part: pa) { 216 if (part!=null) { 217 ret.addPart(part); 218 } 219 } 220 return ret; 221 } 222 223 return this; 224 } 225 226 public boolean isContextDependent() { 227 for (Predicate<T, C> part: getParts()) { 228 if (part.isContextDependent()) { 229 return true; 230 } 231 } 232 return false; 233 } 234 235 @Override 236 public String toString() { 237 return getClass().getName()+getParts(); 238 } 239 240 @Override 241 public double getCost() { 242 if (cost==0 && costUnit==null) { 243 double ret = 0; 244 for (Predicate<T,C> part: parts) { 245 ret+=part.getCost(); 246 } 247 return ret; 248 } 249 return super.getCost(); 250 } 251 252 @Override 253 public Extractor<T, Boolean, C> map(int[] map) { 254 And<T,C> ret = new And<T, C>(initialCost, costUnit); 255 for (Predicate<T,C> part: parts) { 256 ret.addPart(MappedPredicate.mapPredicate(part, map)); 257 } 258 return ret; 259 } 260 261 @Override 262 public Object clone() throws CloneNotSupportedException { 263 @SuppressWarnings("unchecked") 264 And<T,C> ret = (And<T, C>) super.clone(); 265 ret.parts = new ArrayList<Predicate<T,C>>(parts); 266 return ret; 267 } 268 269 @Override 270 public And<T, C> add(Predicate<T, C> part) { 271 And<T, C> ret = new And<T, C>(initialCost, costUnit, parts); 272 ret.parts.add(part); 273 return ret; 274 } 275}