blob: 6bac0f19d443ec3009d8889818eed78b8fd34df5 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2017, 2022 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.rj.server.rh;
import static org.eclipse.statet.rj.server.rh.ObjectManager.NO_REF;
import static org.eclipse.statet.rj.server.rh.ObjectManager.STRONG_REF;
import static org.eclipse.statet.rj.server.rh.ObjectManager.WEAK_REF;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Set;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
/**
* R environment.
*/
@NonNullByDefault
public final class RhEnv {
private static final Object NO_DATA= new Object();
public final Handle handle;
private boolean isDisposed;
private final RhEngine engine;
private final @Nullable RhRefListener refListener;
private int strongCounter;
private int weakCounter;
private @Nullable RhWeakRef weakRef;
private final IdentityHashMap<String, @Nullable Object> regKeys= new IdentityHashMap<>(4);
public RhEnv(final RhEngine engine, final Handle handle,
final @Nullable RhRefListener refListener) {
this.engine= engine;
this.handle= handle;
this.refListener= refListener;
}
public boolean isRegAny() {
return (this.regKeys.size() > 0);
}
public boolean isReg(final String key) {
return this.regKeys.containsKey(key);
}
public boolean isRegAny(final Collection<String> keys) {
final Set<String> keySet= this.regKeys.keySet();
for (final String key : keys) {
if (keySet.contains(key)) {
return true;
}
}
return false;
}
public boolean addReg(final String key) {
if (!this.regKeys.containsKey(key)) {
this.regKeys.put(key, NO_DATA);
if (!this.isDisposed) {
switch (key.charAt(1)) {
case STRONG_REF:
preserveStrong();
break;
case WEAK_REF:
preserveWeak();
break;
default:
break;
}
}
return true;
}
return false;
}
public boolean addReg(final String key, final Object data) {
if (this.regKeys.put(key, data) == null) {
if (!this.isDisposed) {
switch (key.charAt(1)) {
case STRONG_REF:
preserveStrong();
break;
case WEAK_REF:
preserveWeak();
break;
default:
break;
}
}
return true;
}
return false;
}
public @Nullable Object getData(final String key) {
final Object object= this.regKeys.get(key);
return (object != NO_DATA) ? object : null;
}
public boolean removeReg(final String key) {
if (this.regKeys.remove(key) != null) {
if (!this.isDisposed) {
switch (key.charAt(1)) {
case STRONG_REF:
releaseStrong();
break;
case WEAK_REF:
releaseWeak();
break;
default:
break;
}
}
return true;
}
return false;
}
private void checkWeakRef() {
if (this.weakCounter > 0 && this.strongCounter == 0 && this.weakRef == null) {
this.weakRef= this.engine.newWeakRef(this.handle, (this.refListener != null) ?
this.refListener :
(final RhRef ref) -> dispose() );
}
}
private void preserveStrong() {
if (this.strongCounter++ == 0) {
this.engine.preserve(this.handle);
}
}
private void releaseStrong() {
if (--this.strongCounter == 0) {
checkWeakRef();
this.engine.releasePreserved(this.handle);
}
}
private void preserveWeak() {
if (this.weakCounter++ == 0) {
checkWeakRef();
}
}
private void releaseWeak() {
--this.weakCounter;
}
public boolean isDisposed() {
return this.isDisposed;
}
protected void dispose() {
if (this.isDisposed) {
return;
}
this.isDisposed= true;
if (this.weakRef != null) {
this.weakRef.dispose(this.engine);
}
if (this.strongCounter > 0) {
this.strongCounter= 0;
this.engine.releasePreserved(this.handle);
}
}
@Override
public String toString() {
final StringBuilder sb= new StringBuilder("env ");
sb.append(this.handle.toString());
sb.append(" (");
if (this.isDisposed) {
sb.append("disposed, ");
}
if (this.strongCounter > 0) {
sb.append("r= " + STRONG_REF);
}
else if (this.weakRef != null) {
sb.append("r= " + WEAK_REF);
}
else {
sb.append("r= " + NO_REF);
}
sb.append(')');
return sb.toString();
}
}