/*
* TclObject.java
*
* Copyright (c) 1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
*
* RCS: @(#) $Id: TclObject.java,v 1.4 2006/06/09 20:13:39 mdejong Exp $
*
*/
package tcl.lang;
import java.util.Hashtable;
/**
* This class extends TclObjectBase to implement the basic notion of
* an object in Tcl.
*/
public final class TclObject extends TclObjectBase {
static final boolean saveObjRecords = TclObjectBase.saveObjRecords;
static Hashtable objRecordMap = TclObjectBase.objRecordMap;
/**
* Creates a TclObject with the given InternalRep. This method should be
* called only by an InternalRep implementation.
*
* @param rep the initial InternalRep for this object.
*/
public TclObject(final InternalRep rep) {
super(rep);
}
/**
* Creates a TclObject with the given InternalRep and stringRep.
* This constructor is used by the TclString class only. No other place
* should call this constructor.
*
* @param rep the initial InternalRep for this object.
* @param s the initial string rep for this object.
*/
protected TclObject(final TclString rep, final String s) {
super(rep, s);
}
/**
* Creates a TclObject with the given integer value.
* This constructor is used by the TclInteger class only. No other place
* should call this constructor.
*
* @param ivalue the integer value
*/
protected TclObject(final int ivalue) {
super(ivalue);
}
/**
* Change the internal rep of the object. The old internal rep
* will be deallocated as a result. This method should be
* called only by an InternalRep implementation. This method
* overloads the setInternalRep() method in TclObjectBase
* so that the CObject internal rep special case is handled.
*
* @param rep the new internal rep.
*/
public void setInternalRep(InternalRep rep) {
if (internalRep == null) {
disposedError();
}
if (rep == null) {
throw new TclRuntimeError("null InternalRep");
}
if (rep == internalRep) {
return;
}
// In the special case where the internal representation is a CObject,
// we want to call the special interface to convert the underlying
// native object into a reference to the Java TclObject. Note that
// this test will always fail if we are not using the native
// implementation. Also note that the makeReference method
// will do nothing in the case where the Tcl_Obj inside the
// CObject was originally allocated in Java. When converting
// to a CObject we need to break the link made earlier.
if ((internalRep instanceof CObject) && !(rep instanceof CObject)) {
// We must ensure that the string rep is copied into Java
// before we lose the reference to the underlying CObject.
// Otherwise we will lose the original string information
// when the backpointer is lost.
if (stringRep == null) {
stringRep = internalRep.toString();
}
((CObject) internalRep).makeReference(this);
}
//System.out.println("TclObject setInternalRep for \"" + stringRep + "\"");
//System.out.println("from \"" + internalRep.getClass().getName() +
// "\" to \"" + rep.getClass().getName() + "\"");
internalRep.dispose();
internalRep = rep;
ivalue = 0;
}
/**
* Tcl_IncrRefCount -> preserve
*
* Increments the refCount to indicate the caller's intent to
* preserve the value of this object. Each preserve() call must be matched
* by a corresponding release() call.
*
* @exception TclRuntimeError if the object has already been deallocated.
*/
public final void preserve() {
if (internalRep == null) {
disposedError();
}
if (internalRep instanceof CObject) {
((CObject) internalRep).incrRefCount();
}
_preserve();
}
/**
* _preserve
*
* Private implementation of preserve() method.
* This method will be invoked from Native code
* to change the TclObject's ref count without
* effecting the ref count of a CObject.
*/
private final void _preserve() {
refCount++;
}
/**
* Tcl_DecrRefCount -> release
*
* Decrements the refCount to indicate that the caller is no longer
* interested in the value of this object. If the refCount reaches 0,
* the obejct will be deallocated.
*/
public final void release() {
if (internalRep == null) {
disposedError();
}
if (internalRep instanceof CObject) {
((CObject) internalRep).decrRefCount();
}
_release();
}
/**
* _release
*
* Private implementation of preserve() method.
* This method will be invoked from Native code
* to change the TclObject's ref count without
* effecting the ref count of a CObject.
*/
private final void _release() {
if (--refCount <= 0) {
disposeObject();
}
}
/**
* Returns the Tcl_Obj* objPtr member for a CObject or TclList.
* This method is only called from Tcl Blend.
*/
final long getCObjectPtr() {
if (internalRep instanceof CObject) {
return ((CObject) internalRep).getCObjectPtr();
} else {
return 0;
}
}
/**
* Returns 2 if the internal rep is a TclList.
* Returns 1 if the internal rep is a CObject.
* Otherwise returns 0.
* This method provides an optimization over
* invoking getInternalRep() and two instanceof
* checks via JNI. It is only used by Tcl Blend.
*/
final int getCObjectInst() {
if (internalRep instanceof CObject) {
if (internalRep instanceof TclList)
return 2;
else
return 1;
} else {
return 0;
}
}
/**
* Return a String that describes TclObject and internal
* rep type allocations and conversions. The string is
* in lines separated by newlines. The saveObjRecords
* needs to be set to true and Jacl recompiled for
* this method to return a useful value.
*/
public static String getObjRecords() {
return TclObjectBase.getObjRecords();
}
}