Skip to content

Commit 2255af0

Browse files
committed
Optimized Map/Set lookups in Structure
Reduced the number of Set lookups in Structure.read / Structure.write. Introduced a new class to replace two entries of a HashMap with one. This reduces the number of lookups and the initial capacity has been reduced too.
1 parent dc0c453 commit 2255af0

File tree

1 file changed

+25
-17
lines changed

1 file changed

+25
-17
lines changed

src/com/sun/jna/Structure.java

+25-17
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,17 @@ public interface ByValue { }
127127
*/
128128
public interface ByReference { }
129129

130+
private static class PointerTracking {
131+
132+
private final Pointer pointer;
133+
private final Object value;
134+
135+
PointerTracking(Pointer pointer, Object value) {
136+
this.pointer = pointer;
137+
this.value = value;
138+
}
139+
}
140+
130141
/** Use the platform default alignment. */
131142
public static final int ALIGN_DEFAULT = 0;
132143
/** No alignment, place all fields on nearest 1-byte boundary */
@@ -157,7 +168,7 @@ public interface ByReference { }
157168
private Map<String, StructField> structFields;
158169
// Keep track of native C strings which have been allocated,
159170
// corresponding to String fields of this Structure
160-
private final Map<String, Object> nativeStrings = new HashMap<String, Object>();
171+
private final Map<String, PointerTracking> nativeStrings = new HashMap<String, PointerTracking>(8);
161172
private TypeMapper typeMapper;
162173
// This field is accessed by native code
163174
private long typeInfo;
@@ -343,14 +354,15 @@ void useMemory(Pointer m, int offset, boolean force) {
343354
this.memory.write(0, buf, 0, buf.length);
344355
}
345356
else {
346-
// Ensure our memory pointer is initialized, even if we can't
347-
// yet figure out a proper size/layout
348-
this.memory = m.share(offset);
349357
if (size == CALCULATE_SIZE) {
350358
size = calculateSize(false);
351359
}
352360
if (size != CALCULATE_SIZE) {
353361
this.memory = m.share(offset, size);
362+
} else {
363+
// Ensure our memory pointer is initialized, even if we can't
364+
// yet figure out a proper size/layout
365+
this.memory = m.share(offset);
354366
}
355367
}
356368
this.array = null;
@@ -508,8 +520,9 @@ public boolean add(Structure o) {
508520
if (!contains(o)) {
509521
ensureCapacity(count+1);
510522
elements[count++] = o;
523+
return true;
511524
}
512-
return true;
525+
return false;
513526
}
514527
private int indexOf(Structure s1) {
515528
for (int i=0;i < count;i++) {
@@ -579,10 +592,9 @@ public void read() {
579592
ensureAllocated();
580593

581594
// Avoid redundant reads
582-
if (busy().contains(this)) {
595+
if (!busy().add(this)) {
583596
return;
584597
}
585-
busy().add(this);
586598
if (this instanceof Structure.ByReference) {
587599
reading().put(getPointer(), this);
588600
}
@@ -593,7 +605,7 @@ public void read() {
593605
}
594606
finally {
595607
busy().remove(this);
596-
if (reading().get(getPointer()) == this) {
608+
if (this instanceof Structure.ByReference && reading().get(getPointer()) == this) {
597609
reading().remove(getPointer());
598610
}
599611
}
@@ -740,8 +752,7 @@ protected Object readField(StructField structField) {
740752

741753
if (fieldType.equals(String.class)
742754
|| fieldType.equals(WString.class)) {
743-
nativeStrings.put(structField.name + ".ptr", memory.getPointer(offset));
744-
nativeStrings.put(structField.name + ".val", result);
755+
nativeStrings.put(structField.name, new PointerTracking(memory.getPointer(offset), result));
745756
}
746757

747758
// Update the value on the Java field
@@ -769,10 +780,9 @@ public void write() {
769780
}
770781

771782
// Avoid redundant writes
772-
if (busy().contains(this)) {
783+
if (!busy().add(this)) {
773784
return;
774785
}
775-
busy().add(this);
776786
try {
777787
// Write all fields, except those marked 'volatile'
778788
for (StructField sf : fields().values()) {
@@ -845,23 +855,21 @@ protected void writeField(StructField structField) {
845855
if (value != null) {
846856
// If we've already allocated a native string here, and the
847857
// string value is unchanged, leave it alone
848-
if (nativeStrings.containsKey(structField.name + ".ptr")
849-
&& value.equals(nativeStrings.get(structField.name + ".val"))) {
858+
PointerTracking tracking = nativeStrings.get(structField.name);
859+
if (tracking != null && value.equals(tracking.value)) {
850860
return;
851861
}
852862
NativeString nativeString = wide
853863
? new NativeString(value.toString(), true)
854864
: new NativeString(value.toString(), encoding);
855865
// Keep track of allocated C strings to avoid
856866
// premature garbage collection of the memory.
857-
nativeStrings.put(structField.name, nativeString);
867+
nativeStrings.put(structField.name, new PointerTracking(nativeString.getPointer(), nativeString));
858868
value = nativeString.getPointer();
859869
}
860870
else {
861871
nativeStrings.remove(structField.name);
862872
}
863-
nativeStrings.remove(structField.name + ".ptr");
864-
nativeStrings.remove(structField.name + ".val");
865873
}
866874

867875
try {

0 commit comments

Comments
 (0)