@@ -347,6 +347,7 @@ size_t ExternalStreamingStream::FillBuffer(size_t position) {
347347 current_data_length_ = source_stream_->GetMoreData (¤t_data_);
348348 current_data_offset_ = 0 ;
349349 bool data_ends = current_data_length_ == 0 ;
350+ bookmark_data_is_from_current_data_ = false ;
350351
351352 // A caveat: a data chunk might end with bytes from an incomplete UTF-8
352353 // character (the rest of the bytes will be in the next chunk).
@@ -406,6 +407,15 @@ bool ExternalStreamingStream::SetBookmark() {
406407 // - buffer_[buffer_cursor_ .. buffer_end_] => bookmark_buffer_
407408 // - current_data_[.._offset_ .. .._length_] => bookmark_data_
408409 // - utf8_split_char_buffer_* => bookmark_utf8_split...
410+ //
411+ // To make sure we don't unnecessarily copy data, we also maintain
412+ // whether bookmark_data_ contains a copy of the current current_data_
413+ // block. This is done with:
414+ // - bookmark_data_is_from_current_data_
415+ // - bookmark_data_offset_: offset into bookmark_data_
416+ //
417+ // Note that bookmark_data_is_from_current_data_ must be maintained
418+ // whenever current_data_ is updated.
409419
410420 bookmark_ = pos_;
411421
@@ -415,10 +425,21 @@ bool ExternalStreamingStream::SetBookmark() {
415425 CopyCharsUnsigned (bookmark_buffer_.start (), buffer_cursor_, buffer_length);
416426
417427 size_t data_length = current_data_length_ - current_data_offset_;
418- bookmark_data_.Dispose ();
419- bookmark_data_ = Vector<uint8_t >::New (static_cast <int >(data_length));
420- CopyBytes (bookmark_data_.start (), current_data_ + current_data_offset_,
421- data_length);
428+ size_t bookmark_data_length = static_cast <size_t >(bookmark_data_.length ());
429+ if (bookmark_data_is_from_current_data_ &&
430+ data_length < bookmark_data_length) {
431+ // Fast case: bookmark_data_ was previously copied from the current
432+ // data block, and we have enough data for this bookmark.
433+ bookmark_data_offset_ = bookmark_data_length - data_length;
434+ } else {
435+ // Slow case: We need to copy current_data_.
436+ bookmark_data_.Dispose ();
437+ bookmark_data_ = Vector<uint8_t >::New (static_cast <int >(data_length));
438+ CopyBytes (bookmark_data_.start (), current_data_ + current_data_offset_,
439+ data_length);
440+ bookmark_data_is_from_current_data_ = true ;
441+ bookmark_data_offset_ = 0 ;
442+ }
422443
423444 bookmark_utf8_split_char_buffer_length_ = utf8_split_char_buffer_length_;
424445 for (size_t i = 0 ; i < utf8_split_char_buffer_length_; i++) {
@@ -437,12 +458,14 @@ void ExternalStreamingStream::ResetToBookmark() {
437458
438459 // bookmark_data_* => current_data_*
439460 // (current_data_ assumes ownership of its memory.)
440- uint8_t * data = new uint8_t [bookmark_data_.length ()];
461+ uint8_t * data = new uint8_t [bookmark_data_.length () - bookmark_data_offset_ ];
441462 current_data_offset_ = 0 ;
442- current_data_length_ = bookmark_data_.length ();
443- CopyCharsUnsigned (data, bookmark_data_.begin (), bookmark_data_.length ());
463+ current_data_length_ = bookmark_data_.length () - bookmark_data_offset_;
464+ CopyCharsUnsigned (data, bookmark_data_.begin () + bookmark_data_offset_,
465+ bookmark_data_.length ());
444466 delete[] current_data_;
445467 current_data_ = data;
468+ bookmark_data_is_from_current_data_ = true ;
446469
447470 // bookmark_buffer_ needs to be copied to buffer_.
448471 CopyCharsUnsigned (buffer_, bookmark_buffer_.begin (),
@@ -463,6 +486,7 @@ void ExternalStreamingStream::FlushCurrent() {
463486 current_data_ = NULL ;
464487 current_data_length_ = 0 ;
465488 current_data_offset_ = 0 ;
489+ bookmark_data_is_from_current_data_ = false ;
466490}
467491
468492
0 commit comments