diff options
author | Sven Gothel <[email protected]> | 2015-03-05 07:14:04 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-03-05 07:14:04 +0100 |
commit | 72d3635279ffc8ad88e47dff9bbe95d211226d11 (patch) | |
tree | 62b3735680dfc5980a94afa14c56045bd082af24 /src/java/com/jogamp/gluegen/cgram | |
parent | dd2440cbadc642a561d8f92c502fe822b2f11762 (diff) |
Bug 1134 - Enhance GlueGen Compiler: Minimal GL Header Changes _and_ Typesafety
- We shall be able to import 'most' vanilla GL header,
i.e. only change the typedef part using our GlueGen types
- Type Safety:
- GlueGen now detects '#define' and 'enum' redefines
and throw an exception in this case.
This helps detecting wrongly renamed GL extensions into core!
- GlueGen now detects function redefines (overloading)
and throw an exception in this case.
Hence the semantics of duplicate functions has to be equal!
This helps detecting wrongly renamed GL extensions into core!
- Semantic equality for all types is provided
via interface TypeComparator.SemanticEqualityOp, i.e. 'boolean equalSemantics(..)'
implemented by com.jogamp.gluegen.cgram.types.Type.
Semantic equality can be relaxed via config "RelaxedEqualSemanticsTest true",
i.e. ignoring integer size, and const / volatile qualifiers.
- All equality/hash methods of 'com.jogamp.gluegen.cgram.types.*'
are restructured.
- Track and simplify renamed 'symbol', i.e. use a common
sub-interface for all renamed symbols (ConstantDefinition, FunctionSymbol, ..)
- This is provided in a unified manner
via interface com.jogamp.gluegen.cgram.types.AliasedSymbol
and its common implementation AliasedSymbolImpl
- All JavaConfiguration.shouldIgnore* methods operate w/
'AliasedSymbol' trying to match all aliases.
- Support 'struct NAME [ { ... } ]' w/o typedef's
- New GL / CL headers do not use typedef's for anonymous opaque types
- Opaque Type handling
- JavaConfiguration.typeInfo(..), identifying opaque types,
no more back references from target-type -> typedef.
Hence the following is possible now:
typedef void * Opaque01; // Opaque
typedef void * APointerBuffer; // A Buffer
- All Logger instances are no more static
and derive their warning level from the package's root Logger
via Logging.getLogger(..).
Diffstat (limited to 'src/java/com/jogamp/gluegen/cgram')
20 files changed, 1130 insertions, 260 deletions
diff --git a/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java b/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java new file mode 100644 index 0000000..a924876 --- /dev/null +++ b/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java @@ -0,0 +1,154 @@ +/** + * Copyright 2015 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.gluegen.cgram.types; + +import java.util.HashSet; +import java.util.Set; + +/** + * Supports symbol aliasing, i.e. renaming, + * while preserving all its original names, i.e. aliases. + */ +public interface AliasedSymbol { + /** + * Rename this symbol with the given {@code newName} if not equal {@link #getName() current-name}. + * <p> + * Before renaming the {@link #getName() current-name} will be added + * to the list of {@link #getAliasedNames() aliases}. + * while the given {@code newName} will be removed. + * </p> + * @param newName the new {@link #getName() current-name} + */ + void rename(final String newName); + /** + * Add the given {@code origName} to the list of {@link #getAliasedNames() aliases} + * if not equal {@link #getName() current-name}. + * @param origName the new alias to be added + */ + void addAliasedName(final String origName); + /** + * + * Returns {@code true} if this symbol has aliases, i.e. either being {@link #rename(String) renamed} + * or {@link #addAliasedName(String) aliases-added}. + * <p> + * Otherwise {@code false} is being returned. + * </p> + */ + boolean hasAliases(); + /** + * Return all aliases for this symbol, i.e. original names, for this symbol. + * <p> + * Exclusive {@link #getName() current-name}. + * </p> + * <p> + * May return {@code null} or a zero sized {@link Set} for no aliases. + * </p> + */ + Set<String> getAliasedNames(); + /** + * Return the current-name, which is the last {@link #rename(String) renamed-name} if issued, + * or the original-name. + */ + String getName(); + /** + * Return this object's {@link #toString()} wrapped w/ the {@link #getName() current-name} + * and all {@link #getAliasedNames() aliases}. + */ + String getAliasedString(); + + public static class AliasedSymbolImpl implements AliasedSymbol { + private final HashSet<String> aliasedNames; + private String name; + + public AliasedSymbolImpl(final String origName) { + this.aliasedNames=new HashSet<String>(); + this.name = origName; + } + @Override + public void rename(final String newName) { + if( !name.equals(newName) ) { + aliasedNames.add(name); + aliasedNames.remove(newName); + name = newName; + } + } + @Override + public void addAliasedName(final String origName) { + if( !name.equals(origName) ) { + aliasedNames.add(origName); + } + } + @Override + public boolean hasAliases() { + return aliasedNames.size() > 0; + } + @Override + public Set<String> getAliasedNames() { + return aliasedNames; + } + @Override + public String getName() { + return name; + } + @Override + public String getAliasedString() { + return "["+name+", aliases "+aliasedNames.toString()+", "+toString()+"]"; + } + } + public static class NoneAliasedSymbol implements AliasedSymbol { + private final String name; + + public NoneAliasedSymbol(final String origName) { + this.name = origName; + } + @Override + public void rename(final String newName) { + throw new UnsupportedOperationException(); + } + @Override + public void addAliasedName(final String origName) { + throw new UnsupportedOperationException(); + } + @Override + public boolean hasAliases() { + return false; + } + @Override + public Set<String> getAliasedNames() { + return null; + } + @Override + public String getName() { + return name; + } + @Override + public String getAliasedString() { + return toString(); + } + } +} diff --git a/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java b/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java index d867b40..281c68d 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java @@ -48,7 +48,6 @@ package com.jogamp.gluegen.cgram.types; public class ArrayType extends MemoryLayoutType implements Cloneable { private final Type elementType; private final int length; - private String computedName; public ArrayType(final Type elementType, final SizeThunk sizeInBytes, final int length, final int cvAttributes) { super(elementType.getName() + " *", sizeInBytes, cvAttributes); @@ -57,24 +56,39 @@ public class ArrayType extends MemoryLayoutType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) return true; - if (arg == null || (!(arg instanceof ArrayType))) { - return false; - } + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = elementType.hashCode(); + return ((hash << 5) - hash) + length; + } + + @Override + protected boolean equalsImpl(final Type arg) { + final ArrayType t = (ArrayType) arg; + return elementType.equals(t.elementType) && + length == t.length; + } + + @Override + protected int hashCodeSemanticsImpl() { + // 31 * x == (x << 5) - x + final int hash = elementType.hashCodeSemantics(); + return ((hash << 5) - hash) + length; + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { final ArrayType t = (ArrayType) arg; - return (super.equals(arg) && elementType.equals(t.elementType) && (length == t.length)); + return elementType.equalSemantics(t.elementType) && + length == t.length; } @Override + public boolean hasName() { return null != elementType.getName(); } + + @Override public String getName(final boolean includeCVAttrs) { - // Lazy computation of name due to lazy setting of compound type - // names during parsing - // Note: don't think cvAttributes can be set for array types (unlike pointer types) - if (computedName == null) { - computedName = (elementType.getName() + " *").intern(); - } - return computedName; + return elementType.getName() + " *"; } @Override @@ -114,7 +128,7 @@ public class ArrayType extends MemoryLayoutType implements Cloneable { if(elementType.isConst()) { buf.append("const "); } - buf.append(elementType.getName()); + buf.append(elementType.getCName()); if (variableName != null) { buf.append(" "); buf.append(variableName); diff --git a/src/java/com/jogamp/gluegen/cgram/types/BitType.java b/src/java/com/jogamp/gluegen/cgram/types/BitType.java index 2644551..87eb8ce 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/BitType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/BitType.java @@ -40,6 +40,8 @@ package com.jogamp.gluegen.cgram.types; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; + /** Represents a bitfield in a struct. */ public class BitType extends IntType implements Cloneable { @@ -55,14 +57,35 @@ public class BitType extends IntType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) return true; - if (arg == null || (!(arg instanceof BitType))) { - return false; - } - final BitType t = (BitType) arg; - return (super.equals(arg) && underlyingType.equals(t.underlyingType) && - (sizeInBits == t.sizeInBits) && (offset == t.offset)); + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = underlyingType.hashCode(); + hash = ((hash << 5) - hash) + sizeInBits; + return ((hash << 5) - hash) + offset; + } + + @Override + protected boolean equalsImpl(final Type arg) { + final BitType t = (BitType) arg; + return underlyingType.equals(t.underlyingType) && + sizeInBits == t.sizeInBits && + offset == t.offset; + } + + @Override + protected int hashCodeSemanticsImpl() { + // 31 * x == (x << 5) - x + int hash = underlyingType.hashCodeSemantics(); + hash = ((hash << 5) - hash) + sizeInBits; + return ((hash << 5) - hash) + offset; + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { + final BitType t = (BitType) arg; + return underlyingType.equalSemantics(t.underlyingType) && + sizeInBits == t.sizeInBits && + offset == t.offset; } @Override diff --git a/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java b/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java index 9716f54..c3aca40 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java @@ -46,29 +46,67 @@ import java.util.*; and unions. The boolean type accessors indicate how the type is really defined. */ -public abstract class CompoundType extends MemoryLayoutType implements Cloneable { +public abstract class CompoundType extends MemoryLayoutType implements Cloneable, AliasedSymbol { // The name "foo" in the construct "struct foo { ... }"; - private String structName; + private final String structName; private ArrayList<Field> fields; private boolean visiting; private boolean bodyParsed; - private boolean computedHashcode; - private int hashcode; - + /** + * + * @param name + * @param size + * @param cvAttributes + * @param structName + */ CompoundType(final String name, final SizeThunk size, final int cvAttributes, final String structName) { super(name, size, cvAttributes); this.structName = structName; } - public static CompoundType create(final String name, final SizeThunk size, final CompoundTypeKind kind, final int cvAttributes) { + @Override + public void rename(final String newName) { + throw new UnsupportedOperationException(); + } + @Override + public void addAliasedName(final String origName) { + throw new UnsupportedOperationException(); + } + @Override + public boolean hasAliases() { + return false; + } + @Override + public Set<String> getAliasedNames() { + return null; + } + @Override + public String getAliasedString() { + return toString(); + } + + /** + * @param structName struct name of this CompoundType, i.e. the "foo" in the + construct {@code struct foo { int a, ... };} or {@code struct foo;} <i>even</i> for anonymous structs. + * @param size + * @param kind + * @param cvAttributes + * @return + */ + public static CompoundType create(final String structName, final SizeThunk size, final CompoundTypeKind kind, final int cvAttributes) + { + final CompoundType res; switch (kind) { case STRUCT: - return new StructType(name, size, cvAttributes); + res = new StructType(null, size, cvAttributes, structName); + break; case UNION: - return new UnionType(name, size, cvAttributes); + res = new UnionType(null, size, cvAttributes, structName); + break; default: throw new RuntimeException("OO relation "+kind+" / Compount not yet supported"); } + return res; } @Override @@ -81,34 +119,31 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable } @Override - public int hashCode() { - if (computedHashcode) { - return hashcode; - } + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = 31 + ( null != structName ? structName.hashCode() : 0 ); + return ((hash << 5) - hash) + TypeComparator.listsHashCode(fields); + } - if (structName != null) { - hashcode = structName.hashCode(); - } else if (getName() != null) { - hashcode = getName().hashCode(); - } else { - hashcode = 0; - } + @Override + protected boolean equalsImpl(final Type arg) { + final CompoundType ct = (CompoundType) arg; + return ( (structName == null ? ct.structName == null : structName.equals(ct.structName)) || + (structName != null && structName.equals(ct.structName)) + ) && + TypeComparator.listsEqual(fields, ct.fields); + } - computedHashcode = true; - return hashcode; + @Override + protected int hashCodeSemanticsImpl() { + // 31 * x == (x << 5) - x + return TypeComparator.listsHashCodeSemantics(fields); } @Override - public boolean equals(final Object arg) { - if (arg == this) return true; - if (arg == null || !(arg instanceof CompoundType)) { - return false; - } - final CompoundType t = (CompoundType) arg; - return super.equals(arg) && - ((structName == null ? t.structName == null : structName.equals(t.structName)) || - (structName != null && structName.equals(t.structName))) && - listsEqual(fields, t.fields); + protected boolean equalSemanticsImpl(final Type arg) { + final CompoundType ct = (CompoundType) arg; + return TypeComparator.listsEqualSemantics(fields, ct.fields); } /** Returns the struct name of this CompoundType, i.e. the "foo" in @@ -117,12 +152,6 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable return structName; } - /** Sets the struct name of this CompoundType, i.e. the "foo" in the - construct "struct foo { ... };". */ - public void setStructName(final String structName) { - this.structName = structName; - } - @Override public void setSize(final SizeThunk size) { super.setSize(size); @@ -131,8 +160,17 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable @Override public CompoundType asCompound() { return this; } + @Override + public String getCName(final boolean includeCVAttrs) { + if( hasTypedefName() ) { + return getName(includeCVAttrs); + } else { + return (isStruct() ? "struct " : "union ")+getName(includeCVAttrs); + } + } + ArrayList<Field> getFields() { return fields; } - void setFields(final ArrayList<Field> fields) { this.fields = fields; } + void setFields(final ArrayList<Field> fields) { this.fields = fields; clearCache(); } /** Returns the number of fields in this type. */ public int getNumFields() { @@ -147,18 +185,42 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable /** Adds a field to this type. */ public void addField(final Field f) { if (bodyParsed) { - throw new RuntimeException("Body of this CompoundType has already been parsed; should not be adding more fields"); + throw new IllegalStateException("Body of this CompoundType has been already closed"); } if (fields == null) { fields = new ArrayList<Field>(); } fields.add(f); + clearCache(); } - /** Indicates to this CompoundType that its body has been parsed and - that no more {@link #addField} operations will be made. */ - public void setBodyParsed() { + /** + * Indicates to this CompoundType that its body has been parsed and + * that no more {@link #addField} operations will be made. + * <p> + * If {@code evalStructTypeName} is {@code true}, {@link #evalStructTypeName()} is performed. + * </p> + * @throws IllegalStateException If called twice. + */ + public void setBodyParsed(final boolean evalStructTypeName) throws IllegalStateException { + if (bodyParsed) { + throw new IllegalStateException("Body of this CompoundType has been already closed"); + } bodyParsed = true; + if( evalStructTypeName ) { + evalStructTypeName(); + } + } + public boolean isBodyParsed() { return bodyParsed; } + /** + * {@link #getName() name} is set to {@link #getStructName() struct-name}, + * which promotes this instance for emission by its struct-name. + */ + public Type evalStructTypeName() { + if( null == getName() ) { + setName(structName); + } + return this; } /** Indicates whether this type was declared as a struct. */ @@ -169,8 +231,9 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable @Override public String toString() { final String cvAttributesString = getCVAttributesString(); - if (getName() != null) { - return cvAttributesString + getName(); + final String cname = getCName(); + if ( null != cname ) { + return cvAttributesString + cname; } else if (getStructName() != null) { return cvAttributesString + "struct " + getStructName(); } else { diff --git a/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java b/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java index de42522..1e13701 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java @@ -47,19 +47,28 @@ public class DoubleType extends PrimitiveType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) { - return true; - } - if (arg == null || (!(arg instanceof DoubleType))) { - return false; - } - return super.equals(arg); + public DoubleType asDouble() { + return this; } @Override - public DoubleType asDouble() { - return this; + protected int hashCodeImpl() { + return 0; + } + + @Override + protected boolean equalsImpl(final Type t) { + return true; + } + + @Override + protected int hashCodeSemanticsImpl() { + return 0; + } + + @Override + protected boolean equalSemanticsImpl(final Type t) { + return true; } @Override diff --git a/src/java/com/jogamp/gluegen/cgram/types/EnumType.java b/src/java/com/jogamp/gluegen/cgram/types/EnumType.java index 0b1193b..f0e71dc 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/EnumType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/EnumType.java @@ -42,6 +42,8 @@ package com.jogamp.gluegen.cgram.types; import java.util.ArrayList; import java.util.NoSuchElementException; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; + /** Describes enumerated types. Enumerations are like ints except that they have a set of named values. */ @@ -49,10 +51,9 @@ public class EnumType extends IntType implements Cloneable { private IntType underlyingType; - private static class Enum { - - String name; - long value; + private static class Enum implements TypeComparator.SemanticEqualityOp { + final String name; + final long value; Enum(final String name, final long value) { this.name = name; @@ -66,6 +67,37 @@ public class EnumType extends IntType implements Cloneable { long getValue() { return value; } + + @Override + public int hashCode() { + // 31 * x == (x << 5) - x + final int hash = name.hashCode(); + return ((hash << 5) - hash) + (int)(value ^ (value >>> 32)); + } + + @Override + public boolean equals(final Object arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof Enum) ) { + return false; + } + final Enum t = (Enum) arg; + return name.equals(t.name) && + value == t.value; + } + + @Override + public int hashCodeSemantics() { + return hashCode(); + } + + @Override + public boolean equalSemantics(final SemanticEqualityOp arg) { + return equals(arg); + } + + public String toString() { return name+" = "+value; } } private ArrayList<Enum> enums; @@ -98,17 +130,31 @@ public class EnumType extends IntType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) { - return true; - } - if (arg == null || (!(arg instanceof EnumType))) { - return false; - } + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = underlyingType.hashCode(); + return ((hash << 5) - hash) + TypeComparator.listsHashCode(enums); + } + + @Override + protected boolean equalsImpl(final Type arg) { final EnumType t = (EnumType) arg; - return (super.equals(arg) - && underlyingType.equals(t.underlyingType) - && listsEqual(enums, t.enums)); + return underlyingType.equals(t.underlyingType) && + TypeComparator.listsEqual(enums, t.enums); + } + + @Override + protected int hashCodeSemanticsImpl() { + // 31 * x == (x << 5) - x + final int hash = underlyingType.hashCodeSemantics(); + return ((hash << 5) - hash) + TypeComparator.listsHashCodeSemantics(enums); + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { + final EnumType t = (EnumType) arg; + return underlyingType.equalSemantics(t.underlyingType) && + TypeComparator.listsEqualSemantics(enums, t.enums); } @Override @@ -116,11 +162,14 @@ public class EnumType extends IntType implements Cloneable { return this; } + public Type getUnderlyingType() { return this.underlyingType; } + public void addEnum(final String name, final long val) { if (enums == null) { enums = new ArrayList<Enum>(); } enums.add(new Enum(name, val)); + clearCache(); } /** Number of enumerates defined in this enum. */ @@ -169,12 +218,24 @@ public class EnumType extends IntType implements Cloneable { final Enum e = enums.get(i); if (e.getName().equals(name)) { enums.remove(e); + clearCache(); return true; } } return false; } + public StringBuilder appendEnums(final StringBuilder sb, final boolean cr) { + for(int i=0; i<enums.size(); i++) { + sb.append(enums.get(i)).append(", "); + if( cr ) { + sb.append(String.format("%n")); + } + } + sb.append("}"); + return sb; + } + @Override public void visit(final TypeVisitor arg) { super.visit(arg); diff --git a/src/java/com/jogamp/gluegen/cgram/types/Field.java b/src/java/com/jogamp/gluegen/cgram/types/Field.java index 858d81a..a8fc599 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/Field.java +++ b/src/java/com/jogamp/gluegen/cgram/types/Field.java @@ -40,10 +40,11 @@ package com.jogamp.gluegen.cgram.types; import com.jogamp.common.os.MachineDataInfo; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; /** Represents a field in a struct or union. */ -public class Field { +public class Field implements SemanticEqualityOp { private final String name; private final Type type; private SizeThunk offset; @@ -56,21 +57,41 @@ public class Field { @Override public int hashCode() { - return name.hashCode(); + // 31 * x == (x << 5) - x + final int hash = 31 + ( null != name ? name.hashCode() : 0 ); + return ((hash << 5) - hash) + type.hashCode(); } @Override public boolean equals(final Object arg) { - if (arg == null || (!(arg instanceof Field))) { + if ( !(arg instanceof Field) ) { return false; } final Field f = (Field) arg; // Note: don't know how to examine offset any more since it's // implemented in terms of code and they're not canonicalized - return (((name != null && name.equals(f.name)) || - (name == null && f.name == null)) && - type.equals(f.type)); + return ( ( name != null && name.equals(f.name) ) || + ( name == null && f.name == null ) + ) && + type.equals(f.type); + } + + @Override + public int hashCodeSemantics() { + return type.hashCodeSemantics(); + } + + @Override + public boolean equalSemantics(final SemanticEqualityOp arg) { + if ( !(arg instanceof Field) ) { + return false; + } + + final Field f = (Field) arg; + // Note: don't know how to examine offset any more since it's + // implemented in terms of code and they're not canonicalized + return type.equalSemantics(f.type); } /** Name of this field in the containing data structure. */ diff --git a/src/java/com/jogamp/gluegen/cgram/types/FloatType.java b/src/java/com/jogamp/gluegen/cgram/types/FloatType.java index d8b0b13..0428543 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/FloatType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/FloatType.java @@ -48,18 +48,27 @@ public class FloatType extends PrimitiveType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) { + public FloatType asFloat() { return this; } + + @Override + protected int hashCodeImpl() { + return 0; + } + + @Override + protected boolean equalsImpl(final Type t) { return true; - } - if (arg == null || (!(arg instanceof FloatType))) { - return false; - } - return super.equals(arg); } @Override - public FloatType asFloat() { return this; } + protected int hashCodeSemanticsImpl() { + return 0; + } + + @Override + protected boolean equalSemanticsImpl(final Type t) { + return true; + } @Override Type newCVVariant(final int cvAttributes) { diff --git a/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java b/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java index d41f2fd..ee68b68 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java +++ b/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java @@ -38,6 +38,12 @@ */ package com.jogamp.gluegen.cgram.types; +import java.util.List; + +import com.jogamp.gluegen.cgram.types.AliasedSymbol.AliasedSymbolImpl; +import com.jogamp.gluegen.cgram.types.TypeComparator.AliasedSemanticSymbol; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; + /** * Describes a function symbol, which includes the name and @@ -51,20 +57,15 @@ package com.jogamp.gluegen.cgram.types; * Deep comparison can be performed via {@link #isCompletelyEqual(Object o)}; * </p> **/ -public class FunctionSymbol { +public class FunctionSymbol extends AliasedSymbolImpl implements AliasedSemanticSymbol { - private final String name; private final FunctionType type; public FunctionSymbol(final String name, final FunctionType type) { - this.name = name; + super(name); this.type = type; } - public String getName() { - return name; - } - /** Returns the type of this function. Do not add arguments to it directly; use addArgument instead. */ public FunctionType getType() { @@ -109,10 +110,10 @@ public class FunctionSymbol { @Override public int hashCode() { - if (name == null) { + if (getName() == null) { return 0; } - return name.hashCode(); + return getName().hashCode(); } @Override @@ -120,25 +121,54 @@ public class FunctionSymbol { if (arg == this) { return true; } - - if (arg == null || (!(arg instanceof FunctionSymbol))) { + if ( !(arg instanceof FunctionSymbol) ) { return false; } - final FunctionSymbol other = (FunctionSymbol) arg; - if (getName() == null && other.getName() != null) { return false; } - return getName().equals(other.getName()); } + @Override + public int hashCodeSemantics() { + return type.hashCodeSemantics(); + } + @Override + public final boolean equalSemantics(final SemanticEqualityOp arg) { + if (arg == this) { + return true; + } + if ( !(arg instanceof FunctionSymbol) ) { + return false; + } + final FunctionSymbol other = (FunctionSymbol) arg; + return type.equalSemantics(other.type); + } + + + public static boolean containsExactly(final List<FunctionSymbol> l, final FunctionSymbol s) { + return exactIndexOf(l, s) >= 0; + } + + public static int exactIndexOf(final List<FunctionSymbol> l, final FunctionSymbol s) { + final int size = l.size(); + for (int i = 0; i < size; i++) { + final FunctionSymbol e = l.get(i); + if( null == s && null == e || + s.equals( e ) && s.type.equals(e.type) ) { + return i; + } + } + return -1; + } + /** * Compares the function type as well, since {@link #equals(Object)} * and {@link #hashCode()} won't. */ - public boolean isCompletelyEqual(final Object arg) { + public boolean exactlyEqual(final Object arg) { if( !this.equals(arg) ) { return false; } diff --git a/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java b/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java index 4b39a34..b0d16e1 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java @@ -41,6 +41,8 @@ package com.jogamp.gluegen.cgram.types; import java.util.*; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; + /** Describes a function type, used to model both function declarations and (via PointerType) function pointers. */ public class FunctionType extends Type implements Cloneable { @@ -67,17 +69,31 @@ public class FunctionType extends Type implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) { - return true; - } - if (arg == null || (!(arg instanceof FunctionType))) { - return false; - } + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = returnType.hashCode(); + return ((hash << 5) - hash) + TypeComparator.listsHashCode(argumentTypes); + } + + @Override + protected boolean equalsImpl(final Type arg) { + final FunctionType t = (FunctionType) arg; + return returnType.equals(t.returnType) && + TypeComparator.listsEqual(argumentTypes, t.argumentTypes); + } + + @Override + protected int hashCodeSemanticsImpl() { + // 31 * x == (x << 5) - x + final int hash = returnType.hashCodeSemantics(); + return ((hash << 5) - hash) + TypeComparator.listsHashCodeSemantics(argumentTypes); + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { final FunctionType t = (FunctionType) arg; - return (super.equals(arg) - && returnType.equals(t.returnType) - && listsEqual(argumentTypes, t.argumentTypes)); + return returnType.equalSemantics(t.returnType) && + TypeComparator.listsEqualSemantics(argumentTypes, t.argumentTypes); } @Override @@ -115,10 +131,12 @@ public class FunctionType extends Type implements Cloneable { } argumentTypes.add(argumentType); argumentNames.add(argumentName); + clearCache(); } public void setArgumentName(final int i, final String name) { argumentNames.set(i, name); + clearCache(); } @Override @@ -136,7 +154,7 @@ public class FunctionType extends Type implements Cloneable { String toString(final String functionName, final String callingConvention, final boolean emitNativeTag, final boolean isPointer) { final StringBuilder res = new StringBuilder(); - res.append(getReturnType()); + res.append(getReturnType().getCName(true)); res.append(" "); if (isPointer) { res.append("("); @@ -169,7 +187,7 @@ public class FunctionType extends Type implements Cloneable { } else if (t.isArray()) { res.append(t.asArray().toString(getArgumentName(i))); } else { - res.append(t); + res.append(t.getCName(true)); final String argumentName = getArgumentName(i); if (argumentName != null) { res.append(" "); diff --git a/src/java/com/jogamp/gluegen/cgram/types/IntType.java b/src/java/com/jogamp/gluegen/cgram/types/IntType.java index 3f8dddc..502fe2a 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/IntType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/IntType.java @@ -55,20 +55,36 @@ public class IntType extends PrimitiveType implements Cloneable { } @Override - public boolean equals(final Object arg) { - if (arg == this) { - return true; - } - if (arg == null || (!(arg instanceof IntType))) { - return false; - } + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = 31 + ( unsigned ? 1 : 0 ); + return ((hash << 5) - hash) + ( typedefedUnsigned ? 1 : 0 ); + } + + @Override + protected boolean equalsImpl(final Type arg) { + final IntType t = (IntType) arg; + return unsigned == t.unsigned && + typedefedUnsigned == t.typedefedUnsigned; + } + + @Override + protected int hashCodeSemanticsImpl() { + return hashCodeImpl(); + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { final IntType t = (IntType) arg; - return (super.equals(arg) && (unsigned == t.unsigned)); + return relaxedEqSem || + ( unsigned == t.unsigned && + typedefedUnsigned == t.typedefedUnsigned + ); } @Override - public void setName(final String name) { - super.setName(name); + public void setTypedefName(final String name) { + super.setTypedefName(name); typedefedUnsigned = unsigned; } @@ -89,7 +105,7 @@ public class IntType extends PrimitiveType implements Cloneable { @Override public String toString() { - return getCVAttributesString() + ((isUnsigned() & (!typedefedUnsigned)) ? "unsigned " : "") + getName(); + return getCVAttributesString() + ((isUnsigned() & (!typedefedUnsigned)) ? "unsigned " : "") + getCName(); } @Override diff --git a/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java b/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java index 25d2d1d..fb8c86b 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java @@ -36,6 +36,8 @@ public abstract class MemoryLayoutType extends Type { } public boolean isLayouted() { return isLayouted; } - public void setLayouted() { isLayouted = true; } + public void setLayouted() { + isLayouted = true; + } } diff --git a/src/java/com/jogamp/gluegen/cgram/types/PointerType.java b/src/java/com/jogamp/gluegen/cgram/types/PointerType.java index d1dfb17..c6496bb 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/PointerType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/PointerType.java @@ -42,72 +42,68 @@ package com.jogamp.gluegen.cgram.types; public class PointerType extends Type implements Cloneable { private final Type targetType; - private String computedName; - private boolean hasTypedefedName; - public PointerType(final SizeThunk size, final Type targetType, final int cvAttributes) { + public PointerType(final SizeThunk size, final Type targetType, final int cvAttributes, final String typedefedName) { // can pass null for the final name parameter because the PointerType's getName() // completely replaces superclass behavior - this(size, targetType, cvAttributes, false, null); - } - - private PointerType(final SizeThunk size, final Type targetType, final int cvAttributes, final boolean hasTypedefedName, final String typedefedName) { super(targetType.getName() + " *", size, cvAttributes); - this.hasTypedefedName = false; this.targetType = targetType; - if (hasTypedefedName) { - setName(typedefedName); + if (null != typedefedName) { + setTypedefName(typedefedName); } } @Override - public int hashCode() { - return targetType.hashCode(); + protected int hashCodeImpl() { + return targetType.hashCode(); } @Override - public boolean equals(final Object arg) { - if (arg == this) { - return true; - } - if (arg == null || (!(arg instanceof PointerType))) { - return false; - } + protected boolean equalsImpl(final Type arg) { final PointerType t = (PointerType) arg; - // Note we ignore the name of this type (which might be a typedef - // name) for comparison purposes because this is what allows - // e.g. a newly-fabricated type "PIXELFORMATDESCRIPTOR *" to be - // canonicalized to e.g. "LPPIXELFORMATDESCRIPTOR" - return ((getSize() == t.getSize()) - && (getCVAttributes() == t.getCVAttributes()) - && targetType.equals(t.targetType)); + return targetType.equals(t.targetType); + } + + @Override + protected int hashCodeSemanticsImpl() { + return targetType.hashCodeSemantics(); + } + + @Override + protected boolean equalSemanticsImpl(final Type arg) { + final PointerType pt = (PointerType) arg; + return targetType.equalSemantics(pt.targetType); } @Override - public void setName(final String name) { - super.setName(name); - hasTypedefedName = true; + public boolean hasName() { + if ( hasTypedefName() ) { + return super.hasName(); + } else { + return targetType.hasName(); + } } @Override public String getName(final boolean includeCVAttrs) { - if (hasTypedefedName) { + if ( hasTypedefName() ) { return super.getName(includeCVAttrs); + } else if (!includeCVAttrs) { + return targetType.getName(includeCVAttrs) + " *"; } else { - // Lazy computation of name due to lazy setting of compound type - // names during parsing - if (computedName == null) { - computedName = (targetType.getName(includeCVAttrs) + " *").intern(); - } - if (!includeCVAttrs) { - return computedName; - } return targetType.getName(includeCVAttrs) + " * " + getCVAttributesString(); } } - public boolean hasTypedefedName() { - return hasTypedefedName; + @Override + public String getCName(final boolean includeCVAttrs) { + if ( hasTypedefName() ) { + return super.getCName(includeCVAttrs); + } else if (!includeCVAttrs) { + return targetType.getCName(includeCVAttrs) + " *"; + } else { + return targetType.getCName(includeCVAttrs) + " * " + getCVAttributesString(); + } } @Override @@ -115,6 +111,7 @@ public class PointerType extends Type implements Cloneable { return this; } + @Override public Type getTargetType() { return targetType; } @@ -137,13 +134,18 @@ public class PointerType extends Type implements Cloneable { @Override public String toString() { - if (hasTypedefedName) { - return super.getName(true); + if ( hasTypedefName() ) { + return super.getCName(true); + } else { + return toStringInt(); + } + } + private String toStringInt() { + if (!targetType.isFunction()) { + return targetType.getCName(true) + " * " + getCVAttributesString(); } else { - if (!targetType.isFunction()) { - return targetType.toString() + " * " + getCVAttributesString(); - } - return toString(null, null); // this is a pointer to an unnamed function + // return toString(null, null); // this is a pointer to an unnamed function + return ((FunctionType) targetType).toString(null /* functionName */, null /* callingConvention */, false, true); } } @@ -165,6 +167,6 @@ public class PointerType extends Type implements Cloneable { @Override Type newCVVariant(final int cvAttributes) { - return new PointerType(getSize(), targetType, cvAttributes, hasTypedefedName, (hasTypedefedName ? getName() : null)); + return new PointerType(getSize(), targetType, cvAttributes, (hasTypedefName() ? getName() : null)); } } diff --git a/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java b/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java index 9843d6b..7a9c62a 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java +++ b/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java @@ -41,17 +41,25 @@ package com.jogamp.gluegen.cgram.types; import com.jogamp.common.os.MachineDataInfo; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; /** Provides a level of indirection between the definition of a type's size and the absolute value of this size. Necessary when generating glue code for two different CPU architectures (e.g., 32-bit and 64-bit) from the same internal representation of the various types involved. */ -public abstract class SizeThunk implements Cloneable { +public abstract class SizeThunk implements Cloneable, SemanticEqualityOp { + /* pp */ static boolean relaxedEqSem = false; private final boolean fixedNativeSize; + public static void setRelaxedEqualSemanticsTest(final boolean v) { + relaxedEqSem = v; + } + // Private constructor because there are only a few of these - private SizeThunk(final boolean fixedNativeSize) { this.fixedNativeSize = fixedNativeSize; } + private SizeThunk(final boolean fixedNativeSize) { + this.fixedNativeSize = fixedNativeSize; + } @Override public Object clone() { @@ -67,6 +75,55 @@ public abstract class SizeThunk implements Cloneable { public abstract long computeSize(MachineDataInfo machDesc); public abstract long computeAlignment(MachineDataInfo machDesc); + @Override + public final int hashCode() { + final int hash = 0x02DEAD6F; // magic hash start + return ((hash << 5) - hash) + hashCodeImpl(); + } + /* pp */ abstract int hashCodeImpl(); + + @Override + public final boolean equals(final Object arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof SizeThunk) ) { + return false; + } else { + final SizeThunk t = (SizeThunk) arg; + return hashCodeImpl() == t.hashCodeImpl(); + } + } + + @Override + public final int hashCodeSemantics() { + final int hash = 0x01DEAD5F; // magic hash start + return ((hash << 5) - hash) + hashCodeSemanticsImpl(); + } + /* pp */ abstract int hashCodeSemanticsImpl(); + + @Override + public final boolean equalSemantics(final SemanticEqualityOp arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof SizeThunk) ) { + return false; + } else { + final SizeThunk t = (SizeThunk) arg; + return hashCodeSemanticsImpl() == t.hashCodeSemanticsImpl(); + } + } + + static final int magic_int08 = 0x00000010; + static final int magic_int16 = 0x00000012; + static final int magic_int32 = 0x00000014; + static final int magic_intxx = 0x00000016; + static final int magic_long64 = 0x00000020; + static final int magic_longxx = 0x00000022; + static final int magic_float32 = 0x00000030; + static final int magic_float64 = 0x00000032; + static final int magic_aptr64 = 0x00000040; + static final int magic_ops = 0x00010000; + public static final SizeThunk INT8 = new SizeThunk(true) { @Override public long computeSize(final MachineDataInfo machDesc) { @@ -76,6 +133,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.int8AlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 1; } + @Override + protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_int32 : magic_int08; } }; public static final SizeThunk INT16 = new SizeThunk(true) { @@ -87,6 +148,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.int16AlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 2; } + @Override + protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_int32 : magic_int16; } }; public static final SizeThunk INT32 = new SizeThunk(true) { @@ -98,6 +163,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.int32AlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 3; } + @Override + protected int hashCodeSemanticsImpl() { return magic_int32; } }; public static final SizeThunk INTxx = new SizeThunk(false) { @@ -109,6 +178,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.intAlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 4; } + @Override + protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_int32 : magic_intxx; } }; public static final SizeThunk LONG = new SizeThunk(false) { @@ -120,6 +193,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.longAlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 5; } + @Override + protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_long64 : magic_longxx; } }; public static final SizeThunk INT64 = new SizeThunk(true) { @@ -131,6 +208,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.int64AlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 6; } + @Override + protected int hashCodeSemanticsImpl() { return magic_long64; } }; public static final SizeThunk FLOAT = new SizeThunk(true) { @@ -142,6 +223,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.floatAlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 7; } + @Override + protected int hashCodeSemanticsImpl() { return magic_float32; } }; public static final SizeThunk DOUBLE = new SizeThunk(true) { @@ -153,6 +238,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.doubleAlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 8; } + @Override + protected int hashCodeSemanticsImpl() { return magic_float64; } }; public static final SizeThunk POINTER = new SizeThunk(false) { @@ -164,6 +253,10 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return machDesc.pointerAlignmentInBytes(); } + @Override + protected int hashCodeImpl() { return 9; } + @Override + protected int hashCodeSemanticsImpl() { return magic_aptr64; } }; // Factory methods for performing certain limited kinds of @@ -181,6 +274,15 @@ public abstract class SizeThunk implements Cloneable { final long thunk2A = thunk2.computeAlignment(machDesc); return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ; } + @Override + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = 31 + 10; + hash = ((hash << 5) - hash) + ( null != thunk1 ? thunk1.hashCode() : 0 ); + return ((hash << 5) - hash) + ( null != thunk2 ? thunk2.hashCode() : 0 ); + } + @Override + protected int hashCodeSemanticsImpl() { return magic_ops + 1; } }; } @@ -197,6 +299,15 @@ public abstract class SizeThunk implements Cloneable { final long thunk2A = thunk2.computeAlignment(machDesc); return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ; } + @Override + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = 31 + 11; + hash = ((hash << 5) - hash) + ( null != thunk1 ? thunk1.hashCode() : 0 ); + return ((hash << 5) - hash) + ( null != thunk2 ? thunk2.hashCode() : 0 ); + } + @Override + protected int hashCodeSemanticsImpl() { return magic_ops + 2; } }; } @@ -239,6 +350,15 @@ public abstract class SizeThunk implements Cloneable { final long thunk2A = alignmentThunk.computeAlignment(machDesc); return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ; } + @Override + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = 31 + 12; + hash = ((hash << 5) - hash) + ( null != offsetThunk ? offsetThunk.hashCode() : 0 ); + return ((hash << 5) - hash) + ( null != alignmentThunk ? alignmentThunk.hashCode() : 0 ); + } + @Override + protected int hashCodeSemanticsImpl() { return magic_ops + 3; } }; } @@ -255,6 +375,15 @@ public abstract class SizeThunk implements Cloneable { final long thunk2A = thunk2.computeAlignment(machDesc); return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ; } + @Override + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = 31 + 13; + hash = ((hash << 5) - hash) + ( null != thunk1 ? thunk1.hashCode() : 0 ); + return ((hash << 5) - hash) + ( null != thunk2 ? thunk2.hashCode() : 0 ); + } + @Override + protected int hashCodeSemanticsImpl() { return magic_ops + 4; } }; } @@ -268,6 +397,14 @@ public abstract class SizeThunk implements Cloneable { public long computeAlignment(final MachineDataInfo machDesc) { return 1; // no alignment for constants } + @Override + protected int hashCodeImpl() { + // 31 * x == (x << 5) - x + final int hash = 31 + 14; + return ((hash << 5) - hash) + constant; + } + @Override + protected int hashCodeSemanticsImpl() { return magic_ops + 5; } }; } } diff --git a/src/java/com/jogamp/gluegen/cgram/types/StructType.java b/src/java/com/jogamp/gluegen/cgram/types/StructType.java index 27099e9..4998484 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/StructType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/StructType.java @@ -38,14 +38,6 @@ public class StructType extends CompoundType { } @Override - public boolean equals(final Object arg) { - if (arg == null || !(arg instanceof StructType)) { - return false; - } - return super.equals(arg); - } - - @Override public final boolean isStruct() { return true; } @Override public final boolean isUnion() { return false; } @@ -54,6 +46,9 @@ public class StructType extends CompoundType { Type newCVVariant(final int cvAttributes) { final StructType t = new StructType(getName(), getSize(), cvAttributes, getStructName()); t.setFields(getFields()); + if( hasTypedefName() ) { + t.setTypedefName( getName() ); + } return t; } diff --git a/src/java/com/jogamp/gluegen/cgram/types/Type.java b/src/java/com/jogamp/gluegen/cgram/types/Type.java index 28ba6b4..cd48aa0 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/Type.java +++ b/src/java/com/jogamp/gluegen/cgram/types/Type.java @@ -40,27 +40,45 @@ package com.jogamp.gluegen.cgram.types; -import java.util.List; - import com.jogamp.common.os.MachineDataInfo; +import com.jogamp.gluegen.GlueGen; +import com.jogamp.gluegen.TypeConfig; +import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp; /** Models a C type. Primitive types include int, float, and double. All types have an associated name. Structs and unions are modeled as "compound" types -- composed of fields of primitive or other types. */ -public abstract class Type implements Cloneable { - +public abstract class Type implements Cloneable, SemanticEqualityOp { + public final boolean relaxedEqSem; + private final int cvAttributes; private String name; private SizeThunk size; - private final int cvAttributes; private int typedefedCVAttributes; private boolean hasTypedefName; + private boolean hasCachedHash; + private int cachedHash; + private boolean hasCachedSemanticHash; + private int cachedSemanticHash; protected Type(final String name, final SizeThunk size, final int cvAttributes) { setName(name); - this.size = size; + this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest(); this.cvAttributes = cvAttributes; - hasTypedefName = false; + this.size = size; + this.typedefedCVAttributes = 0; + this.hasTypedefName = false; + this.hasCachedHash = false; + this.cachedHash = 0; + this.hasCachedSemanticHash = false; + this.cachedSemanticHash = 0; + } + + protected final void clearCache() { + cachedHash = 0; + hasCachedHash = false; + cachedSemanticHash = 0; + hasCachedHash = false; } @Override @@ -72,14 +90,28 @@ public abstract class Type implements Cloneable { } } + public final boolean isAnonymous() { return null == name; } + + public boolean hasName() { return null != name; } + + /** Returns the name of this type. The returned string is suitable + for use as a type specifier for native C. Does not include any const/volatile + attributes. */ + public final String getCName() { return getCName(false); } + + /** Returns the name of this type, optionally including + const/volatile attributes. The returned string is suitable for + use as a type specifier for native C. */ + public String getCName(final boolean includeCVAttrs) { return getName(includeCVAttrs); } + /** Returns the name of this type. The returned string is suitable - for use as a type specifier. Does not include any const/volatile + for use as a type specifier for Java. Does not include any const/volatile attributes. */ public final String getName() { return getName(false); } /** Returns the name of this type, optionally including const/volatile attributes. The returned string is suitable for - use as a type specifier. */ + use as a type specifier for Java. */ public String getName(final boolean includeCVAttrs) { if (!includeCVAttrs) { return name; @@ -87,6 +119,18 @@ public abstract class Type implements Cloneable { return getCVAttributesString() + name; } + /** + * Returns a string representation of this type. + * The returned string is suitable for use as a type specifier for native C. + * It does contain an expanded description of structs/unions, + * hence may not be suitable for type declarations. + */ + @Override + public String toString() { + return getCName(true); + } + + private void append(final StringBuilder sb, final String val, final boolean prepComma) { if( prepComma ) { sb.append(", "); @@ -98,15 +142,30 @@ public abstract class Type implements Cloneable { final StringBuilder sb = new StringBuilder(); boolean prepComma = false; sb.append("CType["); + sb.append("(").append(getClass().getSimpleName()).append(") "); + if( hasTypedefName() ) { + sb.append("typedef "); + } if( null != name ) { - append(sb, "'"+name+"'", prepComma); prepComma=true; + sb.append("'").append(name).append("'"); } else { - append(sb, "ANON", prepComma); prepComma=true; + sb.append("ANON"); } - if( hasTypedefName() ) { - sb.append(" (typedef)"); + final Type targetType = getTargetType(); + if( null != targetType && this != targetType ) { + sb.append(" -> "); + if (!targetType.isFunction()) { + sb.append(targetType.toString() + " * " + getCVAttributesString()); + } else { + sb.append(((FunctionType) targetType).toString(null /* functionName */, null /* callingConvention */, false, true)); + } + } + if( GlueGen.debug() ) { + // sb.append(", o=0x"+Integer.toHexString(objHash())+" h=0x"+Integer.toHexString(hashCode())); + sb.append(", o=0x"+Integer.toHexString(objHash())); } - append(sb, "size ", prepComma); prepComma=true; + sb.append(", size "); + prepComma=true; if( null != size ) { final long mdSize; { @@ -137,14 +196,17 @@ public abstract class Type implements Cloneable { append(sb, "bit", prepComma); prepComma=true; } if( isCompound() ) { - sb.append("struct{").append(asCompound().getNumFields()); + sb.append("struct{").append(asCompound().getStructName()).append(": ").append(asCompound().getNumFields()); append(sb, "}", prepComma); prepComma=true; } if( isDouble() ) { append(sb, "double", prepComma); prepComma=true; } if( isEnum() ) { - append(sb, "enum", prepComma); prepComma=true; + final EnumType eT = asEnum(); + sb.append("enum ").append(" [").append(eT.getUnderlyingType()).append("] {").append(eT.getNumEnumerates()).append(": "); + eT.appendEnums(sb, false); + prepComma=true; } if( isFloat() ) { append(sb, "float", prepComma); prepComma=true; @@ -164,20 +226,33 @@ public abstract class Type implements Cloneable { sb.append("]]"); return sb.toString(); } + private final int objHash() { return super.hashCode(); } - /** Set the name of this type; used for handling typedefs. */ - public void setName(final String name) { + + protected final void setName(final String name) { if (name == null) { this.name = name; } else { this.name = name.intern(); } + clearCache(); + } + + /** Set the name of this type; used for handling typedefs. */ + public void setTypedefName(final String name) { + setName(name); // Capture the const/volatile attributes at the time of typedef so // we don't redundantly repeat them in the CV attributes string typedefedCVAttributes = cvAttributes; hasTypedefName = true; } + /** Indicates whether {@link #setTypedefName(String)} has been called on this type, + indicating that it already has a typedef name. */ + public final boolean hasTypedefName() { + return hasTypedefName; + } + /** SizeThunk which computes size of this type in bytes. */ public SizeThunk getSize() { return size; } /** Size of this type in bytes according to the given MachineDataInfo. */ @@ -189,7 +264,10 @@ public abstract class Type implements Cloneable { return thunk.computeSize(machDesc); } /** Set the size of this type; only available for CompoundTypes. */ - void setSize(final SizeThunk size) { this.size = size; } + void setSize(final SizeThunk size) { + this.size = size; + clearCache(); + } /** Casts this to a BitType or returns null if not a BitType. */ public BitType asBit() { return null; } @@ -249,43 +327,92 @@ public abstract class Type implements Cloneable { /** Hashcode for Types. */ @Override - public int hashCode() { - if (name == null) { - return 0; - } - - if (cvAttributes != 0) { - final String nameWithAttribs = name + cvAttributes; - return nameWithAttribs.hashCode(); + public final int hashCode() { + if( !hasCachedHash ) { + // 31 * x == (x << 5) - x + int hash = 31 + ( hasTypedefName ? 1 : 0 ); + hash = ((hash << 5) - hash) + ( null != size ? size.hashCode() : 0 ); + hash = ((hash << 5) - hash) + cvAttributes; + hash = ((hash << 5) - hash) + ( null != name ? name.hashCode() : 0 ); + if( !hasTypedefName ) { + hash = ((hash << 5) - hash) + hashCodeImpl(); + } + cachedHash = hash; + hasCachedHash = true; } - return name.hashCode(); + return cachedHash; } + protected abstract int hashCodeImpl(); /** - * Equality test for Types. + * Equality test for Types inclusive its given {@link #getName() name}. */ @Override - public boolean equals(final Object arg) { + public final boolean equals(final Object arg) { if (arg == this) { - return true; + return true; + } else if ( !getClass().isInstance(arg) ) { // implies null == arg || !(arg instanceof Type) + return false; + } else { + final Type t = (Type)arg; + if( hasTypedefName == t.hasTypedefName && + ( ( null != size && size.equals(t.size) ) || + ( null == size && null == t.size ) + ) && + cvAttributes == t.cvAttributes && + ( null == name ? null == t.name : name.equals(t.name) ) + ) + { + if( !hasTypedefName ) { + return equalsImpl(t); + } else { + return true; + } + } else { + return false; + } } + } + protected abstract boolean equalsImpl(final Type t); - if ( !(arg instanceof Type) ) { - return false; + @Override + public final int hashCodeSemantics() { + if( !hasCachedSemanticHash ) { + // 31 * x == (x << 5) - x + int hash = 31 + ( null != size ? size.hashCodeSemantics() : 0 ); + if( !relaxedEqSem ) { + hash = ((hash << 5) - hash) + cvAttributes; + } + hash = ((hash << 5) - hash) + hashCodeSemanticsImpl(); + cachedSemanticHash = hash; + hasCachedSemanticHash = true; } - - final Type t = (Type)arg; - return size == t.size && cvAttributes == t.cvAttributes && - ( null == name ? null == t.name : name.equals(t.name) ) ; + return cachedSemanticHash; } + protected abstract int hashCodeSemanticsImpl(); - /** Returns a string representation of this type. This string is not - necessarily suitable for use as a type specifier; for example, - it will contain an expanded description of structs/unions. */ @Override - public String toString() { - return getName(true); + public final boolean equalSemantics(final SemanticEqualityOp arg) { + if (arg == this) { + return true; + } else if ( !(arg instanceof Type) || + !getClass().isInstance(arg) ) { // implies null == arg + return false; + } else { + final Type t = (Type) arg; + if( ( ( null != size && size.equalSemantics(t.size) ) || + ( null == size && null == t.size ) + ) && + ( relaxedEqSem || cvAttributes == t.cvAttributes ) + ) + { + return equalSemanticsImpl(t); + } else { + return false; + } + } } + protected abstract boolean equalSemanticsImpl(final Type t); /** Visit this type and all of the component types of this one; for example, the return type and argument types of a FunctionType. */ @@ -319,12 +446,6 @@ public abstract class Type implements Cloneable { const/volatile attributes. */ abstract Type newCVVariant(int cvAttributes); - /** Indicates whether setName() has been called on this type, - indicating that it already has a typedef name. */ - public boolean hasTypedefName() { - return hasTypedefName; - } - /** Helper method for determining how many pointer indirections this type represents (i.e., "void **" returns 2). Returns 0 if this type is not a pointer type. */ @@ -358,8 +479,10 @@ public abstract class Type implements Cloneable { return this; } - /** Helper routine for list equality comparison */ - static <C> boolean listsEqual(final List<C> a, final List<C> b) { - return ((a == null && b == null) || (a != null && b != null && a.equals(b))); + /** + * Helper method to returns the target type of this type, in case another type is being referenced. + */ + public Type getTargetType() { + return this; } } diff --git a/src/java/com/jogamp/gluegen/cgram/types/TypeComparator.java b/src/java/com/jogamp/gluegen/cgram/types/TypeComparator.java new file mode 100644 index 0000000..850d953 --- /dev/null +++ b/src/java/com/jogamp/gluegen/cgram/types/TypeComparator.java @@ -0,0 +1,143 @@ +/** + * Copyright 2015 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.gluegen.cgram.types; + +import java.util.List; + +public class TypeComparator { + /** + * Supports semantic equality and hash functions for types. + */ + public static interface SemanticEqualityOp { + /** + * Semantic hashcode for Types exclusive its given {@link #getName() name}. + * @see #equalSemantics(SemanticEqualityOp) + */ + int hashCodeSemantics(); + + /** + * Semantic equality test for Types exclusive its given {@link #getName() name}. + * @see #hashCodeSemantics() + */ + boolean equalSemantics(final SemanticEqualityOp arg); + } + /** + * Supports common interface for {@link SemanticEqualityOp} and {@link AliasedSymbol}. + */ + public static interface AliasedSemanticSymbol extends AliasedSymbol, SemanticEqualityOp { }; + + /** Helper routine for list equality comparison*/ + static <C> boolean listsEqual(final List<C> a, final List<C> b) { + if( a == null ) { + if( null != b ) { + return false; + } else { + return true; // elements equal, i.e. both null + } + } + if( b != null && a.size() == b.size() ) { + final int count = a.size(); + for(int i=0; i<count; i++) { + final C ac = a.get(i); + final C bc = b.get(i); + if( null == ac ) { + if( null != bc ) { + return false; + } else { + continue; // elements equal, i.e. both null + } + } + if( !ac.equals(bc) ) { + return false; + } + } + return true; + } + return false; + } + + /** Helper routine for list hashCode */ + static <C extends SemanticEqualityOp> int listsHashCode(final List<C> a) { + if( a == null ) { + return 0; + } else { + final int count = a.size(); + int hash = 31; + for(int i=0; i<count; i++) { + final C ac = a.get(i); + hash = ((hash << 5) - hash) + ( null != ac ? ac.hashCode() : 0 ); + } + return hash; + } + } + + /** Helper routine for list semantic equality comparison*/ + static <C extends SemanticEqualityOp> boolean listsEqualSemantics(final List<C> a, final List<C> b) { + if( a == null ) { + if( null != b ) { + return false; + } else { + return true; // elements equal, i.e. both null + } + } + if( b != null && a.size() == b.size() ) { + final int count = a.size(); + for(int i=0; i<count; i++) { + final C ac = a.get(i); + final C bc = b.get(i); + if( null == ac ) { + if( null != bc ) { + return false; + } else { + continue; // elements equal, i.e. both null + } + } + if( !ac.equalSemantics(bc) ) { + return false; + } + } + return true; + } + return false; + } + + /** Helper routine for list hashCode */ + static <C extends SemanticEqualityOp> int listsHashCodeSemantics(final List<C> a) { + if( a == null ) { + return 0; + } else { + final int count = a.size(); + int hash = 31; + for(int i=0; i<count; i++) { + final C ac = a.get(i); + hash = ((hash << 5) - hash) + ( null != ac ? ac.hashCodeSemantics() : 0 ); + } + return hash; + } + } +} diff --git a/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java b/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java index cd03388..c1cfcdf 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java +++ b/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java @@ -41,6 +41,9 @@ package com.jogamp.gluegen.cgram.types; import java.util.*; +import com.jogamp.gluegen.GlueGen; +import com.jogamp.gluegen.JavaConfiguration; + /** Utility class for recording names of typedefs and structs. */ @@ -63,6 +66,38 @@ public class TypeDictionary { return map.get(name); } + public List<Type> getEqualSemantics(final Type s, final JavaConfiguration cfg, final boolean skipOpaque) { + final List<Type> res = new ArrayList<Type>(); + if( !skipOpaque || null == cfg.typeInfo(s) ) { + final Set<Map.Entry<String, Type>> entries = entrySet(); + for(final Iterator<Map.Entry<String, Type>> iter = entries.iterator(); iter.hasNext(); ) { + final Map.Entry<String, Type> entry = iter.next(); + final Type t = entry.getValue(); + if( s.equalSemantics(t) ) { + if( !skipOpaque || null == cfg.typeInfo(t) ) { + if( GlueGen.debug() ) { + System.err.println(" tls["+res.size()+"]: -> "+entry.getKey()+" -> "+t.getDebugString()); + } + res.add(t); + } + } + } + } + return res; + } + public Type getEqualSemantics1(final Type s, final JavaConfiguration cfg, final boolean skipOpaque) { + final List<Type> tls = getEqualSemantics(s, cfg, skipOpaque); + if( tls.size() > 0 ) { + final Type res = tls.get(0); + if( GlueGen.debug() ) { + System.err.println(" tls.0: "+res.getDebugString()); + } + return res; + } else { + return null; + } + } + //this method is broken /** * Get the names that correspond to the given type. There will be more than diff --git a/src/java/com/jogamp/gluegen/cgram/types/UnionType.java b/src/java/com/jogamp/gluegen/cgram/types/UnionType.java index 99d2fed..6ccc4a2 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/UnionType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/UnionType.java @@ -38,14 +38,6 @@ public class UnionType extends CompoundType { } @Override - public boolean equals(final Object arg) { - if (arg == null || !(arg instanceof UnionType)) { - return false; - } - return super.equals(arg); - } - - @Override public final boolean isStruct() { return false; } @Override public final boolean isUnion() { return true; } @@ -54,6 +46,9 @@ public class UnionType extends CompoundType { Type newCVVariant(final int cvAttributes) { final UnionType t = new UnionType(getName(), getSize(), cvAttributes, getStructName()); t.setFields(getFields()); + if( hasTypedefName() ) { + t.setTypedefName( getName() ); + } return t; } diff --git a/src/java/com/jogamp/gluegen/cgram/types/VoidType.java b/src/java/com/jogamp/gluegen/cgram/types/VoidType.java index 2e1f069..f6adaac 100644 --- a/src/java/com/jogamp/gluegen/cgram/types/VoidType.java +++ b/src/java/com/jogamp/gluegen/cgram/types/VoidType.java @@ -58,4 +58,24 @@ public class VoidType extends Type implements Cloneable { Type newCVVariant(final int cvAttributes) { return new VoidType(getName(), cvAttributes); } + + @Override + protected int hashCodeImpl() { + return 0; + } + + @Override + protected boolean equalsImpl(final Type t) { + return true; + } + + @Override + protected int hashCodeSemanticsImpl() { + return 0; + } + + @Override + protected boolean equalSemanticsImpl(final Type t) { + return true; + } } |