Mercurial > hg > Members > kono > jpf-core
view src/main/gov/nasa/jpf/util/ObjectList.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
line wrap: on
line source
/* * Copyright (C) 2014, United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. * * The Java Pathfinder core (jpf-core) platform is 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 gov.nasa.jpf.util; import gov.nasa.jpf.JPFException; import gov.nasa.jpf.SystemAttribute; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.NoSuchElementException; /** * a minimal container API that transparently handles Object lists which can * degenerate to single values that are stored directly. Value lists are * implemented by means of a private Node type, which is transparently handled * through the (static) ObjectList API * * No null objects can be stored in the list. No list can only contain a single * Node object * * Conversion between single objects and lists is done transparently if you * follow a pattern like: * * Object attr; // either a single value or a list * .. * attr = ObjectList.remove(attr, v); * * If there is only one remaining value in a list, the corresponding Node will * be replaced with this value. * * iterators are LIFO. * * We assume that attribute collections are small, otherwise retrieval and * deletion with this API becomes rather inefficient * * NOTE: while ObjectList heads are stored in simple Object fields within the * user (and therefore could be just overwritten by simple assignments) * YOU SHOULD NOT DO THIS! Other extensions or JPF itself could rely on * current attributes. In case you have to change the whole list, use * set(oldAttrs,newAttr), which checks if there currently is a SystemAttribute * instance in the list, in which case it throws a JPFException unless the * new attibute value is also a gov.nasa.jpf.SystemAttribute instance. Use * forceSet(null) if you really have to remove lists with SystemAttributes * * * usage: * Object attr; * ... * attr = AttrContainer.add( newAttr, attr); * * MyAttr a = AttrContainer.getNext( MyAttr.class, attr); * * attr = AttrContainer.remove( a, attr); * * for (MyAttr a = ObjectList.getFirst(MyAttr.class, attr); a != null; * a = ObjectList.getNext(MyAttr.class, attr, a)) {..} * */ public abstract class ObjectList { // there are no instances, this class is only a static API private ObjectList(){} private static class Node implements Cloneable { Object data; Node next; Node(Object data, Node next) { this.data = data; this.next = next; } @Override public boolean equals(Object o){ if (o instanceof Node){ Node n = this; Node no = (Node)o; for (; n != null && no != null; n=n.next, no=no.next){ if (!n.data.equals(no.data)){ return false; } } return (n == null) && (no == null); } else { return false; } } @Override protected Node clone(){ try { return (Node)super.clone(); } catch (CloneNotSupportedException cnsx){ throw new RuntimeException("Node clone failed"); } } // recursively clone up to the node with the specified data public Node cloneWithReplacedData (Object oldData, Object newData){ Node newThis = clone(); if (data.equals(oldData)){ newThis.data = newData; } else if (next != null) { newThis.next = next.cloneWithReplacedData(oldData, newData); } return newThis; } public Node cloneWithRemovedData (Object oldData){ Node newThis = clone(); if (next != null){ if (next.data.equals(oldData)){ newThis.next = next.next; } else { newThis.next = next.cloneWithRemovedData( oldData); } } return newThis; } } public static class Iterator implements java.util.Iterator<Object>, Iterable<Object> { Object cur; Iterator (Object head){ cur = head; } @Override public boolean hasNext() { return cur != null; } @Override public Object next() { if (cur != null){ if (cur instanceof Node){ Node n = (Node)cur; cur = n.next; return n.data; } else { // single attr value Object n = cur; cur = null; return n; } } else { throw new NoSuchElementException(); } } @Override public void remove() { // we can't remove since that would have to change the head field in the client throw new UnsupportedOperationException(); } @Override public java.util.Iterator<Object> iterator(){ return this; } } static final Iterator emptyIterator = new Iterator(null); public static Iterator iterator (Object head){ if (head == null){ return emptyIterator; } else { return new Iterator(head); } } public static class TypedIterator<A> implements java.util.Iterator<A>, Iterable<A> { Object cur; Class<A> type; TypedIterator (Object head, Class<A> type){ this.type = type; this.cur = null; if (head instanceof Node){ for (Node n = (Node)head; n != null; n = n.next){ if (type.isAssignableFrom(n.data.getClass())) { cur = n; break; } } } else if (head != null) { if (type.isAssignableFrom(head.getClass())) { cur = head; } } } @Override public boolean hasNext() { return cur != null; } @Override public A next() { if (cur != null){ if (cur instanceof Node){ Node nCur = (Node)cur; cur = null; A d = (A)nCur.data; for (Node n=nCur.next; n != null; n=n.next){ if (type.isAssignableFrom(n.data.getClass())){ cur = n; break; } } return d; } else { // single attr value A d = (A)cur; cur = null; return d; } } else { throw new NoSuchElementException(); } } @Override public void remove() { // we can't remove since that would have to change the head field in the client throw new UnsupportedOperationException(); } @Override public java.util.Iterator<A> iterator(){ return this; } } static final TypedIterator<Object> emptyTypedIterator = new TypedIterator<Object>(null,Object.class); public static <A> TypedIterator<A> typedIterator (Object head, Class<A> type){ if (head == null){ return (TypedIterator<A>) emptyTypedIterator; } else { return new TypedIterator<A>(head, type); } } /** * this returns either the first value if there is only one element, or * a Node list containing all the values in the order they are provided * * note - elements in the list occur in order of arguments, whereas normal * add() always adds at the head of the list */ public static Object createList(Object... values){ if (values.length == 0){ return null; } else if (values.length == 1){ return values[0]; } else { Node node = null, next = null; for (int i=values.length-1; i>=0; i--){ node = new Node(values[i], next); next = node; } return node; } } public static Object valueOf (Object o){ return (o instanceof Node) ? ((Node)o).data : o; } public static Object set (Object head, Object newHead){ if (head == null || newHead instanceof SystemAttribute){ return newHead; // Ok to overwrite } else { if (head instanceof Node){ // check if there is any SystemAttribute in the list for (Node n = (Node)head; n != null; n = n.next){ if (n.data instanceof SystemAttribute){ throw new JPFException("attempt to overwrite SystemAttribute with " + newHead); } } return newHead; // Ok to overwrite } else { // single data attribute if (head instanceof SystemAttribute){ throw new JPFException("attempt to overwrite SystemAttribute with " + newHead); } else { return newHead; // Ok to overwrite } } } } /** * just to provide a way to overwrite SystemAttributes (e.g. with null) */ public static Object forceSet (Object head, Object newHead){ return newHead; } public static Object add (Object head, Object data){ if (head == null){ return data; } else if (data == null){ return head; } else { if (head instanceof Node){ return new Node(data, (Node)head); } else { // was single value -> turn into list Node p = new Node(head,null); return new Node(data, p); } } } public static Object replace (Object head, Object oldData, Object newData){ if (oldData == null){ return head; } if (newData == null){ return remove(head, oldData); // no null data, remove oldData } if (head instanceof Node){ // <2do> perhaps we should first check if it is there return ((Node)head).cloneWithReplacedData(oldData, newData); } else { // single object if (oldData.equals(head)){ return newData; } else { return head; } } } public static Object remove (Object head, Object data){ if (head == null || data == null){ return head; } if (head instanceof Node) { Node nh = (Node) head; Node nhn = nh.next; if (nhn != null && nhn.next == null) { // 2 node case - reduce if found if (nh.data.equals(data)) { return nhn.data; } else if (nhn.data.equals(data)) { return nh.data; } else { // not there return head; } } return nh.cloneWithRemovedData(data); } else { // single object if (head.equals(data)){ return null; } else { return head; } } } public static boolean contains (Object head, Object o){ if (head == null || o == null){ return false; } else if (head instanceof Node){ for (Node n = (Node)head; n != null; n = n.next){ if (o.equals(n.data)){ return true; } } return false; } else { return o.equals(head); } } public static boolean containsType (Object head, Class<?> type){ if (head == null || type == null){ return false; } else if (head instanceof Node){ for (Node n = (Node)head; n != null; n = n.next){ if (type.isAssignableFrom(n.data.getClass())){ return true; } } return false; } else { return type.isAssignableFrom(head.getClass()); } } //--- various qualifiers public static boolean isList (Object head){ return (head instanceof Node); } public static boolean isEmpty(Object head){ return head == null; } public static int size(Object head){ int len = 0; if (head instanceof Node){ for (Node n = (Node) head; n != null; n = n.next) { len++; } } else { if (head != null){ len = 1; } } return len; } public static int numberOfInstances (Object head, Class<?> type){ int len = 0; if (head instanceof Node){ for (Node n = (Node) head; n != null; n = n.next) { if (type.isInstance(n.data)){ len++; } } } else { if (head != null){ if (type.isInstance(head)){ len = 1; } } } return len; } public static Object get (Object head, int idx){ if (head instanceof Node){ int i=0; for (Node n = (Node) head; n != null; n = n.next) { if (i++ == idx){ return n.data; } } } else { if (idx == 0){ return head; } } return null; } public static Object getFirst(Object head){ if (head instanceof Node){ return ((Node)head).data; } else { return head; } } public static Object getNext(Object head, Object prevData){ if (head instanceof Node){ Node n = (Node)head; if (prevData != null){ for (; n != null && n.data != prevData; n=n.next); if (n == null){ return null; } else { n = n.next; } } return n.data; } else { if (prevData == null){ return head; } } return null; } public static <A> A getFirst (Object head, Class<A> type){ if (head != null){ if (type.isAssignableFrom(head.getClass())) { return (A) head; } if (head instanceof Node) { for (Node n = (Node) head; n != null; n = n.next) { if (type.isAssignableFrom(n.data.getClass())) { return (A) n.data; } } } } return null; } public static <A> A getNext (Object head, Class<A> type, Object prevData){ if (head instanceof Node){ Node n = (Node)head; if (prevData != null){ for (; n != null && n.data != prevData; n=n.next); if (n == null){ return null; } else { n = n.next; } } for (; n != null; n = n.next) { if (type.isAssignableFrom(n.data.getClass())) { return (A) n.data; } } } else if (head != null) { if (prevData == null){ if (type.isAssignableFrom(head.getClass())){ return (A)head; } } } return null; } public static void hash (Object head, HashData hd){ if (head instanceof Node){ for (Node n = (Node) head; n != null; n = n.next) { hd.add(n.data); } } else if (head != null){ hd.add(head); } } public static boolean equals( Object head1, Object head2){ if (head1 != null){ return head1.equals(head2); } else { return head2 == null; // both null is treated as equal } } static Object cloneData (Object o) throws CloneNotSupportedException { if (o instanceof CloneableObject) { CloneableObject co = (CloneableObject) o; return co.clone(); } else if (o != null) { Class<?> cls = o.getClass(); try { Method m = cls.getMethod("clone"); // it can't be static because this would mask Object.clone() // since Class.getMethod() only returns publics, we don't have to set accessible return m.invoke(o); } catch (NoSuchMethodException nsmx){ // since Object.clone() would throw it (unless this is a Cloneable, in which // case there most probably is a public clone() and we would not have // gotten here), there is no use trying to call it throw new CloneNotSupportedException("no public clone(): " + o); } catch (InvocationTargetException ix){ throw new RuntimeException( "generic clone failed: " + o, ix.getCause()); } catch (IllegalAccessException iax){ throw new RuntimeException("clone() not accessible: " + o); } } else { return null; } } static Node cloneNode (Node n) throws CloneNotSupportedException { if (n == null){ return null; } else { return new Node( cloneData(n.data), cloneNode(n.next)); } } public static Object clone (Object head) throws CloneNotSupportedException { if (head instanceof Node){ return cloneNode( (Node)head); } else if (head != null){ return cloneData( head); } else { return null; } } }