diff --git a/src/main/java/java/lang/Class.java b/src/main/java/java/lang/Class.java index 832ad57..36d0482 100644 --- a/src/main/java/java/lang/Class.java +++ b/src/main/java/java/lang/Class.java @@ -39,6 +39,58 @@ import org.cprover.CProver; +/** + * Instances of the class {@code Class} represent classes and + * interfaces in a running Java application. An enum is a kind of + * class and an annotation is a kind of interface. Every array also + * belongs to a class that is reflected as a {@code Class} object + * that is shared by all arrays with the same element type and number + * of dimensions. The primitive Java types ({@code boolean}, + * {@code byte}, {@code char}, {@code short}, + * {@code int}, {@code long}, {@code float}, and + * {@code double}), and the keyword {@code void} are also + * represented as {@code Class} objects. + * + *

{@code Class} has no public constructor. Instead {@code Class} + * objects are constructed automatically by the Java Virtual Machine as classes + * are loaded and by calls to the {@code defineClass} method in the class + * loader. + * + *

The following example uses a {@code Class} object to print the + * class name of an object: + * + *

+ *     void printClassName(Object obj) {
+ *         System.out.println("The class of " + obj +
+ *                            " is " + obj.getClass().getName());
+ *     }
+ * 
+ * + *

It is also possible to get the {@code Class} object for a named + * type (or for void) using a class literal. See Section 15.8.2 of + * The Java™ Language Specification. + * For example: + * + *

+ * {@code System.out.println("The name of class Foo is: "+Foo.class.getName());} + *
+ * + * @param the type of the class modeled by this {@code Class} + * object. For example, the type of {@code String.class} is {@code + * Class}. Use {@code Class} if the class being modeled is + * unknown. + * + * @author unascribed + * @see java.lang.ClassLoader#defineClass(byte[], int, int) + * @since JDK1.0 + * + * @diffblue.limitedSupport + * Generated tests that create an instance of Class will be incorrect: + * + */ public final class Class { private Class() {} @@ -55,6 +107,13 @@ private Class() {} private boolean cproverIsMemberClass; private boolean cproverIsEnum; + // TODO: these fields are to enforce singleton semantics of + // Class objects as returned by Object.getClass() and Class.forName() + // The size is currently hard-coded which may lead to incorrect results. + // A map could be used here in future. + private static String[] cproverClassNames = new String[8]; + private static Class[] cproverClassInstances = new Class[8]; + public String toString() { return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) + getName(); @@ -111,9 +170,25 @@ public String toGenericString() { // forName method. The goal is to correctly model combinations of forName // and getName, but precisely following the JDK behaviour is more involved. public static Class forName(String className) { - Class c=new Class(); - c.name=className; - return c; + CProver.notModelled(); + throw new AssertionError(); + /* + String foundName = null; + for (int i = 0; i < cproverClassNames.length; ++i) { + String currentName = cproverClassNames[i]; + if (currentName == null) { + Class c = new Class(); + c.name = className; + cproverClassNames[i] = className; + cproverClassInstances[i] = c; + return c; + } + if (className.equals(currentName)) { + return cproverClassInstances[i]; + } + } + return CProver.nondetWithoutNullForNotModelled(); + */ } public static Class forName(String name, boolean initialize, @@ -205,7 +280,7 @@ ClassLoader getClassLoader0() { // DIFFBLUE MODEL LIBRARY The real java.lang.Class stores a // `private final ClassLoader classLoader` which is initialised by the // jvm rather than by the constructor of this object. - // TODO test-gen should understand this method natively. + // TODO JBMC should understand this method natively. return null; } @@ -453,6 +528,7 @@ private static boolean desiredAssertionStatus0(Class clazz) { protected void cproverNondetInitialize() { CProver.assume(name != null); CProver.assume(enumConstantDirectory == null); + CProver.assume(classValueMap == null); } // DIFFBLUE MODEL LIBRARY @@ -607,6 +683,13 @@ public Method getMethod(String name, Class... parameterTypes) throws NoSuchMe return new Method(this, name, parameterTypes); } + // DIFFBLUE MODEL LIBRARY + // This field is never read in our model. We include them because ClassValue + // (in the java library, not our models) references it, so it is needed to + // make ClassValue compile. + // transient ClassValue.ClassValueMap classValueMap; + transient ClassValue.ClassValueMap classValueMap = null; + /** * Returns the {@code Class} representing the component type of an * array. If this class does not represent an array class this method @@ -615,10 +698,12 @@ public Method getMethod(String name, Class... parameterTypes) throws NoSuchMe * @return the {@code Class} representing the component type of this * class if this class is an array * @see java.lang.reflect.Array - * @since 1.1 + * @since JDK1.1 + * @diffblue.noSupport */ + // public native Class getComponentType(); public Class getComponentType() { CProver.notModelled(); - return CProver.nondetWithoutNullForNotModelled(); + return CProver.nondetWithNullForNotModelled(); } } diff --git a/src/main/java/java/lang/Double.java b/src/main/java/java/lang/Double.java index 037d557..4c73944 100644 --- a/src/main/java/java/lang/Double.java +++ b/src/main/java/java/lang/Double.java @@ -816,7 +816,7 @@ public static int hashCode(double value) { * @diffblue.fullSupport * * Until the native method doubleToRawLongBits(D) is implemented in - * CBMC, this model will allow test generation for checking equality + * CBMC, this model will allow JBMC for checking equality * between two Doubles. */ public boolean equals(Object obj) { diff --git a/src/main/java/java/lang/Float.java b/src/main/java/java/lang/Float.java index 452bb87..e18d54f 100644 --- a/src/main/java/java/lang/Float.java +++ b/src/main/java/java/lang/Float.java @@ -716,7 +716,7 @@ public static int hashCode(float value) { * @diffblue.fullSupport * * Until the native method floatToRawIntBits(F) is implemented in - * CBMC, this model will allow test generation for checking equality + * CBMC, this model will allow JBMC for checking equality * between two Floats. */ public boolean equals(Object obj) { diff --git a/src/main/java/java/lang/Math.java b/src/main/java/java/lang/Math.java index 9c214af..6c26ea5 100644 --- a/src/main/java/java/lang/Math.java +++ b/src/main/java/java/lang/Math.java @@ -364,12 +364,10 @@ public static double log10(double a) { * result of sqrt is equal to the original number, which is not always * true. As a result, the solver will return UNSAT in many cases. * For instance, {@code Math.sqrt(2.0)} will cause the solver to be UNSAT. - * Reported in: TG-5598 * * Also, there are precision issues on very small numbers. For instance, * for values between 0 and {@code 0x0.0000000000001p-900}, the sqrt method * is likely to not be equal to the result of the real Math.sqrt method. - * Reported in: TG-5602 */ public static double sqrt(double a) { // return StrictMath.sqrt(a); // default impl. delegates to StrictMath diff --git a/src/main/java/java/lang/String.java b/src/main/java/java/lang/String.java index 390e734..e43cb1f 100644 --- a/src/main/java/java/lang/String.java +++ b/src/main/java/java/lang/String.java @@ -2996,8 +2996,7 @@ public String replaceAll(String regex, String replacement) { // return Pattern.compile(regex).matcher(this).replaceAll(replacement); // DIFFBLUE MODELS LIBRARY: we assume the expression is just a string literal - CProver.assume( - regex.indexOf('[') == -1 && + if (regex.indexOf('[') == -1 && regex.indexOf(']') == -1 && regex.indexOf('.') == -1 && regex.indexOf('\\') == -1 && @@ -3010,8 +3009,12 @@ public String replaceAll(String regex, String replacement) regex.indexOf('}') == -1 && regex.indexOf('|') == -1 && regex.indexOf('(') == -1 && - regex.indexOf(')') == -1); - return replace(regex, replacement); + regex.indexOf(')') == -1) { + return replace(regex, replacement); + } else { + CProver.notModelled(); + return CProver.nondetWithNullForNotModelled(); + } } /** @@ -4330,7 +4333,7 @@ public static String valueOf(float f) { */ public static String valueOf(double d) { // string solver only knows how to convert floats to string - return CProverString.toString(d); + return CProverString.toString((float)d); // return Double.toString(d); } diff --git a/src/main/java/java/lang/StringBuffer.java b/src/main/java/java/lang/StringBuffer.java index 46f3cd9..281936a 100644 --- a/src/main/java/java/lang/StringBuffer.java +++ b/src/main/java/java/lang/StringBuffer.java @@ -333,7 +333,7 @@ public synchronized void setCharAt(int index, char ch) { /** * @diffblue.limitedSupport - * This method can be slow to generate tests due to TG-2866 and is + * This method can be slow to generate tests due to an issue and is * also limited by which {@code toString()} methods have been modelled. */ @Override diff --git a/src/main/java/java/lang/StringBuilder.java b/src/main/java/java/lang/StringBuilder.java index e9e6a3f..5ab1b2f 100644 --- a/src/main/java/java/lang/StringBuilder.java +++ b/src/main/java/java/lang/StringBuilder.java @@ -156,7 +156,7 @@ public StringBuilder(CharSequence seq) { /** * @diffblue.limitedSupport - * This method can be slow to generate tests due to TG-2866 and is + * This method can be slow to generate tests due to an issue and is * also limited by which {@code toString()} methods have been modelled. */ @Override diff --git a/src/main/java/java/net/URLDecoder.java b/src/main/java/java/net/URLDecoder.java new file mode 100644 index 0000000..1e1138a --- /dev/null +++ b/src/main/java/java/net/URLDecoder.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.net; + +import java.io.*; + +/** + * Utility class for HTML form decoding. This class contains static methods + * for decoding a String from the application/x-www-form-urlencoded + * MIME format. + *

+ * The conversion process is the reverse of that used by the URLEncoder class. It is assumed + * that all characters in the encoded string are one of the following: + * "{@code a}" through "{@code z}", + * "{@code A}" through "{@code Z}", + * "{@code 0}" through "{@code 9}", and + * "{@code -}", "{@code _}", + * "{@code .}", and "{@code *}". The + * character "{@code %}" is allowed but is interpreted + * as the start of a special escaped sequence. + *

+ * The following rules are applied in the conversion: + * + *

    + *
  • The alphanumeric characters "{@code a}" through + * "{@code z}", "{@code A}" through + * "{@code Z}" and "{@code 0}" + * through "{@code 9}" remain the same. + *
  • The special characters "{@code .}", + * "{@code -}", "{@code *}", and + * "{@code _}" remain the same. + *
  • The plus sign "{@code +}" is converted into a + * space character "   " . + *
  • A sequence of the form "{@code %xy}" will be + * treated as representing a byte where xy is the two-digit + * hexadecimal representation of the 8 bits. Then, all substrings + * that contain one or more of these byte sequences consecutively + * will be replaced by the character(s) whose encoding would result + * in those consecutive bytes. + * The encoding scheme used to decode these characters may be specified, + * or if unspecified, the default encoding of the platform will be used. + *
+ *

+ * There are two possible ways in which this decoder could deal with + * illegal strings. It could either leave illegal characters alone or + * it could throw an {@link java.lang.IllegalArgumentException}. + * Which approach the decoder takes is left to the + * implementation. + * + * @author Mark Chamness + * @author Michael McCloskey + * @since 1.2 + */ + +public class URLDecoder { + + // The platform default encoding + static String dfltEncName = URLEncoder.dfltEncName; + + /** + * Decodes a {@code x-www-form-urlencoded} string. + * The platform's default encoding is used to determine what characters + * are represented by any consecutive sequences of the form + * "{@code %xy}". + * @param s the {@code String} to decode + * @deprecated The resulting string may vary depending on the platform's + * default encoding. Instead, use the decode(String,String) method + * to specify the encoding. + * @return the newly decoded {@code String} + */ + @Deprecated + public static String decode(String s) { + + String str = null; + + try { + str = decode(s, dfltEncName); + } catch (UnsupportedEncodingException e) { + // The system should always have the platform default + } + + return str; + } + + /** + * Decodes a {@code application/x-www-form-urlencoded} string using a specific + * encoding scheme. + * The supplied encoding is used to determine + * what characters are represented by any consecutive sequences of the + * form "{@code %xy}". + *

+ * Note: The + * World Wide Web Consortium Recommendation states that + * UTF-8 should be used. Not doing so may introduce + * incompatibilities. + * + * @param s the {@code String} to decode + * @param enc The name of a supported + * character + * encoding. + * @return the newly decoded {@code String} + * @exception UnsupportedEncodingException + * If character encoding needs to be consulted, but + * named character encoding is not supported + * @see URLEncoder#encode(java.lang.String, java.lang.String) + * @since 1.4 + */ + public static String decode(String s, String enc) + throws UnsupportedEncodingException{ + + boolean needToChange = false; + int numChars = s.length(); + StringBuffer sb = new StringBuffer(numChars > 500 ? numChars / 2 : numChars); + int i = 0; + + if (enc.length() == 0) { + throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter"); + } + + char c; + byte[] bytes = null; + while (i < numChars) { + c = s.charAt(i); + switch (c) { + case '+': + sb.append(' '); + i++; + needToChange = true; + break; + case '%': + /* + * Starting with this instance of %, process all + * consecutive substrings of the form %xy. Each + * substring %xy will yield a byte. Convert all + * consecutive bytes obtained this way to whatever + * character(s) they represent in the provided + * encoding. + */ + + try { + + // (numChars-i)/3 is an upper bound for the number + // of remaining bytes + if (bytes == null) + bytes = new byte[(numChars-i)/3]; + int pos = 0; + + while ( ((i+2) < numChars) && + (c=='%')) { + int v = Integer.parseInt(s.substring(i+1,i+3),16); + if (v < 0) + throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - negative value"); + bytes[pos++] = (byte) v; + i+= 3; + if (i < numChars) + c = s.charAt(i); + } + + // A trailing, incomplete byte encoding such as + // "%x" will cause an exception to be thrown + + if ((i < numChars) && (c=='%')) + throw new IllegalArgumentException( + "URLDecoder: Incomplete trailing escape (%) pattern"); + + sb.append(new String(bytes, 0, pos, enc)); + } catch (NumberFormatException e) { + throw new IllegalArgumentException( + "URLDecoder: Illegal hex characters in escape (%) pattern - " + + e.getMessage()); + } + needToChange = true; + break; + default: + sb.append(c); + i++; + break; + } + } + + return (needToChange? sb.toString() : s); + } +} diff --git a/src/main/java/java/net/URLEncoder.java b/src/main/java/java/net/URLEncoder.java new file mode 100644 index 0000000..86377b7 --- /dev/null +++ b/src/main/java/java/net/URLEncoder.java @@ -0,0 +1,292 @@ +/* + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.net; + +import java.io.ByteArrayOutputStream; +import java.io.BufferedWriter; +import java.io.OutputStreamWriter; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.io.CharArrayWriter; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException ; +import java.util.BitSet; +import java.security.AccessController; +import java.security.PrivilegedAction; +import sun.security.action.GetBooleanAction; +import sun.security.action.GetPropertyAction; + +/** + * Utility class for HTML form encoding. This class contains static methods + * for converting a String to the application/x-www-form-urlencoded MIME + * format. For more information about HTML form encoding, consult the HTML + * specification. + * + *

+ * When encoding a String, the following rules apply: + * + *

    + *
  • The alphanumeric characters "{@code a}" through + * "{@code z}", "{@code A}" through + * "{@code Z}" and "{@code 0}" + * through "{@code 9}" remain the same. + *
  • The special characters "{@code .}", + * "{@code -}", "{@code *}", and + * "{@code _}" remain the same. + *
  • The space character "   " is + * converted into a plus sign "{@code +}". + *
  • All other characters are unsafe and are first converted into + * one or more bytes using some encoding scheme. Then each byte is + * represented by the 3-character string + * "{@code %xy}", where xy is the + * two-digit hexadecimal representation of the byte. + * The recommended encoding scheme to use is UTF-8. However, + * for compatibility reasons, if an encoding is not specified, + * then the default encoding of the platform is used. + *
+ * + *

+ * For example using UTF-8 as the encoding scheme the string "The + * string ü@foo-bar" would get converted to + * "The+string+%C3%BC%40foo-bar" because in UTF-8 the character + * ü is encoded as two bytes C3 (hex) and BC (hex), and the + * character @ is encoded as one byte 40 (hex). + * + * @author Herb Jellinek + * @since JDK1.0 + */ +public class URLEncoder { + static BitSet dontNeedEncoding; + static final int caseDiff = ('a' - 'A'); + static String dfltEncName = null; + + static { + + /* The list of characters that are not encoded has been + * determined as follows: + * + * RFC 2396 states: + * ----- + * Data characters that are allowed in a URI but do not have a + * reserved purpose are called unreserved. These include upper + * and lower case letters, decimal digits, and a limited set of + * punctuation marks and symbols. + * + * unreserved = alphanum | mark + * + * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" + * + * Unreserved characters can be escaped without changing the + * semantics of the URI, but this should not be done unless the + * URI is being used in a context that does not allow the + * unescaped character to appear. + * ----- + * + * It appears that both Netscape and Internet Explorer escape + * all special characters from this list with the exception + * of "-", "_", ".", "*". While it is not clear why they are + * escaping the other characters, perhaps it is safest to + * assume that there might be contexts in which the others + * are unsafe if not escaped. Therefore, we will use the same + * list. It is also noteworthy that this is consistent with + * O'Reilly's "HTML: The Definitive Guide" (page 164). + * + * As a last note, Intenet Explorer does not encode the "@" + * character which is clearly not unreserved according to the + * RFC. We are being consistent with the RFC in this matter, + * as is Netscape. + * + */ + + dontNeedEncoding = new BitSet(256); + int i; + for (i = 'a'; i <= 'z'; i++) { + dontNeedEncoding.set(i); + } + for (i = 'A'; i <= 'Z'; i++) { + dontNeedEncoding.set(i); + } + for (i = '0'; i <= '9'; i++) { + dontNeedEncoding.set(i); + } + dontNeedEncoding.set(' '); /* encoding a space to a + is done + * in the encode() method */ + dontNeedEncoding.set('-'); + dontNeedEncoding.set('_'); + dontNeedEncoding.set('.'); + dontNeedEncoding.set('*'); + + dfltEncName = AccessController.doPrivileged( + new GetPropertyAction("file.encoding") + ); + } + + /** + * You can't call the constructor. + */ + private URLEncoder() { } + + /** + * Translates a string into {@code x-www-form-urlencoded} + * format. This method uses the platform's default encoding + * as the encoding scheme to obtain the bytes for unsafe characters. + * + * @param s {@code String} to be translated. + * @deprecated The resulting string may vary depending on the platform's + * default encoding. Instead, use the encode(String,String) + * method to specify the encoding. + * @return the translated {@code String}. + */ + @Deprecated + public static String encode(String s) { + + String str = null; + + try { + str = encode(s, dfltEncName); + } catch (UnsupportedEncodingException e) { + // The system should always have the platform default + } + + return str; + } + + /** + * Translates a string into {@code application/x-www-form-urlencoded} + * format using a specific encoding scheme. This method uses the + * supplied encoding scheme to obtain the bytes for unsafe + * characters. + *

+ * Note: The + * World Wide Web Consortium Recommendation states that + * UTF-8 should be used. Not doing so may introduce + * incompatibilities. + * + * @param s {@code String} to be translated. + * @param enc The name of a supported + * character + * encoding. + * @return the translated {@code String}. + * @exception UnsupportedEncodingException + * If the named encoding is not supported + * @see URLDecoder#decode(java.lang.String, java.lang.String) + * @since 1.4 + */ + public static String encode(String s, String enc) + throws UnsupportedEncodingException { + + boolean needToChange = false; + StringBuffer out = new StringBuffer(s.length()); + Charset charset; + CharArrayWriter charArrayWriter = new CharArrayWriter(); + + if (enc == null) + throw new NullPointerException("charsetName"); + + try { + charset = Charset.forName(enc); + } catch (IllegalCharsetNameException e) { + throw new UnsupportedEncodingException(enc); + } catch (UnsupportedCharsetException e) { + throw new UnsupportedEncodingException(enc); + } + + for (int i = 0; i < s.length();) { + int c = (int) s.charAt(i); + //System.out.println("Examining character: " + c); + if (dontNeedEncoding.get(c)) { + if (c == ' ') { + c = '+'; + needToChange = true; + } + //System.out.println("Storing: " + c); + out.append((char)c); + i++; + } else { + // convert to external encoding before hex conversion + do { + charArrayWriter.write(c); + /* + * If this character represents the start of a Unicode + * surrogate pair, then pass in two characters. It's not + * clear what should be done if a bytes reserved in the + * surrogate pairs range occurs outside of a legal + * surrogate pair. For now, just treat it as if it were + * any other character. + */ + if (c >= 0xD800 && c <= 0xDBFF) { + /* + System.out.println(Integer.toHexString(c) + + " is high surrogate"); + */ + if ( (i+1) < s.length()) { + int d = (int) s.charAt(i+1); + /* + System.out.println("\tExamining " + + Integer.toHexString(d)); + */ + if (d >= 0xDC00 && d <= 0xDFFF) { + /* + System.out.println("\t" + + Integer.toHexString(d) + + " is low surrogate"); + */ + charArrayWriter.write(d); + i++; + } + } + } + i++; + } while (i < s.length() && !dontNeedEncoding.get((c = (int) s.charAt(i)))); + + charArrayWriter.flush(); + String str = new String(charArrayWriter.toCharArray()); + byte[] ba = str.getBytes(charset); + for (int j = 0; j < ba.length; j++) { + out.append('%'); + char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16); + // converting to use uppercase letter as part of + // the hex value if ch is a letter. + if (Character.isLetter(ch)) { + ch -= caseDiff; + } + out.append(ch); + ch = Character.forDigit(ba[j] & 0xF, 16); + if (Character.isLetter(ch)) { + ch -= caseDiff; + } + out.append(ch); + } + charArrayWriter.reset(); + needToChange = true; + } + } + + return (needToChange? out.toString() : s); + } +} diff --git a/src/main/java/java/util/AbstractList.java b/src/main/java/java/util/AbstractList.java new file mode 100644 index 0000000..91745e5 --- /dev/null +++ b/src/main/java/java/util/AbstractList.java @@ -0,0 +1,895 @@ +/* + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import org.cprover.CProver; + +/** + * This class provides a skeletal implementation of the {@link List} + * interface to minimize the effort required to implement this interface + * backed by a "random access" data store (such as an array). For sequential + * access data (such as a linked list), {@link AbstractSequentialList} should + * be used in preference to this class. + * + *

To implement an unmodifiable list, the programmer needs only to extend + * this class and provide implementations for the {@link #get(int)} and + * {@link List#size() size()} methods. + * + *

To implement a modifiable list, the programmer must additionally + * override the {@link #set(int, Object) set(int, E)} method (which otherwise + * throws an {@code UnsupportedOperationException}). If the list is + * variable-size the programmer must additionally override the + * {@link #add(int, Object) add(int, E)} and {@link #remove(int)} methods. + * + *

The programmer should generally provide a void (no argument) and collection + * constructor, as per the recommendation in the {@link Collection} interface + * specification. + * + *

Unlike the other abstract collection implementations, the programmer does + * not have to provide an iterator implementation; the iterator and + * list iterator are implemented by this class, on top of the "random access" + * methods: + * {@link #get(int)}, + * {@link #set(int, Object) set(int, E)}, + * {@link #add(int, Object) add(int, E)} and + * {@link #remove(int)}. + * + *

The documentation for each non-abstract method in this class describes its + * implementation in detail. Each of these methods may be overridden if the + * collection being implemented admits a more efficient implementation. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @author Josh Bloch + * @author Neal Gafter + * @since 1.2 + */ + +public abstract class AbstractList extends AbstractCollection implements List { + /** + * Sole constructor. (For invocation by subclass constructors, typically + * implicit.) + */ + protected AbstractList() { + // DIFFBLUE MODEL LIBRARY + // For JBMC to recognise the values of variables, they need to be + // assigned within a constructor. + modCount = 0; + } + + /** + * Appends the specified element to the end of this list (optional + * operation). + * + *

Lists that support this operation may place limitations on what + * elements may be added to this list. In particular, some + * lists will refuse to add null elements, and others will impose + * restrictions on the type of elements that may be added. List + * classes should clearly specify in their documentation any restrictions + * on what elements may be added. + * + *

This implementation calls {@code add(size(), e)}. + * + *

Note that this implementation throws an + * {@code UnsupportedOperationException} unless + * {@link #add(int, Object) add(int, E)} is overridden. + * + * @param e element to be appended to this list + * @return {@code true} (as specified by {@link Collection#add}) + * @throws UnsupportedOperationException if the {@code add} operation + * is not supported by this list + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this list + * @throws NullPointerException if the specified element is null and this + * list does not permit null elements + * @throws IllegalArgumentException if some property of this element + * prevents it from being added to this list + */ + public boolean add(E e) { + add(size(), e); + return true; + } + + /** + * {@inheritDoc} + * + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + abstract public E get(int index); + + /** + * {@inheritDoc} + * + *

This implementation always throws an + * {@code UnsupportedOperationException}. + * + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public E set(int index, E element) { + // throw new UnsupportedOperationException(); + CProver.notModelled(); + return CProver.nondetWithNullForNotModelled(); + } + + /** + * {@inheritDoc} + * + *

This implementation always throws an + * {@code UnsupportedOperationException}. + * + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public void add(int index, E element) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + * + *

This implementation always throws an + * {@code UnsupportedOperationException}. + * + * @throws UnsupportedOperationException {@inheritDoc} + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public E remove(int index) { + throw new UnsupportedOperationException(); + } + + + // Search Operations + + /** + * {@inheritDoc} + * + *

This implementation first gets a list iterator (with + * {@code listIterator()}). Then, it iterates over the list until the + * specified element is found or the end of the list is reached. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public int indexOf(Object o) { + // ListIterator it = listIterator(); + // if (o==null) { + // while (it.hasNext()) + // if (it.next()==null) + // return it.previousIndex(); + // } else { + // while (it.hasNext()) + // if (o.equals(it.next())) + // return it.previousIndex(); + // } + // return -1; + CProver.notModelled(); + return CProver.nondetInt(); + } + + /** + * {@inheritDoc} + * + *

This implementation first gets a list iterator that points to the end + * of the list (with {@code listIterator(size())}). Then, it iterates + * backwards over the list until the specified element is found, or the + * beginning of the list is reached. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public int lastIndexOf(Object o) { + // ListIterator it = listIterator(size()); + // if (o==null) { + // while (it.hasPrevious()) + // if (it.previous()==null) + // return it.nextIndex(); + // } else { + // while (it.hasPrevious()) + // if (o.equals(it.previous())) + // return it.nextIndex(); + // } + // return -1; + CProver.notModelled(); + return CProver.nondetInt(); + } + + + // Bulk Operations + + /** + * Removes all of the elements from this list (optional operation). + * The list will be empty after this call returns. + * + *

This implementation calls {@code removeRange(0, size())}. + * + *

Note that this implementation throws an + * {@code UnsupportedOperationException} unless {@code remove(int + * index)} or {@code removeRange(int fromIndex, int toIndex)} is + * overridden. + * + * @throws UnsupportedOperationException if the {@code clear} operation + * is not supported by this list + */ + public void clear() { + // removeRange(0, size()); + CProver.notModelled(); + } + + /** + * {@inheritDoc} + * + *

This implementation gets an iterator over the specified collection + * and iterates over it, inserting the elements obtained from the + * iterator into this list at the appropriate position, one at a time, + * using {@code add(int, E)}. + * Many implementations will override this method for efficiency. + * + *

Note that this implementation throws an + * {@code UnsupportedOperationException} unless + * {@link #add(int, Object) add(int, E)} is overridden. + * + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public boolean addAll(int index, Collection c) { + rangeCheckForAdd(index); + boolean modified = false; + for (E e : c) { + add(index++, e); + modified = true; + } + return modified; + } + + + // Iterators + + /** + * Returns an iterator over the elements in this list in proper sequence. + * + *

This implementation returns a straightforward implementation of the + * iterator interface, relying on the backing list's {@code size()}, + * {@code get(int)}, and {@code remove(int)} methods. + * + *

Note that the iterator returned by this method will throw an + * {@link UnsupportedOperationException} in response to its + * {@code remove} method unless the list's {@code remove(int)} method is + * overridden. + * + *

This implementation can be made to throw runtime exceptions in the + * face of concurrent modification, as described in the specification + * for the (protected) {@link #modCount} field. + * + * @return an iterator over the elements in this list in proper sequence + */ + public Iterator iterator() { + return new Itr(); + } + + /** + * {@inheritDoc} + * + *

This implementation returns {@code listIterator(0)}. + * + * @see #listIterator(int) + * + * @diffblue.fullSupport + * @diffblue.untested + */ + // DIFFBLUE MODEL LIBRARY + // This method is inherited by ArrayList$SubList. + public ListIterator listIterator() { + return listIterator(0); + } + + /** + * {@inheritDoc} + * + *

This implementation returns a straightforward implementation of the + * {@code ListIterator} interface that extends the implementation of the + * {@code Iterator} interface returned by the {@code iterator()} method. + * The {@code ListIterator} implementation relies on the backing list's + * {@code get(int)}, {@code set(int, E)}, {@code add(int, E)} + * and {@code remove(int)} methods. + * + *

Note that the list iterator returned by this implementation will + * throw an {@link UnsupportedOperationException} in response to its + * {@code remove}, {@code set} and {@code add} methods unless the + * list's {@code remove(int)}, {@code set(int, E)}, and + * {@code add(int, E)} methods are overridden. + * + *

This implementation can be made to throw runtime exceptions in the + * face of concurrent modification, as described in the specification for + * the (protected) {@link #modCount} field. + * + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public ListIterator listIterator(final int index) { + // rangeCheckForAdd(index); + + // return new ListItr(index); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + private class Itr implements Iterator { + /** + * Index of element to be returned by subsequent call to next. + */ + int cursor = 0; + + /** + * Index of element returned by most recent call to next or + * previous. Reset to -1 if this element is deleted by a call + * to remove. + */ + int lastRet = -1; + + /** + * The modCount value that the iterator believes that the backing + * List should have. If this expectation is violated, the iterator + * has detected concurrent modification. + */ + int expectedModCount = modCount; + + // DIFFBLUE MODEL LIBRARY + // For JBMC to recognise the values of variables, they need to be + // assigned within a constructor. + Itr() { + cursor = 0; + lastRet = -1; + expectedModCount = modCount; + } + + public boolean hasNext() { + return cursor != size(); + } + + public E next() { + checkForComodification(); + try { + int i = cursor; + E next = get(i); + lastRet = i; + cursor = i + 1; + return next; + } catch (IndexOutOfBoundsException e) { + checkForComodification(); + throw new NoSuchElementException(); + } + } + + public void remove() { + if (lastRet < 0) + throw new IllegalStateException(); + checkForComodification(); + + try { + AbstractList.this.remove(lastRet); + if (lastRet < cursor) + cursor--; + lastRet = -1; + expectedModCount = modCount; + } catch (IndexOutOfBoundsException e) { + throw new ConcurrentModificationException(); + } + } + + final void checkForComodification() { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + } + } + + private class ListItr extends Itr implements ListIterator { + ListItr(int index) { + // DIFFBLUE MODEL LIBRARY + // Include call to Itr constructor + super(); + cursor = index; + } + + public boolean hasPrevious() { + return cursor != 0; + } + + public E previous() { + checkForComodification(); + try { + int i = cursor - 1; + E previous = get(i); + lastRet = cursor = i; + return previous; + } catch (IndexOutOfBoundsException e) { + checkForComodification(); + throw new NoSuchElementException(); + } + } + + public int nextIndex() { + return cursor; + } + + public int previousIndex() { + return cursor-1; + } + + public void set(E e) { + if (lastRet < 0) + throw new IllegalStateException(); + checkForComodification(); + + try { + AbstractList.this.set(lastRet, e); + expectedModCount = modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + public void add(E e) { + checkForComodification(); + + try { + int i = cursor; + AbstractList.this.add(i, e); + lastRet = -1; + cursor = i + 1; + expectedModCount = modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + } + + /** + * {@inheritDoc} + * + *

This implementation returns a list that subclasses + * {@code AbstractList}. The subclass stores, in private fields, the + * offset of the subList within the backing list, the size of the subList + * (which can change over its lifetime), and the expected + * {@code modCount} value of the backing list. There are two variants + * of the subclass, one of which implements {@code RandomAccess}. + * If this list implements {@code RandomAccess} the returned list will + * be an instance of the subclass that implements {@code RandomAccess}. + * + *

The subclass's {@code set(int, E)}, {@code get(int)}, + * {@code add(int, E)}, {@code remove(int)}, {@code addAll(int, + * Collection)} and {@code removeRange(int, int)} methods all + * delegate to the corresponding methods on the backing abstract list, + * after bounds-checking the index and adjusting for the offset. The + * {@code addAll(Collection c)} method merely returns {@code addAll(size, + * c)}. + * + *

The {@code listIterator(int)} method returns a "wrapper object" + * over a list iterator on the backing list, which is created with the + * corresponding method on the backing list. The {@code iterator} method + * merely returns {@code listIterator()}, and the {@code size} method + * merely returns the subclass's {@code size} field. + * + *

All methods first check to see if the actual {@code modCount} of + * the backing list is equal to its expected value, and throw a + * {@code ConcurrentModificationException} if it is not. + * + * @throws IndexOutOfBoundsException if an endpoint index value is out of range + * {@code (fromIndex < 0 || toIndex > size)} + * @throws IllegalArgumentException if the endpoint indices are out of order + * {@code (fromIndex > toIndex)} + */ + public List subList(int fromIndex, int toIndex) { + // return (this instanceof RandomAccess ? + // new RandomAccessSubList<>(this, fromIndex, toIndex) : + // new SubList<>(this, fromIndex, toIndex)); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + // Comparison and hashing + + /** + * Compares the specified object with this list for equality. Returns + * {@code true} if and only if the specified object is also a list, both + * lists have the same size, and all corresponding pairs of elements in + * the two lists are equal. (Two elements {@code e1} and + * {@code e2} are equal if {@code (e1==null ? e2==null : + * e1.equals(e2))}.) In other words, two lists are defined to be + * equal if they contain the same elements in the same order.

+ * + * This implementation first checks if the specified object is this + * list. If so, it returns {@code true}; if not, it checks if the + * specified object is a list. If not, it returns {@code false}; if so, + * it iterates over both lists, comparing corresponding pairs of elements. + * If any comparison returns {@code false}, this method returns + * {@code false}. If either iterator runs out of elements before the + * other it returns {@code false} (as the lists are of unequal length); + * otherwise it returns {@code true} when the iterations complete. + * + * @param o the object to be compared for equality with this list + * @return {@code true} if the specified object is equal to this list + */ + // DIFFBLUE MODEL LIBRARY + // We currently cannot enable this method, or it will cause infinite + // unwinding loops for methods in ArrayList that use Object.equals, like + // remove(Object) and contains(Object). + public boolean equals(Object o) { + // if (o == this) + // return true; + // if (!(o instanceof List)) + // return false; + + // ListIterator e1 = listIterator(); + // ListIterator e2 = ((List) o).listIterator(); + // while (e1.hasNext() && e2.hasNext()) { + // E o1 = e1.next(); + // Object o2 = e2.next(); + // if (!(o1==null ? o2==null : o1.equals(o2))) + // return false; + // } + // return !(e1.hasNext() || e2.hasNext()); + CProver.notModelled(); + return CProver.nondetBoolean(); + } + + /** + * Returns the hash code value for this list. + * + *

This implementation uses exactly the code that is used to define the + * list hash function in the documentation for the {@link List#hashCode} + * method. + * + * @return the hash code value for this list + */ + // DIFFBLUE MODEL LIBRARY + // Always returns 0, for consistency with Object.hashCode(). + public int hashCode() { + // int hashCode = 1; + // for (E e : this) + // hashCode = 31*hashCode + (e==null ? 0 : e.hashCode()); + // return hashCode; + return 0; + } + + /** + * Removes from this list all of the elements whose index is between + * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive. + * Shifts any succeeding elements to the left (reduces their index). + * This call shortens the list by {@code (toIndex - fromIndex)} elements. + * (If {@code toIndex==fromIndex}, this operation has no effect.) + * + *

This method is called by the {@code clear} operation on this list + * and its subLists. Overriding this method to take advantage of + * the internals of the list implementation can substantially + * improve the performance of the {@code clear} operation on this list + * and its subLists. + * + *

This implementation gets a list iterator positioned before + * {@code fromIndex}, and repeatedly calls {@code ListIterator.next} + * followed by {@code ListIterator.remove} until the entire range has + * been removed. Note: if {@code ListIterator.remove} requires linear + * time, this implementation requires quadratic time. + * + * @param fromIndex index of first element to be removed + * @param toIndex index after last element to be removed + */ + protected void removeRange(int fromIndex, int toIndex) { + // ListIterator it = listIterator(fromIndex); + // for (int i=0, n=toIndex-fromIndex; istructurally modified. + * Structural modifications are those that change the size of the + * list, or otherwise perturb it in such a fashion that iterations in + * progress may yield incorrect results. + * + *

This field is used by the iterator and list iterator implementation + * returned by the {@code iterator} and {@code listIterator} methods. + * If the value of this field changes unexpectedly, the iterator (or list + * iterator) will throw a {@code ConcurrentModificationException} in + * response to the {@code next}, {@code remove}, {@code previous}, + * {@code set} or {@code add} operations. This provides + * fail-fast behavior, rather than non-deterministic behavior in + * the face of concurrent modification during iteration. + * + *

Use of this field by subclasses is optional. If a subclass + * wishes to provide fail-fast iterators (and list iterators), then it + * merely has to increment this field in its {@code add(int, E)} and + * {@code remove(int)} methods (and any other methods that it overrides + * that result in structural modifications to the list). A single call to + * {@code add(int, E)} or {@code remove(int)} must add no more than + * one to this field, or the iterators (and list iterators) will throw + * bogus {@code ConcurrentModificationExceptions}. If an implementation + * does not wish to provide fail-fast iterators, this field may be + * ignored. + */ + protected transient int modCount = 0; + + // DIFFBLUE MODEL LIBRARY + // String operations can significantly slow down JBMC in some + // cases. This should be reviewed again with improved versions of the string + // solver. + private void rangeCheckForAdd(int index) { + if (index < 0 || index > size()) + // throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + throw new IndexOutOfBoundsException(); + } + + // DIFFBLUE MODEL LIBRARY + // String operations can significantly slow down JBMC in some + // cases. This should be reviewed again with improved versions of the string + // solver. + // private String outOfBoundsMsg(int index) { + // return "Index: "+index+", Size: "+size(); + // } + + /** + * @diffblue.fullSupport + * In the JDK, this method is inherited from AbstractCollection. + * This may be slow to generate traces for LinkedList-type + * Lists. + * See docs in {@link AbstractCollection#toString()} + */ + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + b.append('['); + + int len = size(); + // append first length - 1 elements + for (int i = 0; i < len - 1; i++) { + b.append(get(i)); + b.append(", "); + } + + // then the final element + if (len > 0) { + b.append(get(len - 1)); + } + + b.append(']'); + return b.toString(); + } + + // DIFFBLUE MODEL LIBRARY + // This method is called by CBMC just after nondeterministic object + // creation, i.e. the constraints that it specifies are only enforced at + // that time and do not have to hold globally. + // We generally want to make sure that all necessary invariants of the class + // are satisfied, and potentially restrict some fields to speed up test + // generation. + @org.cprover.MustNotThrow + protected void cproverNondetInitialize() { + CProver.assume(modCount >= 0); + } +} + +class SubList extends AbstractList { + private final AbstractList l; + private final int offset; + private int size; + + // DIFFBLUE MODEL LIBRARY + // String operations can significantly slow down JBMC in some + // cases. This should be reviewed again with improved versions of the string + // solver. + SubList(AbstractList list, int fromIndex, int toIndex) { + if (fromIndex < 0) + // throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); + throw new IndexOutOfBoundsException(); + if (toIndex > list.size()) + // throw new IndexOutOfBoundsException("toIndex = " + toIndex); + throw new IndexOutOfBoundsException(); + if (fromIndex > toIndex) + // throw new IllegalArgumentException("fromIndex(" + fromIndex + + // ") > toIndex(" + toIndex + ")"); + throw new IllegalArgumentException(); + l = list; + offset = fromIndex; + size = toIndex - fromIndex; + this.modCount = l.modCount; + } + + public E set(int index, E element) { + rangeCheck(index); + checkForComodification(); + return l.set(index+offset, element); + } + + public E get(int index) { + rangeCheck(index); + checkForComodification(); + return l.get(index+offset); + } + + public int size() { + checkForComodification(); + return size; + } + + public void add(int index, E element) { + rangeCheckForAdd(index); + checkForComodification(); + l.add(index+offset, element); + this.modCount = l.modCount; + size++; + } + + public E remove(int index) { + rangeCheck(index); + checkForComodification(); + E result = l.remove(index+offset); + this.modCount = l.modCount; + size--; + return result; + } + + protected void removeRange(int fromIndex, int toIndex) { + checkForComodification(); + l.removeRange(fromIndex+offset, toIndex+offset); + this.modCount = l.modCount; + size -= (toIndex-fromIndex); + } + + public boolean addAll(Collection c) { + return addAll(size, c); + } + + public boolean addAll(int index, Collection c) { + rangeCheckForAdd(index); + int cSize = c.size(); + if (cSize==0) + return false; + + checkForComodification(); + l.addAll(offset+index, c); + this.modCount = l.modCount; + size += cSize; + return true; + } + + public Iterator iterator() { + return listIterator(); + } + + public ListIterator listIterator(final int index) { + checkForComodification(); + rangeCheckForAdd(index); + + return new ListIterator() { + private final ListIterator i = l.listIterator(index+offset); + + public boolean hasNext() { + return nextIndex() < size; + } + + public E next() { + if (hasNext()) + return i.next(); + else + throw new NoSuchElementException(); + } + + public boolean hasPrevious() { + return previousIndex() >= 0; + } + + public E previous() { + if (hasPrevious()) + return i.previous(); + else + throw new NoSuchElementException(); + } + + public int nextIndex() { + return i.nextIndex() - offset; + } + + public int previousIndex() { + return i.previousIndex() - offset; + } + + public void remove() { + i.remove(); + SubList.this.modCount = l.modCount; + size--; + } + + public void set(E e) { + i.set(e); + } + + public void add(E e) { + i.add(e); + SubList.this.modCount = l.modCount; + size++; + } + }; + } + + public List subList(int fromIndex, int toIndex) { + return new SubList<>(this, fromIndex, toIndex); + } + + // DIFFBLUE MODEL LIBRARY + // String operations can significantly slow down JBMC in some + // cases. This should be reviewed again with improved versions of the string + // solver. + private void rangeCheck(int index) { + if (index < 0 || index >= size) + // throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + throw new IndexOutOfBoundsException(); + } + + // DIFFBLUE MODEL LIBRARY + // String operations can significantly slow down JBMC in some + // cases. This should be reviewed again with improved versions of the string + // solver. + private void rangeCheckForAdd(int index) { + if (index < 0 || index > size) + // throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + throw new IndexOutOfBoundsException(); + } + + // DIFFBLUE MODEL LIBRARY + // String operations can significantly slow down JBMC in some + // cases. This should be reviewed again with improved versions of the string + // solver. + // private String outOfBoundsMsg(int index) { + // return "Index: "+index+", Size: "+size; + // } + + private void checkForComodification() { + if (this.modCount != l.modCount) + throw new ConcurrentModificationException(); + } +} + +class RandomAccessSubList extends SubList implements RandomAccess { + RandomAccessSubList(AbstractList list, int fromIndex, int toIndex) { + super(list, fromIndex, toIndex); + } + + public List subList(int fromIndex, int toIndex) { + return new RandomAccessSubList<>(this, fromIndex, toIndex); + } +} diff --git a/src/main/java/java/util/AbstractSet.java b/src/main/java/java/util/AbstractSet.java new file mode 100644 index 0000000..2761023 --- /dev/null +++ b/src/main/java/java/util/AbstractSet.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import org.cprover.CProver; + +/** + * This class provides a skeletal implementation of the Set + * interface to minimize the effort required to implement this + * interface.

+ * + * The process of implementing a set by extending this class is identical + * to that of implementing a Collection by extending AbstractCollection, + * except that all of the methods and constructors in subclasses of this + * class must obey the additional constraints imposed by the Set + * interface (for instance, the add method must not permit addition of + * multiple instances of an object to a set).

+ * + * Note that this class does not override any of the implementations from + * the AbstractCollection class. It merely adds implementations + * for equals and hashCode.

+ * + * This class is a member of the + * + * Java Collections Framework. + * + * @param the type of elements maintained by this set + * + * @author Josh Bloch + * @author Neal Gafter + * @see Collection + * @see AbstractCollection + * @see Set + * @since 1.2 + */ + +public abstract class AbstractSet extends AbstractCollection implements Set { + /** + * Sole constructor. (For invocation by subclass constructors, typically + * implicit.) + */ + protected AbstractSet() { + } + + // Comparison and hashing + + /** + * Compares the specified object with this set for equality. Returns + * true if the given object is also a set, the two sets have + * the same size, and every member of the given set is contained in + * this set. This ensures that the equals method works + * properly across different implementations of the Set + * interface.

+ * + * This implementation first checks if the specified object is this + * set; if so it returns true. Then, it checks if the + * specified object is a set whose size is identical to the size of + * this set; if not, it returns false. If so, it returns + * containsAll((Collection) o). + * + * @param o object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + public boolean equals(Object o) { + // if (o == this) + // return true; + + // if (!(o instanceof Set)) + // return false; + // Collection c = (Collection) o; + // if (c.size() != size()) + // return false; + // try { + // return containsAll(c); + // } catch (ClassCastException unused) { + // return false; + // } catch (NullPointerException unused) { + // return false; + // } + CProver.notModelled(); + return CProver.nondetBoolean(); + } + + /** + * Returns the hash code value for this set. The hash code of a set is + * defined to be the sum of the hash codes of the elements in the set, + * where the hash code of a null element is defined to be zero. + * This ensures that s1.equals(s2) implies that + * s1.hashCode()==s2.hashCode() for any two sets s1 + * and s2, as required by the general contract of + * {@link Object#hashCode}. + * + *

This implementation iterates over the set, calling the + * hashCode method on each element in the set, and adding up + * the results. + * + * @return the hash code value for this set + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + public int hashCode() { + // int h = 0; + // Iterator i = iterator(); + // while (i.hasNext()) { + // E obj = i.next(); + // if (obj != null) + // h += obj.hashCode(); + // } + // return h; + return 0; + } + + /** + * Removes from this set all of its elements that are contained in the + * specified collection (optional operation). If the specified + * collection is also a set, this operation effectively modifies this + * set so that its value is the asymmetric set difference of + * the two sets. + * + *

This implementation determines which is the smaller of this set + * and the specified collection, by invoking the size + * method on each. If this set has fewer elements, then the + * implementation iterates over this set, checking each element + * returned by the iterator in turn to see if it is contained in + * the specified collection. If it is so contained, it is removed + * from this set with the iterator's remove method. If + * the specified collection has fewer elements, then the + * implementation iterates over the specified collection, removing + * from this set each element returned by the iterator, using this + * set's remove method. + * + *

Note that this implementation will throw an + * UnsupportedOperationException if the iterator returned by the + * iterator method does not implement the remove method. + * + * @param c collection containing elements to be removed from this set + * @return true if this set changed as a result of the call + * @throws UnsupportedOperationException if the removeAll operation + * is not supported by this set + * @throws ClassCastException if the class of an element of this set + * is incompatible with the specified collection + * (optional) + * @throws NullPointerException if this set contains a null element and the + * specified collection does not permit null elements + * (optional), + * or if the specified collection is null + * @see #remove(Object) + * @see #contains(Object) + */ + public boolean removeAll(Collection c) { + // Objects.requireNonNull(c); + // boolean modified = false; + + // if (size() > c.size()) { + // for (Iterator i = c.iterator(); i.hasNext(); ) + // modified |= remove(i.next()); + // } else { + // for (Iterator i = iterator(); i.hasNext(); ) { + // if (c.contains(i.next())) { + // i.remove(); + // modified = true; + // } + // } + // } + // return modified; + CProver.notModelled(); + return CProver.nondetBoolean(); + } + + /* + * @diffblue.noSupport + * This method cannot be modelled because the iterator + * cannot be guaranteed to be return the elements in the same + * order from models-library as in the jdk. + * It is added here to override AbstractCollection as a safeguard so + * that if in the future toString() is implemented it more generally + * in AbstractCollection, this will not allow Sets to use that + * method, which would generate traces that do not pass because + * equality between the returned Strings cannot be asserted. + */ + @Override + public String toString() { + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + +} diff --git a/src/main/java/java/util/ArrayList.java b/src/main/java/java/util/ArrayList.java new file mode 100644 index 0000000..f378380 --- /dev/null +++ b/src/main/java/java/util/ArrayList.java @@ -0,0 +1,1853 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + +import org.cprover.CProver; + +/** + * Resizable-array implementation of the List interface. Implements + * all optional list operations, and permits all elements, including + * null. In addition to implementing the List interface, + * this class provides methods to manipulate the size of the array that is + * used internally to store the list. (This class is roughly equivalent to + * Vector, except that it is unsynchronized.) + * + *

The size, isEmpty, get, set, + * iterator, and listIterator operations run in constant + * time. The add operation runs in amortized constant time, + * that is, adding n elements requires O(n) time. All of the other operations + * run in linear time (roughly speaking). The constant factor is low compared + * to that for the LinkedList implementation. + *.grow + *

Each ArrayList instance has a capacity. The capacity is + * the size of the array used to store the elements in the list. It is always + * at least as large as the list size. As elements are added to an ArrayList, + * its capacity grows automatically. The details of the growth policy are not + * specified beyond the fact that adding an element has constant amortized + * time cost. + * + *

An application can increase the capacity of an ArrayList instance + * before adding a large number of elements using the ensureCapacity + * operation. This may reduce the amount of incremental reallocation. + * + *

Note that this implementation is not synchronized. + * If multiple threads access an ArrayList instance concurrently, + * and at least one of the threads modifies the list structurally, it + * must be synchronized externally. (A structural modification is + * any operation that adds or deletes one or more elements, or explicitly + * resizes the backing array; merely setting the value of an element is not + * a structural modification.) This is typically accomplished by + * synchronizing on some object that naturally encapsulates the list. + * + * If no such object exists, the list should be "wrapped" using the + * {@link Collections#synchronizedList Collections.synchronizedList} + * method. This is best done at creation time, to prevent accidental + * unsynchronized access to the list:

+ *   List list = Collections.synchronizedList(new ArrayList(...));
+ * + *

+ * The iterators returned by this class's {@link #iterator() iterator} and + * {@link #listIterator(int) listIterator} methods are fail-fast: + * if the list is structurally modified at any time after the iterator is + * created, in any way except through the iterator's own + * {@link ListIterator#remove() remove} or + * {@link ListIterator#add(Object) add} methods, the iterator will throw a + * {@link ConcurrentModificationException}. Thus, in the face of + * concurrent modification, the iterator fails quickly and cleanly, rather + * than risking arbitrary, non-deterministic behavior at an undetermined + * time in the future. + * + *

Note that the fail-fast behavior of an iterator cannot be guaranteed + * as it is, generally speaking, impossible to make any hard guarantees in the + * presence of unsynchronized concurrent modification. Fail-fast iterators + * throw {@code ConcurrentModificationException} on a best-effort basis. + * Therefore, it would be wrong to write a program that depended on this + * exception for its correctness: the fail-fast behavior of iterators + * should be used only to detect bugs. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @author Josh Bloch + * @author Neal Gafter + * @see Collection + * @see List + * @see LinkedList + * @see Vector + * @since 1.2 + * + * @diffblue.limitedSupport + *

+ * For performance reasons, there may be restrictions on the number of elements + * that can be stored in the model of ArrayList: + *

    + *
  • ArrayLists constructed using constructors of this class will have a + * fixed capacity of CProver.defaultContainerCapacity(). + *
  • Non-deterministic ArrayLists are limited by the JBMC + * parameter `--max-nondet-array-length`. + *
  • ArrayLists read from `--static-values` are currently unlimited. + *
+ */ + +public class ArrayList extends AbstractList + implements List, RandomAccess, Cloneable, java.io.Serializable +{ + private static final long serialVersionUID = 8683452581122892189L; + + /** + * Default initial capacity. + */ + private static final int DEFAULT_CAPACITY = 10; + + /** + * Shared empty array instance used for empty instances. + */ + // DIFFBLUE MODEL LIBRARY + // private static final Object[] EMPTY_ELEMENTDATA = {}; + + /** + * Shared empty array instance used for default sized empty instances. We + * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when + * first element is added. + */ + // DIFFBLUE MODEL LIBRARY + // private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; + + // DIFFBLUE MODEL LIBRARY + // Limit for the initialCapacity value passed as argument to a constructor. + // Prevents out of memory errors in the JVM when running generated traces. + // Actual behaviour will depend on the memory limits of the JVM. + static final int CPROVER_MAX_CAPACITY = 1 << 20; + + /** + * The array buffer into which the elements of the ArrayList are stored. + * The capacity of the ArrayList is the length of this array buffer. Any + * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA + * will be expanded to DEFAULT_CAPACITY when the first element is added. + */ + // DIFFBLUE MODEL LIBRARY + // We need to change the type of elementData for cbmc to recognise that only + // objects of type E are allowed to be added to it. In the original implementation + // this was ensured through the behaviour of constructors and methods alone. + // transient Object[] elementData; // non-private to simplify nested class access + transient E[] elementData; + + /** + * The size of the ArrayList (the number of elements it contains). + * + * @serial + */ + private int size; + + // DIFFBLUE MODEL LIBRARY + // Model variable which is true iff elementData in the implementation from + // the jdk would point to DEFAULTCAPACITY_EMPTY_ELEMENTDATA. + private boolean cproverIsDefaultCapacityEmpty; + + /** + * Constructs an empty list with the specified initial capacity. + * + * @param initialCapacity the initial capacity of the list + * @throws IllegalArgumentException if the specified initial capacity + * is negative + * + * @diffblue.limitedSupport + *

The initialCapacity value is limited to 2^27, to avoid + * generating tests that might exceed the memory limits of the JVM. + * The number of elements of an array list created this way is limited by + * CProver.defaultContainerCapacity() for performance reasons. + *

+ */ + // DIFFBLUE MODEL LIBRARY + // In the original implementation, when a new ArrayList object is created, + // the length of its elementData is a constant value. When this array gets + // full, a larger array is created and the contents of the original array + // are copied to the new one. + // Simulating this exact behaviour would lead to a high number of branches + // to be analysed by CBMC. To avoid this problem, we set the length of + // elementData in the model to be fixed to + // CProver.defaultContainerCapacity(). + // For this reason the number of elements of an array list created this way + // is limited by CProver.defaultContainerCapacity(). + // We also avoid string operations for exception messages, as they can + // negatively impact performance. + public ArrayList(int initialCapacity) { + // if (initialCapacity > 0) { + // this.elementData = new Object[initialCapacity]; + // } else if (initialCapacity == 0) { + // this.elementData = EMPTY_ELEMENTDATA; + // } else { + // throw new IllegalArgumentException("Illegal Capacity: "+ + // initialCapacity); + // } + CProver.assume(initialCapacity <= CPROVER_MAX_CAPACITY); + if (initialCapacity < 0) { + // throw new IllegalArgumentException("Illegal Capacity: "+ + // (initialCapacity)); + throw new IllegalArgumentException(); + } + CProver.assume(initialCapacity <= CPROVER_MAX_CAPACITY); + // elementData = (E[]) new Object[CProver.defaultContainerCapacity()]; + elementData = (E[]) new Object[DEFAULT_CAPACITY]; + size = 0; + modCount = 0; + cproverIsDefaultCapacityEmpty = false; + } + + /** + * Constructs an empty list with an initial capacity of ten. + * + * @diffblue.limitedSupport + *

The number of elements in the list is limited by + * CProver.defaultContainerCapacity(). + *

+ */ + public ArrayList() { + // this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; + // elementData = (E[]) new Object[CProver.defaultContainerCapacity()]; + elementData = (E[]) new Object[DEFAULT_CAPACITY]; + size = 0; + modCount = 0; + cproverIsDefaultCapacityEmpty = true; + } + + /** + * Constructs a list containing the elements of the specified + * collection, in the order they are returned by the collection's + * iterator. + * + * @param c the collection whose elements are to be placed into this list + * @throws NullPointerException if the specified collection is null + * + * @diffblue.limitedSupport + *

The number of elements in the list is limited to + * CProver.defaultContainerCapacity() for performance reasons. + *

+ */ + // DIFFBLUE MODEL LIBRARY + // Note that the original implementation uses + // elementData = c.toArray(); (using toArray:()[Ljava/lang/Object;) + // which creates a new array of fixed length c.size() and stores c's contents in it. + // In the model, we create an array of fixed size + // CProver.defaultContainerCapacity() and then call + // c.toArray(elementData); (using toArray:([Ljava/lang/Object;)[Ljava/lang/Object;) + // to store the contents of c in that array. + public ArrayList(Collection c) { + // elementData = c.toArray(); + // if ((size = elementData.length) != 0) { + // // c.toArray might (incorrectly) not return Object[] (see 6260652) + // if (elementData.getClass() != Object[].class) + // elementData = Arrays.copyOf(elementData, size, Object[].class); + // } else { + // // replace with empty array. + // this.elementData = EMPTY_ELEMENTDATA; + // } + size = c.size(); + // elementData = (E[]) new Object[CProver.defaultContainerCapacity()]; + elementData = (E[]) new Object[DEFAULT_CAPACITY]; + c.toArray(elementData); + cproverIsDefaultCapacityEmpty = false; + } + + /** + * Trims the capacity of this ArrayList instance to be the + * list's current size. An application can use this operation to minimize + * the storage of an ArrayList instance. + */ + // DIFFBLUE MODEL LIBRARY + // The only observable effect this method has on the model is incrementing + // modCount. Since we never change elementData.length in the model, the + // rest of it is ignored. + public void trimToSize() { + modCount++; + // if (size < elementData.length) { + // elementData = (size == 0) + // ? EMPTY_ELEMENTDATA + // : Arrays.copyOf(elementData, size); + // } + } + + /** + * Increases the capacity of this ArrayList instance, if + * necessary, to ensure that it can hold at least the number of elements + * specified by the minimum capacity argument. + * + * @param minCapacity the desired minimum capacity + */ + // DIFFBLUE MODEL LIBRARY + // The comparison of elementData and DEFAULTCAPACITY_EMPTY_ELEMENTDATA is + // replaced by conditioning on the value of the model variable + // cproverIsDefaultCapacityEmpty. We do not actually need to call + // ensureExplicitCapacity from this method in the model, incrementing + // modCount is enough and works better for nondeterministic ArrayLists. + public void ensureCapacity(int minCapacity) { + // int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) + // // any size if not default element table + // ? 0 + // // larger than default for default empty table. It's already + // // supposed to be at default size. + // : DEFAULT_CAPACITY; + int minExpand = (cproverIsDefaultCapacityEmpty) ? DEFAULT_CAPACITY : 0; + + if (minCapacity > minExpand) { + // ensureExplicitCapacity(minCapacity); + // DIFFBLUE MODEL LIBRARY Simplified call to ensureExplicitCapacity: + modCount++; + } + } + + // DIFFBLUE MODEL LIBRARY + // It is important that ensureCapacityInternal() still call ensureExplicitCapacity, + // since the latter increments modCount. + // Note that since we never actually use grow() in the model, the potential + // modification of minCapacity is not needed. + private void ensureCapacityInternal(int minCapacity) { + // if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { + // minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); + // } + + ensureExplicitCapacity(minCapacity); + } + + // DIFFBLUE MODEL LIBRARY + // Instead of growing the array, we validate that the existing array is big + // enough. We also need to set cproverIsDefaultCapacityEmpty to false, as + // either: + // - It was previously false, in which case it should stay false, or + // - It was previously true, meaning that elementData was set to + // DEFAULTCAPACITY_EMPTY_ELEMENTDATA, so minCapacity will be at least 10 + // when this method is called and elementData is modified in the jdk (by + // grow()) so it does no longer point to DEFAULTCAPACITY_EMPTY_ELEMENTDATA + // after a call to this method. + private void ensureExplicitCapacity(int minCapacity) { + modCount++; + cproverIsDefaultCapacityEmpty = false; + + // // overflow-conscious code + // if (minCapacity - elementData.length > 0) + // grow(minCapacity); + CProver.assume(elementData.length >= minCapacity); + } + + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** + * Increases the capacity to ensure that it can hold at least the + * number of elements specified by the minimum capacity argument. + * + * @param minCapacity the desired minimum capacity + */ + // DIFFBLUE MODEL LIBRARY + // This private method is not needed in the model. + // private void grow(int minCapacity) { + // // overflow-conscious code + // int oldCapacity = elementData.length; + // int newCapacity = oldCapacity + (oldCapacity >> 1); + // if (newCapacity - minCapacity < 0) + // newCapacity = minCapacity; + // if (newCapacity - MAX_ARRAY_SIZE > 0) + // newCapacity = hugeCapacity(minCapacity); + // // minCapacity is usually close to size, so this is a win: + // elementData = Arrays.copyOf(elementData, newCapacity); + // } + + // DIFFBLUE MODEL LIBRARY + // This private method is not needed in the model. + // private static int hugeCapacity(int minCapacity) { + // // if (minCapacity < 0) // overflow + // // throw new OutOfMemoryError(); + // // return (minCapacity > MAX_ARRAY_SIZE) ? + // // Integer.MAX_VALUE : + // // MAX_ARRAY_SIZE; + // CProver.notModelled(); + // return CProver.nondetInt(); + // } + + /** + * Returns the number of elements in this list. + * + * @return the number of elements in this list + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public int size() { + return size; + } + + /** + * Returns true if this list contains no elements. + * + * @return true if this list contains no elements + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns true if this list contains the specified element. + * More formally, returns true if and only if this list contains + * at least one element e such that + * (o==null ? e==null : o.equals(e)). + * + * @param o element whose presence in this list is to be tested + * @return true if this list contains the specified element + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public boolean contains(Object o) { + return indexOf(o) >= 0; + } + + /** + * Returns the index of the first occurrence of the specified element + * in this list, or -1 if this list does not contain the element. + * More formally, returns the lowest index i such that + * (o==null ? get(i)==null : o.equals(get(i))), + * or -1 if there is no such index. + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public int indexOf(Object o) { + if (o == null) { + for (int i = 0; i < size; i++) + if (elementData[i]==null) + return i; + } else { + for (int i = 0; i < size; i++) + if (o.equals(elementData[i])) + return i; + } + return -1; + } + + /** + * Returns the index of the last occurrence of the specified element + * in this list, or -1 if this list does not contain the element. + * More formally, returns the highest index i such that + * (o==null ? get(i)==null : o.equals(get(i))), + * or -1 if there is no such index. + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public int lastIndexOf(Object o) { + if (o == null) { + for (int i = size-1; i >= 0; i--) + if (elementData[i]==null) + return i; + } else { + for (int i = size-1; i >= 0; i--) + if (o.equals(elementData[i])) + return i; + } + return -1; + } + + /** + * Returns a shallow copy of this ArrayList instance. (The + * elements themselves are not copied.) + * + * @return a clone of this ArrayList instance + */ + // DIFFBLUE MODEL LIBRARY + // This behaves close to the corresponding method in the jdk, which is + // implemented natively. A shallow copy of the ArrayList is created: it has + // its own array, but the array elements are shared, and modifying an + // element in one of the two lists will also modify this element for the + // other. + // One small difference is that in the jdk, the clone is set to be of type + // ArrayList, while in the model we need to use ArrayList for + // performance reasons. + public Object clone() { + // try { + // ArrayList v = (ArrayList) super.clone(); + // v.elementData = Arrays.copyOf(elementData, size); + // v.modCount = 0; + // return v; + // } catch (CloneNotSupportedException e) { + // // this shouldn't happen, since we are Cloneable + // throw new InternalError(e); + // } + ArrayList v = new ArrayList(); + CProver.assume(v.elementData.length >= size); + for (int i = 0; i < size; i++) { + v.elementData[i] = elementData[i]; + } + v.modCount = 0; + v.size = size; + // DIFFBLUE MODEL LIBRARY + // This line may seem counterintuitive, but it is correct and a + // regression test exists for it. When an ArrayList is created using the + // default constructor with no arguments, and then clone() is called on + // this object, the elementData field of the cloned list does not point + // to DEFAULTCAPACITY_EMPTY_ELEMENTDATA in the JDK, since it was + // constructed by a call to + // Arrays.copyOf(DEFAULTCAPACITY_EMPTY_ELEMENTDATA, 0). + // So a cloned ArrayList will never have default capacity, even if the + // ArrayList it was cloned from did. + v.cproverIsDefaultCapacityEmpty = false; + return v; + } + + /** + * Returns an array containing all of the elements in this list + * in proper sequence (from first to last element). + * + *

The returned array will be "safe" in that no references to it are + * maintained by this list. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this list in + * proper sequence + * @diffblue.fullSupport + */ + // DIFFBLUE MODEL LIBRARY + // This method behaves like the corresponding method in the jdk, which is + // implemented natively (using System.arraycopy). + public Object[] toArray() { + return Arrays.copyOf(elementData, size); + } + + /** + * Returns an array containing all of the elements in this list in proper + * sequence (from first to last element); the runtime type of the returned + * array is that of the specified array. If the list fits in the + * specified array, it is returned therein. Otherwise, a new array is + * allocated with the runtime type of the specified array and the size of + * this list. + * + *

If the list fits in the specified array with room to spare + * (i.e., the array has more elements than the list), the element in + * the array immediately following the end of the collection is set to + * null. (This is useful in determining the length of the + * list only if the caller knows that the list does not contain + * any null elements.) + * + * @param a the array into which the elements of the list are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose. + * @return an array containing the elements of the list + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this list + * @throws NullPointerException if the specified array is null + * @diffblue.limitedSupport + * + * DIFFBLUE MODEL LIBRARY + * This behaves like the real JDK method, except that an ArrayStoreException + * won't be raised if you pass in an array that can't store the actual + * elements held in this container (the element will be stored regardless, + * and any type clash may never be detected) + */ + // @SuppressWarnings("unchecked") + // (the original JDK needed an unchecked cast here; we use the intrinsic + // CProver.createArrayWithType instead) + public T[] toArray(T[] a) { + // if (a.length < size) + // // Make a new array of a's runtime type, but my contents: + // return (T[]) Arrays.copyOf(elementData, size, a.getClass()); + // System.arraycopy(elementData, 0, a, 0, size); + // if (a.length > size) + // a[size] = null; + // return a; + if (a.length < size) { + // DIFFBLUE MODEL LIBRARY + // Object.getClass() is currently not modelled, so we need to use + // createArrayWithType to create a new array of the required type. + T[] newArray = CProver.createArrayWithType(size, a); + for (int i = 0; i < size; i++) { + newArray[i] = (T) elementData[i]; + } + return newArray; + } + for (int i = 0; i < size; i++) { + a[i] = (T) elementData[i]; + } + if (a.length > size) + a[size] = null; + return a; + } + + // Positional Access Operations + + @SuppressWarnings("unchecked") + // DIFFBLUE MODEL LIBRARY + // The type cast is needed in the jdk (where elementData is of type Object[]) + // but we do not need it in the model (as elementData is of type E[]). + E elementData(int index) { + // return (E) elementData[index]; + return elementData[index]; + } + + /** + * Returns the element at the specified position in this list. + * + * @param index index of the element to return + * @return the element at the specified position in this list + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public E get(int index) { + rangeCheck(index); + + return elementData(index); + } + + /** + * Replaces the element at the specified position in this list with + * the specified element. + * + * @param index index of the element to replace + * @param element element to be stored at the specified position + * @return the element previously at the specified position + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public E set(int index, E element) { + rangeCheck(index); + + E oldValue = elementData(index); + elementData[index] = element; + return oldValue; + } + + /** + * Appends the specified element to the end of this list. + * + * @param e element to be appended to this list + * @return true (as specified by {@link Collection#add}) + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public boolean add(E e) { + ensureCapacityInternal(size + 1); // Increments modCount!! + elementData[size++] = e; + return true; + } + + /** + * Inserts the specified element at the specified position in this + * list. Shifts the element currently at that position (if any) and + * any subsequent elements to the right (adds one to their indices). + * + * @param index index at which the specified element is to be inserted + * @param element element to be inserted + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk, except for System.arraycopy being replaced with + // a simpler for-loop. + public void add(int index, E element) { + rangeCheckForAdd(index); + + ensureCapacityInternal(size + 1); // Increments modCount!! + // System.arraycopy(elementData, index, elementData, index + 1, + // size - index); + // DIFFBLUE MODEL LIBRARY + // It is ok to move elements within the array without creating copies + // of them first, as long as higher indices are written to first. + for (int i = size; i > index; i--) { + elementData[i] = elementData[i-1]; + } + elementData[index] = element; + size++; + } + + /** + * Removes the element at the specified position in this list. + * Shifts any subsequent elements to the left (subtracts one from their + * indices). + * + * @param index the index of the element to be removed + * @return the element that was removed from the list + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + // DIFFBLUE MODEL LIBRARY + // System.arraycopy is replaced with a simpler for-loop, and memory + // management is ignored. + public E remove(int index) { + rangeCheck(index); + + modCount++; + E oldValue = elementData(index); + + // int numMoved = size - index - 1; + // if (numMoved > 0) + // System.arraycopy(elementData, index+1, elementData, index, + // numMoved); + // DIFFBLUE MODEL LIBRARY + // It is ok to move elements within the array without creating copies + // of them first, as long as lower indices are written to first. + for (int i = index; i < size - 1; i++) { + elementData[i] = elementData[i+1]; + } + // elementData[--size] = null; // clear to let GC do its work + size--; + + return oldValue; + } + + /** + * Removes the first occurrence of the specified element from this list, + * if it is present. If the list does not contain the element, it is + * unchanged. More formally, removes the element with the lowest index + * i such that + * (o==null ? get(i)==null : o.equals(get(i))) + * (if such an element exists). Returns true if this list + * contained the specified element (or equivalently, if this list + * changed as a result of the call). + * + * @param o element to be removed from this list, if present + * @return true if this list contained the specified element + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public boolean remove(Object o) { + if (o == null) { + for (int index = 0; index < size; index++) + if (elementData[index] == null) { + fastRemove(index); + return true; + } + } else { + for (int index = 0; index < size; index++) + if (o.equals(elementData[index])) { + fastRemove(index); + return true; + } + } + return false; + } + + /* + * Private remove method that skips bounds checking and does not + * return the value removed. + */ + // DIFFBLUE MODEL LIBRARY + // System.arraycopy is replaced with a simpler for-loop, and memory + // management is ignored. + private void fastRemove(int index) { + modCount++; + // int numMoved = size - index - 1; + // if (numMoved > 0) + // System.arraycopy(elementData, index+1, elementData, index, + // numMoved); + // DIFFBLUE MODEL LIBRARY + // It is ok to move elements within the array without creating copies + // of them first, as long as lower indices are written to first. + for (int i = index; i < size - 1; i++) { + elementData[i] = elementData[i+1]; + } + // elementData[--size] = null; // clear to let GC do its work + size--; + } + + /** + * Removes all of the elements from this list. The list will + * be empty after this call returns. + */ + // DIFFBLUE MODEL LIBRARY + // Memory management can be ignored in the model. + public void clear() { + modCount++; + + // // clear to let GC do its work + // for (int i = 0; i < size; i++) + // elementData[i] = null; + + size = 0; + } + + /** + * Appends all of the elements in the specified collection to the end of + * this list, in the order that they are returned by the + * specified collection's Iterator. The behavior of this operation is + * undefined if the specified collection is modified while the operation + * is in progress. (This implies that the behavior of this call is + * undefined if the specified collection is this list, and this + * list is nonempty.) + * + * @param c collection containing elements to be added to this list + * @return true if this list changed as a result of the call + * @throws NullPointerException if the specified collection is null + */ + // DIFFBLUE MODEL LIBRARY + // System.arraycopy is replaced with a simpler for-loop. + public boolean addAll(Collection c) { + E[] a = (E[]) c.toArray(); + int numNew = a.length; + ensureCapacityInternal(size + numNew); // Increments modCount + // System.arraycopy(a, 0, elementData, size, numNew); + for (int i = 0; i < numNew; i++) { + elementData[size+i] = a[i]; + } + size += numNew; + return numNew != 0; + } + + /** + * Inserts all of the elements in the specified collection into this + * list, starting at the specified position. Shifts the element + * currently at that position (if any) and any subsequent elements to + * the right (increases their indices). The new elements will appear + * in the list in the order that they are returned by the + * specified collection's iterator. + * + * @param index index at which to insert the first element from the + * specified collection + * @param c collection containing elements to be added to this list + * @return true if this list changed as a result of the call + * @throws IndexOutOfBoundsException {@inheritDoc} + * @throws NullPointerException if the specified collection is null + */ + // DIFFBLUE MODEL LIBRARY + // System.arraycopy is replaced with a simpler for-loop. + public boolean addAll(int index, Collection c) { + rangeCheckForAdd(index); + + E[] a = (E[]) c.toArray(); + int numNew = a.length; + ensureCapacityInternal(size + numNew); // Increments modCount + + // int numMoved = size - index; + // if (numMoved > 0) + // System.arraycopy(elementData, index, elementData, index + numNew, + // numMoved); + // DIFFBLUE MODEL LIBRARY + // It is ok to move elements within the array without creating copies + // of them first, as long as higher indices are written to first. + for (int i = size-1; i >= index; i--) { + elementData[i+numNew] = elementData[i]; + } + + // System.arraycopy(a, 0, elementData, index, numNew); + for (int i = 0; i < numNew; i++) { + elementData[index+i] = a[i]; + } + size += numNew; + return numNew != 0; + } + + /** + * Removes from this list all of the elements whose index is between + * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive. + * Shifts any succeeding elements to the left (reduces their index). + * This call shortens the list by {@code (toIndex - fromIndex)} elements. + * (If {@code toIndex==fromIndex}, this operation has no effect.) + * + * @throws IndexOutOfBoundsException if {@code fromIndex} or + * {@code toIndex} is out of range + * ({@code fromIndex < 0 || + * fromIndex >= size() || + * toIndex > size() || + * toIndex < fromIndex}) + */ + // DIFFBLUE MODEL LIBRARY + // System.arraycopy is replaced with a simpler for-loop, and memory + // management is ignored. + protected void removeRange(int fromIndex, int toIndex) { + modCount++; + int numMoved = size - toIndex; + // System.arraycopy(elementData, toIndex, elementData, fromIndex, + // numMoved); + // DIFFBLUE MODEL LIBRARY + // It is ok to move elements within the array without creating copies + // of them first, as long as lower indices are written to first. + for (int i = 0; i < numMoved; i++) { + elementData[fromIndex+i] = elementData[toIndex+i]; + } + + // // clear to let GC do its work + int newSize = size - (toIndex-fromIndex); + // for (int i = newSize; i < size; i++) { + // elementData[i] = null; + // } + size = newSize; + } + + /** + * Checks if the given index is in range. If not, throws an appropriate + * runtime exception. This method does *not* check if the index is + * negative: It is always used immediately prior to an array access, + * which throws an ArrayIndexOutOfBoundsException if index is negative. + */ + // DIFFBLUE MODEL LIBRARY + // String operations can significantly slow down JBMC in some + // cases. This should be reviewed again with improved versions of the string + // solver. + private void rangeCheck(int index) { + if (index >= size) + // throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + throw new IndexOutOfBoundsException(); + } + + /** + * A version of rangeCheck used by add and addAll. + */ + private void rangeCheckForAdd(int index) { + if (index > size || index < 0) + // throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + throw new IndexOutOfBoundsException(); + } + + /** + * Constructs an IndexOutOfBoundsException detail message. + * Of the many possible refactorings of the error handling code, + * this "outlining" performs best with both server and client VMs. + */ + // DIFFBLUE MODEL LIBRARY + // String operations can significantly slow down JBMC in some + // cases. This should be reviewed again with improved versions of the string + // solver. + // private String outOfBoundsMsg(int index) { + // return "Index: "+index+", Size: "+size; + // } + + /** + * Removes from this list all of its elements that are contained in the + * specified collection. + * + * @param c collection containing elements to be removed from this list + * @return {@code true} if this list changed as a result of the call + * @throws ClassCastException if the class of an element of this list + * is incompatible with the specified collection + * (optional) + * @throws NullPointerException if this list contains a null element and the + * specified collection does not permit null elements + * (optional), + * or if the specified collection is null + * @see Collection#contains(Object) + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public boolean removeAll(Collection c) { + Objects.requireNonNull(c); + return batchRemove(c, false); + } + + /** + * Retains only the elements in this list that are contained in the + * specified collection. In other words, removes from this list all + * of its elements that are not contained in the specified collection. + * + * @param c collection containing elements to be retained in this list + * @return {@code true} if this list changed as a result of the call + * @throws ClassCastException if the class of an element of this list + * is incompatible with the specified collection + * (optional) + * @throws NullPointerException if this list contains a null element and the + * specified collection does not permit null elements + * (optional), + * or if the specified collection is null + * @see Collection#contains(Object) + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public boolean retainAll(Collection c) { + Objects.requireNonNull(c); + return batchRemove(c, true); + } + + // DIFFBLUE MODEL LIBRARY + // System.arraycopy is replaced with a simpler for-loop, and memory + // management is ignored. + private boolean batchRemove(Collection c, boolean complement) { + final Object[] elementData = this.elementData; + int r = 0, w = 0; + boolean modified = false; + try { + for (; r < size; r++) + if (c.contains(elementData[r]) == complement) + elementData[w++] = elementData[r]; + } finally { + // Preserve behavioral compatibility with AbstractCollection, + // even if c.contains() throws. + if (r != size) { + // System.arraycopy(elementData, r, + // elementData, w, + // size - r); + for (int i = 0; i < size - r; i++) { + elementData[w+i] = elementData[r+i]; + } + w += size - r; + } + if (w != size) { + // clear to let GC do its work + // for (int i = w; i < size; i++) + // elementData[i] = null; + modCount += size - w; + size = w; + modified = true; + } + } + return modified; + } + + /** + * Save the state of the ArrayList instance to a stream (that + * is, serialize it). + * + * @serialData The length of the array backing the ArrayList + * instance is emitted (int), followed by all of its elements + * (each an Object) in the proper order. + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException{ + // // Write out element count, and any hidden stuff + // int expectedModCount = modCount; + // s.defaultWriteObject(); + + // // Write out size as capacity for behavioural compatibility with clone() + // s.writeInt(size); + + // // Write out all elements in the proper order. + // for (int i=0; iArrayList instance from a stream (that is, + * deserialize it). + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // elementData = EMPTY_ELEMENTDATA; + + // // Read in size, and any hidden stuff + // s.defaultReadObject(); + + // // Read in capacity + // s.readInt(); // ignored + + // if (size > 0) { + // // be like clone(), allocate array based upon size not capacity + // ensureCapacityInternal(size); + + // Object[] a = elementData; + // // Read in all elements in the proper order. + // for (int i=0; iThe returned list iterator is fail-fast. + * + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk, except for the string operation, which can lead + // to performance issues. + public ListIterator listIterator(int index) { + if (index < 0 || index > size) + // throw new IndexOutOfBoundsException("Index: "+index); + throw new IndexOutOfBoundsException(); + return new ListItr(index); + } + + /** + * Returns a list iterator over the elements in this list (in proper + * sequence). + * + *

The returned list iterator is fail-fast. + * + * @see #listIterator(int) + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public ListIterator listIterator() { + return new ListItr(0); + } + + /** + * Returns an iterator over the elements in this list in proper sequence. + * + *

The returned iterator is fail-fast. + * + * @return an iterator over the elements in this list in proper sequence + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public Iterator iterator() { + return new Itr(); + } + + /** + * An optimized version of AbstractList.Itr + */ + // DIFFBLUE MODEL LIBRARY + // The implementation of Itr in the model is virtually identical to its + // implementation in the jdk. The only very minor difference is that + // expectedModCount = modCount needs to be defined in the constructor of the + // Itr model. + // The only reason why forEachRemaining() is marked as not modelled is that + // we do not yet have a model for any classes implementing the Consumer + // interface, so we do not have a way to test this method. + private class Itr implements Iterator { + int cursor; // index of next element to return + int lastRet = -1; // index of last element returned; -1 if no such + int expectedModCount = modCount; + + Itr() { + cursor = 0; + lastRet = -1; + expectedModCount = modCount; + // CProver.assume(ArrayList.this.elementData.length < 2); + } + + public boolean hasNext() { + return cursor != size; + } + + @SuppressWarnings("unchecked") + public E next() { + checkForComodification(); + int i = cursor; + if (i >= size) + throw new NoSuchElementException(); + Object[] elementData = ArrayList.this.elementData; + if (i >= elementData.length) + throw new ConcurrentModificationException(); + cursor = i + 1; + return (E) elementData[lastRet = i]; + } + + public void remove() { + if (lastRet < 0) + throw new IllegalStateException(); + checkForComodification(); + + try { + ArrayList.this.remove(lastRet); + cursor = lastRet; + lastRet = -1; + expectedModCount = modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + @Override + @SuppressWarnings("unchecked") + public void forEachRemaining(Consumer consumer) { + // Objects.requireNonNull(consumer); + // final int size = ArrayList.this.size; + // int i = cursor; + // if (i >= size) { + // return; + // } + // final Object[] elementData = ArrayList.this.elementData; + // if (i >= elementData.length) { + // throw new ConcurrentModificationException(); + // } + // while (i != size && modCount == expectedModCount) { + // consumer.accept((E) elementData[i++]); + // } + // // update once at end of iteration to reduce heap write traffic + // cursor = i; + // lastRet = i - 1; + // checkForComodification(); + CProver.notModelled(); + } + + final void checkForComodification() { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + } + } + + /** + * An optimized version of AbstractList.ListItr + */ + // DIFFBLUE MODEL LIBRARY + // The implementation of ListItr in the model is virtually identical to its + // implementation in the jdk. The only very minor difference is in the + // constructor of its superclass Itr. + private class ListItr extends Itr implements ListIterator { + ListItr(int index) { + super(); + cursor = index; + } + + public boolean hasPrevious() { + return cursor != 0; + } + + public int nextIndex() { + return cursor; + } + + public int previousIndex() { + return cursor - 1; + } + + @SuppressWarnings("unchecked") + public E previous() { + checkForComodification(); + int i = cursor - 1; + if (i < 0) + throw new NoSuchElementException(); + Object[] elementData = ArrayList.this.elementData; + if (i >= elementData.length) + throw new ConcurrentModificationException(); + cursor = i; + return (E) elementData[lastRet = i]; + } + + public void set(E e) { + if (lastRet < 0) + throw new IllegalStateException(); + checkForComodification(); + + try { + ArrayList.this.set(lastRet, e); + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + public void add(E e) { + checkForComodification(); + + try { + int i = cursor; + ArrayList.this.add(i, e); + cursor = i + 1; + lastRet = -1; + expectedModCount = modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + } + + /** + * Returns a view of the portion of this list between the specified + * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive. (If + * {@code fromIndex} and {@code toIndex} are equal, the returned list is + * empty.) The returned list is backed by this list, so non-structural + * changes in the returned list are reflected in this list, and vice-versa. + * The returned list supports all of the optional list operations. + * + *

This method eliminates the need for explicit range operations (of + * the sort that commonly exist for arrays). Any operation that expects + * a list can be used as a range operation by passing a subList view + * instead of a whole list. For example, the following idiom + * removes a range of elements from a list: + *

+     *      list.subList(from, to).clear();
+     * 
+ * Similar idioms may be constructed for {@link #indexOf(Object)} and + * {@link #lastIndexOf(Object)}, and all of the algorithms in the + * {@link Collections} class can be applied to a subList. + * + *

The semantics of the list returned by this method become undefined if + * the backing list (i.e., this list) is structurally modified in + * any way other than via the returned list. (Structural modifications are + * those that change the size of this list, or otherwise perturb it in such + * a fashion that iterations in progress may yield incorrect results.) + * + * @throws IndexOutOfBoundsException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + // DIFFBLUE MODEL LIBRARY + // The inner class SubList is correctly modelled, but actually calling it + // as in + // arrayList.subList(from, to).clear(); + // results in recursive unwinding due to the fact that methods like clear, + // removeRange etc. are defined in several classes (SubList, ArrayList, + // AbstractList, AbstractCollection...) + public List subList(int fromIndex, int toIndex) { + // subListRangeCheck(fromIndex, toIndex, size); + // return new SubList(this, 0, fromIndex, toIndex); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk, except for string operations, which can lead to + // performance issues. + static void subListRangeCheck(int fromIndex, int toIndex, int size) { + if (fromIndex < 0) + // throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); + throw new IndexOutOfBoundsException(); + if (toIndex > size) + // throw new IndexOutOfBoundsException("toIndex = " + toIndex); + throw new IndexOutOfBoundsException(); + if (fromIndex > toIndex) + // throw new IllegalArgumentException("fromIndex(" + fromIndex + + // ") > toIndex(" + toIndex + ")"); + throw new IllegalArgumentException(); + } + + // DIFFBLUE MODEL LIBRARY + // The implementation of SubList in the model is identical to its + // implementation in the jdk (except for the two methods that are not yet + // modelled). + private class SubList extends AbstractList implements RandomAccess { + private final AbstractList parent; + private final int parentOffset; + private final int offset; + int size; + + SubList(AbstractList parent, + int offset, int fromIndex, int toIndex) { + this.parent = parent; + this.parentOffset = fromIndex; + this.offset = offset + fromIndex; + this.size = toIndex - fromIndex; + this.modCount = ArrayList.this.modCount; + } + + public E set(int index, E e) { + rangeCheck(index); + checkForComodification(); + E oldValue = ArrayList.this.elementData(offset + index); + ArrayList.this.elementData[offset + index] = e; + return oldValue; + } + + public E get(int index) { + rangeCheck(index); + checkForComodification(); + return ArrayList.this.elementData(offset + index); + } + + public int size() { + checkForComodification(); + return this.size; + } + + public void add(int index, E e) { + rangeCheckForAdd(index); + checkForComodification(); + parent.add(parentOffset + index, e); + this.modCount = parent.modCount; + this.size++; + } + + public E remove(int index) { + rangeCheck(index); + checkForComodification(); + E result = parent.remove(parentOffset + index); + this.modCount = parent.modCount; + this.size--; + return result; + } + + protected void removeRange(int fromIndex, int toIndex) { + checkForComodification(); + parent.removeRange(parentOffset + fromIndex, + parentOffset + toIndex); + this.modCount = parent.modCount; + this.size -= toIndex - fromIndex; + } + + public boolean addAll(Collection c) { + return addAll(this.size, c); + } + + public boolean addAll(int index, Collection c) { + rangeCheckForAdd(index); + int cSize = c.size(); + if (cSize==0) + return false; + + checkForComodification(); + parent.addAll(parentOffset + index, c); + this.modCount = parent.modCount; + this.size += cSize; + return true; + } + + public Iterator iterator() { + return listIterator(); + } + + public ListIterator listIterator(final int index) { + checkForComodification(); + rangeCheckForAdd(index); + final int offset = this.offset; + + return new ListIterator() { + int cursor = index; + int lastRet = -1; + int expectedModCount = ArrayList.this.modCount; + + public boolean hasNext() { + return cursor != SubList.this.size; + } + + @SuppressWarnings("unchecked") + public E next() { + checkForComodification(); + int i = cursor; + if (i >= SubList.this.size) + throw new NoSuchElementException(); + Object[] elementData = ArrayList.this.elementData; + if (offset + i >= elementData.length) + throw new ConcurrentModificationException(); + cursor = i + 1; + return (E) elementData[offset + (lastRet = i)]; + } + + public boolean hasPrevious() { + return cursor != 0; + } + + @SuppressWarnings("unchecked") + public E previous() { + checkForComodification(); + int i = cursor - 1; + if (i < 0) + throw new NoSuchElementException(); + Object[] elementData = ArrayList.this.elementData; + if (offset + i >= elementData.length) + throw new ConcurrentModificationException(); + cursor = i; + return (E) elementData[offset + (lastRet = i)]; + } + + @SuppressWarnings("unchecked") + public void forEachRemaining(Consumer consumer) { + // Objects.requireNonNull(consumer); + // final int size = SubList.this.size; + // int i = cursor; + // if (i >= size) { + // return; + // } + // final Object[] elementData = ArrayList.this.elementData; + // if (offset + i >= elementData.length) { + // throw new ConcurrentModificationException(); + // } + // while (i != size && modCount == expectedModCount) { + // consumer.accept((E) elementData[offset + (i++)]); + // } + // // update once at end of iteration to reduce heap write traffic + // lastRet = cursor = i; + // checkForComodification(); + CProver.notModelled(); + } + + public int nextIndex() { + return cursor; + } + + public int previousIndex() { + return cursor - 1; + } + + public void remove() { + if (lastRet < 0) + throw new IllegalStateException(); + checkForComodification(); + + try { + SubList.this.remove(lastRet); + cursor = lastRet; + lastRet = -1; + expectedModCount = ArrayList.this.modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + public void set(E e) { + if (lastRet < 0) + throw new IllegalStateException(); + checkForComodification(); + + try { + ArrayList.this.set(offset + lastRet, e); + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + public void add(E e) { + checkForComodification(); + + try { + int i = cursor; + SubList.this.add(i, e); + cursor = i + 1; + lastRet = -1; + expectedModCount = ArrayList.this.modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + final void checkForComodification() { + if (expectedModCount != ArrayList.this.modCount) + throw new ConcurrentModificationException(); + } + }; + } + + public List subList(int fromIndex, int toIndex) { + subListRangeCheck(fromIndex, toIndex, size); + return new SubList(this, offset, fromIndex, toIndex); + } + + private void rangeCheck(int index) { + if (index < 0 || index >= this.size) + // throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + throw new IndexOutOfBoundsException(); + } + + private void rangeCheckForAdd(int index) { + if (index < 0 || index > this.size) + // throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + throw new IndexOutOfBoundsException(); + } + + // DIFFBLUE MODEL LIBRARY + // String operations can significantly slow down JBMC in some + // cases. This should be reviewed again with improved versions of the string + // solver. + // private String outOfBoundsMsg(int index) { + // return "Index: "+index+", Size: "+this.size; + // } + + private void checkForComodification() { + if (ArrayList.this.modCount != this.modCount) + throw new ConcurrentModificationException(); + } + + public Spliterator spliterator() { + // checkForComodification(); + // return new ArrayListSpliterator(ArrayList.this, offset, + // offset + this.size, this.modCount); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + } + + // DIFFBLUE MODEL LIBRARY + // We do not yet have a model for any classes implementing the Consumer + // interface, so we do not have a way to model and test this method. + @Override + public void forEach(Consumer action) { + // Objects.requireNonNull(action); + // final int expectedModCount = modCount; + // @SuppressWarnings("unchecked") + // final E[] elementData = (E[]) this.elementData; + // final int size = this.size; + // for (int i=0; modCount == expectedModCount && i < size; i++) { + // action.accept(elementData[i]); + // } + // if (modCount != expectedModCount) { + // throw new ConcurrentModificationException(); + // } + CProver.notModelled(); + } + + /** + * Creates a late-binding + * and fail-fast {@link Spliterator} over the elements in this + * list. + * + *

The {@code Spliterator} reports {@link Spliterator#SIZED}, + * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}. + * Overriding implementations should document the reporting of additional + * characteristic values. + * + * @return a {@code Spliterator} over the elements in this list + * @since 1.8 + */ + // DIFFBLUE MODELS LIBRARY: Inherit from Collection's basic implementaton instead + /* + @Override + public Spliterator spliterator() { + // return new ArrayListSpliterator<>(this, 0, -1, 0); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + */ + + /** Index-based split-by-two, lazily initialized Spliterator */ + // DIFFBLUE MODEL LIBRARY + // The ArrayListSpliterator class is not modelled yet, due to its dependency + // on the Customer interface. Since we do not have models for any of + // Customer's implementations, we cannot model and test most of the methods + // in this class. + // static final class ArrayListSpliterator implements Spliterator { + + // /* + // * If ArrayLists were immutable, or structurally immutable (no + // * adds, removes, etc), we could implement their spliterators + // * with Arrays.spliterator. Instead we detect as much + // * interference during traversal as practical without + // * sacrificing much performance. We rely primarily on + // * modCounts. These are not guaranteed to detect concurrency + // * violations, and are sometimes overly conservative about + // * within-thread interference, but detect enough problems to + // * be worthwhile in practice. To carry this out, we (1) lazily + // * initialize fence and expectedModCount until the latest + // * point that we need to commit to the state we are checking + // * against; thus improving precision. (This doesn't apply to + // * SubLists, that create spliterators with current non-lazy + // * values). (2) We perform only a single + // * ConcurrentModificationException check at the end of forEach + // * (the most performance-sensitive method). When using forEach + // * (as opposed to iterators), we can normally only detect + // * interference after actions, not before. Further + // * CME-triggering checks apply to all other possible + // * violations of assumptions for example null or too-small + // * elementData array given its size(), that could only have + // * occurred due to interference. This allows the inner loop + // * of forEach to run without any further checks, and + // * simplifies lambda-resolution. While this does entail a + // * number of checks, note that in the common case of + // * list.stream().forEach(a), no checks or other computation + // * occur anywhere other than inside forEach itself. The other + // * less-often-used methods cannot take advantage of most of + // * these streamlinings. + // */ + + // private final ArrayList list; + // private int index; // current index, modified on advance/split + // private int fence; // -1 until used; then one past last index + // private int expectedModCount; // initialized when fence set + + // /** Create new spliterator covering the given range */ + // ArrayListSpliterator(ArrayList list, int origin, int fence, + // int expectedModCount) { + // this.list = list; // OK if null unless traversed + // this.index = origin; + // this.fence = fence; + // this.expectedModCount = expectedModCount; + // } + + // private int getFence() { // initialize fence to size on first use + // int hi; // (a specialized variant appears in method forEach) + // ArrayList lst; + // if ((hi = fence) < 0) { + // if ((lst = list) == null) + // hi = fence = 0; + // else { + // expectedModCount = lst.modCount; + // hi = fence = lst.size; + // } + // } + // return hi; + // } + + // public ArrayListSpliterator trySplit() { + // int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; + // return (lo >= mid) ? null : // divide range in half unless too small + // new ArrayListSpliterator(list, lo, index = mid, + // expectedModCount); + // } + + // public boolean tryAdvance(Consumer action) { + // if (action == null) + // throw new NullPointerException(); + // int hi = getFence(), i = index; + // if (i < hi) { + // index = i + 1; + // @SuppressWarnings("unchecked") E e = (E)list.elementData[i]; + // action.accept(e); + // if (list.modCount != expectedModCount) + // throw new ConcurrentModificationException(); + // return true; + // } + // return false; + // } + + // public void forEachRemaining(Consumer action) { + // int i, hi, mc; // hoist accesses and checks from loop + // ArrayList lst; Object[] a; + // if (action == null) + // throw new NullPointerException(); + // if ((lst = list) != null && (a = lst.elementData) != null) { + // if ((hi = fence) < 0) { + // mc = lst.modCount; + // hi = lst.size; + // } + // else + // mc = expectedModCount; + // if ((i = index) >= 0 && (index = hi) <= a.length) { + // for (; i < hi; ++i) { + // @SuppressWarnings("unchecked") E e = (E) a[i]; + // action.accept(e); + // } + // if (lst.modCount == mc) + // return; + // } + // } + // throw new ConcurrentModificationException(); + // } + + // public long estimateSize() { + // return (long) (getFence() - index); + // } + + // public int characteristics() { + // return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; + // } + // } + + // DIFFBLUE MODEL LIBRARY + // We do not yet have a model for any classes implementing the Predicate + // interface, so we do not have a way to model and test this method. + @Override + public boolean removeIf(Predicate filter) { + // Objects.requireNonNull(filter); + // // figure out which elements are to be removed + // // any exception thrown from the filter predicate at this stage + // // will leave the collection unmodified + // int removeCount = 0; + // final BitSet removeSet = new BitSet(size); + // final int expectedModCount = modCount; + // final int size = this.size; + // for (int i=0; modCount == expectedModCount && i < size; i++) { + // @SuppressWarnings("unchecked") + // final E element = (E) elementData[i]; + // if (filter.test(element)) { + // removeSet.set(i); + // removeCount++; + // } + // } + // if (modCount != expectedModCount) { + // throw new ConcurrentModificationException(); + // } + + // // shift surviving elements left over the spaces left by removed elements + // final boolean anyToRemove = removeCount > 0; + // if (anyToRemove) { + // final int newSize = size - removeCount; + // for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) { + // i = removeSet.nextClearBit(i); + // elementData[j] = elementData[i]; + // } + // for (int k=newSize; k < size; k++) { + // elementData[k] = null; // Let gc do its work + // } + // this.size = newSize; + // if (modCount != expectedModCount) { + // throw new ConcurrentModificationException(); + // } + // modCount++; + // } + + // return anyToRemove; + CProver.notModelled(); + return CProver.nondetBoolean(); + } + + // DIFFBLUE MODEL LIBRARY + // We do not yet have a model for any classes implementing the UnaryOperator + // interface, so we do not have a way to model and test this method. + @Override + @SuppressWarnings("unchecked") + public void replaceAll(UnaryOperator operator) { + // Objects.requireNonNull(operator); + // final int expectedModCount = modCount; + // final int size = this.size; + // for (int i=0; modCount == expectedModCount && i < size; i++) { + // elementData[i] = operator.apply((E) elementData[i]); + // } + // if (modCount != expectedModCount) { + // throw new ConcurrentModificationException(); + // } + // modCount++; + CProver.notModelled(); + } + + // DIFFBLUE MODEL LIBRARY + // We do not yet have a model for any classes implementing the Comparator + // interface, so we do not have a way to model and test this method. + @Override + @SuppressWarnings("unchecked") + public void sort(Comparator c) { + // final int expectedModCount = modCount; + // Arrays.sort((E[]) elementData, 0, size, c); + // if (modCount != expectedModCount) { + // throw new ConcurrentModificationException(); + // } + // modCount++; + CProver.notModelled(); + } + + // DIFFBLUE MODEL LIBRARY + // This method is called by CBMC just after nondeterministic object + // creation, i.e. the constraints that it specifies are only enforced at + // that time and do not have to hold globally. + // We generally want to make sure that all necessary invariants of the class + // are satisfied, and potentially restrict some fields to speed up test + // generation. + @org.cprover.MustNotThrow + protected void cproverNondetInitialize() { + CProver.assume(size >= 0); + CProver.assume(elementData != null); + CProver.assume(elementData.length >= size); + // Nondeterministic ArrayLists are created using a + // call to the + // public ArrayList() + // constructor, followed by a sequence of calls to add, where the number + // of such calls is equal to size. If the size is 0, the ArrayList has + // default capacity (in the jdk implementation). + CProver.assume(cproverIsDefaultCapacityEmpty == (size == 0)); + // The number of calls to add in the traces is equal to size. + // Each call to add increments the modCount variable by 1. + CProver.assume(modCount == size); + } + +} diff --git a/src/main/java/java/util/BitSet.java b/src/main/java/java/util/BitSet.java new file mode 100644 index 0000000..67f6643 --- /dev/null +++ b/src/main/java/java/util/BitSet.java @@ -0,0 +1,1689 @@ +/* + * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.LongBuffer; +import java.util.stream.IntStream; +import java.util.stream.StreamSupport; + +import org.cprover.CProver; + +/** + * This class implements a vector of bits that grows as needed. Each + * component of the bit set has a {@code boolean} value. The + * bits of a {@code BitSet} are indexed by nonnegative integers. + * Individual indexed bits can be examined, set, or cleared. One + * {@code BitSet} may be used to modify the contents of another + * {@code BitSet} through logical AND, logical inclusive OR, and + * logical exclusive OR operations. + * + *

By default, all bits in the set initially have the value + * {@code false}. + * + *

Every bit set has a current size, which is the number of bits + * of space currently in use by the bit set. Note that the size is + * related to the implementation of a bit set, so it may change with + * implementation. The length of a bit set relates to logical length + * of a bit set and is defined independently of implementation. + * + *

Unless otherwise noted, passing a null parameter to any of the + * methods in a {@code BitSet} will result in a + * {@code NullPointerException}. + * + *

A {@code BitSet} is not safe for multithreaded use without + * external synchronization. + * + * @author Arthur van Hoff + * @author Michael McCloskey + * @author Martin Buchholz + * @since JDK1.0 + * + * @diffblue.limitedSupport + * Some methods are not supported. + * Since we represent BitSets as arrays of booleans in the model, large elements + * can cause problems with JBMC. + */ +public class BitSet implements Cloneable, java.io.Serializable { + // DIFFBLUE MODEL LIBRARY + // None of the private variables of the JDK version of this class are used + // in the model. + /* + * BitSets are packed into arrays of "words." Currently a word is + * a long, which consists of 64 bits, requiring 6 address bits. + * The choice of word size is determined purely by performance concerns. + */ + // private final static int ADDRESS_BITS_PER_WORD = 6; + // private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD; + // private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1; + + /* Used to shift left or right for a partial word mask */ + // private static final long WORD_MASK = 0xffffffffffffffffL; + + /** + * @serialField bits long[] + * + * The bits in this BitSet. The ith bit is stored in bits[i/64] at + * bit position i % 64 (where bit position 0 refers to the least + * significant bit and 63 refers to the most significant bit). + */ + // private static final ObjectStreamField[] serialPersistentFields = { + // new ObjectStreamField("bits", long[].class), + // }; + + /** + * The internal field corresponding to the serialField "bits". + */ + // private long[] words; + + /** + * The number of words in the logical size of this BitSet. + */ + // private transient int wordsInUse = 0; + + /** + * Whether the size of "words" is user-specified. If so, we assume + * the user knows what he's doing and try harder to preserve it. + */ + // private transient boolean sizeIsSticky = false; + + /* use serialVersionUID from JDK 1.0.2 for interoperability */ + // private static final long serialVersionUID = 7997698588986878753L; + + // DIFFBLUE MODEL LIBRARY + // This field does not exist in the JDK. + // JDK's implementation uses array of longs for performance + // reasons. Here we use array of booleans, as it's simpler + // to manipulate. + // TODO Evaluate if it might be better to use an array of bytes or longs + // instead of an array of booleans in the model because of restrictions on + // array lengths for JBMC. + private boolean[] bits; + + /** + * Given a bit index, return word index containing it. + */ + // DIFFBLUE MODEL LIBRARY Private method not used in model + // private static int wordIndex(int bitIndex) { + // return bitIndex >> ADDRESS_BITS_PER_WORD; + // } + + /** + * Every public method must preserve these invariants. + */ + // DIFFBLUE MODEL LIBRARY Private method not used in model + // private void checkInvariants() { + // assert(wordsInUse == 0 || words[wordsInUse - 1] != 0); + // assert(wordsInUse >= 0 && wordsInUse <= words.length); + // assert(wordsInUse == words.length || words[wordsInUse] == 0); + // } + + /** + * Sets the field wordsInUse to the logical size in words of the bit set. + * WARNING:This method assumes that the number of words actually in use is + * less than or equal to the current value of wordsInUse! + */ + // DIFFBLUE MODEL LIBRARY Private method not used in model + // private void recalculateWordsInUse() { + // // Traverse the bitset until a used word is found + // int i; + // for (i = wordsInUse-1; i >= 0; i--) + // if (words[i] != 0) + // break; + // wordsInUse = i+1; // The new logical size + // } + + /** + * Creates a new bit set. All bits are initially {@code false}. + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public BitSet() { + // initWords(BITS_PER_WORD); + // sizeIsSticky = false; + + int cproverCapacity = CProver.nondetInt(); + CProver.assume(cproverCapacity >= 0); + bits = new boolean[cproverCapacity]; + } + + /** + * Creates a bit set whose initial size is large enough to explicitly + * represent bits with indices in the range {@code 0} through + * {@code nbits-1}. All bits are initially {@code false}. + * + * @param nbits the initial size of the bit set + * @throws NegativeArraySizeException if the specified initial size + * is negative + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public BitSet(int nbits) { + // // nbits can't be negative; size 0 is OK + // if (nbits < 0) + // throw new NegativeArraySizeException("nbits < 0: " + nbits); + + // initWords(nbits); + // sizeIsSticky = true; + + if (nbits < 0) + throw new NegativeArraySizeException(); + int cproverCapacity = CProver.nondetInt(); + CProver.assume(cproverCapacity >= 0); + bits = new boolean[cproverCapacity]; + } + + // DIFFBLUE MODEL LIBRARY Private method not used in model + // private void initWords(int nbits) { + // words = new long[wordIndex(nbits-1) + 1]; + // } + + /** + * Creates a bit set using words as the internal representation. + * The last word (if there is one) must be non-zero. + */ + // DIFFBLUE MODEL LIBRARY Private constructor not used in model + // private BitSet(long[] words) { + // this.words = words; + // this.wordsInUse = words.length; + // checkInvariants(); + // } + + /** + * Returns a new bit set containing all the bits in the given long array. + * + *

More precisely, + *
{@code BitSet.valueOf(longs).get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)} + *
for all {@code n < 64 * longs.length}. + * + *

This method is equivalent to + * {@code BitSet.valueOf(LongBuffer.wrap(longs))}. + * + * @param longs a long array containing a little-endian representation + * of a sequence of bits to be used as the initial bits of the + * new bit set + * @return a {@code BitSet} containing all the bits in the long array + * @since 1.7 + * + * @diffblue.noSupport + */ + public static BitSet valueOf(long[] longs) { + // DIFFBLUE MODEL LIBRARY jdk code + // int n; + // for (n = longs.length; n > 0 && longs[n - 1] == 0; n--) + // ; + // return new BitSet(Arrays.copyOf(longs, n)); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + /** + * Returns a new bit set containing all the bits in the given long + * buffer between its position and limit. + * + *

More precisely, + *
{@code BitSet.valueOf(lb).get(n) == ((lb.get(lb.position()+n/64) & (1L<<(n%64))) != 0)} + *
for all {@code n < 64 * lb.remaining()}. + * + *

The long buffer is not modified by this method, and no + * reference to the buffer is retained by the bit set. + * + * @param lb a long buffer containing a little-endian representation + * of a sequence of bits between its position and limit, to be + * used as the initial bits of the new bit set + * @return a {@code BitSet} containing all the bits in the buffer in the + * specified range + * @since 1.7 + * + * @diffblue.noSupport + * We do not have a model for LongBuffer. + */ + public static BitSet valueOf(LongBuffer lb) { + // DIFFBLUE MODEL LIBRARY jdk code + // lb = lb.slice(); + // int n; + // for (n = lb.remaining(); n > 0 && lb.get(n - 1) == 0; n--) + // ; + // long[] words = new long[n]; + // lb.get(words); + // return new BitSet(words); + + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + /** + * Returns a new bit set containing all the bits in the given byte array. + * + *

More precisely, + *
{@code BitSet.valueOf(bytes).get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)} + *
for all {@code n < 8 * bytes.length}. + * + *

This method is equivalent to + * {@code BitSet.valueOf(ByteBuffer.wrap(bytes))}. + * + * @param bytes a byte array containing a little-endian + * representation of a sequence of bits to be used as the + * initial bits of the new bit set + * @return a {@code BitSet} containing all the bits in the byte array + * @since 1.7 + * + * @diffblue.limitedSupport + * Depending on the value of --unwind, this generally only works with a + * small number of bytes in the input array. + */ + public static BitSet valueOf(byte[] bytes) { + // return BitSet.valueOf(ByteBuffer.wrap(bytes)); + + BitSet bitSet = new BitSet(); + CProver.assume(bitSet.bits.length >= bytes.length * 8); + for (int i = 0; i < bytes.length; i++) { + for (int j = 0; j < 8; j++) { + if ((bytes[i] & (1 << j)) != 0) { + bitSet.bits[i * 8 + j] = true; + } + } + } + return bitSet; + + // DIFFBLUE MODEL LIBRARY + // Alternative implementation: this might be more efficient as it does + // not need a nested for-loop, but it generally requires higher values + // of --unwind. + // int cproverSize = bytes.length * 8; + // BitSet bitSet = new BitSet(); + // CProver.assume(bitSet.bits.length >= cproverSize); + // for (int i = 0; i < cproverSize; i++) { + // int byteIndex = i >> 3; + // bitSet.bits[i] = ((bytes[byteIndex] & (1 << i % 8)) != 0); + // } + // return bitSet; + } + + /** + * Returns a new bit set containing all the bits in the given byte + * buffer between its position and limit. + * + *

More precisely, + *
{@code BitSet.valueOf(bb).get(n) == ((bb.get(bb.position()+n/8) & (1<<(n%8))) != 0)} + *
for all {@code n < 8 * bb.remaining()}. + * + *

The byte buffer is not modified by this method, and no + * reference to the buffer is retained by the bit set. + * + * @param bb a byte buffer containing a little-endian representation + * of a sequence of bits between its position and limit, to be + * used as the initial bits of the new bit set + * @return a {@code BitSet} containing all the bits in the buffer in the + * specified range + * @since 1.7 + * + * @diffblue.noSupport + * We do not have a model for ByteBuffer. + */ + public static BitSet valueOf(ByteBuffer bb) { + // DIFFBLUE MODEL LIBRARY jdk code + // bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN); + // int n; + // for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--) + // ; + // long[] words = new long[(n + 7) / 8]; + // bb.limit(n); + // int i = 0; + // while (bb.remaining() >= 8) + // words[i++] = bb.getLong(); + // for (int remaining = bb.remaining(), j = 0; j < remaining; j++) + // words[i] |= (bb.get() & 0xffL) << (8 * j); + // return new BitSet(words); + + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + /** + * Returns a new byte array containing all the bits in this bit set. + * + *

More precisely, if + *
{@code byte[] bytes = s.toByteArray();} + *
then {@code bytes.length == (s.length()+7)/8} and + *
{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)} + *
for all {@code n < 8 * bytes.length}. + * + * @return a byte array containing a little-endian representation + * of all the bits in this bit set + * @since 1.7 + * + * @diffblue.noSupport + */ + public byte[] toByteArray() { + // DIFFBLUE MODEL LIBRARY jdk code + // int n = wordsInUse; + // if (n == 0) + // return new byte[0]; + // int len = 8 * (n-1); + // for (long x = words[n - 1]; x != 0; x >>>= 8) + // len++; + // byte[] bytes = new byte[len]; + // ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + // for (int i = 0; i < n - 1; i++) + // bb.putLong(words[i]); + // for (long x = words[n - 1]; x != 0; x >>>= 8) + // bb.put((byte) (x & 0xff)); + // return bytes; + + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + /** + * Returns a new long array containing all the bits in this bit set. + * + *

More precisely, if + *
{@code long[] longs = s.toLongArray();} + *
then {@code longs.length == (s.length()+63)/64} and + *
{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)} + *
for all {@code n < 64 * longs.length}. + * + * @return a long array containing a little-endian representation + * of all the bits in this bit set + * @since 1.7 + * + * @diffblue.noSupport + */ + public long[] toLongArray() { + // DIFFBLUE MODEL LIBRARY jdk code + // return Arrays.copyOf(words, wordsInUse); + + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + // DIFFBLUE MODEL LIBRARY jdk code + /** + * Ensures that the BitSet can hold enough words. + * @param wordsRequired the minimum acceptable number of words. + */ + // private void ensureCapacity(int wordsRequired) { + // if (words.length < wordsRequired) { + // // Allocate larger of doubled size or required size + // int request = Math.max(2 * words.length, wordsRequired); + // words = Arrays.copyOf(words, request); + // sizeIsSticky = false; + // } + // } + + private void cproverEnsureCapacity(int bitsRequired) { + CProver.assume(bits.length >= bitsRequired); + } + + // DIFFBLUE MODEL LIBRARY jdk code + /** + * Ensures that the BitSet can accommodate a given wordIndex, + * temporarily violating the invariants. The caller must + * restore the invariants before returning to the user, + * possibly using recalculateWordsInUse(). + * @param wordIndex the index to be accommodated. + */ + // private void expandTo(int wordIndex) { + // int wordsRequired = wordIndex+1; + // if (wordsInUse < wordsRequired) { + // ensureCapacity(wordsRequired); + // wordsInUse = wordsRequired; + // } + // } + + /** + * Checks that fromIndex ... toIndex is a valid range of bit indices. + */ + private static void checkRange(int fromIndex, int toIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // if (fromIndex < 0) + // throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); + // if (toIndex < 0) + // throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex); + // if (fromIndex > toIndex) + // throw new IndexOutOfBoundsException("fromIndex: " + fromIndex + + // " > toIndex: " + toIndex); + + if (fromIndex < 0) + throw new IndexOutOfBoundsException(); + if (toIndex < 0) + throw new IndexOutOfBoundsException(); + if (fromIndex > toIndex) + throw new IndexOutOfBoundsException(); + } + + /** + * Sets the bit at the specified index to the complement of its + * current value. + * + * @param bitIndex the index of the bit to flip + * @throws IndexOutOfBoundsException if the specified index is negative + * @since 1.4 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public void flip(int bitIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // if (bitIndex < 0) + // throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); + + // int wordIndex = wordIndex(bitIndex); + // expandTo(wordIndex); + + // words[wordIndex] ^= (1L << bitIndex); + + // recalculateWordsInUse(); + // checkInvariants(); + + if (bitIndex < 0) + throw new IndexOutOfBoundsException(); + cproverEnsureCapacity(bitIndex + 1); + bits[bitIndex] = !bits[bitIndex]; + } + + /** + * Sets each bit from the specified {@code fromIndex} (inclusive) to the + * specified {@code toIndex} (exclusive) to the complement of its current + * value. + * + * @param fromIndex index of the first bit to flip + * @param toIndex index after the last bit to flip + * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, + * or {@code toIndex} is negative, or {@code fromIndex} is + * larger than {@code toIndex} + * @since 1.4 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public void flip(int fromIndex, int toIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // checkRange(fromIndex, toIndex); + + // if (fromIndex == toIndex) + // return; + + // int startWordIndex = wordIndex(fromIndex); + // int endWordIndex = wordIndex(toIndex - 1); + // expandTo(endWordIndex); + + // long firstWordMask = WORD_MASK << fromIndex; + // long lastWordMask = WORD_MASK >>> -toIndex; + // if (startWordIndex == endWordIndex) { + // // Case 1: One word + // words[startWordIndex] ^= (firstWordMask & lastWordMask); + // } else { + // // Case 2: Multiple words + // // Handle first word + // words[startWordIndex] ^= firstWordMask; + + // // Handle intermediate words, if any + // for (int i = startWordIndex+1; i < endWordIndex; i++) + // words[i] ^= WORD_MASK; + + // // Handle last word + // words[endWordIndex] ^= lastWordMask; + // } + + // recalculateWordsInUse(); + // checkInvariants(); + + checkRange(fromIndex, toIndex); + cproverEnsureCapacity(toIndex + 1); + for (int i = fromIndex; i < toIndex; i++) + bits[i] = !bits[i]; + } + + /** + * Sets the bit at the specified index to {@code true}. + * + * @param bitIndex a bit index + * @throws IndexOutOfBoundsException if the specified index is negative + * @since JDK1.0 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public void set(int bitIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // if (bitIndex < 0) + // throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); + + // int wordIndex = wordIndex(bitIndex); + // expandTo(wordIndex); + + // words[wordIndex] |= (1L << bitIndex); // Restores invariants + + // checkInvariants(); + + if (bitIndex < 0) + throw new IndexOutOfBoundsException(); + cproverEnsureCapacity(bitIndex + 1); + bits[bitIndex] = true; + } + + /** + * Sets the bit at the specified index to the specified value. + * + * @param bitIndex a bit index + * @param value a boolean value to set + * @throws IndexOutOfBoundsException if the specified index is negative + * @since 1.4 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public void set(int bitIndex, boolean value) { + if (value) + set(bitIndex); + else + clear(bitIndex); + } + + /** + * Sets the bits from the specified {@code fromIndex} (inclusive) to the + * specified {@code toIndex} (exclusive) to {@code true}. + * + * @param fromIndex index of the first bit to be set + * @param toIndex index after the last bit to be set + * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, + * or {@code toIndex} is negative, or {@code fromIndex} is + * larger than {@code toIndex} + * @since 1.4 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public void set(int fromIndex, int toIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // checkRange(fromIndex, toIndex); + + // if (fromIndex == toIndex) + // return; + + // // Increase capacity if necessary + // int startWordIndex = wordIndex(fromIndex); + // int endWordIndex = wordIndex(toIndex - 1); + // expandTo(endWordIndex); + + // long firstWordMask = WORD_MASK << fromIndex; + // long lastWordMask = WORD_MASK >>> -toIndex; + // if (startWordIndex == endWordIndex) { + // // Case 1: One word + // words[startWordIndex] |= (firstWordMask & lastWordMask); + // } else { + // // Case 2: Multiple words + // // Handle first word + // words[startWordIndex] |= firstWordMask; + + // // Handle intermediate words, if any + // for (int i = startWordIndex+1; i < endWordIndex; i++) + // words[i] = WORD_MASK; + + // // Handle last word (restores invariants) + // words[endWordIndex] |= lastWordMask; + // } + + // checkInvariants(); + + checkRange(fromIndex, toIndex); + cproverEnsureCapacity(toIndex + 1); + for (int i = fromIndex; i < toIndex; i++) + bits[i] = true; + } + + /** + * Sets the bits from the specified {@code fromIndex} (inclusive) to the + * specified {@code toIndex} (exclusive) to the specified value. + * + * @param fromIndex index of the first bit to be set + * @param toIndex index after the last bit to be set + * @param value value to set the selected bits to + * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, + * or {@code toIndex} is negative, or {@code fromIndex} is + * larger than {@code toIndex} + * @since 1.4 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public void set(int fromIndex, int toIndex, boolean value) { + if (value) + set(fromIndex, toIndex); + else + clear(fromIndex, toIndex); + } + + /** + * Sets the bit specified by the index to {@code false}. + * + * @param bitIndex the index of the bit to be cleared + * @throws IndexOutOfBoundsException if the specified index is negative + * @since JDK1.0 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public void clear(int bitIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // if (bitIndex < 0) + // throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); + + // int wordIndex = wordIndex(bitIndex); + // if (wordIndex >= wordsInUse) + // return; + + // words[wordIndex] &= ~(1L << bitIndex); + + // recalculateWordsInUse(); + // checkInvariants(); + + if (bitIndex < 0) + throw new IndexOutOfBoundsException(); + + if (bitIndex >= bits.length) + return; + + bits[bitIndex] = false; + } + + /** + * Sets the bits from the specified {@code fromIndex} (inclusive) to the + * specified {@code toIndex} (exclusive) to {@code false}. + * + * @param fromIndex index of the first bit to be cleared + * @param toIndex index after the last bit to be cleared + * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, + * or {@code toIndex} is negative, or {@code fromIndex} is + * larger than {@code toIndex} + * @since 1.4 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public void clear(int fromIndex, int toIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // checkRange(fromIndex, toIndex); + + // if (fromIndex == toIndex) + // return; + + // int startWordIndex = wordIndex(fromIndex); + // if (startWordIndex >= wordsInUse) + // return; + + // int endWordIndex = wordIndex(toIndex - 1); + // if (endWordIndex >= wordsInUse) { + // toIndex = length(); + // endWordIndex = wordsInUse - 1; + // } + + // long firstWordMask = WORD_MASK << fromIndex; + // long lastWordMask = WORD_MASK >>> -toIndex; + // if (startWordIndex == endWordIndex) { + // // Case 1: One word + // words[startWordIndex] &= ~(firstWordMask & lastWordMask); + // } else { + // // Case 2: Multiple words + // // Handle first word + // words[startWordIndex] &= ~firstWordMask; + + // // Handle intermediate words, if any + // for (int i = startWordIndex+1; i < endWordIndex; i++) + // words[i] = 0; + + // // Handle last word + // words[endWordIndex] &= ~lastWordMask; + // } + + // recalculateWordsInUse(); + // checkInvariants(); + + checkRange(fromIndex, toIndex); + for (int i = fromIndex; i < toIndex && i < bits.length; i++) + bits[i] = false; + } + + /** + * Sets all of the bits in this BitSet to {@code false}. + * + * @since 1.4 + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public void clear() { + // DIFFBLUE MODEL LIBRARY jdk code + // while (wordsInUse > 0) + // words[--wordsInUse] = 0; + + for (int i = 0; i < bits.length; i++) + bits[i] = false; + } + + /** + * Returns the value of the bit with the specified index. The value + * is {@code true} if the bit with the index {@code bitIndex} + * is currently set in this {@code BitSet}; otherwise, the result + * is {@code false}. + * + * @param bitIndex the bit index + * @return the value of the bit with the specified index + * @throws IndexOutOfBoundsException if the specified index is negative + * + * @diffblue.limitedSupport + * We do not support exception messages. + */ + public boolean get(int bitIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // if (bitIndex < 0) + // throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); + + // checkInvariants(); + + // int wordIndex = wordIndex(bitIndex); + // return (wordIndex < wordsInUse) + // && ((words[wordIndex] & (1L << bitIndex)) != 0); + + if (bitIndex < 0) + throw new IndexOutOfBoundsException(); + + return bitIndex < bits.length && bits[bitIndex]; + } + + /** + * Returns a new {@code BitSet} composed of bits from this {@code BitSet} + * from {@code fromIndex} (inclusive) to {@code toIndex} (exclusive). + * + * @param fromIndex index of the first bit to include + * @param toIndex index after the last bit to include + * @return a new {@code BitSet} from a range of this {@code BitSet} + * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, + * or {@code toIndex} is negative, or {@code fromIndex} is + * larger than {@code toIndex} + * @since 1.4 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public BitSet get(int fromIndex, int toIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // checkRange(fromIndex, toIndex); + // + // checkInvariants(); + + // int len = length(); + + // // If no set bits in range return empty bitset + // if (len <= fromIndex || fromIndex == toIndex) + // return new BitSet(0); + + // // An optimization + // if (toIndex > len) + // toIndex = len; + + // BitSet result = new BitSet(toIndex - fromIndex); + // int targetWords = wordIndex(toIndex - fromIndex - 1) + 1; + // int sourceIndex = wordIndex(fromIndex); + // boolean wordAligned = ((fromIndex & BIT_INDEX_MASK) == 0); + + // // Process all words but the last word + // for (int i = 0; i < targetWords - 1; i++, sourceIndex++) + // result.words[i] = wordAligned ? words[sourceIndex] : + // (words[sourceIndex] >>> fromIndex) | + // (words[sourceIndex+1] << -fromIndex); + + // // Process the last word + // long lastWordMask = WORD_MASK >>> -toIndex; + // result.words[targetWords - 1] = + // ((toIndex-1) & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK) + // ? /* straddles source words */ + // ((words[sourceIndex] >>> fromIndex) | + // (words[sourceIndex+1] & lastWordMask) << -fromIndex) + // : + // ((words[sourceIndex] & lastWordMask) >>> fromIndex); + + // // Set wordsInUse correctly + // result.wordsInUse = targetWords; + // result.recalculateWordsInUse(); + // result.checkInvariants(); + + // return result; + + checkRange(fromIndex, toIndex); + + BitSet b = new BitSet(); + + b.cproverEnsureCapacity(toIndex - fromIndex); + for (int i = fromIndex; i < toIndex; i++) { + int newIndex = i - fromIndex; + b.bits[newIndex] = i < bits.length && bits[i]; + } + + return b; + } + + /** + * Returns the index of the first bit that is set to {@code true} + * that occurs on or after the specified starting index. If no such + * bit exists then {@code -1} is returned. + * + *

To iterate over the {@code true} bits in a {@code BitSet}, + * use the following loop: + * + *

 {@code
+     * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
+     *     // operate on index i here
+     *     if (i == Integer.MAX_VALUE) {
+     *         break; // or (i+1) would overflow
+     *     }
+     * }}
+ * + * @param fromIndex the index to start checking from (inclusive) + * @return the index of the next set bit, or {@code -1} if there + * is no such bit + * @throws IndexOutOfBoundsException if the specified index is negative + * @since 1.4 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public int nextSetBit(int fromIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // if (fromIndex < 0) + // throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); + + // checkInvariants(); + + // int u = wordIndex(fromIndex); + // if (u >= wordsInUse) + // return -1; + + // long word = words[u] & (WORD_MASK << fromIndex); + + // while (true) { + // if (word != 0) + // return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word); + // if (++u == wordsInUse) + // return -1; + // word = words[u]; + // } + + if (fromIndex < 0) + throw new IndexOutOfBoundsException(); + + for (int i = fromIndex; i < bits.length; i++) + if (bits[i]) + return i; + return -1; + } + + /** + * Returns the index of the first bit that is set to {@code false} + * that occurs on or after the specified starting index. + * + * @param fromIndex the index to start checking from (inclusive) + * @return the index of the next clear bit + * @throws IndexOutOfBoundsException if the specified index is negative + * @since 1.4 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public int nextClearBit(int fromIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // // Neither spec nor implementation handle bitsets of maximal length. + // // See 4816253. + // if (fromIndex < 0) + // throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); + + // checkInvariants(); + + // int u = wordIndex(fromIndex); + // if (u >= wordsInUse) + // return fromIndex; + + // long word = ~words[u] & (WORD_MASK << fromIndex); + + // while (true) { + // if (word != 0) + // return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word); + // if (++u == wordsInUse) + // return wordsInUse * BITS_PER_WORD; + // word = ~words[u]; + // } + + if (fromIndex < 0) + throw new IndexOutOfBoundsException(); + + for (int i = fromIndex; i < bits.length; i++) + if (!bits[i]) + return i; + return bits.length; + } + + /** + * Returns the index of the nearest bit that is set to {@code true} + * that occurs on or before the specified starting index. + * If no such bit exists, or if {@code -1} is given as the + * starting index, then {@code -1} is returned. + * + *

To iterate over the {@code true} bits in a {@code BitSet}, + * use the following loop: + * + *

 {@code
+     * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
+     *     // operate on index i here
+     * }}
+ * + * @param fromIndex the index to start checking from (inclusive) + * @return the index of the previous set bit, or {@code -1} if there + * is no such bit + * @throws IndexOutOfBoundsException if the specified index is less + * than {@code -1} + * @since 1.7 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public int previousSetBit(int fromIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // if (fromIndex < 0) { + // if (fromIndex == -1) + // return -1; + // throw new IndexOutOfBoundsException( + // "fromIndex < -1: " + fromIndex); + // } + + // checkInvariants(); + + // int u = wordIndex(fromIndex); + // if (u >= wordsInUse) + // return length() - 1; + + // long word = words[u] & (WORD_MASK >>> -(fromIndex+1)); + + // while (true) { + // if (word != 0) + // return (u+1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word); + // if (u-- == 0) + // return -1; + // word = words[u]; + // } + + if (fromIndex < 0) { + if (fromIndex == -1) + return -1; + throw new IndexOutOfBoundsException(); + } + + int start = Math.min(bits.length - 1, fromIndex); + + for (int i = start; i >= 0; i--) + if (bits[i]) + return i; + return -1; + } + + /** + * Returns the index of the nearest bit that is set to {@code false} + * that occurs on or before the specified starting index. + * If no such bit exists, or if {@code -1} is given as the + * starting index, then {@code -1} is returned. + * + * @param fromIndex the index to start checking from (inclusive) + * @return the index of the previous clear bit, or {@code -1} if there + * is no such bit + * @throws IndexOutOfBoundsException if the specified index is less + * than {@code -1} + * @since 1.7 + * + * @diffblue.limitedSupport + * We do not support exception messages. + * + * @diffblue.untested + */ + public int previousClearBit(int fromIndex) { + // DIFFBLUE MODEL LIBRARY jdk code + // if (fromIndex < 0) { + // if (fromIndex == -1) + // return -1; + // throw new IndexOutOfBoundsException( + // "fromIndex < -1: " + fromIndex); + // } + + // checkInvariants(); + + // int u = wordIndex(fromIndex); + // if (u >= wordsInUse) + // return fromIndex; + + // long word = ~words[u] & (WORD_MASK >>> -(fromIndex+1)); + + // while (true) { + // if (word != 0) + // return (u+1) * BITS_PER_WORD -1 - Long.numberOfLeadingZeros(word); + // if (u-- == 0) + // return -1; + // word = ~words[u]; + // } + + if (fromIndex < 0) { + if (fromIndex == -1) + return -1; + throw new IndexOutOfBoundsException(); + } + + if (fromIndex >= bits.length) + return fromIndex; + + for (int i = fromIndex; i >= 0; i--) + if (!bits[i]) + return i; + return -1; + } + + /** + * Returns the "logical size" of this {@code BitSet}: the index of + * the highest set bit in the {@code BitSet} plus one. Returns zero + * if the {@code BitSet} contains no set bits. + * + * @return the logical size of this {@code BitSet} + * @since 1.2 + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public int length() { + // DIFFBLUE MODEL LIBRARY jdk code + // if (wordsInUse == 0) + // return 0; + + // return BITS_PER_WORD * (wordsInUse - 1) + + // (BITS_PER_WORD - Long.numberOfLeadingZeros(words[wordsInUse - 1])); + + for (int i = bits.length - 1; i >= 0; i--) + if (bits[i]) + return i+1; + return 0; + } + + /** + * Returns true if this {@code BitSet} contains no bits that are set + * to {@code true}. + * + * @return boolean indicating whether this {@code BitSet} is empty + * @since 1.4 + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public boolean isEmpty() { + // DIFFBLUE MODEL LIBRARY jdk code + // return wordsInUse == 0; + + return length() == 0; + } + + /** + * Returns true if the specified {@code BitSet} has any bits set to + * {@code true} that are also set to {@code true} in this {@code BitSet}. + * + * @param set {@code BitSet} to intersect with + * @return boolean indicating whether this {@code BitSet} intersects + * the specified {@code BitSet} + * @since 1.4 + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public boolean intersects(BitSet set) { + // DIFFBLUE MODEL LIBRARY jdk code + // for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--) + // if ((words[i] & set.words[i]) != 0) + // return true; + // return false; + + int minSize = Math.min(bits.length, set.bits.length); + for (int i = 0; i < minSize; i++) + if (bits[i] && set.bits[i]) return true; + return false; + } + + /** + * Returns the number of bits set to {@code true} in this {@code BitSet}. + * + * @return the number of bits set to {@code true} in this {@code BitSet} + * @since 1.4 + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public int cardinality() { + // DIFFBLUE MODEL LIBRARY jdk code + // int sum = 0; + // for (int i = 0; i < wordsInUse; i++) + // sum += Long.bitCount(words[i]); + // return sum; + + int sum = 0; + for (int i = 0; i < bits.length; i++) + if (bits[i]) sum++; + return sum; + } + + /** + * Performs a logical AND of this target bit set with the + * argument bit set. This bit set is modified so that each bit in it + * has the value {@code true} if and only if it both initially + * had the value {@code true} and the corresponding bit in the + * bit set argument also had the value {@code true}. + * + * @param set a bit set + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public void and(BitSet set) { + // if (this == set) + // return; + + // while (wordsInUse > set.wordsInUse) + // words[--wordsInUse] = 0; + + // // Perform logical AND on words in common + // for (int i = 0; i < wordsInUse; i++) + // words[i] &= set.words[i]; + + // recalculateWordsInUse(); + // checkInvariants(); + + int minSize = Math.min(bits.length, set.bits.length); + + for (int i = 0; i < minSize; i++) { + bits[i] = bits[i] && set.bits[i]; + } + + for (int i = minSize; i < bits.length; i++) { + bits[i] = false; + } + } + + /** + * Performs a logical OR of this bit set with the bit set + * argument. This bit set is modified so that a bit in it has the + * value {@code true} if and only if it either already had the + * value {@code true} or the corresponding bit in the bit set + * argument has the value {@code true}. + * + * @param set a bit set + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public void or(BitSet set) { + // DIFFBLUE MODEL LIBRARY jdk code + // int wordsInCommon = Math.min(wordsInUse, set.wordsInUse); + + // if (wordsInUse < set.wordsInUse) { + // ensureCapacity(set.wordsInUse); + // wordsInUse = set.wordsInUse; + // } + + // // Perform logical OR on words in common + // for (int i = 0; i < wordsInCommon; i++) + // words[i] |= set.words[i]; + + // // Copy any remaining words + // if (wordsInCommon < set.wordsInUse) + // System.arraycopy(set.words, wordsInCommon, + // words, wordsInCommon, + // wordsInUse - wordsInCommon); + + // // recalculateWordsInUse() is unnecessary + // checkInvariants(); + + CProver.assume(bits.length >= set.bits.length); + + for (int i = 0; i < set.bits.length; i++) + bits[i] = bits[i] || set.bits[i]; + } + + /** + * Performs a logical XOR of this bit set with the bit set + * argument. This bit set is modified so that a bit in it has the + * value {@code true} if and only if one of the following + * statements holds: + *
    + *
  • The bit initially has the value {@code true}, and the + * corresponding bit in the argument has the value {@code false}. + *
  • The bit initially has the value {@code false}, and the + * corresponding bit in the argument has the value {@code true}. + *
+ * + * @param set a bit set + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public void xor(BitSet set) { + // DIFFBLUE MODEL LIBRARY jdk code + // int wordsInCommon = Math.min(wordsInUse, set.wordsInUse); + + // if (wordsInUse < set.wordsInUse) { + // ensureCapacity(set.wordsInUse); + // wordsInUse = set.wordsInUse; + // } + + // // Perform logical XOR on words in common + // for (int i = 0; i < wordsInCommon; i++) + // words[i] ^= set.words[i]; + + // // Copy any remaining words + // if (wordsInCommon < set.wordsInUse) + // System.arraycopy(set.words, wordsInCommon, + // words, wordsInCommon, + // set.wordsInUse - wordsInCommon); + + // recalculateWordsInUse(); + // checkInvariants(); + + CProver.assume(bits.length >= set.bits.length); + + for (int i = 0; i < set.bits.length; i++) + bits[i] = bits[i] != set.bits[i]; + } + + /** + * Clears all of the bits in this {@code BitSet} whose corresponding + * bit is set in the specified {@code BitSet}. + * + * @param set the {@code BitSet} with which to mask this + * {@code BitSet} + * @since 1.2 + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public void andNot(BitSet set) { + // DIFFBLUE MODEL LIBRARY jdk code + // // Perform logical (a & !b) on words in common + // for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--) + // words[i] &= ~set.words[i]; + + // recalculateWordsInUse(); + // checkInvariants(); + + CProver.assume(bits.length >= set.bits.length); + + for (int i = 0; i < set.bits.length; i++) { + bits[i] = bits[i] && !set.bits[i]; + } + } + + /** + * Returns the hash code value for this bit set. The hash code depends + * only on which bits are set within this {@code BitSet}. + * + *

The hash code is defined to be the result of the following + * calculation: + *

 {@code
+     * public int hashCode() {
+     *     long h = 1234;
+     *     long[] words = toLongArray();
+     *     for (int i = words.length; --i >= 0; )
+     *         h ^= words[i] * (i + 1);
+     *     return (int)((h >> 32) ^ h);
+     * }}
+ * Note that the hash code changes if the set of bits is altered. + * + * @return the hash code value for this bit set + * + * @diffblue.limitedSupport Will always return 0 + * @diffblue.untested + */ + public int hashCode() { + // DIFFBLUE MODEL LIBRARY jdk code + // long h = 1234; + // for (int i = wordsInUse; --i >= 0; ) + // h ^= words[i] * (i + 1); + + // return (int)((h >> 32) ^ h); + + return 0; + } + + /** + * Returns the number of bits of space actually in use by this + * {@code BitSet} to represent bit values. + * The maximum element in the set is the size - 1st element. + * + * @return the number of bits currently in this bit set + * + * @diffblue.fullSupport This methods mimics behaviour of the original + * implementation, which is based on 64-bit words. In other words, + * it returns the smallest multiple of 64 that's at least length() + * + * @diffblue.untested + */ + public int size() { + // DIFFBLUE MODEL LIBRARY jdk code + // return words.length * BITS_PER_WORD; + + int len = length(); + int result = (len >> 6) << 6; + return (result < len) ? result + 64 : result; + } + + /** + * Compares this object against the specified object. + * The result is {@code true} if and only if the argument is + * not {@code null} and is a {@code Bitset} object that has + * exactly the same set of bits set to {@code true} as this bit + * set. That is, for every nonnegative {@code int} index {@code k}, + *
((BitSet)obj).get(k) == this.get(k)
+ * must be true. The current sizes of the two bit sets are not compared. + * + * @param obj the object to compare with + * @return {@code true} if the objects are the same; + * {@code false} otherwise + * @see #size() + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public boolean equals(Object obj) { + // DIFFBLUE MODEL LIBRARY jdk code + // if (!(obj instanceof BitSet)) + // return false; + + // BitSet set = (BitSet) obj; + + // checkInvariants(); + // set.checkInvariants(); + + // if (wordsInUse != set.wordsInUse) + // return false; + + // // Check words in use by both BitSets + // for (int i = 0; i < wordsInUse; i++) + // if (words[i] != set.words[i]) + // return false; + + // return true; + + if (!(obj instanceof BitSet)) + return false; + + BitSet set = (BitSet) obj; + + int maxSize = Math.max(bits.length, set.bits.length); + for (int i = 0; i < maxSize; i++) { + if (get(i) != set.get(i)) + return false; + } + return true; + } + + /** + * Cloning this {@code BitSet} produces a new {@code BitSet} + * that is equal to it. + * The clone of the bit set is another bit set that has exactly the + * same bits set to {@code true} as this bit set. + * + * @return a clone of this bit set + * @see #size() + * + * @diffblue.noSupport + */ + public Object clone() { + // DIFFBLUE MODEL LIBRARY jdk code + // if (! sizeIsSticky) + // trimToSize(); + + // try { + // BitSet result = (BitSet) super.clone(); + // result.words = words.clone(); + // result.checkInvariants(); + // return result; + // } catch (CloneNotSupportedException e) { + // throw new InternalError(e); + // } + + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + /** + * Attempts to reduce internal storage used for the bits in this bit set. + * Calling this method may, but is not required to, affect the value + * returned by a subsequent call to the {@link #size()} method. + */ + // DIFFBLUE MODEL LIBRARY Private method not used in model + // private void trimToSize() { + // if (wordsInUse != words.length) { + // words = Arrays.copyOf(words, wordsInUse); + // checkInvariants(); + // } + // } + + /** + * Save the state of the {@code BitSet} instance to a stream (i.e., + * serialize it). + */ + // DIFFBLUE MODEL LIBRARY Private method not used in model + // private void writeObject(ObjectOutputStream s) + // throws IOException { + + // checkInvariants(); + + // if (! sizeIsSticky) + // trimToSize(); + + // ObjectOutputStream.PutField fields = s.putFields(); + // fields.put("bits", words); + // s.writeFields(); + // } + + /** + * Reconstitute the {@code BitSet} instance from a stream (i.e., + * deserialize it). + */ + // DIFFBLUE MODEL LIBRARY Private method not used in model + // private void readObject(ObjectInputStream s) + // throws IOException, ClassNotFoundException { + + // ObjectInputStream.GetField fields = s.readFields(); + // words = (long[]) fields.get("bits", null); + + // // Assume maximum length then find real length + // // because recalculateWordsInUse assumes maintenance + // // or reduction in logical size + // wordsInUse = words.length; + // recalculateWordsInUse(); + // sizeIsSticky = (words.length > 0 && words[words.length-1] == 0L); // heuristic + // checkInvariants(); + // } + + /** + * Returns a string representation of this bit set. For every index + * for which this {@code BitSet} contains a bit in the set + * state, the decimal representation of that index is included in + * the result. Such indices are listed in order from lowest to + * highest, separated by ", " (a comma and a space) and + * surrounded by braces, resulting in the usual mathematical + * notation for a set of integers. + * + *

Example: + *

+     * BitSet drPepper = new BitSet();
+ * Now {@code drPepper.toString()} returns "{@code {}}". + *
+     * drPepper.set(2);
+ * Now {@code drPepper.toString()} returns "{@code {2}}". + *
+     * drPepper.set(4);
+     * drPepper.set(10);
+ * Now {@code drPepper.toString()} returns "{@code {2, 4, 10}}". + * + * @return a string representation of this bit set + * + * @diffblue.fullSupport + * @diffblue.untested + */ + public String toString() { + // DIFFBLUE MODEL LIBRARY jdk code + // checkInvariants(); + + // int numBits = (wordsInUse > 128) ? + // cardinality() : wordsInUse * BITS_PER_WORD; + // StringBuilder b = new StringBuilder(6*numBits + 2); + // b.append('{'); + + // int i = nextSetBit(0); + // if (i != -1) { + // b.append(i); + // while (true) { + // if (++i < 0) break; + // if ((i = nextSetBit(i)) < 0) break; + // int endOfRun = nextClearBit(i); + // do { b.append(", ").append(i); } + // while (++i != endOfRun); + // } + // } + + // b.append('}'); + // return b.toString(); + + StringBuilder b = new StringBuilder(); + b.append('{'); + + int len = length(); + for (int i = 0; i < len - 1; i++) { + if(bits[i]) { + b.append(i); + b.append(", "); + } + } + + if (len > 0) // then also "&& bits[len-1]" + b.append(len - 1); + + b.append('}'); + return b.toString(); + } + + /** + * Returns a stream of indices for which this {@code BitSet} + * contains a bit in the set state. The indices are returned + * in order, from lowest to highest. The size of the stream + * is the number of bits in the set state, equal to the value + * returned by the {@link #cardinality()} method. + * + *

The bit set must remain constant during the execution of the + * terminal stream operation. Otherwise, the result of the terminal + * stream operation is undefined. + * + * @return a stream of integers representing set indices + * @since 1.8 + * + * @diffblue.noSupport + */ + public IntStream stream() { + // DIFFBLUE MODEL LIBRARY jdk code + // class BitSetIterator implements PrimitiveIterator.OfInt { + // int next = nextSetBit(0); + + // @Override + // public boolean hasNext() { + // return next != -1; + // } + + // @Override + // public int nextInt() { + // if (next != -1) { + // int ret = next; + // next = nextSetBit(next+1); + // return ret; + // } else { + // throw new NoSuchElementException(); + // } + // } + // } + + // return StreamSupport.intStream( + // () -> Spliterators.spliterator( + // new BitSetIterator(), cardinality(), + // Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED), + // Spliterator.SIZED | Spliterator.SUBSIZED | + // Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED, + // false); + + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + // DIFFBLUE MODEL LIBRARY + // On nondeterministic object creation we make sure that + // the underlying array is not null. + @org.cprover.MustNotThrow + protected void cproverNondetInitialize() { + CProver.assume(bits != null); + } + +} diff --git a/src/main/java/java/util/Collection.java b/src/main/java/java/util/Collection.java new file mode 100644 index 0000000..2ae8872 --- /dev/null +++ b/src/main/java/java/util/Collection.java @@ -0,0 +1,604 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.util.function.Predicate; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * The root interface in the collection hierarchy. A collection + * represents a group of objects, known as its elements. Some + * collections allow duplicate elements and others do not. Some are ordered + * and others unordered. The JDK does not provide any direct + * implementations of this interface: it provides implementations of more + * specific subinterfaces like Set and List. This interface + * is typically used to pass collections around and manipulate them where + * maximum generality is desired. + * + *

Bags or multisets (unordered collections that may contain + * duplicate elements) should implement this interface directly. + * + *

All general-purpose Collection implementation classes (which + * typically implement Collection indirectly through one of its + * subinterfaces) should provide two "standard" constructors: a void (no + * arguments) constructor, which creates an empty collection, and a + * constructor with a single argument of type Collection, which + * creates a new collection with the same elements as its argument. In + * effect, the latter constructor allows the user to copy any collection, + * producing an equivalent collection of the desired implementation type. + * There is no way to enforce this convention (as interfaces cannot contain + * constructors) but all of the general-purpose Collection + * implementations in the Java platform libraries comply. + * + *

The "destructive" methods contained in this interface, that is, the + * methods that modify the collection on which they operate, are specified to + * throw UnsupportedOperationException if this collection does not + * support the operation. If this is the case, these methods may, but are not + * required to, throw an UnsupportedOperationException if the + * invocation would have no effect on the collection. For example, invoking + * the {@link #addAll(Collection)} method on an unmodifiable collection may, + * but is not required to, throw the exception if the collection to be added + * is empty. + * + *

+ * Some collection implementations have restrictions on the elements that + * they may contain. For example, some implementations prohibit null elements, + * and some have restrictions on the types of their elements. Attempting to + * add an ineligible element throws an unchecked exception, typically + * NullPointerException or ClassCastException. Attempting + * to query the presence of an ineligible element may throw an exception, + * or it may simply return false; some implementations will exhibit the former + * behavior and some will exhibit the latter. More generally, attempting an + * operation on an ineligible element whose completion would not result in + * the insertion of an ineligible element into the collection may throw an + * exception or it may succeed, at the option of the implementation. + * Such exceptions are marked as "optional" in the specification for this + * interface. + * + *

It is up to each collection to determine its own synchronization + * policy. In the absence of a stronger guarantee by the + * implementation, undefined behavior may result from the invocation + * of any method on a collection that is being mutated by another + * thread; this includes direct invocations, passing the collection to + * a method that might perform invocations, and using an existing + * iterator to examine the collection. + * + *

Many methods in Collections Framework interfaces are defined in + * terms of the {@link Object#equals(Object) equals} method. For example, + * the specification for the {@link #contains(Object) contains(Object o)} + * method says: "returns true if and only if this collection + * contains at least one element e such that + * (o==null ? e==null : o.equals(e))." This specification should + * not be construed to imply that invoking Collection.contains + * with a non-null argument o will cause o.equals(e) to be + * invoked for any element e. Implementations are free to implement + * optimizations whereby the equals invocation is avoided, for + * example, by first comparing the hash codes of the two elements. (The + * {@link Object#hashCode()} specification guarantees that two objects with + * unequal hash codes cannot be equal.) More generally, implementations of + * the various Collections Framework interfaces are free to take advantage of + * the specified behavior of underlying {@link Object} methods wherever the + * implementor deems it appropriate. + * + *

Some collection operations which perform recursive traversal of the + * collection may fail with an exception for self-referential instances where + * the collection directly or indirectly contains itself. This includes the + * {@code clone()}, {@code equals()}, {@code hashCode()} and {@code toString()} + * methods. Implementations may optionally handle the self-referential scenario, + * however most current implementations do not do so. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @implSpec + * The default method implementations (inherited or otherwise) do not apply any + * synchronization protocol. If a {@code Collection} implementation has a + * specific synchronization protocol, then it must override default + * implementations to apply that protocol. + * + * @param the type of elements in this collection + * + * @author Josh Bloch + * @author Neal Gafter + * @see Set + * @see List + * @see Map + * @see SortedSet + * @see SortedMap + * @see HashSet + * @see TreeSet + * @see ArrayList + * @see LinkedList + * @see Vector + * @see Collections + * @see Arrays + * @see AbstractCollection + * @since 1.2 + */ + +public interface Collection extends Iterable { + // Query Operations + + /** + * Returns the number of elements in this collection. If this collection + * contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this collection + */ + int size(); + + /** + * Returns true if this collection contains no elements. + * + * @return true if this collection contains no elements + */ + boolean isEmpty(); + + /** + * Returns true if this collection contains the specified element. + * More formally, returns true if and only if this collection + * contains at least one element e such that + * (o==null ? e==null : o.equals(e)). + * + * @param o element whose presence in this collection is to be tested + * @return true if this collection contains the specified + * element + * @throws ClassCastException if the type of the specified element + * is incompatible with this collection + * (optional) + * @throws NullPointerException if the specified element is null and this + * collection does not permit null elements + * (optional) + */ + boolean contains(Object o); + + /** + * Returns an iterator over the elements in this collection. There are no + * guarantees concerning the order in which the elements are returned + * (unless this collection is an instance of some class that provides a + * guarantee). + * + * @return an Iterator over the elements in this collection + */ + Iterator iterator(); + + /** + * Returns an array containing all of the elements in this collection. + * If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements in + * the same order. + * + *

The returned array will be "safe" in that no references to it are + * maintained by this collection. (In other words, this method must + * allocate a new array even if this collection is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this collection + */ + Object[] toArray(); + + /** + * Returns an array containing all of the elements in this collection; + * the runtime type of the returned array is that of the specified array. + * If the collection fits in the specified array, it is returned therein. + * Otherwise, a new array is allocated with the runtime type of the + * specified array and the size of this collection. + * + *

If this collection fits in the specified array with room to spare + * (i.e., the array has more elements than this collection), the element + * in the array immediately following the end of the collection is set to + * null. (This is useful in determining the length of this + * collection only if the caller knows that this collection does + * not contain any null elements.) + * + *

If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements in + * the same order. + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose x is a collection known to contain only strings. + * The following code can be used to dump the collection into a newly + * allocated array of String: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that toArray(new Object[0]) is identical in function to + * toArray(). + * + * @param the runtime type of the array to contain the collection + * @param a the array into which the elements of this collection are to be + * stored, if it is big enough; otherwise, a new array of the same + * runtime type is allocated for this purpose. + * @return an array containing all of the elements in this collection + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this collection + * @throws NullPointerException if the specified array is null + */ + T[] toArray(T[] a); + + // Modification Operations + + /** + * Ensures that this collection contains the specified element (optional + * operation). Returns true if this collection changed as a + * result of the call. (Returns false if this collection does + * not permit duplicates and already contains the specified element.)

+ * + * Collections that support this operation may place limitations on what + * elements may be added to this collection. In particular, some + * collections will refuse to add null elements, and others will + * impose restrictions on the type of elements that may be added. + * Collection classes should clearly specify in their documentation any + * restrictions on what elements may be added.

+ * + * If a collection refuses to add a particular element for any reason + * other than that it already contains the element, it must throw + * an exception (rather than returning false). This preserves + * the invariant that a collection always contains the specified element + * after this call returns. + * + * @param e element whose presence in this collection is to be ensured + * @return true if this collection changed as a result of the + * call + * @throws UnsupportedOperationException if the add operation + * is not supported by this collection + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this collection + * @throws NullPointerException if the specified element is null and this + * collection does not permit null elements + * @throws IllegalArgumentException if some property of the element + * prevents it from being added to this collection + * @throws IllegalStateException if the element cannot be added at this + * time due to insertion restrictions + */ + boolean add(E e); + + /** + * Removes a single instance of the specified element from this + * collection, if it is present (optional operation). More formally, + * removes an element e such that + * (o==null ? e==null : o.equals(e)), if + * this collection contains one or more such elements. Returns + * true if this collection contained the specified element (or + * equivalently, if this collection changed as a result of the call). + * + * @param o element to be removed from this collection, if present + * @return true if an element was removed as a result of this call + * @throws ClassCastException if the type of the specified element + * is incompatible with this collection + * (optional) + * @throws NullPointerException if the specified element is null and this + * collection does not permit null elements + * (optional) + * @throws UnsupportedOperationException if the remove operation + * is not supported by this collection + */ + boolean remove(Object o); + + + // Bulk Operations + + /** + * Returns true if this collection contains all of the elements + * in the specified collection. + * + * @param c collection to be checked for containment in this collection + * @return true if this collection contains all of the elements + * in the specified collection + * @throws ClassCastException if the types of one or more elements + * in the specified collection are incompatible with this + * collection + * (optional) + * @throws NullPointerException if the specified collection contains one + * or more null elements and this collection does not permit null + * elements + * (optional), + * or if the specified collection is null. + * @see #contains(Object) + */ + boolean containsAll(Collection c); + + /** + * Adds all of the elements in the specified collection to this collection + * (optional operation). The behavior of this operation is undefined if + * the specified collection is modified while the operation is in progress. + * (This implies that the behavior of this call is undefined if the + * specified collection is this collection, and this collection is + * nonempty.) + * + * @param c collection containing elements to be added to this collection + * @return true if this collection changed as a result of the call + * @throws UnsupportedOperationException if the addAll operation + * is not supported by this collection + * @throws ClassCastException if the class of an element of the specified + * collection prevents it from being added to this collection + * @throws NullPointerException if the specified collection contains a + * null element and this collection does not permit null elements, + * or if the specified collection is null + * @throws IllegalArgumentException if some property of an element of the + * specified collection prevents it from being added to this + * collection + * @throws IllegalStateException if not all the elements can be added at + * this time due to insertion restrictions + * @see #add(Object) + */ + boolean addAll(Collection c); + + /** + * Removes all of this collection's elements that are also contained in the + * specified collection (optional operation). After this call returns, + * this collection will contain no elements in common with the specified + * collection. + * + * @param c collection containing elements to be removed from this collection + * @return true if this collection changed as a result of the + * call + * @throws UnsupportedOperationException if the removeAll method + * is not supported by this collection + * @throws ClassCastException if the types of one or more elements + * in this collection are incompatible with the specified + * collection + * (optional) + * @throws NullPointerException if this collection contains one or more + * null elements and the specified collection does not support + * null elements + * (optional), + * or if the specified collection is null + * @see #remove(Object) + * @see #contains(Object) + */ + boolean removeAll(Collection c); + + /** + * Removes all of the elements of this collection that satisfy the given + * predicate. Errors or runtime exceptions thrown during iteration or by + * the predicate are relayed to the caller. + * + * @implSpec + * The default implementation traverses all elements of the collection using + * its {@link #iterator}. Each matching element is removed using + * {@link Iterator#remove()}. If the collection's iterator does not + * support removal then an {@code UnsupportedOperationException} will be + * thrown on the first matching element. + * + * @param filter a predicate which returns {@code true} for elements to be + * removed + * @return {@code true} if any elements were removed + * @throws NullPointerException if the specified filter is null + * @throws UnsupportedOperationException if elements cannot be removed + * from this collection. Implementations may throw this exception if a + * matching element cannot be removed or if, in general, removal is not + * supported. + * @since 1.8 + */ + default boolean removeIf(Predicate filter) { + Objects.requireNonNull(filter); + boolean removed = false; + final Iterator each = iterator(); + while (each.hasNext()) { + if (filter.test(each.next())) { + each.remove(); + removed = true; + } + } + return removed; + } + + /** + * Retains only the elements in this collection that are contained in the + * specified collection (optional operation). In other words, removes from + * this collection all of its elements that are not contained in the + * specified collection. + * + * @param c collection containing elements to be retained in this collection + * @return true if this collection changed as a result of the call + * @throws UnsupportedOperationException if the retainAll operation + * is not supported by this collection + * @throws ClassCastException if the types of one or more elements + * in this collection are incompatible with the specified + * collection + * (optional) + * @throws NullPointerException if this collection contains one or more + * null elements and the specified collection does not permit null + * elements + * (optional), + * or if the specified collection is null + * @see #remove(Object) + * @see #contains(Object) + */ + boolean retainAll(Collection c); + + /** + * Removes all of the elements from this collection (optional operation). + * The collection will be empty after this method returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this collection + */ + void clear(); + + + // Comparison and hashing + + /** + * Compares the specified object with this collection for equality.

+ * + * While the Collection interface adds no stipulations to the + * general contract for the Object.equals, programmers who + * implement the Collection interface "directly" (in other words, + * create a class that is a Collection but is not a Set + * or a List) must exercise care if they choose to override the + * Object.equals. It is not necessary to do so, and the simplest + * course of action is to rely on Object's implementation, but + * the implementor may wish to implement a "value comparison" in place of + * the default "reference comparison." (The List and + * Set interfaces mandate such value comparisons.)

+ * + * The general contract for the Object.equals method states that + * equals must be symmetric (in other words, a.equals(b) if and + * only if b.equals(a)). The contracts for List.equals + * and Set.equals state that lists are only equal to other lists, + * and sets to other sets. Thus, a custom equals method for a + * collection class that implements neither the List nor + * Set interface must return false when this collection + * is compared to any list or set. (By the same logic, it is not possible + * to write a class that correctly implements both the Set and + * List interfaces.) + * + * @param o object to be compared for equality with this collection + * @return true if the specified object is equal to this + * collection + * + * @see Object#equals(Object) + * @see Set#equals(Object) + * @see List#equals(Object) + */ + boolean equals(Object o); + + /** + * Returns the hash code value for this collection. While the + * Collection interface adds no stipulations to the general + * contract for the Object.hashCode method, programmers should + * take note that any class that overrides the Object.equals + * method must also override the Object.hashCode method in order + * to satisfy the general contract for the Object.hashCode method. + * In particular, c1.equals(c2) implies that + * c1.hashCode()==c2.hashCode(). + * + * @return the hash code value for this collection + * + * @see Object#hashCode() + * @see Object#equals(Object) + */ + int hashCode(); + + /** + * Creates a {@link Spliterator} over the elements in this collection. + * + * Implementations should document characteristic values reported by the + * spliterator. Such characteristic values are not required to be reported + * if the spliterator reports {@link Spliterator#SIZED} and this collection + * contains no elements. + * + *

The default implementation should be overridden by subclasses that + * can return a more efficient spliterator. In order to + * preserve expected laziness behavior for the {@link #stream()} and + * {@link #parallelStream()}} methods, spliterators should either have the + * characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be + * late-binding. + * If none of these is practical, the overriding class should describe the + * spliterator's documented policy of binding and structural interference, + * and should override the {@link #stream()} and {@link #parallelStream()} + * methods to create streams using a {@code Supplier} of the spliterator, + * as in: + *

{@code
+     *     Stream s = StreamSupport.stream(() -> spliterator(), spliteratorCharacteristics)
+     * }
+ *

These requirements ensure that streams produced by the + * {@link #stream()} and {@link #parallelStream()} methods will reflect the + * contents of the collection as of initiation of the terminal stream + * operation. + * + * @implSpec + * The default implementation creates a + * late-binding spliterator + * from the collections's {@code Iterator}. The spliterator inherits the + * fail-fast properties of the collection's iterator. + *

+ * The created {@code Spliterator} reports {@link Spliterator#SIZED}. + * + * @implNote + * The created {@code Spliterator} additionally reports + * {@link Spliterator#SUBSIZED}. + * + *

If a spliterator covers no elements then the reporting of additional + * characteristic values, beyond that of {@code SIZED} and {@code SUBSIZED}, + * does not aid clients to control, specialize or simplify computation. + * However, this does enable shared use of an immutable and empty + * spliterator instance (see {@link Spliterators#emptySpliterator()}) for + * empty collections, and enables clients to determine if such a spliterator + * covers no elements. + * + * @return a {@code Spliterator} over the elements in this collection + * @since 1.8 + */ + @Override + default Spliterator spliterator() { + return Spliterators.spliterator(this, 0); + } + + /** + * Returns a sequential {@code Stream} with this collection as its source. + * + *

This method should be overridden when the {@link #spliterator()} + * method cannot return a spliterator that is {@code IMMUTABLE}, + * {@code CONCURRENT}, or late-binding. (See {@link #spliterator()} + * for details.) + * + * @implSpec + * The default implementation creates a sequential {@code Stream} from the + * collection's {@code Spliterator}. + * + * @return a sequential {@code Stream} over the elements in this collection + * @since 1.8 + */ + default Stream stream() { + return StreamSupport.stream(spliterator(), false); + } + + /** + * Returns a possibly parallel {@code Stream} with this collection as its + * source. It is allowable for this method to return a sequential stream. + * + *

This method should be overridden when the {@link #spliterator()} + * method cannot return a spliterator that is {@code IMMUTABLE}, + * {@code CONCURRENT}, or late-binding. (See {@link #spliterator()} + * for details.) + * + * @implSpec + * The default implementation creates a parallel {@code Stream} from the + * collection's {@code Spliterator}. + * + * @return a possibly parallel {@code Stream} over the elements in this + * collection + * @since 1.8 + */ + default Stream parallelStream() { + return StreamSupport.stream(spliterator(), true); + } +} diff --git a/src/main/java/java/util/Enumeration.java b/src/main/java/java/util/Enumeration.java new file mode 100644 index 0000000..8aebb5c --- /dev/null +++ b/src/main/java/java/util/Enumeration.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1994, 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +/** + * An object that implements the Enumeration interface generates a + * series of elements, one at a time. Successive calls to the + * nextElement method return successive elements of the + * series. + *

+ * For example, to print all elements of a Vector<E> v: + *

+ *   for (Enumeration<E> e = v.elements(); e.hasMoreElements();)
+ *       System.out.println(e.nextElement());
+ *

+ * Methods are provided to enumerate through the elements of a + * vector, the keys of a hashtable, and the values in a hashtable. + * Enumerations are also used to specify the input streams to a + * SequenceInputStream. + *

+ * NOTE: The functionality of this interface is duplicated by the Iterator + * interface. In addition, Iterator adds an optional remove operation, and + * has shorter method names. New implementations should consider using + * Iterator in preference to Enumeration. + * + * @see java.util.Iterator + * @see java.io.SequenceInputStream + * @see java.util.Enumeration#nextElement() + * @see java.util.Hashtable + * @see java.util.Hashtable#elements() + * @see java.util.Hashtable#keys() + * @see java.util.Vector + * @see java.util.Vector#elements() + * + * @author Lee Boynton + * @since JDK1.0 + */ +public interface Enumeration { + /** + * Tests if this enumeration contains more elements. + * + * @return true if and only if this enumeration object + * contains at least one more element to provide; + * false otherwise. + */ + boolean hasMoreElements(); + + /** + * Returns the next element of this enumeration if this enumeration + * object has at least one more element to provide. + * + * @return the next element of this enumeration. + * @exception NoSuchElementException if no more elements exist. + */ + E nextElement(); +} diff --git a/src/main/java/java/util/HashMap.java b/src/main/java/java/util/HashMap.java new file mode 100644 index 0000000..0d10c25 --- /dev/null +++ b/src/main/java/java/util/HashMap.java @@ -0,0 +1,3196 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.Serializable; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.cprover.CProver; + +/** + * Hash table based implementation of the Map interface. This + * implementation provides all of the optional map operations, and permits + * null values and the null key. (The HashMap + * class is roughly equivalent to Hashtable, except that it is + * unsynchronized and permits nulls.) This class makes no guarantees as to + * the order of the map; in particular, it does not guarantee that the order + * will remain constant over time. + * + *

This implementation provides constant-time performance for the basic + * operations (get and put), assuming the hash function + * disperses the elements properly among the buckets. Iteration over + * collection views requires time proportional to the "capacity" of the + * HashMap instance (the number of buckets) plus its size (the number + * of key-value mappings). Thus, it's very important not to set the initial + * capacity too high (or the load factor too low) if iteration performance is + * important. + * + *

An instance of HashMap has two parameters that affect its + * performance: initial capacity and load factor. The + * capacity is the number of buckets in the hash table, and the initial + * capacity is simply the capacity at the time the hash table is created. The + * load factor is a measure of how full the hash table is allowed to + * get before its capacity is automatically increased. When the number of + * entries in the hash table exceeds the product of the load factor and the + * current capacity, the hash table is rehashed (that is, internal data + * structures are rebuilt) so that the hash table has approximately twice the + * number of buckets. + * + *

As a general rule, the default load factor (.75) offers a good + * tradeoff between time and space costs. Higher values decrease the + * space overhead but increase the lookup cost (reflected in most of + * the operations of the HashMap class, including + * get and put). The expected number of entries in + * the map and its load factor should be taken into account when + * setting its initial capacity, so as to minimize the number of + * rehash operations. If the initial capacity is greater than the + * maximum number of entries divided by the load factor, no rehash + * operations will ever occur. + * + *

If many mappings are to be stored in a HashMap + * instance, creating it with a sufficiently large capacity will allow + * the mappings to be stored more efficiently than letting it perform + * automatic rehashing as needed to grow the table. Note that using + * many keys with the same {@code hashCode()} is a sure way to slow + * down performance of any hash table. To ameliorate impact, when keys + * are {@link Comparable}, this class may use comparison order among + * keys to help break ties. + * + *

Note that this implementation is not synchronized. + * If multiple threads access a hash map concurrently, and at least one of + * the threads modifies the map structurally, it must be + * synchronized externally. (A structural modification is any operation + * that adds or deletes one or more mappings; merely changing the value + * associated with a key that an instance already contains is not a + * structural modification.) This is typically accomplished by + * synchronizing on some object that naturally encapsulates the map. + * + * If no such object exists, the map should be "wrapped" using the + * {@link Collections#synchronizedMap Collections.synchronizedMap} + * method. This is best done at creation time, to prevent accidental + * unsynchronized access to the map:

+ *   Map m = Collections.synchronizedMap(new HashMap(...));
+ * + *

The iterators returned by all of this class's "collection view methods" + * are fail-fast: if the map is structurally modified at any time after + * the iterator is created, in any way except through the iterator's own + * remove method, the iterator will throw a + * {@link ConcurrentModificationException}. Thus, in the face of concurrent + * modification, the iterator fails quickly and cleanly, rather than risking + * arbitrary, non-deterministic behavior at an undetermined time in the + * future. + * + *

Note that the fail-fast behavior of an iterator cannot be guaranteed + * as it is, generally speaking, impossible to make any hard guarantees in the + * presence of unsynchronized concurrent modification. Fail-fast iterators + * throw ConcurrentModificationException on a best-effort basis. + * Therefore, it would be wrong to write a program that depended on this + * exception for its correctness: the fail-fast behavior of iterators + * should be used only to detect bugs. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @param the type of keys maintained by this map + * @param the type of mapped values + * + * @author Doug Lea + * @author Josh Bloch + * @author Arthur van Hoff + * @author Neal Gafter + * @see Object#hashCode() + * @see Collection + * @see Map + * @see TreeMap + * @see Hashtable + * @since 1.2 + * + * @diffblue.limitedSupport + *

+ * For performance reasons, there may be restrictions on the number of elements + * that can be stored in the model of HashMap: + *

    + *
  • HashMaps constructed using constructors of this class will have a + * fixed capacity of CProver.defaultContainerCapacity(). + *
  • Non-deterministic HashMaps are currently only of size 0 or 1. + * Any functions that constrain a nondeterministically generated HashMap to be + * greater than a certain size may not deliver correct results. + *
  • HashMaps read from `--static-values` are currently unlimited. + *
+ * + *

Functions that make repeated calls to any method may not work correctly, for + * example, see the {@link #put} method.

+ * + *

Does not implement + *

    + *
  • TreeNode
  • + *
  • spliterators
  • + *
  • methods depending on external classes notModelled (e.g. Function)
  • + *
+ *

+ * + *

JBMC will not work correctly for hash maps on types that do + * not implement the .equals() and .hashcode() + * methods. + *

+ * + *

HashMap<ArrayList,...> is not supported because + * ArrayList.equals() cannot be implemented (needs lazy loading v2). + *

+ * + *

HashMap<StringBuilder,...> is not supported because + * of an issue. + *

+ * + *

HashMaps on array types are not supported because of an issue. + *

+ * + *

HashMaps cannot access nested HashMaps, + * HashSets, ArrayLists. + *

+ * + * There are other issues that might affect JBMC of HashMap. + * + * @diffblue.todo + */ +public class HashMap extends AbstractMap + implements Map, Cloneable, Serializable { + + // DIFFBLUE MODEL LIBRARY Private variable not used in model + // private static final long serialVersionUID = 362498820763181265L; + + /* + * Implementation notes. + * + * This map usually acts as a binned (bucketed) hash table, but + * when bins get too large, they are transformed into bins of + * TreeNodes, each structured similarly to those in + * java.util.TreeMap. Most methods try to use normal bins, but + * relay to TreeNode methods when applicable (simply by checking + * instanceof a node). Bins of TreeNodes may be traversed and + * used like any others, but additionally support faster lookup + * when overpopulated. However, since the vast majority of bins in + * normal use are not overpopulated, checking for existence of + * tree bins may be delayed in the course of table methods. + * + * Tree bins (i.e., bins whose elements are all TreeNodes) are + * ordered primarily by hashCode, but in the case of ties, if two + * elements are of the same "class C implements Comparable", + * type then their compareTo method is used for ordering. (We + * conservatively check generic types via reflection to validate + * this -- see method comparableClassFor). The added complexity + * of tree bins is worthwhile in providing worst-case O(log n) + * operations when keys either have distinct hashes or are + * orderable, Thus, performance degrades gracefully under + * accidental or malicious usages in which hashCode() methods + * return values that are poorly distributed, as well as those in + * which many keys share a hashCode, so long as they are also + * Comparable. (If neither of these apply, we may waste about a + * factor of two in time and space compared to taking no + * precautions. But the only known cases stem from poor user + * programming practices that are already so slow that this makes + * little difference.) + * + * Because TreeNodes are about twice the size of regular nodes, we + * use them only when bins contain enough nodes to warrant use + * (see TREEIFY_THRESHOLD). And when they become too small (due to + * removal or resizing) they are converted back to plain bins. In + * usages with well-distributed user hashCodes, tree bins are + * rarely used. Ideally, under random hashCodes, the frequency of + * nodes in bins follows a Poisson distribution + * (http://en.wikipedia.org/wiki/Poisson_distribution) with a + * parameter of about 0.5 on average for the default resizing + * threshold of 0.75, although with a large variance because of + * resizing granularity. Ignoring variance, the expected + * occurrences of list size k are (exp(-0.5) * pow(0.5, k) / + * factorial(k)). The first values are: + * + * 0: 0.60653066 + * 1: 0.30326533 + * 2: 0.07581633 + * 3: 0.01263606 + * 4: 0.00157952 + * 5: 0.00015795 + * 6: 0.00001316 + * 7: 0.00000094 + * 8: 0.00000006 + * more: less than 1 in ten million + * + * The root of a tree bin is normally its first node. However, + * sometimes (currently only upon Iterator.remove), the root might + * be elsewhere, but can be recovered following parent links + * (method TreeNode.root()). + * + * All applicable internal methods accept a hash code as an + * argument (as normally supplied from a public method), allowing + * them to call each other without recomputing user hashCodes. + * Most internal methods also accept a "tab" argument, that is + * normally the current table, but may be a new or old one when + * resizing or converting. + * + * When bin lists are treeified, split, or untreeified, we keep + * them in the same relative access/traversal order (i.e., field + * Node.next) to better preserve locality, and to slightly + * simplify handling of splits and traversals that invoke + * iterator.remove. When using comparators on insertion, to keep a + * total ordering (or as close as is required here) across + * rebalancings, we compare classes and identityHashCodes as + * tie-breakers. + * + * The use and transitions among plain vs tree modes is + * complicated by the existence of subclass LinkedHashMap. See + * below for hook methods defined to be invoked upon insertion, + * removal and access that allow LinkedHashMap internals to + * otherwise remain independent of these mechanics. (This also + * requires that a map instance be passed to some utility methods + * that may create new nodes.) + * + * The concurrent-programming-like SSA-based coding style helps + * avoid aliasing errors amid all of the twisty pointer operations. + */ + + /** + * The default initial capacity - MUST be a power of two. + */ + // DIFFBLUE MODEL LIBRARY Package-private variable not used in model + // static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 + + /** + * The maximum capacity, used if a higher value is implicitly specified + * by either of the constructors with arguments. + * MUST be a power of two <= 1<<30. + */ + // DIFFBLUE MODEL LIBRARY Package-private variable not used in model + // static final int MAXIMUM_CAPACITY = 1 << 30; + + /** + * The load factor used when none specified in constructor. + */ + // DIFFBLUE MODEL LIBRARY Package-private variable not used in model + // static final float DEFAULT_LOAD_FACTOR = 0.75f; + + /** + * The bin count threshold for using a tree rather than list for a + * bin. Bins are converted to trees when adding an element to a + * bin with at least this many nodes. The value must be greater + * than 2 and should be at least 8 to mesh with assumptions in + * tree removal about conversion back to plain bins upon + * shrinkage. + */ + // DIFFBLUE MODEL LIBRARY Package-private variable not used in model + // static final int TREEIFY_THRESHOLD = 8; + + /** + * The bin count threshold for untreeifying a (split) bin during a + * resize operation. Should be less than TREEIFY_THRESHOLD, and at + * most 6 to mesh with shrinkage detection under removal. + */ + // DIFFBLUE MODEL LIBRARY Package-private variable not used in model + // static final int UNTREEIFY_THRESHOLD = 6; + + /** + * The smallest table capacity for which bins may be treeified. + * (Otherwise the table is resized if too many nodes in a bin.) + * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts + * between resizing and treeification thresholds. + */ + // DIFFBLUE MODEL LIBRARY Package-private variable not used in model + // static final int MIN_TREEIFY_CAPACITY = 64; + + // DIFFBLUE MODEL LIBRARY + // Limit for the initialCapacity value passed as argument to a constructor. + // Prevents out of memory errors in the JVM when running generated traces. + // Actual behaviour will depend on the memory limits of the JVM. + static final int CPROVER_MAX_CAPACITY = 1 << 20; + + /** + * Basic hash bin node, used for most entries. (See below for + * TreeNode subclass, and in LinkedHashMap for its Entry subclass.) + * + * @diffblue.limitedSupport + * In the original implementation, HashMap uses an array of nodes which can + * be part of either a linked list or tree list. + * We use a simplified version where each array entry is simply a pair of + * one key and one value. + * While it would make more sense to call this class Pair rather than Node, + * we keep the original name to stay as close as possible to the original + * code and for compatibility with subclasses. + * + * The methods equals() and toString() are not modelled for this inner class, + * though this should not affect the overall use of the Node class + * by HashMap. + */ + static class Node implements Map.Entry { + // DIFFBLUE MODEL LIBRARY Variable not needed in model. + // final int hash; + final K key; + V value; + // DIFFBLUE MODEL LIBRARY Variable not needed in model. + // Node next; + + // DIFFBLUE MODEL LIBRARY + // We use a simplified constructor that only takes two arguments. + // Node(int hash, K key, V value, Node next) { + // this.hash = hash; + // this.key = key; + // this.value = value; + // this.next = next; + // } + Node(K key, V value) { + this.key = key; + this.value = value; + } + + public final K getKey() { return key; } + public final V getValue() { return value; } + public final String toString() { + // return key + "=" + value; + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + // DIFFBLUE MODEL LIBRARY + // Always return 0 to be consistent with the current model of + // Object.hashCode. + public final int hashCode() { + // return Objects.hashCode(key) ^ Objects.hashCode(value); + return 0; + } + + public final V setValue(V newValue) { + V oldValue = value; + value = newValue; + return oldValue; + } + + public final boolean equals(Object o) { + // if (o == this) + // return true; + // if (o instanceof Map.Entry) { + // Map.Entry e = (Map.Entry)o; + // if (Objects.equals(key, e.getKey()) && + // Objects.equals(value, e.getValue())) + // return true; + // } + // return false; + CProver.notModelled(); + return CProver.nondetBoolean(); + } + } + + /* ---------------- Static utilities -------------- */ + + /** + * Computes key.hashCode() and spreads (XORs) higher bits of hash + * to lower. Because the table uses power-of-two masking, sets of + * hashes that vary only in bits above the current mask will + * always collide. (Among known examples are sets of Float keys + * holding consecutive whole numbers in small tables.) So we + * apply a transform that spreads the impact of higher bits + * downward. There is a tradeoff between speed, utility, and + * quality of bit-spreading. Because many common sets of hashes + * are already reasonably distributed (so don't benefit from + * spreading), and because we use trees to handle large sets of + * collisions in bins, we just XOR some shifted bits in the + * cheapest possible way to reduce systematic lossage, as well as + * to incorporate impact of the highest bits that would otherwise + * never be used in index calculations because of table bounds. + */ + // DIFFBLUE MODEL LIBRARY Package-private method not used in model + // static final int hash(Object key) { + // int h; + // return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); + // } + + /** + * Returns x's Class if it is of the form "class C implements + * Comparable", else null. + */ + // DIFFBLUE MODEL LIBRARY Package-private method not used in model + // static Class comparableClassFor(Object x) { + // if (x instanceof Comparable) { + // Class c; Type[] ts, as; Type t; ParameterizedType p; + // if ((c = x.getClass()) == String.class) // bypass checks + // return c; + // if ((ts = c.getGenericInterfaces()) != null) { + // for (int i = 0; i < ts.length; ++i) { + // if (((t = ts[i]) instanceof ParameterizedType) && + // ((p = (ParameterizedType)t).getRawType() == + // Comparable.class) && + // (as = p.getActualTypeArguments()) != null && + // as.length == 1 && as[0] == c) // type arg is c + // return c; + // } + // } + // } + // return null; + // } + + /** + * Returns k.compareTo(x) if x matches kc (k's screened comparable + * class), else 0. + */ + // DIFFBLUE MODEL LIBRARY Package-private method not used in model + // @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable + // static int compareComparables(Class kc, Object k, Object x) { + // return (x == null || x.getClass() != kc ? 0 : + // ((Comparable)k).compareTo(x)); + // } + + /** + * Returns a power of two size for the given target capacity. + */ + // DIFFBLUE MODEL LIBRARY Package-private method not used in model + // static final int tableSizeFor(int cap) { + // int n = cap - 1; + // n |= n >>> 1; + // n |= n >>> 2; + // n |= n >>> 4; + // n |= n >>> 8; + // n |= n >>> 16; + // return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; + // } + + /* ---------------- Fields -------------- */ + + /** + * The table, initialized on first use, and resized as + * necessary. When allocated, length is always a power of two. + * (We also tolerate length zero in some operations to allow + * bootstrapping mechanics that are currently not needed.) + */ + // DIFFBLUE MODEL LIBRARY + // This field is allowed to be null in the original implementation to save + // memory, but in the model we restrict it to be non-null to restrict the + // number of branches to consider. + transient Node[] table; + + /** + * Holds cached entrySet(). Note that AbstractMap fields are used + * for keySet() and values(). + */ + // DIFFBLUE MODEL LIBRARY + // This field is never read in our model. We include it because some + // classes which extend this one reference it. + // transient Set> entrySet; + transient Set> entrySet = null; + + /** + * The number of key-value mappings contained in this map. + */ + transient int size; + + /** + * The number of times this HashMap has been structurally modified + * Structural modifications are those that change the number of mappings in + * the HashMap or otherwise modify its internal structure (e.g., + * rehash). This field is used to make iterators on Collection-views of + * the HashMap fail-fast. (See ConcurrentModificationException). + */ + transient int modCount; + + /** + * The next size value at which to resize (capacity * load factor). + * + * @serial + */ + // (The javadoc description is true upon serialization. + // Additionally, if the table array has not been allocated, this + // field holds the initial array capacity, or zero signifying + // DEFAULT_INITIAL_CAPACITY.) + // DIFFBLUE MODEL LIBRARY Variable not used in model + // int threshold; + + /** + * The load factor for the hash table. + * + * @serial + */ + // DIFFBLUE MODEL LIBRARY Variable not used in the model + // final float loadFactor; + + // DIFFBLUE MODEL LIBRARY + // Fields inherited from AbstractMap: + // transient Set keySet; + // transient Collection values; + + /* ---------------- Public operations -------------- */ + + /** + * Constructs an empty HashMap with the specified initial + * capacity and load factor. + * + * @param initialCapacity the initial capacity + * @param loadFactor the load factor + * @throws IllegalArgumentException if the initial capacity is negative + * or the load factor is nonpositive + * + * @diffblue.fullSupport + *

In the original implementation, the table field of a new HashMap + * object is initially null in the case of the first three constructors, and + * is only initialised when {@link #put} or {@link #putAll} is called. + * We simplify this in the model so that a table array is always initialised + * on object creation. The state after using a modelled constructor is + * equivalent to the state of a HashMap that was created, had an element + * added and then had that element removed again in the implementation from + * the jdk (except for modCount being 0).

+ * + *

The initialCapacity value is limited to 2^20, to avoid + * generating tests that might exceed the memory limits of the JVM.

+ */ + // DIFFBLUE MODEL LIBRARY + // @SuppressWarnings is needed for the type cast to Node[]. + @SuppressWarnings("unchecked") + public HashMap(int initialCapacity, float loadFactor) { + // if (initialCapacity < 0) + // throw new IllegalArgumentException("Illegal initial capacity: " + + // initialCapacity); + // if (initialCapacity > MAXIMUM_CAPACITY) + // initialCapacity = MAXIMUM_CAPACITY; + // if (loadFactor <= 0 || Float.isNaN(loadFactor)) + // throw new IllegalArgumentException("Illegal load factor: " + + // loadFactor); + // this.loadFactor = loadFactor; + // this.threshold = tableSizeFor(initialCapacity); + + // DIFFBLUE MODEL LIBRARY + // The string operations on the exception arguments can significantly + // slow down JBMC in some cases. This should be reviewed + // again with improved versions of the string solver. + CProver.assume(initialCapacity <= CPROVER_MAX_CAPACITY); + if (initialCapacity < 0) + throw new IllegalArgumentException(); + if (loadFactor <= 0 || Float.isNaN(loadFactor)) + throw new IllegalArgumentException(); + this.table = (Node[]) new Node[5]; + this.size = 0; + this.modCount = 0; + } + + /** + * Constructs an empty HashMap with the specified initial + * capacity and the default load factor (0.75). + * + * @param initialCapacity the initial capacity. + * @throws IllegalArgumentException if the initial capacity is negative. + * + * @diffblue.fullSupport + *

Instead of calling {@link #HashMap(int, float) this(int, float)}, we + * model this constructor explicitly in order to avoid the exception for + * invalid loadFactor values. This exception can slow down JBMC + * especially in the case of recursive unwinding.

+ * + *

The initialCapacity value is limited to 2^20, to avoid + * generating tests that might exceed the memory limits of the JVM.

+ */ + public HashMap(int initialCapacity) { + // this(initialCapacity, DEFAULT_LOAD_FACTOR); + CProver.assume(initialCapacity <= CPROVER_MAX_CAPACITY); + if (initialCapacity < 0) + throw new IllegalArgumentException(); + this.table = (Node[]) new Node[5]; + this.size = 0; + this.modCount = 0; + } + + /** + * Constructs an empty HashMap with the default initial capacity + * (16) and the default load factor (0.75). + * + * @diffblue.fullSupport + */ + // DIFFBLUE MODEL LIBRARY + // @SuppressWarnings is needed for the type cast to Node[]. + @SuppressWarnings("unchecked") + public HashMap() { + // DIFFBLUE MODEL LIBRARY + // this.loadFactor = DEFAULT_LOAD_FACTOR; + this.table = (Node[]) new Node[5]; + this.size = 0; + this.modCount = 0; + } + + /** + * Constructs a new HashMap with the same mappings as the + * specified Map. The HashMap is created with + * default load factor (0.75) and an initial capacity sufficient to + * hold the mappings in the specified Map. + * + * @param m the map whose mappings are to be placed in this map + * @throws NullPointerException if the specified map is null + * + * @diffblue.fullSupport + * The implementation does not check for duplicates in the Map parameter + * to speed up JBMC, but this is OK because a Map cannot + * contain duplicate keys. + */ + @SuppressWarnings("unchecked") + public HashMap(Map m) { + // DIFFBLUE MODEL LIBRARY + // this.loadFactor = DEFAULT_LOAD_FACTOR; + // putMapEntries(m, false); + this.size = m.size(); + this.table = (Node[]) new Node[5]; + this.modCount = 0; + int index = 0; + for (Map.Entry e : m.entrySet()) { + K key = e.getKey(); + V value = e.getValue(); + // DIFFBLUE MODEL LIBRARY + // Custom implementation of put that does not check for duplicates + // (Can save a lot of time in JBMC) + table[index] = new Node(key, value); + index++; + } + } + + /** + * Implements Map.putAll and Map constructor + * + * @param m the map + * @param evict false when initially constructing this map, else + * true (relayed to method afterNodeInsertion). + */ + // DIFFBLUE MODEL LIBRARY Package-private method not used in model + // final void putMapEntries(Map m, boolean evict) { + // int s = m.size(); + // if (s > 0) { + // if (table == null) { // pre-size + // float ft = ((float)s / loadFactor) + 1.0F; + // int t = ((ft < (float)MAXIMUM_CAPACITY) ? + // (int)ft : MAXIMUM_CAPACITY); + // if (t > threshold) + // threshold = tableSizeFor(t); + // } + // else if (s > threshold) + // resize(); + // for (Map.Entry e : m.entrySet()) { + // K key = e.getKey(); + // V value = e.getValue(); + // putVal(hash(key), key, value, false, evict); + // } + // } + // } + + /** + * Returns the number of key-value mappings in this map. + * + * @return the number of key-value mappings in this map + * + * @diffblue.fullSupport + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public int size() { + return size; + } + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + * + * @diffblue.fullSupport + */ + // DIFFBLUE MODEL LIBRARY + // Implementation from jdk. + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + *

More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code (key==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

A return value of {@code null} does not necessarily + * indicate that the map contains no mapping for the key; it's also + * possible that the map explicitly maps the key to {@code null}. + * The {@link #containsKey containsKey} operation may be used to + * distinguish these two cases. + * + * @see #put(Object, Object) + * + * @diffblue.fullSupport + */ + // DIFFBLUE MODEL LIBRARY + // Similar to original implementation, using cproverIndexOfKey instead of + // getNode to find the specified key in elementData. + public V get(Object key) { + // Node e; + // return (e = getNode(hash(key), key)) == null ? null : e.value; + int index = cproverIndexOfKey(key); + return index < 0 ? null : table[index].value; + } + + /** + * Implements Map.get and related methods + * + * @param hash hash for key + * @param key the key + * @return the node, or null if none + */ + // DIFFBLUE MODEL LIBRARY + // We do not use this method in the model. Instead, we use the newly defined + // method cproverIndexOfKey(Object key) to find the index of a node (pair) + // with a given key in the array. + // final Node getNode(int hash, Object key) { + // Node[] tab; Node first, e; int n; K k; + // if ((tab = table) != null && (n = tab.length) > 0 && + // (first = tab[(n - 1) & hash]) != null) { + // if (first.hash == hash && // always check first node + // ((k = first.key) == key || (key != null && key.equals(k)))) + // return first; + // if ((e = first.next) != null) { + // if (first instanceof TreeNode) + // return ((TreeNode)first).getTreeNode(hash, key); + // do { + // if (e.hash == hash && + // ((k = e.key) == key || (key != null && key.equals(k)))) + // return e; + // } while ((e = e.next) != null); + // } + // } + // return null; + // } + + /** + * Returns true if this map contains a mapping for the + * specified key. + * + * @param key The key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key. + * + * @diffblue.fullSupport + */ + // DIFFBLUE MODEL LIBRARY + // Similar to original implementation, using cproverIndexOfKey instead of + // getNode to find the specified key in elementData. + public boolean containsKey(Object key) { + // return getNode(hash(key), key) != null; + return cproverIndexOfKey(key) >= 0; + } + + /** + * Associates the specified value with the specified key in this map. + * If the map previously contained a mapping for the key, the old + * value is replaced. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with key, or + * null if there was no mapping for key. + * (A null return can also indicate that the map + * previously associated null with key.) + * + * @diffblue.limitedSupport + *

Calling this method more than 5 times on a nondeterministically generated + * HashMap or 8 times on a hardcoded HashMap can affect JBMC.

+ */ + // DIFFBLUE MODEL LIBRARY + // We use cproverIndexOfKey to check if a mapping for the specified key is + // already present, then replace the associated value if it is present, or + // append a new key-value pair to elementData otherwise. + public V put(K key, V value) { + // return putVal(hash(key), key, value, false, true); + int index = cproverIndexOfKey(key); + if (index >= 0) { // existing mapping for key + V oldValue = table[index].value; + table[index].value = value; + return oldValue; + } + else { // key not present + CProver.assume(table.length > size); + table[size++] = new Node(key, value); + modCount++; + return null; + } + } + + /** + * Implements Map.put and related methods + * + * @param hash hash for key + * @param key the key + * @param value the value to put + * @param onlyIfAbsent if true, don't change existing value + * @param evict if false, the table is in creation mode. + * @return previous value, or null if none + */ + // DIFFBLUE MODEL LIBRARY + // We do not use this method in the model. + // final V putVal(int hash, K key, V value, boolean onlyIfAbsent, + // boolean evict) { + // Node[] tab; Node p; int n, i; + // if ((tab = table) == null || (n = tab.length) == 0) + // n = (tab = resize()).length; + // if ((p = tab[i = (n - 1) & hash]) == null) + // tab[i] = newNode(hash, key, value, null); + // else { + // Node e; K k; + // if (p.hash == hash && + // ((k = p.key) == key || (key != null && key.equals(k)))) + // e = p; + // else if (p instanceof TreeNode) + // e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value); + // else { + // for (int binCount = 0; ; ++binCount) { + // if ((e = p.next) == null) { + // p.next = newNode(hash, key, value, null); + // if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st + // treeifyBin(tab, hash); + // break; + // } + // if (e.hash == hash && + // ((k = e.key) == key || (key != null && key.equals(k)))) + // break; + // p = e; + // } + // } + // if (e != null) { // existing mapping for key + // V oldValue = e.value; + // if (!onlyIfAbsent || oldValue == null) + // e.value = value; + // afterNodeAccess(e); + // return oldValue; + // } + // } + // ++modCount; + // if (++size > threshold) + // resize(); + // afterNodeInsertion(evict); + // return null; + // } + + /** + * Initializes or doubles table size. If null, allocates in + * accord with initial capacity target held in field threshold. + * Otherwise, because we are using power-of-two expansion, the + * elements from each bin must either stay at same index, or move + * with a power of two offset in the new table. + * + * @return the table + */ + // DIFFBLUE MODEL LIBRARY + // We do not use this method in the model. + // final Node[] resize() { + // Node[] oldTab = table; + // int oldCap = (oldTab == null) ? 0 : oldTab.length; + // int oldThr = threshold; + // int newCap, newThr = 0; + // if (oldCap > 0) { + // if (oldCap >= MAXIMUM_CAPACITY) { + // threshold = Integer.MAX_VALUE; + // return oldTab; + // } + // else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && + // oldCap >= DEFAULT_INITIAL_CAPACITY) + // newThr = oldThr << 1; // double threshold + // } + // else if (oldThr > 0) // initial capacity was placed in threshold + // newCap = oldThr; + // else { // zero initial threshold signifies using defaults + // newCap = DEFAULT_INITIAL_CAPACITY; + // newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); + // } + // if (newThr == 0) { + // float ft = (float)newCap * loadFactor; + // newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? + // (int)ft : Integer.MAX_VALUE); + // } + // threshold = newThr; + // @SuppressWarnings({"rawtypes","unchecked"}) + // Node[] newTab = (Node[])new Node[newCap]; + // table = newTab; + // if (oldTab != null) { + // for (int j = 0; j < oldCap; ++j) { + // Node e; + // if ((e = oldTab[j]) != null) { + // oldTab[j] = null; + // if (e.next == null) + // newTab[e.hash & (newCap - 1)] = e; + // else if (e instanceof TreeNode) + // ((TreeNode)e).split(this, newTab, j, oldCap); + // else { // preserve order + // Node loHead = null, loTail = null; + // Node hiHead = null, hiTail = null; + // Node next; + // do { + // next = e.next; + // if ((e.hash & oldCap) == 0) { + // if (loTail == null) + // loHead = e; + // else + // loTail.next = e; + // loTail = e; + // } + // else { + // if (hiTail == null) + // hiHead = e; + // else + // hiTail.next = e; + // hiTail = e; + // } + // } while ((e = next) != null); + // if (loTail != null) { + // loTail.next = null; + // newTab[j] = loHead; + // } + // if (hiTail != null) { + // hiTail.next = null; + // newTab[j + oldCap] = hiHead; + // } + // } + // } + // } + // } + // return newTab; + // } + + /** + * Replaces all linked nodes in bin at index for given hash unless + * table is too small, in which case resizes instead. + */ + // DIFFBLUE MODEL LIBRARY + // We do not use this method in the model. + // final void treeifyBin(Node[] tab, int hash) { + // int n, index; Node e; + // if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) + // resize(); + // else if ((e = tab[index = (n - 1) & hash]) != null) { + // TreeNode hd = null, tl = null; + // do { + // TreeNode p = replacementTreeNode(e, null); + // if (tl == null) + // hd = p; + // else { + // p.prev = tl; + // tl.next = p; + // } + // tl = p; + // } while ((e = e.next) != null); + // if ((tab[index] = hd) != null) + // hd.treeify(tab); + // } + // } + + /** + * Copies all of the mappings from the specified map to this map. + * These mappings will replace any mappings that this map had for + * any of the keys currently in the specified map. + * + * @param m mappings to be stored in this map + * @throws NullPointerException if the specified map is null + * + * @diffblue.limitedSupport + *

Calling this method with a large Map (more than 5 elements) can affect + * the results.

+ *

Exceptions are not thrown unless the + * --throw-runtime-exceptions is added to JBMC.

+ */ + // DIFFBLUE MODEL LIBRARY + // We use repeated calls to put() in the model: for each entry in m, we need + // to check whether an entry with the same key is already present in + // elementData, and if so, replace the corresponding value, otherwise add a + // new entry. + public void putAll(Map m) { + // putMapEntries(m, true); + for (Map.Entry e : m.entrySet()) { + K key = e.getKey(); + V value = e.getValue(); + put(key, value); + } + } + + /** + * Removes the mapping for the specified key from this map if present. + * + * @param key key whose mapping is to be removed from the map + * @return the previous value associated with key, or + * null if there was no mapping for key. + * (A null return can also indicate that the map + * previously associated null with key.) + * + * @diffblue.fullSupport + */ + // DIFFBLUE MODEL LIBRARY + // Similar to original implementation, using cproverIndexOfKey instead of + // removeNode to find the node (pair) to remove. + public V remove(Object key) { + // Node e; + // return (e = removeNode(hash(key), key, null, false, true)) == null ? + // null : e.value; + int index = cproverIndexOfKey(key); + if (index >= 0) { + V v = table[index].value; + // remove element at table[index] + for (int i = index; i < size - 1; i++) { + table[i] = table[i+1]; + } + size--; + modCount++; + return v; + } + return null; + } + + /** + * Implements Map.remove and related methods + * + * @param hash hash for key + * @param key the key + * @param value the value to match if matchValue, else ignored + * @param matchValue if true only remove if value is equal + * @param movable if false do not move other nodes while removing + * @return the node, or null if none + */ + // DIFFBLUE MODEL LIBRARY + // We do not use this method in the model. + // final Node removeNode(int hash, Object key, Object value, + // boolean matchValue, boolean movable) { + // Node[] tab; Node p; int n, index; + // if ((tab = table) != null && (n = tab.length) > 0 && + // (p = tab[index = (n - 1) & hash]) != null) { + // Node node = null, e; K k; V v; + // if (p.hash == hash && + // ((k = p.key) == key || (key != null && key.equals(k)))) + // node = p; + // else if ((e = p.next) != null) { + // if (p instanceof TreeNode) + // node = ((TreeNode)p).getTreeNode(hash, key); + // else { + // do { + // if (e.hash == hash && + // ((k = e.key) == key || + // (key != null && key.equals(k)))) { + // node = e; + // break; + // } + // p = e; + // } while ((e = e.next) != null); + // } + // } + // if (node != null && (!matchValue || (v = node.value) == value || + // (value != null && value.equals(v)))) { + // if (node instanceof TreeNode) + // ((TreeNode)node).removeTreeNode(this, tab, movable); + // else if (node == p) + // tab[index] = node.next; + // else + // p.next = node.next; + // ++modCount; + // --size; + // afterNodeRemoval(node); + // return node; + // } + // } + // return null; + // } + + /** + * Removes all of the mappings from this map. + * The map will be empty after this call returns. + * + * @diffblue.fullSupport + */ + // DIFFBLUE MODEL LIBRARY + // We assume that table is never null, and we don't have to set the old + // entries to null as we use an array representation. + public void clear() { + // Node[] tab; + modCount++; + // if ((tab = table) != null && size > 0) { + // size = 0; + // for (int i = 0; i < tab.length; ++i) + // tab[i] = null; + // } + size = 0; + } + + /** + * Returns true if this map maps one or more keys to the + * specified value. + * + * @param value value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * + * @diffblue.fullSupport + */ + // DIFFBLUE MODEL LIBRARY + // We use cproverIndexOfValue to find the specified value in elementData. + public boolean containsValue(Object value) { + // Node[] tab; V v; + // if ((tab = table) != null && size > 0) { + // for (int i = 0; i < tab.length; ++i) { + // for (Node e = tab[i]; e != null; e = e.next) { + // if ((v = e.value) == value || + // (value != null && value.equals(v))) + // return true; + // } + // } + // } + // return false; + return cproverIndexOfValue(value) >= 0; + } + + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. If the map is modified + * while an iteration over the set is in progress (except through + * the iterator's own remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + * + * @diffblue.limitedSupport + *

The forEach method is not modelled. + *

Calling an iterator on a keySet with more than six elements can cause + * issues with JBMC.
+ * Because keySet(), entrySet() and values() all return an abstract type Set + * or Collection, this can cause JBMC to be slow. This should + * be fixed with lazy loading v2.
+ */ + // DIFFBLUE MODEL LIBRARY + // We do not use the cache from the original implementation (to make things + // more deterministic for symex) so the keySet() method generates a new + // KeySet object every time it is called. + public Set keySet() { + // Set ks = keySet; + // if (ks == null) { + // ks = new KeySet(); + // keySet = ks; + // } + // return ks; + return new KeySet(); + } + + final class KeySet extends AbstractSet { + public final int size() { return size; } + public final void clear() { HashMap.this.clear(); } + public final Iterator iterator() { return new KeyIterator(); } + public final boolean contains(Object o) { return containsKey(o); } + public final boolean remove(Object key) { + // return removeNode(hash(key), key, null, false, true) != null; + // DIFFBLUE MODEL LIBRARY + // We use cproverIndexOfKey and cproverRemoveIndex instead of + // removeNode in the model. + int index = cproverIndexOfKey(key); + if (index < 0) return false; + // remove element at table[index] + cproverRemoveIndex(index); + return true; + } + public final Spliterator spliterator() { + // return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + public final void forEach(Consumer action) { + // Node[] tab; + // if (action == null) + // throw new NullPointerException(); + // if (size > 0 && (tab = table) != null) { + // int mc = modCount; + // for (int i = 0; i < tab.length; ++i) { + // for (Node e = tab[i]; e != null; e = e.next) + // action.accept(e.key); + // } + // if (modCount != mc) + // throw new ConcurrentModificationException(); + // } + CProver.notModelled(); + } + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. If the map is + * modified while an iteration over the collection is in progress + * (except through the iterator's own remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Collection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a view of the values contained in this map + * + * @diffblue.limitedSupport + *

The forEach method is not modelled. + * Calling an iterator on a values Collection with more than seven elements + * can cause issues with JBMC.
+ * Because keySet(), entrySet() and values() all return an abstract type Set + * or Collection, this can cause JBMC to be slow. This should + * be fixed with lazy loading v2.
+ */ + // DIFFBLUE MODEL LIBRARY + // We do not use the cache from the original implementation (HashMap.values + // is not present in the model) so the values() method generates a new + // Values object every time it is called. + public Collection values() { + // Collection vs = values; + // if (vs == null) { + // vs = new Values(); + // values = vs; + // } + // return vs; + return new Values(); + } + + final class Values extends AbstractCollection { + public final int size() { return size; } + public final void clear() { HashMap.this.clear(); } + public final Iterator iterator() { return new ValueIterator(); } + public final boolean contains(Object o) { return containsValue(o); } + // DIFFBLUE MODEL LIBRARY + // This method is inherited from AbstractCollection in the jdk. In the + // model, we override it to reduce the number of branches to analyse. + public final boolean remove(Object value) { + int index = cproverIndexOfValue(value); + if (index < 0) return false; + // remove element at table[index] + cproverRemoveIndex(index); + return true; + } + public final Spliterator spliterator() { + // return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + public final void forEach(Consumer action) { + // Node[] tab; + // if (action == null) + // throw new NullPointerException(); + // if (size > 0 && (tab = table) != null) { + // int mc = modCount; + // for (int i = 0; i < tab.length; ++i) { + // for (Node e = tab[i]; e != null; e = e.next) + // action.accept(e.value); + // } + // if (modCount != mc) + // throw new ConcurrentModificationException(); + // } + CProver.notModelled(); + } + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. If the map is modified + * while an iteration over the set is in progress (except through + * the iterator's own remove operation, or through the + * setValue operation on a map entry returned by the + * iterator) the results of the iteration are undefined. The set + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Set.remove, removeAll, retainAll and + * clear operations. It does not support the + * add or addAll operations. + * + * @return a set view of the mappings contained in this map + * + * @diffblue.limitedSupport + *

The forEach method is not modelled.
+ * Calling an iterator on an entrySet can cause issues with JBMC. + * Because keySet(), entrySet() and values() all return an abstract type Set + * or Collection, this can cause JBMC to be slow. This should + * be fixed with lazy loading v2.
+ */ + // DIFFBLUE MODEL LIBRARY + // We do not use the cache from the original implementation (HashMap.entrySet + // is always null) so the entrySet() method generates a new + // EntrySet object every time it is called. + public Set> entrySet() { + // Set> es; + // return (es = entrySet) == null ? (entrySet = new EntrySet()) : es; + // Seems to decrease coverage? + return new EntrySet(); + } + + final class EntrySet extends AbstractSet> { + public final int size() { return size; } + public final void clear() { HashMap.this.clear(); } + public final Iterator> iterator() { + return new EntryIterator(); + } + public final boolean contains(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry) o; + Object key = e.getKey(); + // Node candidate = getNode(hash(key), key); + // return candidate != null && candidate.equals(e); + // DIFFBLUE MODEL LIBRARY + // We use cproverIndexOfKey instead of getNode in the model. + // We also need to compare keys and values separately instead of + // calling Node.equals, as Node.equals is not currently modelled + // due to recursive unwinding issues. + Object value = e.getValue(); + int index = cproverIndexOfKey(key); + if (index < 0) return false; + V candidateValue = table[index].value; + if (candidateValue == null) { + return value == null; + } + return candidateValue.equals(value); + } + public final boolean remove(Object o) { + if (o instanceof Map.Entry) { + Map.Entry e = (Map.Entry) o; + Object key = e.getKey(); + Object value = e.getValue(); + // return removeNode(hash(key), key, value, true, true) != null; + // DIFFBLUE MODEL LIBRARY + // We use cproverIndexOfKey and cproverRemoveIndex instead of + // removeNode in the model. + // We also need to compare keys and values separately instead of + // calling Node.equals, as Node.equals is not currently modelled + // due to recursive unwinding issues. + int index = cproverIndexOfKey(key); + if (index < 0) return false; + V candidateValue = table[index].value; + if (candidateValue == null && value == null || + candidateValue != null && candidateValue.equals(value)) { + // remove element at table[index] + cproverRemoveIndex(index); + return true; + } + } + return false; + } + public final Spliterator> spliterator() { + // return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + public final void forEach(Consumer> action) { + // Node[] tab; + // if (action == null) + // throw new NullPointerException(); + // if (size > 0 && (tab = table) != null) { + // int mc = modCount; + // for (int i = 0; i < tab.length; ++i) { + // for (Node e = tab[i]; e != null; e = e.next) + // action.accept(e); + // } + // if (modCount != mc) + // throw new ConcurrentModificationException(); + // } + CProver.notModelled(); + } + } + + // Overrides of JDK8 Map extension methods + + /** + * @diffblue.untested + */ + // DIFFBLUE MODELS LIBRARY: Just inherit the simple default implementation from Map. + /* + @Override + public V getOrDefault(Object key, V defaultValue) { + // Node e; + // return (e = getNode(hash(key), key)) == null ? defaultValue : e.value; + V ret = get(key); + if(ret != null) + return ret; + else + return defaultValue; + } + */ + + /** + * @diffblue.untested + */ + // DIFFBLUE MODELS LIBRARY: Just inherit the simple default implementation from Map. + /* + @Override + public V putIfAbsent(K key, V value) { + // return putVal(hash(key), key, value, true, true); + CProver.notModelled(); + return CProver.nondetWithNullForNotModelled(); + } + */ + + /** + * @diffblue.untested + */ + // DIFFBLUE MODELS LIBRARY: Just inherit the simple default implementation from Map. + /* + @Override + public boolean remove(Object key, Object value) { + // return removeNode(hash(key), key, value, true, true) != null; + CProver.notModelled(); + return CProver.nondetBoolean(); + }*/ + + /** + * @diffblue.untested + */ + // DIFFBLUE MODELS LIBRARY: Just inherit the simple default implementation from Map. + /* + @Override + public boolean replace(K key, V oldValue, V newValue) { + // Node e; V v; + // if ((e = getNode(hash(key), key)) != null && + // ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) { + // e.value = newValue; + // afterNodeAccess(e); + // return true; + // } + // return false; + CProver.notModelled(); + return CProver.nondetBoolean(); + } + */ + + /** + * @diffblue.fullSupport + */ + @Override + public V replace(K key, V value) { + // Node e; + // if ((e = getNode(hash(key), key)) != null) { + // V oldValue = e.value; + // e.value = value; + // afterNodeAccess(e); + // return oldValue; + // } + // return null; + int index = cproverIndexOfKey(key); + if (index >= 0) { + V oldValue = table[index].value; + table[index].value = value; + return oldValue; + } + return null; + } + + /** + * @diffblue.untested + */ + // DIFFBLUE MODELS LIBRARY: Just inherit the simple default implementation from Map. + /* + @Override + public V computeIfAbsent(K key, + Function mappingFunction) { + // if (mappingFunction == null) + // throw new NullPointerException(); + // int hash = hash(key); + // Node[] tab; Node first; int n, i; + // int binCount = 0; + // TreeNode t = null; + // Node old = null; + // if (size > threshold || (tab = table) == null || + // (n = tab.length) == 0) + // n = (tab = resize()).length; + // if ((first = tab[i = (n - 1) & hash]) != null) { + // if (first instanceof TreeNode) + // old = (t = (TreeNode)first).getTreeNode(hash, key); + // else { + // Node e = first; K k; + // do { + // if (e.hash == hash && + // ((k = e.key) == key || (key != null && key.equals(k)))) { + // old = e; + // break; + // } + // ++binCount; + // } while ((e = e.next) != null); + // } + // V oldValue; + // if (old != null && (oldValue = old.value) != null) { + // afterNodeAccess(old); + // return oldValue; + // } + // } + // V v = mappingFunction.apply(key); + // if (v == null) { + // return null; + // } else if (old != null) { + // old.value = v; + // afterNodeAccess(old); + // return v; + // } + // else if (t != null) + // t.putTreeVal(this, tab, hash, key, v); + // else { + // tab[i] = newNode(hash, key, v, first); + // if (binCount >= TREEIFY_THRESHOLD - 1) + // treeifyBin(tab, hash); + // } + // ++modCount; + // ++size; + // afterNodeInsertion(true); + // return v; + CProver.notModelled(); + return CProver.nondetWithNullForNotModelled(); + }*/ + + /** + * @diffblue.untested + */ + // DIFFBLUE MODELS LIBRARY: Just inherit the simple default implementation from Map. + /* + public V computeIfPresent(K key, + BiFunction remappingFunction) { + // if (remappingFunction == null) + // throw new NullPointerException(); + // Node e; V oldValue; + // int hash = hash(key); + // if ((e = getNode(hash, key)) != null && + // (oldValue = e.value) != null) { + // V v = remappingFunction.apply(key, oldValue); + // if (v != null) { + // e.value = v; + // afterNodeAccess(e); + // return v; + // } + // else + // removeNode(hash, key, null, false, true); + // } + // return null; + CProver.notModelled(); + return CProver.nondetWithNullForNotModelled(); + }*/ + + /** + * @diffblue.untested + */ + // DIFFBLUE MODELS LIBRARY: Just inherit the simple default implementation from Map. + /* + @Override + public V compute(K key, + BiFunction remappingFunction) { + // if (remappingFunction == null) + // throw new NullPointerException(); + // int hash = hash(key); + // Node[] tab; Node first; int n, i; + // int binCount = 0; + // TreeNode t = null; + // Node old = null; + // if (size > threshold || (tab = table) == null || + // (n = tab.length) == 0) + // n = (tab = resize()).length; + // if ((first = tab[i = (n - 1) & hash]) != null) { + // if (first instanceof TreeNode) + // old = (t = (TreeNode)first).getTreeNode(hash, key); + // else { + // Node e = first; K k; + // do { + // if (e.hash == hash && + // ((k = e.key) == key || (key != null && key.equals(k)))) { + // old = e; + // break; + // } + // ++binCount; + // } while ((e = e.next) != null); + // } + // } + // V oldValue = (old == null) ? null : old.value; + // V v = remappingFunction.apply(key, oldValue); + // if (old != null) { + // if (v != null) { + // old.value = v; + // afterNodeAccess(old); + // } + // else + // removeNode(hash, key, null, false, true); + // } + // else if (v != null) { + // if (t != null) + // t.putTreeVal(this, tab, hash, key, v); + // else { + // tab[i] = newNode(hash, key, v, first); + // if (binCount >= TREEIFY_THRESHOLD - 1) + // treeifyBin(tab, hash); + // } + // ++modCount; + // ++size; + // afterNodeInsertion(true); + // } + // return v; + CProver.notModelled(); + return CProver.nondetWithNullForNotModelled(); + } + */ + + /** + * @diffblue.untested + */ + // DIFFBLUE MODELS LIBRARY: Just inherit the simple default implementation from Map. + /* + @Override + public V merge(K key, V value, + BiFunction remappingFunction) { + // if (value == null) + // throw new NullPointerException(); + // if (remappingFunction == null) + // throw new NullPointerException(); + // int hash = hash(key); + // Node[] tab; Node first; int n, i; + // int binCount = 0; + // TreeNode t = null; + // Node old = null; + // if (size > threshold || (tab = table) == null || + // (n = tab.length) == 0) + // n = (tab = resize()).length; + // if ((first = tab[i = (n - 1) & hash]) != null) { + // if (first instanceof TreeNode) + // old = (t = (TreeNode)first).getTreeNode(hash, key); + // else { + // Node e = first; K k; + // do { + // if (e.hash == hash && + // ((k = e.key) == key || (key != null && key.equals(k)))) { + // old = e; + // break; + // } + // ++binCount; + // } while ((e = e.next) != null); + // } + // } + // if (old != null) { + // V v; + // if (old.value != null) + // v = remappingFunction.apply(old.value, value); + // else + // v = value; + // if (v != null) { + // old.value = v; + // afterNodeAccess(old); + // } + // else + // removeNode(hash, key, null, false, true); + // return v; + // } + // if (value != null) { + // if (t != null) + // t.putTreeVal(this, tab, hash, key, value); + // else { + // tab[i] = newNode(hash, key, value, first); + // if (binCount >= TREEIFY_THRESHOLD - 1) + // treeifyBin(tab, hash); + // } + // ++modCount; + // ++size; + // afterNodeInsertion(true); + // } + // return value; + CProver.notModelled(); + return CProver.nondetWithNullForNotModelled(); + } + */ + + /** + * @diffblue.untested + */ + // DIFFBLUE MODELS LIBRARY: Just inherit the simple default implementation from Map. + /* + @Override + public void forEach(BiConsumer action) { + // Node[] tab; + // if (action == null) + // throw new NullPointerException(); + // if (size > 0 && (tab = table) != null) { + // int mc = modCount; + // for (int i = 0; i < tab.length; ++i) { + // for (Node e = tab[i]; e != null; e = e.next) + // action.accept(e.key, e.value); + // } + // if (modCount != mc) + // throw new ConcurrentModificationException(); + // } + CProver.notModelled(); + } + */ + + /** + * @diffblue.untested + */ + // DIFFBLUE MODELS LIBRARY: Just inherit the simple default implementation from Map. + /* + @Override + public void replaceAll(BiFunction function) { + // Node[] tab; + // if (function == null) + // throw new NullPointerException(); + // if (size > 0 && (tab = table) != null) { + // int mc = modCount; + // for (int i = 0; i < tab.length; ++i) { + // for (Node e = tab[i]; e != null; e = e.next) { + // e.value = function.apply(e.key, e.value); + // } + // } + // if (modCount != mc) + // throw new ConcurrentModificationException(); + // } + CProver.notModelled(); + } + */ + + /* ------------------------------------------------------------ */ + // Cloning and serialization + + /** + * Returns a shallow copy of this HashMap instance: the keys and + * values themselves are not cloned. + * + * @return a shallow copy of this map + * + * @diffblue.fullSupport + * In the jdk, part of this method (super.clone() is inherited from AbstractMap, + * which uses its own super.clone(), inherited from Object) is implemented + * natively. Like the jdk, the model creates a shallow copy of the HashMap: + * it has its own array, but the array elements are shared, and modifying an + * element in one of the two maps will also modify this element for the other. + * The clone will have always have the default load factor, which does not + * cause any problems as long as we hide the internal state of the model in + * traces. Trying to call new {@link #HashMap(int, float)} and setting + * the load factor in it can slow down JBMC significantly due to + * unwinding. + */ + @SuppressWarnings("unchecked") + @Override + public Object clone() { + // HashMap result; + // try { + // result = (HashMap)super.clone(); + // } catch (CloneNotSupportedException e) { + // // this shouldn't happen, since we are Cloneable + // throw new InternalError(e); + // } + // result.reinitialize(); + // result.putMapEntries(this, false); + // return result; + HashMap result = new HashMap(this); + return result; + } + + // These methods are also used when serializing HashSets + // DIFFBLUE MODEL LIBRARY Package-private method not used in model + // final float loadFactor() { + // return loadFactor; + // } + // DIFFBLUE MODEL LIBRARY Package-private method not used in model + // final int capacity() { + // return (table != null) ? table.length : + // (threshold > 0) ? threshold : + // DEFAULT_INITIAL_CAPACITY; + // } + + /** + * Save the state of the HashMap instance to a stream (i.e., + * serialize it). + * + * @serialData The capacity of the HashMap (the length of the + * bucket array) is emitted (int), followed by the + * size (an int, the number of key-value + * mappings), followed by the key (Object) and value (Object) + * for each key-value mapping. The key-value mappings are + * emitted in no particular order. + */ + // DIFFBLUE MODEL LIBRARY Private method not used in model + // private void writeObject(java.io.ObjectOutputStream s) + // throws IOException { + // int buckets = capacity(); + // // Write out the threshold, loadfactor, and any hidden stuff + // s.defaultWriteObject(); + // s.writeInt(buckets); + // s.writeInt(size); + // internalWriteEntries(s); + // } + + /** + * Reconstitute the {@code HashMap} instance from a stream (i.e., + * deserialize it). + */ + // DIFFBLUE MODEL LIBRARY Private method not used in model + // private void readObject(java.io.ObjectInputStream s) + // throws IOException, ClassNotFoundException { + // // Read in the threshold (ignored), loadfactor, and any hidden stuff + // s.defaultReadObject(); + // reinitialize(); + // if (loadFactor <= 0 || Float.isNaN(loadFactor)) + // throw new InvalidObjectException("Illegal load factor: " + + // loadFactor); + // s.readInt(); // Read and ignore number of buckets + // int mappings = s.readInt(); // Read number of mappings (size) + // if (mappings < 0) + // throw new InvalidObjectException("Illegal mappings count: " + + // mappings); + // else if (mappings > 0) { // (if zero, use defaults) + // // Size the table using given load factor only if within + // // range of 0.25...4.0 + // float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f); + // float fc = (float)mappings / lf + 1.0f; + // int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ? + // DEFAULT_INITIAL_CAPACITY : + // (fc >= MAXIMUM_CAPACITY) ? + // MAXIMUM_CAPACITY : + // tableSizeFor((int)fc)); + // float ft = (float)cap * lf; + // threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ? + // (int)ft : Integer.MAX_VALUE); + // @SuppressWarnings({"rawtypes","unchecked"}) + // Node[] tab = (Node[])new Node[cap]; + // table = tab; + + // // Read the keys and values, and put the mappings in the HashMap + // for (int i = 0; i < mappings; i++) { + // @SuppressWarnings("unchecked") + // K key = (K) s.readObject(); + // @SuppressWarnings("unchecked") + // V value = (V) s.readObject(); + // putVal(hash(key), key, value, false, false); + // } + // } + // } + + /* ------------------------------------------------------------ */ + // iterators + + // TODO ------------------------------------------------------- + // DIFFBLUE MODEL LIBRARY + // Uncomment the HashIterator class and its subclasses, and delete the + // versions of KeyIterator, ValueIterator and EntryIterator below, when + // an issue is fixed. + // abstract class HashIterator { + // // Node next; // next entry to return + // int cursor; // index of next element to return + // // Node current; // current entry + // int expectedModCount; // for fast-fail + // // int index; // current slot + // int lastRet; // index of last element returned; -1 if no such + + // HashIterator() { + // expectedModCount = modCount; + // // Node[] t = table; + // // current = next = null; + // // index = 0; + // // if (t != null && size > 0) { // advance to first entry + // // do {} while (index < t.length && (next = t[index++]) == null); + // // } + // // DIFFBLUE MODEL LIBRARY + // cursor = 0; + // lastRet = -1; + // } + + // public final boolean hasNext() { + // // return next != null; + // // return cursor != size; + // return true; + // } + + // final Node nextNode() { + // // Node[] t; + // // Node e = next; + // // if (modCount != expectedModCount) + // // throw new ConcurrentModificationException(); + // // if (e == null) + // // throw new NoSuchElementException(); + // // if ((next = (current = e).next) == null && (t = table) != null) { + // // do {} while (index < t.length && (next = t[index++]) == null); + // // } + // // DIFFBLUE MODEL LIBRARY + // if (cursor >= size) + // throw new NoSuchElementException(); + // if (modCount != expectedModCount) + // throw new ConcurrentModificationException(); + // lastRet = cursor; + // cursor++; + // return table[lastRet]; + // } + + // public final void remove() { + // // Node p = current; + // // if (p == null) + // // throw new IllegalStateException(); + // // if (modCount != expectedModCount) + // // throw new ConcurrentModificationException(); + // // current = null; + // // K key = p.key; + // // removeNode(hash(key), key, null, false, false); + // // DIFFBLUE MODEL LIBRARY + // // We use a custom method cproverRemoveIndex(), which is not + // // present in the jdk, to remove elements. + // if (lastRet < 0) + // throw new IllegalStateException(); + // if (modCount != expectedModCount) + // throw new ConcurrentModificationException(); + // cproverRemoveIndex(lastRet); + // cursor = lastRet; + // lastRet = -1; + // expectedModCount = modCount; + // } + // } + + // final class KeyIterator extends HashIterator + // implements Iterator { + // public final K next() { return nextNode().key; } + // } + + // final class ValueIterator extends HashIterator + // implements Iterator { + // public final V next() { return nextNode().value; } + // } + + // final class EntryIterator extends HashIterator + // implements Iterator> { + // public final Map.Entry next() { return nextNode(); } + // } + + /** + * @diffblue.todo + * Delete this iterator class, and uncomment the four above iterator classes + * (HashIterator and its subclasses) when an issue is fixed. + * Check whether the hack for EntryIterator will have to be applied to + * HashIterator instead. + */ + // DIFFBLUE MODEL LIBRARY + // This class is not present in the jdk. It is a temporary workaround for + // an issue. + final class KeyIterator implements Iterator { + int cursor; // index of next element to return + int expectedModCount; // for fast-fail + int lastRet; // index of last element returned; -1 if no such + + KeyIterator() { + expectedModCount = modCount; + cursor = 0; + lastRet = -1; + } + + public final boolean hasNext() { + return cursor != size; + } + + final Node nextNode() { + if (cursor >= size) + throw new NoSuchElementException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + lastRet = cursor; + cursor++; + return table[lastRet]; + } + + public final void remove() { + // DIFFBLUE MODEL LIBRARY + // We use a custom method cproverRemoveIndex(), which is not + // present in the jdk, to remove elements. + if (lastRet < 0) + throw new IllegalStateException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + cproverRemoveIndex(lastRet); + cursor = lastRet; + lastRet = -1; + expectedModCount = modCount; + } + + public final K next() { + return nextNode().key; + } + } + + /** + * @diffblue.todo + * Delete this iterator class, and uncomment the four above iterator classes + * (HashIterator and its subclasses) when an issue is fixed. + * Check whether the hack for EntryIterator will have to be applied to + * HashIterator instead. + */ + // DIFFBLUE MODEL LIBRARY + // This class is not present in the jdk. It is a temporary workaround for + // an issue. + final class ValueIterator implements Iterator { + int cursor; // index of next element to return + int expectedModCount; // for fast-fail + int lastRet; // index of last element returned; -1 if no such + + ValueIterator() { + expectedModCount = modCount; + cursor = 0; + lastRet = -1; + } + + public final boolean hasNext() { + return cursor != size; + } + + final Node nextNode() { + if (cursor >= size) + throw new NoSuchElementException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + lastRet = cursor; + cursor++; + return table[lastRet]; + } + + public final void remove() { + // DIFFBLUE MODEL LIBRARY + // We use a custom method cproverRemoveIndex(), which is not + // present in the jdk, to remove elements. + if (lastRet < 0) + throw new IllegalStateException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + cproverRemoveIndex(lastRet); + cursor = lastRet; + lastRet = -1; + expectedModCount = modCount; + } + + public final V next() { + return nextNode().value; + } + } + + /** + * @diffblue.todo + * Delete this iterator class, and uncomment the four above iterator classes + * (HashIterator and its subclasses) when an issue is fixed. + * Check whether the hack for EntryIterator will have to be applied to + * HashIterator instead. + */ + // DIFFBLUE MODEL LIBRARY + // This class is not present in the jdk. It is a temporary workaround for + // an issue. + final class EntryIterator implements Iterator> { + int cursor; // index of next element to return + int expectedModCount; // for fast-fail + int lastRet; // index of last element returned; -1 if no such + + EntryIterator() { + // DIFFBLUE MODEL LIBRARY + // HACK: The following three lines have been added as a quick + // workaround for a deadline. They should be removed once + // the following issue is resolved: + // JBMC sometimes doesn't load any + // methods on the Node class when accessed through an iterator on + // the HashMap's EntrySet. Adding a dummy Node and two common calls + // to it here is the workaround. + Node temp = new Node(null, null); + temp.getKey(); + temp.getValue(); + // END OF HACK + expectedModCount = modCount; + cursor = 0; + lastRet = -1; + } + + public final boolean hasNext() { + return cursor != size; + } + + final Node nextNode() { + if (cursor >= size) + throw new NoSuchElementException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + lastRet = cursor; + cursor++; + return table[lastRet]; + } + + public final void remove() { + // DIFFBLUE MODEL LIBRARY + // We use a custom method cproverRemoveIndex(), which is not + // present in the jdk, to remove elements. + if (lastRet < 0) + throw new IllegalStateException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + cproverRemoveIndex(lastRet); + cursor = lastRet; + lastRet = -1; + expectedModCount = modCount; + } + + public final Map.Entry next() { + return nextNode(); + } + } + + /* ------------------------------------------------------------ */ + // spliterators + + /** + * @diffblue.noSupport + */ + static class HashMapSpliterator { + final HashMap map; + Node current; // current node + int index; // current index, modified on advance/split + int fence; // one past last index + int est; // size estimate + int expectedModCount; // for comodification checks + + HashMapSpliterator(HashMap m, int origin, + int fence, int est, + int expectedModCount) { + this.map = m; + this.index = origin; + this.fence = fence; + this.est = est; + this.expectedModCount = expectedModCount; + } + + final int getFence() { // initialize fence and size on first use + // int hi; + // if ((hi = fence) < 0) { + // HashMap m = map; + // est = m.size; + // expectedModCount = m.modCount; + // Node[] tab = m.table; + // hi = fence = (tab == null) ? 0 : tab.length; + // } + // return hi; + CProver.notModelled(); + return CProver.nondetInt(); + } + + public final long estimateSize() { + // getFence(); // force init + // return (long) est; + CProver.notModelled(); + return CProver.nondetLong(); + } + } + + /** + * @diffblue.noSupport + */ + static final class KeySpliterator + extends HashMapSpliterator + implements Spliterator { + KeySpliterator(HashMap m, int origin, int fence, int est, + int expectedModCount) { + super(m, origin, fence, est, expectedModCount); + } + + public KeySpliterator trySplit() { + // int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; + // return (lo >= mid || current != null) ? null : + // new KeySpliterator<>(map, lo, index = mid, est >>>= 1, + // expectedModCount); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + public void forEachRemaining(Consumer action) { + // int i, hi, mc; + // if (action == null) + // throw new NullPointerException(); + // HashMap m = map; + // Node[] tab = m.table; + // if ((hi = fence) < 0) { + // mc = expectedModCount = m.modCount; + // hi = fence = (tab == null) ? 0 : tab.length; + // } + // else + // mc = expectedModCount; + // if (tab != null && tab.length >= hi && + // (i = index) >= 0 && (i < (index = hi) || current != null)) { + // Node p = current; + // current = null; + // do { + // if (p == null) + // p = tab[i++]; + // else { + // action.accept(p.key); + // p = p.next; + // } + // } while (p != null || i < hi); + // if (m.modCount != mc) + // throw new ConcurrentModificationException(); + // } + CProver.notModelled(); + } + + public boolean tryAdvance(Consumer action) { + // int hi; + // if (action == null) + // throw new NullPointerException(); + // Node[] tab = map.table; + // if (tab != null && tab.length >= (hi = getFence()) && index >= 0) { + // while (current != null || index < hi) { + // if (current == null) + // current = tab[index++]; + // else { + // K k = current.key; + // current = current.next; + // action.accept(k); + // if (map.modCount != expectedModCount) + // throw new ConcurrentModificationException(); + // return true; + // } + // } + // } + // return false; + CProver.notModelled(); + return CProver.nondetBoolean(); + } + + public int characteristics() { + // return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) | + // Spliterator.DISTINCT; + CProver.notModelled(); + return CProver.nondetInt(); + } + } + + /** + * @diffblue.noSupport + */ + static final class ValueSpliterator + extends HashMapSpliterator + implements Spliterator { + ValueSpliterator(HashMap m, int origin, int fence, int est, + int expectedModCount) { + super(m, origin, fence, est, expectedModCount); + } + + public ValueSpliterator trySplit() { + // int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; + // return (lo >= mid || current != null) ? null : + // new ValueSpliterator<>(map, lo, index = mid, est >>>= 1, + // expectedModCount); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + public void forEachRemaining(Consumer action) { + // int i, hi, mc; + // if (action == null) + // throw new NullPointerException(); + // HashMap m = map; + // Node[] tab = m.table; + // if ((hi = fence) < 0) { + // mc = expectedModCount = m.modCount; + // hi = fence = (tab == null) ? 0 : tab.length; + // } + // else + // mc = expectedModCount; + // if (tab != null && tab.length >= hi && + // (i = index) >= 0 && (i < (index = hi) || current != null)) { + // Node p = current; + // current = null; + // do { + // if (p == null) + // p = tab[i++]; + // else { + // action.accept(p.value); + // p = p.next; + // } + // } while (p != null || i < hi); + // if (m.modCount != mc) + // throw new ConcurrentModificationException(); + // } + CProver.notModelled(); + } + + public boolean tryAdvance(Consumer action) { + // int hi; + // if (action == null) + // throw new NullPointerException(); + // Node[] tab = map.table; + // if (tab != null && tab.length >= (hi = getFence()) && index >= 0) { + // while (current != null || index < hi) { + // if (current == null) + // current = tab[index++]; + // else { + // V v = current.value; + // current = current.next; + // action.accept(v); + // if (map.modCount != expectedModCount) + // throw new ConcurrentModificationException(); + // return true; + // } + // } + // } + // return false; + CProver.notModelled(); + return CProver.nondetBoolean(); + } + + public int characteristics() { + // return (fence < 0 || est == map.size ? Spliterator.SIZED : 0); + CProver.notModelled(); + return CProver.nondetInt(); + } + } + + /** + * @diffblue.noSupport + */ + static final class EntrySpliterator + extends HashMapSpliterator + implements Spliterator> { + EntrySpliterator(HashMap m, int origin, int fence, int est, + int expectedModCount) { + super(m, origin, fence, est, expectedModCount); + CProver.notModelled(); + } + + public EntrySpliterator trySplit() { + // int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; + // return (lo >= mid || current != null) ? null : + // new EntrySpliterator<>(map, lo, index = mid, est >>>= 1, + // expectedModCount); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + public void forEachRemaining(Consumer> action) { + // int i, hi, mc; + // if (action == null) + // throw new NullPointerException(); + // HashMap m = map; + // Node[] tab = m.table; + // if ((hi = fence) < 0) { + // mc = expectedModCount = m.modCount; + // hi = fence = (tab == null) ? 0 : tab.length; + // } + // else + // mc = expectedModCount; + // if (tab != null && tab.length >= hi && + // (i = index) >= 0 && (i < (index = hi) || current != null)) { + // Node p = current; + // current = null; + // do { + // if (p == null) + // p = tab[i++]; + // else { + // action.accept(p); + // p = p.next; + // } + // } while (p != null || i < hi); + // if (m.modCount != mc) + // throw new ConcurrentModificationException(); + // } + CProver.notModelled(); + } + + public boolean tryAdvance(Consumer> action) { + // int hi; + // if (action == null) + // throw new NullPointerException(); + // Node[] tab = map.table; + // if (tab != null && tab.length >= (hi = getFence()) && index >= 0) { + // while (current != null || index < hi) { + // if (current == null) + // current = tab[index++]; + // else { + // Node e = current; + // current = current.next; + // action.accept(e); + // if (map.modCount != expectedModCount) + // throw new ConcurrentModificationException(); + // return true; + // } + // } + // } + // return false; + CProver.notModelled(); + return CProver.nondetBoolean(); + } + + public int characteristics() { + // return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) | + // Spliterator.DISTINCT; + CProver.notModelled(); + return CProver.nondetInt(); + } + } + + /* ------------------------------------------------------------ */ + // LinkedHashMap support + + + /* + * The following package-protected methods are designed to be + * overridden by LinkedHashMap, but not by any other subclass. + * Nearly all other internal methods are also package-protected + * but are declared final, so can be used by LinkedHashMap, view + * classes, and HashSet. + */ + + // Create a regular (non-tree) node + // DIFFBLUE MODEL LIBRARY Package-private model not used in model + // Node newNode(int hash, K key, V value, Node next) { + // return new Node<>(hash, key, value, next); + // } + + // For conversion from TreeNodes to plain nodes + // DIFFBLUE MODEL LIBRARY Package-private model not used in model + // Node replacementNode(Node p, Node next) { + // return new Node<>(p.hash, p.key, p.value, next); + // } + + // Create a tree bin node + // DIFFBLUE MODEL LIBRARY Package-private model not used in model + // TreeNode newTreeNode(int hash, K key, V value, Node next) { + // return new TreeNode<>(hash, key, value, next); + // } + + // For treeifyBin + // DIFFBLUE MODEL LIBRARY Package-private model not used in model + // TreeNode replacementTreeNode(Node p, Node next) { + // return new TreeNode<>(p.hash, p.key, p.value, next); + // } + + /** + * Reset to initial default state. Called by clone and readObject. + */ + // DIFFBLUE MODEL LIBRARY Package-private model not used in model + // void reinitialize() { + // table = null; + // entrySet = null; + // keySet = null; + // values = null; + // modCount = 0; + // threshold = 0; + // size = 0; + // } + + // Callbacks to allow LinkedHashMap post-actions + // DIFFBLUE MODEL LIBRARY Package-private model not used in model + // void afterNodeAccess(Node p) { } + // DIFFBLUE MODEL LIBRARY Package-private model not used in model + // void afterNodeInsertion(boolean evict) { } + // DIFFBLUE MODEL LIBRARY Package-private model not used in model + // void afterNodeRemoval(Node p) { } + + // Called only from writeObject, to ensure compatible ordering. + // DIFFBLUE MODEL LIBRARY Package-private model not used in model + // void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException { + // Node[] tab; + // if (size > 0 && (tab = table) != null) { + // for (int i = 0; i < tab.length; ++i) { + // for (Node e = tab[i]; e != null; e = e.next) { + // s.writeObject(e.key); + // s.writeObject(e.value); + // } + // } + // } + // } + + /* ------------------------------------------------------------ */ + // Tree bins + + /** + * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn + * extends Node) so can be used as extension of either regular or + * linked node. + */ + // DIFFBLUE MODEL LIBRARY This inner class is not used in the model + // static final class TreeNode extends LinkedHashMap.Entry { + // TreeNode parent; // red-black tree links + // TreeNode left; + // TreeNode right; + // TreeNode prev; // needed to unlink next upon deletion + // boolean red; + // TreeNode(int hash, K key, V val, Node next) { + // super(hash, key, val, next); + // } + + // /** + // * Returns root of tree containing this node. + // */ + // final TreeNode root() { + // for (TreeNode r = this, p;;) { + // if ((p = r.parent) == null) + // return r; + // r = p; + // } + // } + + // /** + // * Ensures that the given root is the first node of its bin. + // */ + // static void moveRootToFront(Node[] tab, TreeNode root) { + // int n; + // if (root != null && tab != null && (n = tab.length) > 0) { + // int index = (n - 1) & root.hash; + // TreeNode first = (TreeNode)tab[index]; + // if (root != first) { + // Node rn; + // tab[index] = root; + // TreeNode rp = root.prev; + // if ((rn = root.next) != null) + // ((TreeNode)rn).prev = rp; + // if (rp != null) + // rp.next = rn; + // if (first != null) + // first.prev = root; + // root.next = first; + // root.prev = null; + // } + // assert checkInvariants(root); + // } + // } + + // /** + // * Finds the node starting at root p with the given hash and key. + // * The kc argument caches comparableClassFor(key) upon first use + // * comparing keys. + // */ + // final TreeNode find(int h, Object k, Class kc) { + // TreeNode p = this; + // do { + // int ph, dir; K pk; + // TreeNode pl = p.left, pr = p.right, q; + // if ((ph = p.hash) > h) + // p = pl; + // else if (ph < h) + // p = pr; + // else if ((pk = p.key) == k || (k != null && k.equals(pk))) + // return p; + // else if (pl == null) + // p = pr; + // else if (pr == null) + // p = pl; + // else if ((kc != null || + // (kc = comparableClassFor(k)) != null) && + // (dir = compareComparables(kc, k, pk)) != 0) + // p = (dir < 0) ? pl : pr; + // else if ((q = pr.find(h, k, kc)) != null) + // return q; + // else + // p = pl; + // } while (p != null); + // return null; + // } + + // /** + // * Calls find for root node. + // */ + // final TreeNode getTreeNode(int h, Object k) { + // return ((parent != null) ? root() : this).find(h, k, null); + // } + + // /** + // * Tie-breaking utility for ordering insertions when equal + // * hashCodes and non-comparable. We don't require a total + // * order, just a consistent insertion rule to maintain + // * equivalence across rebalancings. Tie-breaking further than + // * necessary simplifies testing a bit. + // */ + // static int tieBreakOrder(Object a, Object b) { + // int d; + // if (a == null || b == null || + // (d = a.getClass().getName(). + // compareTo(b.getClass().getName())) == 0) + // d = (System.identityHashCode(a) <= System.identityHashCode(b) ? + // -1 : 1); + // return d; + // } + + // /** + // * Forms tree of the nodes linked from this node. + // * @return root of tree + // */ + // final void treeify(Node[] tab) { + // TreeNode root = null; + // for (TreeNode x = this, next; x != null; x = next) { + // next = (TreeNode)x.next; + // x.left = x.right = null; + // if (root == null) { + // x.parent = null; + // x.red = false; + // root = x; + // } + // else { + // K k = x.key; + // int h = x.hash; + // Class kc = null; + // for (TreeNode p = root;;) { + // int dir, ph; + // K pk = p.key; + // if ((ph = p.hash) > h) + // dir = -1; + // else if (ph < h) + // dir = 1; + // else if ((kc == null && + // (kc = comparableClassFor(k)) == null) || + // (dir = compareComparables(kc, k, pk)) == 0) + // dir = tieBreakOrder(k, pk); + + // TreeNode xp = p; + // if ((p = (dir <= 0) ? p.left : p.right) == null) { + // x.parent = xp; + // if (dir <= 0) + // xp.left = x; + // else + // xp.right = x; + // root = balanceInsertion(root, x); + // break; + // } + // } + // } + // } + // moveRootToFront(tab, root); + // } + + // /** + // * Returns a list of non-TreeNodes replacing those linked from + // * this node. + // */ + // final Node untreeify(HashMap map) { + // Node hd = null, tl = null; + // for (Node q = this; q != null; q = q.next) { + // Node p = map.replacementNode(q, null); + // if (tl == null) + // hd = p; + // else + // tl.next = p; + // tl = p; + // } + // return hd; + // } + + // /** + // * Tree version of putVal. + // */ + // final TreeNode putTreeVal(HashMap map, Node[] tab, + // int h, K k, V v) { + // Class kc = null; + // boolean searched = false; + // TreeNode root = (parent != null) ? root() : this; + // for (TreeNode p = root;;) { + // int dir, ph; K pk; + // if ((ph = p.hash) > h) + // dir = -1; + // else if (ph < h) + // dir = 1; + // else if ((pk = p.key) == k || (k != null && k.equals(pk))) + // return p; + // else if ((kc == null && + // (kc = comparableClassFor(k)) == null) || + // (dir = compareComparables(kc, k, pk)) == 0) { + // if (!searched) { + // TreeNode q, ch; + // searched = true; + // if (((ch = p.left) != null && + // (q = ch.find(h, k, kc)) != null) || + // ((ch = p.right) != null && + // (q = ch.find(h, k, kc)) != null)) + // return q; + // } + // dir = tieBreakOrder(k, pk); + // } + + // TreeNode xp = p; + // if ((p = (dir <= 0) ? p.left : p.right) == null) { + // Node xpn = xp.next; + // TreeNode x = map.newTreeNode(h, k, v, xpn); + // if (dir <= 0) + // xp.left = x; + // else + // xp.right = x; + // xp.next = x; + // x.parent = x.prev = xp; + // if (xpn != null) + // ((TreeNode)xpn).prev = x; + // moveRootToFront(tab, balanceInsertion(root, x)); + // return null; + // } + // } + // } + + // /** + // * Removes the given node, that must be present before this call. + // * This is messier than typical red-black deletion code because we + // * cannot swap the contents of an interior node with a leaf + // * successor that is pinned by "next" pointers that are accessible + // * independently during traversal. So instead we swap the tree + // * linkages. If the current tree appears to have too few nodes, + // * the bin is converted back to a plain bin. (The test triggers + // * somewhere between 2 and 6 nodes, depending on tree structure). + // */ + // final void removeTreeNode(HashMap map, Node[] tab, + // boolean movable) { + // int n; + // if (tab == null || (n = tab.length) == 0) + // return; + // int index = (n - 1) & hash; + // TreeNode first = (TreeNode)tab[index], root = first, rl; + // TreeNode succ = (TreeNode)next, pred = prev; + // if (pred == null) + // tab[index] = first = succ; + // else + // pred.next = succ; + // if (succ != null) + // succ.prev = pred; + // if (first == null) + // return; + // if (root.parent != null) + // root = root.root(); + // if (root == null || root.right == null || + // (rl = root.left) == null || rl.left == null) { + // tab[index] = first.untreeify(map); // too small + // return; + // } + // TreeNode p = this, pl = left, pr = right, replacement; + // if (pl != null && pr != null) { + // TreeNode s = pr, sl; + // while ((sl = s.left) != null) // find successor + // s = sl; + // boolean c = s.red; s.red = p.red; p.red = c; // swap colors + // TreeNode sr = s.right; + // TreeNode pp = p.parent; + // if (s == pr) { // p was s's direct parent + // p.parent = s; + // s.right = p; + // } + // else { + // TreeNode sp = s.parent; + // if ((p.parent = sp) != null) { + // if (s == sp.left) + // sp.left = p; + // else + // sp.right = p; + // } + // if ((s.right = pr) != null) + // pr.parent = s; + // } + // p.left = null; + // if ((p.right = sr) != null) + // sr.parent = p; + // if ((s.left = pl) != null) + // pl.parent = s; + // if ((s.parent = pp) == null) + // root = s; + // else if (p == pp.left) + // pp.left = s; + // else + // pp.right = s; + // if (sr != null) + // replacement = sr; + // else + // replacement = p; + // } + // else if (pl != null) + // replacement = pl; + // else if (pr != null) + // replacement = pr; + // else + // replacement = p; + // if (replacement != p) { + // TreeNode pp = replacement.parent = p.parent; + // if (pp == null) + // root = replacement; + // else if (p == pp.left) + // pp.left = replacement; + // else + // pp.right = replacement; + // p.left = p.right = p.parent = null; + // } + + // TreeNode r = p.red ? root : balanceDeletion(root, replacement); + + // if (replacement == p) { // detach + // TreeNode pp = p.parent; + // p.parent = null; + // if (pp != null) { + // if (p == pp.left) + // pp.left = null; + // else if (p == pp.right) + // pp.right = null; + // } + // } + // if (movable) + // moveRootToFront(tab, r); + // } + + // /** + // * Splits nodes in a tree bin into lower and upper tree bins, + // * or untreeifies if now too small. Called only from resize; + // * see above discussion about split bits and indices. + // * + // * @param map the map + // * @param tab the table for recording bin heads + // * @param index the index of the table being split + // * @param bit the bit of hash to split on + // */ + // final void split(HashMap map, Node[] tab, int index, int bit) { + // TreeNode b = this; + // // Relink into lo and hi lists, preserving order + // TreeNode loHead = null, loTail = null; + // TreeNode hiHead = null, hiTail = null; + // int lc = 0, hc = 0; + // for (TreeNode e = b, next; e != null; e = next) { + // next = (TreeNode)e.next; + // e.next = null; + // if ((e.hash & bit) == 0) { + // if ((e.prev = loTail) == null) + // loHead = e; + // else + // loTail.next = e; + // loTail = e; + // ++lc; + // } + // else { + // if ((e.prev = hiTail) == null) + // hiHead = e; + // else + // hiTail.next = e; + // hiTail = e; + // ++hc; + // } + // } + + // if (loHead != null) { + // if (lc <= UNTREEIFY_THRESHOLD) + // tab[index] = loHead.untreeify(map); + // else { + // tab[index] = loHead; + // if (hiHead != null) // (else is already treeified) + // loHead.treeify(tab); + // } + // } + // if (hiHead != null) { + // if (hc <= UNTREEIFY_THRESHOLD) + // tab[index + bit] = hiHead.untreeify(map); + // else { + // tab[index + bit] = hiHead; + // if (loHead != null) + // hiHead.treeify(tab); + // } + // } + // } + + // /* ------------------------------------------------------------ */ + // // Red-black tree methods, all adapted from CLR + + // static TreeNode rotateLeft(TreeNode root, + // TreeNode p) { + // TreeNode r, pp, rl; + // if (p != null && (r = p.right) != null) { + // if ((rl = p.right = r.left) != null) + // rl.parent = p; + // if ((pp = r.parent = p.parent) == null) + // (root = r).red = false; + // else if (pp.left == p) + // pp.left = r; + // else + // pp.right = r; + // r.left = p; + // p.parent = r; + // } + // return root; + // } + + // static TreeNode rotateRight(TreeNode root, + // TreeNode p) { + // TreeNode l, pp, lr; + // if (p != null && (l = p.left) != null) { + // if ((lr = p.left = l.right) != null) + // lr.parent = p; + // if ((pp = l.parent = p.parent) == null) + // (root = l).red = false; + // else if (pp.right == p) + // pp.right = l; + // else + // pp.left = l; + // l.right = p; + // p.parent = l; + // } + // return root; + // } + + // static TreeNode balanceInsertion(TreeNode root, + // TreeNode x) { + // x.red = true; + // for (TreeNode xp, xpp, xppl, xppr;;) { + // if ((xp = x.parent) == null) { + // x.red = false; + // return x; + // } + // else if (!xp.red || (xpp = xp.parent) == null) + // return root; + // if (xp == (xppl = xpp.left)) { + // if ((xppr = xpp.right) != null && xppr.red) { + // xppr.red = false; + // xp.red = false; + // xpp.red = true; + // x = xpp; + // } + // else { + // if (x == xp.right) { + // root = rotateLeft(root, x = xp); + // xpp = (xp = x.parent) == null ? null : xp.parent; + // } + // if (xp != null) { + // xp.red = false; + // if (xpp != null) { + // xpp.red = true; + // root = rotateRight(root, xpp); + // } + // } + // } + // } + // else { + // if (xppl != null && xppl.red) { + // xppl.red = false; + // xp.red = false; + // xpp.red = true; + // x = xpp; + // } + // else { + // if (x == xp.left) { + // root = rotateRight(root, x = xp); + // xpp = (xp = x.parent) == null ? null : xp.parent; + // } + // if (xp != null) { + // xp.red = false; + // if (xpp != null) { + // xpp.red = true; + // root = rotateLeft(root, xpp); + // } + // } + // } + // } + // } + // } + + // static TreeNode balanceDeletion(TreeNode root, + // TreeNode x) { + // for (TreeNode xp, xpl, xpr;;) { + // if (x == null || x == root) + // return root; + // else if ((xp = x.parent) == null) { + // x.red = false; + // return x; + // } + // else if (x.red) { + // x.red = false; + // return root; + // } + // else if ((xpl = xp.left) == x) { + // if ((xpr = xp.right) != null && xpr.red) { + // xpr.red = false; + // xp.red = true; + // root = rotateLeft(root, xp); + // xpr = (xp = x.parent) == null ? null : xp.right; + // } + // if (xpr == null) + // x = xp; + // else { + // TreeNode sl = xpr.left, sr = xpr.right; + // if ((sr == null || !sr.red) && + // (sl == null || !sl.red)) { + // xpr.red = true; + // x = xp; + // } + // else { + // if (sr == null || !sr.red) { + // if (sl != null) + // sl.red = false; + // xpr.red = true; + // root = rotateRight(root, xpr); + // xpr = (xp = x.parent) == null ? + // null : xp.right; + // } + // if (xpr != null) { + // xpr.red = (xp == null) ? false : xp.red; + // if ((sr = xpr.right) != null) + // sr.red = false; + // } + // if (xp != null) { + // xp.red = false; + // root = rotateLeft(root, xp); + // } + // x = root; + // } + // } + // } + // else { // symmetric + // if (xpl != null && xpl.red) { + // xpl.red = false; + // xp.red = true; + // root = rotateRight(root, xp); + // xpl = (xp = x.parent) == null ? null : xp.left; + // } + // if (xpl == null) + // x = xp; + // else { + // TreeNode sl = xpl.left, sr = xpl.right; + // if ((sl == null || !sl.red) && + // (sr == null || !sr.red)) { + // xpl.red = true; + // x = xp; + // } + // else { + // if (sl == null || !sl.red) { + // if (sr != null) + // sr.red = false; + // xpl.red = true; + // root = rotateLeft(root, xpl); + // xpl = (xp = x.parent) == null ? + // null : xp.left; + // } + // if (xpl != null) { + // xpl.red = (xp == null) ? false : xp.red; + // if ((sl = xpl.left) != null) + // sl.red = false; + // } + // if (xp != null) { + // xp.red = false; + // root = rotateRight(root, xp); + // } + // x = root; + // } + // } + // } + // } + // } + + // /** + // * Recursive invariant check + // */ + // static boolean checkInvariants(TreeNode t) { + // TreeNode tp = t.parent, tl = t.left, tr = t.right, + // tb = t.prev, tn = (TreeNode)t.next; + // if (tb != null && tb.next != t) + // return false; + // if (tn != null && tn.prev != t) + // return false; + // if (tp != null && t != tp.left && t != tp.right) + // return false; + // if (tl != null && (tl.parent != t || tl.hash > t.hash)) + // return false; + // if (tr != null && (tr.parent != t || tr.hash < t.hash)) + // return false; + // if (t.red && tl != null && tl.red && tr != null && tr.red) + // return false; + // if (tl != null && !checkInvariants(tl)) + // return false; + // if (tr != null && !checkInvariants(tr)) + // return false; + // return true; + // } + // } + + // DIFFBLUE MODEL LIBRARY + // A helper method used in various methods in the model to find the array + // index of a Node (pair) with the specified key. It has a similar purpose + // to getNode() in the original implementation. + protected int cproverIndexOfKey(Object key) { + if (key == null) { + for (int i = 0; i < size; i++) + if (table[i].key == null) + return i; + } else { + for (int i = 0; i < size; i++) + if (key.equals(table[i].key)) + return i; + } + return -1; + } + + // DIFFBLUE MODEL LIBRARY + // A helper method used in various methods in the model to find the array + // index of a Node (pair) with the specified value. + protected int cproverIndexOfValue(Object value) { + if (value == null) { + for (int i = 0; i < size; i++) + if (table[i].value == null) + return i; + } else { + for (int i = 0; i < size; i++) + if (value.equals(table[i].value)) + return i; + } + return -1; + } + + // DIFFBLUE MODEL LIBRARY + // Remove the object at the given index in the array. This method is not + // present in the original jdk. + // Since we do not care about the order of elements in the array, we can + // simply move the last element into the index of the removed element. + protected void cproverRemoveIndex(int index) { + table[index] = table[size-1]; + modCount++; + size--; + } + + // DIFFBLUE MODEL LIBRARY + // This method is called by CBMC just after nondeterministic object + // creation, i.e. the constraints that it specifies are only enforced at + // that time and do not have to hold globally. + // We generally want to make sure that all necessary invariants of the class + // are satisfied, and potentially restrict some fields to speed up test + // generation. + @org.cprover.MustNotThrow + protected void cproverNondetInitialize() { + // super.cproverNondetInitialize(); + // We limit the number of elements in the nondeterministically created + // HashMap to at most 1 so we won't have to worry about duplicate keys. + CProver.assume(size == 0 || size == 1); + CProver.assume(table != null); + CProver.assume(table.length >= size); + if (size > 0) { + CProver.assume(table[0] != null); + } + // Nondeterministic HashMaps are created using a + // call to the + // public HashMap() + // constructor, followed by a sequence of calls to put, where the number + // of such calls is equal to size. Each call to put increments the + // modCount variable by 1. + CProver.assume(modCount == size); + CProver.assume(entrySet == null); + } + +} diff --git a/src/main/java/java/util/Iterator.java b/src/main/java/java/util/Iterator.java new file mode 100644 index 0000000..18fb11d --- /dev/null +++ b/src/main/java/java/util/Iterator.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.util.function.Consumer; + +import org.cprover.CProver; + +/** + * An iterator over a collection. {@code Iterator} takes the place of + * {@link Enumeration} in the Java Collections Framework. Iterators + * differ from enumerations in two ways: + * + *

    + *
  • Iterators allow the caller to remove elements from the + * underlying collection during the iteration with well-defined + * semantics. + *
  • Method names have been improved. + *
+ * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @param the type of elements returned by this iterator + * + * @author Josh Bloch + * @see Collection + * @see ListIterator + * @see Iterable + * @since 1.2 + */ +public interface Iterator { + /** + * Returns {@code true} if the iteration has more elements. + * (In other words, returns {@code true} if {@link #next} would + * return an element rather than throwing an exception.) + * + * @return {@code true} if the iteration has more elements + */ + boolean hasNext(); + + /** + * Returns the next element in the iteration. + * + * @return the next element in the iteration + * @throws NoSuchElementException if the iteration has no more elements + */ + E next(); + + /** + * Removes from the underlying collection the last element returned + * by this iterator (optional operation). This method can be called + * only once per call to {@link #next}. The behavior of an iterator + * is unspecified if the underlying collection is modified while the + * iteration is in progress in any way other than by calling this + * method. + * + * @implSpec + * The default implementation throws an instance of + * {@link UnsupportedOperationException} and performs no other action. + * + * @throws UnsupportedOperationException if the {@code remove} + * operation is not supported by this iterator + * + * @throws IllegalStateException if the {@code next} method has not + * yet been called, or the {@code remove} method has already + * been called after the last call to the {@code next} + * method + */ + default void remove() { + // throw new UnsupportedOperationException("remove"); + CProver.notModelled(); + } + + /** + * Performs the given action for each remaining element until all elements + * have been processed or the action throws an exception. Actions are + * performed in the order of iteration, if that order is specified. + * Exceptions thrown by the action are relayed to the caller. + * + * @implSpec + *

The default implementation behaves as if: + *

{@code
+     *     while (hasNext())
+     *         action.accept(next());
+     * }
+ * + * @param action The action to be performed for each element + * @throws NullPointerException if the specified action is null + * @since 1.8 + */ + default void forEachRemaining(Consumer action) { + // Objects.requireNonNull(action); + // while (hasNext()) + // action.accept(next()); + CProver.notModelled(); + } +} diff --git a/src/main/java/java/util/LinkedList.java b/src/main/java/java/util/LinkedList.java new file mode 100644 index 0000000..7d96530 --- /dev/null +++ b/src/main/java/java/util/LinkedList.java @@ -0,0 +1,1701 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.util.function.Consumer; + +import org.cprover.CProver; + +/** + * Doubly-linked list implementation of the {@code List} and {@code Deque} + * interfaces. Implements all optional list operations, and permits all + * elements (including {@code null}). + * + *

All of the operations perform as could be expected for a doubly-linked + * list. Operations that index into the list will traverse the list from + * the beginning or the end, whichever is closer to the specified index. + * + *

Note that this implementation is not synchronized. + * If multiple threads access a linked list concurrently, and at least + * one of the threads modifies the list structurally, it must be + * synchronized externally. (A structural modification is any operation + * that adds or deletes one or more elements; merely setting the value of + * an element is not a structural modification.) This is typically + * accomplished by synchronizing on some object that naturally + * encapsulates the list. + * + * If no such object exists, the list should be "wrapped" using the + * {@link Collections#synchronizedList Collections.synchronizedList} + * method. This is best done at creation time, to prevent accidental + * unsynchronized access to the list:

+ *   List list = Collections.synchronizedList(new LinkedList(...));
+ * + *

The iterators returned by this class's {@code iterator} and + * {@code listIterator} methods are fail-fast: if the list is + * structurally modified at any time after the iterator is created, in + * any way except through the Iterator's own {@code remove} or + * {@code add} methods, the iterator will throw a {@link + * ConcurrentModificationException}. Thus, in the face of concurrent + * modification, the iterator fails quickly and cleanly, rather than + * risking arbitrary, non-deterministic behavior at an undetermined + * time in the future. + * + *

Note that the fail-fast behavior of an iterator cannot be guaranteed + * as it is, generally speaking, impossible to make any hard guarantees in the + * presence of unsynchronized concurrent modification. Fail-fast iterators + * throw {@code ConcurrentModificationException} on a best-effort basis. + * Therefore, it would be wrong to write a program that depended on this + * exception for its correctness: the fail-fast behavior of iterators + * should be used only to detect bugs. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @author Josh Bloch + * @see List + * @see ArrayList + * @since 1.2 + * @param the type of elements held in this collection + * + * @diffblue.limitedSupport + * Only a few high-priority methods are modelled. + * The model uses a circular buffer to store the elements of the linked list. + * Circular buffers are commonly used for queues with bounded capacity. + * For performance reasons, there may be restrictions on the capacity of this + * buffer, which limits the number of elements which can be stored in the model + * of LinkedList: + *

    + *
  • LinkedLists constructed using constructors of this class will have a + * fixed capacity of CProver.defaultContainerCapacity(). + *
  • Non-deterministic LinkedLists are limited by the JBMC + * parameter `--max-nondet-array-length`. + *
  • LinkedLists read from `--static-values` are currently unlimited. + *
+ * LinkedLists with a greater number of elements are not supported. + * Adding/Removing elements to/from the beginning/end of the queue is easy to + * analyse, and traces should be generated in a short amount of time. Adding or + * removing elements to/from the middle of the array (not modelled yet) will be + * more complicated and JBMC will take longer. + *

The {@code ListIterator} implementation provided in this model is not + * supported as an input or a return value as long as custom initialisers have + * not been implemented in JBMC. + */ + +public class LinkedList + extends AbstractSequentialList + implements List, Deque, Cloneable, java.io.Serializable +{ + transient int size = 0; + + /** + * Pointer to first node. + * Invariant: (first == null && last == null) || + * (first.prev == null && first.item != null) + */ + // DIFFBLUE MODEL LIBRARY + // This package-private variable is only used in the original implementation + // of LinkedList, not in the model. + // transient Node first; + + /** + * Pointer to last node. + * Invariant: (first == null && last == null) || + * (last.next == null && last.item != null) + */ + // DIFFBLUE MODEL LIBRARY + // This package-private variable is only used in the original implementation + // of LinkedList, not in the model. + // transient Node last; + + // DIFFBLUE MODEL LIBRARY + // We avoid the doubly-linked list data structure from the original + // implementation, which would be difficult to analyse for CBMC, and instead + // use a circular buffer representation. This representation consists of + // - an array cproverData + // - an index cproverFirstIndex + // - a value size. + // The first element of the list (if nonempty) is stored at + // cproverData[cproverFirstIndex], and the element n steps after the first + // one is stored at + // cproverData[(cproverFirstIndex + n) mod cproverData.length], + // i.e., indices of subsequent elements increase by 1 until the end of the + // array is reached, at which point the structure "wraps around" and the + // index of the next element is 0. + // The empty case (size == 0) is treated as a special case when necessary. + E[] cproverData; + int cproverFirstIndex; + + /** + * Constructs an empty list. + * + * @diffblue.limitedSupport + * The number of elements in a LinkedList created that way is limited by + * CProver.defaultContainerCapacity(). + */ + public LinkedList() { + // DIFFBLUE MODEL LIBRARY + // cproverData = (E[]) new Object[CProver.defaultContainerCapacity()]; + cproverData = (E[]) new Object[4096]; + cproverFirstIndex = 0; + size = 0; + } + + /** + * Constructs a list containing the elements of the specified + * collection, in the order they are returned by the collection's + * iterator. + * + * @param c the collection whose elements are to be placed into this list + * @throws NullPointerException if the specified collection is null + * + * @diffblue.fullSupport + */ + public LinkedList(Collection c) { + this(); + addAll(c); + } + + /** + * Links e as first element. + */ + private void linkFirst(E e) { + // final Node f = first; + // final Node newNode = new Node<>(null, e, f); + // first = newNode; + // if (f == null) + // last = newNode; + // else + // f.prev = newNode; + // size++; + // modCount++; + int newFirst = cproverGetShiftedIndex(cproverFirstIndex, -1); + CProver.assume(newFirst != cproverGetLastIndex() || size == 0); + cproverData[newFirst] = e; + cproverFirstIndex = newFirst; + size++; + modCount++; + } + + /** + * Links e as last element. + */ + void linkLast(E e) { + // final Node l = last; + // final Node newNode = new Node<>(l, e, null); + // last = newNode; + // if (l == null) + // first = newNode; + // else + // l.next = newNode; + // size++; + // modCount++; + int newLast = cproverGetShiftedIndex(cproverGetLastIndex(), 1); + CProver.assume(newLast != cproverFirstIndex || size == 0); + cproverData[newLast] = e; + size++; + modCount++; + } + + /** + * Inserts element e before non-null Node succ. + */ + // DIFFBLUE MODEL LIBRARY Package-private method + // void linkBefore(E e, Node succ) { + // // assert succ != null; + // final Node pred = succ.prev; + // final Node newNode = new Node<>(pred, e, succ); + // succ.prev = newNode; + // if (pred == null) + // first = newNode; + // else + // pred.next = newNode; + // size++; + // modCount++; + // } + + /** + * Unlinks non-null first node f. + */ + // DIFFBLUE MODEL LIBRARY Private method + // private E unlinkFirst(Node f) { + // // assert f == first && f != null; + // final E element = f.item; + // final Node next = f.next; + // f.item = null; + // f.next = null; // help GC + // first = next; + // if (next == null) + // last = null; + // else + // next.prev = null; + // size--; + // modCount++; + // return element; + // } + + /** + * Unlinks non-null last node l. + */ + // DIFFBLUE MODEL LIBRARY Private method + // private E unlinkLast(Node l) { + // // assert l == last && l != null; + // final E element = l.item; + // final Node prev = l.prev; + // l.item = null; + // l.prev = null; // help GC + // last = prev; + // if (prev == null) + // first = null; + // else + // prev.next = null; + // size--; + // modCount++; + // return element; + // } + + /** + * Unlinks non-null node x. + */ + // DIFFBLUE MODEL LIBRARY Package-private method + // E unlink(Node x) { + // // assert x != null; + // final E element = x.item; + // final Node next = x.next; + // final Node prev = x.prev; + + // if (prev == null) { + // first = next; + // } else { + // prev.next = next; + // x.prev = null; + // } + + // if (next == null) { + // last = prev; + // } else { + // next.prev = prev; + // x.next = null; + // } + + // x.item = null; + // size--; + // modCount++; + // return element; + // } + + /** + * Returns the first element in this list. + * + * @return the first element in this list + * @throws NoSuchElementException if this list is empty + * + * @diffblue.fullSupport + */ + public E getFirst() { + // final Node f = first; + // if (f == null) + // throw new NoSuchElementException(); + // return f.item; + if (size == 0) { + throw new NoSuchElementException(); + } + return cproverData[cproverFirstIndex]; + } + + /** + * Returns the last element in this list. + * + * @return the last element in this list + * @throws NoSuchElementException if this list is empty + * + * @diffblue.fullSupport + */ + public E getLast() { + // final Node l = last; + // if (l == null) + // throw new NoSuchElementException(); + // return l.item; + if (size == 0) + throw new NoSuchElementException(); + return cproverData[cproverGetLastIndex()]; + } + + /** + * Removes and returns the first element from this list. + * + * @return the first element from this list + * @throws NoSuchElementException if this list is empty + * + * @diffblue.fullSupport + */ + public E removeFirst() { + // final Node f = first; + // if (f == null) + // throw new NoSuchElementException(); + // return unlinkFirst(f); + if (size == 0) + throw new NoSuchElementException(); + E first = cproverData[cproverFirstIndex]; + cproverFirstIndex = cproverGetShiftedIndex(cproverFirstIndex, 1); + size--; + modCount++; + return first; + } + + /** + * Removes and returns the last element from this list. + * + * @return the last element from this list + * @throws NoSuchElementException if this list is empty + * + * @diffblue.fullSupport + */ + public E removeLast() { + // final Node l = last; + // if (l == null) + // throw new NoSuchElementException(); + // return unlinkLast(l); + if (size == 0) + throw new NoSuchElementException(); + E last = cproverData[cproverGetLastIndex()]; + size--; + modCount++; + return last; + } + + /** + * Inserts the specified element at the beginning of this list. + * + * @param e the element to add + * + * @diffblue.fullSupport + */ + public void addFirst(E e) { + linkFirst(e); + } + + /** + * Appends the specified element to the end of this list. + * + *

This method is equivalent to {@link #add}. + * + * @param e the element to add + * + * @diffblue.fullSupport + * @diffblue.untested + * Untested since practically the same implementation as add() + */ + public void addLast(E e) { + linkLast(e); + } + + /** + * Returns {@code true} if this list contains the specified element. + * More formally, returns {@code true} if and only if this list contains + * at least one element {@code e} such that + * (o==null ? e==null : o.equals(e)). + * + * @param o element whose presence in this list is to be tested + * @return {@code true} if this list contains the specified element + * + * @diffblue.fullSupport + */ + public boolean contains(Object o) { + return indexOf(o) != -1; + } + + /** + * Returns the number of elements in this list. + * + * @return the number of elements in this list + * + * @diffblue.fullSupport + */ + public int size() { + return size; + } + + /** + * Appends the specified element to the end of this list. + * + *

This method is equivalent to {@link #addLast}. + * + * @param e element to be appended to this list + * @return {@code true} (as specified by {@link Collection#add}) + * + * @diffblue.fullSupport + */ + public boolean add(E e) { + linkLast(e); + return true; + } + + /** + * Removes the first occurrence of the specified element from this list, + * if it is present. If this list does not contain the element, it is + * unchanged. More formally, removes the element with the lowest index + * {@code i} such that + * (o==null ? get(i)==null : o.equals(get(i))) + * (if such an element exists). Returns {@code true} if this list + * contained the specified element (or equivalently, if this list + * changed as a result of the call). + * + * @param o element to be removed from this list, if present + * @return {@code true} if this list contained the specified element + * + * @diffblue.limitedSupport + * No traces generated for String lists containing null values + */ + public boolean remove(Object o) { + // if (o == null) { + // for (Node x = first; x != null; x = x.next) { + // if (x.item == null) { + // unlink(x); + // return true; + // } + // } + // } else { + // for (Node x = first; x != null; x = x.next) { + // if (o.equals(x.item)) { + // unlink(x); + // return true; + // } + // } + // } + // return false; + // We use indexOf to get the index of o then call remove(int). + // If the index doesn't exist, indexOf returns -1. + int i = indexOf(o); + if (i == -1) { + return false; + } + remove(i); + return true; + } + + /** + * Appends all of the elements in the specified collection to the end of + * this list, in the order that they are returned by the specified + * collection's iterator. The behavior of this operation is undefined if + * the specified collection is modified while the operation is in + * progress. (Note that this will occur if the specified collection is + * this list, and it's nonempty.) + * + * @param c collection containing elements to be added to this list + * @return {@code true} if this list changed as a result of the call + * @throws NullPointerException if the specified collection is null + * + * @diffblue.fullSupport + */ + public boolean addAll(Collection c) { + // return addAll(size, c); + boolean modified = false; + E[] a = (E[]) c.toArray(); + for (int i = 0; i < a.length; i++) { + modified |= add(a[i]); + } + return modified; + } + + /** + * Inserts all of the elements in the specified collection into this + * list, starting at the specified position. Shifts the element + * currently at that position (if any) and any subsequent elements to + * the right (increases their indices). The new elements will appear + * in the list in the order that they are returned by the + * specified collection's iterator. + * + * @param index index at which to insert the first element + * from the specified collection + * @param c collection containing elements to be added to this list + * @return {@code true} if this list changed as a result of the call + * @throws IndexOutOfBoundsException {@inheritDoc} + * @throws NullPointerException if the specified collection is null + * + * @diffblue.noSupport + */ + public boolean addAll(int index, Collection c) { + // checkPositionIndex(index); + + // Object[] a = c.toArray(); + // int numNew = a.length; + // if (numNew == 0) + // return false; + + // Node pred, succ; + // if (index == size) { + // succ = null; + // pred = last; + // } else { + // succ = node(index); + // pred = succ.prev; + // } + + // for (Object o : a) { + // @SuppressWarnings("unchecked") E e = (E) o; + // Node newNode = new Node<>(pred, e, null); + // if (pred == null) + // first = newNode; + // else + // pred.next = newNode; + // pred = newNode; + // } + + // if (succ == null) { + // last = pred; + // } else { + // pred.next = succ; + // succ.prev = pred; + // } + + // size += numNew; + // modCount++; + // return true; + CProver.notModelled(); + return CProver.nondetBoolean(); + } + + /** + * Removes all of the elements from this list. + * The list will be empty after this call returns. + * + * @diffblue.fullSupport + */ + // DIFFBLUE MODEL LIBRARY + // Memory management can be ignored in the model. + public void clear() { + // // Clearing all of the links between nodes is "unnecessary", but: + // // - helps a generational GC if the discarded nodes inhabit + // // more than one generation + // // - is sure to free memory even if there is a reachable Iterator + // for (Node x = first; x != null; ) { + // Node next = x.next; + // x.item = null; + // x.next = null; + // x.prev = null; + // x = next; + // } + // first = last = null; + // size = 0; + // modCount++; + modCount++; + size = 0; + cproverFirstIndex = 0; + } + + + // Positional Access Operations + + /** + * Returns the element at the specified position in this list. + * + * @param index index of the element to return + * @return the element at the specified position in this list + * @throws IndexOutOfBoundsException {@inheritDoc} + * + * @diffblue.limitedSupport + * We do not support exception messages. + */ + public E get(int index) { + checkElementIndex(index); + // return node(index).item; + int dest = cproverGetShiftedIndex(cproverFirstIndex, index); + return cproverData[dest]; + } + + /** + * Replaces the element at the specified position in this list with the + * specified element. + * + * @param index index of the element to replace + * @param element element to be stored at the specified position + * @return the element previously at the specified position + * @throws IndexOutOfBoundsException {@inheritDoc} + * + * @diffblue.fullSupport + */ + public E set(int index, E element) { + // checkElementIndex(index); + // Node x = node(index); + // E oldVal = x.item; + // x.item = element; + // return oldVal; + checkElementIndex(index); + E oldValue = get(index); + int dest = cproverGetShiftedIndex(cproverFirstIndex, index); + cproverData[dest] = element; + return oldValue; + } + + /** + * Inserts the specified element at the specified position in this list. + * Shifts the element currently at that position (if any) and any + * subsequent elements to the right (adds one to their indices). + * + * @param index index at which the specified element is to be inserted + * @param element element to be inserted + * @throws IndexOutOfBoundsException {@inheritDoc} + * + * @diffblue.fullSupport + */ + public void add(int index, E element) { + // checkPositionIndex(index); + + // if (index == size) + // linkLast(element); + // else + // linkBefore(element, node(index)); + checkPositionIndex(index); + int newLast = cproverGetShiftedIndex(cproverGetLastIndex(), 1); + CProver.assume(newLast != cproverFirstIndex || size == 0); + for (int i = newLast; i > index; i--) { + cproverData[cproverGetShiftedIndex(cproverFirstIndex, i)] = + cproverData[cproverGetShiftedIndex(cproverFirstIndex, i-1)]; + } + cproverData[cproverGetShiftedIndex(cproverFirstIndex, index)] = element; + size++; + modCount++; + } + + /** + * Removes the element at the specified position in this list. Shifts any + * subsequent elements to the left (subtracts one from their indices). + * Returns the element that was removed from the list. + * + * @param index the index of the element to be removed + * @return the element previously at the specified position + * @throws IndexOutOfBoundsException {@inheritDoc} + * + * @diffblue.fullSupport + */ + public E remove(int index) { + // checkElementIndex(index); + // return unlink(node(index)); + checkElementIndex(index); + E oldValue = cproverData[cproverGetShiftedIndex(cproverFirstIndex, index)]; + for (int i = index; i < size - 1; i++) { + cproverData[cproverGetShiftedIndex(cproverFirstIndex, i)] = + cproverData[cproverGetShiftedIndex(cproverFirstIndex, i+1)]; + } + size--; + modCount++; + return oldValue; + } + + /** + * Tells if the argument is the index of an existing element. + */ + private boolean isElementIndex(int index) { + return index >= 0 && index < size; + } + + /** + * Tells if the argument is the index of a valid position for an + * iterator or an add operation. + */ + private boolean isPositionIndex(int index) { + return index >= 0 && index <= size; + } + + /** + * Constructs an IndexOutOfBoundsException detail message. + * Of the many possible refactorings of the error handling code, + * this "outlining" performs best with both server and client VMs. + */ + // DIFFBLUE MODEL LIBRARY Private method + // private String outOfBoundsMsg(int index) { + // return "Index: "+index+", Size: "+size; + // } + + private void checkElementIndex(int index) { + if (!isElementIndex(index)) + // throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + // DIFFBLUE MODEL LIBRARY + // We avoid the string concatenation in exception messages to speed + // up JBMC. + throw new IndexOutOfBoundsException(); + } + + private void checkPositionIndex(int index) { + if (!isPositionIndex(index)) + // throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + // DIFFBLUE MODEL LIBRARY + // We avoid the string concatenation in exception messages to speed + // up JBMC. + throw new IndexOutOfBoundsException(); + } + + /** + * Returns the (non-null) Node at the specified element index. + */ + // DIFFBLUE MODEL LIBRARY Package-private method + // Node node(int index) { + // // assert isElementIndex(index); + + // if (index < (size >> 1)) { + // Node x = first; + // for (int i = 0; i < index; i++) + // x = x.next; + // return x; + // } else { + // Node x = last; + // for (int i = size - 1; i > index; i--) + // x = x.prev; + // return x; + // } + // } + + // Search Operations + + /** + * Returns the index of the first occurrence of the specified element + * in this list, or -1 if this list does not contain the element. + * More formally, returns the lowest index {@code i} such that + * (o==null ? get(i)==null : o.equals(get(i))), + * or -1 if there is no such index. + * + * @param o element to search for + * @return the index of the first occurrence of the specified element in + * this list, or -1 if this list does not contain the element + * + * @diffblue.limitedSupport + * No traces generated for String lists containing null values + */ + public int indexOf(Object o) { + // int index = 0; + // if (o == null) { + // for (Node x = first; x != null; x = x.next) { + // if (x.item == null) + // return index; + // index++; + // } + // } else { + // for (Node x = first; x != null; x = x.next) { + // if (o.equals(x.item)) + // return index; + // index++; + // } + // } + // return -1; + if (o == null) { + for (int i = 0; i < size; i++) + if (cproverData[cproverGetShiftedIndex(cproverFirstIndex, i)]==null) + return i; + } else { + for (int i = 0; i < size; i++) + if (o.equals(cproverData[cproverGetShiftedIndex(cproverFirstIndex, i)])) + return i; + } + return -1; + } + + /** + * Returns the index of the last occurrence of the specified element + * in this list, or -1 if this list does not contain the element. + * More formally, returns the highest index {@code i} such that + * (o==null ? get(i)==null : o.equals(get(i))), + * or -1 if there is no such index. + * + * @param o element to search for + * @return the index of the last occurrence of the specified element in + * this list, or -1 if this list does not contain the element + * + * @diffblue.limitedSupport + * No traces generated for String lists containing null values + */ + public int lastIndexOf(Object o) { + // int index = size; + // if (o == null) { + // for (Node x = last; x != null; x = x.prev) { + // index--; + // if (x.item == null) + // return index; + // } + // } else { + // for (Node x = last; x != null; x = x.prev) { + // index--; + // if (o.equals(x.item)) + // return index; + // } + // } + // return -1; + if (o == null) { + for (int i = size-1; i >= 0; i--) + if (cproverData[cproverGetShiftedIndex(cproverFirstIndex, i)]==null) + return i; + } else { + for (int i = size-1; i >= 0; i--) + if (o.equals(cproverData[cproverGetShiftedIndex(cproverFirstIndex, i)])) + return i; + } + return -1; + } + + // Queue operations. + + /** + * Retrieves, but does not remove, the head (first element) of this list. + * + * @return the head of this list, or {@code null} if this list is empty + * @since 1.5 + * + * @diffblue.fullSupport + */ + public E peek() { + // final Node f = first; + // return (f == null) ? null : f.item; + return (size == 0) ? null : cproverData[cproverFirstIndex]; + } + + /** + * Retrieves, but does not remove, the head (first element) of this list. + * + * @return the head of this list + * @throws NoSuchElementException if this list is empty + * @since 1.5 + * + * @diffblue.untested + * @diffblue.fullSupport + * Untested since simply calls getFirst() + */ + public E element() { + return getFirst(); + } + + /** + * Retrieves and removes the head (first element) of this list. + * + * @return the head of this list, or {@code null} if this list is empty + * @since 1.5 + * + * @diffblue.fullSupport + */ + public E poll() { + // final Node f = first; + // return (f == null) ? null : unlinkFirst(f); + if (size == 0) + return null; + E first = cproverData[cproverFirstIndex]; + cproverFirstIndex = cproverGetShiftedIndex(cproverFirstIndex, 1); + size--; + modCount++; + return first; + } + + /** + * Retrieves and removes the head (first element) of this list. + * + * @return the head of this list + * @throws NoSuchElementException if this list is empty + * @since 1.5 + * + * @diffblue.untested + * @diffblue.fullSupport + * Untested since simply calls removeFirst() + */ + public E remove() { + return removeFirst(); + } + + /** + * Adds the specified element as the tail (last element) of this list. + * + * @param e the element to add + * @return {@code true} (as specified by {@link Queue#offer}) + * @since 1.5 + * + * @diffblue.untested + * @diffblue.fullSupport + * Untested since simply calls add() + */ + public boolean offer(E e) { + return add(e); + } + + // Deque operations + /** + * Inserts the specified element at the front of this list. + * + * @param e the element to insert + * @return {@code true} (as specified by {@link Deque#offerFirst}) + * @since 1.6 + * + * @diffblue.untested + * @diffblue.fullSupport + * Untested since simply calls addFirst() + */ + public boolean offerFirst(E e) { + addFirst(e); + return true; + } + + /** + * Inserts the specified element at the end of this list. + * + * @param e the element to insert + * @return {@code true} (as specified by {@link Deque#offerLast}) + * @since 1.6 + * + * @diffblue.untested + * @diffblue.fullSupport + * Untested since simply calls addLast + */ + public boolean offerLast(E e) { + addLast(e); + return true; + } + + /** + * Retrieves, but does not remove, the first element of this list, + * or returns {@code null} if this list is empty. + * + * @return the first element of this list, or {@code null} + * if this list is empty + * @since 1.6 + * + * @diffblue.untested + * @diffblue.fullSupport + * Untested since same implementation as peek() + */ + public E peekFirst() { + // final Node f = first; + // return (f == null) ? null : f.item; + return peek(); + } + + /** + * Retrieves, but does not remove, the last element of this list, + * or returns {@code null} if this list is empty. + * + * @return the last element of this list, or {@code null} + * if this list is empty + * @since 1.6 + * + * @diffblue.untested + * @diffblue.fullSupport + * Untested since trivial + */ + public E peekLast() { + // final Node l = last; + // return (l == null) ? null : l.item; + return (size == 0) ? null : cproverData[cproverGetLastIndex()]; + } + + /** + * Retrieves and removes the first element of this list, + * or returns {@code null} if this list is empty. + * + * @return the first element of this list, or {@code null} if + * this list is empty + * @since 1.6 + * + * @diffblue.fullSupport + * @diffblue.untested + * Untested since same implementation as poll() + */ + public E pollFirst() { + // final Node f = first; + // return (f == null) ? null : unlinkFirst(f); + return poll(); + } + + /** + * Retrieves and removes the last element of this list, + * or returns {@code null} if this list is empty. + * + * @return the last element of this list, or {@code null} if + * this list is empty + * @since 1.6 + * + * @diffblue.fullSupport + */ + public E pollLast() { + // final Node l = last; + // return (l == null) ? null : unlinkLast(l); + if (size == 0) + return null; + E last = cproverData[cproverGetLastIndex()]; + size--; + modCount++; + return last; + } + + /** + * Pushes an element onto the stack represented by this list. In other + * words, inserts the element at the front of this list. + * + *

This method is equivalent to {@link #addFirst}. + * + * @param e the element to push + * @since 1.6 + * + * @diffblue.fullSupport + */ + public void push(E e) { + addFirst(e); + } + + /** + * Pops an element from the stack represented by this list. In other + * words, removes and returns the first element of this list. + * + *

This method is equivalent to {@link #removeFirst()}. + * + * @return the element at the front of this list (which is the top + * of the stack represented by this list) + * @throws NoSuchElementException if this list is empty + * @since 1.6 + * + * @diffblue.fullSupport + * @diffblue.untested + * Untested since simply calls removeFirst() + */ + public E pop() { + return removeFirst(); + } + + /** + * Removes the first occurrence of the specified element in this + * list (when traversing the list from head to tail). If the list + * does not contain the element, it is unchanged. + * + * @param o element to be removed from this list, if present + * @return {@code true} if the list contained the specified element + * @since 1.6 + * + * @diffblue.limitedSupport + * @diffblue.untested + * Untested since simply calls remove() + * No traces generated for String lists containing null values + */ + public boolean removeFirstOccurrence(Object o) { + return remove(o); + } + + /** + * Removes the last occurrence of the specified element in this + * list (when traversing the list from head to tail). If the list + * does not contain the element, it is unchanged. + * + * @param o element to be removed from this list, if present + * @return {@code true} if the list contained the specified element + * @since 1.6 + * + * @diffblue.limitedSupport + * No traces generated for String lists containing null values + */ + public boolean removeLastOccurrence(Object o) { + // if (o == null) { + // for (Node x = last; x != null; x = x.prev) { + // if (x.item == null) { + // unlink(x); + // return true; + // } + // } + // } else { + // for (Node x = last; x != null; x = x.prev) { + // if (o.equals(x.item)) { + // unlink(x); + // return true; + // } + // } + // } + // return false; + int i = lastIndexOf(o); + if (i == -1) { + return false; + } + remove(i); + return true; + } + + /** + * Returns a list-iterator of the elements in this list (in proper + * sequence), starting at the specified position in the list. + * Obeys the general contract of {@code List.listIterator(int)}.

+ * + * The list-iterator is fail-fast: if the list is structurally + * modified at any time after the Iterator is created, in any way except + * through the list-iterator's own {@code remove} or {@code add} + * methods, the list-iterator will throw a + * {@code ConcurrentModificationException}. Thus, in the face of + * concurrent modification, the iterator fails quickly and cleanly, rather + * than risking arbitrary, non-deterministic behavior at an undetermined + * time in the future. + * + * @param index index of the first element to be returned from the + * list-iterator (by a call to {@code next}) + * @return a ListIterator of the elements in this list (in proper + * sequence), starting at the specified position in the list + * @throws IndexOutOfBoundsException {@inheritDoc} + * @see List#listIterator(int) + * + * @diffblue.limitedSupport + * Exception messages not supported and not all iterator methods modelled + */ + public ListIterator listIterator(int index) { + checkPositionIndex(index); + return new ListItr(index); + } + + private class ListItr implements ListIterator { + // private Node lastReturned; + // private Node next; + + // DIFFBLUE MODEL LIBRARY + // We store the elements directly instead of node objects + private E cproverLastReturned; + private E cproverNext; + private int cproverLastIndex; // index of last element returned + + private int nextIndex; + private int expectedModCount = modCount; + + ListItr(int index) { + // // assert isPositionIndex(index); + // next = (index == size) ? null : node(index); + // nextIndex = index; + cproverNext = (index == size) ? null : get(index); + nextIndex = index; + cproverLastIndex = -1; + } + + public boolean hasNext() { + return nextIndex < size; + } + + public E next() { + // checkForComodification(); + // if (!hasNext()) + // throw new NoSuchElementException(); + + // lastReturned = next; + // next = next.next; + // nextIndex++; + // return lastReturned.item; + checkForComodification(); + if (!hasNext()) + throw new NoSuchElementException(); + cproverLastReturned = cproverNext; + cproverLastIndex = nextIndex; + nextIndex++; + cproverNext = (nextIndex == size) ? null : get(nextIndex); + return cproverLastReturned; + } + + public boolean hasPrevious() { + return nextIndex > 0; + } + + public E previous() { + // checkForComodification(); + // if (!hasPrevious()) + // throw new NoSuchElementException(); + + // lastReturned = next = (next == null) ? last : next.prev; + // nextIndex--; + // return lastReturned.item; + checkForComodification(); + if (!hasPrevious()) + throw new NoSuchElementException(); + nextIndex--; + cproverLastIndex = nextIndex; + cproverNext = (nextIndex == size) ? getLast() : get(nextIndex); + cproverLastReturned = cproverNext; + return cproverLastReturned; + } + + public int nextIndex() { + return nextIndex; + } + + public int previousIndex() { + return nextIndex - 1; + } + + public void remove() { + // checkForComodification(); + // if (lastReturned == null) + // throw new IllegalStateException(); + + // Node lastNext = lastReturned.next; + // unlink(lastReturned); + // if (next == lastReturned) + // next = lastNext; + // else + // nextIndex--; + // lastReturned = null; + // expectedModCount++; + CProver.notModelled(); + } + + public void set(E e) { + // if (lastReturned == null) + // throw new IllegalStateException(); + // checkForComodification(); + // lastReturned.item = e; + if (cproverLastReturned == null) + throw new IllegalStateException(); + checkForComodification(); + LinkedList.this.set(cproverLastIndex, e); + } + + public void add(E e) { + // checkForComodification(); + // lastReturned = null; + // if (next == null) + // linkLast(e); + // else + // linkBefore(e, next); + // nextIndex++; + // expectedModCount++; + CProver.notModelled(); + } + + public void forEachRemaining(Consumer action) { + // Objects.requireNonNull(action); + // while (modCount == expectedModCount && nextIndex < size) { + // action.accept(next.item); + // lastReturned = next; + // next = next.next; + // nextIndex++; + // } + // checkForComodification(); + CProver.notModelled(); + } + + final void checkForComodification() { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + } + } + + // DIFFBLUE MODEL LIBRARY + // Private class used for the original implementation of LinkedList + // private static class Node { + // E item; + // Node next; + // Node prev; + + // Node(Node prev, E element, Node next) { + // this.item = element; + // this.next = next; + // this.prev = prev; + // } + // } + + /** + * @since 1.6 + * + * @diffblue.limitedSupport + * Descending iterator doesn't have remove() modelled + * Assertion error from multiple calls to next(), returns + * only the first element correctly + */ + public Iterator descendingIterator() { + return new DescendingIterator(); + } + + /** + * Adapter to provide descending iterators via ListItr.previous + */ + private class DescendingIterator implements Iterator { + private final ListItr itr = new ListItr(size()); + public boolean hasNext() { + return itr.hasPrevious(); + } + public E next() { + return itr.previous(); + } + public void remove() { + // itr.remove(); + CProver.notModelled(); + } + } + + // DIFFBLUE MODEL LIBRARY Private method + // @SuppressWarnings("unchecked") + // private LinkedList superClone() { + // try { + // return (LinkedList) super.clone(); + // } catch (CloneNotSupportedException e) { + // throw new InternalError(e); + // } + // } + + /** + * Returns a shallow copy of this {@code LinkedList}. (The elements + * themselves are not cloned.) + * + * @return a shallow copy of this {@code LinkedList} instance + * + * @diffblue.fullSupport + */ + public Object clone() { + // LinkedList clone = superClone(); + + // // Put clone into "virgin" state + // clone.first = clone.last = null; + // clone.size = 0; + // clone.modCount = 0; + + // // Initialize clone with our elements + // for (Node x = first; x != null; x = x.next) + // clone.add(x.item); + + // return clone; + LinkedList v = new LinkedList(); + CProver.assume(v.cproverData.length >= size); + for (int i = 0; i < size; i++) { + v.cproverData[i] = cproverData[i]; + } + v.modCount = 0; + v.size = size; + v.cproverFirstIndex = cproverFirstIndex; + return v; + } + + /** + * Returns an array containing all of the elements in this list + * in proper sequence (from first to last element). + * + *

The returned array will be "safe" in that no references to it are + * maintained by this list. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this list + * in proper sequence + * + * @diffblue.limitedSupport + * Arrays may not always be correctly generated + */ + public Object[] toArray() { + // Object[] result = new Object[size]; + // int i = 0; + // for (Node x = first; x != null; x = x.next) + // result[i++] = x.item; + // return result; + Object[] a = new Object[size]; + for (int i = 0; i < size; i++) { + a[i] = cproverData[cproverGetShiftedIndex(cproverFirstIndex, i)]; + } + return a; + } + + /** + * Returns an array containing all of the elements in this list in + * proper sequence (from first to last element); the runtime type of + * the returned array is that of the specified array. If the list fits + * in the specified array, it is returned therein. Otherwise, a new + * array is allocated with the runtime type of the specified array and + * the size of this list. + * + *

If the list fits in the specified array with room to spare (i.e., + * the array has more elements than the list), the element in the array + * immediately following the end of the list is set to {@code null}. + * (This is useful in determining the length of the list only if + * the caller knows that the list does not contain any null elements.) + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose {@code x} is a list known to contain only strings. + * The following code can be used to dump the list into a newly + * allocated array of {@code String}: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param a the array into which the elements of the list are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose. + * @return an array containing the elements of the list + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this list + * @throws NullPointerException if the specified array is null + * + * @diffblue.limitedSupport + * Arrays may not always be correctly generated + * + * DIFFBLUE MODEL LIBRARY + * This behaves like the real JDK method, except that an ArrayStoreException + * won't be raised if you pass in an array that can't store the actual + * elements held in this container. + */ + // @SuppressWarnings("unchecked") + // (the JDK implementation makes an unchecked cast from Array.newInstance; + // we use CPRover.createArrayWithType instead) + public T[] toArray(T[] a) { + // if (a.length < size) + // a = (T[])java.lang.reflect.Array.newInstance( + // a.getClass().getComponentType(), size); + // int i = 0; + // Object[] result = a; + // for (Node x = first; x != null; x = x.next) + // result[i++] = x.item; + + // if (a.length > size) + // a[size] = null; + + // return a; + if (a.length < size) { + // DIFFBLUE MODEL LIBRARY + // Object.getClass() is currently not modelled, so we need to use + // createArrayWithType to create a new array of the required type. + T[] newArray = CProver.createArrayWithType(size, a); + for (int i = 0; i < size; i++) { + newArray[i] = (T) cproverData[cproverGetShiftedIndex(cproverFirstIndex, i)]; + } + return newArray; + } + for (int i = 0; i < size; i++) { + a[i] = (T) cproverData[cproverGetShiftedIndex(cproverFirstIndex, i)]; + } + if (a.length > size) + a[size] = null; + return a; + } + + // DIFFBLUE MODEL LIBRARY Private field + // private static final long serialVersionUID = 876323262645176354L; + + /** + * Saves the state of this {@code LinkedList} instance to a stream + * (that is, serializes it). + * + * @serialData The size of the list (the number of elements it + * contains) is emitted (int), followed by all of its + * elements (each an Object) in the proper order. + */ + // DIFFBLUE MODEL LIBRARY Private method + // private void writeObject(java.io.ObjectOutputStream s) + // throws java.io.IOException { + // // Write out any hidden serialization magic + // s.defaultWriteObject(); + + // // Write out size + // s.writeInt(size); + + // // Write out all elements in the proper order. + // for (Node x = first; x != null; x = x.next) + // s.writeObject(x.item); + // } + + /** + * Reconstitutes this {@code LinkedList} instance from a stream + * (that is, deserializes it). + */ + // DIFFBLUE MODEL LIBRARY Private method + // @SuppressWarnings("unchecked") + // private void readObject(java.io.ObjectInputStream s) + // throws java.io.IOException, ClassNotFoundException { + // // Read in any hidden serialization magic + // s.defaultReadObject(); + + // // Read in size + // int size = s.readInt(); + + // // Read in all elements in the proper order. + // for (int i = 0; i < size; i++) + // linkLast((E)s.readObject()); + // } + + /** + * Creates a late-binding + * and fail-fast {@link Spliterator} over the elements in this + * list. + * + *

The {@code Spliterator} reports {@link Spliterator#SIZED} and + * {@link Spliterator#ORDERED}. Overriding implementations should document + * the reporting of additional characteristic values. + * + * @implNote + * The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED} + * and implements {@code trySplit} to permit limited parallelism.. + * + * @return a {@code Spliterator} over the elements in this list + * @since 1.8 + * + * @diffblue.noSupport + */ + @Override + public Spliterator spliterator() { + // return new LLSpliterator(this, -1, 0); + CProver.notModelled(); + return CProver.nondetWithoutNullForNotModelled(); + } + + /** A customized variant of Spliterators.IteratorSpliterator */ + // DIFFBLUE MODEL LIBRARY + // Package-private class required for the spliterator() method, which is not + // modelled yet. + // static final class LLSpliterator implements Spliterator { + // static final int BATCH_UNIT = 1 << 10; // batch array size increment + // static final int MAX_BATCH = 1 << 25; // max batch array size; + // final LinkedList list; // null OK unless traversed + // Node current; // current node; null until initialized + // int est; // size estimate; -1 until first needed + // int expectedModCount; // initialized when est set + // int batch; // batch size for splits + + // LLSpliterator(LinkedList list, int est, int expectedModCount) { + // this.list = list; + // this.est = est; + // this.expectedModCount = expectedModCount; + // } + + // final int getEst() { + // int s; // force initialization + // final LinkedList lst; + // if ((s = est) < 0) { + // if ((lst = list) == null) + // s = est = 0; + // else { + // expectedModCount = lst.modCount; + // current = lst.first; + // s = est = lst.size; + // } + // } + // return s; + // } + + // public long estimateSize() { return (long) getEst(); } + + // public Spliterator trySplit() { + // Node p; + // int s = getEst(); + // if (s > 1 && (p = current) != null) { + // int n = batch + BATCH_UNIT; + // if (n > s) + // n = s; + // if (n > MAX_BATCH) + // n = MAX_BATCH; + // Object[] a = new Object[n]; + // int j = 0; + // do { a[j++] = p.item; } while ((p = p.next) != null && j < n); + // current = p; + // batch = j; + // est = s - j; + // return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED); + // } + // return null; + // } + + // public void forEachRemaining(Consumer action) { + // Node p; int n; + // if (action == null) throw new NullPointerException(); + // if ((n = getEst()) > 0 && (p = current) != null) { + // current = null; + // est = 0; + // do { + // E e = p.item; + // p = p.next; + // action.accept(e); + // } while (p != null && --n > 0); + // } + // if (list.modCount != expectedModCount) + // throw new ConcurrentModificationException(); + // } + + // public boolean tryAdvance(Consumer action) { + // Node p; + // if (action == null) throw new NullPointerException(); + // if (getEst() > 0 && (p = current) != null) { + // --est; + // E e = p.item; + // current = p.next; + // action.accept(e); + // if (list.modCount != expectedModCount) + // throw new ConcurrentModificationException(); + // return true; + // } + // return false; + // } + + // public int characteristics() { + // return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; + // } + // } + + // DIFFBLUE MODEL LIBRARY + // The % operator returns the remainder of the division operation, which may + // be negative. This helper method returns i mod j (which is always in the + // range [0, j)). + private static int cproverPositiveModulo(int i, int j) { + return (i % j + j) % j; + } + + // DIFFBLUE MODEL LIBRARY + // Given a start index and a number of steps to move to the right (to the + // left if distance is negative), returns the index where we will end up, + // assuming that the two ends of the array are connected. + private int cproverGetShiftedIndex(int startIndex, int distance) { + return cproverPositiveModulo(startIndex + distance, cproverData.length); + } + + // DIFFBLUE MODEL LIBRARY + // Returns the index of the last element in the list. + private int cproverGetLastIndex() { + return cproverGetShiftedIndex(cproverFirstIndex, size - 1); + } + + // DIFFBLUE MODEL LIBRARY + // This method is called by CBMC just after nondeterministic object + // creation, i.e. the constraints that it specifies are only enforced at + // that time and do not have to hold globally. + // We generally want to make sure that all necessary invariants of the class + // are satisfied, and potentially restrict some fields to speed up test + // generation. + @org.cprover.MustNotThrow + protected void cproverNondetInitialize() { + CProver.assume(size >= 0); + CProver.assume(cproverData != null); + CProver.assume(cproverData.length >= size); + // Initial value chosen for the first element of the list. By setting + // this value to 0, we know that in custom initialisers, we can call the + // add method on the elements to be stored at indices 0, 1, 2, ... + // size - 1. + CProver.assume(cproverFirstIndex == 0); + // Nondeterministic LinkedLists are created using a + // call to the + // public LinkedList() + // constructor, followed by a sequence of calls to add, where the number + // of such calls is equal to size. + // Each call to add increments the modCount variable by 1. + CProver.assume(modCount == size); + } + +} diff --git a/src/main/java/java/util/List.java b/src/main/java/java/util/List.java new file mode 100644 index 0000000..80fe4be --- /dev/null +++ b/src/main/java/java/util/List.java @@ -0,0 +1,734 @@ +/* + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.util.function.UnaryOperator; + +/** + * An ordered collection (also known as a sequence). The user of this + * interface has precise control over where in the list each element is + * inserted. The user can access elements by their integer index (position in + * the list), and search for elements in the list.

+ * + * Unlike sets, lists typically allow duplicate elements. More formally, + * lists typically allow pairs of elements e1 and e2 + * such that e1.equals(e2), and they typically allow multiple + * null elements if they allow null elements at all. It is not inconceivable + * that someone might wish to implement a list that prohibits duplicates, by + * throwing runtime exceptions when the user attempts to insert them, but we + * expect this usage to be rare.

+ * + * The List interface places additional stipulations, beyond those + * specified in the Collection interface, on the contracts of the + * iterator, add, remove, equals, and + * hashCode methods. Declarations for other inherited methods are + * also included here for convenience.

+ * + * The List interface provides four methods for positional (indexed) + * access to list elements. Lists (like Java arrays) are zero based. Note + * that these operations may execute in time proportional to the index value + * for some implementations (the LinkedList class, for + * example). Thus, iterating over the elements in a list is typically + * preferable to indexing through it if the caller does not know the + * implementation.

+ * + * The List interface provides a special iterator, called a + * ListIterator, that allows element insertion and replacement, and + * bidirectional access in addition to the normal operations that the + * Iterator interface provides. A method is provided to obtain a + * list iterator that starts at a specified position in the list.

+ * + * The List interface provides two methods to search for a specified + * object. From a performance standpoint, these methods should be used with + * caution. In many implementations they will perform costly linear + * searches.

+ * + * The List interface provides two methods to efficiently insert and + * remove multiple elements at an arbitrary point in the list.

+ * + * Note: While it is permissible for lists to contain themselves as elements, + * extreme caution is advised: the equals and hashCode + * methods are no longer well defined on such a list. + * + *

Some list implementations have restrictions on the elements that + * they may contain. For example, some implementations prohibit null elements, + * and some have restrictions on the types of their elements. Attempting to + * add an ineligible element throws an unchecked exception, typically + * NullPointerException or ClassCastException. Attempting + * to query the presence of an ineligible element may throw an exception, + * or it may simply return false; some implementations will exhibit the former + * behavior and some will exhibit the latter. More generally, attempting an + * operation on an ineligible element whose completion would not result in + * the insertion of an ineligible element into the list may throw an + * exception or it may succeed, at the option of the implementation. + * Such exceptions are marked as "optional" in the specification for this + * interface. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @param the type of elements in this list + * + * @author Josh Bloch + * @author Neal Gafter + * @see Collection + * @see Set + * @see ArrayList + * @see LinkedList + * @see Vector + * @see Arrays#asList(Object[]) + * @see Collections#nCopies(int, Object) + * @see Collections#EMPTY_LIST + * @see AbstractList + * @see AbstractSequentialList + * @since 1.2 + */ + +public interface List extends Collection { + // Query Operations + + /** + * Returns the number of elements in this list. If this list contains + * more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this list + */ + int size(); + + /** + * Returns true if this list contains no elements. + * + * @return true if this list contains no elements + */ + boolean isEmpty(); + + /** + * Returns true if this list contains the specified element. + * More formally, returns true if and only if this list contains + * at least one element e such that + * (o==null ? e==null : o.equals(e)). + * + * @param o element whose presence in this list is to be tested + * @return true if this list contains the specified element + * @throws ClassCastException if the type of the specified element + * is incompatible with this list + * (optional) + * @throws NullPointerException if the specified element is null and this + * list does not permit null elements + * (optional) + */ + boolean contains(Object o); + + /** + * Returns an iterator over the elements in this list in proper sequence. + * + * @return an iterator over the elements in this list in proper sequence + */ + Iterator iterator(); + + /** + * Returns an array containing all of the elements in this list in proper + * sequence (from first to last element). + * + *

The returned array will be "safe" in that no references to it are + * maintained by this list. (In other words, this method must + * allocate a new array even if this list is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this list in proper + * sequence + * @see Arrays#asList(Object[]) + */ + Object[] toArray(); + + /** + * Returns an array containing all of the elements in this list in + * proper sequence (from first to last element); the runtime type of + * the returned array is that of the specified array. If the list fits + * in the specified array, it is returned therein. Otherwise, a new + * array is allocated with the runtime type of the specified array and + * the size of this list. + * + *

If the list fits in the specified array with room to spare (i.e., + * the array has more elements than the list), the element in the array + * immediately following the end of the list is set to null. + * (This is useful in determining the length of the list only if + * the caller knows that the list does not contain any null elements.) + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose x is a list known to contain only strings. + * The following code can be used to dump the list into a newly + * allocated array of String: + * + *

{@code
+     *     String[] y = x.toArray(new String[0]);
+     * }
+ * + * Note that toArray(new Object[0]) is identical in function to + * toArray(). + * + * @param a the array into which the elements of this list are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose. + * @return an array containing the elements of this list + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this list + * @throws NullPointerException if the specified array is null + */ + T[] toArray(T[] a); + + + // Modification Operations + + /** + * Appends the specified element to the end of this list (optional + * operation). + * + *

Lists that support this operation may place limitations on what + * elements may be added to this list. In particular, some + * lists will refuse to add null elements, and others will impose + * restrictions on the type of elements that may be added. List + * classes should clearly specify in their documentation any restrictions + * on what elements may be added. + * + * @param e element to be appended to this list + * @return true (as specified by {@link Collection#add}) + * @throws UnsupportedOperationException if the add operation + * is not supported by this list + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this list + * @throws NullPointerException if the specified element is null and this + * list does not permit null elements + * @throws IllegalArgumentException if some property of this element + * prevents it from being added to this list + */ + boolean add(E e); + + /** + * Removes the first occurrence of the specified element from this list, + * if it is present (optional operation). If this list does not contain + * the element, it is unchanged. More formally, removes the element with + * the lowest index i such that + * (o==null ? get(i)==null : o.equals(get(i))) + * (if such an element exists). Returns true if this list + * contained the specified element (or equivalently, if this list changed + * as a result of the call). + * + * @param o element to be removed from this list, if present + * @return true if this list contained the specified element + * @throws ClassCastException if the type of the specified element + * is incompatible with this list + * (optional) + * @throws NullPointerException if the specified element is null and this + * list does not permit null elements + * (optional) + * @throws UnsupportedOperationException if the remove operation + * is not supported by this list + */ + boolean remove(Object o); + + + // Bulk Modification Operations + + /** + * Returns true if this list contains all of the elements of the + * specified collection. + * + * @param c collection to be checked for containment in this list + * @return true if this list contains all of the elements of the + * specified collection + * @throws ClassCastException if the types of one or more elements + * in the specified collection are incompatible with this + * list + * (optional) + * @throws NullPointerException if the specified collection contains one + * or more null elements and this list does not permit null + * elements + * (optional), + * or if the specified collection is null + * @see #contains(Object) + */ + boolean containsAll(Collection c); + + /** + * Appends all of the elements in the specified collection to the end of + * this list, in the order that they are returned by the specified + * collection's iterator (optional operation). The behavior of this + * operation is undefined if the specified collection is modified while + * the operation is in progress. (Note that this will occur if the + * specified collection is this list, and it's nonempty.) + * + * @param c collection containing elements to be added to this list + * @return true if this list changed as a result of the call + * @throws UnsupportedOperationException if the addAll operation + * is not supported by this list + * @throws ClassCastException if the class of an element of the specified + * collection prevents it from being added to this list + * @throws NullPointerException if the specified collection contains one + * or more null elements and this list does not permit null + * elements, or if the specified collection is null + * @throws IllegalArgumentException if some property of an element of the + * specified collection prevents it from being added to this list + * @see #add(Object) + */ + boolean addAll(Collection c); + + /** + * Inserts all of the elements in the specified collection into this + * list at the specified position (optional operation). Shifts the + * element currently at that position (if any) and any subsequent + * elements to the right (increases their indices). The new elements + * will appear in this list in the order that they are returned by the + * specified collection's iterator. The behavior of this operation is + * undefined if the specified collection is modified while the + * operation is in progress. (Note that this will occur if the specified + * collection is this list, and it's nonempty.) + * + * @param index index at which to insert the first element from the + * specified collection + * @param c collection containing elements to be added to this list + * @return true if this list changed as a result of the call + * @throws UnsupportedOperationException if the addAll operation + * is not supported by this list + * @throws ClassCastException if the class of an element of the specified + * collection prevents it from being added to this list + * @throws NullPointerException if the specified collection contains one + * or more null elements and this list does not permit null + * elements, or if the specified collection is null + * @throws IllegalArgumentException if some property of an element of the + * specified collection prevents it from being added to this list + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index > size()) + */ + boolean addAll(int index, Collection c); + + /** + * Removes from this list all of its elements that are contained in the + * specified collection (optional operation). + * + * @param c collection containing elements to be removed from this list + * @return true if this list changed as a result of the call + * @throws UnsupportedOperationException if the removeAll operation + * is not supported by this list + * @throws ClassCastException if the class of an element of this list + * is incompatible with the specified collection + * (optional) + * @throws NullPointerException if this list contains a null element and the + * specified collection does not permit null elements + * (optional), + * or if the specified collection is null + * @see #remove(Object) + * @see #contains(Object) + */ + boolean removeAll(Collection c); + + /** + * Retains only the elements in this list that are contained in the + * specified collection (optional operation). In other words, removes + * from this list all of its elements that are not contained in the + * specified collection. + * + * @param c collection containing elements to be retained in this list + * @return true if this list changed as a result of the call + * @throws UnsupportedOperationException if the retainAll operation + * is not supported by this list + * @throws ClassCastException if the class of an element of this list + * is incompatible with the specified collection + * (optional) + * @throws NullPointerException if this list contains a null element and the + * specified collection does not permit null elements + * (optional), + * or if the specified collection is null + * @see #remove(Object) + * @see #contains(Object) + */ + boolean retainAll(Collection c); + + /** + * Replaces each element of this list with the result of applying the + * operator to that element. Errors or runtime exceptions thrown by + * the operator are relayed to the caller. + * + * @implSpec + * The default implementation is equivalent to, for this {@code list}: + *

{@code
+     *     final ListIterator li = list.listIterator();
+     *     while (li.hasNext()) {
+     *         li.set(operator.apply(li.next()));
+     *     }
+     * }
+ * + * If the list's list-iterator does not support the {@code set} operation + * then an {@code UnsupportedOperationException} will be thrown when + * replacing the first element. + * + * @param operator the operator to apply to each element + * @throws UnsupportedOperationException if this list is unmodifiable. + * Implementations may throw this exception if an element + * cannot be replaced or if, in general, modification is not + * supported + * @throws NullPointerException if the specified operator is null or + * if the operator result is a null value and this list does + * not permit null elements + * (optional) + * @since 1.8 + */ + default void replaceAll(UnaryOperator operator) { + Objects.requireNonNull(operator); + final ListIterator li = this.listIterator(); + while (li.hasNext()) { + li.set(operator.apply(li.next())); + } + } + + /** + * Sorts this list according to the order induced by the specified + * {@link Comparator}. + * + *

All elements in this list must be mutually comparable using the + * specified comparator (that is, {@code c.compare(e1, e2)} must not throw + * a {@code ClassCastException} for any elements {@code e1} and {@code e2} + * in the list). + * + *

If the specified comparator is {@code null} then all elements in this + * list must implement the {@link Comparable} interface and the elements' + * {@linkplain Comparable natural ordering} should be used. + * + *

This list must be modifiable, but need not be resizable. + * + * @implSpec + * The default implementation obtains an array containing all elements in + * this list, sorts the array, and iterates over this list resetting each + * element from the corresponding position in the array. (This avoids the + * n2 log(n) performance that would result from attempting + * to sort a linked list in place.) + * + * @implNote + * This implementation is a stable, adaptive, iterative mergesort that + * requires far fewer than n lg(n) comparisons when the input array is + * partially sorted, while offering the performance of a traditional + * mergesort when the input array is randomly ordered. If the input array + * is nearly sorted, the implementation requires approximately n + * comparisons. Temporary storage requirements vary from a small constant + * for nearly sorted input arrays to n/2 object references for randomly + * ordered input arrays. + * + *

The implementation takes equal advantage of ascending and + * descending order in its input array, and can take advantage of + * ascending and descending order in different parts of the same + * input array. It is well-suited to merging two or more sorted arrays: + * simply concatenate the arrays and sort the resulting array. + * + *

The implementation was adapted from Tim Peters's list sort for Python + * ( + * TimSort). It uses techniques from Peter McIlroy's "Optimistic + * Sorting and Information Theoretic Complexity", in Proceedings of the + * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, + * January 1993. + * + * @param c the {@code Comparator} used to compare list elements. + * A {@code null} value indicates that the elements' + * {@linkplain Comparable natural ordering} should be used + * @throws ClassCastException if the list contains elements that are not + * mutually comparable using the specified comparator + * @throws UnsupportedOperationException if the list's list-iterator does + * not support the {@code set} operation + * @throws IllegalArgumentException + * (optional) + * if the comparator is found to violate the {@link Comparator} + * contract + * @since 1.8 + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + default void sort(Comparator c) { + Object[] a = this.toArray(); + Arrays.sort(a, (Comparator) c); + ListIterator i = this.listIterator(); + for (Object e : a) { + i.next(); + i.set((E) e); + } + } + + /** + * Removes all of the elements from this list (optional operation). + * The list will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this list + */ + void clear(); + + + // Comparison and hashing + + /** + * Compares the specified object with this list for equality. Returns + * true if and only if the specified object is also a list, both + * lists have the same size, and all corresponding pairs of elements in + * the two lists are equal. (Two elements e1 and + * e2 are equal if (e1==null ? e2==null : + * e1.equals(e2)).) In other words, two lists are defined to be + * equal if they contain the same elements in the same order. This + * definition ensures that the equals method works properly across + * different implementations of the List interface. + * + * @param o the object to be compared for equality with this list + * @return true if the specified object is equal to this list + */ + boolean equals(Object o); + + /** + * Returns the hash code value for this list. The hash code of a list + * is defined to be the result of the following calculation: + *

{@code
+     *     int hashCode = 1;
+     *     for (E e : list)
+     *         hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
+     * }
+ * This ensures that list1.equals(list2) implies that + * list1.hashCode()==list2.hashCode() for any two lists, + * list1 and list2, as required by the general + * contract of {@link Object#hashCode}. + * + * @return the hash code value for this list + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); + + + // Positional Access Operations + + /** + * Returns the element at the specified position in this list. + * + * @param index index of the element to return + * @return the element at the specified position in this list + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + E get(int index); + + /** + * Replaces the element at the specified position in this list with the + * specified element (optional operation). + * + * @param index index of the element to replace + * @param element element to be stored at the specified position + * @return the element previously at the specified position + * @throws UnsupportedOperationException if the set operation + * is not supported by this list + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this list + * @throws NullPointerException if the specified element is null and + * this list does not permit null elements + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this list + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + E set(int index, E element); + + /** + * Inserts the specified element at the specified position in this list + * (optional operation). Shifts the element currently at that position + * (if any) and any subsequent elements to the right (adds one to their + * indices). + * + * @param index index at which the specified element is to be inserted + * @param element element to be inserted + * @throws UnsupportedOperationException if the add operation + * is not supported by this list + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this list + * @throws NullPointerException if the specified element is null and + * this list does not permit null elements + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this list + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index > size()) + */ + void add(int index, E element); + + /** + * Removes the element at the specified position in this list (optional + * operation). Shifts any subsequent elements to the left (subtracts one + * from their indices). Returns the element that was removed from the + * list. + * + * @param index the index of the element to be removed + * @return the element previously at the specified position + * @throws UnsupportedOperationException if the remove operation + * is not supported by this list + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= size()) + */ + E remove(int index); + + + // Search Operations + + /** + * Returns the index of the first occurrence of the specified element + * in this list, or -1 if this list does not contain the element. + * More formally, returns the lowest index i such that + * (o==null ? get(i)==null : o.equals(get(i))), + * or -1 if there is no such index. + * + * @param o element to search for + * @return the index of the first occurrence of the specified element in + * this list, or -1 if this list does not contain the element + * @throws ClassCastException if the type of the specified element + * is incompatible with this list + * (optional) + * @throws NullPointerException if the specified element is null and this + * list does not permit null elements + * (optional) + */ + int indexOf(Object o); + + /** + * Returns the index of the last occurrence of the specified element + * in this list, or -1 if this list does not contain the element. + * More formally, returns the highest index i such that + * (o==null ? get(i)==null : o.equals(get(i))), + * or -1 if there is no such index. + * + * @param o element to search for + * @return the index of the last occurrence of the specified element in + * this list, or -1 if this list does not contain the element + * @throws ClassCastException if the type of the specified element + * is incompatible with this list + * (optional) + * @throws NullPointerException if the specified element is null and this + * list does not permit null elements + * (optional) + */ + int lastIndexOf(Object o); + + + // List Iterators + + /** + * Returns a list iterator over the elements in this list (in proper + * sequence). + * + * @return a list iterator over the elements in this list (in proper + * sequence) + */ + ListIterator listIterator(); + + /** + * Returns a list iterator over the elements in this list (in proper + * sequence), starting at the specified position in the list. + * The specified index indicates the first element that would be + * returned by an initial call to {@link ListIterator#next next}. + * An initial call to {@link ListIterator#previous previous} would + * return the element with the specified index minus one. + * + * @param index index of the first element to be returned from the + * list iterator (by a call to {@link ListIterator#next next}) + * @return a list iterator over the elements in this list (in proper + * sequence), starting at the specified position in the list + * @throws IndexOutOfBoundsException if the index is out of range + * ({@code index < 0 || index > size()}) + */ + ListIterator listIterator(int index); + + // View + + /** + * Returns a view of the portion of this list between the specified + * fromIndex, inclusive, and toIndex, exclusive. (If + * fromIndex and toIndex are equal, the returned list is + * empty.) The returned list is backed by this list, so non-structural + * changes in the returned list are reflected in this list, and vice-versa. + * The returned list supports all of the optional list operations supported + * by this list.

+ * + * This method eliminates the need for explicit range operations (of + * the sort that commonly exist for arrays). Any operation that expects + * a list can be used as a range operation by passing a subList view + * instead of a whole list. For example, the following idiom + * removes a range of elements from a list: + *

{@code
+     *      list.subList(from, to).clear();
+     * }
+ * Similar idioms may be constructed for indexOf and + * lastIndexOf, and all of the algorithms in the + * Collections class can be applied to a subList.

+ * + * The semantics of the list returned by this method become undefined if + * the backing list (i.e., this list) is structurally modified in + * any way other than via the returned list. (Structural modifications are + * those that change the size of this list, or otherwise perturb it in such + * a fashion that iterations in progress may yield incorrect results.) + * + * @param fromIndex low endpoint (inclusive) of the subList + * @param toIndex high endpoint (exclusive) of the subList + * @return a view of the specified range within this list + * @throws IndexOutOfBoundsException for an illegal endpoint index value + * (fromIndex < 0 || toIndex > size || + * fromIndex > toIndex) + */ + List subList(int fromIndex, int toIndex); + + /** + * Creates a {@link Spliterator} over the elements in this list. + * + *

The {@code Spliterator} reports {@link Spliterator#SIZED} and + * {@link Spliterator#ORDERED}. Implementations should document the + * reporting of additional characteristic values. + * + * @implSpec + * The default implementation creates a + * late-binding spliterator + * from the list's {@code Iterator}. The spliterator inherits the + * fail-fast properties of the list's iterator. + * + * @implNote + * The created {@code Spliterator} additionally reports + * {@link Spliterator#SUBSIZED}. + * + * @return a {@code Spliterator} over the elements in this list + * @since 1.8 + */ + @Override + default Spliterator spliterator() { + return Spliterators.spliterator(this, Spliterator.ORDERED); + } +} diff --git a/src/main/java/java/util/Map.java b/src/main/java/java/util/Map.java new file mode 100644 index 0000000..844e9de --- /dev/null +++ b/src/main/java/java/util/Map.java @@ -0,0 +1,1185 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.io.Serializable; + +import org.cprover.CProver; + +/** + * An object that maps keys to values. A map cannot contain duplicate keys; + * each key can map to at most one value. + * + *

This interface takes the place of the Dictionary class, which + * was a totally abstract class rather than an interface. + * + *

The Map interface provides three collection views, which + * allow a map's contents to be viewed as a set of keys, collection of values, + * or set of key-value mappings. The order of a map is defined as + * the order in which the iterators on the map's collection views return their + * elements. Some map implementations, like the TreeMap class, make + * specific guarantees as to their order; others, like the HashMap + * class, do not. + * + *

Note: great care must be exercised if mutable objects are used as map + * keys. The behavior of a map is not specified if the value of an object is + * changed in a manner that affects equals comparisons while the + * object is a key in the map. A special case of this prohibition is that it + * is not permissible for a map to contain itself as a key. While it is + * permissible for a map to contain itself as a value, extreme caution is + * advised: the equals and hashCode methods are no longer + * well defined on such a map. + * + *

All general-purpose map implementation classes should provide two + * "standard" constructors: a void (no arguments) constructor which creates an + * empty map, and a constructor with a single argument of type Map, + * which creates a new map with the same key-value mappings as its argument. + * In effect, the latter constructor allows the user to copy any map, + * producing an equivalent map of the desired class. There is no way to + * enforce this recommendation (as interfaces cannot contain constructors) but + * all of the general-purpose map implementations in the JDK comply. + * + *

The "destructive" methods contained in this interface, that is, the + * methods that modify the map on which they operate, are specified to throw + * UnsupportedOperationException if this map does not support the + * operation. If this is the case, these methods may, but are not required + * to, throw an UnsupportedOperationException if the invocation would + * have no effect on the map. For example, invoking the {@link #putAll(Map)} + * method on an unmodifiable map may, but is not required to, throw the + * exception if the map whose mappings are to be "superimposed" is empty. + * + *

Some map implementations have restrictions on the keys and values they + * may contain. For example, some implementations prohibit null keys and + * values, and some have restrictions on the types of their keys. Attempting + * to insert an ineligible key or value throws an unchecked exception, + * typically NullPointerException or ClassCastException. + * Attempting to query the presence of an ineligible key or value may throw an + * exception, or it may simply return false; some implementations will exhibit + * the former behavior and some will exhibit the latter. More generally, + * attempting an operation on an ineligible key or value whose completion + * would not result in the insertion of an ineligible element into the map may + * throw an exception or it may succeed, at the option of the implementation. + * Such exceptions are marked as "optional" in the specification for this + * interface. + * + *

Many methods in Collections Framework interfaces are defined + * in terms of the {@link Object#equals(Object) equals} method. For + * example, the specification for the {@link #containsKey(Object) + * containsKey(Object key)} method says: "returns true if and + * only if this map contains a mapping for a key k such that + * (key==null ? k==null : key.equals(k))." This specification should + * not be construed to imply that invoking Map.containsKey + * with a non-null argument key will cause key.equals(k) to + * be invoked for any key k. Implementations are free to + * implement optimizations whereby the equals invocation is avoided, + * for example, by first comparing the hash codes of the two keys. (The + * {@link Object#hashCode()} specification guarantees that two objects with + * unequal hash codes cannot be equal.) More generally, implementations of + * the various Collections Framework interfaces are free to take advantage of + * the specified behavior of underlying {@link Object} methods wherever the + * implementor deems it appropriate. + * + *

Some map operations which perform recursive traversal of the map may fail + * with an exception for self-referential instances where the map directly or + * indirectly contains itself. This includes the {@code clone()}, + * {@code equals()}, {@code hashCode()} and {@code toString()} methods. + * Implementations may optionally handle the self-referential scenario, however + * most current implementations do not do so. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @param the type of keys maintained by this map + * @param the type of mapped values + * + * @author Josh Bloch + * @see HashMap + * @see TreeMap + * @see Hashtable + * @see SortedMap + * @see Collection + * @see Set + * @since 1.2 + */ +public interface Map { + // Query Operations + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * (key==null ? k==null : key.equals(k)). (There can be + * at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map + * (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys + * (optional) + */ + boolean containsKey(Object key); + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==null ? v==null : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + * + * @param value value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map + * (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values + * (optional) + */ + boolean containsValue(Object value); + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + *

More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code (key==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then a return value of + * {@code null} does not necessarily indicate that the map + * contains no mapping for the key; it's also possible that the map + * explicitly maps the key to {@code null}. The {@link #containsKey + * containsKey} operation may be used to distinguish these two cases. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map + * (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys + * (optional) + */ + V get(Object key); + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(Object) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with key, or + * null if there was no mapping for key. + * (A null return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + */ + V put(K key, V value); + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * (key==null ? k==null : key.equals(k)), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map + * (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys + * (optional) + */ + V remove(Object key); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(Object,Object) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by this map + * @throws ClassCastException if the class of a key or value in the + * specified map prevents it from being stored in this map + * @throws NullPointerException if the specified map is null, or if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll(Map m); + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. If the map is modified + * while an iteration over the set is in progress (except through + * the iterator's own remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + Set keySet(); + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. If the map is + * modified while an iteration over the collection is in progress + * (except through the iterator's own remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Collection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + Collection values(); + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. If the map is modified + * while an iteration over the set is in progress (except through + * the iterator's own remove operation, or through the + * setValue operation on a map entry returned by the + * iterator) the results of the iteration are undefined. The set + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Set.remove, removeAll, retainAll and + * clear operations. It does not support the + * add or addAll operations. + * + * @return a set view of the mappings contained in this map + */ + Set> entrySet(); + + /** + * A map entry (key-value pair). The Map.entrySet method returns + * a collection-view of the map, whose elements are of this class. The + * only way to obtain a reference to a map entry is from the + * iterator of this collection-view. These Map.Entry objects are + * valid only for the duration of the iteration; more formally, + * the behavior of a map entry is undefined if the backing map has been + * modified after the entry was returned by the iterator, except through + * the setValue operation on the map entry. + * + * @see Map#entrySet() + * @since 1.2 + */ + interface Entry { + /** + * Returns the key corresponding to this entry. + * + * @return the key corresponding to this entry + * @throws IllegalStateException implementations may, but are not + * required to, throw this exception if the entry has been + * removed from the backing map. + */ + K getKey(); + + /** + * Returns the value corresponding to this entry. If the mapping + * has been removed from the backing map (by the iterator's + * remove operation), the results of this call are undefined. + * + * @return the value corresponding to this entry + * @throws IllegalStateException implementations may, but are not + * required to, throw this exception if the entry has been + * removed from the backing map. + */ + V getValue(); + + /** + * Replaces the value corresponding to this entry with the specified + * value (optional operation). (Writes through to the map.) The + * behavior of this call is undefined if the mapping has already been + * removed from the map (by the iterator's remove operation). + * + * @param value new value to be stored in this entry + * @return old value corresponding to the entry + * @throws UnsupportedOperationException if the put operation + * is not supported by the backing map + * @throws ClassCastException if the class of the specified value + * prevents it from being stored in the backing map + * @throws NullPointerException if the backing map does not permit + * null values, and the specified value is null + * @throws IllegalArgumentException if some property of this value + * prevents it from being stored in the backing map + * @throws IllegalStateException implementations may, but are not + * required to, throw this exception if the entry has been + * removed from the backing map. + */ + V setValue(V value); + + /** + * Compares the specified object with this entry for equality. + * Returns true if the given object is also a map entry and + * the two entries represent the same mapping. More formally, two + * entries e1 and e2 represent the same mapping + * if

+         *     (e1.getKey()==null ?
+         *      e2.getKey()==null : e1.getKey().equals(e2.getKey()))  &&
+         *     (e1.getValue()==null ?
+         *      e2.getValue()==null : e1.getValue().equals(e2.getValue()))
+         * 
+ * This ensures that the equals method works properly across + * different implementations of the Map.Entry interface. + * + * @param o object to be compared for equality with this map entry + * @return true if the specified object is equal to this map + * entry + */ + boolean equals(Object o); + + /** + * Returns the hash code value for this map entry. The hash code + * of a map entry e is defined to be:
+         *     (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *     (e.getValue()==null ? 0 : e.getValue().hashCode())
+         * 
+ * This ensures that e1.equals(e2) implies that + * e1.hashCode()==e2.hashCode() for any two Entries + * e1 and e2, as required by the general + * contract of Object.hashCode. + * + * @return the hash code value for this map entry + * @see Object#hashCode() + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); + + /** + * Returns a comparator that compares {@link Map.Entry} in natural order on key. + * + *

The returned comparator is serializable and throws {@link + * NullPointerException} when comparing an entry with a null key. + * + * @param the {@link Comparable} type of then map keys + * @param the type of the map values + * @return a comparator that compares {@link Map.Entry} in natural order on key. + * @see Comparable + * @since 1.8 + */ + public static , V> Comparator> comparingByKey() { + return (Comparator> & Serializable) + (c1, c2) -> c1.getKey().compareTo(c2.getKey()); + } + + /** + * Returns a comparator that compares {@link Map.Entry} in natural order on value. + * + *

The returned comparator is serializable and throws {@link + * NullPointerException} when comparing an entry with null values. + * + * @param the type of the map keys + * @param the {@link Comparable} type of the map values + * @return a comparator that compares {@link Map.Entry} in natural order on value. + * @see Comparable + * @since 1.8 + */ + public static > Comparator> comparingByValue() { + return (Comparator> & Serializable) + (c1, c2) -> c1.getValue().compareTo(c2.getValue()); + } + + /** + * Returns a comparator that compares {@link Map.Entry} by key using the given + * {@link Comparator}. + * + *

The returned comparator is serializable if the specified comparator + * is also serializable. + * + * @param the type of the map keys + * @param the type of the map values + * @param cmp the key {@link Comparator} + * @return a comparator that compares {@link Map.Entry} by the key. + * @since 1.8 + */ + public static Comparator> comparingByKey(Comparator cmp) { + Objects.requireNonNull(cmp); + return (Comparator> & Serializable) + (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey()); + } + + /** + * Returns a comparator that compares {@link Map.Entry} by value using the given + * {@link Comparator}. + * + *

The returned comparator is serializable if the specified comparator + * is also serializable. + * + * @param the type of the map keys + * @param the type of the map values + * @param cmp the value {@link Comparator} + * @return a comparator that compares {@link Map.Entry} by the value. + * @since 1.8 + */ + public static Comparator> comparingByValue(Comparator cmp) { + Objects.requireNonNull(cmp); + return (Comparator> & Serializable) + (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue()); + } + } + + // Comparison and hashing + + /** + * Compares the specified object with this map for equality. Returns + * true if the given object is also a map and the two maps + * represent the same mappings. More formally, two maps m1 and + * m2 represent the same mappings if + * m1.entrySet().equals(m2.entrySet()). This ensures that the + * equals method works properly across different implementations + * of the Map interface. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals(Object o); + + /** + * Returns the hash code value for this map. The hash code of a map is + * defined to be the sum of the hash codes of each entry in the map's + * entrySet() view. This ensures that m1.equals(m2) + * implies that m1.hashCode()==m2.hashCode() for any two maps + * m1 and m2, as required by the general contract of + * {@link Object#hashCode}. + * + * @return the hash code value for this map + * @see Map.Entry#hashCode() + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); + + // Defaultable methods + + /** + * Returns the value to which the specified key is mapped, or + * {@code defaultValue} if this map contains no mapping for the key. + * + * @implSpec + * The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @param key the key whose associated value is to be returned + * @param defaultValue the default mapping of the key + * @return the value to which the specified key is mapped, or + * {@code defaultValue} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map + * (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys + * (optional) + * @since 1.8 + */ + default V getOrDefault(Object key, V defaultValue) { + V v; + return (((v = get(key)) != null) || containsKey(key)) + ? v + : defaultValue; + } + + /** + * Performs the given action for each entry in this map until all entries + * have been processed or the action throws an exception. Unless + * otherwise specified by the implementing class, actions are performed in + * the order of entry set iteration (if an iteration order is specified.) + * Exceptions thrown by the action are relayed to the caller. + * + * @implSpec + * The default implementation is equivalent to, for this {@code map}: + *

 {@code
+     * for (Map.Entry entry : map.entrySet())
+     *     action.accept(entry.getKey(), entry.getValue());
+     * }
+ * + * The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @param action The action to be performed for each entry + * @throws NullPointerException if the specified action is null + * @throws ConcurrentModificationException if an entry is found to be + * removed during iteration + * @since 1.8 + */ + default void forEach(BiConsumer action) { + Objects.requireNonNull(action); + for (Map.Entry entry : entrySet()) { + K k; + V v; + try { + k = entry.getKey(); + v = entry.getValue(); + } catch(IllegalStateException ise) { + // this usually means the entry is no longer in the map. + throw new ConcurrentModificationException(ise); + } + action.accept(k, v); + } + } + + /** + * Replaces each entry's value with the result of invoking the given + * function on that entry until all entries have been processed or the + * function throws an exception. Exceptions thrown by the function are + * relayed to the caller. + * + * @implSpec + *

The default implementation is equivalent to, for this {@code map}: + *

 {@code
+     * for (Map.Entry entry : map.entrySet())
+     *     entry.setValue(function.apply(entry.getKey(), entry.getValue()));
+     * }
+ * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @param function the function to apply to each entry + * @throws UnsupportedOperationException if the {@code set} operation + * is not supported by this map's entry set iterator. + * @throws ClassCastException if the class of a replacement value + * prevents it from being stored in this map + * @throws NullPointerException if the specified function is null, or the + * specified replacement value is null, and this map does not permit null + * values + * @throws ClassCastException if a replacement value is of an inappropriate + * type for this map + * (optional) + * @throws NullPointerException if function or a replacement value is null, + * and this map does not permit null keys or values + * (optional) + * @throws IllegalArgumentException if some property of a replacement value + * prevents it from being stored in this map + * (optional) + * @throws ConcurrentModificationException if an entry is found to be + * removed during iteration + * @since 1.8 + */ + default void replaceAll(BiFunction function) { + Objects.requireNonNull(function); + for (Map.Entry entry : entrySet()) { + K k; + V v; + try { + k = entry.getKey(); + v = entry.getValue(); + } catch(IllegalStateException ise) { + // this usually means the entry is no longer in the map. + throw new ConcurrentModificationException(ise); + } + + // ise thrown from function is not a cme. + v = function.apply(k, v); + + try { + entry.setValue(v); + } catch(IllegalStateException ise) { + // this usually means the entry is no longer in the map. + throw new ConcurrentModificationException(ise); + } + } + } + + /** + * If the specified key is not already associated with a value (or is mapped + * to {@code null}) associates it with the given value and returns + * {@code null}, else returns the current value. + * + * @implSpec + * The default implementation is equivalent to, for this {@code + * map}: + * + *

 {@code
+     * V v = map.get(key);
+     * if (v == null)
+     *     v = map.put(key, value);
+     *
+     * return v;
+     * }
+ * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key, or + * {@code null} if there was no mapping for the key. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with the key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the key or value is of an inappropriate + * type for this map + * (optional) + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values + * (optional) + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * (optional) + * @since 1.8 + */ + default V putIfAbsent(K key, V value) { + V v = get(key); + if (v == null) { + v = put(key, value); + } + + return v; + } + + /** + * Removes the entry for the specified key only if it is currently + * mapped to the specified value. + * + * @implSpec + * The default implementation is equivalent to, for this {@code map}: + * + *

 {@code
+     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+     *     map.remove(key);
+     *     return true;
+     * } else
+     *     return false;
+     * }
+ * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @param key key with which the specified value is associated + * @param value value expected to be associated with the specified key + * @return {@code true} if the value was removed + * @throws UnsupportedOperationException if the {@code remove} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the key or value is of an inappropriate + * type for this map + * (optional) + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values + * (optional) + * @since 1.8 + */ + default boolean remove(Object key, Object value) { + Object curValue = get(key); + if (!Objects.equals(curValue, value) || + (curValue == null && !containsKey(key))) { + return false; + } + remove(key); + return true; + } + + /** + * Replaces the entry for the specified key only if currently + * mapped to the specified value. + * + * @implSpec + * The default implementation is equivalent to, for this {@code map}: + * + *

 {@code
+     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+     *     map.put(key, newValue);
+     *     return true;
+     * } else
+     *     return false;
+     * }
+ * + * The default implementation does not throw NullPointerException + * for maps that do not support null values if oldValue is null unless + * newValue is also null. + * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @param key key with which the specified value is associated + * @param oldValue value expected to be associated with the specified key + * @param newValue value to be associated with the specified key + * @return {@code true} if the value was replaced + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of a specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if a specified key or newValue is null, + * and this map does not permit null keys or values + * @throws NullPointerException if oldValue is null and this map does not + * permit null values + * (optional) + * @throws IllegalArgumentException if some property of a specified key + * or value prevents it from being stored in this map + * @since 1.8 + */ + default boolean replace(K key, V oldValue, V newValue) { + Object curValue = get(key); + if (!Objects.equals(curValue, oldValue) || + (curValue == null && !containsKey(key))) { + return false; + } + put(key, newValue); + return true; + } + + /** + * Replaces the entry for the specified key only if it is + * currently mapped to some value. + * + * @implSpec + * The default implementation is equivalent to, for this {@code map}: + * + *

 {@code
+     * if (map.containsKey(key)) {
+     *     return map.put(key, value);
+     * } else
+     *     return null;
+     * }
+ * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. + * + * @param key key with which the specified value is associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key, or + * {@code null} if there was no mapping for the key. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with the key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (optional) + * @throws NullPointerException if the specified key or value is null, + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @since 1.8 + */ + default V replace(K key, V value) { + V curValue; + if (((curValue = get(key)) != null) || containsKey(key)) { + curValue = put(key, value); + } + return curValue; + } + + /** + * If the specified key is not already associated with a value (or is mapped + * to {@code null}), attempts to compute its value using the given mapping + * function and enters it into this map unless {@code null}. + * + *

If the function returns {@code null} no mapping is recorded. If + * the function itself throws an (unchecked) exception, the + * exception is rethrown, and no mapping is recorded. The most + * common usage is to construct a new object serving as an initial + * mapped value or memoized result, as in: + * + *

 {@code
+     * map.computeIfAbsent(key, k -> new Value(f(k)));
+     * }
+ * + *

Or to implement a multi-value map, {@code Map>}, + * supporting multiple values per key: + * + *

 {@code
+     * map.computeIfAbsent(key, k -> new HashSet()).add(v);
+     * }
+ * + * + * @implSpec + * The default implementation is equivalent to the following steps for this + * {@code map}, then returning the current value or {@code null} if now + * absent: + * + *
 {@code
+     * if (map.get(key) == null) {
+     *     V newValue = mappingFunction.apply(key);
+     *     if (newValue != null)
+     *         map.put(key, newValue);
+     * }
+     * }
+ * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. + * + * @param key key with which the specified value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with + * the specified key, or null if the computed value is null + * @throws NullPointerException if the specified key is null and + * this map does not support null keys, or the mappingFunction + * is null + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (optional) + * @since 1.8 + */ + default V computeIfAbsent(K key, + Function mappingFunction) { + Objects.requireNonNull(mappingFunction); + V v; + if ((v = get(key)) == null) { + V newValue; + if ((newValue = mappingFunction.apply(key)) != null) { + put(key, newValue); + return newValue; + } + } + + return v; + } + + /** + * If the value for the specified key is present and non-null, attempts to + * compute a new mapping given the key and its current mapped value. + * + *

If the function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception is + * rethrown, and the current mapping is left unchanged. + * + * @implSpec + * The default implementation is equivalent to performing the following + * steps for this {@code map}, then returning the current value or + * {@code null} if now absent: + * + *

 {@code
+     * if (map.get(key) != null) {
+     *     V oldValue = map.get(key);
+     *     V newValue = remappingFunction.apply(key, oldValue);
+     *     if (newValue != null)
+     *         map.put(key, newValue);
+     *     else
+     *         map.remove(key);
+     * }
+     * }
+ * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key is null and + * this map does not support null keys, or the + * remappingFunction is null + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (optional) + * @since 1.8 + */ + default V computeIfPresent(K key, + BiFunction remappingFunction) { + Objects.requireNonNull(remappingFunction); + V oldValue; + if ((oldValue = get(key)) != null) { + V newValue = remappingFunction.apply(key, oldValue); + if (newValue != null) { + put(key, newValue); + return newValue; + } else { + remove(key); + return null; + } + } else { + return null; + } + } + + /** + * Attempts to compute a mapping for the specified key and its current + * mapped value (or {@code null} if there is no current mapping). For + * example, to either create or append a {@code String} msg to a value + * mapping: + * + *

 {@code
+     * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}
+ * (Method {@link #merge merge()} is often simpler to use for such purposes.) + * + *

If the function returns {@code null}, the mapping is removed (or + * remains absent if initially absent). If the function itself throws an + * (unchecked) exception, the exception is rethrown, and the current mapping + * is left unchanged. + * + * @implSpec + * The default implementation is equivalent to performing the following + * steps for this {@code map}, then returning the current value or + * {@code null} if absent: + * + *

 {@code
+     * V oldValue = map.get(key);
+     * V newValue = remappingFunction.apply(key, oldValue);
+     * if (oldValue != null ) {
+     *    if (newValue != null)
+     *       map.put(key, newValue);
+     *    else
+     *       map.remove(key);
+     * } else {
+     *    if (newValue != null)
+     *       map.put(key, newValue);
+     *    else
+     *       return null;
+     * }
+     * }
+ * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none + * @throws NullPointerException if the specified key is null and + * this map does not support null keys, or the + * remappingFunction is null + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (optional) + * @since 1.8 + */ + default V compute(K key, + BiFunction remappingFunction) { + Objects.requireNonNull(remappingFunction); + V oldValue = get(key); + + V newValue = remappingFunction.apply(key, oldValue); + if (newValue == null) { + // delete mapping + if (oldValue != null || containsKey(key)) { + // something to remove + remove(key); + return null; + } else { + // nothing to do. Leave things as they were. + return null; + } + } else { + // add or replace old mapping + put(key, newValue); + return newValue; + } + } + + /** + * If the specified key is not already associated with a value or is + * associated with null, associates it with the given non-null value. + * Otherwise, replaces the associated value with the results of the given + * remapping function, or removes if the result is {@code null}. This + * method may be of use when combining multiple mapped values for a key. + * For example, to either create or append a {@code String msg} to a + * value mapping: + * + *

 {@code
+     * map.merge(key, msg, String::concat)
+     * }
+ * + *

If the function returns {@code null} the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception is + * rethrown, and the current mapping is left unchanged. + * + * @implSpec + * The default implementation is equivalent to performing the following + * steps for this {@code map}, then returning the current value or + * {@code null} if absent: + * + *

 {@code
+     * V oldValue = map.get(key);
+     * V newValue = (oldValue == null) ? value :
+     *              remappingFunction.apply(oldValue, value);
+     * if (newValue == null)
+     *     map.remove(key);
+     * else
+     *     map.put(key, newValue);
+     * }
+ * + *

The default implementation makes no guarantees about synchronization + * or atomicity properties of this method. Any implementation providing + * atomicity guarantees must override this method and document its + * concurrency properties. In particular, all implementations of + * subinterface {@link java.util.concurrent.ConcurrentMap} must document + * whether the function is applied once atomically only if the value is not + * present. + * + * @param key key with which the resulting value is to be associated + * @param value the non-null value to be merged with the existing value + * associated with the key or, if no existing value or a null value + * is associated with the key, to be associated with the key + * @param remappingFunction the function to recompute a value if present + * @return the new value associated with the specified key, or null if no + * value is associated with the key + * @throws UnsupportedOperationException if the {@code put} operation + * is not supported by this map + * (optional) + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * (optional) + * @throws NullPointerException if the specified key is null and this map + * does not support null keys or the value or remappingFunction is + * null + * @since 1.8 + */ + default V merge(K key, V value, + BiFunction remappingFunction) { + Objects.requireNonNull(remappingFunction); + Objects.requireNonNull(value); + V oldValue = get(key); + V newValue = (oldValue == null) ? value : + remappingFunction.apply(oldValue, value); + if(newValue == null) { + remove(key); + } else { + put(key, newValue); + } + return newValue; + } +} diff --git a/src/main/java/java/util/Objects.java b/src/main/java/java/util/Objects.java new file mode 100644 index 0000000..57c9c71 --- /dev/null +++ b/src/main/java/java/util/Objects.java @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.util.function.Supplier; + +/** + * This class consists of {@code static} utility methods for operating + * on objects. These utilities include {@code null}-safe or {@code + * null}-tolerant methods for computing the hash code of an object, + * returning a string for an object, and comparing two objects. + * + * @since 1.7 + */ +public final class Objects { + private Objects() { + throw new AssertionError("No java.util.Objects instances for you!"); + } + + /** + * Returns {@code true} if the arguments are equal to each other + * and {@code false} otherwise. + * Consequently, if both arguments are {@code null}, {@code true} + * is returned and if exactly one argument is {@code null}, {@code + * false} is returned. Otherwise, equality is determined by using + * the {@link Object#equals equals} method of the first + * argument. + * + * @param a an object + * @param b an object to be compared with {@code a} for equality + * @return {@code true} if the arguments are equal to each other + * and {@code false} otherwise + * @see Object#equals(Object) + */ + public static boolean equals(Object a, Object b) { + return (a == b) || (a != null && a.equals(b)); + } + + /** + * Returns {@code true} if the arguments are deeply equal to each other + * and {@code false} otherwise. + * + * Two {@code null} values are deeply equal. If both arguments are + * arrays, the algorithm in {@link Arrays#deepEquals(Object[], + * Object[]) Arrays.deepEquals} is used to determine equality. + * Otherwise, equality is determined by using the {@link + * Object#equals equals} method of the first argument. + * + * @param a an object + * @param b an object to be compared with {@code a} for deep equality + * @return {@code true} if the arguments are deeply equal to each other + * and {@code false} otherwise + * @see Arrays#deepEquals(Object[], Object[]) + * @see Objects#equals(Object, Object) + */ + public static boolean deepEquals(Object a, Object b) { + if (a == b) + return true; + else if (a == null || b == null) + return false; + else + return Arrays.deepEquals0(a, b); + } + + /** + * Returns the hash code of a non-{@code null} argument and 0 for + * a {@code null} argument. + * + * @param o an object + * @return the hash code of a non-{@code null} argument and 0 for + * a {@code null} argument + * @see Object#hashCode + */ + public static int hashCode(Object o) { + return o != null ? o.hashCode() : 0; + } + + /** + * Generates a hash code for a sequence of input values. The hash + * code is generated as if all the input values were placed into an + * array, and that array were hashed by calling {@link + * Arrays#hashCode(Object[])}. + * + *

This method is useful for implementing {@link + * Object#hashCode()} on objects containing multiple fields. For + * example, if an object that has three fields, {@code x}, {@code + * y}, and {@code z}, one could write: + * + *

+    * @Override public int hashCode() {
+    *     return Objects.hash(x, y, z);
+    * }
+    * 
+ * + * Warning: When a single object reference is supplied, the returned + * value does not equal the hash code of that object reference. This + * value can be computed by calling {@link #hashCode(Object)}. + * + * @param values the values to be hashed + * @return a hash value of the sequence of input values + * @see Arrays#hashCode(Object[]) + * @see List#hashCode + */ + public static int hash(Object... values) { + return Arrays.hashCode(values); + } + + /** + * Returns the result of calling {@code toString} for a non-{@code + * null} argument and {@code "null"} for a {@code null} argument. + * + * @param o an object + * @return the result of calling {@code toString} for a non-{@code + * null} argument and {@code "null"} for a {@code null} argument + * @see Object#toString + * @see String#valueOf(Object) + */ + public static String toString(Object o) { + return String.valueOf(o); + } + + /** + * Returns the result of calling {@code toString} on the first + * argument if the first argument is not {@code null} and returns + * the second argument otherwise. + * + * @param o an object + * @param nullDefault string to return if the first argument is + * {@code null} + * @return the result of calling {@code toString} on the first + * argument if it is not {@code null} and the second argument + * otherwise. + * @see Objects#toString(Object) + */ + public static String toString(Object o, String nullDefault) { + return (o != null) ? o.toString() : nullDefault; + } + + /** + * Returns 0 if the arguments are identical and {@code + * c.compare(a, b)} otherwise. + * Consequently, if both arguments are {@code null} 0 + * is returned. + * + *

Note that if one of the arguments is {@code null}, a {@code + * NullPointerException} may or may not be thrown depending on + * what ordering policy, if any, the {@link Comparator Comparator} + * chooses to have for {@code null} values. + * + * @param the type of the objects being compared + * @param a an object + * @param b an object to be compared with {@code a} + * @param c the {@code Comparator} to compare the first two arguments + * @return 0 if the arguments are identical and {@code + * c.compare(a, b)} otherwise. + * @see Comparable + * @see Comparator + */ + public static int compare(T a, T b, Comparator c) { + return (a == b) ? 0 : c.compare(a, b); + } + + /** + * Checks that the specified object reference is not {@code null}. This + * method is designed primarily for doing parameter validation in methods + * and constructors, as demonstrated below: + *

+     * public Foo(Bar bar) {
+     *     this.bar = Objects.requireNonNull(bar);
+     * }
+     * 
+ * + * @param obj the object reference to check for nullity + * @param the type of the reference + * @return {@code obj} if not {@code null} + * @throws NullPointerException if {@code obj} is {@code null} + * + * @diffblue.fullSupport + * @diffblue.untested + * We do not have tests for this method, but it is called from some tested + * modelled methods. + */ + public static T requireNonNull(T obj) { + if (obj == null) + throw new NullPointerException(); + return obj; + } + + /** + * Checks that the specified object reference is not {@code null} and + * throws a customized {@link NullPointerException} if it is. This method + * is designed primarily for doing parameter validation in methods and + * constructors with multiple parameters, as demonstrated below: + *
+     * public Foo(Bar bar, Baz baz) {
+     *     this.bar = Objects.requireNonNull(bar, "bar must not be null");
+     *     this.baz = Objects.requireNonNull(baz, "baz must not be null");
+     * }
+     * 
+ * + * @param obj the object reference to check for nullity + * @param message detail message to be used in the event that a {@code + * NullPointerException} is thrown + * @param the type of the reference + * @return {@code obj} if not {@code null} + * @throws NullPointerException if {@code obj} is {@code null} + */ + public static T requireNonNull(T obj, String message) { + if (obj == null) + throw new NullPointerException(message); + return obj; + } + + /** + * Returns {@code true} if the provided reference is {@code null} otherwise + * returns {@code false}. + * + * @apiNote This method exists to be used as a + * {@link java.util.function.Predicate}, {@code filter(Objects::isNull)} + * + * @param obj a reference to be checked against {@code null} + * @return {@code true} if the provided reference is {@code null} otherwise + * {@code false} + * + * @see java.util.function.Predicate + * @since 1.8 + */ + public static boolean isNull(Object obj) { + return obj == null; + } + + /** + * Returns {@code true} if the provided reference is non-{@code null} + * otherwise returns {@code false}. + * + * @apiNote This method exists to be used as a + * {@link java.util.function.Predicate}, {@code filter(Objects::nonNull)} + * + * @param obj a reference to be checked against {@code null} + * @return {@code true} if the provided reference is non-{@code null} + * otherwise {@code false} + * + * @see java.util.function.Predicate + * @since 1.8 + */ + public static boolean nonNull(Object obj) { + return obj != null; + } + + /** + * Checks that the specified object reference is not {@code null} and + * throws a customized {@link NullPointerException} if it is. + * + *

Unlike the method {@link #requireNonNull(Object, String)}, + * this method allows creation of the message to be deferred until + * after the null check is made. While this may confer a + * performance advantage in the non-null case, when deciding to + * call this method care should be taken that the costs of + * creating the message supplier are less than the cost of just + * creating the string message directly. + * + * @param obj the object reference to check for nullity + * @param messageSupplier supplier of the detail message to be + * used in the event that a {@code NullPointerException} is thrown + * @param the type of the reference + * @return {@code obj} if not {@code null} + * @throws NullPointerException if {@code obj} is {@code null} + * @since 1.8 + */ + public static T requireNonNull(T obj, Supplier messageSupplier) { + if (obj == null) + throw new NullPointerException(messageSupplier.get()); + return obj; + } +} diff --git a/src/main/java/java/util/Random.java b/src/main/java/java/util/Random.java index ead9e2c..9d07255 100644 --- a/src/main/java/java/util/Random.java +++ b/src/main/java/java/util/Random.java @@ -188,7 +188,7 @@ public Random(long seed) { * * @diffblue.mock * @diffblue.limitedSupport - * We currently ignore seeds and make test-generator pick return values + * We currently ignore seeds and make JBMC pick return values * for the methods in this class nondeterministically rather than * calculating them according to a probability distribution. So this * method is simply modelled as a no-op. @@ -374,7 +374,7 @@ public void nextBytes(byte[] bytes) { * * @diffblue.fullSupport * This method returns a nondeterministic {@code int} value. - * The nondeterminism is introduced by test-generator itself, and + * The nondeterminism is introduced by JBMC itself, and * probability distributions are ignored. * * @diffblue.mock @@ -441,9 +441,9 @@ public int nextInt() { * @diffblue.limitedSupport * This method returns a nondeterministic {@code int} value between 0 * (inclusive) and {@code bound} (exclusive). - * The nondeterminism is introduced by test-generator itself, and + * The nondeterminism is introduced by JBMC itself, and * probability distributions are ignored. - * Exceptions for mocked methods are currently not supported, see TG-1387. + * Exceptions for mocked methods are currently not supported. * * @diffblue.mock */ @@ -522,7 +522,7 @@ public long nextLong() { * * @diffblue.fullSupport * This method returns a nondeterministic {@code boolean} value. - * The nondeterminism is introduced by test-generator itself, and + * The nondeterminism is introduced by JBMC itself, and * probability distributions are ignored. * * @diffblue.mock @@ -572,7 +572,7 @@ public boolean nextBoolean() { * @diffblue.fullSupport * This method returns a nondeterministic {@code float} value between 0.0 * (inclusive) and 1.0 (exclusive). - * The nondeterminism is introduced by test-generator itself, and + * The nondeterminism is introduced by JBMC itself, and * probability distributions are ignored. * * @diffblue.mock @@ -626,7 +626,7 @@ public float nextFloat() { * @diffblue.fullSupport * This method returns a nondeterministic {@code double} value between 0.0 * (inclusive) and 1.0 (exclusive). - * The nondeterminism is introduced by test-generator itself, and + * The nondeterminism is introduced by JBMC itself, and * probability distributions are ignored. * * @diffblue.mock @@ -688,7 +688,7 @@ public double nextDouble() { * * @diffblue.fullSupport * This method returns a nondeterministic {@code double} value. - * The nondeterminism is introduced by test-generator itself, and + * The nondeterminism is introduced by JBMC itself, and * probability distributions are ignored. * * @diffblue.mock diff --git a/src/main/java/java/util/Set.java b/src/main/java/java/util/Set.java new file mode 100644 index 0000000..2703049 --- /dev/null +++ b/src/main/java/java/util/Set.java @@ -0,0 +1,413 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +/** + * A collection that contains no duplicate elements. More formally, sets + * contain no pair of elements e1 and e2 such that + * e1.equals(e2), and at most one null element. As implied by + * its name, this interface models the mathematical set abstraction. + * + *

The Set interface places additional stipulations, beyond those + * inherited from the Collection interface, on the contracts of all + * constructors and on the contracts of the add, equals and + * hashCode methods. Declarations for other inherited methods are + * also included here for convenience. (The specifications accompanying these + * declarations have been tailored to the Set interface, but they do + * not contain any additional stipulations.) + * + *

The additional stipulation on constructors is, not surprisingly, + * that all constructors must create a set that contains no duplicate elements + * (as defined above). + * + *

Note: Great care must be exercised if mutable objects are used as set + * elements. The behavior of a set is not specified if the value of an object + * is changed in a manner that affects equals comparisons while the + * object is an element in the set. A special case of this prohibition is + * that it is not permissible for a set to contain itself as an element. + * + *

Some set implementations have restrictions on the elements that + * they may contain. For example, some implementations prohibit null elements, + * and some have restrictions on the types of their elements. Attempting to + * add an ineligible element throws an unchecked exception, typically + * NullPointerException or ClassCastException. Attempting + * to query the presence of an ineligible element may throw an exception, + * or it may simply return false; some implementations will exhibit the former + * behavior and some will exhibit the latter. More generally, attempting an + * operation on an ineligible element whose completion would not result in + * the insertion of an ineligible element into the set may throw an + * exception or it may succeed, at the option of the implementation. + * Such exceptions are marked as "optional" in the specification for this + * interface. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @param the type of elements maintained by this set + * + * @author Josh Bloch + * @author Neal Gafter + * @see Collection + * @see List + * @see SortedSet + * @see HashSet + * @see TreeSet + * @see AbstractSet + * @see Collections#singleton(java.lang.Object) + * @see Collections#EMPTY_SET + * @since 1.2 + */ + +public interface Set extends Collection { + // Query Operations + + /** + * Returns the number of elements in this set (its cardinality). If this + * set contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this set (its cardinality) + */ + int size(); + + /** + * Returns true if this set contains no elements. + * + * @return true if this set contains no elements + */ + boolean isEmpty(); + + /** + * Returns true if this set contains the specified element. + * More formally, returns true if and only if this set + * contains an element e such that + * (o==null ? e==null : o.equals(e)). + * + * @param o element whose presence in this set is to be tested + * @return true if this set contains the specified element + * @throws ClassCastException if the type of the specified element + * is incompatible with this set + * (optional) + * @throws NullPointerException if the specified element is null and this + * set does not permit null elements + * (optional) + */ + boolean contains(Object o); + + /** + * Returns an iterator over the elements in this set. The elements are + * returned in no particular order (unless this set is an instance of some + * class that provides a guarantee). + * + * @return an iterator over the elements in this set + */ + Iterator iterator(); + + /** + * Returns an array containing all of the elements in this set. + * If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this set. (In other words, this method must + * allocate a new array even if this set is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this set + */ + Object[] toArray(); + + /** + * Returns an array containing all of the elements in this set; the + * runtime type of the returned array is that of the specified array. + * If the set fits in the specified array, it is returned therein. + * Otherwise, a new array is allocated with the runtime type of the + * specified array and the size of this set. + * + *

If this set fits in the specified array with room to spare + * (i.e., the array has more elements than this set), the element in + * the array immediately following the end of the set is set to + * null. (This is useful in determining the length of this + * set only if the caller knows that this set does not contain + * any null elements.) + * + *

If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose x is a set known to contain only strings. + * The following code can be used to dump the set into a newly allocated + * array of String: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that toArray(new Object[0]) is identical in function to + * toArray(). + * + * @param a the array into which the elements of this set are to be + * stored, if it is big enough; otherwise, a new array of the same + * runtime type is allocated for this purpose. + * @return an array containing all the elements in this set + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in this + * set + * @throws NullPointerException if the specified array is null + */ + T[] toArray(T[] a); + + + // Modification Operations + + /** + * Adds the specified element to this set if it is not already present + * (optional operation). More formally, adds the specified element + * e to this set if the set contains no element e2 + * such that + * (e==null ? e2==null : e.equals(e2)). + * If this set already contains the element, the call leaves the set + * unchanged and returns false. In combination with the + * restriction on constructors, this ensures that sets never contain + * duplicate elements. + * + *

The stipulation above does not imply that sets must accept all + * elements; sets may refuse to add any particular element, including + * null, and throw an exception, as described in the + * specification for {@link Collection#add Collection.add}. + * Individual set implementations should clearly document any + * restrictions on the elements that they may contain. + * + * @param e element to be added to this set + * @return true if this set did not already contain the specified + * element + * @throws UnsupportedOperationException if the add operation + * is not supported by this set + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this set + * @throws NullPointerException if the specified element is null and this + * set does not permit null elements + * @throws IllegalArgumentException if some property of the specified element + * prevents it from being added to this set + */ + boolean add(E e); + + + /** + * Removes the specified element from this set if it is present + * (optional operation). More formally, removes an element e + * such that + * (o==null ? e==null : o.equals(e)), if + * this set contains such an element. Returns true if this set + * contained the element (or equivalently, if this set changed as a + * result of the call). (This set will not contain the element once the + * call returns.) + * + * @param o object to be removed from this set, if present + * @return true if this set contained the specified element + * @throws ClassCastException if the type of the specified element + * is incompatible with this set + * (optional) + * @throws NullPointerException if the specified element is null and this + * set does not permit null elements + * (optional) + * @throws UnsupportedOperationException if the remove operation + * is not supported by this set + */ + boolean remove(Object o); + + + // Bulk Operations + + /** + * Returns true if this set contains all of the elements of the + * specified collection. If the specified collection is also a set, this + * method returns true if it is a subset of this set. + * + * @param c collection to be checked for containment in this set + * @return true if this set contains all of the elements of the + * specified collection + * @throws ClassCastException if the types of one or more elements + * in the specified collection are incompatible with this + * set + * (optional) + * @throws NullPointerException if the specified collection contains one + * or more null elements and this set does not permit null + * elements + * (optional), + * or if the specified collection is null + * @see #contains(Object) + */ + boolean containsAll(Collection c); + + /** + * Adds all of the elements in the specified collection to this set if + * they're not already present (optional operation). If the specified + * collection is also a set, the addAll operation effectively + * modifies this set so that its value is the union of the two + * sets. The behavior of this operation is undefined if the specified + * collection is modified while the operation is in progress. + * + * @param c collection containing elements to be added to this set + * @return true if this set changed as a result of the call + * + * @throws UnsupportedOperationException if the addAll operation + * is not supported by this set + * @throws ClassCastException if the class of an element of the + * specified collection prevents it from being added to this set + * @throws NullPointerException if the specified collection contains one + * or more null elements and this set does not permit null + * elements, or if the specified collection is null + * @throws IllegalArgumentException if some property of an element of the + * specified collection prevents it from being added to this set + * @see #add(Object) + */ + boolean addAll(Collection c); + + /** + * Retains only the elements in this set that are contained in the + * specified collection (optional operation). In other words, removes + * from this set all of its elements that are not contained in the + * specified collection. If the specified collection is also a set, this + * operation effectively modifies this set so that its value is the + * intersection of the two sets. + * + * @param c collection containing elements to be retained in this set + * @return true if this set changed as a result of the call + * @throws UnsupportedOperationException if the retainAll operation + * is not supported by this set + * @throws ClassCastException if the class of an element of this set + * is incompatible with the specified collection + * (optional) + * @throws NullPointerException if this set contains a null element and the + * specified collection does not permit null elements + * (optional), + * or if the specified collection is null + * @see #remove(Object) + */ + boolean retainAll(Collection c); + + /** + * Removes from this set all of its elements that are contained in the + * specified collection (optional operation). If the specified + * collection is also a set, this operation effectively modifies this + * set so that its value is the asymmetric set difference of + * the two sets. + * + * @param c collection containing elements to be removed from this set + * @return true if this set changed as a result of the call + * @throws UnsupportedOperationException if the removeAll operation + * is not supported by this set + * @throws ClassCastException if the class of an element of this set + * is incompatible with the specified collection + * (optional) + * @throws NullPointerException if this set contains a null element and the + * specified collection does not permit null elements + * (optional), + * or if the specified collection is null + * @see #remove(Object) + * @see #contains(Object) + */ + boolean removeAll(Collection c); + + /** + * Removes all of the elements from this set (optional operation). + * The set will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear method + * is not supported by this set + */ + void clear(); + + + // Comparison and hashing + + /** + * Compares the specified object with this set for equality. Returns + * true if the specified object is also a set, the two sets + * have the same size, and every member of the specified set is + * contained in this set (or equivalently, every member of this set is + * contained in the specified set). This definition ensures that the + * equals method works properly across different implementations of the + * set interface. + * + * @param o object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + boolean equals(Object o); + + /** + * Returns the hash code value for this set. The hash code of a set is + * defined to be the sum of the hash codes of the elements in the set, + * where the hash code of a null element is defined to be zero. + * This ensures that s1.equals(s2) implies that + * s1.hashCode()==s2.hashCode() for any two sets s1 + * and s2, as required by the general contract of + * {@link Object#hashCode}. + * + * @return the hash code value for this set + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + int hashCode(); + + /** + * Creates a {@code Spliterator} over the elements in this set. + * + *

The {@code Spliterator} reports {@link Spliterator#DISTINCT}. + * Implementations should document the reporting of additional + * characteristic values. + * + * @implSpec + * The default implementation creates a + * late-binding spliterator + * from the set's {@code Iterator}. The spliterator inherits the + * fail-fast properties of the set's iterator. + *

+ * The created {@code Spliterator} additionally reports + * {@link Spliterator#SIZED}. + * + * @implNote + * The created {@code Spliterator} additionally reports + * {@link Spliterator#SUBSIZED}. + * + * @return a {@code Spliterator} over the elements in this set + * @since 1.8 + */ + @Override + default Spliterator spliterator() { + return Spliterators.spliterator(this, Spliterator.DISTINCT); + } +} diff --git a/src/main/java/java/util/regex/Pattern.java b/src/main/java/java/util/regex/Pattern.java index ae980dd..ff12bfe 100644 --- a/src/main/java/java/util/regex/Pattern.java +++ b/src/main/java/java/util/regex/Pattern.java @@ -1157,9 +1157,9 @@ public int flags() { * no characters that has special meaning in regular expressions. * This way we can then match the regex using String.equals(). */ - private static void cproverAssumeIsPlainString(String regex) + private static boolean cproverIsPlainString(String regex) { - CProver.assume( + return regex.indexOf('[') == -1 && regex.indexOf(']') == -1 && regex.indexOf('{') == -1 && @@ -1173,7 +1173,11 @@ private static void cproverAssumeIsPlainString(String regex) regex.indexOf('*') == -1 && regex.indexOf('^') == -1 && regex.indexOf('$') == -1 && - regex.indexOf('|') == -1); + regex.indexOf('|') == -1; + } + private static void cproverAssumeIsPlainString(String regex) + { + CProver.assume(cproverIsPlainString(regex)); } /** @@ -1210,14 +1214,18 @@ public static boolean matches(String regex, CharSequence input) { // Matcher m = p.matcher(input); // return m.matches(); - // DIFFBLUE MODEL LIBRARY - // We disallow special characters so that we can do matching using equals. - cproverAssumeIsPlainString(regex); // if (input == null) { throw new NullPointerException(); // JDK throws NPE when the 2nd param is null } - return regex.equals(input); + // DIFFBLUE MODEL LIBRARY + // We disallow special characters so that we can do matching using equals. + if (cproverIsPlainString(regex)) { + return regex.equals(input); + } else { + CProver.notModelled(); + return CProver.nondetBoolean(); + } } /** @@ -1441,7 +1449,9 @@ public static String quote(String s) { private Pattern(String p, int f) { // DIFFBLUE MODEL LIBRARY // We disallow special characters so that we can use equals for matching. - cproverAssumeIsPlainString(p); + if (!cproverIsPlainString(p)) { + CProver.notModelled(); + } pattern = p; // pattern = p; // flags = f;