From f88f3c4b03a8f767f6b65767bb6e22e579c23d23 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 18 Feb 2022 17:17:19 -0600 Subject: [PATCH] Feat: add tr_block_info::Location (#2649) --- libtransmission/block-info.h | 161 +++++++++------- libtransmission/cache.cc | 7 +- libtransmission/completion.cc | 5 +- libtransmission/file-piece-map.cc | 4 +- libtransmission/peer-mgr.cc | 11 +- libtransmission/peer-msgs.cc | 11 +- libtransmission/peer-msgs.h | 1 - libtransmission/torrent-metainfo.h | 35 ++-- libtransmission/torrent.cc | 22 +-- libtransmission/torrent.h | 29 +-- libtransmission/webseed.cc | 9 +- tests/libtransmission/block-info-test.cc | 236 +++++++++++++++++++---- 12 files changed, 342 insertions(+), 189 deletions(-) diff --git a/libtransmission/block-info.h b/libtransmission/block-info.h index c3f832e8f..85589caed 100644 --- a/libtransmission/block-info.h +++ b/libtransmission/block-info.h @@ -38,9 +38,9 @@ struct tr_block_info return block_size; } + // return the number of bytes in `block` [[nodiscard]] constexpr auto blockSize(tr_block_index_t block) const { - // how many bytes are in this block? return block + 1 == n_blocks ? final_block_size : blockSize(); } @@ -49,86 +49,25 @@ struct tr_block_info return n_pieces; } - [[nodiscard]] constexpr tr_piece_index_t pieceForBlock(tr_block_index_t block) const - { - // if not initialized yet, don't divide by zero - if (n_blocks_in_piece == 0) - { - return 0; - } - - return block / n_blocks_in_piece; - } - [[nodiscard]] constexpr auto pieceSize() const { return piece_size; } + // return the number of bytes in `piece` [[nodiscard]] constexpr auto pieceSize(tr_piece_index_t piece) const { - // how many bytes are in this piece? return piece + 1 == n_pieces ? final_piece_size : pieceSize(); } - [[nodiscard]] constexpr tr_piece_index_t pieceOf(uint64_t offset) const - { - // if not initialized yet, don't divide by zero - if (piece_size == 0) - { - return 0; - } - - // handle 0-byte files at the end of a torrent - if (offset == total_size) - { - return n_pieces - 1; - } - - return offset / piece_size; - } - - [[nodiscard]] constexpr tr_block_index_t blockOf(uint64_t offset) const - { - // if not initialized yet, don't divide by zero - if (block_size == 0) - { - return 0; - } - - // handle 0-byte files at the end of a torrent - if (offset == total_size) - { - return n_blocks - 1; - } - - return offset / block_size; - } - - [[nodiscard]] constexpr uint64_t offset(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const - { - auto ret = piece_size; - ret *= piece; - ret += offset; - ret += length; - return ret; - } - - [[nodiscard]] constexpr auto blockOf(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const - { - return blockOf(this->offset(piece, offset, length)); - } - [[nodiscard]] constexpr tr_block_span_t blockSpanForPiece(tr_piece_index_t piece) const { - if (block_size == 0) + if (!isInitialized()) { return {}; } - auto const begin = blockOf(offset(piece, 0)); - auto const end = 1 + blockOf(offset(piece, pieceSize(piece) - 1)); - return { begin, end }; + return { pieceLoc(piece).block, pieceLastLoc(piece).block + 1 }; } [[nodiscard]] constexpr auto totalSize() const @@ -136,5 +75,95 @@ struct tr_block_info return total_size; } - static uint32_t bestBlockSize(uint64_t piece_size); + struct Location + { + uint64_t byte = 0; + + tr_piece_index_t piece = 0; + uint32_t piece_offset = 0; + + tr_block_index_t block = 0; + uint32_t block_offset = 0; + + [[nodiscard]] bool operator==(Location const& that) const + { + return this->byte == that.byte; + } + + [[nodiscard]] bool operator<(Location const& that) const + { + return this->byte < that.byte; + } + }; + + // Location of the first byte in `block`. + [[nodiscard]] Location constexpr blockLoc(tr_block_index_t block) const + { + return byteLoc(uint64_t{ block } * blockSize()); + } + + // Location of the last byte in `block`. + [[nodiscard]] Location constexpr blockLastLoc(tr_block_index_t block) const + { + if (!isInitialized()) + { + return {}; + } + + return byteLoc(uint64_t{ block } * blockSize() + blockSize(block) - 1); + } + + // Location of the first byte (+ optional offset and length) in `piece` + [[nodiscard]] Location constexpr pieceLoc(tr_piece_index_t piece, uint32_t offset = 0, uint32_t length = 0) const + { + return byteLoc(uint64_t{ piece } * pieceSize() + offset + length); + } + + // Location of the last byte in `piece`. + [[nodiscard]] Location constexpr pieceLastLoc(tr_piece_index_t piece) const + { + if (!isInitialized()) + { + return {}; + } + + return byteLoc(uint64_t{ piece } * pieceSize() + pieceSize(piece) - 1); + } + + // Location of the torrent's nth byte + [[nodiscard]] Location constexpr byteLoc(uint64_t byte) const + { + if (!isInitialized()) + { + return {}; + } + + auto loc = Location{}; + + loc.byte = byte; + + if (byte == totalSize()) // handle 0-byte files at the end of a torrent + { + loc.block = blockCount() - 1; + loc.piece = pieceCount() - 1; + } + else + { + loc.block = byte / blockSize(); + loc.piece = byte / pieceSize(); + } + + loc.block_offset = static_cast(loc.byte - (uint64_t{ loc.block } * blockSize())); + loc.piece_offset = static_cast(loc.byte - (uint64_t{ loc.piece } * pieceSize())); + + return loc; + } + + [[nodiscard]] static uint32_t bestBlockSize(uint64_t piece_size); + +private: + [[nodiscard]] bool constexpr isInitialized() const + { + return n_blocks_in_piece != 0; + } }; diff --git a/libtransmission/cache.cc b/libtransmission/cache.cc index bfb5098d1..61d548b8b 100644 --- a/libtransmission/cache.cc +++ b/libtransmission/cache.cc @@ -31,6 +31,7 @@ struct cache_block { tr_torrent* tor; + // TODO: use tr_block_info::Location tr_piece_index_t piece; uint32_t offset; uint32_t length; @@ -304,9 +305,9 @@ static int cache_block_compare(void const* va, void const* vb) static struct cache_block* findBlock(tr_cache* cache, tr_torrent* torrent, tr_piece_index_t piece, uint32_t offset) { - struct cache_block key; + auto key = cache_block{}; key.tor = torrent; - key.block = torrent->blockOf(piece, offset); + key.block = torrent->pieceLoc(piece, offset).block; return static_cast(tr_ptrArrayFindSorted(&cache->blocks, &key, cache_block_compare)); } @@ -329,7 +330,7 @@ int tr_cacheWriteBlock( cb->piece = piece; cb->offset = offset; cb->length = length; - cb->block = torrent->blockOf(piece, offset); + cb->block = torrent->pieceLoc(piece, offset).block; cb->evbuf = evbuffer_new(); tr_ptrArrayInsertSorted(&cache->blocks, cb, cache_block_compare); } diff --git a/libtransmission/completion.cc b/libtransmission/completion.cc index 1efd7bc36..fb92a7d29 100644 --- a/libtransmission/completion.cc +++ b/libtransmission/completion.cc @@ -222,9 +222,8 @@ uint64_t tr_completion::countHasBytesInSpan(tr_byte_span_t span) const } // get the block span of the byte span - auto const begin_block = block_info_->blockOf(begin_byte); - auto const final_byte = end_byte - 1; - auto const final_block = block_info_->blockOf(final_byte); + auto const begin_block = block_info_->byteLoc(begin_byte).block; + auto const final_block = block_info_->byteLoc(end_byte - 1).block; // if the entire span is in a single block if (begin_block == final_block) diff --git a/libtransmission/file-piece-map.cc b/libtransmission/file-piece-map.cc index 9de3994fd..19c1d7a8d 100644 --- a/libtransmission/file-piece-map.cc +++ b/libtransmission/file-piece-map.cc @@ -26,7 +26,7 @@ void tr_file_piece_map::reset(tr_block_info const& block_info, uint64_t const* f { auto const file_size = file_sizes[i]; auto const begin_byte = offset; - auto const begin_piece = block_info.pieceOf(begin_byte); + auto const begin_piece = block_info.byteLoc(begin_byte).piece; auto end_byte = tr_byte_index_t{}; auto end_piece = tr_piece_index_t{}; @@ -34,7 +34,7 @@ void tr_file_piece_map::reset(tr_block_info const& block_info, uint64_t const* f { end_byte = offset + file_size; auto const final_byte = end_byte - 1; - auto const final_piece = block_info.pieceOf(final_byte); + auto const final_piece = block_info.byteLoc(final_byte).piece; end_piece = final_piece + 1; } else diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc index ad405782f..046d7f668 100644 --- a/libtransmission/peer-mgr.cc +++ b/libtransmission/peer-mgr.cc @@ -816,7 +816,7 @@ static void peerCallbackFunc(tr_peer* peer, tr_peer_event const* e, void* vs) break; case TR_PEER_CLIENT_GOT_REJ: - s->active_requests.remove(s->tor->blockOf(e->pieceIndex, e->offset), peer); + s->active_requests.remove(s->tor->pieceLoc(e->pieceIndex, e->offset).block, peer); break; case TR_PEER_CLIENT_GOT_CHOKE: @@ -841,12 +841,11 @@ static void peerCallbackFunc(tr_peer* peer, tr_peer_event const* e, void* vs) case TR_PEER_CLIENT_GOT_BLOCK: { - tr_torrent* tor = s->tor; - tr_piece_index_t const p = e->pieceIndex; - tr_block_index_t const block = tor->blockOf(p, e->offset); - cancelAllRequestsForBlock(s, block, peer); + auto* const tor = s->tor; + auto const loc = tor->pieceLoc(e->pieceIndex, e->offset); + cancelAllRequestsForBlock(s, loc.block, peer); peer->blocksSentToClient.add(tr_time(), 1); - tr_torrentGotBlock(tor, block); + tr_torrentGotBlock(tor, loc.block); break; } diff --git a/libtransmission/peer-msgs.cc b/libtransmission/peer-msgs.cc index ff424d7a4..5608d0c42 100644 --- a/libtransmission/peer-msgs.cc +++ b/libtransmission/peer-msgs.cc @@ -363,11 +363,6 @@ public: return tr_peerIoGetAge(io); } - [[nodiscard]] bool is_reading_block(tr_block_index_t block) const override - { - return state == AwaitingBt::Piece && block == torrent->blockOf(incoming.blockReq.index, incoming.blockReq.offset); - } - void cancel_block_request(tr_block_index_t block) override { protocolSendCancel(this, blockToReq(torrent, block)); @@ -1888,8 +1883,8 @@ static int clientGotBlock(tr_peerMsgsImpl* msgs, struct evbuffer* data, struct p TR_ASSERT(msgs != nullptr); TR_ASSERT(req != nullptr); - tr_torrent* tor = msgs->torrent; - tr_block_index_t const block = tor->blockOf(req->index, req->offset); + tr_torrent* const tor = msgs->torrent; + auto const block = tor->pieceLoc(req->index, req->offset).block; if (!requestIsValid(msgs, req)) { @@ -1952,7 +1947,7 @@ static ReadState canRead(tr_peerIo* io, void* vmsgs, size_t* piece) struct evbuffer* in = tr_peerIoGetReadBuffer(io); size_t const inlen = evbuffer_get_length(in); - dbgmsg(msgs, "canRead: inlen is %zu, msgs->state is %d", inlen, msgs->state); + dbgmsg(msgs, "canRead: inlen is %zu, msgs->state is %d", inlen, int(msgs->state)); auto ret = ReadState{}; if (inlen == 0) diff --git a/libtransmission/peer-msgs.h b/libtransmission/peer-msgs.h index b055f1590..32781afc8 100644 --- a/libtransmission/peer-msgs.h +++ b/libtransmission/peer-msgs.h @@ -48,7 +48,6 @@ public: virtual void update_active(tr_direction direction) = 0; virtual time_t get_connection_age() const = 0; - virtual bool is_reading_block(tr_block_index_t block) const = 0; virtual void cancel_block_request(tr_block_index_t block) = 0; diff --git a/libtransmission/torrent-metainfo.h b/libtransmission/torrent-metainfo.h index 0111d6467..922d9a971 100644 --- a/libtransmission/torrent-metainfo.h +++ b/libtransmission/torrent-metainfo.h @@ -16,7 +16,6 @@ #include "magnet-metainfo.h" struct tr_error; -struct tr_info; struct tr_torrent_metainfo : public tr_magnet_metainfo { @@ -45,13 +44,17 @@ public: { return blockInfo().blockCount(); } - [[nodiscard]] constexpr auto blockOf(uint64_t offset) const + [[nodiscard]] auto byteLoc(uint64_t byte) const { - return blockInfo().blockOf(offset); + return blockInfo().byteLoc(byte); } - [[nodiscard]] constexpr auto blockOf(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const + [[nodiscard]] auto blockLoc(tr_block_index_t block) const { - return blockInfo().blockOf(piece, offset, length); + return blockInfo().blockLoc(block); + } + [[nodiscard]] auto pieceLoc(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const + { + return blockInfo().pieceLoc(piece, offset, length); } [[nodiscard]] constexpr auto blockSize() const { @@ -65,22 +68,10 @@ public: { return blockInfo().blockSpanForPiece(piece); } - [[nodiscard]] constexpr auto offset(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const - { - return blockInfo().offset(piece, offset, length); - } [[nodiscard]] constexpr auto pieceCount() const { return blockInfo().pieceCount(); } - [[nodiscard]] constexpr auto pieceForBlock(tr_block_index_t block) const - { - return blockInfo().pieceForBlock(block); - } - [[nodiscard]] constexpr auto pieceOf(uint64_t offset) const - { - return blockInfo().pieceOf(offset); - } [[nodiscard]] constexpr auto pieceSize() const { return blockInfo().pieceSize(); @@ -147,12 +138,12 @@ public: return pieces_offset_; } - std::string torrentFile(std::string_view torrent_dir) const + [[nodiscard]] std::string torrentFile(std::string_view torrent_dir) const { return makeFilename(torrent_dir, name(), infoHashString(), BasenameFormat::Hash, ".torrent"); } - std::string resumeFile(std::string_view resume_dir) const + [[nodiscard]] std::string resumeFile(std::string_view resume_dir) const { return makeFilename(resume_dir, name(), infoHashString(), BasenameFormat::Hash, ".resume"); } @@ -190,7 +181,7 @@ private: BasenameFormat format, std::string_view suffix); - std::string makeFilename(std::string_view dirname, BasenameFormat format, std::string_view suffix) const + [[nodiscard]] std::string makeFilename(std::string_view dirname, BasenameFormat format, std::string_view suffix) const { return makeFilename(dirname, name(), infoHashString(), format, suffix); } @@ -198,7 +189,7 @@ private: struct file_t { public: - std::string const& path() const + [[nodiscard]] std::string const& path() const { return path_; } @@ -208,7 +199,7 @@ private: path_ = subpath; } - uint64_t size() const + [[nodiscard]] uint64_t size() const { return size_; } diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index 615abf29e..3c29ef7d8 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -1977,7 +1977,7 @@ bool tr_torrentReqIsValid(tr_torrent const* tor, tr_piece_index_t index, uint32_ { err = 4; } - else if (tor->offset(index, offset, length) > tor->totalSize()) + else if (tor->pieceLoc(index, offset, length).byte > tor->totalSize()) { err = 5; } @@ -2001,14 +2001,14 @@ tr_block_span_t tr_torGetFileBlockSpan(tr_torrent const* tor, tr_file_index_t i) { auto const [begin_byte, end_byte] = tor->fpm_.byteSpan(i); - auto const begin_block = tor->blockOf(begin_byte); + auto const begin_block = tor->byteLoc(begin_byte).block; if (begin_byte >= end_byte) { return { begin_block, begin_block }; } - auto const final_byte = end_byte - 1; - auto const end_block = tor->blockOf(final_byte) + 1; + auto const final_block = tor->byteLoc(end_byte - 1).block; + auto const end_block = final_block + 1; return { begin_block, end_block }; } @@ -2572,21 +2572,21 @@ void tr_torrentGotBlock(tr_torrent* tor, tr_block_index_t block) tor->completion.addBlock(block); tor->setDirty(); - tr_piece_index_t const p = tor->pieceForBlock(block); + auto const piece = tor->blockLoc(block).piece; - if (tor->hasPiece(p)) + if (tor->hasPiece(piece)) { - if (tor->checkPiece(p)) + if (tor->checkPiece(piece)) { - tr_torrentPieceCompleted(tor, p); + tr_torrentPieceCompleted(tor, piece); } else { - uint32_t const n = tor->pieceSize(p); - tr_logAddTorErr(tor, _("Piece %" PRIu32 ", which was just downloaded, failed its checksum test"), p); + uint32_t const n = tor->pieceSize(piece); + tr_logAddTorErr(tor, _("Piece %" PRIu32 ", which was just downloaded, failed its checksum test"), piece); tor->corruptCur += n; tor->downloadedCur -= std::min(tor->downloadedCur, uint64_t{ n }); - tr_peerMgrGotBadPiece(tor, p); + tr_peerMgrGotBadPiece(tor, piece); } } } diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index 23e973d71..eb465dad9 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -155,13 +155,17 @@ public: { return metainfo_.blockCount(); } - [[nodiscard]] constexpr auto blockOf(uint64_t offset) const + [[nodiscard]] auto byteLoc(uint64_t byte) const { - return metainfo_.blockOf(offset); + return metainfo_.byteLoc(byte); } - [[nodiscard]] constexpr auto blockOf(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const + [[nodiscard]] auto blockLoc(tr_block_index_t block) const { - return metainfo_.blockOf(piece, offset, length); + return metainfo_.blockLoc(block); + } + [[nodiscard]] auto pieceLoc(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const + { + return metainfo_.pieceLoc(piece, offset, length); } [[nodiscard]] constexpr auto blockSize() const { @@ -175,22 +179,10 @@ public: { return metainfo_.blockSpanForPiece(piece); } - [[nodiscard]] constexpr auto offset(tr_piece_index_t piece, uint32_t offset, uint32_t length = 0) const - { - return metainfo_.offset(piece, offset, length); - } [[nodiscard]] constexpr auto pieceCount() const { return metainfo_.pieceCount(); } - [[nodiscard]] constexpr auto pieceForBlock(tr_block_index_t block) const - { - return metainfo_.pieceForBlock(block); - } - [[nodiscard]] constexpr auto pieceOf(uint64_t offset) const - { - return metainfo_.pieceOf(offset); - } [[nodiscard]] constexpr auto pieceSize() const { return metainfo_.pieceSize(); @@ -297,7 +289,7 @@ public: [[nodiscard]] auto fileOffset(tr_piece_index_t piece, uint32_t piece_offset) const { - return fpm_.fileOffset(this->offset(piece, piece_offset)); + return fpm_.fileOffset(this->pieceLoc(piece, piece_offset).byte); } /// WANTED @@ -784,9 +776,6 @@ char* tr_torrentBuildPartial(tr_torrent const*, tr_file_index_t fileNo); tr_peer_id_t const& tr_torrentGetPeerId(tr_torrent* tor); -/** @brief free a metainfo */ -void tr_metainfoFree(tr_info* inf); - tr_torrent_metainfo&& tr_ctorStealMetainfo(tr_ctor* ctor); bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, std::string const& filename, tr_error** error); diff --git a/libtransmission/webseed.cc b/libtransmission/webseed.cc index 30259770c..323b527d1 100644 --- a/libtransmission/webseed.cc +++ b/libtransmission/webseed.cc @@ -41,10 +41,9 @@ public: tr_webseed_task(tr_torrent* tor, tr_webseed* webseed_in, tr_block_span_t span) : webseed{ webseed_in } , session{ tor->session } - , block{ span.begin } - , piece_index{ tor->pieceForBlock(this->block) } - , piece_offset{ static_cast( - int64_t{ tor->blockSize() } * this->block - tor->pieceSize() * this->piece_index) } + , block{ span.begin } // TODO(ckerr): just own the loc + , piece_index{ tor->blockLoc(this->block).piece } + , piece_offset{ tor->blockLoc(this->block).piece_offset } , block_size{ tor->blockSize() } , length{ (span.end - 1 - span.begin) * tor->blockSize() + tor->blockSize(span.end - 1) } { @@ -500,7 +499,7 @@ void task_request_next_chunk(tr_webseed_task* t) auto const piece_size = tor->pieceSize(); uint64_t const remain = t->length - t->blocks_done * tor->blockSize() - evbuffer_get_length(t->content()); - auto const total_offset = tor->offset(t->piece_index, t->piece_offset, t->length - remain); + auto const total_offset = tor->pieceLoc(t->piece_index, t->piece_offset, t->length - remain).byte; tr_piece_index_t const step_piece = total_offset / piece_size; uint64_t const step_piece_offset = total_offset - uint64_t(piece_size) * step_piece; diff --git a/tests/libtransmission/block-info-test.cc b/tests/libtransmission/block-info-test.cc index 7cc718bfd..8a176c38a 100644 --- a/tests/libtransmission/block-info-test.cc +++ b/tests/libtransmission/block-info-test.cc @@ -65,23 +65,6 @@ TEST_F(BlockInfoTest, handlesOddSize) EXPECT_EQ(TotalSize, info.total_size); } -TEST_F(BlockInfoTest, pieceForBlock) -{ - auto info = tr_block_info{}; - - uint64_t constexpr ExpectedBlockSize = 1024 * 16; - uint64_t constexpr ExpectedBlocksPerPiece = 4; - uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; - uint64_t constexpr PieceCount = 4; - uint64_t constexpr TotalSize = PieceSize * PieceCount; - info.initSizes(TotalSize, PieceSize); - - for (uint64_t i = 0; i < info.n_blocks; ++i) - { - EXPECT_EQ((i * ExpectedBlockSize) / PieceSize, info.pieceForBlock(i)); - } -} - TEST_F(BlockInfoTest, pieceSize) { auto info = tr_block_info{}; @@ -112,31 +95,6 @@ TEST_F(BlockInfoTest, blockSize) EXPECT_EQ(1, info.blockSize(info.n_blocks - 1)); } -TEST_F(BlockInfoTest, offset) -{ - auto info = tr_block_info{}; - - uint64_t constexpr ExpectedBlockSize = 1024 * 16; - uint64_t constexpr ExpectedBlocksPerPiece = 4; - uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; - uint64_t constexpr PieceCount = 5; - uint64_t constexpr TotalSize = PieceSize * (PieceCount - 1) + 1; - info.initSizes(TotalSize, PieceSize); - - EXPECT_EQ(0, info.offset(0, 0)); - EXPECT_EQ(1, info.offset(0, 0, 1)); - EXPECT_EQ(PieceSize * 2 + 100 + 1, info.offset(2, 100, 1)); - EXPECT_EQ( - info.total_size - 1, - info.offset( - info.n_pieces - 1, - ((info.n_blocks_in_final_piece - 1) * info.block_size) + info.n_blocks_in_final_piece - 1)); - EXPECT_EQ(info.n_blocks_in_piece, info.blockOf(info.offset(1, 0))); - EXPECT_EQ(info.n_blocks_in_piece, info.blockOf(info.offset(1, info.block_size - 1))); - EXPECT_EQ(info.n_blocks_in_piece + 1, info.blockOf(info.offset(1, info.block_size))); - EXPECT_EQ(info.n_blocks - 1, info.blockOf(info.total_size - 1)); -} - TEST_F(BlockInfoTest, blockSpanForPiece) { auto info = tr_block_info{}; @@ -160,3 +118,197 @@ TEST_F(BlockInfoTest, blockSpanForPiece) EXPECT_EQ(0, info.blockSpanForPiece(0).begin); EXPECT_EQ(0, info.blockSpanForPiece(0).end); } + +TEST_F(BlockInfoTest, blockLoc) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 5; + uint64_t constexpr TotalSize = PieceSize * (PieceCount - 1) + 1; + info.initSizes(TotalSize, PieceSize); + + // begin + auto loc = info.blockLoc(0); + EXPECT_EQ(tr_block_info::Location{}, loc); + + // third block is halfway through the first piece + loc = info.blockLoc(2); + EXPECT_EQ(ExpectedBlockSize * 2, loc.byte); + EXPECT_EQ(2, loc.block); + EXPECT_EQ(0, loc.block_offset); + EXPECT_EQ(0, loc.piece); + EXPECT_EQ(ExpectedBlockSize * 2, loc.piece_offset); + + // second piece aligns with fifth block + loc = info.blockLoc(4); + EXPECT_EQ(PieceSize, loc.byte); + EXPECT_EQ(4, loc.block); + EXPECT_EQ(0, loc.block_offset); + EXPECT_EQ(1, loc.piece); + EXPECT_EQ(0, loc.piece_offset); +} + +TEST_F(BlockInfoTest, blockLastLoc) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 5; + uint64_t constexpr TotalSize = PieceSize * (PieceCount - 1) + 1; + info.initSizes(TotalSize, PieceSize); + + auto loc = info.blockLastLoc(0); + EXPECT_EQ(ExpectedBlockSize - 1, loc.byte); + EXPECT_EQ(0, loc.block); + EXPECT_EQ(ExpectedBlockSize - 1, loc.block_offset); + EXPECT_EQ(0, loc.piece); + EXPECT_EQ(ExpectedBlockSize - 1, loc.piece_offset); + + loc = info.blockLastLoc(info.blockCount() - 1); + EXPECT_EQ(info.totalSize() - 1, loc.byte); + EXPECT_EQ(info.blockCount() - 1, loc.block); + EXPECT_EQ(info.totalSize() - 1 - (ExpectedBlockSize * (info.blockCount() - 1)), loc.block_offset); + EXPECT_EQ(info.pieceCount() - 1, loc.piece); + EXPECT_EQ(info.totalSize() - 1 - PieceSize * (PieceCount - 1), loc.piece_offset); +} + +TEST_F(BlockInfoTest, pieceLoc) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 5; + uint64_t constexpr TotalSize = PieceSize * (PieceCount - 1) + 1; + info.initSizes(TotalSize, PieceSize); + + // begin + auto loc = info.pieceLoc(0); + EXPECT_EQ(tr_block_info::Location{}, loc); + + for (uint64_t i = 0; i < PieceCount; ++i) + { + loc = info.pieceLoc(i); + EXPECT_EQ(info.blockLoc(i * ExpectedBlocksPerPiece), loc); + EXPECT_EQ(PieceSize * i, loc.byte); + EXPECT_EQ(ExpectedBlocksPerPiece * i, loc.block); + EXPECT_EQ(0, loc.block_offset); + EXPECT_EQ(i, loc.piece); + EXPECT_EQ(0, loc.piece_offset); + } + + loc = info.pieceLoc(0, PieceSize - 1); + EXPECT_EQ(PieceSize - 1, loc.byte); + EXPECT_EQ(ExpectedBlocksPerPiece - 1, loc.block); + EXPECT_EQ(ExpectedBlockSize - 1, loc.block_offset); + EXPECT_EQ(0, loc.piece); + EXPECT_EQ(PieceSize - 1, loc.piece_offset); + + loc = info.pieceLoc(0, PieceSize); + EXPECT_EQ(PieceSize, loc.byte); + EXPECT_EQ(ExpectedBlocksPerPiece, loc.block); + EXPECT_EQ(0, loc.block_offset); + EXPECT_EQ(1, loc.piece); + EXPECT_EQ(0, loc.piece_offset); + + loc = info.pieceLoc(0, PieceSize + 1); + EXPECT_EQ(PieceSize + 1, loc.byte); + EXPECT_EQ(ExpectedBlocksPerPiece, loc.block); + EXPECT_EQ(1, loc.block_offset); + EXPECT_EQ(1, loc.piece); + EXPECT_EQ(1, loc.piece_offset); +} + +TEST_F(BlockInfoTest, pieceLastLoc) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 5; + uint64_t constexpr TotalSize = PieceSize * (PieceCount - 1) + 1; + info.initSizes(TotalSize, PieceSize); + + auto loc = info.pieceLastLoc(0); + EXPECT_EQ(PieceSize - 1, loc.byte); + EXPECT_EQ(ExpectedBlocksPerPiece - 1, loc.block); + EXPECT_EQ(ExpectedBlockSize - 1, loc.block_offset); + EXPECT_EQ(0, loc.piece); + EXPECT_EQ(PieceSize - 1, loc.piece_offset); + + loc = info.pieceLastLoc(info.pieceCount() - 1); + EXPECT_EQ(info.totalSize() - 1, loc.byte); + EXPECT_EQ(info.blockCount() - 1, loc.block); + EXPECT_EQ(info.totalSize() - 1 - (ExpectedBlockSize * (info.blockCount() - 1)), loc.block_offset); + EXPECT_EQ(info.pieceCount() - 1, loc.piece); + EXPECT_EQ(info.totalSize() - 1 - PieceSize * (PieceCount - 1), loc.piece_offset); +} + +TEST_F(BlockInfoTest, byteLoc) +{ + auto info = tr_block_info{}; + + uint64_t constexpr ExpectedBlockSize = 1024 * 16; + uint64_t constexpr ExpectedBlocksPerPiece = 4; + uint64_t constexpr PieceSize = ExpectedBlockSize * ExpectedBlocksPerPiece; + uint64_t constexpr PieceCount = 5; + uint64_t constexpr TotalSize = PieceSize * (PieceCount - 1) + 1; + info.initSizes(TotalSize, PieceSize); + + auto loc = info.byteLoc(0); + EXPECT_EQ(tr_block_info::Location{}, loc); + + loc = info.byteLoc(1); + EXPECT_EQ(1, loc.byte); + EXPECT_EQ(0, loc.block); + EXPECT_EQ(1, loc.block_offset); + EXPECT_EQ(0, loc.piece); + EXPECT_EQ(1, loc.piece_offset); + + auto n = ExpectedBlockSize - 1; + loc = info.byteLoc(n); + EXPECT_EQ(n, loc.byte); + EXPECT_EQ(0, loc.block); + EXPECT_EQ(n, loc.block_offset); + EXPECT_EQ(0, loc.piece); + EXPECT_EQ(n, loc.piece_offset); + + n = ExpectedBlockSize; + loc = info.byteLoc(n); + EXPECT_EQ(n, loc.byte); + EXPECT_EQ(1, loc.block); + EXPECT_EQ(0, loc.block_offset); + EXPECT_EQ(0, loc.piece); + EXPECT_EQ(n, loc.piece_offset); + + n = ExpectedBlockSize + 1; + loc = info.byteLoc(n); + EXPECT_EQ(n, loc.byte); + EXPECT_EQ(1, loc.block); + EXPECT_EQ(1, loc.block_offset); + EXPECT_EQ(0, loc.piece); + EXPECT_EQ(n, loc.piece_offset); + + n = PieceSize - 1; + loc = info.byteLoc(n); + EXPECT_EQ(n, loc.byte); + EXPECT_EQ(ExpectedBlocksPerPiece - 1, loc.block); + EXPECT_EQ(ExpectedBlockSize - 1, loc.block_offset); + EXPECT_EQ(0, loc.piece); + EXPECT_EQ(n, loc.piece_offset); + + n = PieceSize; + loc = info.byteLoc(n); + EXPECT_EQ(n, loc.byte); + EXPECT_EQ(ExpectedBlocksPerPiece, loc.block); + EXPECT_EQ(0, loc.block_offset); + EXPECT_EQ(1, loc.piece); + EXPECT_EQ(0, loc.piece_offset); +}