Commits

Michael Ludwig committed 7737837

Remove TypeId and update main API to use Classes instead.

Comments (0)

Files changed (5)

src/main/java/com/lhkbob/entreri/Component.java

      *         component is not live
      */
     public T getData() {
-        T data = getEntitySystem().createDataInstance(getTypeId());
+        T data = getEntitySystem().createDataInstance(getType());
         if (data.set(this)) {
             return data;
         } else {
     /**
      * @return The TypeId of the ComponentData for this Component
      */
-    public TypeId<T> getTypeId() {
-        return owner.getTypeId();
+    public Class<T> getType() {
+        return owner.getType();
     }
 
     /**

src/main/java/com/lhkbob/entreri/ComponentRepository.java

  */
 final class ComponentRepository<T extends ComponentData<T>> {
     private final EntitySystem system;
-    private final TypeId<T> type;
+    private final Class<T> type;
 
     private final ComponentDataFactory<T> factory;
 
      * @throws NullPointerException if system or type are null
      */
     @SuppressWarnings({"rawtypes", "unchecked"})
-    public ComponentRepository(EntitySystem system, TypeId<T> type,
+    public ComponentRepository(EntitySystem system, Class<T> type,
                                ComponentDataFactory<T> factory) {
         if (system == null || type == null) {
             throw new NullPointerException("Arguments cannot be null");
     /**
      * @return The type of component data stored by this component index
      */
-    public TypeId<T> getTypeId() {
+    public Class<T> getType() {
         return type;
     }
 
         if (fromTemplate.getEntitySystem() != getEntitySystem()) {
             throw new IllegalArgumentException("Component not owned by expected EntitySystem");
         }
-        if (!fromTemplate.getTypeId().equals(type)) {
+        if (!fromTemplate.getClass().equals(type)) {
             throw new IllegalArgumentException("Component not of expected type, expected: " + type + ", but was: " + type);
         }
         if (!fromTemplate.isLive()) {

src/main/java/com/lhkbob/entreri/Entity.java

      * </p>
      * <p>
      * If the entity has a component of the given type, but it has been marked
-     * as disabled, this will return null. Use {@link #get(TypeId, boolean)} to
+     * as disabled, this will return null. Use {@link #get(Class, boolean)} to
      * override this behavior and return disabled components.
      * </p>
      * 
      * @param <T> The parameterized type of ComponentData of the component
-     * @param componentId The TypeId representing the given type
+     * @param componentType The given type
      * @return The current Component of type T attached to this entity
      * @throws NullPointerException if id is null
      */
-    public <T extends ComponentData<T>> Component<T> get(TypeId<T> componentId) {
-        return get(componentId, false);
+    public <T extends ComponentData<T>> Component<T> get(Class<T> componentType) {
+        return get(componentType, false);
     }
 
     /**
      * be returned as well.
      * 
      * @param <T> The parameterized type of ComponentData of the component
-     * @param componentId The TypeId representing the data type
+     * @param componentType The data type
      * @param ignoreEnable True if disabled components should be returned as
      *            well
      * @return The current Component of type T attached to this entity
-     * @throws NullPointerException if id is null
+     * @throws NullPointerException if componentType is null
      */
-    public <T extends ComponentData<T>> Component<T> get(TypeId<T> componentId,
+    public <T extends ComponentData<T>> Component<T> get(Class<T> componentType,
                                                          boolean ignoreEnable) {
-        ComponentRepository<T> ci = system.getRepository(componentId);
+        ComponentRepository<T> ci = system.getRepository(componentType);
         Component<T> c = ci.getComponent(ci.getComponentIndex(index));
 
         if (c == null || ignoreEnable || c.isEnabled()) {
      * </p>
      * 
      * @param <T> The parameterized type of component being added
-     * @param componentId The TypeId of the component type
+     * @param componentType The component type
      * @return A new component of type T
      * @throws NullPointerException if componentId is null
      */
-    public <T extends ComponentData<T>> Component<T> add(TypeId<T> componentId) {
-        ComponentRepository<T> ci = system.getRepository(componentId);
+    public <T extends ComponentData<T>> Component<T> add(Class<T> componentType) {
+        ComponentRepository<T> ci = system.getRepository(componentType);
         return ci.addComponent(index);
     }
 
         if (toClone == null) {
             throw new NullPointerException("ComponentData template, toClone, cannot be null");
         }
-        ComponentRepository ci = system.getRepository(toClone.getTypeId());
+        ComponentRepository ci = system.getRepository(toClone.getType());
         return ci.addComponent(index, toClone);
     }
 
      * component even if the component has been disabled.
      * 
      * @param <T> The parameterized type of component to remove
-     * @param componentId The TypeId of the component type
+     * @param componentType The component type
      * @return True if a component was removed
      * @throws NullPointerException if componentId is null
      */
-    public <T extends ComponentData<T>> boolean remove(TypeId<T> componentId) {
-        ComponentRepository<T> ci = system.getRepository(componentId);
+    public <T extends ComponentData<T>> boolean remove(Class<T> componentType) {
+        ComponentRepository<T> ci = system.getRepository(componentType);
         return ci.removeComponent(index);
     }
 

src/main/java/com/lhkbob/entreri/EntitySystem.java

 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.NoSuchElementException;
 
 import com.lhkbob.entreri.task.Scheduler;
  * @author Michael Ludwig
  */
 public final class EntitySystem implements Iterable<Entity> {
+    // converts valid component data types into indices into componentRepositories
+    private final Map<Class<? extends ComponentData<?>>, Integer> typeIndexMap;
+    private int typeIdSeq;
+
     private ComponentRepository<?>[] componentRepositories;
 
     private Entity[] entities;
      * Create a new EntitySystem that has no entities added.
      */
     public EntitySystem() {
+        typeIndexMap = new HashMap<Class<? extends ComponentData<?>>, Integer>();
+        typeIdSeq = 0;
+
         manager = new Scheduler(this);
         entities = new Entity[1];
         componentRepositories = new ComponentRepository[0];
      * </p>
      * 
      * @param <T> The ComponentData type created by the factory
-     * @param id The type id for the component type
+     * @param type The type of the component type
      * @param factory The factory to use in this system for the given type
      * @throws NullPointerException if id or factory are null
      * @throws IllegalArgumentException if the factory does not actually create
      *             for the given type
      */
     @SuppressWarnings("unchecked")
-    public <T extends ComponentData<T>> void setFactory(TypeId<T> id,
+    public <T extends ComponentData<T>> void setFactory(Class<T> type,
                                                         ComponentDataFactory<T> factory) {
-        if (id == null) {
+        if (type == null) {
             throw new NullPointerException("TypeId cannot be null");
         }
         if (factory == null) {
             throw new NullPointerException("ComponentDataFactory cannot be null");
         }
 
-        int index = id.getId();
+        int index = getTypeIndex(type);
         if (index >= componentRepositories.length) {
             // make sure it's the correct size
             componentRepositories = Arrays.copyOf(componentRepositories, index + 1);
         ComponentRepository<T> i = (ComponentRepository<T>) componentRepositories[index];
         if (i != null) {
             // a factory is already defined
-            throw new IllegalStateException("A ComponentDataFactory is already assigned to the type: " + id);
+            throw new IllegalStateException("A ComponentDataFactory is already assigned to the type: " + type);
         }
 
         // verify that the factory creates the proper instances
         T data = factory.createInstance();
-        if (!id.getType().isInstance(data)) {
-            throw new IllegalArgumentException("ComponentDataFactory does not create instances of type: " + id);
+        if (!type.isInstance(data)) {
+            throw new IllegalArgumentException("ComponentDataFactory does not create instances of type: " + type);
         }
 
-        i = new ComponentRepository<T>(this, id, factory);
+        i = new ComponentRepository<T>(this, type, factory);
         i.expandEntityIndex(entities.length);
         componentRepositories[index] = i;
     }
      * {@link ComponentIterator}).
      * 
      * @param <T> The type of ComponentData to create
-     * @param id The type id of the ComponentDat
+     * @param type The type of the ComponentData
      * @return A new instance of T linked to this EntitySystem
      */
-    public <T extends ComponentData<T>> T createDataInstance(TypeId<T> id) {
-        return getRepository(id).createDataInstance();
+    public <T extends ComponentData<T>> T createDataInstance(Class<T> type) {
+        return getRepository(type).createDataInstance();
     }
 
     /**
      * types that store primitive data, the estimate will be quite accurate. For
      * types that store references to objects, it is likely be an underestimate.
      * 
-     * @param id The TypeId to estimate
+     * @param type The component type whose memory usage is estimated
      * @return The memory estimate for the given type
      * @throws NullPointerException if id is null
      */
-    public long estimateMemory(TypeId<?> id) {
-        int index = id.getId();
+    public long estimateMemory(Class<? extends ComponentData<?>> type) {
+        int index = getTypeIndex(type);
         if (index < componentRepositories.length) {
             ComponentRepository<?> repo = componentRepositories[index];
             return repo.estimateMemory();
      * @throws NullPointerException if type is null
      */
     @SuppressWarnings({"rawtypes", "unchecked"})
-    public <T extends ComponentData<? extends T>> Collection<TypeId<? extends T>> getTypes(Class<T> type) {
+    public <T extends ComponentData<? extends T>> Collection<Class<? extends T>> getComponentTypes(Class<T> type) {
         if (type == null) {
             throw new NullPointerException("Type cannot be null");
         }
 
-        List<TypeId<? extends T>> ids = new ArrayList<TypeId<? extends T>>();
+        List<Class<? extends T>> ids = new ArrayList<Class<? extends T>>();
         for (int i = 0; i < componentRepositories.length; i++) {
             if (componentRepositories[i] != null) {
                 // check the type
-                if (type.isAssignableFrom(componentRepositories[i].getTypeId().getType())) {
+                if (type.isAssignableFrom(componentRepositories[i].getType())) {
                     // this type is a subclass of the requested type
-                    ids.add((TypeId) componentRepositories[i].getTypeId());
+                    ids.add((Class) componentRepositories[i].getType());
                 }
             }
         }
      * 
      * @return All TypeIds at one point used by this system
      */
-    public Collection<TypeId<?>> getTypes() {
-        List<TypeId<?>> ids = new ArrayList<TypeId<?>>();
+    public Collection<Class<? extends ComponentData<?>>> getComponentTypes() {
+        List<Class<? extends ComponentData<?>>> ids = new ArrayList<Class<? extends ComponentData<?>>>();
         for (int i = 0; i < componentRepositories.length; i++) {
             if (componentRepositories[i] != null) {
                 // check the type
                 // this type is a subclass of the requested type
-                ids.add(componentRepositories[i].getTypeId());
+                ids.add(componentRepositories[i].getType());
             }
         }
         return ids;
     }
 
     /**
-     * Return the ControllerManager for this EntitySystem that can be used to
-     * organize processing of the system using {@link Task} implementations.
+     * Return the Scheduler for this EntitySystem that can be used to organize
+     * processing of the system using {@link Task} implementations.
      * 
-     * @return The ControllerManager for this system
+     * @return The Scheduler for this system
      */
-    public Scheduler getControllerManager() {
+    public Scheduler getScheduler() {
         return manager;
     }
 
      * fast iterator. This effectively wraps a {@link ComponentIterator} in a
      * standard {@link Iterator} with a single required component type.
      * 
-     * @param id The type of component to iterate over
+     * @param type The type of component to iterate over
      * @return A fast iterator over components in this system
      */
-    public <T extends ComponentData<T>> Iterator<T> iterator(TypeId<T> id) {
-        return new ComponentIteratorWrapper<T>(id);
+    public <T extends ComponentData<T>> Iterator<T> iterator(Class<T> type) {
+        return new ComponentIteratorWrapper<T>(type);
     }
 
     /**
 
         if (template != null) {
             for (Component<?> c : template) {
-                addFromTemplate(entityIndex, c.getTypeId(), c);
+                addFromTemplate(entityIndex, c.getType(), c);
             }
         }
 
      * @return The property that has decorated the given component type
      * @throws NullPointerException if type or factory are null
      */
-    public <T extends ComponentData<T>, P extends Property> P decorate(TypeId<T> type,
+    public <T extends ComponentData<T>, P extends Property> P decorate(Class<T> type,
                                                                        PropertyFactory<P> factory) {
         ComponentRepository<?> index = getRepository(type);
         return index.decorate(factory);
      * the type is not registered
      * 
      * @param <T> The ComponentData type
-     * @param id The id for the component type
+     * @param type The component type
      * @return The ComponentRepository for the type
      */
     @SuppressWarnings("unchecked")
-    <T extends ComponentData<T>> ComponentRepository<T> getRepository(TypeId<T> id) {
-        int index = id.getId();
+    <T extends ComponentData<T>> ComponentRepository<T> getRepository(Class<T> type) {
+        int index = getTypeIndex(type);
         if (index >= componentRepositories.length) {
             // make sure it's the correct size
             componentRepositories = Arrays.copyOf(componentRepositories, index + 1);
         ComponentRepository<T> i = (ComponentRepository<T>) componentRepositories[index];
         if (i == null) {
             // if the index does not exist, then we need to use the default component data factory
-            i = new ComponentRepository<T>(this, id, createDefaultFactory(id));
+            i = new ComponentRepository<T>(this, type, createDefaultFactory(type));
             i.expandEntityIndex(entities.length);
             componentRepositories[index] = i;
         }
         return i;
     }
 
+    private int getTypeIndex(Class<? extends ComponentData<?>> type) {
+        Integer id = typeIndexMap.get(type);
+        if (id == null) {
+            id = typeIdSeq++;
+            typeIndexMap.put(type, id);
+        }
+        return id.intValue();
+    }
+
     /*
      * Create a new ComponentDataFactory for the given id, using the default
      * annotation if available.
      */
     @SuppressWarnings({"rawtypes", "unchecked"})
-    private <T extends ComponentData<T>> ComponentDataFactory<T> createDefaultFactory(TypeId<T> id) {
-        DefaultFactory factoryAnnot = id.getType().getAnnotation(DefaultFactory.class);
+    private <T extends ComponentData<T>> ComponentDataFactory<T> createDefaultFactory(Class<T> type) {
+        DefaultFactory factoryAnnot = type.getAnnotation(DefaultFactory.class);
         if (factoryAnnot != null) {
             Class factoryType = factoryAnnot.value();
-            // check for supported constructors, priority: TypeId, Class, default
+            // check for supported constructors, priority: Class, default
             ComponentDataFactory<T> factory = (ComponentDataFactory<T>) attemptInstantiation(factoryType,
-                                                                                             id);
-            if (factory == null) {
-                factory = (ComponentDataFactory<T>) attemptInstantiation(factoryType,
-                                                                         id.getType());
-            }
+                                                                                             type);
             if (factory == null) {
                 factory = (ComponentDataFactory<T>) attemptInstantiation(factoryType);
             }
             if (factory == null) {
-                throw new IllegalComponentDefinitionException(id.getType(),
+                throw new IllegalComponentDefinitionException(type,
                                                               "Cannot instantiate default ComponentDataFactory of type: " + factoryType);
             }
 
             return factory;
         } else {
             // use the reflection default
-            return new ReflectionComponentDataFactory<T>(id.getType());
+            return new ReflectionComponentDataFactory<T>(type);
         }
     }
 
 
     @SuppressWarnings({"rawtypes", "unchecked"})
     private <T extends ComponentData<T>> void addFromTemplate(int entityIndex,
-                                                              TypeId typeId,
-                                                              Component<T> c) {
-        ComponentRepository index = getRepository(typeId);
+                                                              Class type, Component<T> c) {
+        ComponentRepository index = getRepository(type);
         index.addComponent(entityIndex, c);
     }
 
         private boolean nextCalled;
         private boolean hasNext;
 
-        public ComponentIteratorWrapper(TypeId<T> type) {
+        public ComponentIteratorWrapper(Class<T> type) {
             data = createDataInstance(type);
             it = new ComponentIterator(EntitySystem.this);
             it.addRequired(data);

src/main/java/com/lhkbob/entreri/TypeId.java

-/*
- * Entreri, an entity-component framework in Java
- *
- * Copyright (c) 2012, Michael Ludwig
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- *     Redistributions of source code must retain the above copyright notice,
- *         this list of conditions and the following disclaimer.
- *     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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
- */
-package com.lhkbob.entreri;
-
-import java.lang.reflect.Modifier;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * <p>
- * TypeId is a dynamically assigned identifier unique to the desired component
- * data types. Every instance of a type T will use the same TypeId. TypeId is a
- * glorified integer id assigned to set of class types that share a common
- * parent class. Each class will be assigned a unique id within the currently
- * executing JVM.
- * </p>
- * <p>
- * TypeId's enable typed, random-access lookups.
- * </p>
- * 
- * @author Michael Ludwig
- * @param <T> The identified type
- */
-public class TypeId<T extends ComponentData<T>> {
-    // Use a ConcurrentHashMap to perform reads. It is still synchronized completely to do
-    // an insert to make sure a type doesn't try to use two different id values.
-    private static final ConcurrentHashMap<Class<? extends ComponentData<?>>, TypeId<? extends ComponentData<?>>> typeMap = new ConcurrentHashMap<Class<? extends ComponentData<?>>, TypeId<? extends ComponentData<?>>>();
-
-    private static int idSeq = 0;
-
-    private final Class<T> type;
-    private final int id;
-
-    /**
-     * Create a new Id for the given type, with the given numeric id. It is
-     * assumed that the id will remain unique.
-     * 
-     * @param type The type that is identified
-     * @param id The unique numeric id
-     * @throws NullPointerException if type is null
-     * @throws IllegalArgumentException if id is less than 0
-     */
-    private TypeId(Class<T> type, int id) {
-        // Sanity checks, shouldn't happen
-        if (type == null) {
-            throw new NullPointerException("Type cannot be null");
-        }
-        if (id < 0) {
-            throw new IllegalArgumentException("Id must be at least 0, not: " + id);
-        }
-
-        this.type = type;
-        this.id = id;
-    }
-
-    /**
-     * Return the type that this TypeId corresponds to. All instances of the
-     * returned type will have the same TypeId.
-     * 
-     * @return The type that corresponds to this id
-     */
-    public Class<T> getType() {
-        return type;
-    }
-
-    /**
-     * Return the numeric id corresponding to this ComponentId. This id is
-     * unique such that a ComponentId corresponding to a different
-     * {@link ComponentData} implementation will not have the same id.
-     * 
-     * @return The numeric id, which will be at least 0
-     */
-    public int getId() {
-        return id;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof TypeId)) {
-            return false;
-        }
-        TypeId<?> cid = (TypeId<?>) o;
-        return cid.id == id && cid.type.equals(type);
-    }
-
-    @Override
-    public int hashCode() {
-        return id;
-    }
-
-    @Override
-    public String toString() {
-        return "TypeId (" + type.getSimpleName() + ", id=" + id + ")";
-    }
-
-    /**
-     * <p>
-     * Return the unique TypeId instance for the given <tt>type</tt>. If a
-     * TypeId hasn't yet been created a new one is instantiated with the next
-     * numeric id in the internal id sequence. The new TypeId is stored for
-     * later, so that subsequent calls to {@link #get(Class)} with <tt>type</tt>
-     * will return the same instance. It is recommended that a ComponentData
-     * declare a static final <tt>ID</tt> holding its TypeId.
-     * </p>
-     * <p>
-     * This method does not validate the definition of the ComponentData because
-     * validation depends on the potentially customized ComponentDataFactory
-     * used by each EntitySystem. Additionally, abstract ComponentData types
-     * cannot have a TypeId assigned to them.
-     * </p>
-     * 
-     * @param <T> The ComponentData class type
-     * @param type The Class whose TypeId is fetched, which must be a subclass
-     *            of ComponentData
-     * @return A unique TypeId associated with the given type
-     * @throws NullPointerException if type is null
-     * @throws IllegalArgumentException if type is not actually a subclass of
-     *             ComponentData, or if it is abstract
-     */
-    @SuppressWarnings("unchecked")
-    public static <T extends ComponentData<T>> TypeId<T> get(Class<T> type) {
-        if (type == null) {
-            throw new NullPointerException("Type cannot be null");
-        }
-
-        // Do a look up first without locking to avoid the synchronized lock and expensive
-        // error checking.  If we found one, we know it passed validation the first time, otherwise
-        // we'll validate it before creating a new TypeId.
-        TypeId<T> id = (TypeId<T>) typeMap.get(type);
-        if (id != null) {
-            return id; // Found an existing id
-        }
-
-        if (!ComponentData.class.isAssignableFrom(type)) {
-            throw new IllegalArgumentException("Class does not extend ComponentData: " + type);
-        }
-        if (Modifier.isAbstract(type.getModifiers())) {
-            throw new IllegalArgumentException("Abstract classes cannot have TypeIds: " + type);
-        }
-
-        synchronized (typeMap) {
-            // Must create a new id, we lock completely to prevent concurrent get() on the
-            // same type using two different ids.  One would get overridden and its returned TypeId
-            // would be invalid.
-            // - Double check, then, before creating a new id
-            id = (TypeId<T>) typeMap.get(type);
-            if (id != null) {
-                return id; // Someone else put in the type after we checked but before we locked
-            }
-
-            id = new TypeId<T>(type, idSeq++);
-            typeMap.put(type, id);
-            return id;
-        }
-    }
-}