public override int CopyTo(int position, char[] destination, int destinationOffset, int length)
//^^ requires 0 <= position && 0 <= length && 0 <= position+length && position <= this.Length;
//^^ requires 0 <= destinationOffset && 0 <= destinationOffset+length && destinationOffset+length <= destination.Length;
//^^ ensures 0 <= result && result <= length && position+result <= this.Length;
{
if (this.length != null && position >= (int)this.length) return 0;
if (!this.enumeratorIsValid || position < this.currentFragmentOffset) {
this.fragmentEnumerator = this.GetFragments().GetEnumerator();
this.currentFragmentOffset = 0;
this.enumeratorIsValid = this.fragmentEnumerator.MoveNext();
}
Contract.Assert(this.fragmentEnumerator != null);
while (this.enumeratorIsValid) {
int fragmentLength = this.fragmentEnumerator.Current.Length;
if (this.currentFragmentOffset + fragmentLength > position) break;
this.currentFragmentOffset += fragmentLength;
this.enumeratorIsValid = this.fragmentEnumerator.MoveNext();
}
int charsCopied = 0;
Contract.Assume(0 <= position && position <= this.Length); //follows from the precondition
while (this.enumeratorIsValid && charsCopied < length) {
Contract.Assert(this.fragmentEnumerator != null);
Contract.Assert(this.currentFragmentOffset+this.fragmentEnumerator.Current.Length > position);
Contract.Assert(0 <= position && position <= this.Length);
Contract.Assert(0 <= charsCopied && charsCopied <= length);
Contract.Assert(position+charsCopied <= this.Length);
int fragmentLength = this.fragmentEnumerator.Current.Length;
int fragmentStart = 0;
if (position > this.currentFragmentOffset) fragmentStart = position - this.currentFragmentOffset;
Contract.Assume(fragmentStart <= this.Length); //position < this.Length as per the loop invariant
int fragmentCharsToCopy = fragmentLength - fragmentStart;
if (charsCopied + fragmentCharsToCopy > length) fragmentCharsToCopy = length - charsCopied;
//Contract.Assume(fragmentStart <= this.Length);
int fragCharsCopied = this.fragmentEnumerator.Current.CopyTo(fragmentStart, destination, destinationOffset, fragmentCharsToCopy);
if (fragCharsCopied == 0) {
this.enumeratorIsValid = false;
break;
}
charsCopied += fragCharsCopied;
Contract.Assume(position + charsCopied <= this.Length);
destinationOffset += fragmentCharsToCopy;
if (fragmentStart + fragmentCharsToCopy >= fragmentLength) {
this.currentFragmentOffset += fragmentLength;
this.enumeratorIsValid = this.fragmentEnumerator.MoveNext();
}
}
if (!this.enumeratorIsValid) this.length = this.currentFragmentOffset;
Contract.Assert(0 <= charsCopied && charsCopied <= length && position+charsCopied <= this.Length);
return charsCopied;
}