Created
November 12, 2025 23:38
-
-
Save X547/2d0bf5aaa944137c300457113767374c to your computer and use it in GitHub Desktop.
C++ traits with stable ABI
This file contains hidden or 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
| #pragma once | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| template <class T, class M> | |
| static inline constexpr ptrdiff_t OffsetOf(const M T::*member) | |
| { | |
| return reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<T*>(0)->*member)); | |
| } | |
| template <class T, class M> | |
| static inline constexpr T& ContainerOf(M &ptr, const M T::*member) | |
| { | |
| return *reinterpret_cast<T*>(reinterpret_cast<intptr_t>(&ptr) - OffsetOf(member)); | |
| } | |
| template <class T, class M> | |
| static inline constexpr T& ContainerOf(const M &ptr, const M T::*member) | |
| { | |
| return *reinterpret_cast<T*>(reinterpret_cast<intptr_t>(&ptr) - OffsetOf(member)); | |
| } |
This file contains hidden or 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
| #pragma once | |
| #include <drivers/Drivers.h> | |
| #include "ContainerOf.h" | |
| #include "DeviceRoster.h" | |
| class DevfsNodeHandle; | |
| class DevfsNode { | |
| public: | |
| const device_hooks* fCls; | |
| public: | |
| DevfsNode(const device_hooks* cls = nullptr): fCls(cls) {} | |
| status_t Open(const char *path, uint32 flags, DevfsNodeHandle& handle); | |
| }; | |
| class DevfsNodeHandle { | |
| public: | |
| const device_hooks* fCls; | |
| void* fInst; | |
| public: | |
| DevfsNodeHandle(const device_hooks* cls = nullptr, void* inst = nullptr): fCls(cls), fInst(inst) {} | |
| status_t Close(); | |
| status_t Free(); | |
| struct Read { | |
| operator bool(); | |
| status_t operator()(off_t pos, void *buffer, size_t *_length); | |
| } Read; | |
| struct Write { | |
| operator bool(); | |
| status_t operator()(off_t pos, const void *buffer, size_t *_length); | |
| } Write; | |
| struct Control { | |
| operator bool(); | |
| status_t operator()(uint32 op, void *buffer, size_t length); | |
| } Control; | |
| struct Select { | |
| operator bool(); | |
| status_t operator()(uint8 event, uint32 ref, selectsync *sync); | |
| } Select; | |
| struct Deselect { | |
| operator bool(); | |
| status_t operator()(uint8 event, selectsync *sync); | |
| } Deselect; | |
| }; | |
| // #pragma mark - | |
| template <typename DevfsNodeImpl, typename DevfsNodeHandleImpl> | |
| constexpr device_hooks_ex GetDevfsNodeClass() | |
| { | |
| device_hooks_ex cls {}; | |
| cls.open = [](const char *name, uint32 flags, void **cookie) { | |
| int32 idx = FindDevfsNode(name); | |
| if (idx < 0) | |
| return ENOENT; | |
| DevfsNodeHandle handle; | |
| status_t res = static_cast<DevfsNodeImpl*>(gDevfsNodeInsts[idx])->Open(flags, handle); | |
| *cookie = handle.fInst; | |
| return res; | |
| }; | |
| cls.close = [](void *cookie) { | |
| return static_cast<DevfsNodeHandleImpl*>(cookie)->Close(); | |
| }; | |
| cls.free = [](void *cookie) { | |
| delete static_cast<DevfsNodeHandleImpl*>(cookie); | |
| return B_OK; | |
| }; | |
| if constexpr (requires(DevfsNodeHandleImpl h, off_t pos, void *buffer, size_t *_length) { | |
| h.Read(pos, buffer, _length); | |
| }) { | |
| cls.read = [](void *cookie, off_t pos, void *buffer, size_t *_length) { | |
| return static_cast<DevfsNodeHandleImpl*>(cookie)->Read(pos, buffer, _length); | |
| }; | |
| } | |
| if constexpr (requires(DevfsNodeHandleImpl h, off_t pos, const void *buffer, size_t *_length) { | |
| h.Write(pos, buffer, _length); | |
| }) { | |
| cls.write = [](void *cookie, off_t pos, const void *buffer, size_t *_length) { | |
| return static_cast<DevfsNodeHandleImpl*>(cookie)->Write(pos, buffer, _length); | |
| }; | |
| } | |
| if constexpr (requires(DevfsNodeHandleImpl h, uint32 op, void *buffer, size_t length) { | |
| h.Control(op, buffer, length); | |
| }) { | |
| cls.control = [](void *cookie, uint32 op, void *buffer, size_t length) { | |
| return static_cast<DevfsNodeHandleImpl*>(cookie)->Control(op, buffer, length); | |
| }; | |
| } | |
| if constexpr (requires(DevfsNodeHandleImpl h, uint8 event, uint32 ref, selectsync *sync) { | |
| h.Select(event, ref, sync); | |
| }) { | |
| cls.select = [](void *cookie, uint8 event, uint32 ref, selectsync *sync) { | |
| return static_cast<DevfsNodeHandleImpl*>(cookie)->Select(event, ref, sync); | |
| }; | |
| } | |
| if constexpr (requires(DevfsNodeHandleImpl h, uint8 event, selectsync *sync) { | |
| h.Deselect(event, sync); | |
| }) { | |
| cls.deselect = [](void *cookie, uint8 event, selectsync *sync) { | |
| return static_cast<DevfsNodeHandleImpl*>(cookie)->Deselect(event, sync); | |
| }; | |
| } | |
| cls.free_device = [](void *cookie) { | |
| delete static_cast<DevfsNodeImpl*>(cookie); | |
| }; | |
| return cls; | |
| } | |
| // #pragma mark - DevfsNode | |
| inline status_t DevfsNode::Open(const char *path, uint32 flags, DevfsNodeHandle& handle) | |
| { | |
| handle.fCls = fCls; | |
| return fCls->open(path, flags, &handle.fInst); | |
| } | |
| // #pragma mark - DevfsNodeHandle | |
| inline status_t DevfsNodeHandle::Close() | |
| { | |
| return fCls->close(fInst); | |
| } | |
| inline status_t DevfsNodeHandle::Free() | |
| { | |
| status_t res = fCls->free(fInst); | |
| fInst = nullptr; | |
| return res; | |
| } | |
| inline DevfsNodeHandle::Read::operator bool() | |
| { | |
| DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Read); | |
| return base.fCls->read != nullptr; | |
| } | |
| inline status_t DevfsNodeHandle::Read::operator()(off_t pos, void *buffer, size_t *_length) | |
| { | |
| DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Read); | |
| return base.fCls->read(base.fInst, pos, buffer, _length); | |
| } | |
| inline DevfsNodeHandle::Write::operator bool() | |
| { | |
| DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Write); | |
| return base.fCls->write != nullptr; | |
| } | |
| inline status_t DevfsNodeHandle::Write::operator()(off_t pos, const void *buffer, size_t *_length) | |
| { | |
| DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Write); | |
| return base.fCls->write(base.fInst, pos, buffer, _length); | |
| } | |
| inline DevfsNodeHandle::Control::operator bool() | |
| { | |
| DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Control); | |
| return base.fCls->control != nullptr; | |
| } | |
| inline status_t DevfsNodeHandle::Control::operator()(uint32 op, void *buffer, size_t length) | |
| { | |
| DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Control); | |
| return base.fCls->control(base.fInst, op, buffer, length); | |
| } | |
| inline DevfsNodeHandle::Select::operator bool() | |
| { | |
| DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Select); | |
| return base.fCls->select != nullptr; | |
| } | |
| inline status_t DevfsNodeHandle::Select::operator()(uint8 event, uint32 ref, selectsync *sync) | |
| { | |
| DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Select); | |
| return base.fCls->select(base.fInst, event, ref, sync); | |
| } | |
| inline DevfsNodeHandle::Deselect::operator bool() | |
| { | |
| DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Deselect); | |
| return base.fCls->deselect != nullptr; | |
| } | |
| inline status_t DevfsNodeHandle::Deselect::operator()(uint8 event, selectsync *sync) | |
| { | |
| DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Deselect); | |
| return base.fCls->deselect(base.fInst, event, sync); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment