convex.core.data.RefDirect Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of convex-core Show documentation
Show all versions of convex-core Show documentation
Convex core libraries and common utilities
The newest version!
package convex.core.data;
import convex.core.exceptions.InvalidDataException;
import convex.core.store.AStore;
/**
* Ref subclass for direct in-memory references.
*
* Direct Refs store the underlying value directly with a regular Java strong reference.
*
* Care must be taken to ensure recursive structures do not exceed reasonable memory bounds.
* In smart contract execution, juice limits serve this purpose.
*
* @param Type of Value referenced
*/
public class RefDirect extends Ref {
/**
* Direct value of this Ref
*/
private final T value;
private RefDirect(T value, Hash hash, int flags) {
super(hash, flags);
this.value = value;
}
/**
* Construction function for a Direct Ref
* @param Type of value
* @param value Value for the Ref
* @param hash Hash (may be null)
* @param status Status for the Ref
* @return New Direct Ref
*/
static RefDirect create(T value, Hash hash, int status) {
int flags=status&Ref.STATUS_MASK;
return new RefDirect(value, hash, flags);
}
/**
* Creates a new Direct ref to the given value. Does not compute hash.
* @param Type of Value
* @param value Value
* @return Direct Ref to Value
*/
@SuppressWarnings("unchecked")
public static RefDirect create(T value) {
if (value==null) return (RefDirect) Ref.NULL_VALUE;
return create(value, null, UNKNOWN);
}
public T getValue() {
return value;
}
@Override
public boolean isDirect() {
return true;
}
@Override
public Hash getHash() {
if (hash!=null) return hash;
if (value==null) return Hash.NULL_HASH;
Hash newHash=value.getHash();
hash=newHash;
return newHash;
}
@Override
public RefDirect toDirect() {
return this;
}
@Override
public RefSoft toSoft(AStore store) {
return RefSoft.create(store, value, flags);
}
@Override
public boolean equals(Ref a) {
if (a == this) return true;
if (a instanceof RefDirect) {
T va=((RefDirect) a).value;
if (value==va) return true; // fast path
if (value==null) return va==null; // catch nulls
if (this.hash != null) {
Hash ha=a.hash;
// use hash if available for both Refs
if (ha != null) return this.hash.equals(ha);
}
return value.equals(va);
} else {
// Don't want to pull from store, so use hash comparison
return getHash().equals(a.getHash());
}
}
@Override
public void validate() throws InvalidDataException {
super.validate();
if (isEmbedded() != Format.isEmbedded(value)) throw new InvalidDataException("Embedded flag is wrong!", this);
if (value == null) {
if (this != Ref.NULL_VALUE) throw new InvalidDataException("Null Ref not singleton!", this);
}
}
@Override
public Ref withValue(T newValue) {
if (newValue!=value) return new RefDirect(newValue,hash,flags);
return this;
}
@Override
public int estimatedEncodingSize() {
if(value==null) return Format.NULL_ENCODING_LENGTH;
return isEmbedded()?value.estimatedEncodingSize():Ref.INDIRECT_ENCODING_LENGTH;
}
@Override
public boolean isMissing() {
// Never missing, since we have the value at hand
return false;
}
@Override
public RefDirect withFlags(int newFlags) {
return new RefDirect(value,hash,newFlags);
}
@SuppressWarnings("unchecked")
@Override
public RefDirect ensureCanonical() {
if ((value==null)||value.isCanonical()) return this;
return new RefDirect((T)value.toCanonical(), hash,flags);
}
}