Makes writeValueRecursively iterative#368
Conversation
The method `_Private_IonWriterBase#writeValueRecursively` is recursive in two senses: 1. It visits all of the children in the provided IonReader's current value recursively. 2. The method itself is implemented using recursion. This patch modifies the implementation (#2) to be iterative, eliminating a source of StackOverflowExceptions and offering a modest reduction in CPU cost.
Codecov Report
@@ Coverage Diff @@
## master #368 +/- ##
=========================================
Coverage 64.04% 64.05%
+ Complexity 4838 4835 -3
=========================================
Files 136 136
Lines 21105 21108 +3
Branches 3818 3821 +3
=========================================
+ Hits 13517 13520 +3
+ Misses 6254 6251 -3
- Partials 1334 1337 +3
Continue to review full report at Codecov.
|
| // The isNullValue() check above will handle this. | ||
| throw new IllegalStateException("isNullValue() was false but IonType was NULL."); |
There was a problem hiding this comment.
I wondered about this, thanks for the clarification
| stepIn(IonType.SEXP); | ||
| break; | ||
| default: | ||
| throw new IllegalStateException("Unknown value type: " + type); |
There was a problem hiding this comment.
Your mileage may vary here, but what do you think of this expression?
switch (type) {
case NULL: // The isNullValue() check above will handle this.
throw new IllegalStateException("isNullValue() was false but IonType was NULL.");
case BOOL: writeBool(reader.booleanValue()); break;
case INT: writeInt(reader.bigIntegerValue()); break;
case FLOAT: writeFloat(reader.doubleValue()); break;
case DECIMAL: writeDecimal(reader.decimalValue()); break;
case TIMESTAMP: writeTimestamp(reader.timestampValue()); break;
case STRING: writeString(reader.stringValue()); break;
case SYMBOL: writeSymbolToken(reader.symbolValue()); break;
case BLOB: writeBlob(reader.newBytes()); break;
case CLOB: writeClob(reader.newBytes()); break;
case STRUCT: // Intentional fallthrough
case LIST: // Intentional fallthrough
case SEXP: reader.stepIn(); stepIn(type); break;
default:
throw new IllegalStateException("Unexpected value type: " + type);
}There was a problem hiding this comment.
I adopted the fallthrough for the container types, thanks!
| */ | ||
| final void writeValueRecursively(IonType type, IonReader reader) | ||
| throws IOException | ||
| final void writeValueRecursively(IonType ionType, IonReader reader) |
There was a problem hiding this comment.
Zack responded offline that while the implementation is no longer recursive the value structure still is. This makes sense, traversing a recursive structure is what this does no matter how it does it.
|
Thank you for the detailed comments! |
The method
_Private_IonWriterBase#writeValueRecursivelyisrecursive in two senses:
current value recursively.
This patch modifies the implementation to be iterative,
eliminating a source of StackOverflowExceptions and offering
a modest reduction in CPU cost.
Benchmark
This benchmark creates an
IonStructthat is 1,000 levels deep, wraps it in anIonReader, then useswriteValueRecursivelyto write it to a binary Ion stream 100k times. The source can be viewed here.This change does not affect allocations or garbage collection, only CPU time.
Before
After
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.