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 OR. 015 * @author Pavel Vlasov. 016 * 017 * @param <T> 018 */ 019public class Or<T, C> extends ExtractorBase<T, Boolean, C> implements CompositePredicate<T, List<Predicate<T, C>>, C, Or<T,C>>, Serializable { 020 021 private List<Predicate<T, C>> parts = new ArrayList<Predicate<T, C>>(); 022 023 public Or(double initialCost, TimeUnit costUnit) { 024 super(initialCost, costUnit); 025 } 026 027 public Or(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 Or(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 Or) { 043 for (Predicate<T, C> pp: ((Or<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 Or && parts.equals(((Or) otherPredicate).parts)) { 063 return ComparisonResult.EQUAL_NM; 064 } 065 066 boolean isTrue = false; 067 boolean isFalse = true; 068 for (Predicate<T, C> part: getParts()) { 069 ComparisonResult pcr = part.compareTo((Predicate<T, C>) True.getInstance()); 070 if (pcr.getType().equals(ComparisonResult.Type.EQUAL)) { 071 isTrue = true; 072 isFalse = false; 073 break; 074 } else if (!pcr.getType().equals(ComparisonResult.Type.OPPOSITE)) { 075 isFalse = 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().iterator().next().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 LESS_RESTRICTIVE: 096 return ComparisonResult.LESS_RESTRICTIVE_NM; 097// case OPPOSITE: 098// case OPPOSITE_LESS_RESTRICTIVE: 099// return ComparisonResult.OPPOSITE_MORE_RESTRICTIVE_NM; 100 } 101 } 102 } 103 104 return super.compareTo(otherPredicate); 105 } 106 107 protected Boolean extractInternal( 108 C context, 109 Map<C, Map<Extractor<T, ? super Boolean, C>, ? super Boolean>> cache, 110 T... obj) { 111 112 for (Predicate<T, C> part: parts) { 113 if (part.extract(context, cache, obj)) { 114 return true; 115 } 116 } 117 return false; 118 } 119 120 public Set<Integer> parameterIndices() { 121 Set<Integer> ret = new TreeSet<Integer>(); 122 for (Predicate<T, C> part: parts) { 123 ret.addAll(part.parameterIndices()); 124 } 125 return ret; 126 } 127 128 129 @SuppressWarnings("unchecked") 130 public Predicate<T, C> remove(Predicate<T, C> part) { 131 if (!parts.contains(part)) { 132 return this; 133 } 134 try { 135 Or<T, C> ret = (Or<T, C>) clone(); 136 ret.parts.remove(part); 137 return ret.parts.size()==1 ? ret.parts.get(0) : ret; 138 } catch (CloneNotSupportedException e) { 139 throw new ExtractorException(e); 140 } 141 } 142 143 @SuppressWarnings("unchecked") 144 public Predicate<T, C> normalize() { 145 if (getParts().isEmpty()) { 146 return True.getInstance(); 147 } 148 if (getParts().size()==1) { 149 Predicate<T, C> ret = getParts().get(0); 150 if (ret instanceof CompositePredicate) { 151 ((CompositePredicate) ret).normalize(); 152 } 153 return ret; 154 } 155 ComparisonResult cr = compareTo((Predicate<T, C>) True.getInstance()); 156 if (cr.getType().equals(ComparisonResult.Type.EQUAL)) { 157 return True.getInstance(); 158 } 159 if (cr.getType().equals(ComparisonResult.Type.OPPOSITE)) { 160 return False.getInstance(); 161 } 162 Predicate<T, C>[] pa = getParts().toArray(new Predicate[getParts().size()]); 163 Z: for (int i=0; i<pa.length; ++i) { 164 for (int j=0; j<pa.length; ++j) { 165 if (j!=i && pa[i]!=null && pa[j]!=null) { 166 ComparisonResult pcr1 = pa[i].compareTo(pa[j]); 167 if (pcr1.isOneToOneMapping()) { 168 switch (pcr1.getType()) { 169 case EQUAL: 170 case MORE_RESTRICTIVE: 171 pa[j]=null; 172 continue; 173 case OPPOSITE: 174 case OPPOSITE_MORE_RESTRICTIVE: 175 return True.getInstance(); 176 } 177 } 178 179 ComparisonResult pcr2 = pa[j].compareTo(pa[i]); 180 if (pcr2.isOneToOneMapping()) { 181 switch (pcr2.getType()) { 182 case EQUAL: 183 case MORE_RESTRICTIVE: 184 pa[i]=null; 185 continue Z; 186 case OPPOSITE: 187 case OPPOSITE_MORE_RESTRICTIVE: 188 return True.getInstance(); 189 } 190 } 191 } 192 } 193 } 194 195 int pc = 0; 196 for (Predicate<T, C> part: pa) { 197 if (part!=null) { 198 ++pc; 199 } 200 } 201 202 if (pc==0) { 203 return True.getInstance(); 204 } 205 206 if (pc==1) { 207 for (Predicate<T, C> part: pa) { 208 if (part!=null) { 209 if (part instanceof CompositePredicate) { 210 ((CompositePredicate) part).normalize(); 211 } 212 return part; 213 } 214 } 215 } 216 217 if (pc!=pa.length) { 218 Or<T, C> ret = new Or<T, C>(cost, costUnit); 219 for (Predicate<T, C> part: pa) { 220 if (part!=null) { 221 ret.addPart(part); 222 } 223 } 224 return ret; 225 } 226 227 return this; 228 } 229 230 public boolean isContextDependent() { 231 for (Predicate<T, C> part: getParts()) { 232 if (part.isContextDependent()) { 233 return true; 234 } 235 } 236 return false; 237 } 238 239 @Override 240 public String toString() { 241 return getClass().getName()+getParts(); 242 } 243 244 @Override 245 public double getCost() { 246 if (cost==0 && costUnit==null) { 247 double ret = 0; 248 for (Predicate<T,C> part: parts) { 249 ret+=part.getCost(); 250 } 251 return ret; 252 } 253 return super.getCost(); 254 } 255 256 257 @Override 258 public Extractor<T, Boolean, C> map(int[] map) { 259 Or<T,C> ret = new Or<T, C>(initialCost, costUnit); 260 for (Predicate<T,C> part: parts) { 261 ret.addPart(MappedPredicate.mapPredicate(part, map)); 262 } 263 return ret; 264 } 265 266 @Override 267 public Object clone() throws CloneNotSupportedException { 268 @SuppressWarnings("unchecked") 269 Or<T,C> ret = (Or<T, C>) super.clone(); 270 ret.parts = new ArrayList<Predicate<T,C>>(parts); 271 return ret; 272 } 273 274 @Override 275 public Or<T, C> add(Predicate<T, C> part) { 276 Or<T, C> ret = new Or<T, C>(initialCost, costUnit, parts); 277 ret.parts.add(part); 278 return ret; 279 } 280}