{@code Date}s, {@code Cloneable}s and arrays are defensively copied on the way in (constructor) and out (getters).
* Arrays and {@code Cloneable} objects use the {@code clone} method. For your own classes,
* it is up to you to define this method and use deep cloning if appropriate.
- *
{@code Collection}s and {@code Map}s are wrapped by immutable wrapper classes (but not deeply cloned!).
+ *
{@code Collection}s and {@code Map}s are wrapped by unmodifiable wrapper classes (but not deeply cloned!).
* Attempts to update them will result in an {@code UnsupportedOperationException}.
*
Fields that are enums or other {@code @Immutable} classes are allowed but for an
* otherwise possible mutable property type, an error is thrown.
@@ -101,7 +101,7 @@
* it is up to you to define this method and use deep cloning if appropriate.
*
*
- * As outlined above, {@code Collection}s and {@code Map}s are wrapped by immutable wrapper classes (but not deeply cloned!).
+ * As outlined above, {@code Collection}s and {@code Map}s are wrapped by unmodifiable wrapper classes (but not deeply cloned!).
*
*
* Currently {@code BigInteger} and {@code BigDecimal} are deemed immutable but see:
diff --git a/src/main/groovy/util/immutable/ImmutableCollection.java b/src/main/groovy/util/immutable/ImmutableCollection.java
new file mode 100644
index 0000000000..c5d5172539
--- /dev/null
+++ b/src/main/groovy/util/immutable/ImmutableCollection.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * 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 groovy.util.immutable;
+
+import java.util.Collection;
+
+/**
+ * An immutable and persistent collection of elements of type E.
+ *
+ * @author harold
+ * @author Yu Kobayashi
+ * @since 2.4.0
+ */
+public interface ImmutableCollection extends Collection {
+ /**
+ * @param element an element to append
+ * @return a collection which contains the element and all of the elements of this
+ */
+ ImmutableCollection plus(E element);
+
+ /**
+ * @param iterable elements to append
+ * @return a collection which contains all of the elements of iterable and this
+ */
+ ImmutableCollection plus(Iterable extends E> iterable);
+
+ /**
+ * @param element an element to remove
+ * @return this with a single instance of the element removed, if the element is in this collection
+ */
+ ImmutableCollection minus(Object element);
+
+ /**
+ * @param iterable elements to remove
+ * @return this with all elements of the iterable completely removed
+ */
+ ImmutableCollection minus(Iterable> iterable);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ boolean add(E o);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ boolean remove(Object o);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ boolean addAll(Collection extends E> c);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ boolean removeAll(Collection> c);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ boolean retainAll(Collection> c);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ void clear();
+}
diff --git a/src/main/groovy/util/immutable/ImmutableCollections.java b/src/main/groovy/util/immutable/ImmutableCollections.java
new file mode 100644
index 0000000000..769f1e9267
--- /dev/null
+++ b/src/main/groovy/util/immutable/ImmutableCollections.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * 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 groovy.util.immutable;
+
+import java.util.Map;
+
+/**
+ * A static utility class for getting empty immutable and persistent collections or creating immutable and persistent collections from mutable collections backed by the 'default' implementations.
+ *
+ * @author mtklein
+ * @author Yu Kobayashi
+ * @since 2.4.0
+ */
+public final class ImmutableCollections {
+ /**
+ * non-instantiable
+ */
+ private ImmutableCollections() {
+ }
+
+ /**
+ * Creates an empty immutable deque.
+ *
+ * @return an empty immutable deque
+ */
+ public static ImmutableDeque deque() {
+ return ImmutableDequeImpl.empty();
+ }
+
+ /**
+ * Creates an immutable deque from an iterable.
+ *
+ * @param iterable creates from
+ * @return the immutable deque
+ */
+ public static ImmutableDeque deque(Iterable extends E> iterable) {
+ return ImmutableDequeImpl.from(iterable);
+ }
+
+ /**
+ * Creates an empty immutable list.
+ *
+ * @return an empty immutable list
+ */
+ public static ImmutableList list() {
+ return ImmutableListImpl.empty();
+ }
+
+ /**
+ * Creates an immutable list from an iterable.
+ *
+ * @param iterable creates from
+ * @return the immutable list
+ */
+ public static ImmutableList list(Iterable extends E> iterable) {
+ return ImmutableListImpl.from(iterable);
+ }
+
+ /**
+ * Creates an empty immutable set.
+ *
+ * @return an empty immutable set
+ */
+ public static ImmutableSet set() {
+ return ImmutableSetImpl.empty();
+ }
+
+ /**
+ * Creates an immutable set from an iterable.
+ *
+ * @param iterable creates from
+ * @return the immutable set
+ */
+ public static ImmutableSet set(Iterable extends E> iterable) {
+ return ImmutableSetImpl.from(iterable);
+ }
+
+ /**
+ * Creates an empty immutable list set.
+ *
+ * @return an empty immutable list set
+ */
+ public static ImmutableListSet listSet() {
+ return ImmutableListSetImpl.empty();
+ }
+
+ /**
+ * Creates an immutable list set from an iterable.
+ *
+ * @param iterable creates from
+ * @return the immutable list set
+ */
+ public static ImmutableListSet listSet(Iterable extends E> iterable) {
+ return ImmutableListSetImpl.from(iterable);
+ }
+
+ /**
+ * Creates an empty immutable map.
+ *
+ * @return an empty immutable map
+ */
+ public static ImmutableMap map() {
+ return ImmutableMapImpl.empty();
+ }
+
+ /**
+ * Creates an immutable map from a mutable map.
+ *
+ * @param map creates from
+ * @return the immutable map
+ */
+ public static ImmutableMap map(Map extends K, ? extends V> map) {
+ return ImmutableMapImpl.from(map);
+ }
+}
diff --git a/src/main/groovy/util/immutable/ImmutableDeque.java b/src/main/groovy/util/immutable/ImmutableDeque.java
new file mode 100644
index 0000000000..6391d28502
--- /dev/null
+++ b/src/main/groovy/util/immutable/ImmutableDeque.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * 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 groovy.util.immutable;
+
+import java.util.Deque;
+
+/**
+ * An immutable and persistent deque.
+ * The elements can be null.
+ *
+ * You can create an instance by {@code [] as ImmutableDeque}.
+ *
+ * Example:
+ *
+ *
+ * @author mtklein
+ * @author Yu Kobayashi
+ * @since 2.4.0
+ */
+public interface ImmutableDeque extends ImmutableCollection, Deque {
+ /**
+ * Complexity: O(1)
+ *
+ * @return the first element of this deque
+ */
+ E peek();
+
+ /**
+ * Complexity: O(1)
+ *
+ * @return the first element of this deque
+ */
+ E peekFirst();
+
+ /**
+ * Complexity: O(1)
+ *
+ * @return the last element of this deque
+ */
+ E peekLast();
+
+ /**
+ * Complexity: O(1)
+ *
+ * @return the first element of this deque
+ * @throws java.util.NoSuchElementException if this deque is empty
+ */
+ E element();
+
+ /**
+ * Complexity: O(1)
+ *
+ * @return the first element of this deque
+ * @throws java.util.NoSuchElementException if this deque is empty
+ */
+ E getFirst();
+
+ /**
+ * Complexity: O(1)
+ *
+ * @return the last element of this deque
+ * @throws java.util.NoSuchElementException if this deque is empty
+ */
+ E getLast();
+
+ /**
+ * Complexity: O(1)
+ *
+ * @return the first element of this deque
+ * @throws java.util.NoSuchElementException if this deque is empty
+ */
+ E first();
+
+ /**
+ * Complexity: O(1)
+ *
+ * @return the first element of this deque
+ * @throws java.util.NoSuchElementException if this deque is empty
+ */
+ E head();
+
+ /**
+ * Complexity: O(1)
+ *
+ * @return the last element of this deque
+ * @throws java.util.NoSuchElementException if this deque is empty
+ */
+ E last();
+
+ /**
+ * Complexity:
+ *
+ *
Average-case
Amortized
Worst-case
+ *
+ *
Used as Deque
O(1)
O(n)
O(n)
+ *
Used as Queue
O(1)
O(1)
O(n)
+ *
Used as Stack
O(1)
O(1)
O(1)
+ *
+ *
+ *
+ * @return a deque without its first element
+ * @throws java.util.NoSuchElementException if this deque is empty
+ */
+ ImmutableDeque tail();
+
+ /**
+ * Complexity:
+ *
+ *
Average-case
Amortized
Worst-case
+ *
+ *
Used as Deque
O(1)
O(n)
O(n)
+ *
Used as Queue
O(1)
O(1)
O(n)
+ *
Used as Stack
O(1)
O(1)
O(1)
+ *
+ *
+ *
+ * @return a deque without its last element
+ * @throws java.util.NoSuchElementException if this deque is empty
+ */
+ ImmutableDeque init();
+
+ /**
+ * Complexity: O(1)
+ *
+ * @param element an element to append
+ * @return a deque which contains the element and all of the elements of this
+ */
+ ImmutableDeque plus(E element);
+
+ /**
+ * Complexity: O(1)
+ *
+ * @param element an element to append
+ * @return a deque which contains the element and all of the elements of this
+ */
+ ImmutableDeque plusFirst(E element);
+
+ /**
+ * Complexity: O(1)
+ *
+ * @param element an element to append
+ * @return a deque which contains the element and all of the elements of this
+ */
+ ImmutableDeque plusLast(E element);
+
+ /**
+ * Complexity: O(iterable.size())
+ *
+ * @param iterable elements to append
+ * @return a deque which contains all of the elements of iterable and this
+ */
+ ImmutableDeque plus(Iterable extends E> iterable);
+
+ /**
+ * Complexity: O(iterable.size())
+ *
+ * @param iterable elements to append
+ * @return a deque which contains all of the elements of iterable and this
+ */
+ ImmutableDeque plusFirst(Iterable extends E> iterable);
+
+ /**
+ * Complexity: O(iterable.size())
+ *
+ * @param iterable elements to append
+ * @return a deque which contains all of the elements of iterable and this
+ */
+ ImmutableDeque plusLast(Iterable extends E> iterable);
+
+ /**
+ * Complexity: O(n)
+ *
+ * @param element an element to remove
+ * @return this with a single instance of the element removed, if the element is in this deque
+ */
+ ImmutableDeque minus(Object element);
+
+ /**
+ * Complexity: O(n + iterable.size())
+ *
+ * @param iterable elements to remove
+ * @return this with all elements of the iterable completely removed
+ */
+ ImmutableDeque minus(Iterable> iterable);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ boolean offer(E e);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ E poll();
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ E remove();
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ void addFirst(E e);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ void addLast(E e);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ boolean offerFirst(E e);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ boolean offerLast(E e);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ E removeFirst();
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ E removeLast();
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ E pollFirst();
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ E pollLast();
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ boolean removeFirstOccurrence(Object o);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ boolean removeLastOccurrence(Object o);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ void push(E e);
+
+ /**
+ * Always throws {@link UnsupportedOperationException}.
+ */
+ @Deprecated
+ E pop();
+}
diff --git a/src/main/groovy/util/immutable/ImmutableDequeImpl.java b/src/main/groovy/util/immutable/ImmutableDequeImpl.java
new file mode 100644
index 0000000000..cc8d970b4b
--- /dev/null
+++ b/src/main/groovy/util/immutable/ImmutableDequeImpl.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * 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 groovy.util.immutable;
+
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.pcollections.AmortizedPDeque;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * @author Yu Kobayashi
+ * @since 2.4.0
+ */
+@SuppressWarnings("deprecation")
+class ImmutableDequeImpl implements ImmutableDeque, Serializable {
+ private static final ImmutableDequeImpl