Storing entity state in Map<String,Object>

I am storing entity state in a map. I build up entities by composition (so an entity is a list of behaviors and other properties), but I’m writing all the state to a shared map to simplify serialization. Knowing me, I need a simple way of saving state that does not rely on me remembering repeatedly to write instance variables to file.

I know it’s not the most efficient approach, but I want to stay sane :slight_smile:

I’m wondering about my string keys. Would there be a significant difference in the lookup performance in a map with longer keys (“Behavior/CraftBehavior/workCompleted”) or one with short keys (“work”)? I’m guessing that the hashing algorithm takes time proportional to the length of a string?

It’s probably not horrendous since HashMap should be using hashCode and only do further checks if there is a clash. Since strings are immutable I gather the hash code is stored and not generated every time the method is called.

OpenJDK: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/HashMap.java#336

No need to guess. Why don’t you just look at the source for String.hashCode()?

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

So yes, it does appear that String stores its hash after the first time it’s calculated.

But the best way to answer this question is by doing some benchmarking with your actual use case. What are the exact Strings? How many are there? What are the Objects? What’s the load factor of your HashMap? How many entries does it have?

I would guess that this is a non-issue and you’re suffering from premature optimization. Don’t sweat the small stuff.

We could generalise on that a bit and have a general maxim:

Performance only matters on a frame-by-frame basis. Everything else can be slow and inefficient*.

Cas :slight_smile:

  • Until proven otherwise

If you’re looking up something up enough that it effects performance, then that something needs to be moved out of the map and into the entity. It’s common thing and not a specializing thing.

I personally wouldn’t go the only type you store is a String route. It’s a usage pain. I stuck a bare-bones, dumbest thing on the planet skeleton here: https://github.com/roquendm/JGO-Grabbag/tree/master/src/roquen/wiki/dvar

The worst thing is really that Java’s hash-maps implementation blows chunks…but that doesn’t really matter either unless you have lots of stuff in your maps.

I don’t know if this is recommended but

class KeyValue {
	Map<Object, Object> values = new HashMap<>();
	
	public <T> T get(Object key) {
		return (T)values.get(key);
	}
	
	public void put(Object key, Object value) {
		values.put(key, value);
	}
}
KeyValue kv = new KeyValue();

kv.put("test", "Hi I'm a thing");
kv.put(1, 123);
kv.put("myvalue", 123);

String s = kv.get("test");
int i = kv.get(1);
int j = kv.get("myvalue");

System.out.println(s + ", " + i + ", " + j);

compiles to:

KeyValue kv = new KeyValue();

kv.put("test", "Hi I'm a thing");
kv.put(Integer.valueOf(1), Integer.valueOf(123));
kv.put("myvalue", Integer.valueOf(123));

String str = (String)kv.get("test");
int i = ((Integer)kv.get(Integer.valueOf(1))).intValue();
int j = ((Integer)kv.get("myvalue")).intValue();

System.out.println(str + ", " + i + ", " + j);

My take is:

Allowing anything to be a key isn’t useful.
The transforms the compiler is providing for you are very expensive and don’t buy you anything interesting.
You’re opening up runtime errors. [icode]int k = kv.get(“test”);[/icode]

My take is that what we’re talking about here is a “poor man’s” component architecture implementation regardless of storing by strings or objects.

It ignores the main benefit of Java which is the Class / type system. I’ve gone down the full component architecture implementation path with TyphonRT.

A simplified / reduced example from the API:


   public final <T extends IComponent> T getAs(@Nonnull Class<T> componentType) { ... }

   public final <T extends IComponent> boolean set(@Nonnull Class<T> componentType, @Nonnull T component) { ... }


   // Basic usage 
   entity.set(Stuff.class, new Stuff());
   Stuff stuff = entity.getAs(Stuff.class);

The nice thing about using the type system to your advantage is that it allows type safety for setting and getting objects / components out of the container. In my efforts I also allow storage in a List by type and retrieving a protected iterator by type.

The big trouble spot for all Java entity systems / component architectures is the trick of storing multiple single components or collections by the same type. I’ve overcome that by some really fancy extensible enum tricks and generic method signatures for the component architecture API.

You can do:


   // LEFT_ENGINE, RIGHT_ENGINE come from an extensible enum let's say `Engines` and statically imported. 

   entity.set(LEFT_ENGINE, new Engine());
   entity.set(RIGHT_ENGINE, new Engine());

   Engine engineLeft = entity.getAs(LEFT_ENGINE);
   Engine engineRight = entity.getAs(RIGHT_ENGINE);

So, in short for the OP. What you are doing is a pseudo solution and one that ignores the biggest benefit of Java which is the type system. I’d say take a look at the various entity system implementations out there. They are adequate, but not as far as things can actually be taken.

For now check out:


One day I’ll release the beast / TyphonRT… ::slight_smile:

If you’re going component architecture, you don’t have to follow the articles everyone googles and follows.
Using the and then making the ComponentType class is such a mess, unless you want to make it your mess then go for it.

Here’s what I do, I make a hashset, and then use integers to identify the component type, then I use strings to hold the values (to take away from the oop side of programming in case I’m using over 9000 objects with this.)

The reason why is simple.

“Check if this entities collides with collide-able entities.”
How do we do that?
Well instead of using a ‘T extends Collideable’, we just store the entity that’s collideable in a Set of values that are collideable. If they aren’t in that Set, they aren’t solid.

I think that’s what you’re going after.

You will probably want to have an indexer create tags for each unique object you are using, place that object in a Map with an Integer (Tag) as the key and the Entity as the value.

Then take all the information of that entity and pass it through a class that keeps track of the Sets of entities with attributes of a certain type so that you don’t have to perform excessive forloop iterations.

Seems redundant, but it’s better than going through every entity you have and checking it for specific conditions, when you can hold a set for said conditions to iterate over.

@micecd Your reply is diverging from the OP topic which is a way to store / retrieve data with an emphasis on serialization.

I also should have commented on serialization aspects in my previous post as that is the goal of the OP. Of course by storing data using the Java type system aids serialization since one can use the type data during serialization and deserialization.

I probably should have given the simple code example as:


public final <T> T getAs(@Nonnull Class<T> type) { ... }

public final <T> boolean set(@Nonnull Class<T> type, @Nonnull T object) { ... }

The “” you misunderstood perhaps as there is no separate “ComponentType” class. It’s just the Class of the object one is storing. In my CA (component architecture) I have a component interface (IComponent) which just provides a few extra methods for resetting state and recycling the component / basic house keeping on top of “Object” that makes something a “component” in the context of my CA.

The rest of your post diverges into other topics of which there are reasonable solutions in my CA, but are beyond discussing in this thread. I can agree with this though, “If you’re going component architecture, you don’t have to follow the articles everyone googles and follows.”

Mimicking prototype based variables is far from poor man’s component based.

I just realised @ags1 never quite mentioned what the actual use case was for the question.

If it’s for modestly persistent storage (in-game entity hibernation) I’d use reflective serialization. If it’s long-term storage I’d use either a database (if there are a lot) or just file-per-entity containing, say, JSON, which again would be generated automatically using reflection and annotations.

Cas :slight_smile:

How so? I wouldn’t really connote it to “mimicking prototype” / prototypical inheritance ala Javascript. The basic Map<String, Object> store has nothing to do with being prototype based or prototype properties IMHO. Losing all typing in a typed language does not make it or mimic being prototypical.

As a side note while I’ve been waiting for Vulkan in the past 3 months I’ve been jamming on a lot of modern ES6 Javascript framework dev to get around the 30% tax for mobile apps for a new product. Hell hath frozen over and after 20 years I can now say I don’t hate Javascript w/ a passion. With ES6 + JSPM / SystemJS for package management / modularization it’s actually pretty neat.

If it’s just for serialization and @ags1 is sticking with OOP indeed this is the way to go for the normal use case and there are plenty of serialization libraries that support this well.

If @ags1 is taking a step towards the entity system / component architecture route ala implicit composition then indeed there are better solutions.

Of course one can take multiple views of manual feature extensions. Having an instance that at runtime one can add new fields and/or methods is the origin of prototype based as a programming model.

That’s not a requirement. You can choose whatever level of strong vs. weak typing you want.

That is obviously a much better solution, it is pretty simple and it takes away my performance concerns. The goal would be to have a system that does not require per-field mapping. For example, annotation only the fields I don’t want to persist… Also it gives me the opportunity to work with annotations a bit more; the only ones I use on a day-to-day basis are the JUnit and TestNG ones.

It’s not going to be a file-per-entity; that would be 60k+ files.

Also, nothing in Vangard hibernates :slight_smile:

EDIT: …and I now have a prototype no-per-field-coding reflection approach working!

Any reason you wouldn’t use something like Kryo?

Because what I want to do is fairly trivial and I don’t want to add a whole library to do single very specific task that I can accomplish in just a few lines.