A 'lazy' compilation mode to make writting multiplatform code easier without having to clutter the project

ryuukk_ ryuukk.dev at gmail.com
Wed Feb 22 14:54:01 UTC 2023


On Wednesday, 22 February 2023 at 14:51:41 UTC, ryuukk_ wrote:

here my actual module:

```D
module rt.event;

version(Windows)
{
     enum OK = true;
     import core.sys.windows.winsock2;
     import core.stdc.errno;
     import core.stdc.string;

     alias WSAPOLLFD = pollfd;
     alias PWSAPOLLFD = pollfd*;
     alias LPWSAPOLLFD = pollfd*;
     struct pollfd
     {
         SOCKET fd;
         short events;
         short revents;
     }

     alias poll = WSAPoll;
     extern(Windows) nothrow @nogc int WSAPoll(LPWSAPOLLFD 
fdArray, ulong fds, int timeout);

     enum short POLLRDNORM = 0x0100;
     enum short POLLRDBAND = 0x0200;
     enum short POLLIN = (POLLRDNORM | POLLRDBAND);
     enum short POLLPRI = 0x0400;

     enum short POLLWRNORM = 0x0010;
     enum short POLLOUT = (POLLWRNORM);
     enum short POLLWRBAND = 0x0020;

     enum short POLLERR = 0x0001;
     enum short POLLHUP = 0x0002;
     enum short POLLNVAL = 0x0004;

     alias socket_t = size_t;
}

version(Posix)
{
     enum OK = true;
     import core.stdc.string;
     import core.sys.posix.poll;
     import core.stdc.errno;
     alias socket_t = int;
     enum INVALID_SOCKET = -1;
}

version(Linux)
{
     import core.sys.linux.epoll;

     struct EPollSelector(int MAX)
     {
         epoll_event[MAX] fds;
         size_t _count;
	    int epollFD_;
	    int fdsCount_ = 0;

         void create()
         {
             epollFD_ = epoll_create(1);
         }

         Selector selector()
         {
             return Selector.create_it!(EPollSelector)(&this);
         }

         bool insert_fd(socket_t fd, FDEvent ev = FDEvent.READ)
         {
             auto c = _count;
             auto len = fds.length;
             if (c >= len)
                 return false;

             epoll_event it;
             it.data.fd = fd;

             if (ev == FDEvent.READ)
                 it.events = EPOLLIN;
             else if (ev == FDEvent.WRITE)
                 it.events = EPOLLOUT;

             int result = epoll_ctl(epollFD_, EPOLL_CTL_ADD, fd, 
&it);

             // fds[_count++] = it;

             return result;
         }

         bool update_fd(socket_t fd, FDEvent ev)
         {
             epoll_event it;
             it.data.fd = fd;

             if (ev == FDEvent.READ)
                 it.events = EPOLLIN;
             else if (ev == FDEvent.WRITE)
                 it.events = EPOLLOUT;

             int result = epoll_ctl(epollFD_, EPOLL_CTL_MOD, fd, 
&it);
             return result == 0;
         }

         bool remove_fd(socket_t fd)
         {
             int result = epoll_ctl(epollFD_, EPOLL_CTL_DEL, fd, 
null);
             return result == 0;
         }

         WaitStatus wait(int timeout)
         {
             fdsCount_ = epoll_wait(epollFD_, fds.ptr, _count, 
timeout);
             if (fdsCount_ < 0)
             {
                 switch (errno)
                 {
                 case EINTR:
                     return WaitStatus.NONE;
                 default:
                     return WaitStatus.ERROR;
                 }
             }

             if (fdsCount_ == 0)
                 return WaitStatus.NONE;
             else
                 return WaitStatus.OK;
         }

         FDResult get_status(epoll_event* ev)
         {
             auto fd = ev.data.fd;
             // import rt.dbg;
             // LINFO("r: {} {} {}", _count, p.events, p.revents);

		    if (ev.events & EPOLLERR)
                 return FDResult(fd, FDStatus.ERROR);

		    if ((ev.events & EPOLLIN) || (ev.events & EPOLLHUP))
                 return FDResult(fd, FDStatus.READ);

		    if (ev.events & EPOLLOUT)
                 return FDResult(fd, FDStatus.WRITE);

             return FDResult(fd, FDStatus.NONE);
         }

         int opApply(scope int delegate(FDResult) dg)
         {
             int result;
             for (int i = 0; i < _count; i++)
             {
                 auto ptr = &fds[i];
                 auto res = get_status(ptr);
                 if ((result = dg(res)) != 0)
                     break;
             }
             return result;
         }
     }

}


static if (OK)
{
     struct PollSelector(int MAX)
     {
         pollfd[MAX] fds;
         size_t _count;

         void create()
         {
             _count = 0;
             foreach(ref it; fds)
             {
                 it.fd = INVALID_SOCKET;
                 it.events = 0;
                 it.revents = 0;
             }
         }

         Selector selector()
         {
             return Selector.create_it!(PollSelector)(&this);
         }

         bool insert_fd(socket_t fd, FDEvent ev = FDEvent.READ)
         {
             auto c = _count;
             auto len = fds.length;
             if (c >= len)
                 return false;

             pollfd it;
             it.fd = fd;
             if (ev == FDEvent.READ)
                 it.events = POLLIN;
             else if (ev == FDEvent.WRITE)
                 it.events = POLLOUT;
             it.revents = 0;
             fds[_count++] = it;

             return true;
         }

         bool update_fd(socket_t fd, FDEvent ev)
         {
             foreach(ref it; fds)
             {
                 if (it.fd == fd)
                 {
                     if (ev == FDEvent.READ)
                         it.events = POLLIN;
                     else if (ev == FDEvent.WRITE)
                         it.events = POLLOUT;
                     it.revents = 0;
                     return true;
                 }
             }
             return false;
         }

         bool remove_fd(socket_t fd)
         {
             int index = -1;
             foreach(i, ref it; fds)
             {
                 if (it.fd == fd)
                 {
                     index = cast(int) i;
                     it.fd = INVALID_SOCKET;
                     it.events = 0;
                     it.revents = 0;
                     break;
                 }
             }

             if (index >= 0)
             {
                 memmove(fds.ptr + index, // dest
                         fds.ptr + index + 1, // src
                         (_count - index) * pollfd.sizeof); // num 
bytes
             }

             return index >= 0;
         }

         WaitStatus wait(int timeout)
         {
             int activity = poll(fds.ptr, _count, timeout);
             if (activity < 0)
             {
                 switch (last_error())
                 {
                 case EAGAIN:
                 case EINTR:
                     return WaitStatus.OK;
                 default:
                     return WaitStatus.ERROR;
                 }
             }

             if (activity == 0)
                 return WaitStatus.NONE;
             else
                 return WaitStatus.OK;
         }

         FDResult get_status(pollfd* p)
         {
             auto fd = p.fd;

             import  rt.dbg;

             // LINFO("r: {} {} {}", _count, p.events, p.revents);

             if (fd >= 0)
             {
                 if (p.revents & POLLERR)
                     return FDResult(fd, FDStatus.ERROR);

                 if (p.revents & POLLIN)
                     return FDResult(fd, FDStatus.READ);

                 if (p.revents & POLLOUT)
                     return FDResult(fd, FDStatus.WRITE);
             }

             return FDResult(fd, FDStatus.NONE);
         }

         int opApply(scope int delegate(FDResult) dg)
         {
             int result;
             for (int i = 0; i < _count; i++)
             {
                 auto ptr = &fds[i];
                 auto res = get_status(ptr);
                 if ((result = dg(res)) != 0)
                     break;
             }
             return result;
         }
     }

     struct Selector
     {
         struct VTable
         {
             bool function(const void* self, socket_t fd, FDEvent 
ev) insert_fd;
             bool function(const void* self, socket_t fd, FDEvent 
ev) update_fd;
             bool function(const void* self, socket_t fd) 
remove_fd;
             WaitStatus function(const void* self, int timeout) 
wait;
             FDResult function(const void* self, pollfd* p) 
get_status;
         }
         void* ptr;
         VTable* vt;
         static Selector create_it(T)(void* pointer)
         {
             static struct gen(T)
             {
                 __gshared static VTable vtable = {
                     insert_fd: &insert_fd_impl,
                     update_fd: &update_fd_impl,
                     remove_fd: &remove_fd_impl,
                     wait: &wait_impl,
                     get_status: &get_status_impl,
                 };

                 static bool insert_fd_impl(const void* ptr, 
socket_t fd, FDEvent ev)
                 {
                     auto self = cast(T*) ptr;
                     return self.insert_fd(fd, ev);
                 }
                 static bool update_fd_impl(const void* ptr, 
socket_t fd, FDEvent ev)
                 {
                     auto self = cast(T*) ptr;
                     return self.update_fd(fd, ev);
                 }
                 static bool remove_fd_impl(const void* ptr, 
socket_t fd)
                 {
                     auto self = cast(T*) ptr;
                     return self.remove_fd(fd);
                 }
                 static WaitStatus wait_impl(const void* ptr, int 
timeout)
                 {
                     auto self = cast(T*) ptr;
                     return self.wait(timeout);
                 }

                 static FDResult get_status_impl(const void* ptr, 
pollfd* p)
                 {
                     auto self = cast(T*) ptr;
                     return self.get_status(p);
                 }

             }
             assert(pointer);
             return Selector(pointer, &gen!(T).vtable);
         }
     }

     enum WaitStatus
     {
         OK,
         NONE,
         ERROR
     }

     enum FDEvent : bool
     {
         READ,
         WRITE
     }

     enum FDStatus : ubyte
     {
         NONE,
         READ,
         WRITE,
         ERROR,
         STOP
     }

     struct FDResult
     {
         socket_t fd = INVALID_SOCKET;
         FDStatus status;
     }


     package:

     int last_error()
     {
         version (Windows)
             return WSAGetLastError();
         else version (Posix)
             return errno;
         else
             static assert(0);
     }
}
```


More information about the Digitalmars-d mailing list