1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.util; 27 28 import java.lang.ref.ReferenceQueue; 29 import java.lang.ref.WeakReference; 30 import java.util.Iterator; 31 32 /** 33 * This is a helper class for handling weak references across all devices. 34 * We tried to use WeakHashMap, but it isn't available on mobile. We tried to 35 * add it to mobile, but it requires ReferenceQueue and it appears that 36 * ReferenceQueue requires support from the VM which we don't know that we 37 * have on mobile. So this class attempts to lesson the likelyhood of 38 * memory leaks. 39 * 40 * As we abandoned mobile, we considered removal of this class. But replacement 41 * by WeakHashMap is not always possible as we use mutable elements. At least 42 * it was now possible to optimize this class using the ReferenceQueue. 43 */ 44 public class WeakReferenceQueue<E> { 45 /** 46 * Reference queue for cleared weak references 47 */ 48 private final ReferenceQueue garbage = new ReferenceQueue(); 49 50 /** 51 * Strongly referenced list head 52 */ 53 private Object strongRef = new Object(); 54 private ListEntry head = new ListEntry(strongRef, garbage); 55 56 /** 57 * Size of the queue 58 */ 59 int size = 0; 60 61 @SuppressWarnings("unchecked") 62 public void add(E obj) { 63 cleanup(); 64 size++; 65 new ListEntry(obj, garbage).insert(head.prev); 66 } 67 68 public void remove(E obj) { 69 cleanup(); 70 71 ListEntry entry = head.next; 72 while (entry != head) { 73 Object other = entry.get(); 74 if (other == obj) { 75 size--; 76 entry.remove(); 77 return; 78 } 79 entry = entry.next; 80 } 81 } 82 83 public void cleanup() { 84 ListEntry entry; 85 while ((entry = (ListEntry) garbage.poll()) != null) { 86 size--; 87 entry.remove(); 88 } 89 } 90 91 public Iterator<? super E> iterator() { 92 return new Iterator() { 93 private ListEntry index = head; 94 private Object next = null; 95 96 public boolean hasNext() { 97 next = null; 98 while (next == null) { 99 ListEntry nextIndex = index.prev; 100 if (nextIndex == head) { 101 break; 102 } 103 next = nextIndex.get(); 104 if (next == null) { 105 size--; 106 nextIndex.remove(); 107 } 108 } 109 110 return next != null; 111 } 112 113 public Object next() { 114 hasNext(); // forces us to clear out crap up to the next 115 // valid spot 116 index = index.prev; 117 return next; 118 } 119 120 public void remove() { 121 if (index != head) { 122 ListEntry nextIndex = index.next; 123 size--; 124 index.remove(); 125 index = nextIndex; 126 } 127 } 128 }; 129 } 130 131 private static class ListEntry extends WeakReference { 132 ListEntry prev, next; 133 134 public ListEntry(Object o, ReferenceQueue queue) { 135 super(o, queue); 136 prev = this; 137 next = this; 138 } 139 140 public void insert(ListEntry where) { 141 prev = where; 142 next = where.next; 143 where.next = this; 144 next.prev = this; 145 } 146 147 public void remove() { 148 prev.next = next; 149 next.prev = prev; 150 next = this; 151 prev = this; 152 } 153 } 154 155 }