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:
parent
2352bfddc1
commit
5688775e6c
3 changed files with 53 additions and 21 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue