From 230ece3cec034b12e68818da6441112c12298795 Mon Sep 17 00:00:00 2001 From: Wayne Meissner Date: Sun, 15 Aug 2010 13:02:16 +1000 Subject: [PATCH] Use an IdentityHashMap for the main symbol -> field lookup for FFI::StructLayout for approx 10% faster struct field lookups. --- src/org/jruby/ext/ffi/StructLayout.java | 30 ++++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/org/jruby/ext/ffi/StructLayout.java b/src/org/jruby/ext/ffi/StructLayout.java index 8b6035f6b1a..1bd1ca9d5ad 100644 --- a/src/org/jruby/ext/ffi/StructLayout.java +++ b/src/org/jruby/ext/ffi/StructLayout.java @@ -33,6 +33,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -65,7 +67,10 @@ public final class StructLayout extends Type { static final String CLASS_NAME = "StructLayout"; /** The name:offset map for this struct */ - private final Map fieldMap; + private final Map fieldSymbolMap; + + /** The name:offset map for this struct */ + private final Map fieldStringMap; /** The ordered list of field names (as symbols) */ private final List fieldNames; @@ -158,8 +163,9 @@ private StructLayout(Ruby runtime, RubyClass klass, Collection fiel List fieldList = new ArrayList(fields.size()); List names = new ArrayList(fields.size()); List memberList = new ArrayList(fields.size()); - Map memberMap = new LinkedHashMap(fields.size()); - + Map memberStringMap = new HashMap(fields.size()); + Map memberSymbolMap = new IdentityHashMap(fields.size() * 2); + int index = 0; for (IRubyObject obj : fields) { @@ -176,10 +182,11 @@ private StructLayout(Ruby runtime, RubyClass klass, Collection fiel fieldList.add(f); Member m = new Member(f, index, f.isCacheable() ? cfCount++ : -1, f.isValueReferenceNeeded() ? refCount++ : -1); - memberMap.put(f.name, m); + memberSymbolMap.put(f.name, m); // Allow fields to be accessed as ['name'] as well as [:name] for legacy code - memberMap.put(f.name.asString(), m); + memberStringMap.put(f.name, m); + memberStringMap.put(f.name.asString(), m); memberList.add(m); } @@ -190,7 +197,8 @@ private StructLayout(Ruby runtime, RubyClass klass, Collection fiel // Create the ordered list of field names from the map this.fieldNames = Collections.unmodifiableList(new ArrayList(names)); this.fields = Collections.unmodifiableList(fieldList); - this.fieldMap = Collections.unmodifiableMap(memberMap); + this.fieldStringMap = Collections.unmodifiableMap(memberStringMap); + this.fieldSymbolMap = Collections.unmodifiableMap(memberSymbolMap); this.members = Collections.unmodifiableList(memberList); } @@ -264,7 +272,7 @@ public IRubyObject offsets(ThreadContext context) { RubyArray offset = RubyArray.newArray(runtime); // Assemble a [ :name, offset ] array offset.append(name); - offset.append(runtime.newFixnum(fieldMap.get(name).offset)); + offset.append(runtime.newFixnum(getMember(runtime, name).offset)); offsets.append(offset); } @@ -296,10 +304,16 @@ final void putValue(ThreadContext context, IRubyObject name, Storage cache, IRub * @return A Member descriptor. */ final Member getMember(Ruby runtime, IRubyObject name) { - Member f = fieldMap.get(name); + Member f = fieldSymbolMap.get(name); if (f != null) { return f; } + + f = fieldStringMap.get(name); + if (f != null) { + return f; + } + throw runtime.newArgumentError("Unknown field: " + name); }