/* * Copyright 2003-2007 the original author or authors. * * 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 org.codehaus.groovy.util; public class ManagedDoubleKeyMap<K1,K2,V> extends AbstractConcurrentDoubleKeyMap<K1,K2,V> { public ManagedDoubleKeyMap(ReferenceBundle bundle) { super(bundle); } protected AbstractConcurrentDoubleKeyMap.Segment<K1,K2,V> createSegment(Object segmentInfo, int cap) { ReferenceBundle bundle = (ReferenceBundle) segmentInfo; return new Segment<K1,K2,V>(bundle, cap); } static class Segment<K1,K2,V> extends AbstractConcurrentDoubleKeyMap.Segment<K1,K2,V>{ private ReferenceBundle bundle; public Segment(ReferenceBundle bundle, int cap) { super(cap); this.bundle = bundle; } protected AbstractConcurrentDoubleKeyMap.Entry<K1,K2,V> createEntry(K1 key1, K2 key2, int hash) { return new EntryWithValue(bundle, key1, key2, hash, this); } } static class Ref<K> extends ManagedReference<K> { final Entry entry; public Ref(ReferenceBundle bundle, K referent, Entry entry) { super(bundle, referent); this.entry = entry; } public void finalizeRef() { this.entry.clean(); } } public static class Entry<K1,K2, V> implements AbstractConcurrentDoubleKeyMap.Entry<K1,K2,V> { private final int hash; final Ref<K1> ref1; final Ref<K2> ref2; final Segment segment; public Entry(ReferenceBundle bundle, K1 key1, K2 key2, int hash, Segment segment) { this.hash = hash; this.segment = segment; ref1 = new Ref(bundle, key1, this); ref2 = new Ref(bundle, key2, this); } public boolean isValid() { return ref1.get() != null && ref2.get () != null; } public boolean isEqual(K1 key1, K2 key2, int hash) { return this.hash == hash && ref1.get() == key1 && ref2.get() == key2; } public V getValue() { return (V)this; } public void setValue(V value) { } public int getHash() { return hash; } public void clean() { segment.removeEntry(this); ref1.clear(); ref2.clear(); } } private static class EntryWithValue<K1,K2,V> extends Entry<K1,K2,V> { private V value; public EntryWithValue(ReferenceBundle bundle, K1 key1, K2 key2, int hash, Segment segment) { super(bundle, key1, key2, hash, segment); } public V getValue() { return value; } public void setValue(V value) { this.value = value; } public void clean() { super.clean(); value = null; } } }