0

It's possible to fill the appropriate registers of a virtual machine based on the argument list and some logic using a C++17 fold, like so: https://github.com/fwsGonzo/libriscv/blob/master/lib/libriscv/machine_vmcall.hpp#L35

https://github.com/fwsGonzo/libriscv/blob/master/lib/libriscv/machine_vmcall.hpp#L18

Structs will be pushed onto the stack and the address will take up an integer register slot. So, I can turn a regular function call into a call into my virtual machine. I don't think any other programming language can do that.

Now, for the other way around there are system call handlers. They look like this: https://github.com/fwsGonzo/libriscv/blob/master/emulator/src/syscalls.cpp#L20

In an effort to simplify system call handling I want to be able to take a list of argument types, perform some logic on each of them (extract the values based on type), and then optionally call a lambda with the arguments I built up.

The number and types of arguments is known beforehand. The values are not known until they are extracted from the machine registers.

Thanks to @bipll for answering. I chose to implement it like this:

template<typename... Args, std::size_t... indices>
inline auto resolve_args(machine_t& m, std::index_sequence<indices...>)
{
    std::tuple<std::decay_t<Args>...> retval;
    ((std::get<indices>(retval) = m.template sysarg<Args>(indices)), ...);
    return retval;
}
template<typename... Args>
inline auto resolve_args(machine_t& m) {
    return resolve_args<Args...>(m, std::index_sequence_for<Args...>{});
}
gonzo
  • 442
  • 4
  • 15

1 Answers1

1

Hmm, is this something you're after?

#include <iostream>
#include <type_traits>

template<class... Args> void omg(Args &&...args)
{
        ((std::is_integral_v<Args> && std::cout << args << " is integral\n"), ...);
}

int main() {
        omg(1, 42, 3.14, "Hi!", 0<<0);
}
1 is integral
42 is integral
0 is integral

operator, could be the Swiss army knife of unary foreach fold-expressions.

You don't even need actual values for that:

template<class... Args> void omg()
{
        std::size_t i{};
        ((++i,
          std::is_integral_v<Args> && std::cout <<
                  "Arg #" << i << " is integral\n"
          || std::is_scalar_v<Args> && std::cout <<
                  "Arg #" << i << " is not integral, yet is scalar\n"
          ), ...);
}

int main() {
        omg<int, int, double, char const *, std::size_t>();
}

If you don't have actual values at hand, but their types and index access, well, you can easily retrieve them through some very basic way:

template<class... Args, std::size_t... indices> void add_args(
        std::index_sequence<indices...>)
{
    (p.append(sys.get_arg<Args>(indices)), ...);
}

template<class... Args> void add_args() {
    add_args<Args...>(std::index_sequence_for<Args...>{});
}

Even storing them in a tuple is a bit tricky and not quite straightforward:

std::tuple<std::decay_t<Args>...> retval;
((std::get<indices>(retval) = sys.get_arg<Args>(indices)), ...);
return retval;
bipll
  • 11,747
  • 1
  • 18
  • 32
  • The problem is that there is no actual parameters until you have a type, so if we start with "float" then using that type we can do the "float logic" and get a value. The function would have to return values - it does not get values passed to it, only types. – gonzo Apr 07 '20 at 11:03
  • Unfortunately, the `get_arg` calls in `omg(sys.get_arg(indices)...)` are indeterminately sequenced. – aschepler Apr 07 '20 at 12:21
  • @aschepler Ok, a closer example to op's use case is accidentally better sequenced. – bipll Apr 07 '20 at 12:25
  • Your edit looks good now, it's starting to look like a solution. Is it possible to make a function call with the "resolved" arguments after the , fold? Or do I have to return a vector of std::variant? – gonzo Apr 07 '20 at 12:30
  • What about returning a std::tuple (fold, values, here) is that possible? – gonzo Apr 07 '20 at 12:35
  • Or actually, maybe sequencing doesn't matter, now that it sinks in that an index is passed. – aschepler Apr 07 '20 at 12:39
  • 1
    @gonzo I've added an explanation about tuples. – bipll Apr 07 '20 at 12:54
  • 1
    Thank you very much - it finally makes sense - and I'm yet again blown away by how much you can do in modern C++ to make some insanely clean APIs. Thanks again. – gonzo Apr 07 '20 at 13:19