Skip to content

Instantly share code, notes, and snippets.

@AmatanHead
Last active April 28, 2018 08:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AmatanHead/77b608921ef77dec8dea1fac532ce0e0 to your computer and use it in GitHub Desktop.
Save AmatanHead/77b608921ef77dec8dea1fac532ce0e0 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <type_traits>
#include <cassert>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class StreamImplBase {
public:
virtual void* input_raw() = 0;
};
template <typename T>
class StreamImpl: public StreamImplBase {
public:
void* input_raw() final { return input(); }
virtual T* input() = 0;
};
template <typename T>
class Stream {
public:
std::shared_ptr<StreamImplBase> impl = nullptr;
ptrdiff_t offset = 0;
template <typename U>
static ptrdiff_t make_offset() {
ptrdiff_t fake_address = sizeof(U) + sizeof(T) + sizeof(U) + sizeof(T);
U* derived_ptr_1 = reinterpret_cast<U*>(fake_address);
T* base_ptr_1 = static_cast<T*>(derived_ptr_1);
ptrdiff_t offset_1 = reinterpret_cast<ptrdiff_t>(base_ptr_1) - reinterpret_cast<ptrdiff_t>(derived_ptr_1);
T* base_ptr_2 = reinterpret_cast<T*>(fake_address);
U* derived_ptr_2 = static_cast<U*>(base_ptr_2);
ptrdiff_t offset_2 = reinterpret_cast<ptrdiff_t>(base_ptr_2) - reinterpret_cast<ptrdiff_t>(derived_ptr_2);
assert(offset_1 == offset_2);
return offset_1;
}
public:
Stream(std::shared_ptr<StreamImplBase> impl): impl(impl) {}
template <typename U/*, typename = std::enable_if_t<std::is_convertible<U*, T*>::value>*/>
Stream(Stream<U> u): impl(u.impl), offset(u.offset + make_offset<U>()) {};
T* input() {
std::cout << "Running cast to '" << typeid(T).name() << "', offset is " << offset << std::endl;
ptrdiff_t ptr = reinterpret_cast<ptrdiff_t>(impl->input_raw()) + offset;
return reinterpret_cast<T*>(ptr);
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct A {
int a = 0xa;
};
struct B {
int b = 0xb;
};
struct C: public A, public B {
int c = 0xc;
};
struct D: public C {
int d = 0xd;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class MyImpl: public StreamImpl<D> {
public:
D* input() override {
return new D();
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main() {
std::cout << std::hex << std::showbase;
Stream<D> stream{std::make_shared<MyImpl>()};
{
D* x = stream.input();
std::cout << x->a << " " << x->b << " " << x->c << " " << x->d << std::endl;
}
{
C* x = (Stream<C>(stream)).input();
std::cout << x->a << " " << x->b << " " << x->c << std::endl;
}
{
B* x = (Stream<B>(stream)).input();
std::cout << x->b << std::endl;
}
{
A* x = (Stream<A>(stream)).input();
std::cout << x->a << std::endl;
}
{
D* x = Stream<D>(Stream<C>(stream)).input();
std::cout << x->a << " " << x->b << " " << x->c << " " << x->d << std::endl;
}
{
D* x = Stream<D>(Stream<B>(stream)).input();
std::cout << x->a << " " << x->b << " " << x->c << " " << x->d << std::endl;
}
{
D* x = Stream<D>(Stream<A>(stream)).input();
std::cout << x->a << " " << x->b << " " << x->c << " " << x->d << std::endl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment