public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List<PeerId> otherPeers, int count, int startIndex, int endIndex) { // Only request 2 pieces at a time in endgame mode // to prevent a *massive* overshoot if (id.IsChoking || id.AmRequestingPiecesCount > 2) return null; LoadPieces(id, peerBitfield); // 1) See if there are any blocks which have not been requested at all. Request the block if the peer has it foreach (var p in pieces) { if (!peerBitfield[p.Index] || p.AllBlocksRequested) continue; for (var i = 0; i < p.BlockCount; i++) { if (p.Blocks[i].Requested) continue; p.Blocks[i].Requested = true; var request = new Request(id, p.Blocks[i]); requests.Add(request); return new MessageBundle(request.Block.CreateRequest(id)); } } // 2) For each block with an existing request, add another request. We do a search from the start // of the list to the end. So when we add a duplicate request, move both requests to the end of the list foreach (var p in pieces) { if (!peerBitfield[p.Index]) continue; for (var i = 0; i < p.BlockCount; i++) { if (p.Blocks[i].Received || AlreadyRequested(p.Blocks[i], id)) continue; var c = requests.Count; for (var j = 0; j < requests.Count - 1 && (c-- > 0); j++) { if (requests[j].Block.PieceIndex == p.Index && requests[j].Block.StartOffset == p.Blocks[i].StartOffset) { var r = requests[j]; requests.RemoveAt(j); requests.Add(r); j--; } } p.Blocks[i].Requested = true; var request = new Request(id, p.Blocks[i]); requests.Add(request); return new MessageBundle(request.Block.CreateRequest(id)); } } return null; }
private void GenerateRarestFirst(BitField peerBitfield, IEnumerable<PeerId> otherPeers) { // Move anything in the rarest buffer into the spares while (_rarest.Count > 0) _spares.Push(_rarest.Pop()); var current = DequeueSpare(); current.From(peerBitfield); // Store this bitfield as the first iteration of the Rarest First algorithm. _rarest.Push(current); // Get a cloned copy of the bitfield and begin iterating to find the rarest pieces foreach (var t in otherPeers.Where(t => !t.BitField.AllTrue)) { current = DequeueSpare().From(current); // currentBitfield = currentBitfield & (!otherBitfield) // This calculation finds the pieces this peer has that other peers *do not* have. // i.e. the rarest piece. current.NAnd(t.BitField); // If the bitfield now has no pieces we've completed our task if (current.AllFalse) { _spares.Push(current); break; } // Otherwise push the bitfield on the stack and clone it and iterate again. _rarest.Push(current); } }
public InitialSeedingMode(TorrentManager manager) : base(manager) { unchoker = new InitialSeedUnchoker(manager); manager.chokeUnchoker = unchoker; zero = new BitField(manager.Bitfield.Length); }
public void Setup() { alreadyGot = new List<Block>(); bitfield = new BitField(40).SetAll(true); picker = new EndGamePicker(); pieces = new List<Piece>(new Piece[] { new Piece(4, rig.Torrent), new Piece(6, rig.Torrent), new Piece(36, rig.Torrent), new Piece(24, rig.Torrent) }); for (int i = 0; i < pieces.Count; i++) { for (int j = 0; j < pieces[i].BlockCount; j++) { if (j % 3 == 0) { pieces[i].Blocks[j].CreateRequest(id); if (j % 2 == 0) { pieces[i].Blocks[j].Received = true; } pieces[i].Blocks[j].Requested = true; alreadyGot.Add(pieces[i].Blocks[j]); } } } picker.Initialise(bitfield, rig.Torrent.Files, pieces); }
public override bool IsInteresting(BitField bitfield) { temp.From(bitfield).NAnd(this.bitfield); if (temp.AllFalse) return false; return base.IsInteresting(temp); }
public EndGamePickerTests() { rig = TestRig.CreateMultiFile(); bitfield = new BitField(40).SetAll(true) .Set(4, false) .Set(6, false) .Set(24, false) .Set(36, false); picker = new EndGamePicker(); pieces = new List<Piece>(new[] { new Piece(4, rig.Torrent.PieceLength, rig.Torrent.Size), new Piece(6, rig.Torrent.PieceLength, rig.Torrent.Size), new Piece(24, rig.Torrent.PieceLength, rig.Torrent.Size), new Piece(36, rig.Torrent.PieceLength, rig.Torrent.Size) }); id = new PeerId(new Peer("peerid", new Uri("tcp://weburl.com")), rig.Manager); id.IsChoking = false; id.BitField.SetAll(false); other = new PeerId(new Peer("other", new Uri("tcp://other.com")), rig.Manager); other.IsChoking = false; other.BitField.SetAll(false); }
/// <summary> /// Initializes new instance of LinkedInGetMemberOptions /// </summary> public LinkedInGetMemberOptions() { BasicProfileOptions = new BitField<LinkedInBasicProfileFields>(); EmailProfileOptions = new BitField<LinkedInEmailProfileFields>(); FullProfileOptions = new BitField<LinkedInFullProfileFields>(); Parameters = new LinkedInGetMemberParameters(); }
public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List<PeerId> otherPeers, int count, int startIndex, int endIndex) { var bundle = ActivePicker.PickPiece(id, peerBitfield, otherPeers, count, startIndex, endIndex); if (bundle == null && TryEnableEndgame()) return ActivePicker.PickPiece(id, peerBitfield, otherPeers, count, startIndex, endIndex); return bundle; }
public void SetUp() { // The bool[] must be kept in sync with the byte[] constructor. They represent exactly the same thing. initalValues = new bool[] { true, false, true, false, true, false, true, true, true, false, false, true }; secondValues = new bool[] { true, true, false, false, true, false, true, false, true, false, false, true }; initialByteValues = new byte[] { 171, 144 }; bf = new BitField(initalValues); }
public InitialSeedUnchoker(TorrentManager manager) { advertisedPieces = new List<SeededPiece>(); bitfield = new BitField(manager.Bitfield.Length); this.manager = manager; peers = new List<ChokeData>(); temp = new BitField(bitfield.Length); }
public override void Initialise(BitField bitfield, TorrentFile[] files, IEnumerable<Piece> requests) { this.bitfield = bitfield; endgameSelector = new BitField(bitfield.Length); this.files = files; inEndgame = false; TryEnableEndgame(); ActivePicker.Initialise(bitfield, files, requests); }
public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List<PeerId> otherPeers, int count, int startIndex, int endIndex) { // Invert 'bitfield' and AND it with the peers bitfield // Any pieces which are 'true' in the bitfield will not be downloaded temp.From(peerBitfield).NAnd(bitfield); if (temp.AllFalse) return null; return base.PickPiece(id, temp, otherPeers, count, startIndex, endIndex); }
public FastResume(InfoHash infoHash, BitField bitfield) { if (infoHash == null) throw new ArgumentNullException(nameof(infoHash)); if (bitfield == null) throw new ArgumentNullException(nameof(bitfield)); Infohash = infoHash; Bitfield = bitfield; }
public FastResume(InfoHash infoHash, BitField bitfield) { if (infoHash == null) throw new ArgumentNullException("infoHash"); if (bitfield == null) throw new ArgumentNullException("bitfield"); this.infoHash = infoHash; this.bitfield = bitfield; }
public override void Initialise(BitField bitfield, TorrentFile[] files, IEnumerable<Piece> requests) { // 'Requests' should contain a list of all the pieces we need to complete pieces = new List<Piece>(requests); foreach (var piece in pieces) { for (var i = 0; i < piece.BlockCount; i++) if (piece.Blocks[i].RequestedOff != null) this.requests.Add(new Request(piece.Blocks[i].RequestedOff, piece.Blocks[i])); } }
public FastResume(InfoHash infoHash, BitField bitfield, IEnumerable<Priority> priorities) { if (infoHash==null) throw new ArgumentNullException("infoHash"); if(bitfield == null) throw new ArgumentNullException("bitfield"); this.infoHash = infoHash; this.bitfield = bitfield; this.priorities = priorities.ToArray(); }
public FastResume(BEncodedDictionary dict) { CheckContent(dict, VersionKey, 1); CheckContent(dict, InfoHashKey); CheckContent(dict, BitfieldKey); CheckContent(dict, BitfieldLengthKey); Infohash = new InfoHash(((BEncodedString) dict[InfoHashKey]).TextBytes); Bitfield = new BitField((int) ((BEncodedNumber) dict[BitfieldLengthKey]).Number); var data = ((BEncodedString) dict[BitfieldKey]).TextBytes; Bitfield.FromArray(data, 0, data.Length); }
public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List<PeerId> otherPeers, int count, int startIndex, int endIndex) { if (peerBitfield.AllFalse) return null; if (count > 1) return base.PickPiece(id, peerBitfield, otherPeers, count, startIndex, endIndex); int midpoint = random.Next(startIndex, endIndex); return base.PickPiece(id, peerBitfield, otherPeers, count, midpoint, endIndex) ?? base.PickPiece(id, peerBitfield, otherPeers, count, startIndex, midpoint); }
/// <summary> /// Initializes new instance of LinkedInSearchOptions /// </summary> public LinkedInSearchOptions() { Keywords = new List<string>(); MemberFieldOptions = new LinkedInGetMemberOptions(); FacetFields = new BitField<LinkedInFacetFields>(); BucketFields = new BitField<LinkedInBucketFields>(); FacetLanguageValues = new List<LinkedInFacetLanguage>(); FacetLocationValues = new List<string>(); FacetIndustryValues = new List<string>(); FacetCurrentCompanyValues = new List<string>(); FacetPastCompanyValues = new List<string>(); FacetSchoolValues = new List<string>(); }
public void InvalidBitfieldTest() { // Set each of the 4 trailing bits to 1 to force a decode error for (byte i = 8; i > 0; i /= 2) { try { initialByteValues[1] += i; bf = new BitField(initialByteValues, initalValues.Length); Assert.Fail("The bitfield was corrupt but decoded correctly: Loop {0}", i); } catch (MessageException) { initialByteValues[1] -= i; } } }
public void And() { var bf2 = new BitField(_secondValues); _bf.And(bf2); Assert.AreEqual(new BitField(_secondValues), bf2, "#1: bf2 should be unmodified"); for (var i = 0; i < _bf.Length; i++) Assert.AreEqual(_initalValues[i] && _secondValues[i], _bf[i], "#2"); var count = _initalValues .Where((x, i) => x && _secondValues[i]) .Count(); Assert.AreEqual(count, _bf.TrueCount, "#3"); }
public void And() { var bf2 = new BitField(secondValues); bf.And(bf2); Assert.Equal(new BitField(secondValues), bf2); for (var i = 0; i < bf.Length; i++) Assert.Equal(initalValues[i] && secondValues[i], bf[i]); var count = 0; for (var i = 0; i < initalValues.Length; i++) if (initalValues[i] && secondValues[i]) count++; Assert.Equal(count, bf.TrueCount); }
public void And2() { Random r = new Random (); byte [] a = new byte [100]; byte [] b = new byte [100]; r.NextBytes (a); r.NextBytes (b); for (int i = 0; i < a.Length * 8; i++) { BitField first = new BitField (a, i); BitField second = new BitField (b, i); first.And (second); } }
public void And() { BitField bf2 = new BitField(secondValues); bf.And(bf2); Assert.AreEqual(new BitField(secondValues), bf2, "#1: bf2 should be unmodified"); for (int i = 0; i < bf.Length; i++) Assert.AreEqual(initalValues[i] && secondValues[i], bf[i], "#2"); int count = 0; for (int i = 0; i < initalValues.Length; i++) if (initalValues[i] && secondValues[i]) count++; Assert.AreEqual(count, bf.TrueCount, "#3"); }
public void And2() { var random = new Random (); var a = new byte [100]; var b = new byte [100]; random.NextBytes (a); random.NextBytes (b); for (var i = 0; i < a.Length * 8; i++) { var first = new BitField (a, i); var second = new BitField (b, i); first.And(second); } }
public FastResume(BEncodedDictionary dict) { CheckContent(dict, VersionKey, (BEncodedNumber)1); CheckContent(dict, InfoHashKey); CheckContent(dict, BitfieldKey); CheckContent(dict, BitfieldLengthKey); infoHash = new InfoHash(((BEncodedString)dict[InfoHashKey]).TextBytes); bitfield = new BitField((int)((BEncodedNumber)dict[BitfieldLengthKey]).Number); byte[] data = ((BEncodedString)dict[BitfieldKey]).TextBytes; bitfield.FromArray(data, 0, data.Length); if (dict.ContainsKey(PrioritiesKey)) { var list = (BEncodedList)dict[PrioritiesKey]; priorities = list.Select(v => (Priority)((BEncodedNumber)v).Number).ToArray(); } }
public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List<PeerId> otherPeers, int count, int startIndex, int endIndex) { if (peerBitfield.AllFalse) return null; if (count > 1) return base.PickPiece(id, peerBitfield, otherPeers, count, startIndex, endIndex); GenerateRarestFirst(peerBitfield, otherPeers); while (rarest.Count > 0) { BitField current = rarest.Pop(); MessageBundle bundle = base.PickPiece(id, current, otherPeers, count, startIndex, endIndex); spares.Push(current); if (bundle != null) return bundle; } return null; }
public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List<PeerId> otherPeers, int count, int startIndex, int endIndex) { PickPieceId.Add(id); BitField clone = new BitField(peerBitfield.Length); clone.Or(peerBitfield); PickPieceBitfield.Add(clone); PickPiecePeers.Add(otherPeers); PickPieceStartIndex.Add(startIndex); PickPieceEndIndex.Add(endIndex); PickPieceCount.Add(count); for (int i = startIndex; i < endIndex; i++) { if (PickedPieces.Contains(i)) continue; PickedPieces.Add(i); if (ReturnNoPiece) return null; else return new MessageBundle(); } return null; }
void GenerateRarestFirst(BitField peerBitfield, List<PeerId> otherPeers) { // Move anything in the rarest buffer into the spares while (rarest.Count > 0) spares.Push(rarest.Pop()); BitField current = DequeueSpare(); current.From(peerBitfield); // Store this bitfield as the first iteration of the Rarest First algorithm. rarest.Push(current); // Get a cloned copy of the bitfield and begin iterating to find the rarest pieces for (int i = 0; i < otherPeers.Count; i++) { if (otherPeers[i].BitField.AllTrue) continue; current = DequeueSpare().From(current); // currentBitfield = currentBitfield & (!otherBitfield) // This calculation finds the pieces this peer has that other peers *do not* have. // i.e. the rarest piece. current.NAnd(otherPeers[i].BitField); // If the bitfield now has no pieces we've completed our task if (current.AllFalse) { spares.Push(current); break; } // Otherwise push the bitfield on the stack and clone it and iterate again. rarest.Push(current); } }
public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List<PeerId> otherPeers, int count, int startIndex, int endIndex) { MessageBundle bundle; int start, end; if (HighPrioritySetStart >= startIndex && HighPrioritySetStart <= endIndex) { start = HighPrioritySetStart; end = Math.Min(endIndex, HighPrioritySetStart + HighPrioritySetSize - 1); if ((bundle = base.PickPiece(id, peerBitfield, otherPeers, count, start, end)) != null) return bundle; } if (MediumPrioritySetStart >= startIndex && MediumPrioritySetStart <= endIndex) { start = MediumPrioritySetStart; end = Math.Min(endIndex, MediumPrioritySetStart + MediumPrioritySetSize - 1); if ((bundle = base.PickPiece(id, peerBitfield, otherPeers, count, start, end)) != null) return bundle; } return base.PickPiece(id, peerBitfield, otherPeers, count, startIndex, endIndex); }
internal void RefreshPickerWithMetadata(BitField bitfield, ITorrentData data) { ChangePicker(originalPicker, bitfield); Picker.Initialise(bitfield, data, Enumerable.Empty <Piece> ()); }
public bool IsInteresting(IPeer peer, BitField bitfield) { return(!bitfield.AllFalse); }
/// <summary> /// Creates a new BitfieldMessage /// </summary> /// <param name="length">The length of the bitfield</param> public BitfieldMessage(int length) { BitField = new MutableBitField(length); }
public InitialSeedingMode(TorrentManager manager, DiskManager diskManager, ConnectionManager connectionManager, EngineSettings settings) : base(manager, diskManager, connectionManager, settings, new InitialSeedUnchoker(manager)) { zero = new MutableBitField(manager.Bitfield.Length); }
private bool GetFontOption(BitField field) { int options = GetInt(OFFSET_FONT_OPTIONS); return(field.IsSet(options)); }
internal PieceManager(TorrentManager manager) { Manager = manager; Picker = new NullPicker(); PendingHashCheckPieces = new BitField(1); }
public override IList <PieceRequest> PickPiece(PeerId id, BitField peerBitfield, List <PeerId> otherPeers, int count, int startIndex, int endIndex) { // Only request 2 pieces at a time in endgame mode // to prevent a *massive* overshoot if (id.IsChoking || id.AmRequestingPiecesCount > 2) { return(null); } LoadPieces(id, peerBitfield); // 1) See if there are any blocks which have not been requested at all. Request the block if the peer has it foreach (Piece p in pieces) { if (!peerBitfield[p.Index] || p.AllBlocksRequested) { continue; } for (int i = 0; i < p.BlockCount; i++) { if (p.Blocks[i].Requested) { continue; } var requestMessage = p.Blocks[i].CreateRequest(id); requests.Add(new Request(id, p.Blocks[i])); return(new [] { requestMessage }); } } // 2) For each block with an existing request, add another request. We do a search from the start // of the list to the end. So when we add a duplicate request, move both requests to the end of the list foreach (Piece p in pieces) { if (!peerBitfield[p.Index]) { continue; } for (int i = 0; i < p.BlockCount; i++) { if (p.Blocks[i].Received || AlreadyRequested(p.Blocks[i], id)) { continue; } int c = requests.Count; for (int j = 0; j < requests.Count - 1 && (c-- > 0); j++) { if (requests[j].Block.PieceIndex == p.Index && requests[j].Block.StartOffset == p.Blocks[i].StartOffset) { Request r = requests[j]; requests.RemoveAt(j); requests.Add(r); j--; } } var requestMessage = p.Blocks[i].CreateRequest(id); requests.Add(new Request(id, p.Blocks[i])); return(new [] { requestMessage }); } } return(null); }
public PieceRequest PickPiece(IPieceRequester peer, BitField available, IReadOnlyList <IPieceRequester> otherPeers) { IList <PieceRequest> bundle = PickPiece(peer, available, otherPeers, 1); return(bundle?.Single()); }
private void SetModified(bool modified, BitField field) { field_5_options = field.SetBoolean(field_5_options, !modified); }
private bool IsModified(BitField field) { return(!field.IsSet(field_5_options)); }
public override bool IsInteresting(BitField bitfield) { IsInterestingBitfield.Add(bitfield); return(!bitfield.AllFalse); }
internal PieceManager(TorrentManager manager) { Manager = manager; PendingHashCheckPieces = new BitField(1); Requester = manager.Engine !.Factories.CreatePieceRequester(); }
public virtual void Initialise(BitField bitfield, ITorrentData torrentData, IEnumerable <Piece> requests) { CheckOverriden(); BasePicker.Initialise(bitfield, torrentData, requests); }
public void AddRequests(IPeerWithMessaging peer, IReadOnlyList <IPeerWithMessaging> allPeers) { int maxRequests = peer.MaxPendingRequests; if (!peer.CanRequestMorePieces) { return; } int count = peer.PreferredRequestAmount(TorrentData.PieceLength); // This is safe to invoke. 'ContinueExistingRequest' strongly guarantees that a peer will only // continue a piece they have initiated. If they're choking then the only piece they can continue // will be a fast piece (if one exists!) if (!peer.IsChoking || peer.SupportsFastPeer) { while (peer.AmRequestingPiecesCount < maxRequests) { BlockInfo?request = Picker.ContinueExistingRequest(peer, 0, peer.BitField.Length - 1); if (request != null) { peer.EnqueueRequest(request.Value); } else { break; } } } // FIXME: Would it be easier if RequestManager called PickPiece(AllowedFastPieces[0]) or something along those lines? if (!peer.IsChoking || (peer.SupportsFastPeer && peer.IsAllowedFastPieces.Count > 0)) { BitField filtered = null; while (peer.AmRequestingPiecesCount < maxRequests) { filtered ??= ApplyIgnorables(peer.BitField); IList <BlockInfo> request = Picker.PickPiece(peer, filtered, allPeers, count, 0, TorrentData.PieceCount() - 1); if (request != null && request.Count > 0) { peer.EnqueueRequests(request); } else { break; } } } if (!peer.IsChoking && peer.AmRequestingPiecesCount == 0) { while (peer.AmRequestingPiecesCount < maxRequests) { BlockInfo?request = Picker.ContinueAnyExistingRequest(peer, 0, TorrentData.PieceCount() - 1, 1); // If this peer is a seeder and we are unable to request any new blocks, then we should enter // endgame mode. Every block has been requested at least once at this point. if (request == null && (InEndgameMode || peer.IsSeeder)) { request = Picker.ContinueAnyExistingRequest(peer, 0, TorrentData.PieceCount() - 1, 2); InEndgameMode |= request != null; } if (request != null) { peer.EnqueueRequest(request.Value); } else { break; } } } }
public void BitFieldSameContainerTest() { var test = new BitField <byte>(4, startBitOffset: 0); test.Bitmask.ShouldBe <byte>(0b1111_0000); }
public virtual bool IsInteresting(BitField bitfield) { CheckOverriden(); return(BasePicker.IsInteresting(bitfield)); }
private void UpdateCubeRowDirections(int cubex, int cubey, int row, BitField rowA, BitField rowB) { foreach (Cell cell in Cells.CubeRow(cubex, cubey, row)) { // possible values that are exclusive to this row if (!cell.HasValue) { cell.HorizontalDirections = cell.Possibles & !(rowA | rowB); } } }
public override void Initialise(BitField bitfield, TorrentFile[] files, IEnumerable <Piece> requests) { base.Initialise(bitfield, files, requests); this.length = bitfield.Length; }
private void UpdateCubeColumnDirections(int cubex, int cubey, int column, BitField columnA, BitField columnB) { foreach (Cell cell in Cells.CubeColumn(cubex, cubey, column)) { // possible values that are exclusive to this column if (!cell.HasValue) { cell.VerticalDirections = cell.Possibles & !(columnA | columnB); } } }
public ChokeData(PeerId peer) { LastChoked = DateTime.Now; Peer = peer; CurrentPieces = new BitField(peer.BitField.Length); }
public override void Initialise(BitField bitfield, ITorrentData torrentData, IEnumerable <Piece> requests) { }
public TorrentFileInfo(ITorrentFile torrentFile, string fullPath) { TorrentFile = torrentFile; FullPath = DownloadCompleteFullPath = DownloadIncompleteFullPath = fullPath; BitField = new BitField(torrentFile.EndPieceIndex - torrentFile.StartPieceIndex + 1); }
/// <summary> /// Creates a new BitfieldMessage /// </summary> /// <param name="bitfield">The bitfield to use</param> public BitfieldMessage(BitField bitfield) { BitField = bitfield; }
internal PieceManager(TorrentManager manager) { Manager = manager; Picker = new NullPicker(); UnhashedPieces = new BitField(1); }
private bool GetOptionFlag(BitField field) { return(field.IsSet(field_5_options)); }
public IList <PieceRequest> PickPiece(IPieceRequester peer, BitField available, IReadOnlyList <IPieceRequester> otherPeers, int count) { return(PickPiece(peer, available, otherPeers, count, 0, available.Length)); }
private void SetOptionFlag(bool flag, BitField field) { field_5_options = field.SetBoolean(field_5_options, flag); }
internal PieceManager() { Picker = new NullPicker(); UnhashedPieces = new BitField(0); }
public virtual IList <PieceRequest> PickPiece(IPieceRequester peer, BitField available, IReadOnlyList <IPieceRequester> otherPeers, int count, int startIndex, int endIndex) { CheckOverriden(); return(BasePicker.PickPiece(peer, available, otherPeers, count, startIndex, endIndex)); }
int CanRequest(BitField bitfield, int pieceStartIndex, int pieceEndIndex, ref int pieceCount) { // This is the easiest case to consider - special case it if (pieceCount == 1) { while (pieceStartIndex <= pieceEndIndex && (pieceStartIndex = bitfield.FirstTrue(pieceStartIndex, pieceEndIndex)) != -1) { var end = bitfield.FirstFalse(pieceStartIndex, pieceEndIndex); // If end is a valid value, it's the first *false* piece. Subtract '1' from it // to give us the last available piece we can request. If it's -1 then we can use // 'pieceEndIndex' as the last available piece to request as all pieces are available. var lastAvailable = end == -1 ? pieceEndIndex : end - 1; for (int i = pieceStartIndex; i <= lastAvailable; i++) { if (!AlreadyRequested(i)) { return(i); } } pieceStartIndex = lastAvailable + 1; } return(-1); } int largestStart = 0; int largestEnd = 0; while (pieceStartIndex <= pieceEndIndex && (pieceStartIndex = bitfield.FirstTrue(pieceStartIndex, pieceEndIndex)) != -1) { int end = bitfield.FirstFalse(pieceStartIndex, pieceEndIndex); if (end == -1) { end = Math.Min(pieceStartIndex + pieceCount, bitfield.Length); } // Do not include 'end' as it's the first *false* piece. for (int i = pieceStartIndex; i < end; i++) { if (AlreadyRequested(i)) { end = i; } } if ((end - pieceStartIndex) >= pieceCount) { return(pieceStartIndex); } if ((largestEnd - largestStart) < (end - pieceStartIndex)) { largestStart = pieceStartIndex; largestEnd = end; } pieceStartIndex = Math.Max(pieceStartIndex + 1, end); } pieceCount = largestEnd - largestStart; return(pieceCount == 0 ? -1 : largestStart); }