Leandro Lucarella, el 14 de enero a las 15:37 me escribiste:
> 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);")

To implement this point, 2) is necessary if we don't want to be needed to
explicitly set every watcher's loop, because the lack of a "standard" way
to get the default loop.

> 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)

Here's patch that implement this scheme (over the original patch). Even if
it's nice to stay close to the C API and to avoid the posibility of
instantiating 2 default loops from the root, I think the usage is a little
less intuitive in a C++ environment.

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
PADRES DENUNCIAN QUE SU HIJA SE ESCAPO CON UN PARAGUAYITO
        -- Crónica TV
Author: Leandro Lucarella <[EMAIL PROTECTED]>
Date:   Mon Jan 14 14:15:16 2008 -0200

    Enforce singleton-ness of the default loop by using a function to access it.

diff --git a/ev++.h b/ev++.h
index 51051fb..282fcf0 100644
--- a/ev++.h
+++ b/ev++.h
@@ -82,12 +82,6 @@ namespace ev {
       : 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;
@@ -186,61 +180,66 @@ namespace ev {
   };
 
 #if EV_MULTIPLICITY
-  struct simple_loop: loop_ref
+  struct loop_simple: loop_ref
   {
 
-    simple_loop (unsigned int flags = AUTO) throw (bad_loop)
+    loop_simple (unsigned int flags = AUTO) throw (bad_loop)
       : loop_ref (ev_loop_new (flags))
     {
     }
 
-    ~simple_loop () throw ()
+    ~loop_simple () throw ()
     {
       ev_loop_destroy (EV_A);
     }
 
   private:
 
-    simple_loop (const simple_loop &);
+    loop_simple (const loop_simple &);
 
-    simple_loop & operator= (const simple_loop &);
+    loop_simple & operator= (const loop_simple &);
 
   };
 #endif
 
-  bool default_loop_created (int created = -1)
-  {
-    static bool is_created = false;
-    if (created != -1)
-      is_created = created;
-    return is_created;
-  }
+  struct loop_default;
+
+  loop_default&
+  default_loop (int flags = 0);
 
-  struct default_loop: loop_ref
+  struct loop_default: loop_ref
   {
 
-    default_loop (unsigned int flags = AUTO) throw (bad_loop, already_created)
-      : loop_ref (ev_default_loop (flags))
+    ~loop_default () throw ()
     {
-      if (default_loop_created ())
-        throw already_created ();
-      default_loop_created (true);
+      ev_default_destroy ();
     }
 
-    ~default_loop () throw ()
+  private:
+
+    loop_default (unsigned int flags = AUTO) throw (bad_loop)
+      : loop_ref (ev_default_loop (flags))
     {
-      default_loop_created (false);
-      ev_default_destroy ();
     }
 
-  private:
+    loop_default ();
 
-    default_loop (const default_loop &);
+    loop_default (const loop_default &);
 
-    default_loop & operator= (const default_loop &);
+    loop_default & operator= (const loop_default &);
+
+    friend loop_default& default_loop (int flags);
 
   };
 
+  inline
+  loop_default&
+  default_loop (int flags)
+  {
+    static loop_default l (flags);
+    return l;
+  }
+
   template<class ev_watcher, class watcher>
   struct base : ev_watcher
   {
#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 */
		ev::default_loop ().stop (); // just to demostrate the usage
		                             // of the free function a la C-API.
	}
};

int
main (void)
{
	// Needs explicit initialization via a function call which is not as
	// clear as an object instantiation IMHO
	ev::default_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 */
	ev::default_loop ().start ();

	return 0;
}


_______________________________________________
libev mailing list
[email protected]
http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev

Reply via email to