Revision: 8342
Author: [email protected]
Date: Wed Jun 30 08:59:28 2010
Log: Set and MutableSet. Bytecode implementation.
Review at http://gwt-code-reviews.appspot.com/636801
Review by: [email protected]
http://code.google.com/p/google-web-toolkit/source/detail?r=8342
Added:
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/MutableSet.java
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Relation.java
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Set.java
/branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/MutableSetAdapterTest.java
/branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/MutableSetTest.java
Modified:
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Assertions.java
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/CollectionFactory.java
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Map.java
/branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/CollectionsServerSideTestSuite.java
=======================================
--- /dev/null
+++
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/MutableSet.java
Wed Jun 30 08:59:28 2010
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * A {...@link Set} whose content can change over time.
+ *
+ * Elements in {...@code this} Set are indexed by Strings. For each object in
the
+ * Set, the index String is computed by an "adapter" {...@link Relation}
provided
+ * when creating the Set with
+ * {...@link CollectionFactory#createMutableSet(Relation)}.
+ *
+ * Calls to {...@link Relation#applyTo(Object)} should return {...@code null}
for
+ * any object that cannot be a member of the Set. For any two objects to be
+ * stored in the Set, {...@code a} and {...@code b} the adapter must meet
+ * the condition that {...@code adapt(a) == adapt(b)} iff.
+ * {...@code a.equals(b)}.
+ *
+ * For example, suppose we need to store Foo objects uniquely identified
by an
+ * index property provided by {...@code Foo.getIndex()}. The following adapter
+ * would provide support for these objects in a Set:
+ *
+ * <pre class="code">
+ * <code>
+ * public class FooRelation implements Relation<Object, String> {
+ * public String applyTo(Object value) {
+ * return (value instanceof Foo) ? ((Foo) value).getIndex() : null;
+ * }
+ * }
+ * </code>
+ * </pre>
+ *
+ * The default adapter is used when creating a Set with
+ * {...@link CollectionFactory#createMutableSet()}. This adapter uses
+ * {...@link Object#toString()} to obtain the index string for any value.
+ * {...@code null} values are not supported (i.e. the adapter returns
+ * {...@code null}).
+ *
+ * Methods that require comparing one set to another implicitly require
testing
+ * membership of elements of one set into another. Adapters used in each
set may
+ * differ. For a method of {...@code this} set that receives a set
+ * {...@code source} as parameter, the calls will succeed as long as the
+ * following conditions are met:
+ *
+ * <ul>
+ * <li>For {...@link MutableSet#addAll(Set)}, all elements {...@code e} in
+ * {...@code source} must be such that {...@code this.adapt(e) != null}</li>
+ *
+ * <li>For {...@link Set#containsAll}, {...@link Set#containsSome(Set)},
+ * {...@link Set#isEqual(Set)} and MutableSet#removeAll(Set)}, all elements
+ * {...@code e} in {...@code source} must be such that
+ * {...@code this.adapt(e)} will complete successfully</li>
+ *
+ * <li>For {...@link MutableSet#keepAll(Set)}, all elements {...@code e} in
+ * {...@code this} must be such that {...@code source.adapt(e)} will
+ * complete successfully</li>
+ * </ul>
+ *
+ * @param <E> The type stored in the set elements
+ */
+public final class MutableSet<E> extends Set<E> {
+
+ /**
+ * Adds an {...@code element} to this set. {...@code element} must be a value
+ * accepted by the underlying adapter; that is, a call to {...@code
+ * adapt(element)} produces a non-null result.
+ *
+ * @param element element to add
+ */
+ public void add(E element) {
+ String key = adapt(element);
+ assert key != null : Assertions.ACCESS_UNSUPPORTED_VALUE;
+ elements.put(key, element);
+ }
+
+ /**
+ * Adds all elements from {...@code source}. This set will contain the
union of
+ * {...@code this} and {...@code source} sets.
+ *
+ * @param source a set whose contents will be added to this Set
+ * @exception NullPointerException if {...@code source} is {...@code null}
+ */
+ public void addAll(Set<E> source) {
+ if (source == null) {
+ throw new NullPointerException("source == null");
+ }
+
+ HashMap<String, E> sourceElems = source.elements;
+ Iterator<String> i = sourceElems.keySet().iterator();
+
+ while (i.hasNext()) {
+ add(sourceElems.get(i.next()));
+ }
+ }
+
+ @Override
+ public boolean contains(Object element) {
+ String key = adapt(element);
+ if (key == null) {
+ return false;
+ }
+ return elements.containsKey(key);
+ }
+
+ @Override
+ public boolean containsAll(Set<E> source) {
+ if (source == null) {
+ throw new NullPointerException("source == null");
+ }
+
+ HashMap<String, E> sourceElems = source.elements;
+ Iterator<String> i = sourceElems.keySet().iterator();
+
+ while (i.hasNext()) {
+ if (!contains(sourceElems.get(i.next()))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean containsSome(Set<E> source) {
+ if (source == null) {
+ throw new NullPointerException("source == null");
+ }
+
+ HashMap<String, E> sourceElems = source.elements;
+ Iterator<String> i = sourceElems.keySet().iterator();
+
+ while (i.hasNext()) {
+ if (contains(sourceElems.get(i.next()))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return elements.isEmpty();
+ }
+
+ @Override
+ public boolean isEqual(Set<E> source) {
+ return source != null
+ && source.elements.size() == elements.size()
+ && containsAll(source);
+ }
+
+ /**
+ * Removes all elements not in the {...@code source} set. This set will
keep the
+ * intersection of {...@code this} and {...@code source} sets.
+ *
+ * @param source set of elements to keep
+ * @exception NullPointerException if {...@code source} is {...@code null}
+ */
+ public void keepAll(Set<E> source) {
+ if (source == null) {
+ throw new NullPointerException("source == null");
+ }
+
+ Iterator<String> i = elements.keySet().iterator();
+
+ while (i.hasNext()) {
+ if (!source.contains(elements.get(i.next()))) {
+ i.remove();
+ }
+ }
+ }
+
+ /**
+ * Removes an {...@code element} from this set. {...@code element} must be a
value
+ * accepted by the underlying adapter; that is, a call to {...@code
+ * adapt(element)} produces a non-null result.
+ *
+ * @param element element to remove
+ */
+ public void remove(E element) {
+ String key = adapt(element);
+ if (key == null) {
+ return;
+ }
+ elements.remove(key);
+ }
+
+ /**
+ * Removes all elements contained in {...@code source} from this set. The
result
+ * will be the subtraction of {...@code source} from {...@code this} set.
+ *
+ * @param source a set whose contents will be removed from this set
+ * @exception NullPointerException if {...@code source} is {...@code null}
+ */
+ public void removeAll(Set<E> source) {
+ if (source == null) {
+ throw new NullPointerException("source == null");
+ }
+
+ HashMap<String, E> sourceElems = source.elements;
+ Iterator<String> i = sourceElems.keySet().iterator();
+
+ while (i.hasNext()) {
+ remove(sourceElems.get(i.next()));
+ }
+ }
+
+ /**
+ * Sets the {...@link Relation} to use to translate elements of the Set into
+ * Strings.
+ *
+ * @param adapter {...@link Relation} from Object to String
+ * @exception IllegalStateException if an adapter has already been set
or this
+ * set is not empty
+ * @exception NullPointerException if {...@code adapter} is {...@code null}
+ */
+ void setAdapter(Relation<Object, String> adapter) {
+ // TODO Consider allowing re-indexing the set
+ assert this.adapter == null : Assertions.INIT_ADAPTER_TWICE;
+
+ if (adapter == null) {
+ throw new NullPointerException("adapter == null");
+ }
+
+ if (this.adapter != null) {
+ throw new IllegalStateException("Adapter already set");
+ }
+
+ if (!isEmpty()) {
+ throw new IllegalStateException("Adapter set on non-empty set");
+ }
+
+ this.adapter = adapter;
+ }
+
+}
=======================================
--- /dev/null
+++
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Relation.java
Wed Jun 30 08:59:28 2010
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+/**
+ * Encapsulates a single parameter function. Primarily used by {...@code
+ * com.gwt.collections} in the form {...@code Relation<Object, String>} to
obtain a
+ * {...@code String} that represents an {...@code Object} stored in a
+ * {...@link MutableSet} or a {...@link MutableMap}.
+ *
+ * @see MutableSet
+ * @see MutableMap
+ *
+ * @param <I> relation domain type
+ * @param <O> relation range type
+ */
+public interface Relation<I, O> {
+ /**
+ * Applies a function to the {...@code element} passed as a parameter.
+ * @return the result of the function. {...@code null} if {...@code element}
is not
+ * valid as an input to the function represented by this {...@code Relation}
+ */
+ O applyTo(I element);
+}
=======================================
--- /dev/null
+++
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Set.java
Wed Jun 30 08:59:28 2010
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+import java.util.HashMap;
+
+/**
+ * The root Set type that provides read-access to an set that might still
be
+ * mutable by another actor.
+ *
+ * See {...@link MutableSet} for a description of the role
+ * {...@link Set#adapt(Object)} plays in the behavior of this class.
+ *
+ * @param <E> The type stored in the array elements
+ */
+public abstract class Set<E> {
+
+ /**
+ * Encapsulates the logic to transform <E> typed elements into String.
This is
+ * used to index into the set elements into a Map.
+ */
+ protected Relation<Object, String> adapter;
+
+ /**
+ * Backing store for the set elements.
+ */
+ HashMap<String, E> elements = new HashMap<String, E>();
+
+ /**
+ * Tests element membership. {...@code element} can take any value accepted
by
+ * {...@link Set#adapt(Object)}.
+ *
+ * @param element element to test for membership
+ * @return true if the element is a member of this set
+ */
+ public abstract boolean contains(Object element);
+
+ /**
+ * Tests whether {...@code source} is a subset of this set.
+ *
+ * @param source set containing elements to test for membership
+ * @return true if all elements in {...@code source} are in this set
+ * @exception NullPointerException if {...@code source} is {...@code null}
+ */
+ public abstract boolean containsAll(Set<E> source);
+
+ /**
+ * Tests whether the intersection of {...@code source} and this set is not
empty.
+ *
+ * @param source set containing elements to test for membership
+ * @return true if at least one elements in {...@code source} is in this set
+ * @exception NullPointerException if {...@code source} is {...@code null}
+ */
+ public abstract boolean containsSome(Set<E> source);
+
+ /**
+ * Tests whether this set contains any element.
+ *
+ * @return {...@code true} if the set contains at least one element
+ */
+ public abstract boolean isEmpty();
+
+ /**
+ * Tests whether {...@code source} and {...@code this} set contain the same
+ * elements.
+ *
+ * @param source set containing elements to test for membership
+ * @return {...@code true} if source != null, all elements in {...@code
source}
+ * are in {...@code this} set and all elements in {...@code this} set
are
+ * contained in {...@code source}; {...@code false} otherwise
+ */
+ public abstract boolean isEqual(Set<E> source);
+
+ /**
+ * Translates the Set domain into String. Actually calls {...@code
+ * adapter.applyTo(Object)}.
+ *
+ * @see MutableSet
+ * @param value to adapt
+ * @return a String uniquely representing the {...@code value}. {...@code
null}
+ * if the {...@code value} cannot be represented as a String
+ */
+ protected final String adapt(Object value) {
+ return adapter.applyTo(value);
+ }
+
+}
=======================================
--- /dev/null
+++
/branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/MutableSetAdapterTest.java
Wed Jun 30 08:59:28 2010
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests MutableSet when used providing a {...@link Relation} with
+ * custom {...@link MutableSet#setAdapter(Relation)} adapters.
+ */
+public class MutableSetAdapterTest extends GWTTestCase {
+
+ private boolean assertionsEnabled;
+
+ private Relation<Object, String> adapter1 = new Relation<Object,
String>() {
+ public String applyTo(Object element) {
+ if (!(element instanceof Integer) || (Integer) element >= 0) {
+ return null;
+ }
+ return "__" + ((Integer) element).toString();
+ }
+ };
+
+ private Relation<Object, String> adapter2 = new Relation<Object,
String>() {
+ public String applyTo(Object element) {
+ if (!(element instanceof Integer) || (Integer) element >= 0) {
+ return null;
+ }
+ return "_$_" + ((Integer) element).toString();
+ }
+ };
+
+ public void gwtSetUp() {
+ assertionsEnabled = this.getClass().desiredAssertionStatus();
+ }
+
+ public void testAdd() {
+ MutableSet<Integer> ms = CollectionFactory.createMutableSet(adapter1);
+
+ ms.add(-1);
+ assertTrue(ms.contains(-1));
+
+ // Do not test undefined behavior without assertions
+ if (!assertionsEnabled) {
+ return;
+ }
+ try {
+ ms.add(null);
+ fail("Should have triggered an assertion");
+ } catch (AssertionError e) {
+ // Good
+ assertEquals(Assertions.ACCESS_UNSUPPORTED_VALUE, e.getMessage());
+ }
+ try {
+ ms.add(1);
+ fail("Should have triggered an assertion");
+ } catch (AssertionError e) {
+ // Good
+ assertEquals(Assertions.ACCESS_UNSUPPORTED_VALUE, e.getMessage());
+ }
+ }
+
+ public void testAddAll() {
+ MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+
+ msA.add(-1);
+ msA.add(-2);
+ msA.add(-3);
+
+ msB.addAll(msA);
+
+ assertTrue(msB.isEqual(msA));
+ try {
+ msA.addAll(null);
+ fail();
+ } catch (NullPointerException e) {
+ // Expected behavior
+ }
+
+ // Test different adapters
+ MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter2);
+ msC.addAll(msA);
+
+ assertTrue(msC.isEqual(msA));
+ }
+
+ public void testContains() {
+ MutableSet<Integer> ms = CollectionFactory.createMutableSet(adapter1);
+ ms.add(-1);
+
+ assertTrue(ms.contains(-1));
+ assertFalse(ms.contains(-2));
+
+ assertFalse(ms.contains(null));
+ }
+
+ public void testContainsAll() {
+ MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msEmpty =
CollectionFactory.createMutableSet(adapter1);
+
+ msA.add(-1);
+ msA.add(-2);
+ msA.add(-3);
+
+ msB.add(-1);
+ msB.add(-2);
+
+ assertTrue(msA.containsAll(msB));
+ assertFalse(msB.containsAll(msA));
+ assertTrue(msA.containsAll(msEmpty));
+ try {
+ msA.containsAll(null);
+ fail();
+ } catch (NullPointerException e) {
+ // Expected behavior
+ }
+
+ // Test different adapters
+ MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter2);
+
+ msC.add(-1);
+ msC.add(-2);
+
+ assertTrue(msA.containsAll(msC));
+ assertFalse(msC.containsAll(msA));
+ }
+
+ public void testContainsSome() {
+ MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msEmpty =
CollectionFactory.createMutableSet(adapter1);
+
+ msA.add(-1);
+ msA.add(-2);
+ msA.add(-3);
+
+ msB.add(-4);
+ msB.add(-5);
+ msB.add(-1);
+
+ assertTrue(msA.containsSome(msB));
+ msB.remove(-1);
+ assertFalse(msB.containsSome(msA));
+ assertFalse(msA.containsSome(msEmpty));
+ try {
+ msA.containsSome(null);
+ fail();
+ } catch (NullPointerException e) {
+ // Expected behavior
+ }
+
+ // Test different adapters
+ MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter2);
+ msC.add(-4);
+ msC.add(-5);
+ msC.add(-1);
+
+ assertTrue(msA.containsSome(msC));
+ msC.remove(-1);
+ assertFalse(msC.containsSome(msA));
+ }
+
+ public void testIsEmpty() {
+ MutableSet<Integer> ms = CollectionFactory.createMutableSet(adapter1);
+
+ assertTrue(ms.isEmpty());
+ ms.add(-1);
+ assertFalse(ms.isEmpty());
+ }
+
+ public void testIsEqual() {
+ MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+
+ assertTrue(msA.isEqual(msB));
+ msA.add(-1);
+ assertFalse(msA.isEqual(msB));
+ msB.add(-1);
+ assertTrue(msA.isEqual(msB));
+ msB.add(-2);
+ assertFalse(msA.isEqual(msB));
+ assertFalse(msA.isEqual(null));
+
+ // Test different adapters
+ MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msD = CollectionFactory.createMutableSet(adapter2);
+
+ assertTrue(msC.isEqual(msD));
+ msC.add(-1);
+ assertFalse(msC.isEqual(msD));
+ msD.add(-1);
+ assertTrue(msC.isEqual(msD));
+ msD.add(-2);
+ assertFalse(msC.isEqual(msD));
+ }
+
+ public void testKeepAll() {
+ MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter1);
+
+ msA.add(-1);
+ msA.add(-2);
+ msA.add(-3);
+
+ msB.add(-1);
+ msB.add(-2);
+ msB.add(-4);
+
+ msC.add(-1);
+ msC.add(-2);
+
+ msA.keepAll(msB);
+ assertTrue(msC.isEqual(msA));
+ try {
+ msA.keepAll(null);
+ fail();
+ } catch (NullPointerException e) {
+ // Expected behavior
+ }
+
+ // Test different adapters
+ MutableSet<Integer> msD = CollectionFactory.createMutableSet(adapter2);
+
+ msD.add(-1);
+ msD.add(-2);
+ msD.add(-3);
+
+ msD.keepAll(msB);
+
+ assertTrue(msC.isEqual(msD));
+ }
+
+ public void testRemove() {
+ MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+
+ msA.add(-1);
+ msA.add(-2);
+ msA.remove(-1);
+ msB.add(-2);
+ assertTrue(msA.isEqual(msB));
+ msA.remove(-3);
+ assertTrue(msA.isEqual(msB));
+ msA.remove(null);
+ assertTrue(msA.isEqual(msB));
+ msA.remove(-2);
+ assertTrue(msA.isEmpty());
+ }
+
+ public void testRemoveAll() {
+ MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter1);
+
+ msA.add(-1);
+ msA.add(-2);
+ msA.add(-3);
+
+ msB.add(-1);
+ msB.add(-3);
+ msB.add(-4);
+
+ msC.add(-2);
+
+ msA.removeAll(msB);
+ assertTrue(msC.isEqual(msA));
+ msA.removeAll(msC);
+ assertTrue(msA.isEmpty());
+ try {
+ msA.removeAll(null);
+ fail();
+ } catch (NullPointerException e) {
+ // Expected behavior
+ }
+
+ // Test different adapters
+ MutableSet<Integer> msD = CollectionFactory.createMutableSet(adapter2);
+
+ msD.add(-1);
+ msD.add(-2);
+ msD.add(-3);
+
+ msD.removeAll(msB);
+ assertTrue(msC.isEqual(msD));
+ msD.removeAll(msC);
+ assertTrue(msD.isEmpty());
+}
+
+ @Override
+ public String getModuleName() {
+ return null;
+ }
+
+}
=======================================
--- /dev/null
+++
/branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/MutableSetTest.java
Wed Jun 30 08:59:28 2010
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests MutableSet when used without providing a {...@link Relation} with
+ * {...@link MutableSet#setAdapter(Relation)}.
+ */
+public class MutableSetTest extends GWTTestCase {
+
+ private boolean assertionsEnabled;
+
+ public void gwtSetUp() {
+ assertionsEnabled = this.getClass().desiredAssertionStatus();
+ }
+
+ public void testAdd() {
+ MutableSet<String> ms = CollectionFactory.createMutableSet();
+
+ ms.add("peach");
+ assertTrue(ms.contains("peach"));
+
+ // Do not test undefined behavior without assertions
+ if (!assertionsEnabled) {
+ return;
+ }
+ try {
+ ms.add(null);
+ fail("Should have triggered an assertion");
+ } catch (AssertionError e) {
+ // Good
+ assertEquals(Assertions.ACCESS_UNSUPPORTED_VALUE, e.getMessage());
+ }
+ }
+
+ public void testAddAll() {
+ MutableSet<String> msA = CollectionFactory.createMutableSet();
+ MutableSet<String> msB = CollectionFactory.createMutableSet();
+
+ msA.add("peach");
+ msA.add("apricot");
+ msA.add("prune");
+
+ msB.addAll(msA);
+
+ assertTrue(msB.isEqual(msA));
+ try {
+ msA.addAll(null);
+ fail();
+ } catch (NullPointerException e) {
+ // Expected behavior
+ }
+ assertTrue(msB.isEqual(msA));
+ }
+
+ public void testContains() {
+ MutableSet<String> ms = CollectionFactory.createMutableSet();
+ ms.add("peach");
+
+ assertTrue(ms.contains("peach"));
+ assertFalse(ms.contains("lemon"));
+
+ assertFalse(ms.contains(null));
+ }
+
+ public void testContainsAll() {
+ MutableSet<String> msA = CollectionFactory.createMutableSet();
+ MutableSet<String> msB = CollectionFactory.createMutableSet();
+ MutableSet<String> msEmpty = CollectionFactory.createMutableSet();
+
+ msA.add("peach");
+ msA.add("apricot");
+ msA.add("prune");
+
+ msB.add("peach");
+ msB.add("prune");
+
+ assertTrue(msA.containsAll(msB));
+ assertFalse(msB.containsAll(msA));
+ assertTrue(msA.containsAll(msEmpty));
+ try {
+ msA.containsAll(null);
+ fail();
+ } catch (NullPointerException e) {
+ // Expected behavior
+ }
+ }
+
+ public void testContainsSome() {
+ MutableSet<String> msA = CollectionFactory.createMutableSet();
+ MutableSet<String> msB = CollectionFactory.createMutableSet();
+ MutableSet<String> msEmpty = CollectionFactory.createMutableSet();
+
+ msA.add("peach");
+ msA.add("apricot");
+ msA.add("prune");
+
+ msB.add("lemon");
+ msB.add("orange");
+ msB.add("peach");
+
+ assertTrue(msA.containsSome(msB));
+ msB.remove("peach");
+ assertFalse(msB.containsSome(msA));
+ assertFalse(msA.containsSome(msEmpty));
+ try {
+ msA.containsSome(null);
+ fail();
+ } catch (NullPointerException e) {
+ // Expected behavior
+ }
+ }
+
+ public void testIsEmpty() {
+ MutableSet<String> ms = CollectionFactory.createMutableSet();
+
+ assertTrue(ms.isEmpty());
+ ms.add("peach");
+ assertFalse(ms.isEmpty());
+ }
+
+ public void testIsEqual() {
+ MutableSet<String> msA = CollectionFactory.createMutableSet();
+ MutableSet<String> msB = CollectionFactory.createMutableSet();
+
+ assertTrue(msA.isEqual(msB));
+ msA.add("peach");
+ assertFalse(msA.isEqual(msB));
+ msB.add("peach");
+ assertTrue(msA.isEqual(msB));
+ msB.add("apricot");
+ assertFalse(msA.isEqual(msB));
+ assertFalse(msA.isEqual(null));
+ }
+
+ public void testKeepAll() {
+ MutableSet<String> msA = CollectionFactory.createMutableSet();
+ MutableSet<String> msB = CollectionFactory.createMutableSet();
+ MutableSet<String> msC = CollectionFactory.createMutableSet();
+
+ msA.add("peach");
+ msA.add("apricot");
+ msA.add("prune");
+
+ msB.add("peach");
+ msB.add("prune");
+ msB.add("orange");
+
+ msC.add("peach");
+ msC.add("prune");
+
+ msA.keepAll(msB);
+ assertTrue(msC.isEqual(msA));
+ try {
+ msA.keepAll(null);
+ fail();
+ } catch (NullPointerException e) {
+ // Expected behavior
+ }
+ }
+
+ public void testRemove() {
+ MutableSet<String> msA = CollectionFactory.createMutableSet();
+ MutableSet<String> msB = CollectionFactory.createMutableSet();
+
+ msA.add("peach");
+ msA.add("apricot");
+ msA.remove("peach");
+ msB.add("apricot");
+ assertTrue(msA.isEqual(msB));
+ msA.remove("blue_berry");
+ assertTrue(msA.isEqual(msB));
+ msA.remove(null);
+ assertTrue(msA.isEqual(msB));
+ msA.remove("apricot");
+ assertTrue(msA.isEmpty());
+ }
+
+ public void testRemoveAll() {
+ MutableSet<String> msA = CollectionFactory.createMutableSet();
+ MutableSet<String> msB = CollectionFactory.createMutableSet();
+ MutableSet<String> msC = CollectionFactory.createMutableSet();
+
+ msA.add("peach");
+ msA.add("apricot");
+ msA.add("prune");
+
+ msB.add("peach");
+ msB.add("prune");
+ msB.add("orange");
+
+ msC.add("apricot");
+
+ msA.removeAll(msB);
+ assertTrue(msC.isEqual(msA));
+ msA.removeAll(msC);
+ assertTrue(msA.isEmpty());
+ try {
+ msA.removeAll(null);
+ fail();
+ } catch (NullPointerException e) {
+ // Expected behavior
+ }
+ }
+
+ @Override
+ public String getModuleName() {
+ return null;
+ }
+
+}
=======================================
---
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Assertions.java
Mon Jun 14 06:05:16 2010
+++
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Assertions.java
Wed Jun 30 08:59:28 2010
@@ -20,12 +20,25 @@
*/
class Assertions {
+ /**
+ * Message produced when asserting that access into a set or map uses a
value
+ * not in the domain.
+ */
+ static final String ACCESS_UNSUPPORTED_VALUE = "Unsupported value";
+
/**
* Message for asserting that access to an empty array is an illegal
operation.
*/
public static final String ACCESS_EMPTY_ARRAY_MESSAGE =
"Attempt to access an element in an empty array";
+ /**
+ * Message for asserting that adapters can only be set inly once after
+ * creation.
+ */
+ public static final String INIT_ADAPTER_TWICE = "Attempt to call " +
+ "setAdapter(Relation) a second time";
+
static void assertIndexInRange(int index, int minInclusive, int
maxExclusive) {
assert minInclusive < maxExclusive : ACCESS_EMPTY_ARRAY_MESSAGE;
assert (index >= minInclusive && index < maxExclusive) : "Index " +
index
=======================================
---
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/CollectionFactory.java
Mon Jun 14 11:58:23 2010
+++
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/CollectionFactory.java
Wed Jun 30 08:59:28 2010
@@ -20,6 +20,16 @@
* isn't.
*/
public class CollectionFactory {
+
+ static final Relation<Object, String> defaultAdapter =
+ new Relation<Object, String>() {
+ public String applyTo(Object value) {
+ if (value == null) {
+ return null;
+ }
+ return (String) value;
+ }
+ };
/**
* Creates an empty {...@link MutableArray}.
@@ -56,6 +66,27 @@
r.setSize(size, fillValue);
return r;
}
+
+ /**
+ * Creates an empty {...@link MutableSet}.
+ * @param <E> type of elements in the map
+ * @return an empty {...@code MutableSet}
+ */
+ public static <E> MutableSet<E> createMutableSet() {
+ return createMutableSet(defaultAdapter);
+ }
+
+ /**
+ * Creates an empty {...@link MutableSet} that uses a specific adapter.
+ * @param <E> type of elements in the map
+ * @return an empty {...@code MutableSet}
+ */
+ public static <E> MutableSet<E> createMutableSet(
+ Relation<Object, String> adapter) {
+ MutableSet<E> set = new MutableSet<E>();
+ set.setAdapter(adapter);
+ return set;
+ }
/**
* Creates an empty {...@link MutableStringMap}.
=======================================
---
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Map.java
Tue Jun 22 12:49:14 2010
+++
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Map.java
Wed Jun 30 08:59:28 2010
@@ -39,7 +39,7 @@
* Determines if a key is in the set of keys contained in the map.
*
* @param key to use for testing membership
- * @return <code>true</code> if the key is contained in the map
+ * @return {...@code true} if the key is contained in the map
*/
public abstract boolean containsKey(K key);
@@ -51,12 +51,12 @@
* containsKey(K)} to determine key membership.
*
* @param key index to use for retrieval.
- * @return value associated to the key or <code>null</code> otherwise.
+ * @return value associated to the key or {...@code null} otherwise.
*/
public abstract V get(K key);
/**
- * @return <code>true</code> if the map contains no entries.
+ * @return {...@code true} if the map contains no entries.
*/
public abstract boolean isEmpty();
=======================================
---
/branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/CollectionsServerSideTestSuite.java
Mon Jun 14 06:05:16 2010
+++
/branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/CollectionsServerSideTestSuite.java
Wed Jun 30 08:59:28 2010
@@ -30,6 +30,8 @@
suite.addTestSuite(MutableArrayInternalTest.class);
suite.addTestSuite(ImmutableArrayTest.class);
suite.addTestSuite(ImmutableArrayInternalTest.class);
+ suite.addTestSuite(MutableSetTest.class);
+ suite.addTestSuite(MutableSetAdapterTest.class);
return suite;
}
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors