I'm working on a program (an emulator) where I need to access the memory map of the emulated machine. It's done using a templated function (read).
This function returns data size depending on the templated parameter (ie read< uint8_t >(0x10) will return 8 bits of data from memory address 0x10, read< uint32_t >(0x20) will return 32 bits of data from memory address 0x20), etc.
This is done using 3 arrays of pointers to functions (read_8_handler_, read_16_handler_, read_32_handler_), linking each address to a particular function.
Initialization of these arrays is done calling initializeHandlers 3 times for each linked function :
// default handlers
initializeHandler<uint8_t>(0x00, 0xFF, readDummy<uint8_t>);
initializeHandler<uint16_t>(0x00, 0xFF, readDummy<uint16_t>);
initializeHandler<uint32_t>(0x00, 0xFF, readDummy<uint32_t>);
// rom handlers
initializeHandler<uint8_t>(0x60, 0x6F, readRom<uint8_t>);
initializeHandler<uint16_t>(0x60, 0x6F, readRom<uint16_t>);
initializeHandler<uint32_t>(0x60, 0x6F, readRom<uint32_t>);
This leads to a lot of redundancy, as each handler has to use 3 lines for initialization.
So my question is : can I use a one liner to initialize one handler, without providing the template arguments, like this :
initializeHandler(0x00, 0xFF, readDummy);
initializeHandler(0x60, 0x6F, readRom);
? I think it can be done using template template parameters, but I'm not fluent enough in templates to find out how to do it ...
Here's the complete example, which can be tested here
#include <iostream>
#include <cstdlib>
#include <array>
#include <tuple>
template <typename R, typename ...ARGS> using function = R(*)(ARGS...);
template<typename T> using ReadType = function<T, const uint32_t>;
template<class ReadType> using ReadHandlerType = std::array<ReadType, 0x100>;
template<typename T> using ReadHandler = ReadHandlerType<ReadType<T>>;
ReadHandler<uint8_t> read_8_handler_;
ReadHandler<uint16_t> read_16_handler_;
ReadHandler<uint32_t> read_32_handler_;
template<typename T>
T readDummy( const uint32_t addr) {
return sizeof(T{});
}
template<typename T>
T readRom( const uint32_t addr) {
return sizeof(T{})*2;
}
template<typename T>
void initializeHandler(uint32_t begin,
uint32_t end,
ReadType<T> func) {
auto t = std::tie(read_8_handler_, read_16_handler_, read_32_handler_);
for (uint32_t current = begin; current <= end; ++current) {
auto& handler = std::get < ReadHandler<T>& >(t);
handler[current & 0xFF] = func;
}
}
template<typename T>
T read(const uint32_t addr) {
auto& handler = std::get < ReadHandler<T>& >(std::tie(read_8_handler_, read_16_handler_, read_32_handler_));
return handler[addr](addr);
}
int main()
{
initializeHandler<uint8_t>(0x00, 0xFF, readDummy<uint8_t>);
initializeHandler<uint16_t>(0x00, 0xFF, readDummy<uint16_t>);
initializeHandler<uint32_t>(0x00, 0xFF, readDummy<uint32_t>);
initializeHandler<uint8_t>(0x60, 0x6F, readRom<uint8_t>);
initializeHandler<uint16_t>(0x60, 0x6F, readRom<uint16_t>);
initializeHandler<uint32_t>(0x60, 0x6F, readRom<uint32_t>);
std::cout << read<uint16_t>( 0x20) << std::endl;
std::cout << read<uint16_t>( 0x60) << std::endl;
}
Aucun commentaire:
Enregistrer un commentaire