ywkaras commented on PR #9482:
URL: https://github.com/apache/trafficserver/pull/9482#issuecomment-1619143006
OK, here's composition, and the option of multiple services with the same
type. For a total of three shrubberies.
```
#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));
}
// Returns offset from Base1 to data member of Derived.
//
template <class Derived, class Base1, typename MbrT, MbrT Derived::*Mbr>
std::ptrdiff_t base_to_mbr_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 *>(&(addr->*Mbr)) - reinterpret_cast<char
*>(static_cast<Base1 *>(addr));
}
} // end namespace ts
enum class X_SERVICE {
Y1, Y2, Y3_0, Y3_1, Y4, NUM
};
template <class, int>
struct X_Service;
static std::ptrdiff_t const X_SERVICE_NONE{PTRDIFF_MIN};
class X
{
public:
X(std::ptrdiff_t const *service_ofs) : _service_ofs(service_ofs) {}
template <class C, int Selector = 0>
C const * get_service() const
{
auto ofs = _service_ofs[std::size_t(X_Service<C, Selector>::value)];
if (X_SERVICE_NONE == ofs) {
return nullptr;
} else {
return reinterpret_cast<C const *>(reinterpret_cast<char const
*>(this) + ofs);
}
}
template <class C, int Selector = 0>
C * get_service()
{
std::ptrdiff_t ofs = _service_ofs[std::size_t(X_Service<C,
Selector>::value)];
if (X_SERVICE_NONE == ofs) {
return nullptr;
} else {
return reinterpret_cast<C *>(reinterpret_cast<char *>(this) + ofs);
}
}
private:
// Indexed by service (S), where _service_ofs[S] is the offset from base
class X to the base class or data member for
// service S in the same object, or NO_SERVICE if there is no such
base/member in the object for service S.
//
std::ptrdiff_t const * const _service_ofs;
int dummy_data;
};
struct Y1
{
int dummy_data;
};
template <>
struct X_Service<Y1, 0>
{
static X_SERVICE const value{X_SERVICE::Y1};
};
struct Y2
{
int dummy_data;
};
template <>
struct X_Service<Y2, 0>
{
static X_SERVICE const value{X_SERVICE::Y2};
};
struct Y3
{
int dummy_data;
};
template <>
struct X_Service<Y3, 0>
{
static X_SERVICE const value{X_SERVICE::Y3_0};
};
template <>
struct X_Service<Y3, 1>
{
static X_SERVICE const value{X_SERVICE::Y3_1};
};
struct Y4
{
int dummy_data;
};
template <>
struct X_Service<Y4, 0>
{
static X_SERVICE const value{X_SERVICE::Y4};
};
class D1 : public X, public Y1, public Y3
{
public:
D1() : X(_service_ofs_table) {}
Y3 my3;
Y4 my4;
private:
static std::ptrdiff_t const * const _service_ofs_table;
int dummy_data;
};
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_0)] = ts::base_to_base_offset<D1, X, Y3>();
tbl[std::size_t(X_SERVICE::Y3_1)] = ts::base_to_mbr_offset<D1, X, Y3,
&D1::my3>();
tbl[std::size_t(X_SERVICE::Y4)] = ts::base_to_mbr_offset<D1, X, Y4,
&D1::my4>();
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, 0>()) == static_cast<Y3 *>(&d1));
assert((xp->get_service<Y3, 1>()) == &d1.my3);
assert(xp->get_service<Y4>() == &d1.my4);
return 0;
}
```
--
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]