All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.takamaka.code.util.StorageLinkedList Maven / Gradle / Ivy

The newest version!
/*
Copyright 2021 Fausto Spoto

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 io.takamaka.code.util;

import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import io.takamaka.code.lang.Exported;
import io.takamaka.code.lang.Storage;
import io.takamaka.code.lang.View;

/**
 * A list of elements that can be kept in storage. It is possible to
 * add and access elements at both sides of the list. This list can hold
 * {@code null} elements.
 *
 * @param  the type of the elements. This type must be allowed in storage
 */
public class StorageLinkedList extends Storage implements StorageList {

	/**
	 * The first node of the list.
	 */
	private Node first;

	/**
	 * The last node of the list.
	 */
	private Node last;

	/**
	 * The size of the list.
	 */
	private int size;

	/**
	 * A node of the list.
	 * 
	 * @param  the type of the element inside the node
	 */
	private static class Node extends Storage {

		/**
		 * The element inside the node.
		 */
		private final E element;

		/**
		 * The next node.
		 */
		private Node next;

		/**
		 * Builds the node.
		 * 
		 * @param element the element to put inside the node
		 */
		private Node(E element) {
			this.element = element;
		}

		/**
		 * Builds the node.
		 * 
		 * @param element the element to put inside the node
		 * @param next the next node
		 */		
		private Node(E element, Node next) {
			this.element = element;
			this.next = next;
		}
	}

	/**
	 * Creates an empty list.
	 */
	public StorageLinkedList() {
	}

	/**
	 * Creates a list initialized to the same elements as the given parent collection.
	 * 
	 * @param parent the parent collection
	 */
	public StorageLinkedList(Collection parent) {
		parent.forEach(this::add);
	}

	@Override
	public void addFirst(E element) {
		if (first == null)
			first = last = new Node<>(element);
		else
			first = new Node<>(element, first);

		size++;
	}

	@Override
	public void addLast(E element) {
		if (last == null)
			first = last = new Node<>(element);
		else
			last = last.next = new Node<>(element);

		size++;
	}

	@Override
	public void add(E element) {
		addLast(element);
	}

	@Override
	public void clear() {
		first = last = null;
		size = 0;
	}

	@Override
	public E removeFirst() {
		if (first == null)
			throw new NoSuchElementException();
		else {
			E element = first.element;

			if (first == last)
				first = last = null;
			else
				first = first.next;

			size--;
			return element;
		}
	}

	@Override
	public boolean remove(Object e) {
		for (Node cursor = first, previous = null; cursor != null; previous = cursor, cursor = cursor.next) {
			E element = cursor.element;
			if (e == null ? element == null : e.equals(element)) {
				if (last == cursor)
					last = previous;

				if (first == cursor)
					first = cursor.next;

				if (previous != null)
					previous.next = cursor.next;

				size--;

				return true;
			}
		}

		return false;
	}

	@Override
	public @View boolean contains(Object e) {
		for (Node cursor = first; cursor != null; cursor = cursor.next) {
			E element = cursor.element;
			if (e == null ? element == null : e.equals(element))
				return true;
		}

		return false;
	}

	@Override
	public @View E first() {
		if (first == null)
			throw new NoSuchElementException();
		else
			return first.element;
	}

	@Override
	public @View E last() {
		if (last == null)
			throw new NoSuchElementException();
		else
			return last.element;
	}

	@Override
	public @View E get(int index) {
		if (index < 0 || index >= size)
			throw new IndexOutOfBoundsException(String.valueOf(index));

		Node cursor = first;
		for (int indexCopy = index; indexCopy > 0; indexCopy--)
			cursor = cursor.next;

		return cursor.element;
	}

	@Override
	public @View int size() {
		return size;
	}

	@Override
	public void forEach(Consumer what) {
		for (Node cursor = first; cursor != null; cursor = cursor.next)
			what.accept(cursor.element);
	}

	@Override @View
	public String toString() {
		return stream().map(Objects::toString).collect(Collectors.joining(",", "[", "]"));
	}

	@Override
	public Iterator iterator() {
		return new Iterator<>() {
			private Node cursor = first;

			@Override
			public boolean hasNext() {
				return cursor != null;
			}

			@Override
			public E next() {
				E result = cursor.element;
				cursor = cursor.next;

				return result;
			}
		};
	}

	@Override
	public Stream stream() {
		return StreamSupport.stream(spliterator(), false);
	}

	@Override
	public  A[] toArray(IntFunction generator) {
		return stream().toArray(generator);
	}

	@Override
	public StorageListView view() {

		/**
		 * A read-only view of a parent storage list. A view contains the same elements
		 * as the parent storage list, but does not include modification methods.
		 * Moreover, a view is exported, so that it can be safely divulged
		 * outside the store of a node. Calls to the view are simply forwarded to
		 * the parent list.
		 */

		@Exported
		class StorageListViewImpl extends Storage implements StorageListView {

			@Override
			public @View int size() {
				return StorageLinkedList.this.size();
			}

			@Override
			public @View boolean contains(Object value) {
				return StorageLinkedList.this.contains(value);
			}

			@Override
			public Iterator iterator() {
				return StorageLinkedList.this.iterator();
			}

			@Override
			public Stream stream() {
				return StorageLinkedList.this.stream();
			}

			@Override
			public E first() {
				return StorageLinkedList.this.first();
			}

			@Override
			public E last() {
				return StorageLinkedList.this.last();
			}

			@Override
			public E get(int index) {
				return StorageLinkedList.this.get(index);
			}

			@Override
			public String toString() {
				return StorageLinkedList.this.toString();
			}

			@Override
			public  A[] toArray(IntFunction generator) {
				return StorageLinkedList.this.toArray(generator);
			}

			@Override
			public StorageListView snapshot() {
				return StorageLinkedList.this.snapshot();
			}
		}

		return new StorageListViewImpl();
	}

	@Override
	public StorageListView snapshot() {
		StorageLinkedList copy = new StorageLinkedList<>();
		stream().forEachOrdered(copy::addLast);
		return copy.view();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy