@@ -102,6 +102,19 @@ public enum Feature implements FormatFeature {
102
102
* @since 2.15
103
103
*/
104
104
STRINGREF (false ),
105
+
106
+ /**
107
+ * Feature that determines whether generator should try to write doubles
108
+ * as floats: if {@code true}, will write a {@code double} as a 4-byte float if no
109
+ * precision loss will occur; if {@code false}, will always write a {@code double}
110
+ * as an 8-byte double.
111
+ * <p>
112
+ * Default value is {@code false} meaning that doubles will always be written as
113
+ * 8-byte values.
114
+ *
115
+ * @since 2.15
116
+ */
117
+ WRITE_MINIMAL_DOUBLES (false ),
105
118
;
106
119
107
120
protected final boolean _defaultState ;
@@ -177,6 +190,9 @@ public int getMask() {
177
190
178
191
protected boolean _cfgMinimalInts ;
179
192
193
+ // @since 2.15
194
+ protected boolean _cfgMinimalDoubles ;
195
+
180
196
/*
181
197
/**********************************************************
182
198
/* Output state
@@ -275,6 +291,7 @@ public CBORGenerator(IOContext ctxt, int stdFeatures, int formatFeatures,
275
291
_streamWriteContext = CBORWriteContext .createRootContext (dups );
276
292
_formatFeatures = formatFeatures ;
277
293
_cfgMinimalInts = Feature .WRITE_MINIMAL_INTS .enabledIn (formatFeatures );
294
+ _cfgMinimalDoubles = Feature .WRITE_MINIMAL_DOUBLES .enabledIn (formatFeatures );
278
295
_ioContext = ctxt ;
279
296
_out = out ;
280
297
_bufferRecyclable = true ;
@@ -311,6 +328,7 @@ public CBORGenerator(IOContext ctxt, int stdFeatures, int formatFeatures,
311
328
_streamWriteContext = CBORWriteContext .createRootContext (dups );
312
329
_formatFeatures = formatFeatures ;
313
330
_cfgMinimalInts = Feature .WRITE_MINIMAL_INTS .enabledIn (formatFeatures );
331
+ _cfgMinimalDoubles = Feature .WRITE_MINIMAL_DOUBLES .enabledIn (formatFeatures );
314
332
_ioContext = ctxt ;
315
333
_out = out ;
316
334
_bufferRecyclable = bufferRecyclable ;
@@ -413,6 +431,7 @@ public JsonGenerator overrideFormatFeatures(int values, int mask) {
413
431
if (oldState != newState ) {
414
432
_formatFeatures = newState ;
415
433
_cfgMinimalInts = Feature .WRITE_MINIMAL_INTS .enabledIn (newState );
434
+ _cfgMinimalDoubles = Feature .WRITE_MINIMAL_DOUBLES .enabledIn (newState );
416
435
}
417
436
return this ;
418
437
}
@@ -458,6 +477,8 @@ public CBORGenerator enable(Feature f) {
458
477
_formatFeatures |= f .getMask ();
459
478
if (f == Feature .WRITE_MINIMAL_INTS ) {
460
479
_cfgMinimalInts = true ;
480
+ } else if (f == Feature .WRITE_MINIMAL_DOUBLES ) {
481
+ _cfgMinimalDoubles = true ;
461
482
}
462
483
return this ;
463
484
}
@@ -466,6 +487,8 @@ public CBORGenerator disable(Feature f) {
466
487
_formatFeatures &= ~f .getMask ();
467
488
if (f == Feature .WRITE_MINIMAL_INTS ) {
468
489
_cfgMinimalInts = false ;
490
+ } else if (f == Feature .WRITE_MINIMAL_DOUBLES ) {
491
+ _cfgMinimalDoubles = false ;
469
492
}
470
493
return this ;
471
494
}
@@ -691,8 +714,14 @@ public void writeArray(double[] array, int offset, int length) throws IOExceptio
691
714
// short-cut, do not create child array context etc
692
715
_verifyValueWrite ("write int array" );
693
716
_writeLengthMarker (PREFIX_TYPE_ARRAY , length );
694
- for (int i = offset , end = offset +length ; i < end ; ++i ) {
695
- _writeDoubleNoCheck (array [i ]);
717
+ if (_cfgMinimalDoubles ) {
718
+ for (int i = offset , end = offset +length ; i < end ; ++i ) {
719
+ _writeDoubleMinimal (array [i ]);
720
+ }
721
+ } else {
722
+ for (int i = offset , end = offset +length ; i < end ; ++i ) {
723
+ _writeDoubleNoCheck (array [i ]);
724
+ }
696
725
}
697
726
}
698
727
@@ -786,8 +815,24 @@ private final void _writeLongNoCheck(long l) throws IOException
786
815
_outputBuffer [_outputTail ++] = (byte ) i ;
787
816
}
788
817
818
+ private final void _writeFloatNoCheck (float f ) throws IOException {
819
+ _ensureRoomForOutput (5 );
820
+ /*
821
+ * 17-Apr-2010, tatu: could also use 'floatToIntBits', but it seems more
822
+ * accurate to use exact representation; and possibly faster. However,
823
+ * if there are cases where collapsing of NaN was needed (for non-Java
824
+ * clients), this can be changed
825
+ */
826
+ int i = Float .floatToRawIntBits (f );
827
+ _outputBuffer [_outputTail ++] = BYTE_FLOAT32 ;
828
+ _outputBuffer [_outputTail ++] = (byte ) (i >> 24 );
829
+ _outputBuffer [_outputTail ++] = (byte ) (i >> 16 );
830
+ _outputBuffer [_outputTail ++] = (byte ) (i >> 8 );
831
+ _outputBuffer [_outputTail ++] = (byte ) i ;
832
+ }
833
+
789
834
private final void _writeDoubleNoCheck (double d ) throws IOException {
790
- _ensureRoomForOutput (11 );
835
+ _ensureRoomForOutput (9 );
791
836
// 17-Apr-2010, tatu: could also use 'doubleToIntBits', but it seems
792
837
// more accurate to use exact representation; and possibly faster.
793
838
// However, if there are cases where collapsing of NaN was needed (for
@@ -807,6 +852,15 @@ private final void _writeDoubleNoCheck(double d) throws IOException {
807
852
_outputBuffer [_outputTail ++] = (byte ) i ;
808
853
}
809
854
855
+ private final void _writeDoubleMinimal (double d ) throws IOException {
856
+ float f = (float )d ;
857
+ if (f == d ) {
858
+ _writeFloatNoCheck (f );
859
+ } else {
860
+ _writeDoubleNoCheck (d );
861
+ }
862
+ }
863
+
810
864
/*
811
865
/***********************************************************
812
866
/* Output method implementations, textual
@@ -1178,46 +1232,17 @@ protected void _write(BigInteger v) throws IOException {
1178
1232
@ Override
1179
1233
public void writeNumber (double d ) throws IOException {
1180
1234
_verifyValueWrite ("write number" );
1181
- _ensureRoomForOutput (11 );
1182
- /*
1183
- * 17-Apr-2010, tatu: could also use 'doubleToIntBits', but it seems
1184
- * more accurate to use exact representation; and possibly faster.
1185
- * However, if there are cases where collapsing of NaN was needed (for
1186
- * non-Java clients), this can be changed
1187
- */
1188
- long l = Double .doubleToRawLongBits (d );
1189
- _outputBuffer [_outputTail ++] = BYTE_FLOAT64 ;
1190
-
1191
- int i = (int ) (l >> 32 );
1192
- _outputBuffer [_outputTail ++] = (byte ) (i >> 24 );
1193
- _outputBuffer [_outputTail ++] = (byte ) (i >> 16 );
1194
- _outputBuffer [_outputTail ++] = (byte ) (i >> 8 );
1195
- _outputBuffer [_outputTail ++] = (byte ) i ;
1196
- i = (int ) l ;
1197
- _outputBuffer [_outputTail ++] = (byte ) (i >> 24 );
1198
- _outputBuffer [_outputTail ++] = (byte ) (i >> 16 );
1199
- _outputBuffer [_outputTail ++] = (byte ) (i >> 8 );
1200
- _outputBuffer [_outputTail ++] = (byte ) i ;
1235
+ if (_cfgMinimalDoubles ) {
1236
+ _writeDoubleMinimal (d );
1237
+ } else {
1238
+ _writeDoubleNoCheck (d );
1239
+ }
1201
1240
}
1202
1241
1203
1242
@ Override
1204
1243
public void writeNumber (float f ) throws IOException {
1205
- // Ok, now, we needed token type byte plus 5 data bytes (7 bits each)
1206
- _ensureRoomForOutput (6 );
1207
1244
_verifyValueWrite ("write number" );
1208
-
1209
- /*
1210
- * 17-Apr-2010, tatu: could also use 'floatToIntBits', but it seems more
1211
- * accurate to use exact representation; and possibly faster. However,
1212
- * if there are cases where collapsing of NaN was needed (for non-Java
1213
- * clients), this can be changed
1214
- */
1215
- int i = Float .floatToRawIntBits (f );
1216
- _outputBuffer [_outputTail ++] = BYTE_FLOAT32 ;
1217
- _outputBuffer [_outputTail ++] = (byte ) (i >> 24 );
1218
- _outputBuffer [_outputTail ++] = (byte ) (i >> 16 );
1219
- _outputBuffer [_outputTail ++] = (byte ) (i >> 8 );
1220
- _outputBuffer [_outputTail ++] = (byte ) i ;
1245
+ _writeFloatNoCheck (f );
1221
1246
}
1222
1247
1223
1248
@ Override
0 commit comments