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.
This commit is contained in:
King_DuckZ 2020-03-21 23:35:43 +01:00
parent 2352bfddc1
commit 5688775e6c
3 changed files with 53 additions and 21 deletions

View file

@ -46,8 +46,10 @@ public:
typedef FrameIterator<true, Const> 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<Const> toc_entry, std::size_t index);
template <bool Const2> BasicBlock (const BasicBlock<Const2>& 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<Const> m_toc_entry;

View file

@ -34,12 +34,18 @@ public:
typedef BlockIterator<false> iterator;
typedef BlockIterator<true> const_iterator;
static const constexpr std::size_t GameBlocks = 16 - 1;
MemoryCard();
template <typename IT> 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<uint8_t> m_data;
};

View file

@ -27,12 +27,13 @@ namespace {
template <bool Const>
BasicBlock<Const> make_block_for_index (typename BasicBlock<Const>::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<Const>(data + index * Frame::size(), index), index};
return {retptr, BasicFrame<Const>(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<false>(m_data.data(), index + 1);
}
Block MemoryCard::toc_block() {
return make_block_for_index<false>(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<true>(m_data.data(), index + 1);
}
ConstBlock MemoryCard::toc_block() const {
return make_block_for_index<true>(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<false>(m_data.data(), index);
}
ConstBlock MemoryCard::block_at_index(std::size_t index) const {
return make_block_for_index<true>(m_data.data(), index);
}
std::vector<std::size_t> block_group (const MemoryCard& mc, std::size_t index) {
std::vector<std::size_t> 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<bool>(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