diff --git a/hilti/runtime/include/types/stream.h b/hilti/runtime/include/types/stream.h index efe56bb2d..9ba3f5479 100644 --- a/hilti/runtime/include/types/stream.h +++ b/hilti/runtime/include/types/stream.h @@ -717,13 +717,22 @@ class SafeConstIterator { if ( ! n ) return; - _offset += n; + if ( _chain->isValid() ) { + const Chunk* hint = nullptr; + + if ( _chain->inRange(_offset) ) + hint = _chunk; // current chunk is still valid + else + hint = _chain->head(); // previous chunk was likely trimmed off, try new head - if ( ! (_chain && _chain->isValid()) ) - return; // will be caught when dereferenced + _chunk = _chain->findChunk(_offset + n, hint); // null if we're pointing beyond the end now + } + else + // Invalid chain will trigger exception when dereferenced, but + // invalidate chunk to be safe. + _chunk = nullptr; - _chunk = _chain->findChunk(_offset, chunk()); - // chunk will be null if we're pointing beyond the end. + _offset += n; } void _decrement(const integer::safe& n) { @@ -736,16 +745,28 @@ class SafeConstIterator { if ( ! n ) return; - _offset -= n; + if ( _chain->isValid() ) { + const Chunk* hint = nullptr; - if ( _chunk && _offset > _chunk->offset() ) - return; // fast-path, chunk still valid + if ( _chain->inRange(_offset) ) { + if ( _chunk && _chunk->inRange(_offset - n) ) { + _offset -= n; + return; // fast-path, inside still-valid chunk + } - if ( ! (_chain && _chain->isValid()) ) - return; // will be caught when dereferenced + hint = _chunk; // current chunk is still valid + } + else + hint = _chain->head(); // previous chunk was likely trimmed off, try new head - _chunk = _chain->findChunk(_offset, _chunk); - // chunk will be null if we're pointing beyond the beginning. + _chunk = _chain->findChunk(_offset - n, hint); // null if we're pointing outside the chain now + } + else + // Invalid chain will trigger exception when dereferenced, but + // invalidate chunk to be safe. + _chunk = nullptr; + + _offset -= n; } Byte _dereference() const {