Compare commits
No commits in common. "dev" and "master" have entirely different histories.
22 changed files with 53 additions and 2210 deletions
|
@ -1,7 +1,7 @@
|
||||||
project('memoserv', 'cpp',
|
project('memoserv', 'cpp',
|
||||||
version: '0.1.0',
|
version: '0.1.0',
|
||||||
meson_version: '>=0.63.0',
|
meson_version: '>=0.63.0',
|
||||||
default_options: ['debug=true', 'cpp_std=c++20', 'b_ndebug=if-release']
|
default_options: ['debug=true', 'cpp_std=c++17', 'b_ndebug=if-release']
|
||||||
)
|
)
|
||||||
|
|
||||||
is_debug_build = 0
|
is_debug_build = 0
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -60,11 +60,6 @@ MemoservWin::MemoservWin(QApplication* app, QWidget *parent) :
|
||||||
this->centralWidget()->setLayout(vert_lay.release());
|
this->centralWidget()->setLayout(vert_lay.release());
|
||||||
|
|
||||||
create_menu(app);
|
create_menu(app);
|
||||||
|
|
||||||
load_memory_cards(QList<QString>{
|
|
||||||
"/home/michele/sync/emu/memory_psx/epsxe000_xa2.mcr",
|
|
||||||
"/home/michele/sync/emu/memory_psx/epsxe000_minidev00.mcr"
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoservWin::~MemoservWin() noexcept = default;
|
MemoservWin::~MemoservWin() noexcept = default;
|
||||||
|
@ -140,7 +135,8 @@ void MemoservWin::load_memory_cards (const QStringList& paths) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::size_t n = 0; block.has_magic() and n < block.block_count(); ++n) {
|
for (std::size_t n = 0; block.has_magic() and n < block.block_count(); ++n) {
|
||||||
//grid->push_back(make_qt_animation(block, g_icon_size, g_icon_size));
|
grid->push_back(make_qt_animation(block, g_icon_size, g_icon_size));
|
||||||
|
m_lower_grid->push_back(make_qt_animation(block, g_icon_size, g_icon_size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_main_lay->addWidget(grid.release(), 1, m_grid_count);
|
m_main_lay->addWidget(grid.release(), 1, m_grid_count);
|
||||||
|
|
|
@ -39,7 +39,6 @@ executable(app_name,
|
||||||
'make_qt_animation.cpp',
|
'make_qt_animation.cpp',
|
||||||
'animated_pixmap.cpp',
|
'animated_pixmap.cpp',
|
||||||
'savegame_db.cpp',
|
'savegame_db.cpp',
|
||||||
'savegame_model.cpp',
|
|
||||||
include_directories: inc,
|
include_directories: inc,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
qt6_dep,
|
qt6_dep,
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "savegame_db.hpp"
|
#include "savegame_db.hpp"
|
||||||
#include "memcard/alignment.hpp"
|
#include "memcard/block.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ciso646>
|
#include <ciso646>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
@ -24,24 +24,21 @@
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
namespace duck {
|
namespace duck {
|
||||||
namespace {
|
|
||||||
} //unnamed namespace
|
|
||||||
|
|
||||||
BlockEntry::BlockEntry (
|
BlockEntry::BlockEntry (
|
||||||
std::unique_ptr<uint8_t[]>&& data,
|
std::vector<mc::psx::BasicBlock<false>>&& blocks,
|
||||||
std::size_t count
|
std::unique_ptr<uint8_t[]>&& data
|
||||||
) :
|
) :
|
||||||
data(std::move(data)),
|
blocks(std::move(blocks)),
|
||||||
block_count(count)
|
data(std::move(data))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view BlockEntry::identifier() const {
|
std::string_view BlockEntry::identifier() const {
|
||||||
return make_block<true>(0).identifier();
|
return blocks.front().identifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string BlockEntry::title() const {
|
std::string BlockEntry::title() const {
|
||||||
return make_block<true>(0).title();
|
return blocks.front().title();
|
||||||
}
|
}
|
||||||
|
|
||||||
SavegameDb::SavegameDb() = default;
|
SavegameDb::SavegameDb() = default;
|
||||||
|
@ -55,52 +52,31 @@ unsigned int SavegameDb::add (const std::vector<mc::psx::BasicBlock<Const> >& bl
|
||||||
|
|
||||||
const auto block_count = blocks.size();
|
const auto block_count = blocks.size();
|
||||||
assert(block_count == blocks.front().block_count());
|
assert(block_count == blocks.front().block_count());
|
||||||
|
auto mem = std::make_unique<uint8_t[]>(frame_size + block_size * block_count);
|
||||||
|
|
||||||
static_assert(
|
uint8_t* dest = std::copy(blocks.front().toc().cbegin(), blocks.front().toc().cend(), mem.get());
|
||||||
frame_size % mc::psx::Block::DataAlignment == 0,
|
assert(std::distance(mem.get(), dest) == frame_size);
|
||||||
"Unexpected alignment, alignment in this class will be wrong if you ignore this error"
|
mc::psx::Frame toc(mem.get(), 0);
|
||||||
);
|
|
||||||
|
|
||||||
auto mem = mc::psx::make_unique_for_block_aligned(frame_size + block_size * block_count);
|
|
||||||
|
|
||||||
std::uint8_t* const ptr = mc::psx::to_block_aligned(mem.get());
|
|
||||||
uint8_t* dest = std::copy(blocks.front().toc().cbegin(), blocks.front().toc().cend(), ptr);
|
|
||||||
assert(mc::psx::is_block_aligned(dest));
|
|
||||||
assert(std::distance(ptr, dest) == frame_size);
|
|
||||||
mc::psx::Frame toc(ptr, 0);
|
|
||||||
|
|
||||||
|
std::vector<mc::psx::BasicBlock<false>> new_blocks;
|
||||||
|
new_blocks.reserve(block_count);
|
||||||
|
std::size_t index = 0;
|
||||||
for (const auto& block : blocks) {
|
for (const auto& block : blocks) {
|
||||||
assert(block_count == block.block_count() or block.block_count() == 0);
|
assert(block_count == block.block_count() or block.block_count() == 0);
|
||||||
uint8_t* const curr_block_ptr = dest;
|
uint8_t* const curr_block_ptr = dest;
|
||||||
dest = std::copy(block.data(), block.data() + block_size, dest);
|
dest = std::copy(block.data(), block.data() + block_size, dest);
|
||||||
|
new_blocks.emplace_back(curr_block_ptr, toc, index++);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::size_t new_id = m_next_id++;
|
const std::size_t new_id = m_next_id++;
|
||||||
m_saves.emplace(
|
m_saves.emplace(
|
||||||
std::piecewise_construct,
|
std::piecewise_construct,
|
||||||
std::forward_as_tuple(new_id),
|
std::forward_as_tuple(new_id),
|
||||||
std::forward_as_tuple(std::move(mem), block_count)
|
std::forward_as_tuple(std::move(new_blocks), std::move(mem))
|
||||||
);
|
);
|
||||||
m_block_count += block_count;
|
|
||||||
return static_cast<unsigned int>(m_saves.size() - 1u);
|
return static_cast<unsigned int>(m_saves.size() - 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t SavegameDb::savegame_count() const {
|
|
||||||
return m_saves.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t SavegameDb::block_count() const {
|
|
||||||
return m_block_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SavegameDb::begin() -> iterator {
|
|
||||||
return {m_saves.begin()};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SavegameDb::end() -> iterator {
|
|
||||||
return {m_saves.end()};
|
|
||||||
}
|
|
||||||
|
|
||||||
template unsigned int SavegameDb::add<true> (const std::vector<mc::psx::BasicBlock<true> >&);
|
template unsigned int SavegameDb::add<true> (const std::vector<mc::psx::BasicBlock<true> >&);
|
||||||
template unsigned int SavegameDb::add<false> (const std::vector<mc::psx::BasicBlock<false> >&);
|
template unsigned int SavegameDb::add<false> (const std::vector<mc::psx::BasicBlock<false> >&);
|
||||||
} //namespace duck
|
} //namespace duck
|
||||||
|
|
|
@ -17,135 +17,41 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "memcard/alignment.hpp"
|
|
||||||
#include "memcard/block.hpp"
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <utility>
|
|
||||||
#include <iterator>
|
namespace mc::psx {
|
||||||
#include <cassert>
|
template <bool C> class BasicBlock;
|
||||||
#include <ciso646>
|
} //namespace mc::psx
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace duck {
|
namespace duck {
|
||||||
struct BlockEntry {
|
struct BlockEntry {
|
||||||
BlockEntry (
|
BlockEntry (
|
||||||
std::unique_ptr<uint8_t[]>&& data,
|
std::vector<mc::psx::BasicBlock<false> >&& blocks,
|
||||||
std::size_t count
|
std::unique_ptr<uint8_t[]>&& data
|
||||||
);
|
);
|
||||||
|
|
||||||
template <bool C>
|
|
||||||
mc::psx::BasicBlock<C> make_block (std::size_t index) const;
|
|
||||||
std::string_view identifier() const;
|
std::string_view identifier() const;
|
||||||
std::string title() const;
|
std::string title() const;
|
||||||
std::uint8_t* data_ptr() const;
|
|
||||||
|
|
||||||
std::unique_ptr<std::uint8_t[]> data;
|
std::vector<mc::psx::BasicBlock<false> > blocks;
|
||||||
std::size_t block_count;
|
std::unique_ptr<uint8_t[]> data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SavegameDb {
|
class SavegameDb {
|
||||||
typedef std::map<unsigned int, BlockEntry> SavegameMap;
|
|
||||||
public:
|
public:
|
||||||
template <typename It>
|
|
||||||
class BlockIterator {
|
|
||||||
It m_it;
|
|
||||||
std::size_t m_pos_in_it {0};
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef typename std::iterator_traits<It>::difference_type difference_type;
|
|
||||||
typedef mc::psx::BasicBlock<std::is_const<SavegameMap::mapped_type>::value> value_type;
|
|
||||||
typedef std::add_pointer<value_type>::type pointer;
|
|
||||||
typedef value_type reference;
|
|
||||||
typedef mc::psx::ConstBlock const_reference;
|
|
||||||
typedef typename std::iterator_traits<It>::iterator_category iterator_category;
|
|
||||||
|
|
||||||
BlockIterator() = default;
|
|
||||||
BlockIterator(const BlockIterator&) = default;
|
|
||||||
BlockIterator(BlockIterator&&) = default;
|
|
||||||
BlockIterator (It&& it) : m_it(std::move(it)) {}
|
|
||||||
BlockIterator (const It& it) : m_it(it) {}
|
|
||||||
|
|
||||||
bool operator!=(const BlockIterator& other) const
|
|
||||||
{return m_it!=other.m_it or m_pos_in_it!=other.m_pos_in_it;}
|
|
||||||
bool operator==(const BlockIterator& other) const
|
|
||||||
{return m_it==other.m_it and m_pos_in_it==other.m_pos_in_it;}
|
|
||||||
|
|
||||||
BlockIterator& operator++();
|
|
||||||
BlockIterator operator++(int);
|
|
||||||
reference operator*();
|
|
||||||
const_reference operator*() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef BlockIterator<SavegameMap::iterator> iterator;
|
|
||||||
typedef BlockIterator<SavegameMap::const_iterator> const_iterator;
|
|
||||||
|
|
||||||
SavegameDb();
|
SavegameDb();
|
||||||
~SavegameDb() noexcept;
|
~SavegameDb() noexcept;
|
||||||
|
|
||||||
template <bool Const>
|
template <bool Const>
|
||||||
unsigned int add (const std::vector<mc::psx::BasicBlock<Const> >& blocks);
|
unsigned int add (const std::vector<mc::psx::BasicBlock<Const> >& blocks);
|
||||||
std::size_t savegame_count() const;
|
|
||||||
std::size_t block_count() const;
|
|
||||||
|
|
||||||
std::size_t size() const { return block_count(); }
|
|
||||||
iterator begin();
|
|
||||||
iterator end();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SavegameMap m_saves;
|
std::map<unsigned int, BlockEntry> m_saves;
|
||||||
std::size_t m_next_id{0};
|
std::size_t m_next_id{0};
|
||||||
std::size_t m_block_count{0};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <bool C>
|
|
||||||
mc::psx::BasicBlock<C> BlockEntry::make_block (std::size_t index) const {
|
|
||||||
using mc::psx::to_block_aligned;
|
|
||||||
using mc::psx::Frame;
|
|
||||||
using FrameType = typename mc::psx::BasicBlock<C>::FrameType;
|
|
||||||
|
|
||||||
assert(this->block_count > 0);
|
|
||||||
assert(this->block_count > index);
|
|
||||||
|
|
||||||
constexpr std::size_t frame_index = 0;
|
|
||||||
return {
|
|
||||||
to_block_aligned(this->data.get(), index, Frame::Size),
|
|
||||||
FrameType{to_block_aligned(this->data.get()), frame_index},
|
|
||||||
index
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename It>
|
|
||||||
SavegameDb::BlockIterator<It>& SavegameDb::BlockIterator<It>::operator++() {
|
|
||||||
const BlockEntry& entry = m_it->second;
|
|
||||||
++m_pos_in_it;
|
|
||||||
if (m_pos_in_it >= entry.block_count) {
|
|
||||||
++m_it;
|
|
||||||
m_pos_in_it = 0;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename It>
|
|
||||||
SavegameDb::BlockIterator<It> SavegameDb::BlockIterator<It>::operator++(int) {
|
|
||||||
auto retval = *this;
|
|
||||||
this->operator++();
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename It>
|
|
||||||
auto SavegameDb::BlockIterator<It>::operator*() -> reference {
|
|
||||||
BlockEntry& entry = m_it->second;
|
|
||||||
return entry.make_block<value_type::IsConst>(m_pos_in_it);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename It>
|
|
||||||
auto SavegameDb::BlockIterator<It>::operator*() const -> const_reference {
|
|
||||||
BlockEntry& entry = m_it->second;
|
|
||||||
return entry.make_block<value_type::IsConst>(m_pos_in_it);
|
|
||||||
}
|
|
||||||
} //namespace duck
|
} //namespace duck
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
/* Copyright 2020-2025, Michele Santullo
|
|
||||||
* This file is part of memoserv.
|
|
||||||
*
|
|
||||||
* Memoserv is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Memoserv is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Memoserv. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "savegame_model.hpp"
|
|
||||||
#include "savegame_db.hpp"
|
|
||||||
#include <cassert>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <ciso646>
|
|
||||||
|
|
||||||
namespace duck {
|
|
||||||
SavegameModel::SavegameModel() = default;
|
|
||||||
SavegameModel::~SavegameModel() noexcept = default;
|
|
||||||
|
|
||||||
MemoryCardSavegameModel::MemoryCardSavegameModel (mc::psx::MemoryCard* memcard) :
|
|
||||||
m_mc(memcard)
|
|
||||||
{
|
|
||||||
assert(m_mc);
|
|
||||||
}
|
|
||||||
|
|
||||||
SavegameModel::iterator MemoryCardSavegameModel::begin() {
|
|
||||||
return {m_mc->begin()};
|
|
||||||
}
|
|
||||||
|
|
||||||
SavegameModel::iterator MemoryCardSavegameModel::end() {
|
|
||||||
return {m_mc->end()};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t MemoryCardSavegameModel::block_count() const {
|
|
||||||
return m_mc->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MemoryCardSavegameModel::has_toc() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mc::psx::Block MemoryCardSavegameModel::toc() {
|
|
||||||
return m_mc->toc_block();
|
|
||||||
}
|
|
||||||
|
|
||||||
mc::psx::ConstBlock MemoryCardSavegameModel::toc() const {
|
|
||||||
return m_mc->toc_block();
|
|
||||||
}
|
|
||||||
|
|
||||||
mc::psx::Block MemoryCardSavegameModel::block (std::size_t index) {
|
|
||||||
return (*m_mc)[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
mc::psx::ConstBlock MemoryCardSavegameModel::block (std::size_t index) const {
|
|
||||||
return (*m_mc)[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
DbSavegameModel::DbSavegameModel (SavegameDb* db) :
|
|
||||||
m_db(db)
|
|
||||||
{
|
|
||||||
assert(m_db);
|
|
||||||
}
|
|
||||||
|
|
||||||
SavegameModel::iterator DbSavegameModel::begin() {
|
|
||||||
return {m_db->begin()};
|
|
||||||
}
|
|
||||||
|
|
||||||
SavegameModel::iterator DbSavegameModel::end() {
|
|
||||||
return {m_db->end()};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t DbSavegameModel::block_count() const {
|
|
||||||
return m_db->block_count();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DbSavegameModel::has_toc() const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mc::psx::Block DbSavegameModel::toc() {
|
|
||||||
throw std::runtime_error("TOC not available in SavegameDb");
|
|
||||||
}
|
|
||||||
|
|
||||||
mc::psx::ConstBlock DbSavegameModel::toc() const {
|
|
||||||
throw std::runtime_error("TOC not available in SavegameDb");
|
|
||||||
}
|
|
||||||
|
|
||||||
mc::psx::Block DbSavegameModel::block (std::size_t index) {
|
|
||||||
auto it = begin();
|
|
||||||
std::advance(it, index);
|
|
||||||
return *it;
|
|
||||||
}
|
|
||||||
|
|
||||||
mc::psx::ConstBlock DbSavegameModel::block (std::size_t index) const {
|
|
||||||
}
|
|
||||||
|
|
||||||
} //namespace duck
|
|
|
@ -1,90 +0,0 @@
|
||||||
/* Copyright 2020-2025, Michele Santullo
|
|
||||||
* This file is part of memoserv.
|
|
||||||
*
|
|
||||||
* Memoserv is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Memoserv is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Memoserv. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "memcard/memorycard.hpp"
|
|
||||||
#include "any_iterator.hpp"
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
namespace mc::psx {
|
|
||||||
template <bool> class BasicBlock;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace duck {
|
|
||||||
class SavegameDb;
|
|
||||||
|
|
||||||
class SavegameModel {
|
|
||||||
public:
|
|
||||||
typedef liph::any_forward_iterator<
|
|
||||||
mc::psx::BasicBlock<false>,
|
|
||||||
mc::psx::BasicBlock<false>,
|
|
||||||
mc::psx::BasicBlock<false>
|
|
||||||
> iterator;
|
|
||||||
|
|
||||||
SavegameModel();
|
|
||||||
virtual ~SavegameModel() noexcept;
|
|
||||||
|
|
||||||
std::size_t size() const { return this->block_count(); }
|
|
||||||
|
|
||||||
virtual iterator begin() = 0;
|
|
||||||
virtual iterator end() = 0;
|
|
||||||
virtual std::size_t block_count() const = 0;
|
|
||||||
virtual bool has_toc() const = 0;
|
|
||||||
virtual mc::psx::Block toc() = 0;
|
|
||||||
virtual mc::psx::ConstBlock toc() const = 0;
|
|
||||||
virtual mc::psx::Block block (std::size_t index) = 0;
|
|
||||||
virtual mc::psx::ConstBlock block (std::size_t index) const = 0;
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
class MemoryCardSavegameModel : public SavegameModel {
|
|
||||||
public:
|
|
||||||
explicit MemoryCardSavegameModel (mc::psx::MemoryCard* memcard);
|
|
||||||
virtual ~MemoryCardSavegameModel() noexcept = default;
|
|
||||||
|
|
||||||
SavegameModel::iterator begin() override;
|
|
||||||
SavegameModel::iterator end() override;
|
|
||||||
std::size_t block_count() const override;
|
|
||||||
bool has_toc() const override;
|
|
||||||
mc::psx::Block toc() override;
|
|
||||||
mc::psx::ConstBlock toc() const override;
|
|
||||||
mc::psx::Block block (std::size_t index) override;
|
|
||||||
mc::psx::ConstBlock block (std::size_t index) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
mc::psx::MemoryCard* m_mc;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DbSavegameModel : public SavegameModel {
|
|
||||||
public:
|
|
||||||
explicit DbSavegameModel (SavegameDb* db);
|
|
||||||
virtual ~DbSavegameModel() noexcept = default;
|
|
||||||
|
|
||||||
SavegameModel::iterator begin() override;
|
|
||||||
SavegameModel::iterator end() override;
|
|
||||||
std::size_t block_count() const override;
|
|
||||||
bool has_toc() const override;
|
|
||||||
mc::psx::Block toc() override;
|
|
||||||
mc::psx::ConstBlock toc() const override;
|
|
||||||
mc::psx::Block block (std::size_t index) override;
|
|
||||||
mc::psx::ConstBlock block (std::size_t index) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
SavegameDb* m_db;
|
|
||||||
};
|
|
||||||
} //namespace duck
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#include "block_grid.hpp"
|
#include "block_grid.hpp"
|
||||||
#include "vec.hpp"
|
#include "vec.hpp"
|
||||||
#include "savegame_model.hpp"
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
@ -98,10 +97,8 @@ QSize BlockGrid::icon_size() const {
|
||||||
return m_icon_size.isValid() ? m_icon_size : QSize(g_icon_spacing, g_icon_spacing);
|
return m_icon_size.isValid() ? m_icon_size : QSize(g_icon_spacing, g_icon_spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockGrid::set_savegames (std::unique_ptr<duck::SavegameModel>&& savegames) {
|
void BlockGrid::push_back (AnimatedPixmap&& anim) {
|
||||||
m_savegames = std::move(savegames);
|
m_icons.push_back(std::move(anim));
|
||||||
if (m_savegames) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t BlockGrid::size() const {
|
std::size_t BlockGrid::size() const {
|
||||||
|
|
|
@ -27,10 +27,6 @@
|
||||||
|
|
||||||
class QTimer;
|
class QTimer;
|
||||||
|
|
||||||
namespace duck {
|
|
||||||
class SavegameModel;
|
|
||||||
} //namespace duck
|
|
||||||
|
|
||||||
namespace duck::widget {
|
namespace duck::widget {
|
||||||
class BlockGrid : public QWidget {
|
class BlockGrid : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -45,14 +41,13 @@ public:
|
||||||
void set_icon_size (int sz);
|
void set_icon_size (int sz);
|
||||||
QSize icon_size() const;
|
QSize icon_size() const;
|
||||||
|
|
||||||
void set_savegames (std::unique_ptr<duck::SavegameModel>&& savegames);
|
void push_back (AnimatedPixmap&& anim);
|
||||||
std::size_t size() const;
|
std::size_t size() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent (QPaintEvent* event) override;
|
void paintEvent (QPaintEvent* event) override;
|
||||||
void dragEnterEvent(QDragEnterEvent* event) override;
|
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||||
void dropEvent(QDropEvent* event) override;
|
void dropEvent(QDropEvent* event) override;
|
||||||
//void dragMoveEvent(QDragMoveEvent* event) override;
|
|
||||||
void mousePressEvent(QMouseEvent* event) override;
|
void mousePressEvent(QMouseEvent* event) override;
|
||||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||||
void mouseMoveEvent(QMouseEvent* event) override;
|
void mouseMoveEvent(QMouseEvent* event) override;
|
||||||
|
@ -70,7 +65,6 @@ private:
|
||||||
QSize m_icon_size;
|
QSize m_icon_size;
|
||||||
QTimer* m_anim_timer;
|
QTimer* m_anim_timer;
|
||||||
std::unique_ptr<QPixmap> m_empty_icon;
|
std::unique_ptr<QPixmap> m_empty_icon;
|
||||||
std::unique_ptr<duck::SavegameModel> m_savegames;
|
|
||||||
unsigned int m_rows;
|
unsigned int m_rows;
|
||||||
unsigned int m_columns;
|
unsigned int m_columns;
|
||||||
};
|
};
|
||||||
|
|
|
@ -117,29 +117,10 @@ void BlockDragAndDrop::mouse_move_event (const QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockDragAndDrop::drag_enter_event(QDragEnterEvent* event) {
|
void BlockDragAndDrop::drag_enter_event(QDragEnterEvent* event) {
|
||||||
const QMimeData* const mime = event->mimeData();
|
if (not m_dragging and event->mimeData()->hasFormat(g_drag_mime))
|
||||||
if (not m_dragging and mime->hasFormat(g_drag_mime))
|
|
||||||
event->acceptProposedAction();
|
event->acceptProposedAction();
|
||||||
else if (mime->hasUrls())
|
|
||||||
event->acceptProposedAction();
|
|
||||||
else {
|
|
||||||
std::cout << "drag_enter rejected:";
|
|
||||||
for (const auto& str : mime->formats()) {
|
|
||||||
std::cout << ' ' << str.toStdString();
|
|
||||||
}
|
|
||||||
std::cout << '\n';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockDragAndDrop::drop_event(QDropEvent* event) {
|
void BlockDragAndDrop::drop_event(QDropEvent* event) {
|
||||||
if (event->mimeData()->hasUrls()) {
|
|
||||||
for (const auto& url : event->mimeData()->urls()) {
|
|
||||||
if (url.isLocalFile())
|
|
||||||
std::cout << "would accept " << url.toLocalFile().toStdString();
|
|
||||||
else
|
|
||||||
std::cout << "rejecting " << url.toString().toStdString();
|
|
||||||
std::cout << '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} //namespace duck::widget::detail
|
} //namespace duck::widget::detail
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
/* Copyright 2020-2025, Michele Santullo
|
|
||||||
* This file is part of memoserv.
|
|
||||||
*
|
|
||||||
* Memoserv is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Memoserv is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Memoserv. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace dhandy {
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
class PackedPointer;
|
|
||||||
} //namespace dhandy
|
|
||||||
|
|
||||||
namespace mc::psx {
|
|
||||||
std::uint8_t* to_block_aligned (std::uint8_t* ptr, std::size_t index=0, std::ptrdiff_t base_offs=0);
|
|
||||||
const std::uint8_t* to_block_aligned (const std::uint8_t* ptr, std::size_t index=0, std::ptrdiff_t base_offs=0);
|
|
||||||
bool is_block_aligned (const std::uint8_t* ptr);
|
|
||||||
|
|
||||||
template <typename T, std::size_t A>
|
|
||||||
bool is_block_aligned (const dhandy::PackedPointer<T, std::size_t, A>& ptr);
|
|
||||||
|
|
||||||
std::unique_ptr<std::uint8_t[]> make_unique_for_block_aligned(std::size_t size);
|
|
||||||
} //namespace mc::psx
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "memcard/frame.hpp"
|
#include "memcard/frame.hpp"
|
||||||
#include "memcard/frame_iterator.hpp"
|
#include "memcard/frame_iterator.hpp"
|
||||||
#include "memcard/country_code.hpp"
|
#include "memcard/country_code.hpp"
|
||||||
#include "duckhandy/packed_pointer.hpp"
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -45,27 +44,20 @@ public:
|
||||||
using data_type = typename std::conditional<Const, const uint8_t, uint8_t>::type;
|
using data_type = typename std::conditional<Const, const uint8_t, uint8_t>::type;
|
||||||
typedef FrameIterator<Const, Const> iterator;
|
typedef FrameIterator<Const, Const> iterator;
|
||||||
typedef FrameIterator<true, Const> const_iterator;
|
typedef FrameIterator<true, Const> const_iterator;
|
||||||
typedef BasicFrame<Const> FrameType;
|
|
||||||
|
|
||||||
static const constexpr std::size_t FrameCount = 64;
|
static const constexpr std::size_t FrameCount = 64;
|
||||||
static const constexpr std::size_t TOCBlockIndex = 0xFF;
|
static const constexpr std::size_t TOCBlockIndex = 0xFF;
|
||||||
static const constexpr uint16_t LastLink = 0xFFFF;
|
static const constexpr uint16_t LastLink = 0xFFFF;
|
||||||
static constexpr std::size_t BlockByteSize = FrameType::Size * FrameCount;
|
static constexpr std::size_t BlockByteSize = BasicFrame<Const>::Size * FrameCount;
|
||||||
static constexpr auto DataAlignment = FrameType::DataAlignment;
|
|
||||||
static constexpr bool IsConst = Const;
|
|
||||||
static_assert(BlockByteSize % DataAlignment == 0);
|
|
||||||
|
|
||||||
BasicBlock() = default;
|
BasicBlock() = default;
|
||||||
constexpr BasicBlock (const BasicBlock& other);
|
constexpr BasicBlock (const BasicBlock& other);
|
||||||
BasicBlock(BasicBlock&&) = default;
|
BasicBlock(BasicBlock&&) = default;
|
||||||
BasicBlock (data_type* blk, std::size_t index);
|
BasicBlock (data_type* blk, std::size_t index);
|
||||||
BasicBlock (data_type* blk, FrameType toc_entry, std::size_t index);
|
BasicBlock (data_type* blk, BasicFrame<Const> toc_entry, std::size_t index);
|
||||||
template <bool Const2> BasicBlock(const BasicBlock<Const2>& other);
|
template <bool Const2> BasicBlock(const BasicBlock<Const2>& other);
|
||||||
~BasicBlock();
|
~BasicBlock();
|
||||||
|
|
||||||
BasicBlock* operator->() {return this;}
|
|
||||||
const BasicBlock* operator->() const {return this;}
|
|
||||||
|
|
||||||
iterator begin();
|
iterator begin();
|
||||||
iterator end();
|
iterator end();
|
||||||
const_iterator cbegin() const;
|
const_iterator cbegin() const;
|
||||||
|
@ -76,9 +68,9 @@ public:
|
||||||
data_type* data() { return m_begin; }
|
data_type* data() { return m_begin; }
|
||||||
const data_type* data() const { return m_begin; }
|
const data_type* data() const { return m_begin; }
|
||||||
|
|
||||||
FrameType frame(unsigned int idx);
|
BasicFrame<Const> frame(unsigned int idx);
|
||||||
ConstFrame frame(unsigned int idx) const;
|
ConstFrame frame(unsigned int idx) const;
|
||||||
FrameType toc();
|
BasicFrame<Const> toc();
|
||||||
ConstFrame toc() const;
|
ConstFrame toc() const;
|
||||||
|
|
||||||
static constexpr std::size_t size() { return FrameCount; }
|
static constexpr std::size_t size() { return FrameCount; }
|
||||||
|
@ -87,7 +79,7 @@ public:
|
||||||
bool has_magic() const;
|
bool has_magic() const;
|
||||||
IconDisplayFlag icon_display_flag() const;
|
IconDisplayFlag icon_display_flag() const;
|
||||||
std::size_t block_count() const;
|
std::size_t block_count() const;
|
||||||
std::size_t index() const { return dhandy::get<0>(m_begin); }
|
std::size_t index() const { return m_index; }
|
||||||
std::string title() const;
|
std::string title() const;
|
||||||
std::size_t available_blocks() const;
|
std::size_t available_blocks() const;
|
||||||
uint32_t use_byte() const;
|
uint32_t use_byte() const;
|
||||||
|
@ -103,8 +95,9 @@ public:
|
||||||
BasicBlock& operator= (BasicBlock&&) = default;
|
BasicBlock& operator= (BasicBlock&&) = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FrameType m_toc_entry;
|
BasicFrame<Const> m_toc_entry;
|
||||||
dhandy::PackedPointer<data_type, std::size_t, DataAlignment> m_begin;
|
std::size_t m_index;
|
||||||
|
data_type* m_begin;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[gnu::const]]
|
[[gnu::const]]
|
||||||
|
@ -129,6 +122,7 @@ inline int32_t calc_icon_count (IconDisplayFlag idf) {
|
||||||
template <bool Const>
|
template <bool Const>
|
||||||
constexpr BasicBlock<Const>::BasicBlock (const BasicBlock& other) :
|
constexpr BasicBlock<Const>::BasicBlock (const BasicBlock& other) :
|
||||||
m_toc_entry(other.m_toc_entry),
|
m_toc_entry(other.m_toc_entry),
|
||||||
|
m_index(other.m_index),
|
||||||
m_begin(other.m_begin)
|
m_begin(other.m_begin)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -137,6 +131,7 @@ template <bool Const>
|
||||||
template <bool Const2>
|
template <bool Const2>
|
||||||
inline BasicBlock<Const>::BasicBlock(const BasicBlock<Const2>& other) :
|
inline BasicBlock<Const>::BasicBlock(const BasicBlock<Const2>& other) :
|
||||||
m_toc_entry(other.m_toc_entry),
|
m_toc_entry(other.m_toc_entry),
|
||||||
|
m_index(other.m_index),
|
||||||
m_begin(other.m_begin)
|
m_begin(other.m_begin)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "duckhandy/packed_pointer.hpp"
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
@ -30,11 +29,6 @@ class BasicFrame {
|
||||||
using data_type = typename std::conditional<Const, const uint8_t, uint8_t>::type;
|
using data_type = typename std::conditional<Const, const uint8_t, uint8_t>::type;
|
||||||
public:
|
public:
|
||||||
static const constexpr unsigned int Size = 128;
|
static const constexpr unsigned int Size = 128;
|
||||||
//Standard memory cards can hold up to 15 blocks so we need 4 bits in the
|
|
||||||
//data pointer field to use for index storing. This means alignment of the
|
|
||||||
//supplied block should be at least 16
|
|
||||||
static constexpr std::size_t DataAlignment = 16;
|
|
||||||
static_assert(Size % DataAlignment == 0);
|
|
||||||
|
|
||||||
BasicFrame() = default;
|
BasicFrame() = default;
|
||||||
BasicFrame (data_type* data, std::size_t index);
|
BasicFrame (data_type* data, std::size_t index);
|
||||||
|
@ -66,7 +60,8 @@ public:
|
||||||
private:
|
private:
|
||||||
void extract (std::size_t offset, std::size_t sz, uint8_t* out);
|
void extract (std::size_t offset, std::size_t sz, uint8_t* out);
|
||||||
|
|
||||||
dhandy::PackedPointer<data_type, std::size_t, DataAlignment> m_data;
|
std::size_t m_index;
|
||||||
|
data_type* m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, bool Const>
|
template <typename T, bool Const>
|
||||||
|
@ -83,6 +78,7 @@ inline T read_as (const BasicFrame<Const>& frame, std::size_t offset) {
|
||||||
template <bool Const>
|
template <bool Const>
|
||||||
template <bool Const2>
|
template <bool Const2>
|
||||||
inline BasicFrame<Const>::BasicFrame (const BasicFrame<Const2>& other) {
|
inline BasicFrame<Const>::BasicFrame (const BasicFrame<Const2>& other) {
|
||||||
|
m_index = other.m_index;
|
||||||
m_data = other.m_data;
|
m_data = other.m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,9 +58,7 @@ public:
|
||||||
const_iterator end() const;
|
const_iterator end() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::uint8_t* data_ptr() const;
|
std::vector<uint8_t> m_data;
|
||||||
|
|
||||||
std::vector<std::uint8_t> m_data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::size_t> block_group (const MemoryCard& mc, std::size_t index);
|
std::vector<std::size_t> block_group (const MemoryCard& mc, std::size_t index);
|
||||||
|
|
|
@ -1,180 +0,0 @@
|
||||||
/* Copyright 2016-2025 Michele Santullo
|
|
||||||
* This file is part of "duckhandy".
|
|
||||||
*
|
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* "duckhandy" is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef id895441FC389F481EB824A809A0BF5004
|
|
||||||
#define id895441FC389F481EB824A809A0BF5004
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <climits>
|
|
||||||
|
|
||||||
namespace dhandy {
|
|
||||||
namespace implem {
|
|
||||||
template <typename T, std::size_t Index>
|
|
||||||
class BitfieldData;
|
|
||||||
|
|
||||||
template <typename T, std::size_t Index>
|
|
||||||
class BitfieldData : public BitfieldData<T, Index - 1> {
|
|
||||||
protected:
|
|
||||||
BitfieldData (T init) : BitfieldData<T, Index - 1>(init), m_value(init) {}
|
|
||||||
public:
|
|
||||||
T& value() { return m_value; }
|
|
||||||
T value() const { return m_value; }
|
|
||||||
private:
|
|
||||||
T m_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class BitfieldData<T, 1> {
|
|
||||||
protected:
|
|
||||||
BitfieldData (T init) : m_value(init) {}
|
|
||||||
public:
|
|
||||||
T& value() { return m_value; }
|
|
||||||
T value() const { return m_value; }
|
|
||||||
private:
|
|
||||||
T m_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class BitfieldData<T, 0>;
|
|
||||||
|
|
||||||
struct SizeAndOffs {
|
|
||||||
std::size_t size, offset;
|
|
||||||
};
|
|
||||||
struct IndexAndSize {
|
|
||||||
std::size_t index, size;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <std::size_t Sum>
|
|
||||||
constexpr inline SizeAndOffs size_and_offset_impl (std::size_t) {
|
|
||||||
throw std::out_of_range("Requested pack index out of range");
|
|
||||||
}
|
|
||||||
template <std::size_t Sum, std::size_t Sz, std::size_t... Sizes>
|
|
||||||
constexpr inline SizeAndOffs size_and_offset_impl (std::size_t index) {
|
|
||||||
return (index ? size_and_offset_impl<Sum + Sz, Sizes...>(index - 1) : SizeAndOffs{Sz, Sum});
|
|
||||||
}
|
|
||||||
template <std::size_t... Sizes>
|
|
||||||
constexpr inline SizeAndOffs size_and_offset (std::size_t index) {
|
|
||||||
return size_and_offset_impl<0, Sizes...>(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t CurrMax, std::size_t MaxIdx, std::size_t Idx>
|
|
||||||
constexpr inline IndexAndSize index_and_size_impl() {
|
|
||||||
throw std::runtime_error("Should not be reached");
|
|
||||||
}
|
|
||||||
template <std::size_t CurrMax, std::size_t MaxIdx, std::size_t Idx, std::size_t Sz, std::size_t... Sizes>
|
|
||||||
constexpr inline IndexAndSize index_and_size_impl() {
|
|
||||||
return (Idx ? index_and_size_impl<
|
|
||||||
(CurrMax > Sz ? CurrMax : Sz),
|
|
||||||
(CurrMax > Sz ? MaxIdx : Idx),
|
|
||||||
Idx - 1,
|
|
||||||
Sizes...
|
|
||||||
>() : IndexAndSize{(CurrMax > Sz ? MaxIdx : Idx) - 1, CurrMax > Sz ? CurrMax : Sz});
|
|
||||||
}
|
|
||||||
template <std::size_t Sz, std::size_t... Sizes>
|
|
||||||
constexpr inline IndexAndSize index_and_size() {
|
|
||||||
return index_and_size_impl<Sz, sizeof...(Sizes), sizeof...(Sizes), Sz, Sizes...>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, std::size_t... Sizes>
|
|
||||||
struct BitfieldFacts {
|
|
||||||
static const constexpr std::size_t Sum = size_and_offset<Sizes...>(sizeof...(Sizes) - 1).size + size_and_offset<Sizes...>(sizeof...(Sizes) - 1).offset;
|
|
||||||
static const constexpr std::size_t ElementCount = (Sum + CHAR_BIT * sizeof(T) - 1) / (CHAR_BIT * sizeof(T));
|
|
||||||
static const constexpr std::size_t LargestIndex = index_and_size<Sizes...>().index;
|
|
||||||
static const constexpr std::size_t LargestSize = index_and_size<Sizes...>().size;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
[[gnu::const]]
|
|
||||||
constexpr inline T make_mask (std::size_t len) noexcept {
|
|
||||||
return (T{1} << len) - 1;
|
|
||||||
}
|
|
||||||
} //namespace implem
|
|
||||||
|
|
||||||
template <typename T, std::size_t... Sizes>
|
|
||||||
class BitfieldPack;
|
|
||||||
|
|
||||||
template <std::size_t Idx, typename T, std::size_t... Sizes>
|
|
||||||
T get (const BitfieldPack<T, Sizes...>&);
|
|
||||||
template <std::size_t Idx, typename T, typename V, std::size_t... Sizes>
|
|
||||||
void set (BitfieldPack<T, Sizes...>&, V);
|
|
||||||
|
|
||||||
template <typename T, std::size_t... Sizes>
|
|
||||||
class BitfieldPack : private implem::BitfieldData<T, implem::BitfieldFacts<T, Sizes...>::ElementCount> {
|
|
||||||
typedef implem::BitfieldFacts<T, Sizes...> Facts;
|
|
||||||
template <std::size_t Idx, typename U, std::size_t... S> friend U get (const BitfieldPack<U, S...>&);
|
|
||||||
template <std::size_t Idx, typename U, typename V, std::size_t... S> friend void set (BitfieldPack<U, S...>&, V);
|
|
||||||
typedef implem::BitfieldData<T, Facts::ElementCount> base_type;
|
|
||||||
static_assert(Facts::LargestSize <= sizeof(T) * CHAR_BIT, "Bitfield size can't be larger than the data type itself");
|
|
||||||
public:
|
|
||||||
template <std::size_t Idx>
|
|
||||||
static constexpr T max_at_index = implem::make_mask<T>(implem::size_and_offset<Sizes...>(Idx).size);
|
|
||||||
static constexpr std::size_t element_count = sizeof...(Sizes);
|
|
||||||
BitfieldPack (T init=T{}) : base_type(init) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <std::size_t Idx, typename T, std::size_t... Sizes>
|
|
||||||
T get (const BitfieldPack<T, Sizes...>& pack) {
|
|
||||||
using implem::size_and_offset;
|
|
||||||
using implem::BitfieldData;
|
|
||||||
using implem::make_mask;
|
|
||||||
|
|
||||||
static_assert(Idx < sizeof...(Sizes), "Index out of bounds");
|
|
||||||
const constexpr auto so = size_and_offset<Sizes...>(Idx);
|
|
||||||
const constexpr std::size_t index = so.offset / (sizeof(T) * CHAR_BIT);
|
|
||||||
const constexpr std::size_t reloffs = so.offset % (sizeof(T) * CHAR_BIT);
|
|
||||||
const constexpr bool bleeds_into_next = reloffs + so.size > sizeof(T) * CHAR_BIT;
|
|
||||||
|
|
||||||
const T bottom = static_cast<const BitfieldData<T, index + 1>&>(pack).value() >> reloffs;
|
|
||||||
if constexpr (bleeds_into_next) {
|
|
||||||
const std::size_t safe_index = index + 2;
|
|
||||||
const T val = static_cast<const BitfieldData<T, safe_index>&>(pack).value();
|
|
||||||
const T top = val << (sizeof(T) * CHAR_BIT - reloffs);
|
|
||||||
return static_cast<T>(top | bottom) & make_mask<T>(so.size);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return bottom & make_mask<T>(so.size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t Idx, typename T, typename V, std::size_t... Sizes>
|
|
||||||
void set (BitfieldPack<T, Sizes...>& pack, V val) {
|
|
||||||
using implem::size_and_offset;
|
|
||||||
using implem::BitfieldData;
|
|
||||||
using implem::make_mask;
|
|
||||||
|
|
||||||
static_assert(Idx < sizeof...(Sizes), "Index out of bounds");
|
|
||||||
const constexpr auto so = size_and_offset<Sizes...>(Idx);
|
|
||||||
const constexpr std::size_t index = so.offset / (sizeof(T) * CHAR_BIT);
|
|
||||||
const constexpr std::size_t reloffs = so.offset % (sizeof(T) * CHAR_BIT);
|
|
||||||
const constexpr bool bleeds_into_next = reloffs + so.size > sizeof(T) * CHAR_BIT;
|
|
||||||
|
|
||||||
T& bottom = static_cast<BitfieldData<T, index + 1>&>(pack).value();
|
|
||||||
bottom &= ~(make_mask<T>(so.size) << reloffs);
|
|
||||||
bottom |= static_cast<T>((val & make_mask<T>(so.size)) << reloffs);
|
|
||||||
|
|
||||||
if (bleeds_into_next) {
|
|
||||||
const std::size_t safe_index = index + 2 - not bleeds_into_next;
|
|
||||||
T& top = static_cast<BitfieldData<T, safe_index>&>(pack).value();
|
|
||||||
const constexpr std::size_t shift = sizeof(T) * CHAR_BIT - reloffs;
|
|
||||||
top &= ~(make_mask<T>(so.size) >> shift);
|
|
||||||
top |= val >> shift;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} //namespace dhandy
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,306 +0,0 @@
|
||||||
/* Copyright 2016-2025 Michele Santullo
|
|
||||||
* This file is part of "duckhandy".
|
|
||||||
*
|
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* "duckhandy" is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef id83CE9FAB90684250B98EA584C548E13F
|
|
||||||
#define id83CE9FAB90684250B98EA584C548E13F
|
|
||||||
|
|
||||||
#include "bitfield_pack.hpp"
|
|
||||||
#include <cstdint>
|
|
||||||
#include <utility>
|
|
||||||
#include <climits>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <cassert>
|
|
||||||
#include <concepts>
|
|
||||||
|
|
||||||
namespace dhandy {
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
//This monster expression is just the one-liner version of this
|
|
||||||
//implementation of log2:
|
|
||||||
//unsigned int v; // 32-bit value to find the log2 of
|
|
||||||
//register unsigned int r; // result of log2(v) will go here
|
|
||||||
//register unsigned int shift;
|
|
||||||
//
|
|
||||||
//r = (v > 0xFFFF) << 4; v >>= r;
|
|
||||||
//shift = (v > 0xFF ) << 3; v >>= shift; r |= shift;
|
|
||||||
//shift = (v > 0xF ) << 2; v >>= shift; r |= shift;
|
|
||||||
//shift = (v > 0x3 ) << 1; v >>= shift; r |= shift;
|
|
||||||
// r |= (v >> 1);
|
|
||||||
//see https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog for
|
|
||||||
//an explanation of that.
|
|
||||||
//This is a shorter version of it but it only works if the input is a power
|
|
||||||
//of 2:
|
|
||||||
//(((((NUM&0xAAAAAAAA)!=0)|((NUM&0xFFFF0000)!=0)<<4)|((NUM&0xFF00FF00)!=0)<<
|
|
||||||
//3)|((NUM&0xF0F0F0F0)!=0)<<2)|((NUM&0xCCCCCCCC)!=0)<<1
|
|
||||||
//Source for that is also available at the page linked above.
|
|
||||||
template <std::uint32_t NUM> constexpr std::size_t pointer_unused_bit_count =
|
|
||||||
((((((NUM > 0xFFFF) << 4) | (((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) <<
|
|
||||||
3)) | ((((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> ((NUM > 0xFFFF) <<
|
|
||||||
4)) > 0xFF) << 3)) > 0xF) << 2)) | (((((NUM >> ((NUM > 0xFFFF) << 4)) >>
|
|
||||||
(((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) << 3)) >> ((((NUM >> ((NUM >
|
|
||||||
0xFFFF) << 4)) >> (((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) << 3)) > 0xF)
|
|
||||||
<< 2)) > 0x3) << 1)) | (((((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> (
|
|
||||||
(NUM > 0xFFFF) << 4)) > 0xFF) << 3)) >> ((((NUM >> ((NUM > 0xFFFF) << 4)
|
|
||||||
) >> (((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) << 3)) > 0xF) << 2)) >> ((
|
|
||||||
(((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> ((NUM > 0xFFFF) << 4)) >
|
|
||||||
0xFF) << 3)) >> ((((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> ((NUM >
|
|
||||||
0xFFFF) << 4)) > 0xFF) << 3)) > 0xF) << 2)) > 0x3) << 1)) >> 1))
|
|
||||||
;
|
|
||||||
|
|
||||||
template <std::size_t... S>
|
|
||||||
BitfieldPack<
|
|
||||||
std::uintptr_t,
|
|
||||||
sizeof(std::uintptr_t) * CHAR_BIT - sizeof...(S), (S+1)/(S+1)...
|
|
||||||
>
|
|
||||||
guess_bitfield_type (std::index_sequence<S...>);
|
|
||||||
|
|
||||||
template <std::size_t PtrAlign>
|
|
||||||
using BaseBitfieldPackForPackedPointer = decltype(
|
|
||||||
guess_bitfield_type(
|
|
||||||
std::make_index_sequence<pointer_unused_bit_count<PtrAlign>>()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
template <std::size_t PtrAlign>
|
|
||||||
using BaseIntPackForPackedPointer = BitfieldPack<
|
|
||||||
std::uintptr_t,
|
|
||||||
sizeof(std::uintptr_t) * CHAR_BIT - pointer_unused_bit_count<PtrAlign>,
|
|
||||||
pointer_unused_bit_count<PtrAlign>
|
|
||||||
>;
|
|
||||||
|
|
||||||
template <std::size_t PtrAlign, bool BitFlags>
|
|
||||||
using BaseBitfieldType = std::conditional_t<BitFlags,
|
|
||||||
BaseBitfieldPackForPackedPointer<PtrAlign>, BaseIntPackForPackedPointer<PtrAlign>
|
|
||||||
>;
|
|
||||||
|
|
||||||
template <typename T, typename I>
|
|
||||||
struct PackedPointerSetterGetter {
|
|
||||||
template <std::size_t Idx, std::size_t S1, std::size_t S2>
|
|
||||||
static void set (dhandy::BitfieldPack<std::uintptr_t, S1, S2>& out, I val) {
|
|
||||||
static_assert(0 == Idx);
|
|
||||||
dhandy::set<1>(out, val);
|
|
||||||
}
|
|
||||||
template <std::size_t Idx, std::size_t S1, std::size_t S2>
|
|
||||||
static I get (const dhandy::BitfieldPack<std::uintptr_t, S1, S2>& in) {
|
|
||||||
static_assert(0 == Idx);
|
|
||||||
return dhandy::get<1>(in);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct PackedPointerSetterGetter<T, bool> {
|
|
||||||
template <std::size_t Idx, std::size_t... S>
|
|
||||||
static void set (dhandy::BitfieldPack<std::uintptr_t, S...>& out, bool flag) {
|
|
||||||
static_assert(Idx < sizeof...(S) - 1, "Index out of range");
|
|
||||||
dhandy::set<Idx+1>(out, (flag ? 1u : 0u));
|
|
||||||
}
|
|
||||||
template <std::size_t Idx, std::size_t... S>
|
|
||||||
static bool get (const dhandy::BitfieldPack<std::uintptr_t, S...>& in) {
|
|
||||||
static_assert(Idx < sizeof...(S) - 1, "Index out of range");
|
|
||||||
return static_cast<bool>(dhandy::get<Idx+1>(in));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} //namespace detail
|
|
||||||
|
|
||||||
template <typename T, typename I=bool, std::size_t A=alignof(T)>
|
|
||||||
class PackedPointer : detail::BaseBitfieldType<A, std::is_same<I, bool>::value> {
|
|
||||||
static_assert(A >= 2, "Not enough space to pack anything");
|
|
||||||
static_assert(sizeof(T*) == sizeof(std::uintptr_t), "Mismatching int/pointer size");
|
|
||||||
typedef detail::BaseBitfieldType<A, std::is_same<I, bool>::value> parent_type;
|
|
||||||
static_assert(sizeof(parent_type) == sizeof(T*));
|
|
||||||
|
|
||||||
template <std::size_t Idx, typename U, typename J, std::size_t B> friend J get (const PackedPointer<U, J, B>&);
|
|
||||||
template <std::size_t Idx, typename U, typename J, std::size_t B> friend void set (PackedPointer<U, J, B>&, J);
|
|
||||||
public:
|
|
||||||
static constexpr std::size_t FlagsCount = parent_type::element_count - 1;
|
|
||||||
static constexpr auto max_payload =
|
|
||||||
static_cast<std::conditional_t<std::is_same_v<I,bool>, unsigned int, I>>(
|
|
||||||
parent_type::template max_at_index<1>
|
|
||||||
);
|
|
||||||
typedef I int_type;
|
|
||||||
|
|
||||||
PackedPointer();
|
|
||||||
PackedPointer (T* ptr);
|
|
||||||
PackedPointer (const PackedPointer& other);
|
|
||||||
PackedPointer (PackedPointer&& other);
|
|
||||||
~PackedPointer() = default;
|
|
||||||
|
|
||||||
operator T*();
|
|
||||||
operator const T*() const;
|
|
||||||
operator std::uintptr_t() const;
|
|
||||||
operator bool() const;
|
|
||||||
|
|
||||||
PackedPointer& operator= (const PackedPointer& other);
|
|
||||||
PackedPointer& operator= (PackedPointer&& other);
|
|
||||||
PackedPointer& operator= (T* ptr);
|
|
||||||
T* operator+ (std::integral auto diff);
|
|
||||||
const T* operator+ (std::integral auto diff) const;
|
|
||||||
T* operator- (std::integral auto diff);
|
|
||||||
const T* operator- (std::integral auto diff) const;
|
|
||||||
T* operator->();
|
|
||||||
const T* operator->() const;
|
|
||||||
T& operator*();
|
|
||||||
const T& operator*() const;
|
|
||||||
bool operator== (const PackedPointer& other) const;
|
|
||||||
bool operator== (T* other) const;
|
|
||||||
bool operator!= (const PackedPointer& other) const;
|
|
||||||
bool operator!= (T* other) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
//static const constexpr uintptr_t PtrMask = static_cast<uintptr_t>(-1) << FlagsCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <std::size_t Idx=0, typename T=char, typename I=bool, std::size_t A=0>
|
|
||||||
inline void set (PackedPointer<T, I, A>& obj, I value) {
|
|
||||||
assert(value < (1u << A));
|
|
||||||
detail::PackedPointerSetterGetter<T, I>::template set<Idx>(obj, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t Idx=0, typename T=char, typename I=bool, std::size_t A>
|
|
||||||
inline I get (const PackedPointer<T, I, A>& obj) {
|
|
||||||
return detail::PackedPointerSetterGetter<T, I>::template get<Idx>(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A> const constexpr std::size_t PackedPointer<T, I, A>::FlagsCount;
|
|
||||||
//template <typename T> const constexpr std::uintptr_t PackedPointer<T>::PtrMask;
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
PackedPointer<T, I, A>::PackedPointer() :
|
|
||||||
PackedPointer(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
PackedPointer<T, I, A>::PackedPointer (T* ptr) :
|
|
||||||
parent_type(0)
|
|
||||||
{
|
|
||||||
(*this) = ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
PackedPointer<T, I, A>::PackedPointer (const PackedPointer& other) :
|
|
||||||
parent_type(other)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
PackedPointer<T, I, A>::PackedPointer (PackedPointer&& other) :
|
|
||||||
parent_type(std::move(other))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
PackedPointer<T, I, A>::operator T*() {
|
|
||||||
return reinterpret_cast<T*>(get<0>(*static_cast<parent_type*>(this)) << FlagsCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
PackedPointer<T, I, A>::operator const T*() const {
|
|
||||||
return reinterpret_cast<const T*>(get<0>(*static_cast<const parent_type*>(this)) << FlagsCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
PackedPointer<T, I, A>::operator std::uintptr_t() const {
|
|
||||||
return get<0>(*static_cast<const parent_type*>(this)) << FlagsCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
PackedPointer<T, I, A>::operator bool() const {
|
|
||||||
return static_cast<T*>(*this) != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
PackedPointer<T, I, A>& PackedPointer<T, I, A>::operator= (const PackedPointer& other) {
|
|
||||||
*static_cast<parent_type*>(this) = static_cast<parent_type&>(other);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
PackedPointer<T, I, A>& PackedPointer<T, I, A>::operator= (PackedPointer&& other) {
|
|
||||||
*static_cast<parent_type*>(this) = std::move(static_cast<parent_type&>(other));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
PackedPointer<T, I, A>& PackedPointer<T, I, A>::operator= (T* ptr) {
|
|
||||||
assert(reinterpret_cast<std::uintptr_t>(ptr) % A == 0);
|
|
||||||
set<0>(*static_cast<parent_type*>(this), reinterpret_cast<std::uintptr_t>(ptr) >> FlagsCount);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
T* PackedPointer<T, I, A>::operator+ (std::integral auto diff) {
|
|
||||||
return static_cast<T*>(*this) + diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
const T* PackedPointer<T, I, A>::operator+ (std::integral auto diff) const {
|
|
||||||
return static_cast<const T*>(*this) + diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
T* PackedPointer<T, I, A>::operator- (std::integral auto diff) {
|
|
||||||
return static_cast<T*>(*this) + diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
const T* PackedPointer<T, I, A>::operator- (std::integral auto diff) const {
|
|
||||||
return static_cast<const T*>(*this) + diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
T* PackedPointer<T, I, A>::operator->() {
|
|
||||||
return static_cast<T*>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
const T* PackedPointer<T, I, A>::operator->() const {
|
|
||||||
return static_cast<T*>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
T& PackedPointer<T, I, A>::operator*() {
|
|
||||||
return *static_cast<T*>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
const T& PackedPointer<T, I, A>::operator*() const {
|
|
||||||
return *static_cast<T*>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
bool PackedPointer<T, I, A>::operator== (const PackedPointer& other) const {
|
|
||||||
return this == &other or static_cast<T*>(*this) == static_cast<T*>(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
bool PackedPointer<T, I, A>::operator== (T* other) const {
|
|
||||||
return static_cast<T*>(*this) == other;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
bool PackedPointer<T, I, A>::operator!= (const PackedPointer& other) const {
|
|
||||||
return not this->operator==(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename I, std::size_t A>
|
|
||||||
bool PackedPointer<T, I, A>::operator!= (T* other) const {
|
|
||||||
return not this->operator==(other);
|
|
||||||
}
|
|
||||||
} //namepace dhandy
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,9 +1,8 @@
|
||||||
project('memcard', 'cpp', 'c', default_options:['debug=true', 'cpp_std=c++20', 'b_ndebug=if-release'])
|
project('memcard', 'cpp', 'c', default_options:['debug=true', 'cpp_std=c++17', 'b_ndebug=if-release'])
|
||||||
add_project_link_arguments(['-lstdc++fs'], language: 'cpp')
|
add_project_link_arguments(['-lstdc++fs'], language: 'cpp')
|
||||||
|
|
||||||
private_incl = include_directories('src')
|
private_incl = include_directories('src')
|
||||||
library_incl = include_directories('include')
|
library_incl = include_directories('include')
|
||||||
duckhandy_incl = include_directories('lib/duckhandy/include')
|
|
||||||
|
|
||||||
memcard = shared_library('memcard',
|
memcard = shared_library('memcard',
|
||||||
'src/memorycard.cpp',
|
'src/memorycard.cpp',
|
||||||
|
@ -17,12 +16,11 @@ memcard = shared_library('memcard',
|
||||||
'src/part_iterator.cpp',
|
'src/part_iterator.cpp',
|
||||||
'src/frame.cpp',
|
'src/frame.cpp',
|
||||||
'src/country_code.cpp',
|
'src/country_code.cpp',
|
||||||
'src/alignment.cpp',
|
|
||||||
install: true,
|
install: true,
|
||||||
include_directories: [private_incl, library_incl, duckhandy_incl],
|
include_directories: [private_incl, library_incl],
|
||||||
)
|
)
|
||||||
|
|
||||||
memcard_dep = declare_dependency(
|
memcard_dep = declare_dependency(
|
||||||
include_directories: [library_incl, duckhandy_incl],
|
include_directories: library_incl,
|
||||||
link_with: memcard
|
link_with: memcard
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
/* Copyright 2020-2025, Michele Santullo
|
|
||||||
* This file is part of memoserv.
|
|
||||||
*
|
|
||||||
* Memoserv is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Memoserv is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Memoserv. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "memcard/alignment.hpp"
|
|
||||||
#include "memcard/block.hpp"
|
|
||||||
#include "duckhandy/packed_pointer.hpp"
|
|
||||||
|
|
||||||
namespace mc::psx {
|
|
||||||
std::uint8_t* to_block_aligned (std::uint8_t* ptr, std::size_t index, std::ptrdiff_t base_offs) {
|
|
||||||
return reinterpret_cast<std::uint8_t*>(
|
|
||||||
(reinterpret_cast<std::uintptr_t>(ptr) + (Block::DataAlignment-1)) & ~(Block::DataAlignment-1)
|
|
||||||
) + base_offs + index * Block::BlockByteSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::uint8_t* to_block_aligned (const std::uint8_t* ptr, std::size_t index, std::ptrdiff_t base_offs) {
|
|
||||||
return const_cast<const std::uint8_t*>(
|
|
||||||
to_block_aligned(const_cast<std::uint8_t*>(ptr), index, base_offs)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_block_aligned (const std::uint8_t* ptr) {
|
|
||||||
return (0 == reinterpret_cast<std::uintptr_t>(ptr) % Block::DataAlignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, std::size_t A>
|
|
||||||
bool is_block_aligned (const dhandy::PackedPointer<T, std::size_t, A>& ptr) {
|
|
||||||
return (0 == static_cast<std::uintptr_t>(ptr) % Block::DataAlignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
template bool is_block_aligned<std::uint8_t, Block::DataAlignment> (
|
|
||||||
const dhandy::PackedPointer<std::uint8_t, std::size_t, Block::DataAlignment>&
|
|
||||||
);
|
|
||||||
template bool is_block_aligned<const std::uint8_t, Block::DataAlignment> (
|
|
||||||
const dhandy::PackedPointer<const std::uint8_t, std::size_t, Block::DataAlignment>&
|
|
||||||
);
|
|
||||||
|
|
||||||
std::unique_ptr<std::uint8_t[]> make_unique_for_block_aligned(std::size_t size) {
|
|
||||||
return std::make_unique<std::uint8_t[]>(size + Block::DataAlignment - 1);
|
|
||||||
}
|
|
||||||
} //namespace mc::psx
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#include "memcard/block.hpp"
|
#include "memcard/block.hpp"
|
||||||
#include "memcard/memorycard.hpp"
|
#include "memcard/memorycard.hpp"
|
||||||
#include "memcard/alignment.hpp"
|
|
||||||
#include "shiftjis_to_utf8.hpp"
|
#include "shiftjis_to_utf8.hpp"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
@ -95,12 +94,10 @@ BasicBlock<Const>::BasicBlock (data_type* blk, std::size_t index) :
|
||||||
template <bool Const>
|
template <bool Const>
|
||||||
BasicBlock<Const>::BasicBlock (data_type* blk, BasicFrame<Const> toc_entry, std::size_t index) :
|
BasicBlock<Const>::BasicBlock (data_type* blk, BasicFrame<Const> toc_entry, std::size_t index) :
|
||||||
m_toc_entry(toc_entry),
|
m_toc_entry(toc_entry),
|
||||||
|
m_index(index),
|
||||||
m_begin(blk)
|
m_begin(blk)
|
||||||
{
|
{
|
||||||
assert(m_begin);
|
assert(m_begin);
|
||||||
assert(is_block_aligned(m_begin));
|
|
||||||
assert(index <= m_begin.max_payload);
|
|
||||||
dhandy::set<0>(m_begin, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool Const>
|
template <bool Const>
|
||||||
|
|
|
@ -16,16 +16,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "memcard/frame.hpp"
|
#include "memcard/frame.hpp"
|
||||||
#include "memcard/alignment.hpp"
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
namespace mc::psx {
|
namespace mc::psx {
|
||||||
template <bool Const>
|
template <bool Const>
|
||||||
BasicFrame<Const>::BasicFrame (data_type* data, std::size_t index) :
|
BasicFrame<Const>::BasicFrame (data_type* data, std::size_t index) :
|
||||||
|
m_index(index),
|
||||||
m_data(data)
|
m_data(data)
|
||||||
{
|
{
|
||||||
assert(is_block_aligned(m_data));
|
|
||||||
dhandy::set<0>(m_data, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool Const>
|
template <bool Const>
|
||||||
|
@ -43,6 +41,7 @@ auto BasicFrame<Const>::operator[] (std::size_t index) const -> const data_type&
|
||||||
template <bool Const>
|
template <bool Const>
|
||||||
template <bool Const2>
|
template <bool Const2>
|
||||||
BasicFrame<Const>& BasicFrame<Const>::operator= (const BasicFrame<Const2>& other) {
|
BasicFrame<Const>& BasicFrame<Const>::operator= (const BasicFrame<Const2>& other) {
|
||||||
|
m_index = other.m_index;
|
||||||
m_data = other.m_data;
|
m_data = other.m_data;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include "memcard/memorycard.hpp"
|
#include "memcard/memorycard.hpp"
|
||||||
#include "memcard/block.hpp"
|
#include "memcard/block.hpp"
|
||||||
#include "memcard/frame.hpp"
|
#include "memcard/frame.hpp"
|
||||||
#include "memcard/alignment.hpp"
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
@ -40,7 +39,7 @@ namespace {
|
||||||
} //unnamed namespace
|
} //unnamed namespace
|
||||||
|
|
||||||
MemoryCard::MemoryCard() :
|
MemoryCard::MemoryCard() :
|
||||||
m_data(MemoryCardSize + Block::DataAlignment - 1)
|
m_data(MemoryCardSize)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,8 +130,4 @@ std::vector<std::size_t> block_group (const MemoryCard& mc, std::size_t index) {
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::uint8_t* MemoryCard::data_ptr() const {
|
|
||||||
return to_block_aligned(m_data.data());
|
|
||||||
}
|
|
||||||
} //namespace mc::psx
|
} //namespace mc::psx
|
||||||
|
|
Loading…
Add table
Reference in a new issue