/// <summary> /// Indexer to allow the retrieval of the element at the specified index. /// </summary> /// <param name="index">The index of the snapshot element.</param> /// <returns>Returns the snapshot element at the specified index.</returns> public SnapshotElementRef this[Int32 index] { get { SnapshotElementRef element = new SnapshotElementRef(this); element.InitializePointers(index); return(element); } }
/// <summary> /// Gets the enumerator for an element reference within this snapshot region. /// </summary> /// <returns>The enumerator for an element reference within this snapshot region.</returns> public IEnumerator GetEnumerator() { if (this.RegionSize <= 0 || this.Alignment <= 0) { yield break; } // Prevent the GC from moving buffers around GCHandle currentValuesHandle = GCHandle.Alloc(this.CurrentValues, GCHandleType.Pinned); GCHandle previousValuesHandle = GCHandle.Alloc(this.PreviousValues, GCHandleType.Pinned); this.SnapshotElementRef = new SnapshotElementRef(this); this.SnapshotElementRef.InitializePointers(); // Return the first element. This allows us to call IncrementPointers each loop unconditionally based on alignment later. yield return(this.SnapshotElementRef); if (this.Alignment == 1) { // Utilizes ++ operator. This is fast operation wise, but slower because we check every address for (Int32 index = 1; index < this.RegionSize; index++) { this.SnapshotElementRef.IncrementPointers(); yield return(this.SnapshotElementRef); } } else { // Utilizes += operators. This is faster because we access far less addresses for (Int32 index = this.Alignment; index < this.RegionSize; index += this.Alignment) { this.SnapshotElementRef.AddPointers(this.Alignment); yield return(this.SnapshotElementRef); } } // Let the GC do what it wants now currentValuesHandle.Free(); previousValuesHandle.Free(); }