Skip to content

Commit

Permalink
Use an IdentityHashMap for the main symbol -> field lookup for FFI::S…
Browse files Browse the repository at this point in the history
…tructLayout for approx 10% faster struct field lookups.
  • Loading branch information
vp-of-awesome committed Aug 15, 2010
1 parent 767e944 commit 230ece3
Showing 1 changed file with 22 additions and 8 deletions.
30 changes: 22 additions & 8 deletions src/org/jruby/ext/ffi/StructLayout.java
Expand Up @@ -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;
Expand Down Expand Up @@ -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<IRubyObject, Member> fieldMap;
private final Map<IRubyObject, Member> fieldSymbolMap;

/** The name:offset map for this struct */
private final Map<IRubyObject, Member> fieldStringMap;

/** The ordered list of field names (as symbols) */
private final List<IRubyObject> fieldNames;
Expand Down Expand Up @@ -158,8 +163,9 @@ private StructLayout(Ruby runtime, RubyClass klass, Collection<IRubyObject> fiel
List<Field> fieldList = new ArrayList<Field>(fields.size());
List<IRubyObject> names = new ArrayList<IRubyObject>(fields.size());
List<Member> memberList = new ArrayList<Member>(fields.size());
Map<IRubyObject, Member> memberMap = new LinkedHashMap<IRubyObject, Member>(fields.size());

Map<IRubyObject, Member> memberStringMap = new HashMap<IRubyObject, Member>(fields.size());
Map<IRubyObject, Member> memberSymbolMap = new IdentityHashMap<IRubyObject, Member>(fields.size() * 2);

int index = 0;
for (IRubyObject obj : fields) {

Expand All @@ -176,10 +182,11 @@ private StructLayout(Ruby runtime, RubyClass klass, Collection<IRubyObject> 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);
}

Expand All @@ -190,7 +197,8 @@ private StructLayout(Ruby runtime, RubyClass klass, Collection<IRubyObject> fiel
// Create the ordered list of field names from the map
this.fieldNames = Collections.unmodifiableList(new ArrayList<IRubyObject>(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);
}

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -296,10 +304,16 @@ final void putValue(ThreadContext context, IRubyObject name, Storage cache, IRub
* @return A <tt>Member</tt> 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);
}

Expand Down

0 comments on commit 230ece3

Please sign in to comment.