Skip to content

Commit 907e5ce

Browse files
committed
allowing custom float overflow handling
1 parent 7f1998c commit 907e5ce

File tree

15 files changed

+648
-21
lines changed

15 files changed

+648
-21
lines changed

artio-codecs/src/main/java/uk/co/real_logic/artio/builder/CommonDecoderImpl.java

+27-4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import uk.co.real_logic.artio.fields.DecimalFloat;
1919
import uk.co.real_logic.artio.util.AsciiBuffer;
20+
import uk.co.real_logic.artio.util.float_parsing.DecimalFloatOverflowHandler;
2021

2122
import static uk.co.real_logic.artio.dictionary.generation.CodecUtil.MISSING_INT;
2223
import static uk.co.real_logic.artio.dictionary.generation.CodecUtil.MISSING_LONG;
@@ -31,6 +32,7 @@ public abstract class CommonDecoderImpl
3132
protected int invalidTagId = Decoder.NO_ERROR;
3233
protected int rejectReason = Decoder.NO_ERROR;
3334
protected AsciiBuffer buffer;
35+
protected DecimalFloatOverflowHandler decimalFloatOverflowHandler;
3436

3537
public int invalidTagId()
3638
{
@@ -82,11 +84,12 @@ public long getLong(
8284

8385
public DecimalFloat getFloat(
8486
final AsciiBuffer buffer,
85-
final DecimalFloat number, final int offset, final int length, final int tag, final boolean validation)
87+
final DecimalFloat number, final int offset, final int length, final int tag, final boolean validation,
88+
final DecimalFloatOverflowHandler decimalFloatOverflowHandler)
8689
{
8790
try
8891
{
89-
return buffer.getFloat(number, offset, length);
92+
return buffer.getFloat(number, offset, length, tag, decimalFloatOverflowHandler);
9093
}
9194
catch (final NumberFormatException | ArithmeticException e)
9295
{
@@ -104,6 +107,14 @@ public DecimalFloat getFloat(
104107
}
105108
}
106109

110+
public DecimalFloat getFloat(
111+
final AsciiBuffer buffer,
112+
final DecimalFloat number, final int offset, final int length, final int tag, final boolean validation)
113+
{
114+
return getFloat(buffer, number, offset, length, tag, validation, null);
115+
}
116+
117+
107118
public int getIntFlyweight(
108119
final AsciiBuffer buffer, final int offset, final int length, final int tag, final boolean validation)
109120
{
@@ -168,11 +179,12 @@ public DecimalFloat getFloatFlyweight(
168179
final int offset,
169180
final int length,
170181
final int tag,
171-
final boolean codecValidationEnabled)
182+
final boolean codecValidationEnabled,
183+
final DecimalFloatOverflowHandler decimalFloatOverflowHandler)
172184
{
173185
try
174186
{
175-
return buffer.getFloat(number, offset, length);
187+
return buffer.getFloat(number, offset, length, tag, decimalFloatOverflowHandler);
176188
}
177189
catch (final NumberFormatException e)
178190
{
@@ -187,4 +199,15 @@ public DecimalFloat getFloatFlyweight(
187199
}
188200
}
189201
}
202+
203+
public DecimalFloat getFloatFlyweight(
204+
final AsciiBuffer buffer,
205+
final DecimalFloat number,
206+
final int offset,
207+
final int length,
208+
final int tag,
209+
final boolean codecValidationEnabled)
210+
{
211+
return getFloatFlyweight(buffer, number, offset, length, tag, codecValidationEnabled, null);
212+
}
190213
}

artio-codecs/src/main/java/uk/co/real_logic/artio/dictionary/generation/CodecConfiguration.java

+35
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.io.InputStream;
2222
import java.util.function.BiFunction;
2323

24+
import uk.co.real_logic.artio.util.float_parsing.DecimalFloatOverflowHandler;
25+
2426
public final class CodecConfiguration
2527
{
2628
/**
@@ -55,6 +57,7 @@ public final class CodecConfiguration
5557
public static final String PARENT_PACKAGE_PROPERTY = "fix.codecs.parent_package";
5658
public static final String FLYWEIGHTS_ENABLED_PROPERTY = "fix.codecs.flyweight";
5759
public static final String REJECT_UNKNOWN_ENUM_VALUE_PROPERTY = "reject.unknown.enum.value";
60+
public static final String FLOAT_OVERFLOW_HANDLER_PROPERTY = "float.overflow.handler";
5861
public static final String FIX_TAGS_IN_JAVADOC = "fix.codecs.tags_in_javadoc";
5962

6063
public static final String DEFAULT_PARENT_PACKAGE = "uk.co.real_logic.artio";
@@ -74,6 +77,7 @@ public final class CodecConfiguration
7477
private final GeneratorDictionaryConfiguration nonSharedDictionary =
7578
new GeneratorDictionaryConfiguration(null, null, null,
7679
Boolean.getBoolean(FIX_CODECS_ALLOW_DUPLICATE_FIELDS_PROPERTY));
80+
private Class<? extends DecimalFloatOverflowHandler> decimalFloatOverflowHandler = null;
7781

7882
public CodecConfiguration()
7983
{
@@ -94,6 +98,18 @@ public CodecConfiguration outputPath(final String outputPath)
9498
return this;
9599
}
96100

101+
public CodecConfiguration decimalFloatOverflowHandler(
102+
final Class<? extends DecimalFloatOverflowHandler> decimalFloatOverflowHandler)
103+
{
104+
this.decimalFloatOverflowHandler = decimalFloatOverflowHandler;
105+
return this;
106+
}
107+
108+
public Class<? extends DecimalFloatOverflowHandler> getDecimalFloatOverflowHandler()
109+
{
110+
return decimalFloatOverflowHandler;
111+
}
112+
97113
/**
98114
* Sets the parent package where classes are generated. Optional, defaults to {@link #DEFAULT_PARENT_PACKAGE}.
99115
* Different parent packages can be used to use multiple different fix dictionary versions, see the
@@ -305,5 +321,24 @@ void conclude()
305321
"Please provide a path to the XML files either through the fileNames() or fileStreams() option.");
306322
}
307323
}
324+
if (decimalFloatOverflowHandler == null)
325+
{
326+
327+
final String floatOverflowHandler = System.getProperty(FLOAT_OVERFLOW_HANDLER_PROPERTY);
328+
if (floatOverflowHandler != null)
329+
{
330+
try
331+
{
332+
//noinspection unchecked
333+
decimalFloatOverflowHandler = (Class<? extends DecimalFloatOverflowHandler>)Class.forName(
334+
floatOverflowHandler);
335+
}
336+
catch (final ClassNotFoundException e)
337+
{
338+
throw new IllegalArgumentException("Unable to load DecimalFloatOverflowHandler: " +
339+
floatOverflowHandler, e);
340+
}
341+
}
342+
}
308343
}
309344
}

artio-codecs/src/main/java/uk/co/real_logic/artio/dictionary/generation/CodecGenerator.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ private static void generateDictionary(
181181
false,
182182
configuration.wrapEmptyBuffer(),
183183
codecRejectUnknownEnumValueEnabled,
184-
configuration.fixTagsInJavadoc()).generate();
184+
configuration.fixTagsInJavadoc(),
185+
configuration.getDecimalFloatOverflowHandler()).generate();
185186

186187
new PrinterGenerator(dictionary, decoderPackage, decoderOutput).generate();
187188
new AcceptorGenerator(dictionary, decoderPackage, decoderOutput).generate();
@@ -203,7 +204,8 @@ private static void generateDictionary(
203204
true,
204205
configuration.wrapEmptyBuffer(),
205206
codecRejectUnknownEnumValueEnabled,
206-
configuration.fixTagsInJavadoc()).generate();
207+
configuration.fixTagsInJavadoc(),
208+
configuration.getDecimalFloatOverflowHandler()).generate();
207209
}
208210
}
209211
}

artio-codecs/src/main/java/uk/co/real_logic/artio/dictionary/generation/DecoderGenerator.java

+49-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import uk.co.real_logic.artio.dictionary.ir.Field.Type;
3030
import uk.co.real_logic.artio.fields.*;
3131
import uk.co.real_logic.artio.util.MessageTypeEncoding;
32+
import uk.co.real_logic.artio.util.float_parsing.DecimalFloatOverflowHandler;
3233

3334
import java.io.IOException;
3435
import java.io.Writer;
@@ -134,9 +135,42 @@ static String decoderClassName(final String name)
134135
final boolean wrapEmptyBuffer,
135136
final String codecRejectUnknownEnumValueEnabled,
136137
final boolean fixTagsInJavadoc)
138+
{
139+
this(dictionary,
140+
initialBufferSize,
141+
thisPackage,
142+
commonPackage,
143+
encoderPackage,
144+
outputManager,
145+
validationClass,
146+
rejectUnknownFieldClass,
147+
rejectUnknownEnumValueClass,
148+
flyweightsEnabled,
149+
wrapEmptyBuffer,
150+
codecRejectUnknownEnumValueEnabled,
151+
fixTagsInJavadoc,
152+
null);
153+
}
154+
155+
DecoderGenerator(
156+
final Dictionary dictionary,
157+
final int initialBufferSize,
158+
final String thisPackage,
159+
final String commonPackage,
160+
final String encoderPackage,
161+
final OutputManager outputManager,
162+
final Class<?> validationClass,
163+
final Class<?> rejectUnknownFieldClass,
164+
final Class<?> rejectUnknownEnumValueClass,
165+
final boolean flyweightsEnabled,
166+
final boolean wrapEmptyBuffer,
167+
final String codecRejectUnknownEnumValueEnabled,
168+
final boolean fixTagsInJavadoc,
169+
final Class<? extends DecimalFloatOverflowHandler> decimalFloatOverflowHandler)
137170
{
138171
super(dictionary, thisPackage, commonPackage, outputManager, validationClass, rejectUnknownFieldClass,
139-
rejectUnknownEnumValueClass, flyweightsEnabled, codecRejectUnknownEnumValueEnabled, fixTagsInJavadoc);
172+
rejectUnknownEnumValueClass, flyweightsEnabled, codecRejectUnknownEnumValueEnabled, fixTagsInJavadoc,
173+
decimalFloatOverflowHandler);
140174
this.initialBufferSize = initialBufferSize;
141175
this.encoderPackage = encoderPackage;
142176
this.wrapEmptyBuffer = wrapEmptyBuffer;
@@ -192,6 +226,11 @@ else if (type == HEADER)
192226

193227
importEncoders(aggregate, out);
194228

229+
if (decimalFloatOverflowHandler != null)
230+
{
231+
out.append(importFor(decimalFloatOverflowHandler));
232+
}
233+
195234
generateAggregateClass(aggregate, type, className, out);
196235
});
197236
}
@@ -255,6 +294,13 @@ else if (type == HEADER)
255294
}
256295

257296
out.append(classDeclaration(className, interfaces, false, aggregate.isInParent(), isGroup));
297+
if (decimalFloatOverflowHandler != null && type != HEADER)
298+
{
299+
out.append(String.format(" public %s() {\n\n", className));
300+
out.append(String.format(" decimalFloatOverflowHandler = new %s",
301+
decimalFloatOverflowHandler.getSimpleName() + "();\n\n"));
302+
out.append(" }\n\n");
303+
}
258304
generateValidation(out, aggregate, type);
259305
if (isMessage)
260306
{
@@ -2041,7 +2087,8 @@ private String fieldDecodeMethod(final Field field, final String fieldName)
20412087
return "";
20422088
}
20432089
decodeMethod = String.format(
2044-
"getFloat(buffer, %s, valueOffset, valueLength, %d, " + CODEC_VALIDATION_ENABLED + ")",
2090+
"getFloat(buffer, %s, valueOffset, valueLength, %d, " + CODEC_VALIDATION_ENABLED +
2091+
", decimalFloatOverflowHandler)",
20452092
fieldName, field.number());
20462093
break;
20472094
case CHAR:

artio-codecs/src/main/java/uk/co/real_logic/artio/dictionary/generation/EncoderGenerator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ static String encoderClassName(final String name)
169169
final boolean fixTagsInJavadoc)
170170
{
171171
super(dictionary, builderPackage, builderCommonPackage, outputManager, validationClass, rejectUnknownFieldClass,
172-
rejectUnknownEnumValueClass, false, codecRejectUnknownEnumValueEnabled, fixTagsInJavadoc);
172+
rejectUnknownEnumValueClass, false, codecRejectUnknownEnumValueEnabled, fixTagsInJavadoc, null);
173173

174174
final Component header = dictionary.header();
175175
validateHasField(header, BEGIN_STRING);

artio-codecs/src/main/java/uk/co/real_logic/artio/dictionary/generation/Generator.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import uk.co.real_logic.artio.fields.UtcTimestampEncoder;
3333
import uk.co.real_logic.artio.util.AsciiBuffer;
3434
import uk.co.real_logic.artio.util.MutableAsciiBuffer;
35+
import uk.co.real_logic.artio.util.float_parsing.DecimalFloatOverflowHandler;
3536

3637
import java.io.IOException;
3738
import java.io.Writer;
@@ -97,6 +98,7 @@ protected String commonCompoundImports(final String form, final boolean headerWr
9798
protected final boolean flyweightsEnabled;
9899
protected final String codecRejectUnknownEnumValueEnabled;
99100
protected final String scope;
101+
protected final Class<? extends DecimalFloatOverflowHandler> decimalFloatOverflowHandler;
100102
protected final boolean fixTagsInJavadoc;
101103

102104
protected final Deque<Aggregate> aggregateStack = new ArrayDeque<>();
@@ -111,7 +113,8 @@ protected Generator(
111113
final Class<?> rejectUnknownEnumValueClass,
112114
final boolean flyweightsEnabled,
113115
final String codecRejectUnknownEnumValueEnabled,
114-
final boolean fixTagsInJavadoc)
116+
final boolean fixTagsInJavadoc,
117+
final Class<? extends DecimalFloatOverflowHandler> decimalFloatOverflowHandler)
115118
{
116119
this.dictionary = dictionary;
117120
this.thisPackage = thisPackage;
@@ -125,6 +128,7 @@ protected Generator(
125128
this.fixTagsInJavadoc = fixTagsInJavadoc;
126129

127130
scope = dictionary.shared() ? "protected" : "private";
131+
this.decimalFloatOverflowHandler = decimalFloatOverflowHandler;
128132
}
129133

130134
public void generate()

artio-codecs/src/main/java/uk/co/real_logic/artio/util/AsciiBuffer.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import org.agrona.DirectBuffer;
1919
import uk.co.real_logic.artio.fields.DecimalFloat;
20+
import uk.co.real_logic.artio.util.float_parsing.DecimalFloatOverflowHandler;
2021

2122
/**
2223
* Mutable String class that flyweights a data buffer. This assumes a US-ASCII encoding
@@ -67,7 +68,18 @@ public interface AsciiBuffer extends DirectBuffer
6768

6869
long getMessageType(int offset, int length);
6970

70-
DecimalFloat getFloat(DecimalFloat number, int offset, int length);
71+
DecimalFloat getFloat(DecimalFloat number,
72+
int offset,
73+
int length,
74+
int tagId,
75+
DecimalFloatOverflowHandler decimalFloatOverflowHandler);
76+
77+
default DecimalFloat getFloat(DecimalFloat number,
78+
int offset,
79+
int length)
80+
{
81+
return getFloat(number, offset, length, -1, null);
82+
}
7183

7284
int getLocalMktDate(int offset, int length);
7385

artio-codecs/src/main/java/uk/co/real_logic/artio/util/MutableAsciiBuffer.java

+14-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.agrona.concurrent.UnsafeBuffer;
2222
import uk.co.real_logic.artio.fields.*;
2323
import uk.co.real_logic.artio.util.float_parsing.AsciiBufferCharReader;
24+
import uk.co.real_logic.artio.util.float_parsing.DecimalFloatOverflowHandler;
2425
import uk.co.real_logic.artio.util.float_parsing.DecimalFloatParser;
2526

2627
import java.nio.ByteBuffer;
@@ -167,9 +168,19 @@ public long getMessageType(final int offset, final int length)
167168
}
168169

169170
@SuppressWarnings("FinalParameters")
170-
public DecimalFloat getFloat(final DecimalFloat number, int offset, int length)
171-
{
172-
return DecimalFloatParser.extract(number, AsciiBufferCharReader.INSTANCE, this, offset, length);
171+
public DecimalFloat getFloat(final DecimalFloat number,
172+
int offset,
173+
int length,
174+
int tagId,
175+
DecimalFloatOverflowHandler decimalFloatOverflowHandler)
176+
{
177+
return DecimalFloatParser.extract(number,
178+
AsciiBufferCharReader.INSTANCE,
179+
this,
180+
offset,
181+
length,
182+
tagId,
183+
decimalFloatOverflowHandler);
173184
}
174185

175186
public int getLocalMktDate(final int offset, final int length)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2015-2025 Real Logic Limited.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package uk.co.real_logic.artio.util.float_parsing;
17+
18+
import uk.co.real_logic.artio.fields.DecimalFloat;
19+
20+
public interface DecimalFloatOverflowHandler
21+
{
22+
DecimalFloat handleOverflow(CharSequence valueWithOverflow,
23+
int positionOfOverflow,
24+
int positionOfDecimalPoint,
25+
int tagId);
26+
}

0 commit comments

Comments
 (0)