]> git.llucax.com Git - software/libev.git/blob - ev++.h
f62aac47b680d9053e187e49fb678189d147baa7
[software/libev.git] / ev++.h
1 /*
2  * libev simple C++ wrapper classes
3  *
4  * Copyright (c) 2007 Marc Alexander Lehmann <libev@schmorp.de>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without modifica-
8  * tion, are permitted provided that the following conditions are met:
9  * 
10  *   1.  Redistributions of source code must retain the above copyright notice,
11  *       this list of conditions and the following disclaimer.
12  * 
13  *   2.  Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in the
15  *       documentation and/or other materials provided with the distribution.
16  * 
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19  * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
20  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
21  * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
25  * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26  * OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * Alternatively, the contents of this file may be used under the terms of
29  * the GNU General Public License ("GPL") version 2 or any later version,
30  * in which case the provisions of the GPL are applicable instead of
31  * the above. If you wish to allow the use of your version of this file
32  * only under the terms of the GPL and not to allow others to use your
33  * version of this file under the BSD license, indicate your decision
34  * by deleting the provisions above and replace them with the notice
35  * and other provisions required by the GPL. If you do not delete the
36  * provisions above, a recipient may use your version of this file under
37  * either the BSD or the GPL.
38  */
39
40 #ifndef EVPP_H__
41 #define EVPP_H__
42
43 #ifdef EV_H
44 # include EV_H
45 #else
46 # include "ev.h"
47 #endif
48
49 #ifndef EV_CXX_EXCEPTIONS
50 #define EV_CXX_EXCEPTIONS 1
51 #endif
52
53 #undef EV_THROW
54 #if EV_CXX_EXCEPTIONS
55 #  include <stdexcept>
56 #  define EV_THROW(exception) throw (exception)
57 #else
58 #  define EV_THROW(exception)
59 #endif
60
61 namespace ev {
62
63   typedef ev_tstamp tstamp;
64
65   enum {
66     UNDEF    = EV_UNDEF,
67     NONE     = EV_NONE,
68     READ     = EV_READ,
69     WRITE    = EV_WRITE,
70     TIMEOUT  = EV_TIMEOUT,
71     PERIODIC = EV_PERIODIC,
72     SIGNAL   = EV_SIGNAL,
73     CHILD    = EV_CHILD,
74     STAT     = EV_STAT,
75     IDLE     = EV_IDLE,
76     CHECK    = EV_CHECK,
77     PREPARE  = EV_PREPARE,
78     FORK     = EV_FORK,
79     EMBED    = EV_EMBED,
80     ERROR    = EV_ERROR,
81   };
82
83   enum
84   {
85     AUTO = EVFLAG_AUTO,
86     NOENV = EVFLAG_NOENV,
87     FORKCHECK = EVFLAG_FORKCHECK,
88     SELECT = EVBACKEND_SELECT,
89     POLL = EVBACKEND_POLL,
90     EPOLL = EVBACKEND_EPOLL,
91     KQUEUE = EVBACKEND_KQUEUE,
92     DEVPOLL = EVBACKEND_DEVPOLL,
93     PORT = EVBACKEND_PORT
94   };
95
96   enum
97   {
98     NONBLOCK = EVLOOP_NONBLOCK,
99     ONESHOT = EVLOOP_ONESHOT
100   };
101
102   enum how_t
103   {
104     ONE = EVUNLOOP_ONE,
105     ALL = EVUNLOOP_ALL
106   };
107
108 #if EV_CXX_EXCEPTIONS
109   struct bad_loop: std::runtime_error
110   {
111     bad_loop()
112       : std::runtime_error("loop can't be initialized") {}
113   };
114 #endif
115
116 #ifdef EV_AX
117 #  undef EV_AX
118 #endif
119
120 #ifdef EV_AX_
121 #  undef EV_AX_
122 #endif
123
124 #if EV_MULTIPLICITY
125 #  define EV_AX  raw_loop
126 #  define EV_AX_ raw_loop,
127 #else
128 #  define EV_AX
129 #  define EV_AX_
130 #endif
131
132   struct loop_ref
133   {
134
135     loop_ref (EV_P)
136 #if EV_MULTIPLICITY
137       EV_THROW (bad_loop) : EV_AX (EV_A)
138 #endif
139     {
140 #if EV_MULTIPLICIY && EV_CXX_EXCEPTIONS
141       if (!EV_A)
142         throw bad_loop ();
143 #endif
144     }
145
146     bool operator== (const loop_ref &other) const EV_THROW ()
147     {
148 #if EV_MULTIPLICITY
149       return this->EV_AX == other.EV_AX;
150 #else
151       return true;
152 #endif
153     }
154
155     bool operator!= (const loop_ref &other) const EV_THROW ()
156     {
157 #if EV_MULTIPLICITY
158       return ! (*this == other);
159 #else
160       return false;
161 #endif
162     }
163
164 #if EV_MULTIPLICITY
165     bool operator== (struct ev_loop *other) const EV_THROW ()
166     {
167       return this->EV_AX == other;
168     }
169
170     bool operator!= (struct ev_loop *other) const EV_THROW ()
171     {
172       return ! (*this == other);
173     }
174
175     bool operator== (const struct ev_loop *other) const EV_THROW ()
176     {
177       return this->EV_AX == other;
178     }
179
180     bool operator!= (const struct ev_loop *other) const EV_THROW ()
181     {
182       return (*this == other);
183     }
184
185     operator struct ev_loop * () const EV_THROW ()
186     {
187       return EV_AX;
188     }
189
190     operator const struct ev_loop * () const EV_THROW ()
191     {
192       return EV_AX;
193     }
194
195     bool is_default () const EV_THROW ()
196     {
197       return EV_AX == ev_default_loop (0);
198     }
199 #endif
200
201     void loop (int flags = 0)
202     {
203       ev_loop (EV_AX_ flags);
204     }
205
206     void unloop (how_t how = ONE) EV_THROW ()
207     {
208       ev_unloop (EV_AX_ how);
209     }
210
211     void post_fork () EV_THROW ()
212     {
213 #if EV_MULTIPLICITY
214       ev_loop_fork (EV_AX);
215 #else
216       ev_default_fork ();
217 #endif
218     }
219
220     unsigned int count () const EV_THROW ()
221     {
222       return ev_loop_count (EV_AX);
223     }
224
225     unsigned int backend () const EV_THROW ()
226     {
227       return ev_backend (EV_AX);
228     }
229
230     tstamp now () const EV_THROW ()
231     {
232       return ev_now (EV_AX);
233     }
234
235     void ref () EV_THROW ()
236     {
237       ev_ref (EV_AX);
238     }
239
240     void unref () EV_THROW ()
241     {
242       ev_unref (EV_AX);
243     }
244
245     void set_io_collect_interval (tstamp interval) EV_THROW ()
246     {
247       ev_set_io_collect_interval (EV_AX_ interval);
248     }
249
250     void set_timeout_collect_interval (tstamp interval) EV_THROW ()
251     {
252       ev_set_timeout_collect_interval (EV_AX_ interval);
253     }
254
255     // function callback
256     void once (int fd, int events, tstamp timeout, void (*cb)(int, void *), void* arg = 0) EV_THROW ()
257     {
258       ev_once (EV_AX_ fd, events, timeout, cb, arg);
259     }
260
261     // method callback
262     template<class K, void (K::*method)(int)>
263     void once (int fd, int events, tstamp timeout, K *object) EV_THROW ()
264     {
265       once (fd, events, timeout, method_thunk<K, method>, object);
266     }
267
268     template<class K, void (K::*method)(int)>
269     static void method_thunk (int revents, void* arg)
270     {
271       K *obj = static_cast<K *>(arg);
272       (obj->*method) (revents);
273     }
274
275     // const method callback
276     template<class K, void (K::*method)(int) const>
277     void once (int fd, int events, tstamp timeout, const K *object) EV_THROW ()
278     {
279       once (fd, events, timeout, const_method_thunk<K, method>, object);
280     }
281
282     template<class K, void (K::*method)(int) const>
283     static void const_method_thunk (int revents, void* arg)
284     {
285       K *obj = static_cast<K *>(arg);
286       (obj->*method) (revents);
287     }
288
289     // simple method callback
290     template<class K, void (K::*method)()>
291     void once (int fd, int events, tstamp timeout, K *object) EV_THROW ()
292     {
293       once (fd, events, timeout, method_noargs_thunk<K, method>, object);
294     }
295
296     template<class K, void (K::*method)()>
297     static void method_noargs_thunk (int revents, void* arg)
298     {
299       K *obj = static_cast<K *>(arg);
300       (obj->*method) ();
301     }
302
303     // simpler function callback
304     template<void (*cb)(int)>
305     void once (int fd, int events, tstamp timeout) EV_THROW ()
306     {
307       once (fd, events, timeout, simpler_func_thunk<cb>);
308     }
309
310     template<void (*cb)(int)>
311     static void simpler_func_thunk (int revents, void* arg)
312     {
313       (*cb) (revents);
314     }
315
316     // simplest function callback
317     template<void (*cb)()>
318     void once (int fd, int events, tstamp timeout) EV_THROW ()
319     {
320       once (fd, events, timeout, simplest_func_thunk<cb>);
321     }
322
323     template<void (*cb)()>
324     static void simplest_func_thunk (int revents, void* arg)
325     {
326       (*cb) ();
327     }
328
329     void feed_fd_event (int fd, int revents) EV_THROW ()
330     {
331       ev_feed_fd_event (EV_AX_ fd, revents);
332     }
333
334     void feed_signal_event (int signum) EV_THROW ()
335     {
336       ev_feed_signal_event (EV_AX_ signum);
337     }
338
339 #if EV_MULTIPLICITY
340     struct ev_loop* EV_AX;
341 #endif
342
343   };
344
345 #if EV_MULTIPLICITY
346   struct dynamic_loop: loop_ref
347   {
348
349     dynamic_loop (unsigned int flags = AUTO) EV_THROW (bad_loop)
350       : loop_ref (ev_loop_new (flags))
351     {
352     }
353
354     ~dynamic_loop () EV_THROW ()
355     {
356       ev_loop_destroy (EV_AX);
357       EV_AX = 0;
358     }
359
360   private:
361
362     dynamic_loop (const dynamic_loop &);
363
364     dynamic_loop & operator= (const dynamic_loop &);
365
366   };
367 #endif
368
369   struct default_loop: loop_ref
370   {
371
372     default_loop (unsigned int flags = AUTO) EV_THROW (bad_loop)
373 #if EV_MULTIPLICITY
374       : loop_ref (ev_default_loop (flags))
375     {
376     }
377 #else
378     {
379     #if EV_CXX_EXCEPTIONS
380       int r =
381     #endif
382           ev_default_loop (flags);
383     #if EV_CXX_EXCEPTIONS
384       if (!r)
385         throw bad_loop ();
386     #endif
387     }
388 #endif
389
390     ~default_loop () EV_THROW ()
391     {
392       ev_default_destroy ();
393 #if EV_MULTIPLICITY
394       EV_AX = 0;
395 #endif
396     }
397
398   private:
399
400     default_loop (const default_loop &);
401
402     default_loop & operator= (const default_loop &);
403
404   };
405
406   inline loop_ref get_default_loop () EV_THROW ()
407   {
408 #if EV_MULTIPLICITY
409     return ev_default_loop (0);
410 #else
411     return loop_ref ();
412 #endif
413   }
414
415 #undef EV_AX
416 #undef EV_AX_
417
418 #undef EV_PX
419 #undef EV_PX_
420 #if EV_MULTIPLICITY
421 #  define EV_PX  loop_ref EV_A
422 #  define EV_PX_ loop_ref EV_A_
423 #else
424 #  define EV_PX
425 #  define EV_PX_
426 #endif
427
428   template<class ev_watcher, class watcher>
429   struct base : ev_watcher
430   {
431     #if EV_MULTIPLICITY
432       EV_PX;
433
434       void set (EV_PX) EV_THROW ()
435       {
436         this->EV_A = EV_A;
437       }
438     #endif
439
440     base (EV_PX) EV_THROW ()
441     #if EV_MULTIPLICITY
442       : EV_A (EV_A)
443     #endif
444     {
445       ev_init (this, 0);
446     }
447
448     void set_ (void *data, void (*cb)(EV_P_ ev_watcher *w, int revents)) EV_THROW ()
449     {
450       this->data = data;
451       ev_set_cb (static_cast<ev_watcher *>(this), cb);
452     }
453
454     // method callback
455     template<class K, void (K::*method)(watcher &w, int)>
456     void set (K *object) EV_THROW ()
457     {
458       set_ (object, method_thunk<K, method>);
459     }
460
461     template<class K, void (K::*method)(watcher &w, int)>
462     static void method_thunk (EV_P_ ev_watcher *w, int revents)
463     {
464       K *obj = static_cast<K *>(w->data);
465       (obj->*method) (*static_cast<watcher *>(w), revents);
466     }
467
468     // const method callback
469     template<class K, void (K::*method)(watcher &w, int) const>
470     void set (const K *object) EV_THROW ()
471     {
472       set_ (object, const_method_thunk<K, method>);
473     }
474
475     template<class K, void (K::*method)(watcher &w, int) const>
476     static void const_method_thunk (EV_P_ ev_watcher *w, int revents)
477     {
478       K *obj = static_cast<K *>(w->data);
479       (static_cast<K *>(w->data)->*method) (*static_cast<watcher *>(w), revents);
480     }
481
482     // function callback
483     template<void (*function)(watcher &w, int)>
484     void set (void *data = 0) EV_THROW ()
485     {
486       set_ (data, function_thunk<function>);
487     }
488
489     template<void (*function)(watcher &w, int)>
490     static void function_thunk (EV_P_ ev_watcher *w, int revents)
491     {
492       function (*static_cast<watcher *>(w), revents);
493     }
494
495     // simple callback
496     template<class K, void (K::*method)()>
497     void set (K *object) EV_THROW ()
498     {
499       set_ (object, method_noargs_thunk<K, method>);
500     }
501
502     template<class K, void (K::*method)()>
503     static void method_noargs_thunk (EV_P_ ev_watcher *w, int revents)
504     {
505       K *obj = static_cast<K *>(w->data);
506       (obj->*method) ();
507     }
508
509     void operator ()(int events = EV_UNDEF)
510     {
511       return ev_cb (static_cast<ev_watcher *>(this))
512         (static_cast<ev_watcher *>(this), events);
513     }
514
515     bool is_active () const EV_THROW ()
516     {
517       return ev_is_active (static_cast<const ev_watcher *>(this));
518     }
519
520     bool is_pending () const EV_THROW ()
521     {
522       return ev_is_pending (static_cast<const ev_watcher *>(this));
523     }
524
525     void feed_event (int revents) EV_THROW ()
526     {
527       ev_feed_event (EV_A_ static_cast<const ev_watcher *>(this), revents);
528     }
529   };
530
531   inline tstamp now () EV_THROW ()
532   {
533     return ev_time ();
534   }
535
536   inline void delay (tstamp interval) EV_THROW ()
537   {
538     ev_sleep (interval);
539   }
540
541   inline int version_major () EV_THROW ()
542   {
543     return ev_version_major ();
544   }
545
546   inline int version_minor () EV_THROW ()
547   {
548     return ev_version_minor ();
549   }
550
551   inline unsigned int supported_backends () EV_THROW ()
552   {
553     return ev_supported_backends ();
554   }
555
556   inline unsigned int recommended_backends () EV_THROW ()
557   {
558     return ev_recommended_backends ();
559   }
560
561   inline unsigned int embeddable_backends () EV_THROW ()
562   {
563     return ev_embeddable_backends ();
564   }
565
566   inline void set_allocator (void *(*cb)(void *ptr, long size)) EV_THROW ()
567   {
568     ev_set_allocator (cb);
569   }
570
571   inline void set_syserr_cb (void (*cb)(const char *msg)) EV_THROW ()
572   {
573     ev_set_syserr_cb (cb);
574   }
575
576   #if EV_MULTIPLICITY
577     #define EV_CONSTRUCT(cppstem,cstem)                                                 \
578       (EV_PX = get_default_loop ()) EV_THROW ()                                         \
579         : base<ev_ ## cstem, cppstem> (EV_A)                                            \
580       {                                                                                 \
581       }
582   #else
583     #define EV_CONSTRUCT(cppstem,cstem)                                                 \
584       () EV_THROW ()                                                                    \
585       {                                                                                 \
586       }
587   #endif
588
589   /* using a template here would require quite a bit more lines,
590    * so a macro solution was chosen */
591   #define EV_BEGIN_WATCHER(cppstem,cstem)                                               \
592                                                                                         \
593   struct cppstem : base<ev_ ## cstem, cppstem>                                          \
594   {                                                                                     \
595     void start () EV_THROW ()                                                           \
596     {                                                                                   \
597       ev_ ## cstem ## _start (EV_A_ static_cast<ev_ ## cstem *>(this));                 \
598     }                                                                                   \
599                                                                                         \
600     void stop () EV_THROW ()                                                            \
601     {                                                                                   \
602       ev_ ## cstem ## _stop (EV_A_ static_cast<ev_ ## cstem *>(this));                  \
603     }                                                                                   \
604                                                                                         \
605     cppstem EV_CONSTRUCT(cppstem,cstem)                                                 \
606                                                                                         \
607     ~cppstem () EV_THROW ()                                                             \
608     {                                                                                   \
609       stop ();                                                                          \
610     }                                                                                   \
611                                                                                         \
612     using base<ev_ ## cstem, cppstem>::set;                                             \
613                                                                                         \
614   private:                                                                              \
615                                                                                         \
616     cppstem (const cppstem &o);                                                         \
617                                                                                         \
618     cppstem & operator =(const cppstem &o);                                             \
619                                                                                         \
620   public:
621
622   #define EV_END_WATCHER(cppstem,cstem)                                                 \
623   };
624
625   EV_BEGIN_WATCHER (io, io)
626     void set (int fd, int events) EV_THROW ()
627     {
628       int active = is_active ();
629       if (active) stop ();
630       ev_io_set (static_cast<ev_io *>(this), fd, events);
631       if (active) start ();
632     }
633
634     void set (int events) EV_THROW ()
635     {
636       int active = is_active ();
637       if (active) stop ();
638       ev_io_set (static_cast<ev_io *>(this), fd, events);
639       if (active) start ();
640     }
641
642     void start (int fd, int events) EV_THROW ()
643     {
644       set (fd, events);
645       start ();
646     }
647   EV_END_WATCHER (io, io)
648
649   EV_BEGIN_WATCHER (timer, timer)
650     void set (ev_tstamp after, ev_tstamp repeat = 0.) EV_THROW ()
651     {
652       int active = is_active ();
653       if (active) stop ();
654       ev_timer_set (static_cast<ev_timer *>(this), after, repeat);
655       if (active) start ();
656     }
657
658     void start (ev_tstamp after, ev_tstamp repeat = 0.) EV_THROW ()
659     {
660       set (after, repeat);
661       start ();
662     }
663
664     void again () EV_THROW ()
665     {
666       ev_timer_again (EV_A_ static_cast<ev_timer *>(this));
667     }
668   EV_END_WATCHER (timer, timer)
669
670   #if EV_PERIODIC_ENABLE
671   EV_BEGIN_WATCHER (periodic, periodic)
672     void set (ev_tstamp at, ev_tstamp interval = 0.) EV_THROW ()
673     {
674       int active = is_active ();
675       if (active) stop ();
676       ev_periodic_set (static_cast<ev_periodic *>(this), at, interval, 0);
677       if (active) start ();
678     }
679
680     void start (ev_tstamp at, ev_tstamp interval = 0.) EV_THROW ()
681     {
682       set (at, interval);
683       start ();
684     }
685
686     void again () EV_THROW ()
687     {
688       ev_periodic_again (EV_A_ static_cast<ev_periodic *>(this));
689     }
690   EV_END_WATCHER (periodic, periodic)
691   #endif
692
693   EV_BEGIN_WATCHER (sig, signal)
694     void set (int signum) EV_THROW ()
695     {
696       int active = is_active ();
697       if (active) stop ();
698       ev_signal_set (static_cast<ev_signal *>(this), signum);
699       if (active) start ();
700     }
701
702     void start (int signum) EV_THROW ()
703     {
704       set (signum);
705       start ();
706     }
707   EV_END_WATCHER (sig, signal)
708
709   EV_BEGIN_WATCHER (child, child)
710     void set (int pid) EV_THROW ()
711     {
712       int active = is_active ();
713       if (active) stop ();
714       ev_child_set (static_cast<ev_child *>(this), pid);
715       if (active) start ();
716     }
717
718     void start (int pid) EV_THROW ()
719     {
720       set (pid);
721       start ();
722     }
723   EV_END_WATCHER (child, child)
724
725   #if EV_STAT_ENABLE
726   EV_BEGIN_WATCHER (stat, stat)
727     void set (const char *path, ev_tstamp interval = 0.) EV_THROW ()
728     {
729       int active = is_active ();
730       if (active) stop ();
731       ev_stat_set (static_cast<ev_stat *>(this), path, interval);
732       if (active) start ();
733     }
734
735     void start (const char *path, ev_tstamp interval = 0.) EV_THROW ()
736     {
737       stop ();
738       set (path, interval);
739       start ();
740     }
741
742     void update () EV_THROW ()
743     {
744       ev_stat_stat (EV_A_ static_cast<ev_stat *>(this));
745     }
746   EV_END_WATCHER (stat, stat)
747   #endif
748
749   EV_BEGIN_WATCHER (idle, idle)
750     void set () EV_THROW () { }
751   EV_END_WATCHER (idle, idle)
752
753   EV_BEGIN_WATCHER (prepare, prepare)
754     void set () EV_THROW () { }
755   EV_END_WATCHER (prepare, prepare)
756
757   EV_BEGIN_WATCHER (check, check)
758     void set () EV_THROW () { }
759   EV_END_WATCHER (check, check)
760
761   #if EV_EMBED_ENABLE
762   EV_BEGIN_WATCHER (embed, embed)
763     void start (struct ev_loop *embedded_loop) EV_THROW ()
764     {
765       stop ();
766       ev_embed_set (static_cast<ev_embed *>(this), embedded_loop);
767       start ();
768     }
769
770     void sweep ()
771     {
772       ev_embed_sweep (EV_A_ static_cast<ev_embed *>(this));
773     }
774   EV_END_WATCHER (embed, embed)
775   #endif
776
777   #if EV_FORK_ENABLE
778   EV_BEGIN_WATCHER (fork, fork)
779     void set () EV_THROW () { }
780   EV_END_WATCHER (fork, fork)
781   #endif
782
783   #undef EV_PX
784   #undef EV_PX_
785   #undef EV_CONSTRUCT
786   #undef EV_BEGIN_WATCHER
787   #undef EV_END_WATCHER
788
789 }
790
791 #undef EV_THROW
792
793 #endif
794