From 5688775e6c9b90aba749aa28bdc117963fa44657 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Sat, 21 Mar 2020 23:35:43 +0100 Subject: [PATCH] Finish implementation of block_group(). This forced me to think about treating block 0 specially. The problem was with block.index() returning [1-15], while the valid range for MemoryCard::operator[] is [0-14]. This discrepancy was very confusing. A simple solution would've been to just rename Block::index() to eg Block::id(), and then know that one has to do -1 on the id to obtain the index. I tried but discarded this option. I don't think it's intuitive either (what's id? is it guaranteed to be index+1? is it a random number, rather? I know I will forget in 6 months). Treating block 0 normally would, on the other hand, break range iteration, as the first iteration would always be on the TOC block, and all for loops would become 1-based. Also implementing size() correctly becomes tricky (size could never be 0?) I don't like the current implementation either but I did it anyways for now, so operator[] works as before, you can get block 0 by calling toc_block(), and Block::index() returns some silly value for block 0. This should work in the future too when there will be the possibility to forge a new block from scratch. You don't really want to forge a block 0 as that's calculated from adding the normal savegame blocks, and for the latter MemoryCard can just do the +1 internally when receiving a new Block. Besides Block::link_order() seems to like indices this way, with 0 being the first savegame and not the TOC. So it seems to be special in the original PSX API, then let's treat it specially. --- subprojects/memcard/include/memcard/block.hpp | 6 +- .../memcard/include/memcard/memorycard.hpp | 9 ++- subprojects/memcard/src/memorycard.cpp | 59 +++++++++++++------ 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/subprojects/memcard/include/memcard/block.hpp b/subprojects/memcard/include/memcard/block.hpp index 4f7e47e..6d29621 100644 --- a/subprojects/memcard/include/memcard/block.hpp +++ b/subprojects/memcard/include/memcard/block.hpp @@ -46,8 +46,10 @@ public: typedef FrameIterator const_iterator; static const constexpr std::size_t FrameCount = 64; - static const constexpr std::size_t TOCBlockIndex = 0; + static const constexpr std::size_t TOCBlockIndex = 0xFF; + static const constexpr uint16_t LastLink = 0xFFFF; + BasicBlock() = default; BasicBlock (data_type* blk, std::size_t index); BasicBlock (data_type* blk, BasicFrame toc_entry, std::size_t index); template BasicBlock (const BasicBlock& other); @@ -85,6 +87,8 @@ public: uint8_t toc_checksum() const; uint8_t calculate_toc_checksum() const; + BasicBlock& operator= (const BasicBlock&) = default; + BasicBlock& operator= (BasicBlock&&) = default; private: BasicFrame m_toc_entry; diff --git a/subprojects/memcard/include/memcard/memorycard.hpp b/subprojects/memcard/include/memcard/memorycard.hpp index 09c4fff..f122996 100644 --- a/subprojects/memcard/include/memcard/memorycard.hpp +++ b/subprojects/memcard/include/memcard/memorycard.hpp @@ -34,12 +34,18 @@ public: typedef BlockIterator iterator; typedef BlockIterator const_iterator; + static const constexpr std::size_t GameBlocks = 16 - 1; + MemoryCard(); template explicit MemoryCard (IT beg, IT end); ~MemoryCard(); Block operator[] (std::size_t index); + Block block (std::size_t index); + Block toc_block(); ConstBlock operator[] (std::size_t index) const; + ConstBlock block (std::size_t index) const; + ConstBlock toc_block() const; ContentInfo content_info() const; std::size_t size() const; @@ -52,9 +58,6 @@ public: const_iterator end() const; private: - Block block_at_index(std::size_t index); - ConstBlock block_at_index(std::size_t index) const; - std::vector m_data; }; diff --git a/subprojects/memcard/src/memorycard.cpp b/subprojects/memcard/src/memorycard.cpp index 073d9f3..81f2cb7 100644 --- a/subprojects/memcard/src/memorycard.cpp +++ b/subprojects/memcard/src/memorycard.cpp @@ -27,12 +27,13 @@ namespace { template BasicBlock make_block_for_index (typename BasicBlock::data_type* data, std::size_t index) { + const auto new_index = (0 == index ? Block::TOCBlockIndex : index - 1); const auto retptr = data + index * Block::size() * Frame::size(); if (index > 0) { - return {retptr, BasicFrame(data + index * Frame::size(), index), index}; + return {retptr, BasicFrame(data + index * Frame::size(), index), new_index}; } else { - return {data + index, index}; + return {data + index, new_index}; } } } //unnamed namespace @@ -45,23 +46,39 @@ MemoryCard::MemoryCard() : MemoryCard::~MemoryCard() = default; Block MemoryCard::operator[] (std::size_t index) { - assert(index < 15); - return block_at_index(index + 1); + return block(index); +} + +Block MemoryCard::block (std::size_t index) { + assert(index < GameBlocks); + return make_block_for_index(m_data.data(), index + 1); +} + +Block MemoryCard::toc_block() { + return make_block_for_index(m_data.data(), 0); } ConstBlock MemoryCard::operator[] (std::size_t index) const { - assert(index < 15); - return block_at_index(index + 1); + return block(index); +} + +ConstBlock MemoryCard::block (std::size_t index) const { + assert(index < GameBlocks); + return make_block_for_index(m_data.data(), index + 1); +} + +ConstBlock MemoryCard::toc_block() const { + return make_block_for_index(m_data.data(), 0); } ContentInfo MemoryCard::content_info() const { - return {block_at_index(0).frame(0)}; + return {toc_block().frame(0)}; } std::size_t MemoryCard::size() const { return std::count_if( const_iterator(this, 0), - const_iterator(this, 15), + const_iterator(this, GameBlocks), [](const auto& blk) { return (blk.available_blocks() & 0xF) != 0 and (blk.available_blocks() & 0xF) != 0xF; } @@ -92,17 +109,25 @@ auto MemoryCard::end() const -> const_iterator { return const_iterator(this, size()); } -Block MemoryCard::block_at_index(std::size_t index) { - return make_block_for_index(m_data.data(), index); -} - -ConstBlock MemoryCard::block_at_index(std::size_t index) const { - return make_block_for_index(m_data.data(), index); -} - std::vector block_group (const MemoryCard& mc, std::size_t index) { std::vector retval; + retval.reserve(MemoryCard::GameBlocks); - auto block = mc[index]; + for (const auto& block : mc) { + retval.clear(); + std::size_t cur_idx = block.index(); + bool this_run = false; + ConstBlock cur_block; + do { + cur_block = mc[cur_idx]; + this_run |= static_cast(cur_idx == index); + retval.push_back(cur_idx); + cur_idx = cur_block.link_order(); + } while (cur_idx != Block::LastLink); + + if (this_run) + return retval; + } + return {}; } } //namespace mc::psx