Last active
April 28, 2018 08:37
-
-
Save AmatanHead/77b608921ef77dec8dea1fac532ce0e0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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