r.lang.ListExp.java Source code

Java tutorial

Introduction

Here is the source code for r.lang.ListExp.java

Source

/*
 * R : A Computer Language for Statistical Data Analysis
 * Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
 * Copyright (C) 1997-2008  The R Development Core Team
 * Copyright (C) 2003, 2004  The R Foundation
 * Copyright (C) 2010 bedatadriven
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package r.lang;

import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.UnmodifiableIterator;
import r.util.ArgChecker;

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * Linked list of SEXP values
 */
public class ListExp extends SEXP implements RecursiveExp, Iterable<SEXP>, NillOrListExp {

    public static final int TYPE_CODE = 2;
    public static final String TYPE_NAME = "pairlist";

    /**
     * The actual data for this node, .e.g {@code CAR} in
     * the C implementation
     */
    protected SEXP value = NilExp.INSTANCE;

    /**
     * The next node in the linked list, i.e. {@code CDR} in the
     * C implementation.
     * <p/>
     * Contrary to the C impl, {@code nextNode} is either a subclass
     * of {@code ListExp} or {@code null}
     */
    protected ListExp nextNode = null;

    public ListExp(SEXP value, ListExp nextNode) {
        this.value = value;
        this.nextNode = nextNode;
    }

    @Override
    public int getTypeCode() {
        return TYPE_CODE;
    }

    @Override
    public String getTypeName() {
        return TYPE_NAME;
    }

    /**
     * @return the next node in this linked list
     * @throws IllegalStateException if there is no next node
     */
    public final ListExp getNextNode() {
        if (nextNode == null) {
            throw new IllegalStateException("this list has no nextNode. Call hasNextNode() to check first.");
        }
        return nextNode;
    }

    public final boolean hasNextNode() {
        return nextNode != null;
    }

    public void removeNextNode() {
        nextNode = null;
    }

    public static ListExp fromIterable(Iterable<? extends SEXP> values) {
        Iterator<? extends SEXP> it = values.iterator();

        if (!it.hasNext()) {
            throw new IllegalArgumentException("Cannot create a zero-length list");
        }
        ListExp head = new ListExp(it.next(), null);
        ListExp node = head;
        while (it.hasNext()) {
            node.nextNode = new ListExp(it.next(), null);
            node = (ListExp) node.nextNode;
        }
        return head;
    }

    public static ListExp fromArray(SEXP... values) {
        return fromIterable(Arrays.asList(values));
    }

    public final SEXP getValue() {
        return value;
    }

    public final void setValue(SEXP value) {
        this.value = value;
    }

    @Override
    public SEXP getAttribute(String name) {
        /* pre-test to avoid expensive operations if clearly not needed -- LT */

        return NilExp.INSTANCE;
    }

    public void setNextNode(ListExp nextNode) {
        ArgChecker.notNull(nextNode);
        this.nextNode = nextNode;
    }

    @Override
    public Iterator<SEXP> iterator() {
        return new ValueIterator(this);
    }

    /**
     * Creates an iterator for the {@code ListExp}, or returns the
     * empty iterator if exp is {@code null}
     *
     * @param exp  a {@code ListExp}, or {@code null}
     * @return  an iterator
     */
    public static Iterator<SEXP> iterator(NillOrListExp exp) {
        if (exp == null || exp == NilExp.INSTANCE) {
            return Iterators.emptyIterator();
        } else {
            return exp.iterator();
        }
    }

    /**
     * Returns an (immutable) list of all {@code ListExp} nodes tagged
     * with the given {@code SymbolExp}
     */
    public List<ListExp> findAllNodesTaggedWith(SymbolExp symbol) {
        return new ImmutableList.Builder<ListExp>().addAll(Iterators.filter(nodeIterator(), new Tagged(symbol)))
                .build();
    }

    @Override
    public final int length() {
        return Iterators.size(iterator());
    }

    @Override
    public SEXP subset(int from, int to) {
        throw new UnsupportedOperationException("not yet implemented");
    }

    public static SEXP ofLength(int length) {
        return ListExp.fromIterable(Iterables.limit(Iterables.cycle(NilExp.INSTANCE), length));
    }

    public <X extends SEXP> X get(int i) {
        return (X) Iterators.get(iterator(), i);
    }

    public ListExp getNode(int i) {
        return Iterators.get(nodeIterator(), i);
    }

    /**
     * @return a shallow clone of the ListExp from this point on
     */
    @Override
    public ListExp clone() {
        Builder builder = new Builder();
        for (ListExp node : listNodes()) {
            Builder.Tail tail = builder.add(node.getValue());
            if (node.hasTag()) {
                tail.withTag((SymbolExp) node.getTag());
            }
        }
        return builder.list();
    }

    public String toString() {
        if (value == this) {
            return "[ CAR=this, CDR=" + nextNode + "]";
        } else {
            StringBuilder sb = new StringBuilder("[");
            for (ListExp node : listNodes()) {
                if (node != ListExp.this) {
                    sb.append(", ");
                }
                if (node.hasTag()) {
                    sb.append(node.getTag()).append("=");
                }
                sb.append(node.getValue());
            }
            return sb.append("]").toString();
        }
    }

    public SEXP getFirst() {
        return value;
    }

    public SEXP getSecond() {
        return nextNode.value;
    }

    public SEXP getThird() {
        return nextNode.nextNode.value;
    }

    /**
     * Iterator that iterators over the {@code ListExp}'s values
     */
    private static class ValueIterator extends UnmodifiableIterator<SEXP> {

        private ListExp next;

        private ValueIterator(ListExp next) {
            this.next = next;
        }

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

        @Override
        public SEXP next() {
            SEXP value = next.value;
            next = next.nextNode;
            return value;
        }
    }

    public Iterable<SEXP> values() {
        return new Iterable<SEXP>() {
            @Override
            public Iterator<SEXP> iterator() {
                return new ValueIterator(ListExp.this);
            }
        };
    }

    private static class NodeIterator extends UnmodifiableIterator<ListExp> {
        private ListExp next;

        private NodeIterator(ListExp next) {
            this.next = next;
        }

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

        @Override
        public ListExp next() {
            ListExp value = next;
            next = next.nextNode;
            return value;
        }
    }

    /**
     * Creates an {@code Iterable} of the succession of {@code ListExp}s.
     *
     * For a {@code ListExp} {@code L} with three nodes, the sequence will include
     * {@code L}, {@code L.nextNode}, and {@code L.nextNode.nextNode}.
     * 
     *
     * @return an {@code Iterable} of the sucession of {@code ListExp}s.
     */
    public Iterable<ListExp> listNodes() {
        return new Iterable<ListExp>() {
            @Override
            public Iterator<ListExp> iterator() {
                return nodeIterator();
            }
        };
    }

    /**
     * Returns an iterator over the individual ListExp nodes in this list,
     * or an empty iterator if exp is the NilExp.
        
     * @param exp  A ListExp or null
     * @throws IllegalArgumentException if the exp is not of type ListExp or NillExp
     */
    public static Iterable<ListExp> listNodes(NillOrListExp exp) {
        if (exp instanceof ListExp) {
            return ((ListExp) exp).listNodes();
        } else {
            return Collections.emptySet();
        }
    }

    private Iterator<ListExp> nodeIterator() {
        return new NodeIterator(this);
    }

    private class Tagged implements Predicate<ListExp> {
        private SymbolExp symbolToMatch;

        private Tagged(SymbolExp symbolToMatch) {
            this.symbolToMatch = symbolToMatch;
        }

        @Override
        public boolean apply(ListExp listExp) {
            return symbolToMatch.equals(listExp.getTag());
        }
    }

    public static class Builder {
        private ListExp head = null;
        private ListExp tail;

        public Builder() {
        }

        public Tail add(SEXP s) {
            if (head == null) {
                head = new ListExp(s, null);
                tail = head;
            } else {
                ListExp next = new ListExp(s, null);
                tail.nextNode = next;
                tail = next;
            }
            return new Tail(tail);
        }

        public ListExp list() {
            Preconditions.checkState(head != null, "ListExp cannot be empty");

            return head;
        }

        public class Tail {
            private final ListExp node;

            public Tail(ListExp node) {
                this.node = node;
            }

            public void withTag(SymbolExp tag) {
                this.node.setTag(tag);
            }
        }
    }

    @Override
    public EvalResult evaluate(EnvExp rho) {
        Builder builder = new Builder();

        return new EvalResult(builder.list());
    }

    @Override
    public void accept(SexpVisitor visitor) {
        visitor.visit(this);
    }

    public abstract static class Predicates {

        public static Predicate<ListExp> hasTag() {
            return new Predicate<ListExp>() {
                @Override
                public boolean apply(ListExp listExp) {
                    return listExp.hasTag();
                }
            };
        }

    }

}