From 643807420d8c8a9ab7da76b72d96f12181826595 Mon Sep 17 00:00:00 2001
From: charlesbr1 <charlesbr1@users.noreply.github.com>
Date: Sat, 1 Aug 2015 01:03:38 -0500
Subject: [PATCH 1/4] Create NumbersCache.java

A cache for frequently used string of integers
---
 .../src/main/java/quickfix/NumbersCache.java  | 74 +++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 quickfixj-core/src/main/java/quickfix/NumbersCache.java

diff --git a/quickfixj-core/src/main/java/quickfix/NumbersCache.java b/quickfixj-core/src/main/java/quickfix/NumbersCache.java
new file mode 100644
index 0000000000..a3c72707ac
--- /dev/null
+++ b/quickfixj-core/src/main/java/quickfix/NumbersCache.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) quickfixengine.org  All rights reserved.
+ *
+ * This file is part of the QuickFIX FIX Engine
+ *
+ * This file may be distributed under the terms of the quickfixengine.org
+ * license as defined by quickfixengine.org and appearing in the file
+ * LICENSE included in the packaging of this file.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
+ * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ *
+ * See http://www.quickfixengine.org/LICENSE for licensing information.
+ *
+ * Contact ask@quickfixengine.org if any conditions of this licensing
+ * are not clear to you.
+ ******************************************************************************/
+
+package quickfix;
+
+import java.util.ArrayList;
+
+/**
+ * A cache for commonly used string representing numbers.
+ * Hold values from 0 to 999999 and from 1000 to 200 000 000 by step of 1000
+ */
+public final class NumbersCache {
+
+    private static final int littleNumbersLength = 1000000;
+    private static final int bigNumbersLength = 200000;
+    private static final int bigNumbersOffset = 1000;
+    private static final int bigNumbersMax = bigNumbersLength * bigNumbersOffset;
+
+    public static final ArrayList<String> littleNumbers;
+    public static final ArrayList<String> bigNumbers;
+
+    static {
+        littleNumbers = new ArrayList<String>(littleNumbersLength);
+        bigNumbers = new ArrayList<String>(bigNumbersLength);
+        for (int i = 0; i < littleNumbersLength; i++)
+            littleNumbers.add(Integer.toString(i));
+        for (long i = 0; i < bigNumbersLength;)
+            bigNumbers.add(Long.toString(++i * bigNumbersOffset));
+
+    }
+
+    /**
+     * Get the string representing the given number
+     *
+     * @param i the long to convert
+     * @return the String representing the long
+     */
+    public static String get(long i) {
+        if (i < littleNumbersLength)
+            return littleNumbers.get((int)i);
+        if (i <= bigNumbersMax && i % bigNumbersOffset == 0)
+            return bigNumbers.get((int)(i/bigNumbersOffset)-1);
+        return String.valueOf(i);
+    }
+
+    /**
+     * Get the string representing the given double if it's an integer
+     *
+     * @param d the double to convert
+     * @return the String representing the double or null if the double is not an integer
+     */
+    public static String get(double d) {
+        long l = (long)d;
+        if (d == (double)l)
+            return get(l);
+        return null;
+    }
+}

From f004d9ce3ea04b1f385e65084a8204d291e7e729 Mon Sep 17 00:00:00 2001
From: charlesbr1 <charlesbr1@users.noreply.github.com>
Date: Sat, 1 Aug 2015 01:10:25 -0500
Subject: [PATCH 2/4] Remove duplication of inserted fields

All the inserted fields are duplicated : they are converted to StringField, then added to the treeMap.
We can remove a lot of allocations by avoiding this behavior. Unless there is a specific reason for this purpose, it seems to works fine without this.
Furthermore, the setGroupCount() method allocated the string "1" when there is only one group, this is not efficient.
---
 .../src/main/java/quickfix/FieldMap.java      | 166 ++++++++++++++----
 1 file changed, 132 insertions(+), 34 deletions(-)

diff --git a/quickfixj-core/src/main/java/quickfix/FieldMap.java b/quickfixj-core/src/main/java/quickfix/FieldMap.java
index 2e9202f3fa..2e53e17440 100644
--- a/quickfixj-core/src/main/java/quickfix/FieldMap.java
+++ b/quickfixj-core/src/main/java/quickfix/FieldMap.java
@@ -207,69 +207,102 @@ Field<?> getField(int field, Field<?> defaultValue) {
         return f;
     }
 
+    private Field<?> getField(int field, boolean notFoundException) throws FieldNotFound {
+        final Field<?> f = fields.get(field);
+        if (f == null && notFoundException) {
+            throw new FieldNotFound(field);
+        }
+        return f;
+    }
+
+
     public String getString(int field) throws FieldNotFound {
         return getField(field).getObject();
     }
 
     public boolean getBoolean(int field) throws FieldNotFound {
+        Field<?> f = getField(field, true);
+        if(f instanceof BooleanField)
+            return ((BooleanField)f).getValue();
         try {
-            return BooleanConverter.convert(getString(field));
+            return BooleanConverter.convert(f.objectAsString());
         } catch (final FieldConvertError e) {
             throw newIncorrectDataException(e, field);
         }
     }
 
     public char getChar(int field) throws FieldNotFound {
+        Field<?> f = getField(field, true);
+        if(f instanceof CharField)
+            return ((CharField)f).getValue();
         try {
-            return CharConverter.convert(getString(field));
+            return CharConverter.convert(f.objectAsString());
         } catch (final FieldConvertError e) {
             throw newIncorrectDataException(e, field);
         }
     }
 
     public int getInt(int field) throws FieldNotFound {
+        Field<?> f = getField(field, true);
+        if(f instanceof IntField)
+            return ((IntField)f).getValue();
         try {
-            return IntConverter.convert(getString(field));
+            return IntConverter.convert(f.objectAsString());
         } catch (final FieldConvertError e) {
             throw newIncorrectDataException(e, field);
         }
     }
 
     public double getDouble(int field) throws FieldNotFound {
+        Field<?> f = getField(field, true);
+        if(f instanceof DoubleField)
+            return ((DoubleField)f).getValue();
         try {
-            return DoubleConverter.convert(getString(field));
+            return DoubleConverter.convert(f.objectAsString());
         } catch (final FieldConvertError e) {
             throw newIncorrectDataException(e, field);
         }
     }
 
     public BigDecimal getDecimal(int field) throws FieldNotFound {
+        Field<?> f = getField(field, true);
+        if(f instanceof DecimalField)
+            return ((DecimalField)f).getValue();
         try {
-            return DecimalConverter.convert(getString(field));
+            return DecimalConverter.convert(f.objectAsString());
         } catch (final FieldConvertError e) {
             throw newIncorrectDataException(e, field);
         }
     }
 
     public Date getUtcTimeStamp(int field) throws FieldNotFound {
+        Field<?> f = getField(field, true);
+        if(f instanceof UtcTimeStampField)
+            return ((UtcTimeStampField)f).getValue();
         try {
-            return UtcTimestampConverter.convert(getString(field));
+            return UtcTimestampConverter.convert(f.objectAsString());
         } catch (final FieldConvertError e) {
             throw newIncorrectDataException(e, field);
         }
     }
 
     public Date getUtcTimeOnly(int field) throws FieldNotFound {
+        Field<?> f = getField(field, true);
+        if(f instanceof UtcTimeOnlyField)
+            return ((UtcTimeOnlyField)f).getValue();
         try {
-            return UtcTimeOnlyConverter.convert(getString(field));
+            return UtcTimeOnlyConverter.convert(f.objectAsString());
         } catch (final FieldConvertError e) {
             throw newIncorrectDataException(e, field);
         }
     }
 
     public Date getUtcDateOnly(int field) throws FieldNotFound {
+        Field<?> f = getField(field, true);
+        if(f instanceof UtcDateOnlyField)
+            return ((UtcDateOnlyField)f).getValue();
         try {
-            return UtcDateOnlyConverter.convert(getString(field));
+            return UtcDateOnlyConverter.convert(f.objectAsString());
         } catch (final FieldConvertError e) {
             throw newIncorrectDataException(e, field);
         }
@@ -279,43 +312,47 @@ public void setField(int key, Field<?> field) {
         fields.put(key, field);
     }
 
-    public void setField(StringField field) {
-        if (field.getValue() == null) {
+    private void setField(Field<?> field) {
+        if (field.getObject() == null) {
             throw new NullPointerException("Null field values are not allowed.");
         }
         fields.put(field.getField(), field);
     }
 
+    public void setField(StringField field) {
+        setField((Field<?>)field);
+    }
+
     public void setField(BooleanField field) {
-        setBoolean(field.getField(), field.getValue());
+        setField((Field<?>) field);
     }
 
     public void setField(CharField field) {
-        setChar(field.getField(), field.getValue());
+        setField((Field<?>) field);
     }
 
     public void setField(IntField field) {
-        setInt(field.getField(), field.getValue());
+        setField((Field<?>)field);
     }
 
     public void setField(DoubleField field) {
-        setDouble(field.getField(), field.getValue());
+        fields.put(field.getField(), field);
     }
 
     public void setField(DecimalField field) {
-        setDecimal(field.getField(), field.getValue());
+        setField((Field<?>) field);
     }
 
     public void setField(UtcTimeStampField field) {
-        setUtcTimeStamp(field.getField(), field.getValue(), field.showMilliseconds());
+        setField((Field<?>) field);
     }
 
     public void setField(UtcTimeOnlyField field) {
-        setUtcTimeOnly(field.getField(), field.getValue(), field.showMilliseconds());
+        setField((Field<?>) field);
     }
 
     public void setField(UtcDateOnlyField field) {
-        setUtcDateOnly(field.getField(), field.getValue());
+        setField((Field<?>)field);
     }
 
     public void setField(BytesField field) {
@@ -344,35 +381,100 @@ public StringField getField(StringField field) throws FieldNotFound {
     }
 
     public BooleanField getField(BooleanField field) throws FieldNotFound {
-        return updateValue(field, getBoolean(field.getField()));
+        Field<?> f = getField(field.getField(), true);
+        if(f instanceof BooleanField)
+            field.setObject(((BooleanField)f).getObject());
+        else try {
+            field.setObject(BooleanConverter.convert(f.objectAsString()));
+        } catch (final FieldConvertError e) {
+            throw newIncorrectDataException(e, field.getField());
+        }
+        return field;
     }
 
+
     public CharField getField(CharField field) throws FieldNotFound {
-        return updateValue(field, getChar(field.getField()));
+        Field<?> f = getField(field.getField(), true);
+        if(f instanceof CharField)
+            field.setObject(((CharField) f).getObject());
+        else try {
+            field.setObject(CharConverter.convert(f.objectAsString()));
+        } catch (final FieldConvertError e) {
+            throw newIncorrectDataException(e, field.getField());
+        }
+        return field;
     }
 
     public IntField getField(IntField field) throws FieldNotFound {
-        return updateValue(field, getInt(field.getField()));
+        Field<?> f = getField(field.getField(), true);
+        if(f instanceof IntField)
+            field.setObject(((IntField)f).getObject());
+        else try {
+            field.setObject(IntConverter.convert(f.objectAsString()));
+        } catch (final FieldConvertError e) {
+            throw newIncorrectDataException(e, field.getField());
+        }
+        return field;
     }
 
     public DoubleField getField(DoubleField field) throws FieldNotFound {
-        return updateValue(field, getDouble(field.getField()));
+        Field<?> f = getField(field.getField(), true);
+        if(f instanceof DoubleField)
+            field.setObject(((DoubleField)f).getObject());
+        else try {
+            field.setObject(DoubleConverter.convert(f.objectAsString()));
+        } catch (final FieldConvertError e) {
+            throw newIncorrectDataException(e, field.getField());
+        }
+        return field;
     }
 
     public DecimalField getField(DecimalField field) throws FieldNotFound {
-        return updateValue(field, getDecimal(field.getField()));
+        Field<?> f = getField(field.getField(), true);
+        if(f instanceof DecimalField)
+            field.setObject(((DecimalField)f).getObject());
+        else try {
+            field.setObject(DecimalConverter.convert(f.objectAsString()));
+        } catch (final FieldConvertError e) {
+            throw newIncorrectDataException(e, field.getField());
+        }
+        return field;
     }
 
     public UtcTimeStampField getField(UtcTimeStampField field) throws FieldNotFound {
-        return updateValue(field, getUtcTimeStamp(field.getField()));
+        Field<?> f = getField(field.getField(), true);
+        if(f instanceof UtcTimeStampField)
+            field.setObject(((UtcTimeStampField)f).getObject());
+        else try {
+            field.setObject(UtcTimestampConverter.convert(f.objectAsString()));
+        } catch (final FieldConvertError e) {
+            throw newIncorrectDataException(e, field.getField());
+        }
+        return field;
     }
 
     public UtcTimeOnlyField getField(UtcTimeOnlyField field) throws FieldNotFound {
-        return updateValue(field, getUtcTimeOnly(field.getField()));
+        Field<?> f = getField(field.getField(), true);
+        if(f instanceof UtcTimeOnlyField)
+            field.setObject(((UtcTimeOnlyField)f).getObject());
+        else try {
+            field.setObject(UtcTimeOnlyConverter.convert(f.objectAsString()));
+        } catch (final FieldConvertError e) {
+            throw newIncorrectDataException(e, field.getField());
+        }
+        return field;
     }
 
     public UtcDateOnlyField getField(UtcDateOnlyField field) throws FieldNotFound {
-        return updateValue(field, getUtcDateOnly(field.getField()));
+        Field<?> f = getField(field.getField(), true);
+        if(f instanceof UtcDateOnlyField)
+            field.setObject(((UtcDateOnlyField)f).getObject());
+        else try {
+            field.setObject(UtcDateOnlyConverter.convert(f.objectAsString()));
+        } catch (final FieldConvertError e) {
+            throw newIncorrectDataException(e, field.getField());
+        }
+        return field;
     }
 
     private FieldException newIncorrectDataException(FieldConvertError e, int tag) {
@@ -543,14 +645,10 @@ public void addGroupRef(Group group) {
 
     protected void setGroupCount(int countTag, int groupSize) {
         try {
-            StringField count;
-            if (groupSize == 1) {
-                count = new StringField(countTag, "1");
-                setField(countTag, count);
-            } else {
-                count = getField(countTag);
-            }
-            count.setValue(Integer.toString(groupSize));
+            if (groupSize == 1)
+                setField(countTag, new StringField(countTag, "1"));
+            else
+                getField(countTag).setValue(NumbersCache.get(groupSize));
         } catch (final FieldNotFound e) {
             // Shouldn't happen
             throw new RuntimeError(e);

From 37121ebd847124dedc0c6faac044813157ab328d Mon Sep 17 00:00:00 2001
From: Charles Briquel <charlesbr1@users.noreply.github.com>
Date: Sat, 24 Oct 2015 14:01:08 +0200
Subject: [PATCH 3/4] Update MessageComponent.java

Fixed a regression (ClassCastException) with components
---
 .../src/main/java/quickfix/MessageComponent.java          | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/quickfixj-core/src/main/java/quickfix/MessageComponent.java b/quickfixj-core/src/main/java/quickfix/MessageComponent.java
index f172764dae..17741866d0 100644
--- a/quickfixj-core/src/main/java/quickfix/MessageComponent.java
+++ b/quickfixj-core/src/main/java/quickfix/MessageComponent.java
@@ -21,12 +21,12 @@ public void copyFrom(FieldMap fields) {
         try {
             for (int componentField : getFields()) {
                 if (fields.isSetField(componentField)) {
-                    setField(componentField, fields.getField(componentField));
+                    setField(componentField, fields.getField(componentField, null));
                 }
             }
             for (int groupField : getGroupFields()) {
                 if (fields.isSetField(groupField)) {
-                    setField(groupField, fields.getField(groupField));
+                    setField(groupField, fields.getField(groupField, null));
                     setGroups(groupField, fields.getGroups(groupField));
                 }
             }
@@ -39,12 +39,12 @@ public void copyTo(FieldMap fields) {
         try {
             for (int componentField : getFields()) {
                 if (isSetField(componentField)) {
-                    fields.setField(componentField, getField(componentField));
+                    fields.setField(componentField, getField(componentField, null));
                 }
             }
             for (int groupField : getGroupFields()) {
                 if (isSetField(groupField)) {
-                    fields.setField(groupField, getField(groupField));
+                    fields.setField(groupField, getField(groupField, null));
                     fields.setGroups(groupField, getGroups(groupField));
                 }
             }

From 04f4c51f354322f418df70839f3b9f3525d18548 Mon Sep 17 00:00:00 2001
From: Charles Briquel <charlesbr1@users.noreply.github.com>
Date: Sat, 24 Oct 2015 14:02:12 +0200
Subject: [PATCH 4/4] Update MessageComponent.java

---
 .../main/java/quickfix/MessageComponent.java  | 40 ++++++++-----------
 1 file changed, 16 insertions(+), 24 deletions(-)

diff --git a/quickfixj-core/src/main/java/quickfix/MessageComponent.java b/quickfixj-core/src/main/java/quickfix/MessageComponent.java
index 17741866d0..44f4dc34b7 100644
--- a/quickfixj-core/src/main/java/quickfix/MessageComponent.java
+++ b/quickfixj-core/src/main/java/quickfix/MessageComponent.java
@@ -18,38 +18,30 @@ protected MessageComponent(int[] fieldOrder) {
     }
 
     public void copyFrom(FieldMap fields) {
-        try {
-            for (int componentField : getFields()) {
-                if (fields.isSetField(componentField)) {
-                    setField(componentField, fields.getField(componentField, null));
-                }
+        for (int componentField : getFields()) {
+            if (fields.isSetField(componentField)) {
+                setField(componentField, fields.getField(componentField, null));
             }
-            for (int groupField : getGroupFields()) {
-                if (fields.isSetField(groupField)) {
-                    setField(groupField, fields.getField(groupField, null));
-                    setGroups(groupField, fields.getGroups(groupField));
-                }
+        }
+        for (int groupField : getGroupFields()) {
+            if (fields.isSetField(groupField)) {
+                setField(groupField, fields.getField(groupField, null));
+                setGroups(groupField, fields.getGroups(groupField));
             }
-        } catch (FieldNotFound e) {
-            // should not happen
         }
     }
 
     public void copyTo(FieldMap fields) {
-        try {
-            for (int componentField : getFields()) {
-                if (isSetField(componentField)) {
-                    fields.setField(componentField, getField(componentField, null));
-                }
+        for (int componentField : getFields()) {
+            if (isSetField(componentField)) {
+                fields.setField(componentField, getField(componentField, null));
             }
-            for (int groupField : getGroupFields()) {
-                if (isSetField(groupField)) {
-                    fields.setField(groupField, getField(groupField, null));
-                    fields.setGroups(groupField, getGroups(groupField));
-                }
+        }
+        for (int groupField : getGroupFields()) {
+            if (isSetField(groupField)) {
+                fields.setField(groupField, getField(groupField, null));
+                fields.setGroups(groupField, getGroups(groupField));
             }
-        } catch (FieldNotFound e) {
-            // should not happen
         }
     }