Skip to content

Instantly share code, notes, and snippets.

@schaumb
Created August 3, 2022 18:49
Show Gist options
  • Save schaumb/770fb0fa018e1e6e031a011467769748 to your computer and use it in GitHub Desktop.
Save schaumb/770fb0fa018e1e6e031a011467769748 to your computer and use it in GitHub Desktop.
C++ interface dynamic implementation
#include <iostream>
#include <stdexcept>
template<typename T>
struct Mock {
void** mfptr = funptrs + 5;
void* funptrs[15] = {{}, {}, {}, {}, {}};
static void throw_exc(void) {
throw std::runtime_error("Pure virtual function called");
}
Mock() noexcept {
for (auto p = mfptr; p != funptrs + sizeof(funptrs) / sizeof(funptrs[0]); ++p)
*p = reinterpret_cast<void*>(&Mock::throw_exc);
}
template<typename U>
static unsigned int offset(U V) {
struct A {
virtual unsigned int _0(int) { return 0; }
virtual unsigned int _1(int) { return 1; }
virtual unsigned int _2(int) { return 2; }
virtual unsigned int _3(int) { return 3; }
virtual unsigned int _4(int) { return 4; }
virtual unsigned int _5(int) { return 5; }
virtual unsigned int _6(int) { return 6; }
virtual unsigned int _7(int) { return 7; }
virtual unsigned int _8(int) { return 8; }
virtual unsigned int _9(int) { return 9; }
};
union {
U v0;
unsigned int (A:: *v1)(int);
} volatile offs{V};
return (A{}.*offs.v1)(0);
}
template<typename U>
struct MFunToFun;
template<typename Res, typename ...Args>
struct MFunToFun<Res (T::* )(Args...) const> {
using fun_ptr = Res (*)(const T*, Args...);
};
template<typename Res, typename ...Args>
struct MFunToFun<Res (T::*)(Args...)> {
using fun_ptr = Res (*)(T*, Args...);
};
template<auto N>
Mock& set(typename MFunToFun<decltype(N)>::fun_ptr v) {
mfptr[offset(N)] = reinterpret_cast<void*>(v);
return *this;
}
template<typename MP>
Mock& set(MP val, typename MFunToFun<MP>::fun_ptr v) {
mfptr[offset(val)] = reinterpret_cast<void*>(v);
return *this;
}
T* operator ->() {
return std::launder(reinterpret_cast<T*>(this));
}
operator T*() {
return operator->();
}
operator T&() {
return *operator->();
}
};
struct IF {
virtual void first() = 0;
virtual int mult(int) const = 0;
virtual void asd() = 0;
virtual void asdsada() = 0;
virtual int getter() const = 0;
virtual ~IF() = default;
};
int main() {
Mock<IF> m;
m.set(&IF::getter, [](const IF*) { return 42; });
m.set<&IF::asd>([](IF* i) {
std::cout << "Here: asd " << i->getter() << " \n";
});
m.set<&IF::mult>([](const IF*, int p) {
std::cout << "Here: mult " << p << " \n"; return p*2;
});
m->asd(); // use as pointer
IF& inf = m; // or as reference
std::cout << inf.mult(9) << std::endl;
try {
inf.first();
} catch (const std::exception& ex) {
std::cout << "Exception catched: " << ex.what() << " \n";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment