// This file Copyright © Mnemosyne LLC. // It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only), // or any future license endorsed by Mnemosyne LLC. // License text can be found in the licenses/ folder. #pragma once #ifndef __TRANSMISSION__ #error only libtransmission should #include this header. #endif #include // for std::binary_search() #include // for uint64_t #include // for size_t #include #include "libtransmission/transmission.h" #include "libtransmission/bitfield.h" #include "libtransmission/tr-macros.h" // TR_CONSTEXPR20 #include "libtransmission/utils.h" struct tr_block_info; struct tr_torrent_metainfo; class tr_file_piece_map { public: template struct index_span_t { T begin; T end; }; using file_span_t = index_span_t; using piece_span_t = index_span_t; template struct offset_t { T index; uint64_t offset; }; using file_offset_t = offset_t; explicit tr_file_piece_map(tr_torrent_metainfo const& tm) { reset(tm); } tr_file_piece_map(tr_block_info const& block_info, uint64_t const* file_sizes, size_t n_files) { reset(block_info, file_sizes, n_files); } void reset(tr_torrent_metainfo const& tm); [[nodiscard]] TR_CONSTEXPR20 piece_span_t piece_span(tr_file_index_t file) const noexcept { return file_pieces_[file]; } [[nodiscard]] file_span_t file_span(tr_piece_index_t piece) const; [[nodiscard]] file_offset_t file_offset(uint64_t offset, bool include_empty_files) const; [[nodiscard]] TR_CONSTEXPR20 size_t size() const { return std::size(file_pieces_); } [[nodiscard]] TR_CONSTEXPR20 bool empty() const noexcept { return std::empty(file_pieces_); } // TODO(ckerr) minor wart here, two identical span types [[nodiscard]] TR_CONSTEXPR20 tr_byte_span_t byte_span(tr_file_index_t file) const { auto const& span = file_bytes_[file]; return tr_byte_span_t{ span.begin, span.end }; } [[nodiscard]] TR_CONSTEXPR20 bool is_edge_piece(tr_piece_index_t piece) const { return std::binary_search(std::begin(edge_pieces_), std::end(edge_pieces_), piece); } private: void reset(tr_block_info const& block_info, uint64_t const* file_sizes, size_t n_files); using byte_span_t = index_span_t; std::vector file_bytes_; std::vector file_pieces_; std::vector edge_pieces_; template struct CompareToSpan { using span_t = index_span_t; [[nodiscard]] constexpr int compare(T item, span_t span) const // <=> { if (include_empty_span && span.begin == span.end) { return tr_compare_3way(item, span.begin); } if (item < span.begin) { return -1; } if (item >= span.end) { return 1; } return 0; } [[nodiscard]] constexpr bool operator()(T item, span_t span) const // < { return compare(item, span) < 0; } [[nodiscard]] constexpr int compare(span_t span, T item) const // <=> { return -compare(item, span); } [[nodiscard]] constexpr bool operator()(span_t span, T item) const // < { return compare(span, item) < 0; } bool const include_empty_span; }; }; class tr_file_priorities { public: TR_CONSTEXPR20 explicit tr_file_priorities(tr_file_piece_map const* fpm) noexcept : fpm_{ fpm } { } void reset(tr_file_piece_map const*); void set(tr_file_index_t file, tr_priority_t priority); void set(tr_file_index_t const* files, size_t n, tr_priority_t priority); [[nodiscard]] tr_priority_t file_priority(tr_file_index_t file) const; [[nodiscard]] tr_priority_t piece_priority(tr_piece_index_t piece) const; private: tr_file_piece_map const* fpm_; std::vector priorities_; }; class tr_files_wanted { public: explicit tr_files_wanted(tr_file_piece_map const* fpm) : wanted_{ std::size(*fpm) } { reset(fpm); } void reset(tr_file_piece_map const* fpm); void set(tr_file_index_t file, bool wanted); void set(tr_file_index_t const* files, size_t n, bool wanted); [[nodiscard]] TR_CONSTEXPR20 bool file_wanted(tr_file_index_t file) const { return wanted_.test(file); } [[nodiscard]] bool piece_wanted(tr_piece_index_t piece) const; private: tr_file_piece_map const* fpm_; tr_bitfield wanted_; };