diff --git a/src/tests/util/lazy_list.cpp b/src/tests/util/lazy_list.cpp index 9c133b0cb..3426c093b 100644 --- a/src/tests/util/lazy_list.cpp +++ b/src/tests/util/lazy_list.cpp @@ -97,6 +97,7 @@ static void tst1() { display(orelse(filter(take(100, seq(1)), [](int i) { return i < 0; }), take(10, seq(1000)))); #ifndef __APPLE__ display(timeout(append(append(take(10, seq(1)), loop()), seq(100)), 5)); + display(take(10, par(seq(1), loop()))); #endif } diff --git a/src/util/lazy_list_fn.h b/src/util/lazy_list_fn.h index 166865262..415c8daab 100644 --- a/src/util/lazy_list_fn.h +++ b/src/util/lazy_list_fn.h @@ -223,4 +223,64 @@ lazy_list timeout(lazy_list const & l, unsigned ms, unsigned check_ms = g_ } }); } + +/** + \brief Similar to interleave, but the heads are computed in parallel. + Moreover, when pulling results from the lists, if one finishes before the other, + then the other one is interrupted. +*/ +template +lazy_list par(lazy_list const & l1, lazy_list const & l2, unsigned check_ms = g_small_sleep) { + return lazy_list([=]() { + typename lazy_list::maybe_pair r1; + typename lazy_list::maybe_pair r2; + std::atomic done1(false); + std::atomic done2(false); + interruptible_thread th1([&]() { + try { + r1 = l1.pull(); + } catch (...) { + r1 = typename lazy_list::maybe_pair(); + } + done1 = true; + }); + interruptible_thread th2([&]() { + try { + r2 = l2.pull(); + } catch (...) { + r2 = typename lazy_list::maybe_pair(); + } + done2 = true; + }); + try { + std::chrono::milliseconds small(check_ms); + while (!done1 && !done2) { + check_interrupted(); + std::this_thread::sleep_for(small); + } + th1.request_interrupt(); + th2.request_interrupt(); + th1.join(); + th2.join(); + // TODO(Leo): check why the following commented code does not work + // if (r1 && r2) { + // lazy_list tail([=]() { return some(mk_pair(r2->first, par(r1->second, r2->second))); }); + // return some(mk_pair(r1->first, tail)); + // } else + if (r1) { + return some(mk_pair(r1->first, par(r1->second, l2))); + } else if (r2) { + return some(mk_pair(r2->first, par(l1, r2->second))); + } else { + return r2; + } + } catch (...) { + th1.request_interrupt(); + th2.request_interrupt(); + th1.join(); + th2.join(); + throw; + } + }); +} } diff --git a/src/util/optional.h b/src/util/optional.h index 0c532ff76..c97a725ff 100644 --- a/src/util/optional.h +++ b/src/util/optional.h @@ -23,10 +23,6 @@ public: optional(T const & v):m_some(true) { new (&m_value) T(v); } - template - optional(Args&&... args):m_some(true) { - new (&m_value) T(args...); - } optional(optional const & other):m_some(other.m_some) { if (m_some) new (&m_value) T(other.m_value); @@ -35,6 +31,10 @@ public: if (m_some) m_value = std::move(other.m_value); } + template + optional(Args&&... args):m_some(true) { + new (&m_value) T(args...); + } ~optional() { if (m_some) m_value.~T();