Hi, following the "C++ APIs" thread [1], I came to the conclusion that I
didn't like the "whole new wrapper" approach, because it didn't provide
anything ev++.h have (or it would be too hard to implement, and I didn't
thought it worth the effort, because there were too little benefit).

I tried the full wrapper approach, with the goal of making a "C++
binding", trying to hide all the C API (including ev.h only in the cpp
files) but it didn't worked, and add another lib to link to, and lost the
embedding capabilities.

So I decided to improve ev++.h, at least as I see it =)

Attached it a *rough* patch, that can be used as in the example file
test.cpp. There are a few issues I'm not happy about, so I want to know
your opinion before deciding what to do with them, and of course, I want
to know if there is any interest in merging this to the official libev
distribution =)

What I'm not crazy about is:
1) Storing a ev_loop* in the watchers, instead of a loop_ref. But I'm
   affraid that not doing so could break some existing code. This leads to
   the ugly "ev::loop_ref (w.loop).stop (ev::ALL);" in the example (if a
   loop_ref could be stored, it looked like "w.loop.stop (ev::ALL);")
2) The default loop handling. Now a default loop has to be instantiated,
   and a simple check is done to ensure just one default loop exists, but
   with an ugly hack (via de default_loop_created() function) to avoid the
   need of object code (a class static variable would need it).
   This model is a little different to the C API, because you can't get
   the default loop from anywhere (at least not in the same way, but you
   can do it with something like loop_ref(ev_default_loop(0)), but it's
   not very nice). The easiest way to do that is making the default_loop a
   global variable, but it's a "userspace" hack.
   I thought of making a more singleton-approach (using a function to
   get/create the loop object if it doesn't exist, for example
   "get_default_loop(int flags = 0) { static default_loop* l = 0; if (!l) l =
   new default_loop(flags); return l; }" but this way you have to
   explicitly free the default loop). Now that I see this, maybe it could
   be "elegantly" solved using a reference:
   default_loop&
   get_default_loop(int flags = 0)
   {
        static default_loop l(flags);
        return l;
   }
   (class names could be rearranged to name this funtion default_loop()
   and the class loop_default, for example, to be more C API-consistent)

The patch is embedding and EV_MULTIPLICITY aware, but it's not well tested
(to be honest, I just tested it with the example attached, with a default
libev build -EV_MULTIPLICITY = 1-).

[1] http://permalink.gmane.org/gmane.comp.lib.ev/9

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
Qué sabía Galileo de astronomía, Mendieta! Lo que pasa es que en este
país habla cualquiera.
        -- Inodoro Pereyra
Author: Leandro Lucarella <[EMAIL PROTECTED]>
Date:   Mon Jan 14 13:21:28 2008 -0200

    Add loop hierarchy and some missing free functions.

diff --git a/ev++.h b/ev++.h
index 97e015c..edf7bcd 100644
--- a/ev++.h
+++ b/ev++.h
@@ -45,9 +45,202 @@
 #else
 # include <ev.h>
 #endif
+#include <stdexcept>
 
 namespace ev {
 
+  typedef ev_tstamp tstamp;
+
+  enum
+  {
+    AUTO = EVFLAG_AUTO,
+    NOENV = EVFLAG_NOENV,
+    FORKCHECK = EVFLAG_FORKCHECK,
+    SELECT = EVBACKEND_SELECT,
+    POLL = EVBACKEND_POLL,
+    EPOLL = EVBACKEND_EPOLL,
+    KQUEUE = EVBACKEND_KQUEUE,
+    DEVPOLL = EVBACKEND_DEVPOLL,
+    PORT = EVBACKEND_PORT
+  };
+
+  enum
+  {
+    NONBLOCK = EVLOOP_NONBLOCK,
+    ONESHOT = EVLOOP_ONESHOT
+  };
+
+  enum how_t
+  {
+    ONE = EVUNLOOP_ONE,
+    ALL = EVUNLOOP_ALL
+  };
+
+  struct bad_loop: std::runtime_error
+  {
+    bad_loop()
+      : std::runtime_error("loop can't be initialized") {}
+  };
+
+  struct already_created: std::logic_error
+  {
+    bad_loop()
+      : std::runtime_error("there's already a default loop instantiated") {}
+  };
+
+  extern "C"
+  {
+    extern struct ev_loop *ev_default_loop_ptr;
+  }
+
+  struct loop_ref
+  {
+
+    loop_ref (EV_P) throw (bad_loop)
+#if EV_MULTIPLICITY
+      : EV_A (EV_A), is_default (EV_A == ev_default_loop_ptr)
+#endif
+    {
+      if (!EV_A)
+        throw bad_loop ();
+    }
+
+#if EV_MULTIPLICITY
+    virtual
+#endif
+    ~loop_ref () throw ()
+    {
+    }
+
+#if EV_MULTIPLICITY
+    operator struct ev_loop * () throw ()
+    {
+      return EV_A;
+    }
+
+    operator const struct ev_loop * () throw ()
+    {
+      return EV_A;
+    }
+#endif
+
+    void start (int flags = 0) throw ()
+    {
+      ev_loop (EV_A_ flags);
+    }
+
+    void stop (how_t how = ALL) throw ()
+    {
+      ev_unloop (EV_A_ how);
+    }
+
+    void fork () throw ()
+    {
+#if EV_MULTIPLICITY
+      if (!is_default)
+        ev_loop_fork (EV_A);
+      else
+#endif
+        ev_default_fork ();
+    }
+
+    unsigned int count () const throw ()
+    {
+      return ev_loop_count (EV_A);
+    }
+
+    unsigned int backend () const throw ()
+    {
+      return ev_backend (EV_A);
+    }
+
+    tstamp now () const throw ()
+    {
+      return ev_now (EV_A);
+    }
+
+    void ref () throw ()
+    {
+      ev_ref (EV_A);
+    }
+
+    void unref () throw ()
+    {
+      ev_unref (EV_A);
+    }
+
+    void set_io_collect_interval (tstamp interval) throw ()
+    {
+      ev_set_io_collect_interval (EV_A_ interval);
+    }
+
+    void set_timeout_collect_interval (tstamp interval) throw ()
+    {
+      ev_set_timeout_collect_interval (EV_A_ interval);
+    }
+
+#if EV_MULTIPLICITY
+    EV_P;
+    bool is_default;
+#endif
+  };
+
+#if EV_MULTIPLICITY
+  struct simple_loop: loop_ref
+  {
+
+    simple_loop (unsigned int flags = AUTO) throw ()
+      : loop_ref (ev_loop_new (flags))
+    {
+    }
+
+    ~simple_loop () throw ()
+    {
+      ev_loop_destroy (EV_A);
+    }
+
+  private:
+
+    simple_loop (const simple_loop &);
+
+    simple_loop & operator= (const simple_loop &);
+
+  };
+#endif
+
+  bool default_loop_created (int created = -1)
+  {
+    static bool is_created = false;
+    if (created != -1)
+      is_created = created;
+    return is_created;
+  }
+
+  struct default_loop: loop_ref
+  {
+
+    default_loop (unsigned int flags = AUTO) throw (already_created)
+      : loop_ref (ev_default_loop (flags))
+    {
+      if (default_loop_created ())
+        throw already_created ();
+      default_loop_created (true);
+    }
+
+    ~default_loop () throw ()
+    {
+      default_loop_created (false);
+      ev_default_destroy ();
+    }
+
+  private:
+
+    default_loop (const default_loop &);
+
+    default_loop & operator= (const default_loop &);
+
+  };
+
   template<class ev_watcher, class watcher>
   struct base : ev_watcher
   {
@@ -161,14 +354,50 @@ namespace ev {
     ERROR    = EV_ERROR,
   };
 
-  typedef ev_tstamp tstamp;
+  inline tstamp time ()
+  {
+    return ev_time ();
+  }
 
-  #if EV_MULTIPLICITY
-  inline ev_tstamp now (EV_P)
+  inline void sleep (tstamp interval)
   {
-    return ev_now (EV_A);
+    ev_sleep (interval);
+  }
+
+  inline int version_major ()
+  {
+    return ev_version_major ();
+  }
+
+  inline int version_minor ()
+  {
+    return ev_version_minor ();
+  }
+
+  inline unsigned int supported_backends ()
+  {
+    return ev_supported_backends ();
+  }
+
+  inline unsigned int recommended_backends ()
+  {
+    return ev_recommended_backends ();
+  }
+
+  inline unsigned int embeddable_backends ()
+  {
+    return ev_embeddable_backends ();
+  }
+
+  inline void set_allocator (void *(*cb)(void *ptr, long size))
+  {
+    ev_set_allocator (cb);
+  }
+
+  inline void set_syserr_cb (void (*cb)(const char *msg))
+  {
+    ev_set_syserr_cb (cb);
   }
-  #endif
 
   #if EV_MULTIPLICITY
     #define EV_CONSTRUCT                                                                \
@@ -237,7 +466,7 @@ namespace ev {
       if (active) start ();
     }
 
-    void start (int fd, int events)
+    void start (int fd, int events = READ)
     {
       set (fd, events);
       start ();
@@ -381,6 +610,7 @@ namespace ev {
   #undef EV_CONSTRUCT
   #undef EV_BEGIN_WATCHER
   #undef EV_END_WATCHER
+
 }
 
 #endif
#include <ev++.h>
#include <stdio.h>
#include <unistd.h>

/* called when data readable on stdin */
struct myclass
{
	void io_cb (ev::io &w, int revents)
	{
		char buff[BUFSIZ];
		int r = read (w.fd, buff, BUFSIZ);
		printf ("stdin ready, %d bytes read: %s", r, buff);
		w.stop (); /* just a syntax example */
		ev::loop_ref(w.loop).stop (ev::ALL); /* leave all loop calls */
	}
};

int
main (void)
{
	ev::default_loop loop;

	myclass obj;
	ev::io iow;
	iow.set <myclass, &myclass::io_cb> (&obj);

	/* start watching fd 0 for reading (default) */
	iow.start (/*STDIN_FILENO*/ 0);

	/* loop till timeout or data ready */
	loop.start ();

	return 0;
}


_______________________________________________
libev mailing list
libev@lists.schmorp.de
http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev

Reply via email to