cedric pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=0789156c86fb51cadbf173bbb230a4d2ddef9612

commit 0789156c86fb51cadbf173bbb230a4d2ddef9612
Author: Cedric Bail <ced...@osg.samsung.com>
Date:   Wed Jul 27 09:56:07 2016 -0700

    ecore: add efl_future_race.
---
 src/lib/ecore/Ecore_Eo.h    |  15 +++
 src/lib/ecore/efl_promise.c | 245 +++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 235 insertions(+), 25 deletions(-)

diff --git a/src/lib/ecore/Ecore_Eo.h b/src/lib/ecore/Ecore_Eo.h
index 1209232..62c4192 100644
--- a/src/lib/ecore/Ecore_Eo.h
+++ b/src/lib/ecore/Ecore_Eo.h
@@ -74,6 +74,21 @@ EAPI Efl_Future *efl_future_iterator_all(Eina_Iterator *it);
 
 #define efl_future_all(...) efl_future_all_internal(__VA_ARGS__, NULL)
 
+typedef struct _Efl_Future_Race_Success Efl_Future_Race_Success;
+typedef struct _Efl_Future_Composite_Progress Efl_Future_Race_Progress;
+
+struct _Efl_Future_Race_Success
+{
+   Efl_Future *winner;
+   void *value;
+
+   unsigned int index;
+};
+
+EAPI Efl_Future *efl_future_race_internal(Efl_Future *f1, ...);
+
+#define efl_future_race(...) efl_future_race_internal(__VA_ARGS__, NULL)
+
 /**
  * @}
  */
diff --git a/src/lib/ecore/efl_promise.c b/src/lib/ecore/efl_promise.c
index 275c56a..72dfdde 100644
--- a/src/lib/ecore/efl_promise.c
+++ b/src/lib/ecore/efl_promise.c
@@ -588,10 +588,12 @@ _efl_promise_efl_object_destructor(Eo *obj, 
Efl_Promise_Data *pd)
    efl_destructor(efl_super(obj, EFL_PROMISE_CLASS));
 }
 
-typedef struct _Efl_Promise_All Efl_Promise_All;
+typedef struct _Efl_Promise_Composite Efl_Promise_All;
 typedef struct _Efl_Future_All Efl_Future_All;
 typedef struct _Efl_Accessor_All Efl_Accessor_All;
 
+typedef struct _Efl_Promise_Composite Efl_Promise_Race;
+
 struct _Efl_Accessor_All
 {
    Eina_Accessor accessor;
@@ -607,17 +609,34 @@ struct _Efl_Future_All
    Efl_Promise_Msg *d;
 };
 
-struct _Efl_Promise_All
+struct _Efl_Promise_Composite
 {
    Eina_Array members;
 
    Efl_Promise *promise;
 
+   Efl_Future *(*future_get)(void *item);
+
    Eina_Bool failed : 1;
    Eina_Bool progress_triggered : 1;
    Eina_Bool future_triggered : 1;
+   Eina_Bool done : 1;
 };
 
+static Efl_Future *
+_efl_promise_all_future_get(void *item)
+{
+   Efl_Future_All *fa = item;
+
+   return fa->f;
+}
+
+static Efl_Future *
+_efl_promise_race_future_get(void *item)
+{
+   return item;
+}
+
 static void
 _efl_promise_all_free(Efl_Promise_All *all)
 {
@@ -643,10 +662,19 @@ _efl_promise_all_die(void *data, const Efl_Event *ev 
EINA_UNUSED)
 }
 
 static void
-_efl_all_future_set(void *data, const Eo_Event *ev EINA_UNUSED)
+_efl_promise_race_die(void *data, const Efl_Event *ev EINA_UNUSED)
 {
    Efl_Promise_All *all = data;
-   Efl_Future_All *fa;
+
+   eina_array_flush(&all->members);
+   free(all);
+}
+
+static void
+_efl_future_set(void *data, const Efl_Event *ev EINA_UNUSED)
+{
+   Efl_Promise_All *all = data;
+   void *item;
    Eina_Array_Iterator iterator;
    unsigned int i;
 
@@ -654,15 +682,17 @@ _efl_all_future_set(void *data, const Eo_Event *ev 
EINA_UNUSED)
    all->future_triggered = EINA_TRUE;
 
    // Propagate set on demand
-   EINA_ARRAY_ITER_NEXT(&all->members, i, fa, iterator)
+   EINA_ARRAY_ITER_NEXT(&all->members, i, item, iterator)
      {
-        if (fa->f)
+        Efl_Future *f = all->future_get(item);
+
+        if (f)
           {
-             Efl_Loop_Future_Data *pd = efl_data_scope_get(fa->f, 
EFL_LOOP_FUTURE_CLASS);
+             Efl_Loop_Future_Data *pd = efl_data_scope_get(f, 
EFL_LOOP_FUTURE_CLASS);
 
              if (!pd->promise->set.future && 
!pd->promise->set.future_triggered)
                {
-                  efl_event_callback_call(pd->promise->promise, 
EFL_PROMISE_EVENT_FUTURE_SET, fa->f);
+                  efl_event_callback_call(pd->promise->promise, 
EFL_PROMISE_EVENT_FUTURE_SET, f);
                   pd->promise->set.future_triggered = EINA_TRUE;
                   pd->promise->set.future = EINA_TRUE;
                }
@@ -671,10 +701,10 @@ _efl_all_future_set(void *data, const Eo_Event *ev 
EINA_UNUSED)
 }
 
 static void
-_efl_all_future_progress_set(void *data, const Eo_Event *ev EINA_UNUSED)
+_efl_future_progress_set(void *data, const Efl_Event *ev EINA_UNUSED)
 {
    Efl_Promise_All *all = data;
-   Efl_Future_All *fa;
+   void *item;
    Eina_Array_Iterator iterator;
    unsigned int i;
 
@@ -682,15 +712,17 @@ _efl_all_future_progress_set(void *data, const Eo_Event 
*ev EINA_UNUSED)
    all->progress_triggered = 1;
 
    // Propagate progress set
-   EINA_ARRAY_ITER_NEXT(&all->members, i, fa, iterator)
+   EINA_ARRAY_ITER_NEXT(&all->members, i, item, iterator)
      {
-        if (fa->f)
+        Efl_Future *f = all->future_get(item);
+
+        if (f)
           {
-             Efl_Loop_Future_Data *pd = efl_data_scope_get(fa->f, 
EFL_LOOP_FUTURE_CLASS);
+             Efl_Loop_Future_Data *pd = efl_data_scope_get(f, 
EFL_LOOP_FUTURE_CLASS);
 
              if (!pd->promise->set.progress && 
!pd->promise->set.progress_triggered)
                {
-                  efl_event_callback_call(pd->promise->promise, 
EFL_PROMISE_EVENT_FUTURE_PROGRESS_SET, fa->f);
+                  efl_event_callback_call(pd->promise->promise, 
EFL_PROMISE_EVENT_FUTURE_PROGRESS_SET, f);
                   pd->promise->set.progress_triggered = EINA_TRUE;
                   pd->promise->set.progress = EINA_TRUE;
                }
@@ -712,7 +744,28 @@ _efl_all_future_none(void *data, const Efl_Event *ev 
EINA_UNUSED)
    // Trigger cancel on all future
    EINA_ARRAY_ITER_NEXT(&all->members, i, fa, iterator)
      {
-        if (!fa->d) efl_future_cancel(fa->f);
+        if (!fa->d && fa->f) efl_future_cancel(fa->f);
+     }
+
+   // No one is listening to this promise anyway
+   _efl_promise_all_free(all);
+}
+
+static void
+_efl_race_future_none(void *data, const Efl_Event *ev EINA_UNUSED)
+{
+   Efl_Promise_Race *all = data;
+   Efl_Future *f;
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+
+   if (all->failed) return ;
+   all->failed = EINA_TRUE;
+
+   // Trigger cancel on all future
+   EINA_ARRAY_ITER_NEXT(&all->members, i, f, iterator)
+     {
+        if (!f) efl_future_cancel(f);
      }
 
    // No one is listening to this promise anyway
@@ -828,29 +881,28 @@ _progress(void *data, const Efl_Event *ev)
 {
    Efl_Promise_All *all = data;
    Efl_Future_Event_Progress *p = ev->info;
-   Efl_Future_All *fa;
+   void *item;
    Efl_Future_All_Progress a;
    Eina_Array_Iterator iterator;
    unsigned int i;
 
    a.inprogress = ev->object;
    a.progress = p->progress;
-   a.index = 0;
 
-   EINA_ARRAY_ITER_NEXT(&all->members, i, fa, iterator)
+   EINA_ARRAY_ITER_NEXT(&all->members, i, item, iterator)
      {
-        if (fa->f == a.inprogress)
-          {
-             break ;
-          }
-        a.index++;
+        Efl_Future *f = all->future_get(item);
+
+        if (f == a.inprogress) break ;
      }
+   a.index = i;
+
    efl_promise_progress_set(all->promise, &a);
 }
 
 EFL_CALLBACKS_ARRAY_DEFINE(efl_all_callbacks,
-                           { EFL_PROMISE_EVENT_FUTURE_SET, _efl_all_future_set 
},
-                           { EFL_PROMISE_EVENT_FUTURE_PROGRESS_SET, 
_efl_all_future_progress_set },
+                           { EFL_PROMISE_EVENT_FUTURE_SET, _efl_future_set },
+                           { EFL_PROMISE_EVENT_FUTURE_PROGRESS_SET, 
_efl_future_progress_set },
                            { EFL_PROMISE_EVENT_FUTURE_NONE, 
_efl_all_future_none },
                            { EFL_EVENT_DEL, _efl_promise_all_die });
 
@@ -964,4 +1016,147 @@ efl_future_iterator_all(Eina_Iterator *it)
    return NULL;
 }
 
+static void
+_then_race(void *data, const Efl_Event *ev)
+{
+   Efl_Future_Event_Success *success = ev->info;
+   Efl_Promise_Race *race = data;
+   // This is a trick due to the fact we are using internal function call to 
register this functions
+   Efl_Promise_Msg *d = success->value;
+   Efl_Future *f;
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+
+   if (race->done) return ;
+   race->done = EINA_TRUE;
+
+   efl_ref(race->promise);
+
+   EINA_ARRAY_ITER_NEXT(&race->members, i, f, iterator)
+     {
+        // To avoid double cancel/success
+        eina_array_data_set(&race->members, i, NULL);
+
+        if (f == ev->object)
+          {
+             Efl_Future_Race_Success *success = calloc(1, sizeof 
(Efl_Future_Race_Success));
+
+             if (!success) continue ;
+             success->winner = f;
+             success->value = d->value;
+             success->index = i;
+
+             efl_promise_value_set(race->promise, success, free);
+          }
+        else
+          {
+             efl_future_cancel(f);
+          }
+     }
+
+   _efl_promise_all_free(race);
+   efl_unref(race->promise);
+}
+
+static void
+_fail_race(void *data, const Efl_Event *ev)
+{
+   Efl_Future_Event_Failure *fail = ev->info;
+   Efl_Promise_Race *race = data;
+   Efl_Future *f;
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+
+   if (race->done) return ;
+   race->done = EINA_TRUE;
+
+   efl_ref(race->promise);
+
+   EINA_ARRAY_ITER_NEXT(&race->members, i, f, iterator)
+     {
+        // To avoid double cancel/success
+        eina_array_data_set(&race->members, i, NULL);
+
+        if (f != ev->object)
+          {
+             efl_future_cancel(f);
+          }
+     }
+
+   efl_promise_failed(race->promise, fail->error);
+   _efl_promise_all_free(race);
+   efl_unref(race->promise);
+}
+
+EFL_CALLBACKS_ARRAY_DEFINE(efl_race_callbacks,
+                           { EFL_PROMISE_EVENT_FUTURE_SET, _efl_future_set },
+                           { EFL_PROMISE_EVENT_FUTURE_PROGRESS_SET, 
_efl_future_progress_set },
+                           { EFL_PROMISE_EVENT_FUTURE_NONE, 
_efl_race_future_none },
+                           { EFL_EVENT_DEL, _efl_promise_race_die });
+
+static Efl_Promise_Race *
+_efl_future_race_new(Eo *provider)
+{
+   Efl_Promise_Race *race;
+   Eo *loop;
+
+   loop = efl_provider_find(provider, EFL_LOOP_CLASS);
+   if (!loop) return NULL;
+
+   race = calloc(1, sizeof (Efl_Promise_Race));
+   if (!race) return NULL;
+
+   eina_array_step_set(&race->members, sizeof (Eina_Array), 8);
+   race->future_get = _efl_promise_race_future_get;
+   race->promise = efl_add(EFL_PROMISE_CLASS, loop);
+   if (!race->promise) goto on_error;
+
+   return race;
+
+ on_error:
+   free(race);
+   return NULL;
+}
+
+static inline Efl_Future *
+_efl_future_race_done(Efl_Promise_Race *race)
+{
+   Efl_Future *fn;
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+
+   EINA_ARRAY_ITER_NEXT(&race->members, i, fn, iterator)
+     _efl_loop_future_internal_then(fn, _then_race, _fail_race, _progress, 
race);
+
+   efl_event_callback_array_add(race->promise, efl_race_callbacks(), race);
+
+   return efl_promise_future_get(race->promise);
+}
+
+EAPI Efl_Future *
+efl_future_race_internal(Efl_Future *f1, ...)
+{
+   Efl_Promise_Race *race;
+   Efl_Future *fn;
+   va_list args;
+
+   if (!f1) return NULL;
+
+   race = _efl_future_race_new(f1);
+   if (!race) return NULL;
+
+   eina_array_push(&race->members, f1);
+
+   va_start(args, f1);
+
+   while ((fn = va_arg(args, Efl_Future *)))
+     {
+        eina_array_push(&race->members, fn);
+     }
+
+
+
+   return _efl_future_race_done(race);
+}
+
 #include "efl_promise.eo.c"

-- 


Reply via email to