ywkaras commented on PR #9482:
URL: https://github.com/apache/trafficserver/pull/9482#issuecomment-1608277276
How about this approach?
```
wkaras ~/STUFF/GET_SERVICE
$ cat x.cc
#include <cstdint>
namespace ts
{
// Returns offset from Base1 to Base2 in any instance of Derived.
//
template <class Derived, class Base1, class Base2>
std::ptrdiff_t base_to_base_offset()
{
// Don't use 0 for dummy address of derived, since compiler may treat null
address specially.
//
auto addr = reinterpret_cast<Derived *>(0x100);
return reinterpret_cast<char *>(static_cast<Base2 *>(addr)) -
reinterpret_cast<char *>(static_cast<Base1 *>(addr));
}
} // end namespace ts
enum class X_SERVICE {
Y1, Y2, Y3, NUM
};
template <class>
struct X_Service;
static std::ptrdiff_t const X_SERVICE_NONE{PTRDIFF_MIN};
class X
{
public:
template <class C>
C const * get_service() const
{
auto ofs = _service_ofs()[std::size_t(X_Service<C>::value)];
if (X_SERVICE_NONE == ofs) {
return nullptr;
} else {
return reinterpret_cast<C const *>(reinterpret_cast<char const
*>(this) + ofs);
}
}
template <class C>
C * get_service()
{
std::ptrdiff_t ofs = _service_ofs()[std::size_t(X_Service<C>::value)];
if (X_SERVICE_NONE == ofs) {
return nullptr;
} else {
return reinterpret_cast<C *>(reinterpret_cast<char *>(this) + ofs);
}
}
private:
static std::ptrdiff_t const * const _service_ofs_table;
// Returns array (A), indexed by service (S), where A[S] is the offset
from base class X to the base class for service
// S in the same object, or NO_SERVICE if there is no base class in the
object for service S.
//
virtual std::ptrdiff_t const * _service_ofs() const { return
_service_ofs_table; }
int dummy_data;
};
std::ptrdiff_t const * const X::_service_ofs_table{[]() -> std::ptrdiff_t *
{
static std::ptrdiff_t tbl[std::size_t(X_SERVICE::NUM)];
tbl[std::size_t(X_SERVICE::Y1)] = X_SERVICE_NONE;
tbl[std::size_t(X_SERVICE::Y2)] = X_SERVICE_NONE;
tbl[std::size_t(X_SERVICE::Y3)] = X_SERVICE_NONE;
return tbl;
}()};
struct Y1
{
int dummy_data;
};
template <>
struct X_Service<Y1>
{
static X_SERVICE const value{X_SERVICE::Y1};
};
struct Y2
{
int dummy_data;
};
template <>
struct X_Service<Y2>
{
static X_SERVICE const value{X_SERVICE::Y2};
};
struct Y3
{
int dummy_data;
};
template <>
struct X_Service<Y3>
{
static X_SERVICE const value{X_SERVICE::Y3};
};
class D1 : public X, public Y1, public Y3
{
public:
int dummy_data;
private:
static std::ptrdiff_t const * const _service_ofs_table;
// Returns array (A), indexed by service (S), where A[S] is the offset
from base class X to the base class for service
// S in the same object, or NO_SERVICE if there is no base class in the
object for service S.
//
std::ptrdiff_t const * _service_ofs() const override { return
_service_ofs_table; }
};
std::ptrdiff_t const * const D1::_service_ofs_table{[]() -> std::ptrdiff_t *
{
static std::ptrdiff_t tbl[std::size_t(X_SERVICE::NUM)];
tbl[std::size_t(X_SERVICE::Y1)] = ts::base_to_base_offset<D1, X, Y1>();
tbl[std::size_t(X_SERVICE::Y2)] = X_SERVICE_NONE;
tbl[std::size_t(X_SERVICE::Y3)] = ts::base_to_base_offset<D1, X, Y3>();
return tbl;
}()};
#include <cassert>
int main()
{
D1 d1;
X *xp = &d1;
assert(xp->get_service<Y1>() == static_cast<Y1 *>(&d1));
assert(xp->get_service<Y2>() == nullptr);
assert(xp->get_service<Y3>() == static_cast<Y3 *>(&d1));
return 0;
}
wkaras ~/STUFF/GET_SERVICE
$ gcc -Wall -Wextra -pedantic -std=c++17 x.cc -lstdc++
wkaras ~/STUFF/GET_SERVICE
$ ./a.out
wkaras ~/STUFF/GET_SERVICE
$
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]