|
What this is
Other links
The source code/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun * Microsystems, Inc. All Rights Reserved. */ package org.openide.util.lookup; import java.io.*; import java.lang.ref.WeakReference; import java.util.*; import org.openide.util.Lookup; /** ArrayStorage of Pairs from AbstractLookup. * @author Jaroslav Tulach */ final class ArrayStorage extends Object implements Comparator, Serializable, AbstractLookup.Storage { private static final long serialVersionUID = 543532453221L; /** default trashold */ static final Integer DEFAULT_TRASH = new Integer (11); /** list of items */ private Object content; /** linked list of refernces to results */ private transient AbstractLookup.ReferenceToResult results; /** Constructor */ public ArrayStorage() { this (DEFAULT_TRASH); } /** Constructs new ArrayStorage */ public ArrayStorage (Integer treshhold) { this.content = treshhold; } /* JST-PENDING: private void writeObject (ObjectOutputStream oos) throws IOException { oos.writeObject(object); Iterator it = interfaces.entrySet().iterator(); while (it.hasNext()) { Map.Entry e = (Map.Entry)it.next(); Class c = (Class)e.getKey(); oos.writeObject(c.getName()); Object o = e.getValue(); if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) throw new ClassCastException(String.valueOf(o)); oos.writeObject(o); } oos.writeObject(null); } private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException { object = (Node)ois.readObject(); interfaces = new WeakHashMap(); String clazz; ClassLoader l = (ClassLoader)Lookup.getDefault().lookup(ClassLoader.class); while ((clazz = (String)ois.readObject()) != null) { Object o = ois.readObject(); if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) throw new ClassCastException(String.valueOf(o)); Class c = Class.forName(clazz, false, l); interfaces.put(c, o); } } */ /** Adds an item into the tree. * @param item to add * @return true if the Item has been added for the first time or false if some other * item equal to this one already existed in the lookup */ public boolean add(AbstractLookup.Pair item, Object transaction) { Transaction changed = (Transaction)transaction; Object[] arr = changed.current; if (changed.arr == null) { // just simple add of one item for (int i = 0; i < arr.length; i++) { if (arr[i] == null) { arr[i] = item; changed.add (item); return true; } if (arr[i].equals (item)) { // reassign the item number item.setIndex (null, ((AbstractLookup.Pair)arr[i]).getIndex ()); // already there, but update it arr[i] = item; return false; } } // cannot happen as the beginTransaction ensured we can finish // correctly throw new IllegalStateException (); } else { // doing remainAll after that, let Transaction hold the new array int newIndex = changed.addPair (item); for (int i = 0; i < arr.length; i++) { if (arr[i] == null) { changed.add (item); return true; } if (arr[i].equals (item)) { // already there if (i != newIndex) { // change in index changed.add (item); return false; } else { // no change return false; } } } // if not found in the original array changed.add (item); return true; } } /** Removes an item. */ public void remove(AbstractLookup.Pair item, Object transaction) { Transaction changed = (Transaction)transaction; Object[] arr = changed.current; int found = -1; for (int i = 0; i < arr.length; ) { if (arr[i] == null) { // end of task return; } if (found == -1 && arr[i].equals (item)) { // already there ((AbstractLookup.Pair)arr[i]).setIndex (null, -1); changed.add (arr[i]); found = i; } i++; if (found != -1) { if (i < arr.length) { // moving the array arr[i - 1] = arr[i]; } else { arr[i - 1] = null; } } } } /** Removes all items that are not present in the provided collection. * @param retain Pair -> AbstractLookup.Info map * @param notify set of Classes that has possibly changed */ public void retainAll(Map retain, Object transaction) { Transaction changed = (Transaction)transaction; Object[] arr = changed.current; for (int from = 0; from < arr.length; from++) { if (! (arr[from] instanceof AbstractLookup.Pair)) { // end of content break; } AbstractLookup.Pair p = (AbstractLookup.Pair)arr[from]; AbstractLookup.Info info = (AbstractLookup.Info)retain.get (p); if (info == null) { // was removed /* if (info != null) { if (info.index < arr.length) { newArr[info.index] = p; } if (p.getIndex() != info.index) { p.setIndex (null, info.index); changed.add (p); } } else { // removed */ changed.add (p); } } } /** Queries for instances of given class. * @param clazz the class to check * @return enumeration of Item * @see #unsorted */ public Enumeration lookup (final Class clazz) { class CheckEn implements org.openide.util.Enumerations.Processor { public Object process (Object o, Collection ignore) { boolean ok; if (o instanceof AbstractLookup.Pair) { ok = clazz == null || ((AbstractLookup.Pair)o).instanceOf(clazz); } else { ok = false; } return ok ? o : null; } } if (content instanceof Object[]) { Enumeration all = org.openide.util.Enumerations.array ( (Object[])content ); return org.openide.util.Enumerations.filter (all, new CheckEn ()); } else { return org.openide.util.Enumerations.empty(); } } // // Implementation of comparator for AbstractLookup.Pair // /** Compares two items. */ public int compare(Object obj, Object obj1) { AbstractLookup.Pair i1 = (AbstractLookup.Pair)obj; AbstractLookup.Pair i2 = (AbstractLookup.Pair)obj1; int result = i1.getIndex() - i2.getIndex(); if (result == 0) { if (i1 != i2) { java.io.ByteArrayOutputStream bs = new java.io.ByteArrayOutputStream (); java.io.PrintStream ps = new java.io.PrintStream (bs); ps.println ( "Please report this exception as issue http://www.netbeans.org/issues/show_bug.cgi?id=13779 " + // NOI18N "Pair1: " + i1 + " pair2: " + i2 + " index1: " + i1.getIndex() + " index2: " + i2.getIndex() // NOI18N + " item1: " + i1.getInstance () + " item2: " + i2.getInstance () // NOI18N + " id1: " + Integer.toHexString (System.identityHashCode (i1)) // NOI18N + " id2: " + Integer.toHexString (System.identityHashCode (i2)) // NOI18N ); //print (ps, false); ps.close (); throw new IllegalStateException (bs.toString ()); } return 0; } return result; } /** Associates another result with this storage. */ public AbstractLookup.ReferenceToResult registerReferenceToResult(AbstractLookup.ReferenceToResult newRef) { AbstractLookup.ReferenceToResult prev = this.results; this.results = newRef; return prev; } /** Cleanup the references */ public AbstractLookup.ReferenceToResult cleanUpResult(Lookup.Template templ) { AbstractLookup.ReferenceIterator it = new AbstractLookup.ReferenceIterator (this.results); while (it.next()); return this.results = it.first (); } /** We use a hash set of all modified Pair to handle the transaction */ public Object beginTransaction(int ensure) { return new Transaction (ensure, content); } /** Extract all results. */ public void endTransaction(Object transaction, Set modified) { Transaction changed = (Transaction)transaction; AbstractLookup.ReferenceIterator it = new AbstractLookup.ReferenceIterator (this.results); if (changed.arr == null) { // either add or remove, only check the content of check HashSet while (it.next()) { AbstractLookup.ReferenceToResult ref = it.current (); Iterator pairs = changed.iterator(); while (pairs.hasNext()) { AbstractLookup.Pair p = (AbstractLookup.Pair)pairs.next (); if (AbstractLookup.matches (ref.template, p, true)) { modified.add (ref.getResult()); } } } } else { // do full check of changes while (it.next()) { AbstractLookup.ReferenceToResult ref = it.current (); int oldIndex = -1; int newIndex = -1; for (;;) { oldIndex = findMatching (ref.template, changed.current, oldIndex); newIndex = findMatching (ref.template, changed.arr, newIndex); if (oldIndex == -1 && newIndex == -1) { break; } if ( oldIndex == -1 || newIndex == -1 || !changed.current[oldIndex].equals (changed.arr[newIndex]) ) { modified.add (ref.getResult ()); break; } } } } this.results = it.first (); this.content = changed.newContent (); } private static int findMatching (Lookup.Template t, Object[] arr, int from) { while (++from < arr.length) { if (arr[from] instanceof AbstractLookup.Pair) { if (AbstractLookup.matches(t, (AbstractLookup.Pair)arr[from], true)) { return from; } } } return -1; } /** HashSet with additional field for new array which is callocated * in case we are doing replace to hold all new items. */ private static final class Transaction extends HashSet { /** array with current objects */ public final Object[] current; /** array with new objects */ public final Object[] arr; /** number of objects in the array */ private int cnt; public Transaction (int ensure, Object currentContent) { Integer trashold; Object[] arr; if (currentContent instanceof Integer) { trashold = (Integer)currentContent; arr = null; } else { arr = (Object[])currentContent; if (arr[arr.length - 1] instanceof Integer) { trashold = (Integer)arr[arr.length - 1]; } else { // nowhere to grow we have reached the limit trashold = null; } } int maxSize = trashold == null ? arr.length : trashold.intValue(); if (ensure > maxSize) { throw new UnsupportedOperationException (); } if (ensure == -1) { // remove => it is ok this.current = (Object[])currentContent; this.arr = null; return; } if (ensure == -2) { // adding one if (arr == null) { // first time add, let's allocate the array arr = new Object[2]; arr[1] = trashold; } else { if (arr[arr.length - 1] instanceof AbstractLookup.Pair) { // we are full throw new UnsupportedOperationException (); } else { // ensure we have allocated enough space if (arr[arr.length - 2] != null) { // double the array int newSize = (arr.length - 1) * 2; if (newSize > maxSize) { newSize = maxSize; if (newSize <= arr.length) { // no space to get in throw new UnsupportedOperationException (); } arr = new Object[newSize]; } else { // still a lot of space arr = new Object[newSize + 1]; arr[newSize] = trashold; } // copy content of original array without the last Integer into // the new one System.arraycopy(currentContent, 0, arr, 0, ((Object[])currentContent).length - 1); } } } this.current = arr; this.arr = null; } else { // allocate array for complete replacement if (ensure == maxSize) { this.arr = new Object[ensure]; } else { this.arr = new Object[ensure + 1]; this.arr[ensure] = trashold; } this.current = currentContent instanceof Object[] ? (Object[])currentContent : new Object[0]; } } public int addPair (AbstractLookup.Pair p) { p.setIndex (null, cnt); arr[cnt++] = p; return p.getIndex (); } public Object newContent () { return arr == null ? current : arr; } } // end of Transaction } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.