From b5d77b7db034a8382484b06cc1c4727594ad2471 Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 10:09:03 -0500 Subject: [PATCH 01/15] Create NumbersCache.java A cache for strings 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 littleNumbers; + public static final ArrayList bigNumbers; + + static { + littleNumbers = new ArrayList(littleNumbersLength); + bigNumbers = new ArrayList(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 c0901c302620f82d77ed3d8f330d51a211d6b1b7 Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 10:11:10 -0500 Subject: [PATCH 02/15] Allocations optimization See pull request Allocations optimization for converters #34 --- .../converter/AbstractDateTimeConverter.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/field/converter/AbstractDateTimeConverter.java b/quickfixj-core/src/main/java/quickfix/field/converter/AbstractDateTimeConverter.java index cc1d2bdcfb..1c1a33ec86 100644 --- a/quickfixj-core/src/main/java/quickfix/field/converter/AbstractDateTimeConverter.java +++ b/quickfixj-core/src/main/java/quickfix/field/converter/AbstractDateTimeConverter.java @@ -21,6 +21,7 @@ import java.text.DateFormat; import java.text.DateFormatSymbols; +import java.text.FieldPosition; import java.text.SimpleDateFormat; import java.util.Locale; import java.util.TimeZone; @@ -56,18 +57,31 @@ protected static void throwFieldConvertError(String value, String type) } protected static long parseLong(String s) { + return parseLong(s, 0, s.length()); + } + + protected static long parseLong(String s, int begin, int end) { long n = 0; - for (int i = 0; i < s.length(); i++) { + for (int i = begin; i < end; i++) { n = (n * 10) + (s.charAt(i) - '0'); } return n; } - protected DateFormat createDateFormat(String format) { + protected static DateFormat createDateFormat(String format) { SimpleDateFormat sdf = new SimpleDateFormat(format); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); sdf.setDateFormatSymbols(new DateFormatSymbols(Locale.US)); return sdf; } + static final class DontCareFieldPosition extends FieldPosition { + // The singleton of DontCareFieldPosition. + static final FieldPosition INSTANCE = new DontCareFieldPosition(); + + private DontCareFieldPosition() { + super(0); + } + } + } From d8cd45b78f46e0712b10a7f36c2595bb11344f9d Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 10:11:44 -0500 Subject: [PATCH 03/15] Allocations optimization See pull request Allocations optimization for converters #34 --- .../field/converter/UtcDateOnlyConverter.java | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java b/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java index 593bad0448..5484340a8f 100644 --- a/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java +++ b/quickfixj-core/src/main/java/quickfix/field/converter/UtcDateOnlyConverter.java @@ -29,10 +29,20 @@ * Convert between a date and a String */ public class UtcDateOnlyConverter extends AbstractDateTimeConverter { + + protected static final class Context { + private final DateFormat dateFormat = createDateFormat("yyyyMMdd"); + private final StringBuffer buffer = new StringBuffer(128); + } + // SimpleDateFormats are not thread safe. A thread local is being // used to maintain high concurrency among multiple session threads - private static final ThreadLocal utcDateConverter = new ThreadLocal(); - private final DateFormat dateFormat = createDateFormat("yyyyMMdd"); + private static final ThreadLocal utcDateConverter = new ThreadLocal() { + @Override + protected Context initialValue() { + return new Context(); + } + }; /** * Convert a date to a String ("YYYYMMDD") @@ -41,16 +51,29 @@ public class UtcDateOnlyConverter extends AbstractDateTimeConverter { * @return the formatted date */ public static String convert(Date d) { - return getFormatter().format(d); + Context context = utcDateConverter.get(); + try { + context.dateFormat.format(d, context.buffer, DontCareFieldPosition.INSTANCE); + return context.buffer.toString(); + } finally { + context.buffer.setLength(0); + } } - private static DateFormat getFormatter() { - UtcDateOnlyConverter converter = utcDateConverter.get(); - if (converter == null) { - converter = new UtcDateOnlyConverter(); - utcDateConverter.set(converter); + /** + * Convert a date to a String ("YYYYMMDD") + * + * @param d the date to convert + * @param stringBuilder the out buffer to hold formatted date + */ + public static void convert(Date d, StringBuilder stringBuilder) { + Context context = utcDateConverter.get(); + try { + context.dateFormat.format(d, context.buffer, DontCareFieldPosition.INSTANCE); + stringBuilder.append(context.buffer); + } finally { + context.buffer.setLength(0); } - return converter.dateFormat; } /** @@ -66,7 +89,7 @@ public static Date convert(String value) throws FieldConvertError { assertLength(value, 8, type); assertDigitSequence(value, 0, 8, type); try { - d = getFormatter().parse(value); + d = utcDateConverter.get().dateFormat.parse(value); } catch (ParseException e) { throwFieldConvertError(value, type); } From 6cba620f254b1e2c08da7418ed6e73209d55de68 Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 10:14:38 -0500 Subject: [PATCH 04/15] Allocations optimization See pull request Allocations optimization for converters #34 --- .../field/converter/UtcTimeOnlyConverter.java | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java index 797bb36e23..307a7b895e 100644 --- a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java +++ b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimeOnlyConverter.java @@ -29,11 +29,21 @@ * Convert between a time and a String. */ public class UtcTimeOnlyConverter extends AbstractDateTimeConverter { + + protected static final class Context { + private final DateFormat utcTimeFormat = createDateFormat("HH:mm:ss"); + private final DateFormat utcTimeFormatMillis = createDateFormat("HH:mm:ss.SSS"); + private final StringBuffer buffer = new StringBuffer(128); + } + // SimpleDateFormats are not thread safe. A thread local is being // used to maintain high concurrency among multiple session threads - private static final ThreadLocal utcTimeConverter = new ThreadLocal(); - private final DateFormat utcTimeFormat = createDateFormat("HH:mm:ss"); - private final DateFormat utcTimeFormatMillis = createDateFormat("HH:mm:ss.SSS"); + private static final ThreadLocal utcTimeConverter = new ThreadLocal() { + @Override + protected Context initialValue() { + return new Context(); + } + }; /** * Convert a time (represented as a Date) to a String (HH:MM:SS or HH:MM:SS.SSS) @@ -43,15 +53,36 @@ public class UtcTimeOnlyConverter extends AbstractDateTimeConverter { * @return a String representing the time. */ public static String convert(Date d, boolean includeMilliseconds) { - return getFormatter(includeMilliseconds).format(d); + Context context = utcTimeConverter.get(); + try { + (includeMilliseconds ? context.utcTimeFormatMillis : context.utcTimeFormat) + .format(d, context.buffer, DontCareFieldPosition.INSTANCE); + return context.buffer.toString(); + } finally { + context.buffer.setLength(0); + } } - private static DateFormat getFormatter(boolean includeMillis) { - UtcTimeOnlyConverter converter = utcTimeConverter.get(); - if (converter == null) { - converter = new UtcTimeOnlyConverter(); - utcTimeConverter.set(converter); + /** + * Convert a time (represented as a Date) to a String (HH:MM:SS or HH:MM:SS.SSS) + * + * @param d the date with the time to convert + * @param includeMilliseconds controls whether milliseconds are included in the result + * @param stringBuilder the out buffer to hold a String representing the time. + */ + public static void convert(Date d, StringBuilder stringBuilder, boolean includeMilliseconds) { + Context context = utcTimeConverter.get(); + try { + (includeMilliseconds ? context.utcTimeFormatMillis : context.utcTimeFormat) + .format(d, context.buffer, DontCareFieldPosition.INSTANCE); + stringBuilder.append(context.buffer); + } finally { + context.buffer.setLength(0); } + } + + private static DateFormat getFormatter(boolean includeMillis) { + Context converter = utcTimeConverter.get(); return includeMillis ? converter.utcTimeFormatMillis : converter.utcTimeFormat; } From f1b138f42015f70483b3922bccd7999f17f77183 Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 10:15:26 -0500 Subject: [PATCH 05/15] Allocations optimization See pull request Allocations optimization for converters #34 --- .../converter/UtcTimestampConverter.java | 55 ++++++++++++++----- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java index 8b2cfcc916..e515c25491 100644 --- a/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java +++ b/quickfixj-core/src/main/java/quickfix/field/converter/UtcTimestampConverter.java @@ -33,9 +33,20 @@ * and a time. */ public class UtcTimestampConverter extends AbstractDateTimeConverter { - private static final ThreadLocal utcTimestampConverter = new ThreadLocal(); - private final DateFormat utcTimestampFormat = createDateFormat("yyyyMMdd-HH:mm:ss"); - private final DateFormat utcTimestampFormatMillis = createDateFormat("yyyyMMdd-HH:mm:ss.SSS"); + + protected static final class Context { + private final DateFormat utcTimestampFormat = createDateFormat("yyyyMMdd-HH:mm:ss"); + private final DateFormat utcTimestampFormatMillis = createDateFormat("yyyyMMdd-HH:mm:ss.SSS"); + private final StringBuffer buffer = new StringBuffer(128); + } + + private static final ThreadLocal utcTimestampConverter = new ThreadLocal() { + @Override + protected Context initialValue() { + return new Context(); + } + }; + private final static ConcurrentHashMap dateCache = new ConcurrentHashMap(); /** @@ -46,16 +57,32 @@ public class UtcTimestampConverter extends AbstractDateTimeConverter { * @return the formatted timestamp */ public static String convert(Date d, boolean includeMilliseconds) { - return getFormatter(includeMilliseconds).format(d); + Context context = utcTimestampConverter.get(); + try { + (includeMilliseconds ? context.utcTimestampFormatMillis : context.utcTimestampFormat) + .format(d, context.buffer, DontCareFieldPosition.INSTANCE); + return context.buffer.toString(); + } finally { + context.buffer.setLength(0); + } } - private static DateFormat getFormatter(boolean includeMillis) { - UtcTimestampConverter converter = utcTimestampConverter.get(); - if (converter == null) { - converter = new UtcTimestampConverter(); - utcTimestampConverter.set(converter); + /** + * Convert a timestamp (represented as a Date) to a String. + * + * @param d the date to convert + * @param includeMilliseconds controls whether milliseconds are included in the result + * @param stringBuilder the out buffer to hold the formatted timestamp + */ + public static void convert(Date d, StringBuilder stringBuilder, boolean includeMilliseconds) { + Context context = utcTimestampConverter.get(); + try { + (includeMilliseconds ? context.utcTimestampFormatMillis : context.utcTimestampFormat) + .format(d, context.buffer, DontCareFieldPosition.INSTANCE); + stringBuilder.append(context.buffer); + } finally { + context.buffer.setLength(0); } - return includeMillis ? converter.utcTimestampFormatMillis : converter.utcTimestampFormat; } // @@ -73,11 +100,11 @@ private static DateFormat getFormatter(boolean includeMillis) { */ public static Date convert(String value) throws FieldConvertError { verifyFormat(value); - long timeOffset = (parseLong(value.substring(9, 11)) * 3600000L) - + (parseLong(value.substring(12, 14)) * 60000L) - + (parseLong(value.substring(15, 17)) * 1000L); + long timeOffset = (parseLong(value, 9, 11) * 3600000L) + + (parseLong(value, 12, 14) * 60000L) + + (parseLong(value, 15, 17) * 1000L); if (value.length() == 21) { - timeOffset += parseLong(value.substring(18, 21)); + timeOffset += parseLong(value, 18, 21); } return new Date(getMillisForDay(value) + timeOffset); } From e1631d0043b9c134b3bf1a754cecbd58436c8104 Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 10:20:01 -0500 Subject: [PATCH 06/15] Allocations optimization Improve the way data attribute is cached (reuse the data field in toString(...) method. Use thread local buffer to generate the data attribute. --- .../src/main/java/quickfix/Field.java | 92 +++++++++++++++---- 1 file changed, 73 insertions(+), 19 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/Field.java b/quickfixj-core/src/main/java/quickfix/Field.java index cd3ee8f068..29f05a8600 100644 --- a/quickfixj-core/src/main/java/quickfix/Field.java +++ b/quickfixj-core/src/main/java/quickfix/Field.java @@ -22,6 +22,7 @@ import org.quickfixj.CharsetSupport; import java.io.Serializable; +import java.math.BigDecimal; /** * Base class for FIX message fields. This class should be @@ -32,8 +33,7 @@ static final long serialVersionUID = 7098326013456432197L; private int tag; private T object; - private boolean isCalculated = false; - private String data; + protected String data; public Field(int field, T object) { this.tag = field; @@ -66,7 +66,7 @@ public int getField() { */ protected void setObject(T object) { this.object = object; - isCalculated = false; + data = null; } /** @@ -89,22 +89,70 @@ public String toString() { } /*package*/ void toString(StringBuilder buffer) { - buffer.append(tag).append('=').append(objectAsString()); + if(null != data) { + buffer.append(data); + return; + } + buffer.append(quickfix.NumbersCache.get(tag)).append('='); + if(object instanceof Number) { + if(object instanceof Integer) + appendNumber(buffer, ((Integer)object).longValue()); + else if(object instanceof Double) + appendDouble(buffer, (Double) object); + else if(object instanceof Float) + buffer.append(((Float)object).floatValue()); + else if(object instanceof BigDecimal) + buffer.append(((BigDecimal)object).toPlainString()); + else + appendNumber(buffer, ((Number)object).longValue()); + } else + objectAsString(buffer); + } + + private static void appendNumber(StringBuilder buffer, long value) { + if(value < 0) { + buffer.append('-'); + value = Math.abs(value); + } + buffer.append(quickfix.NumbersCache.get(value)); + } + + private static void appendDouble(StringBuilder buffer, double value) { + if(value < 0d) { + buffer.append('-'); + value = Math.abs(value); + } + String str = quickfix.NumbersCache.get(value); + if(null != str) + buffer.append(str); + else + buffer.append(value); } protected String objectAsString() { return object.toString(); } + protected void objectAsString(StringBuilder stringBuilder) { + stringBuilder.append(objectAsString()); + } + public boolean equals(Object object) { - return super.equals(object) - || object instanceof Field - && tag == ((Field) object).getField() - && getObject().equals(((Field) object).getObject()); + return super.equals(object) || (object instanceof Field && + ((Field) object).equals(tag, getObject())); + } + + private boolean equals(int tag, Object object) { + if(this.tag != tag) + return false; + Object thisObject = getObject(); + if(thisObject == null) + return object == null; + return thisObject.equals(object); } public int hashCode() { - return object.hashCode(); + return getObject().hashCode(); } /** @@ -129,21 +177,27 @@ public int hashCode() { return (MessageUtils.checksum(CharsetSupport.getCharsetInstance(), data, false) + 1) & 0xFF; } - private void calculate() { - if (isCalculated) { - return; + private static final ThreadLocal buffers = new ThreadLocal() { + @Override + protected StringBuilder initialValue() { + return new StringBuilder(256); } + }; - StringBuilder buffer = new StringBuilder(); - toString(buffer); - data = buffer.toString(); - - isCalculated = true; + private void calculate() { + if(null == data) { + StringBuilder buffer = buffers.get(); + try { + toString(buffer); + data = buffer.toString(); + } finally { + buffer.setLength(0); + } + } } public void setTag(int tag) { this.tag = tag; - isCalculated = false; - calculate(); + data = null; } } From f4a217500a6c6827d162ea38fc84b806e8260a21 Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 10:21:25 -0500 Subject: [PATCH 07/15] Allocations optimization Use the Boolean converter to convert the value to a string --- .../src/main/java/quickfix/BooleanField.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/BooleanField.java b/quickfixj-core/src/main/java/quickfix/BooleanField.java index 1094b25779..113c1b399c 100644 --- a/quickfixj-core/src/main/java/quickfix/BooleanField.java +++ b/quickfixj-core/src/main/java/quickfix/BooleanField.java @@ -19,7 +19,7 @@ package quickfix; -import java.lang.Boolean; +import quickfix.field.converter.BooleanConverter; public class BooleanField extends Field { @@ -28,11 +28,11 @@ public BooleanField(int field) { } public BooleanField(int field, Boolean data) { - super(field, data); + super(field, null != data ? data : Boolean.FALSE); } public BooleanField(int field, boolean data) { - super(field, data); + super(field, Boolean.valueOf(data)); } public void setValue(Boolean value) { @@ -54,4 +54,14 @@ public boolean valueEquals(Boolean value) { public boolean valueEquals(boolean value) { return getObject().equals(value); } + + @Override + protected String objectAsString() { + return BooleanConverter.convert(getValue()); + } + + @Override + protected void objectAsString(StringBuilder stringBuilder) { + stringBuilder.append(objectAsString()); + } } From b0d10c6cde03067a0b8c47cd72f2567aaed570c3 Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 10:23:05 -0500 Subject: [PATCH 08/15] Allocations optimization Use the DoubleConverter to convert value to a string. Avoid creation of a Double instance when using a scalar double. --- .../src/main/java/quickfix/DoubleField.java | 73 +++++++++++++++++-- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/DoubleField.java b/quickfixj-core/src/main/java/quickfix/DoubleField.java index 419b269ef0..02900508e2 100644 --- a/quickfixj-core/src/main/java/quickfix/DoubleField.java +++ b/quickfixj-core/src/main/java/quickfix/DoubleField.java @@ -19,30 +19,37 @@ package quickfix; +import quickfix.field.converter.DoubleConverter; + /** * A double-values message field. */ public class DoubleField extends Field { + private static final Double ZERO = 0d; + private double value = 0d; private int padding = 0; public DoubleField(int field) { - super(field, 0d); + super(field, ZERO); } public DoubleField(int field, Double data) { super(field, data); checkForValidDouble(data); + value = data; } public DoubleField(int field, double data) { - super(field, data); + super(field, ZERO); checkForValidDouble(data); + value = data; } public DoubleField(int field, double data, int padding) { - super(field, data); + super(field, ZERO); checkForValidDouble(data); + value = data; this.padding = padding; } @@ -53,11 +60,26 @@ public void setValue(Double value) { public void setValue(double value) { checkForValidDouble(value); - setObject(value); + this.value = value; } public double getValue() { - return getObject(); + return value; + } + + @Override + protected void setObject(Double object) { + super.setObject(object); + value = object; + } + + @Override + public Double getObject() { + Double val = super.getObject(); + if(null != val && value == val) + return val; + super.setObject(value); + return super.getObject(); } public int getPadding() { @@ -65,17 +87,52 @@ public int getPadding() { } public boolean valueEquals(Double value) { - return getObject().equals(value); + return null != value && valueEquals(value.doubleValue()); } public boolean valueEquals(double value) { - return getObject().equals(value); + return this.value == value; } // QFJ-808: NaN or infinity values cannot be transmitted via FIX in a DoubleField - private void checkForValidDouble(Double value) throws NumberFormatException { + private void checkForValidDouble(double value) throws NumberFormatException { if (Double.isInfinite(value) || Double.isNaN(value)) { throw new NumberFormatException("Tried to set NaN or infinite value."); } } + + @Override + void toString(StringBuilder buffer) { + if (null != super.data) { + buffer.append(super.data); + return; + } + buffer.append(NumbersCache.get(getTag())).append('='); + double val = value; + if(val < 0d) { + buffer.append('-'); + val = Math.abs(val); + } + String str = NumbersCache.get(val); + if(null != str) + buffer.append(str); + else + buffer.append(val); + } + + @Override + protected String objectAsString() { + return DoubleConverter.convert(value); + } + + @Override + protected void objectAsString(StringBuilder stringBuilder) { + stringBuilder.append(value); + } + + @Override + public int hashCode() { + long bits = Double.doubleToLongBits(value); + return (int)(bits ^ (bits >>> 32)); + } } From 7a4082b9d1897050d0ab8ee558567b48c3a5f6cd Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 10:24:57 -0500 Subject: [PATCH 09/15] Allocations optimization Use the UtcDateOnlyConverter converter to convert value to a string --- .../src/main/java/quickfix/UtcDateOnlyField.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/quickfixj-core/src/main/java/quickfix/UtcDateOnlyField.java b/quickfixj-core/src/main/java/quickfix/UtcDateOnlyField.java index 427b02c26b..9d991f9222 100644 --- a/quickfixj-core/src/main/java/quickfix/UtcDateOnlyField.java +++ b/quickfixj-core/src/main/java/quickfix/UtcDateOnlyField.java @@ -21,6 +21,8 @@ import java.util.Date; +import quickfix.field.converter.UtcDateOnlyConverter; + /** * A date-valued message field. */ @@ -32,4 +34,15 @@ public UtcDateOnlyField(int field) { protected UtcDateOnlyField(int field, Date data) { super(field, data); } + + @Override + protected String objectAsString() { + return UtcDateOnlyConverter.convert(getValue()); + } + + @Override + protected void objectAsString(StringBuilder stringBuilder) { + UtcDateOnlyConverter.convert(getValue(), stringBuilder); + } + } From 7cead85cdd203e5602ad8ede0f5ce61dd758f44e Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 10:26:55 -0500 Subject: [PATCH 10/15] Allocations optimization Use the UtcTimeOnlyConverter converter to convert value to a string --- .../src/main/java/quickfix/UtcTimeOnlyField.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/quickfixj-core/src/main/java/quickfix/UtcTimeOnlyField.java b/quickfixj-core/src/main/java/quickfix/UtcTimeOnlyField.java index 73f73c6706..2959e8525b 100644 --- a/quickfixj-core/src/main/java/quickfix/UtcTimeOnlyField.java +++ b/quickfixj-core/src/main/java/quickfix/UtcTimeOnlyField.java @@ -21,6 +21,8 @@ import java.util.Date; +import quickfix.field.converter.UtcTimeOnlyConverter; + /* * A time-valued message field. */ @@ -49,4 +51,14 @@ boolean showMilliseconds() { return includeMilliseconds; } + @Override + protected String objectAsString() { + return UtcTimeOnlyConverter.convert(getValue(), showMilliseconds()); + } + + @Override + protected void objectAsString(StringBuilder stringBuilder) { + UtcTimeOnlyConverter.convert(getValue(), stringBuilder, showMilliseconds()); + } + } From 6c3bbb0346d183e4d91da04451061c3e167e4e94 Mon Sep 17 00:00:00 2001 From: charlesbr1 Date: Fri, 31 Jul 2015 10:28:15 -0500 Subject: [PATCH 11/15] Allocations optimization Use the UtcTimestampConverter converter to convert value to a string --- .../src/main/java/quickfix/UtcTimeStampField.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/quickfixj-core/src/main/java/quickfix/UtcTimeStampField.java b/quickfixj-core/src/main/java/quickfix/UtcTimeStampField.java index fd09564e60..c5c85be17a 100644 --- a/quickfixj-core/src/main/java/quickfix/UtcTimeStampField.java +++ b/quickfixj-core/src/main/java/quickfix/UtcTimeStampField.java @@ -21,6 +21,8 @@ import java.util.Date; +import quickfix.field.converter.UtcTimestampConverter; + /** * A timestamp-valued message field (a timestamp has both a date and a time). */ @@ -48,4 +50,14 @@ protected UtcTimeStampField(int field, Date data, boolean includeMilliseconds) { boolean showMilliseconds() { return includeMilliseconds; } + + @Override + protected String objectAsString() { + return UtcTimestampConverter.convert(getValue(), showMilliseconds()); + } + + @Override + protected void objectAsString(StringBuilder stringBuilder) { + UtcTimestampConverter.convert(getValue(), stringBuilder, showMilliseconds()); + } } From fdf39451fa6826b3c299a4c3ac981bbbb9da02b1 Mon Sep 17 00:00:00 2001 From: Charles Briquel Date: Sat, 24 Oct 2015 14:20:14 +0200 Subject: [PATCH 12/15] Update FileStore.java Avoid string allocation when storing next target / sender sequence number --- quickfixj-core/src/main/java/quickfix/FileStore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/FileStore.java b/quickfixj-core/src/main/java/quickfix/FileStore.java index 945f34204f..737f3f927e 100644 --- a/quickfixj-core/src/main/java/quickfix/FileStore.java +++ b/quickfixj-core/src/main/java/quickfix/FileStore.java @@ -403,12 +403,12 @@ public boolean set(int sequence, String message) throws IOException { private void storeSenderSequenceNumber() throws IOException { senderSequenceNumberFile.seek(0); - senderSequenceNumberFile.writeUTF("" + cache.getNextSenderMsgSeqNum()); + senderSequenceNumberFile.writeUTF(NumbersCache.get(cache.getNextSenderMsgSeqNum())); } private void storeTargetSequenceNumber() throws IOException { targetSequenceNumberFile.seek(0); - targetSequenceNumberFile.writeUTF("" + cache.getNextTargetMsgSeqNum()); + targetSequenceNumberFile.writeUTF(NumbersCache.get(cache.getNextTargetMsgSeqNum())); } String getHeaderFileName() { From 5deaa48fb55cc5905f1ede384bf7fe3eda1412bb Mon Sep 17 00:00:00 2001 From: Charles Briquel Date: Tue, 29 Dec 2015 15:42:54 +0100 Subject: [PATCH 13/15] Update DoubleField.java Double value improperly converted to string --- quickfixj-core/src/main/java/quickfix/DoubleField.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/DoubleField.java b/quickfixj-core/src/main/java/quickfix/DoubleField.java index 02900508e2..231f4ad282 100644 --- a/quickfixj-core/src/main/java/quickfix/DoubleField.java +++ b/quickfixj-core/src/main/java/quickfix/DoubleField.java @@ -117,7 +117,7 @@ void toString(StringBuilder buffer) { if(null != str) buffer.append(str); else - buffer.append(val); + buffer.append(objectAsString()); } @Override @@ -127,7 +127,7 @@ protected String objectAsString() { @Override protected void objectAsString(StringBuilder stringBuilder) { - stringBuilder.append(value); + stringBuilder.append(objectAsString()); } @Override From 8cd6011fc2e5f40a1caaef0cfe8c48c82a07271f Mon Sep 17 00:00:00 2001 From: Charles Briquel Date: Tue, 29 Dec 2015 15:46:41 +0100 Subject: [PATCH 14/15] Update DoubleField.java --- quickfixj-core/src/main/java/quickfix/DoubleField.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/DoubleField.java b/quickfixj-core/src/main/java/quickfix/DoubleField.java index 231f4ad282..84185e4dec 100644 --- a/quickfixj-core/src/main/java/quickfix/DoubleField.java +++ b/quickfixj-core/src/main/java/quickfix/DoubleField.java @@ -117,7 +117,7 @@ void toString(StringBuilder buffer) { if(null != str) buffer.append(str); else - buffer.append(objectAsString()); + buffer.append(DoubleConverter.convert(val)); } @Override From f6774e8e52b199e951c3a09cc5849983e2b17d0f Mon Sep 17 00:00:00 2001 From: Charles Briquel Date: Tue, 29 Dec 2015 15:49:30 +0100 Subject: [PATCH 15/15] Update Field.java fixed a regression on double conversion --- quickfixj-core/src/main/java/quickfix/Field.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickfixj-core/src/main/java/quickfix/Field.java b/quickfixj-core/src/main/java/quickfix/Field.java index 29f05a8600..94d940f86c 100644 --- a/quickfixj-core/src/main/java/quickfix/Field.java +++ b/quickfixj-core/src/main/java/quickfix/Field.java @@ -20,6 +20,7 @@ package quickfix; import org.quickfixj.CharsetSupport; +import quickfix.field.converter.DoubleConverter; import java.io.Serializable; import java.math.BigDecimal; @@ -126,7 +127,7 @@ private static void appendDouble(StringBuilder buffer, double value) { if(null != str) buffer.append(str); else - buffer.append(value); + buffer.append(DoubleConverter.convert(value)); } protected String objectAsString() {