001// ***** This file is automatically generated from OneOf.java.jpp 002 003package daikon.inv.unary.scalar; 004 005import daikon.*; 006import daikon.inv.*; 007import daikon.inv.unary.OneOf; 008 009 import daikon.derive.unary.*; 010 import daikon.inv.binary.sequenceScalar.*; 011 import daikon.inv.unary.sequence.*; 012 013import java.io.*; 014import java.util.logging.Logger; 015import java.util.logging.Level; 016import java.util.*; 017 018import org.checkerframework.checker.initialization.qual.Initialized; 019import org.checkerframework.checker.interning.qual.Interned; 020import org.checkerframework.checker.lock.qual.GuardSatisfied; 021import org.checkerframework.checker.nullness.qual.NonNull; 022import org.checkerframework.checker.nullness.qual.Nullable; 023import org.checkerframework.dataflow.qual.Pure; 024import org.checkerframework.dataflow.qual.SideEffectFree; 025import org.checkerframework.framework.qual.Unused; 026import org.plumelib.reflection.Signatures; 027import org.plumelib.util.ArraysPlume; 028import org.plumelib.util.Intern; 029import org.plumelib.util.StringsPlume; 030import org.plumelib.util.UtilPlume; 031import typequals.prototype.qual.NonPrototype; 032import typequals.prototype.qual.Prototype; 033 034// This subsumes an "exact" invariant that says the value is always exactly 035// a specific value. Do I want to make that a separate invariant 036// nonetheless? Probably not, as this will simplify implication and such. 037 038 /** 039 * Represents double variables that take on only a few distinct values. Prints as either 040 * {@code x == c} (when there is only one value) or as {@code x one of {c1, c2, c3}} 041 * (when there are multiple values). 042 043 */ 044 045@SuppressWarnings("UnnecessaryParentheses") // generated code, parentheses are sometimes needed 046public final class OneOfFloat extends SingleFloat implements OneOf { 047 // We are Serializable, so we specify a version to allow changes to 048 // method signatures without breaking serialization. If you add or 049 // remove fields, you should change this number to the current date. 050 static final long serialVersionUID = 20030822L; 051 052 /** Debugging logger. */ 053 public static final Logger debug = 054 Logger.getLogger(OneOfFloat.class.getName()); 055 056 // Variables starting with dkconfig_ should only be set via the 057 // daikon.config.Configuration interface. 058 /** Boolean. True iff OneOf invariants should be considered. */ 059 public static boolean dkconfig_enabled = Invariant.invariantEnabledDefault; 060 061 /** 062 * Positive integer. Specifies the maximum set size for this type of invariant (x is one of 063 * {@code size} items). 064 */ 065 066 public static int dkconfig_size = 3; 067 068 // Probably needs to keep its own list of the values, and number of each seen. 069 // (That depends on the slice; maybe not until the slice is cleared out. 070 // But so few values is cheap, so this is quite fine for now and long-term.) 071 072 @Unused(when=Prototype.class) 073 private double[] elts; 074 @Unused(when=Prototype.class) 075 private int num_elts; 076 077 @Prototype OneOfFloat() { 078 super(); 079 } 080 081 OneOfFloat(PptSlice slice) { 082 super(slice); 083 084 elts = new double[dkconfig_size]; 085 086 num_elts = 0; 087 088 } 089 090 private static @Prototype OneOfFloat proto = new @Prototype OneOfFloat(); 091 092 /** Returns the prototype invariant for OneOfFloat */ 093 public static @Prototype OneOfFloat get_proto() { 094 return proto; 095 } 096 097 /** returns whether or not this invariant is enabled */ 098 @Override 099 public boolean enabled() { 100 return dkconfig_enabled; 101 } 102 103 /** instantiate an invariant on the specified slice */ 104 @Override 105 public OneOfFloat instantiate_dyn(@Prototype OneOfFloat this, PptSlice slice) { 106 return new OneOfFloat(slice); 107 } 108 109 @Pure 110 public boolean is_boolean(@GuardSatisfied OneOfFloat this) { 111 return var().file_rep_type.elementType() == ProglangType.BOOLEAN; 112 } 113 @Pure 114 public boolean is_hashcode(@GuardSatisfied OneOfFloat this) { 115 return var().file_rep_type.elementType() == ProglangType.HASHCODE; 116 } 117 118 @SideEffectFree 119 @Override 120 public OneOfFloat clone(@GuardSatisfied OneOfFloat this) { 121 OneOfFloat result = (OneOfFloat) super.clone(); 122 result.elts = elts.clone(); 123 124 result.num_elts = this.num_elts; 125 return result; 126 } 127 128 @Override 129 public int num_elts() { 130 return num_elts; 131 } 132 133 @Override 134 public Object elt() { 135 return elt(0); 136 } 137 138 public Object elt(int index) { 139 if (num_elts <= index) { 140 throw new Error("Represents " + num_elts + " elements, index " + index + " not valid"); 141 } 142 143 return Intern.internedDouble(elts[index]); 144 } 145 146 private void sort_rep(@GuardSatisfied OneOfFloat this) { 147 Arrays.sort(elts, 0, num_elts ); 148 } 149 150 public double min_elt() { 151 if (num_elts == 0) { 152 throw new Error("Represents no elements"); 153 } 154 sort_rep(); 155 return elts[0]; 156 } 157 158 public double max_elt() { 159 if (num_elts == 0) { 160 throw new Error("Represents no elements"); 161 } 162 sort_rep(); 163 return elts[num_elts - 1]; 164 } 165 166 // Assumes the other array is already sorted 167 public boolean compare_rep(int num_other_elts, double[] other_elts) { 168 if (num_elts != num_other_elts) { 169 return false; 170 } 171 sort_rep(); 172 for (int i = 0; i < num_elts; i++) { 173 if (!(Global.fuzzy.eq(elts[i], other_elts[i]) || (Double.isNaN(elts[i]) && Double.isNaN(other_elts[i])))) { // elements are interned 174 return false; 175 } 176 } 177 return true; 178 } 179 180 private String subarray_rep(@GuardSatisfied OneOfFloat this) { 181 // Not so efficient an implementation, but simple; 182 // and how often will we need to print this anyway? 183 sort_rep(); 184 StringBuilder sb = new StringBuilder(); 185 sb.append("{ "); 186 for (int i = 0; i < num_elts; i++) { 187 if (i != 0) { 188 sb.append(", "); 189 } 190 191 if (PrintInvariants.dkconfig_static_const_infer) { 192 boolean curVarMatch = false; 193 PptTopLevel pptt = ppt.parent; 194 for (VarInfo vi : pptt.var_infos) { 195 if (vi.isStaticConstant() && VarComparability.comparable(vi, var())) { 196 // If variable is a double, then use fuzzy comparison 197 if (vi.rep_type == ProglangType.DOUBLE) { 198 Double constantVal = (Double)vi.constantValue(); 199 if (Global.fuzzy.eq(constantVal, elts[i]) || (Double.isNaN(constantVal) && Double.isNaN(elts[i]))) { 200 sb.append(vi.name()); 201 curVarMatch = true; 202 } 203 } 204 // Otherwise just use the equals method 205 else { 206 Object constantVal = vi.constantValue(); 207 if (constantVal.equals(elts[i])) { 208 sb.append(vi.name()); 209 curVarMatch = true; 210 } 211 } 212 } 213 } 214 215 if (curVarMatch == false) { 216 sb.append((Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i]))); 217 } 218 } else { 219 sb.append((Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i]))); 220 } 221 222 } 223 sb.append(" }"); 224 return sb.toString(); 225 } 226 227 @Override 228 public String repr(@GuardSatisfied OneOfFloat this) { 229 return "OneOfFloat" + varNames() + ": falsified=" + falsified 230 + ", num_elts=" + num_elts 231 + ", elts=" + subarray_rep(); 232 } 233 234 public double[] getElts() { 235 double[] temp = new double[elts.length]; 236 for (int i = 0; i < elts.length; i++) { 237 temp[i] = elts[i]; 238 } 239 return temp; 240 } 241 242 @SideEffectFree 243 @Override 244 public String format_using(@GuardSatisfied OneOfFloat this, OutputFormat format) { 245 sort_rep(); 246 247 if (format.isJavaFamily()) { 248 return format_java_family(format); 249 } 250 251 if (format == OutputFormat.DAIKON) { 252 return format_daikon(); 253 } else if (format == OutputFormat.SIMPLIFY) { 254 return format_simplify(); 255 } else if (format == OutputFormat.ESCJAVA) { 256 String result = format_esc(); 257 return result; 258 } else if (format == OutputFormat.CSHARPCONTRACT) { 259 return format_csharp_contract(); 260 } else { 261 return format_unimplemented(format); 262 } 263 } 264 265 public String format_daikon(@GuardSatisfied OneOfFloat this) { 266 String varname = var().name(); 267 if (num_elts == 1) { 268 269 if (PrintInvariants.dkconfig_static_const_infer) { 270 PptTopLevel pptt = ppt.parent; 271 for (VarInfo vi : pptt.var_infos) { 272 if (vi.isStaticConstant() && VarComparability.comparable(vi, var())) { 273 if (vi.rep_type == ProglangType.DOUBLE) { 274 Double constantVal = (Double)vi.constantValue(); 275 if (Global.fuzzy.eq(constantVal, elts[0]) || (Double.isNaN(constantVal) && Double.isNaN(elts[0]))) { 276 return varname + " == " + vi.name(); 277 } 278 } else { 279 Object constantVal = vi.constantValue(); 280 if (constantVal.equals(elts[0])) { 281 return varname + " == " + vi.name(); 282 } 283 } 284 } 285 } 286 } 287 return varname + " == " + (Double.isNaN(elts[0]) ? "Double.NaN" : String.valueOf(elts[0])); 288 } else { 289 return varname + " one of " + subarray_rep(); 290 } 291 } 292 293 public String format_esc(@GuardSatisfied OneOfFloat this) { 294 sort_rep(); 295 296 String varname = var().esc_name(); 297 298 String result; 299 300 { 301 result = ""; 302 for (int i = 0; i < num_elts; i++) { 303 if (i != 0) { result += " || "; } 304 result += varname + " == " + (Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i])); 305 } 306 } 307 308 return result; 309 } 310 311public String format_csharp_contract(@GuardSatisfied OneOfFloat this) { 312 313 @NonNull @Initialized String result; 314 315 String varname = var().csharp_name(); 316 317 if (num_elts == 1) { 318 result = varname + " == " + elts[0]; 319 } else { 320 List<String> e = new ArrayList<>(); 321 for (int i = 0; i < num_elts; i++) { 322 e.add((Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i]))); 323 } 324 String exp = String.join(", ", e); 325 326 if (var().is_array() && !var().isDerived()) { 327 String[] split = var().csharp_array_split(); 328 result = "Contract.ForAll(" + split[0] + ", x => x" + split[1] + ".OneOf(" + exp + "))"; 329 } else { 330 result = varname + ".OneOf(" + exp + ")"; 331 } 332 } 333 334 return result; 335 } 336 337 public String format_java_family(@GuardSatisfied OneOfFloat this, OutputFormat format) { 338 339 String result; 340 341 // Setting up the name of the unary variable 342 String varname = var().name_using(format); 343 344 { 345 result = ""; 346 for (int i = 0; i < num_elts; i++) { 347 if (i != 0) { result += " || "; } 348 349 result += "daikon.Quant.fuzzy.eq(" + varname + ", " + (Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i])) + ")"; 350 351 } 352 } 353 354 return result; 355 } 356 357 public String format_simplify(@GuardSatisfied OneOfFloat this) { 358 359 sort_rep(); 360 361 String varname = 362 var().simplifyFixup(var().name_using(OutputFormat.SIMPLIFY)); 363 364 String result; 365 366 { 367 result = ""; 368 for (int i = 0; i < num_elts; i++) { 369 result += " (EQ " + varname + " " + simplify_format_double(elts[i]) + ")"; 370 } 371 if (num_elts > 1) { 372 result = "(OR" + result + ")"; 373 } else if (num_elts == 1) { 374 // chop leading space 375 result = result.substring(1); 376 } else { 377 // Haven't actually seen any data, so we're vacuously true 378 return format_too_few_samples(OutputFormat.SIMPLIFY, null); 379 } 380 } 381 382 if (result.indexOf("format_simplify") == -1) { 383 daikon.simplify.SimpUtil.assert_well_formed(result); 384 } 385 return result; 386 } 387 388 @Override 389 public InvariantStatus add_modified(double a, int count) { 390 return runValue(a, count, true); 391 } 392 393 @Override 394 public InvariantStatus check_modified(double a, int count) { 395 return runValue(a, count, false); 396 } 397 398 private InvariantStatus runValue(double v, int count, boolean mutate) { 399 InvariantStatus status; 400 if (mutate) { 401 status = add_mod_elem(v, count); 402 } else { 403 status = check_mod_elem(v, count); 404 } 405 if (status == InvariantStatus.FALSIFIED) { 406 if (logOn() && mutate) { 407 StringBuilder eltString = new StringBuilder(); 408 for (int i = 0; i < num_elts; i++) { 409 eltString.append((Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i])) + " "); 410 } 411 log("destroyed on sample %s previous vals = {%s} num_elts = %s", 412 (Double.isNaN(v) ? "Double.NaN" : String.valueOf(v)), eltString, num_elts); 413 } 414 return InvariantStatus.FALSIFIED; 415 } 416 return status; 417 } 418 419 /** 420 * Adds a single sample to the invariant. Returns 421 * the appropriate InvariantStatus from the result 422 * of adding the sample to this. 423 */ 424 public InvariantStatus add_mod_elem(double v, int count) { 425 InvariantStatus status = check_mod_elem(v, count); 426 if (status == InvariantStatus.WEAKENED) { 427 elts[num_elts] = v; 428 num_elts++; 429 } 430 return status; 431 } 432 433 /** 434 * Checks a single sample to the invariant. Returns 435 * the appropriate InvariantStatus from the result 436 * of adding the sample to this. 437 */ 438 public InvariantStatus check_mod_elem(double v, int count) { 439 440 // Look for v in our list of previously seen values. If it's 441 // found, we're all set. 442 for (int i = 0; i < num_elts; i++) { 443 // if (logDetail()) 444 // log ("add_modified (" + v + ")"); 445 if ((Global.fuzzy.eq(elts[i], v) || (Double.isNaN(elts[i]) && Double.isNaN( v)))) { 446 return InvariantStatus.NO_CHANGE; 447 } 448 } 449 450 if (num_elts == dkconfig_size) { 451 return InvariantStatus.FALSIFIED; 452 } 453 454 return InvariantStatus.WEAKENED; 455 } 456 457 @Override 458 protected double computeConfidence() { 459 // This is not ideal. 460 if (num_elts == 0) { 461 return Invariant.CONFIDENCE_UNJUSTIFIED; 462 } else { 463 return Invariant.CONFIDENCE_JUSTIFIED; 464 } 465 } 466 467 @Pure 468 @Override 469 public @Nullable DiscardInfo isObviousStatically(VarInfo[] vis) { 470 // Static constants are necessarily OneOf precisely one value. 471 // This removes static constants from the output, which might not be 472 // desirable if the user doesn't know their actual value. 473 if (vis[0].isStaticConstant()) { 474 assert num_elts <= 1; 475 return new DiscardInfo(this, DiscardCode.obvious, vis[0].name() + " is a static constant."); 476 } 477 return super.isObviousStatically(vis); 478 } 479 480 @Pure 481 @Override 482 public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) { 483 DiscardInfo super_result = super.isObviousDynamically(vis); 484 if (super_result != null) { 485 return super_result; 486 } 487 488 VarInfo v = vis[0]; 489 490 Debug dlog = new Debug(getClass(), ppt, vis); 491 492 if (logOn()) { 493 dlog.log("enter isObviousDynamically"); 494 } 495 496 // We can use the minvalue and maxvalue custom attributes here: if 497 // minimum value and maximum value are the same as the reported 498 // value, then we can suppress this invariant 499 if (num_elts == 1 500 && v.aux.hasValue(VarInfoAux.MINIMUM_VALUE) 501 && v.aux.hasValue(VarInfoAux.MAXIMUM_VALUE)) { 502 int min = v.aux.getInt(VarInfoAux.MINIMUM_VALUE), 503 max = v.aux.getInt(VarInfoAux.MAXIMUM_VALUE); 504 if (min == max && min == elts[0]) { 505 return new DiscardInfo( 506 this, 507 DiscardCode.obvious, 508 v.name() + "'s value matches with the expected value"); 509 } 510 } 511 512 // We can check if all values in the list match with the ones we know about 513 // (useful for booleans and numeric enumerations). 514 if (v.aux.hasValue(VarInfoAux.VALID_VALUES)) { 515 String[] vsValidValues = v.aux.getList(VarInfoAux.VALID_VALUES); 516 Set<Double> setValidValues = new TreeSet<>(); 517 for (String s : vsValidValues) { 518 setValidValues.add(Double.valueOf(s)); 519 } 520 Set<Double> setValuesInvariant = new TreeSet<>(); 521 for (double e : elts) { 522 setValuesInvariant.add(e); 523 } 524 if (setValidValues.equals(setValuesInvariant)) { 525 return new DiscardInfo(this, DiscardCode.obvious, 526 "The value list matches the allowed value list"); 527 } 528 } 529 530 // Obvious if we are 'size(array) == 0' The thinking is that this 531 // will also always show up as 'array == []' which is a little more 532 // illuminating. At this point we insist that we are a SequenceLength 533 // derivation of a base (underived) array. Its quite possible this should 534 // just apply to all arrays. 535 if (v.isDerived() && (v.derived instanceof SequenceLength) 536 && (num_elts == 1) && (elts[0] == 0)) { 537 @NonNull VarInfo b = v.derived.getBase(0); 538 if (!b.isDerived()) { 539 if (logOn()) { 540 dlog.log("isObviousDynamically '" + v.name() 541 + " == 0' ==> '" + b.name() + " == []'"); 542 } 543 return new DiscardInfo(this, DiscardCode.obvious, "size(array) == 0 is implied by array == []"); 544 } 545 } 546 547 if (v.isDerived() && (v.derived instanceof SequenceLength)) { 548 @NonNull SequenceLength sl = (SequenceLength) v.derived; 549 if (sl.shift != 0) { 550 String discardString = v.name() + " is derived with shift!=0 (shift==" + sl.shift + ")"; 551 return new DiscardInfo(this, DiscardCode.obvious, discardString); 552 } 553 } 554 555 // For every EltOneOfFloat at this program point, see if this variable is 556 // an obvious member of that sequence. 557 PptTopLevel parent = ppt.parent; 558 for (Iterator<Invariant> itor = parent.invariants_iterator(); itor.hasNext(); ) { 559 Invariant inv = itor.next(); 560 if ((inv instanceof EltOneOfFloat) && inv.enoughSamples()) { 561 VarInfo v1 = var(); 562 VarInfo v2 = inv.ppt.var_infos[0]; 563 // System.out.println("isObviousImplied: calling Member.isObviousMember(" + v1.name + ", " + v2.name + ")"); 564 // Don't use isEqualToObviousMember: that is too subtle 565 // and eliminates desirable invariants such as "return == null". 566 if (Member.isObviousMember(v1, v2)) { 567 EltOneOfFloat other = (EltOneOfFloat) inv; 568 if (num_elts == other.num_elts()) { 569 sort_rep(); 570 if (other.compare_rep(num_elts, elts)) { 571 // System.out.println("isObviousImplied true"); 572 String discardString = v1.name()+" is a member of "+v2.name()+" for which this Invariant also holds"; 573 return new DiscardInfo(this, DiscardCode.obvious, discardString); 574 } 575 } 576 } 577 } 578 } 579 580 return null; 581 } 582 583 /** 584 * Oneof can merge different formulas from lower points to create a single formula at an upper 585 * point. 586 */ 587 @Override 588 public boolean mergeFormulasOk() { 589 return true; 590 } 591 592 @Pure 593 @Override 594 public boolean isSameFormula(Invariant o) { 595 OneOfFloat other = (OneOfFloat) o; 596 if (num_elts != other.num_elts) { 597 return false; 598 } 599 if (num_elts == 0 && other.num_elts == 0) { 600 return true; 601 } 602 603 sort_rep(); 604 other.sort_rep(); 605 606 for (int i = 0; i < num_elts; i++) { 607 if (!(Global.fuzzy.eq(elts[i], other.elts[i]) || (Double.isNaN(elts[i]) && Double.isNaN(other.elts[i])))) { 608 return false; 609 } 610 } 611 612 return true; 613 } 614 615 @Pure 616 @Override 617 public boolean isExclusiveFormula(Invariant o) { 618 if (o instanceof OneOfFloat) { 619 OneOfFloat other = (OneOfFloat) o; 620 621 if (num_elts == 0 || other.num_elts == 0) { 622 return false; 623 } 624 for (int i = 0; i < num_elts; i++) { 625 for (int j = 0; j < other.num_elts; j++) { 626 if ((Global.fuzzy.eq(elts[i], other.elts[j]) || (Double.isNaN(elts[i]) && Double.isNaN(other.elts[j])))) // elements are interned 627 return false; 628 } 629 } 630 631 return true; 632 } 633 634 // Many more checks can be added here: against nonzero, modulus, etc. 635 if ((o instanceof NonZeroFloat) && (num_elts == 1) && (elts[0] == 0)) { 636 return true; 637 } 638 double elts_min = Double.MAX_VALUE; 639 double elts_max = Double.MIN_VALUE; 640 for (int i = 0; i < num_elts; i++) { 641 elts_min = Math.min(elts_min, elts[i]); 642 elts_max = Math.max(elts_max, elts[i]); 643 } 644 if ((o instanceof LowerBoundFloat) && (elts_max < ((LowerBoundFloat)o).min())) { 645 return true; 646 } 647 if ((o instanceof UpperBoundFloat) && (elts_min > ((UpperBoundFloat)o).max())) { 648 return true; 649 } 650 651 return false; 652 } 653 654 @Override 655 public boolean hasUninterestingConstant() { 656 657 for (int i = 0; i < num_elts; i++) { 658 if (elts[i] < -1.0 || elts[i] > 2.0 || elts[i] != (long)elts[i]) { 659 return true; 660 } 661 } 662 663 return false; 664 } 665 666 @Pure 667 @Override 668 public boolean isExact() { 669 return num_elts == 1; 670 } 671 672 // Look up a previously instantiated invariant. 673 public static @Nullable OneOfFloat find(PptSlice ppt) { 674 assert ppt.arity() == 1; 675 for (Invariant inv : ppt.invs) { 676 if (inv instanceof OneOfFloat) { 677 return (OneOfFloat) inv; 678 } 679 } 680 return null; 681 } 682 683 // Interning is lost when an object is serialized and deserialized. 684 // Manually re-intern any interned fields upon deserialization. 685 private void readObject(ObjectInputStream in) throws IOException, 686 ClassNotFoundException { 687 in.defaultReadObject(); 688 689 for (int i = 0; i < num_elts; i++) { 690 elts[i] = Intern.intern(elts[i]); 691 } 692 } 693 694 /** 695 * Merge the invariants in invs to form a new invariant. Each must be a OneOfFloat invariant. 696 * This code finds all of the oneof values from each of the invariants and returns the merged 697 * invariant (if any). 698 * 699 * @param invs list of invariants to merge. The invariants must all be of the same type and should 700 * come from the children of parent_ppt. They should also all be permuted to match the 701 * variable order in parent_ppt. 702 * @param parent_ppt slice that will contain the new invariant 703 */ 704 @Override 705 public @Nullable Invariant merge(List<Invariant> invs, PptSlice parent_ppt) { 706 707 // Create the initial parent invariant from the first child 708 OneOfFloat first = (OneOfFloat) invs.get(0); 709 OneOfFloat result = first.clone(); 710 result.ppt = parent_ppt; 711 712 // Loop through the rest of the child invariants 713 for (int i = 1; i < invs.size(); i++ ) { 714 715 // Get this invariant 716 OneOfFloat inv = (OneOfFloat) invs.get(i); 717 718 // Loop through each distinct value found in this child and add 719 // it to the parent. If the invariant is falsified, there is no parent 720 // invariant 721 for (int j = 0; j < inv.num_elts; j++) { 722 double val = inv.elts[j]; 723 724 InvariantStatus status = result.add_mod_elem(val, 1); 725 if (status == InvariantStatus.FALSIFIED) { 726 727 result.log("%s", "child value '" + val + "' destroyed oneof"); 728 729 return null; 730 } 731 } 732 } 733 734 result.log("Merged '%s' from %s child invariants", result.format(), invs.size()); 735 return result; 736 } 737 738 /** 739 * Setup the invariant with the specified elements. Normally used when searching for a specified 740 * OneOf. The elements of vals are not necessarily interned; this method interns each element. 741 */ 742 public void set_one_of_val(double[] vals) { 743 744 num_elts = vals.length; 745 for (int i = 0; i < num_elts; i++) { 746 elts[i] = Intern.intern(vals[i]); 747 } 748 } 749 750 /** 751 * Returns true if every element in this invariant is contained in the specified state. For 752 * example if x = 1 and the state contains 1 and 2, true will be returned. 753 */ 754 @Override 755 public boolean state_match(Object state) { 756 757 if (num_elts == 0) { 758 return false; 759 } 760 761 if (!(state instanceof double[])) { 762 // Daikon is about to crash. Produce some debugging output. 763 System.out.printf("state = %s [%s]%n", state, state.getClass()); 764 System.out.printf("problem with %s%n", this); 765 } 766 double[] e = (double[]) state; 767 for (int i = 0; i < num_elts; i++) { 768 boolean match = false; 769 for (int j = 0; j < e.length; j++) { 770 if (elts[i] == e[j]) { 771 match = true; 772 break; 773 } 774 } 775 if (!match) { 776 return false; 777 } 778 } 779 return true; 780 } 781 782}