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

craterdog.collections.List Maven / Gradle / Ivy

/************************************************************************
 * Copyright (c) Crater Dog Technologies(TM).  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 MIT License (MIT), as published by the Open   *
 * Source Initiative. (See http://opensource.org/licenses/MIT)          *
 ************************************************************************/
package craterdog.collections;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import craterdog.collections.abstractions.Collection;
import craterdog.core.Iterator;
import craterdog.core.Manipulator;
import craterdog.collections.abstractions.SortableCollection;
import craterdog.collections.interfaces.Indexed;
import craterdog.collections.primitives.DynamicArray;
import java.util.Arrays;
import org.slf4j.ext.XLogger;
import org.slf4j.ext.XLoggerFactory;


/**
 * This collection class implements a sortable list which performs very well for both inserts and
 * indexed lookups of its values.  The implementation dynamically scales up and down the size of
 * the underlying data structures as the number of associations changes over time.
 *
 * @author Derk Norton
 * @param  The type of element managed by the collection.
 */
public class List extends SortableCollection implements Indexed {

    static private final XLogger logger = XLoggerFactory.getXLogger(List.class);

    private final DynamicArray array;


    /**
     * This constructor creates a new empty list.
     */
    public List() {
        logger.entry();
        this.array = new DynamicArray<>();
        logger.exit();
    }


    /**
     * This constructor creates a new list using the elements provided in an array.
     *
     * @param elements The elements that should be used to seed the list.
     */
    @JsonCreator
    public List(E[] elements) {
        logger.entry(elements);
        int size = elements.length;
        this.array = new DynamicArray<>(size);
        this.array.addAll(Arrays.asList(elements));
        logger.exit();
    }


    @JsonValue
    @Override
    public E[] toArray() {
        return super.toArray();
    }


    /**
     * This constructor creates a new list using the elements provided in a collection.
     *
     * @param elements The elements that should be used to seed the list.
     */
    public List(Collection elements) {
        logger.entry(elements);
        int size = elements.getSize();
        this.array = new DynamicArray<>(size);
        for (E element : elements) {
            this.array.add(element);
        }
        logger.exit();
    }


    /**
     * This constructor creates a new list using the elements provided in a java collection.
     *
     * In general it is confusing to mix java collections with craterdog collections since
     * the former uses zero based indexing and the latter uses positive and negative ordinal
     * based indexing.
     *
     * @param elements The elements that should be used to seed the list.
     */
    public List(java.util.Collection elements) {
        logger.entry(elements);
        this.array = new DynamicArray<>(elements);
        logger.exit();
    }


    @Override
    @SuppressWarnings("unchecked")
    public List copy() {
        return (List) super.copy();
    }


    @Override
    public final int getSize() {
        logger.entry();
        int size = array.size();
        logger.exit(size);
        return size;
    }


    @Override
    public Iterator createIterator() {
        logger.entry();
        Iterator iterator = new ListManipulator();
        logger.exit(iterator);
        return iterator;
    }


    @Override
    public final E getElement(int index) {
        logger.entry(index);
        index = normalizedIndex(index);
        E element = array.get(index - 1);  // convert to zero based indexing
        logger.exit(element);
        return element;
    }


    @Override
    public final int getIndex(E element) {
        logger.entry(element);
        int index = array.indexOf(element) + 1;  // convert to ordinal based indexing
        logger.exit(index);
        return index;
    }


    @Override
    public final List getElements(int firstIndex, int lastIndex) {
        logger.entry(firstIndex, lastIndex);
        firstIndex = normalizedIndex(firstIndex);
        lastIndex = normalizedIndex(lastIndex);
        List result = new List<>();
        Iterator iterator = createIterator();
        iterator.toIndex(firstIndex);
        int numberOfElements = lastIndex - firstIndex + 1;
        while (numberOfElements-- > 0) {
            E element = iterator.getNext();
            logger.debug("Including element: {}", element);
            result.addElement(element);
        }
        logger.exit(result);
        return result;
    }


    @Override
    public final boolean addElement(E element) {
        logger.entry(element);
        boolean result = array.add(element);
        logger.exit(result);
        return result;
    }


    @Override
    public final boolean removeElement(E element) {
        logger.entry(element);
        boolean result = array.remove(element);
        logger.exit(result);
        return result;
    }


    @Override
    public final void removeAll() {
        logger.entry();
        array.clear();
        logger.exit();
    }


    @Override
    public final void insertElement(E element, int index) {
        logger.entry(element, index);
        index = normalizedIndex(index);
        array.add(index - 1, element);  // convert to zero based indexing
        logger.exit();
    }


    @Override
    public final void insertElements(Iterable elements, int index) {
        logger.entry(elements, index);
        index = normalizedIndex(index);
        Manipulator manipulator = createManipulator();
        manipulator.toIndex(index);
        for (E element : elements) {
            logger.debug("Inserting element: {}", element);
            manipulator.insertElement(element);
        }
        logger.exit();
    }


    @Override
    public final E replaceElement(E element, int index) {
        logger.entry(element, index);
        index = normalizedIndex(index);
        E result = array.set(index - 1, element);  // convert to zero based indexing
        logger.exit(result);
        return result;
    }


    @Override
    public final E removeElement(int index) {
        logger.entry(index);
        index = normalizedIndex(index);
        E result = array.remove(index - 1);  // convert to zero based indexing
        logger.exit(result);
        return result;
    }


    @Override
    public final List removeElements(int firstIndex, int lastIndex) {
        logger.entry(firstIndex, lastIndex);
        firstIndex = normalizedIndex(firstIndex);
        lastIndex = normalizedIndex(lastIndex);
        if (lastIndex < firstIndex) {
            // handle the case where the indexes are backwards
            int swap = firstIndex;
            firstIndex = lastIndex;
            lastIndex = swap;
        }
        List result = new List<>(array.remove(firstIndex - 1, lastIndex));  // convert to zero based indexing
        logger.exit(result);
        return result;
    }


    @Override
    public Manipulator createManipulator() {
        logger.entry();
        Manipulator manipulator = new ListManipulator();
        logger.exit(manipulator);
        return manipulator;
    }


    /**
     * This function returns a new list that contains the all the elements from
     * both the specified lists.
     *
     * @param  The type of element contained in the lists.
     * @param list1 The first list whose elements are to be added.
     * @param list2 The second list whose elements are to be added.
     * @return The resulting list.
     */
    static public  List concatenation(List list1, List list2) {
        logger.entry(list1, list2);
        List result = new List<>(list1);
        result.addElements(list2);
        logger.exit(result);
        return result;
    }


    /*
     * This manipulator class implements both the Iterator abstraction
     * and the Manipulator abstraction so it can be used as either depending
     * on how it is returned from the list.  It utilizes the list iterators for the
     * underlying list implementations.  Like most iterators, it should be used to access
     * a list exclusively without any other requests, especially requests that change the
     * length of the list, being made directly on the same list.  None of the manipulator
     * methods will cause the implementation of the list to be switched to a different
     * implementation.
     */
    private class ListManipulator extends Manipulator {

        private java.util.ListIterator iterator = array.iterator();

        @Override
        public void toStart() {
            logger.entry();
            iterator = array.iterator();
            logger.exit();
        }

        @Override
        public void toIndex(int index) {
            logger.entry(index);
            index = normalizedIndex(index);
            iterator = array.listIterator(index - 1);  // convert to zero based indexing
            logger.exit();
        }

        @Override
        public void toEnd() {
            logger.entry();
            iterator = array.listIterator(array.size());  // convert to zero based indexing
            logger.exit();
        }

        @Override
        public boolean hasPrevious() {
            logger.entry();
            boolean result = iterator.nextIndex() > 0;
            logger.exit(result);
            return result;
        }

        @Override
        public boolean hasNext() {
            logger.entry();
            boolean result = iterator.nextIndex() < array.size();
            logger.exit(result);
            return result;
        }

        @Override
        public E getNext() {
            logger.entry();
            if (!hasNext()) {
                IllegalStateException exception = new IllegalStateException("The iterator is at the end of the list.");
                throw logger.throwing(exception);
            }
            E result = iterator.next();
            logger.exit(result);
            return result;
        }

        @Override
        public E getPrevious() {
            logger.entry();
            if (!hasPrevious()) {
                IllegalStateException exception = new IllegalStateException("The iterator is at the beginning of the list.");
                throw logger.throwing(exception);
            }
            E result = iterator.previous();
            logger.exit(result);
            return result;
        }

        @Override
        public void insertElement(E element) {
            logger.entry(element);
            iterator.add(element);
            logger.exit();
        }

        @Override
        public E removeNext() {
            logger.entry();
            if (!hasNext()) {
                IllegalStateException exception = new IllegalStateException("The iterator is at the end of the list.");
                throw logger.throwing(exception);
            }
            E result = iterator.next();
            iterator.remove();
            logger.exit(result);
            return result;
        }

        @Override
        public E removePrevious() {
            logger.entry();
            if (!hasPrevious()) {
                IllegalStateException exception = new IllegalStateException("The iterator is at the beginning of the list.");
                throw logger.throwing(exception);
            }
            E result = iterator.previous();
            iterator.remove();
            logger.exit(result);
            return result;
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy