<commit_before>/**
 * Copyright (c) 2012-2014, <NAME> and <NAME>
 * Released under a BSD3 licence.
 *
 * C++ implementation courtesy of International Telematics Ltd.
 */
#ifndef _SODIUM_SODIUM_H_
#define _SODIUM_SODIUM_H_

#include <sodium/light_ptr.h>
#include <sodium/transaction.h>
#include <functional>
#include <boost/optional.hpp>
#include <memory>
#include <list>
#include <set>
#if defined(SODIUM_NO_EXCEPTIONS)
#include <stdlib.h>
#else
#include <stdexcept>
#endif
#include <vector>

#define SODIUM_CONSTANT_OPTIMIZATION

namespace sodium {
    template <class A, class P> class event;
    template <class A, class P> class behavior;
    template <class A, class P> class behavior_sink;
    template <class A, class P> class behavior_loop;
    template <class A, class P> class event_loop;
    template <class A, class B, class P EQ_DEF_PART>
#if defined(SODIUM_NO_CXX11)
    behavior<B, P> apply(const behavior<lambda1<B,const A&>, P>& bf, const behavior<A, P>& ba);
#else
    behavior<B, P> apply(const behavior<std::function<B(const A&)>, P>& bf, const behavior<A, P>& ba);
#endif
    template <class A, class P EQ_DEF_PART>
    event<A, P> filter_optional(const event<boost::optional<A>, P>& input);
    template <class A, class P EQ_DEF_PART>
    event<A, P> split(const event<std::list<A>, P>& e);
    template <class A, class P EQ_DEF_PART>
    event<A, P> switch_e(const behavior<event<A, P>, P>& bea);
    template <class T, class P EQ_DEF_PART>
    behavior<typename T::time,P> clock(const T& t);

    namespace impl {

        class behavior_;
        class behavior_impl;

        class event_ {
        friend class behavior_;
        template <class A, class P> friend class sodium::event;
        template <class A, class P> friend class sodium::event_loop;
        template <class A, class P> friend class sodium::behavior;
        friend behavior_ switch_b(transaction_impl* trans, const behavior_& bba);
        friend SODIUM_SHARED_PTR<behavior_impl> hold(transaction_impl* trans0, const light_ptr& initValue, const event_& input);
        friend SODIUM_SHARED_PTR<behavior_impl> hold_lazy(transaction_impl* trans0, const std::function<light_ptr()>& initValue, const event_& input);
        template <class A, class B, class P>
#if defined(SODIUM_NO_CXX11)
        friend behavior<B, P> sodium::apply(const behavior<lambda1<B, const A&>, P>& bf, const behavior<A, P>& ba);
#else
        friend behavior<B, P> sodium::apply(const behavior<std::function<B(const A&)>, P>& bf, const behavior<A, P>& ba);
#endif
        friend behavior_ apply(transaction_impl* trans0, const behavior_& bf, const behavior_& ba);
#if defined(SODIUM_NO_CXX11)
        friend event_ map_(transaction_impl* trans, const lambda1<light_ptr, const light_ptr&>& f, const event_& ev);
#else
        friend event_ map_(transaction_impl* trans, const std::function<light_ptr(const light_ptr&)>& f, const event_& ev);
#endif
        friend behavior_ map_(transaction_impl* trans,
#if defined(SODIUM_NO_CXX11)
            const lambda1<light_ptr, const light_ptr&>& f,
#else
            const std::function<light_ptr(const light_ptr&)>& f,
#endif
            const behavior_& beh);
        friend event_ switch_e(transaction_impl* trans, const behavior_& bea);
        template <class A, class P>
        friend event<A, P> sodium::split(const event<std::list<A>, P>& e);
#if defined(SODIUM_NO_CXX11)
        friend struct snapshot_sample_now;
        friend struct switch_e_task;
        friend struct switch_b_handler;
#endif
        friend event_ filter_optional_(transaction_impl* trans, const event_& input,
            const std::function<boost::optional<light_ptr>(const light_ptr&)>& f);

        public:
#if defined(SODIUM_NO_CXX11)
            typedef lambda1<void, std::vector<light_ptr>&> sample_now_func;
#else
            typedef std::function<void(std::vector<light_ptr>&)> sample_now_func;
#endif

        protected:
            boost::intrusive_ptr<listen_impl_func<H_EVENT> > p_listen_impl;
            SODIUM_SHARED_PTR<sample_now_func> p_sample_now;

        public:
            event_();
            event_(const boost::intrusive_ptr<listen_impl_func<H_EVENT> >& p_listen_impl,
                   const SODIUM_SHARED_PTR<sample_now_func>& p_sample_now)
                : p_listen_impl(p_listen_impl), p_sample_now(p_sample_now) {}
            event_(const boost::intrusive_ptr<listen_impl_func<H_EVENT> >& p_listen_impl,
                   sample_now_func* p_sample_now)
                : p_listen_impl(p_listen_impl), p_sample_now(p_sample_now) {}

#if defined(SODIUM_CONSTANT_OPTIMIZATION)
            bool is_never() const { return !impl::alive(p_listen_impl); }
#endif

        protected:

            /*!
             * listen to events.
             */
#if defined(SODIUM_NO_CXX11)
            lambda0<void>* listen_raw(
#else
            std::function<void()>* listen_raw(
#endif
                        transaction_impl* trans0,
                        const SODIUM_SHARED_PTR<impl::node>& target,
#if defined(SODIUM_NO_CXX11)
                        lambda3<void, const SODIUM_SHARED_PTR<impl::node>&, transaction_impl*, const light_ptr&>* handle,
#else
                        std::function<void(const SODIUM_SHARED_PTR<impl::node>&, transaction_impl*, const light_ptr&)>* handle,
#endif
                        bool suppressEarlierFirings,
                        bool pushSampleNows) const;

            /*!
             * This is far more efficient than add_cleanup because it modifies the event
             * in place.
             */
#if defined(SODIUM_NO_CXX11)
            event_ unsafe_add_cleanup(lambda0<void>* cleanup)
#else
            event_ unsafe_add_cleanup(std::function<void()>* cleanup)
#endif
            {
                boost::intrusive_ptr<listen_impl_func<H_STRONG> > li(
                    reinterpret_cast<listen_impl_func<H_STRONG>*>(p_listen_impl.get()));
                if (cleanup != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup);
                    else {
                        (*cleanup)();
                        delete cleanup;
                    }
                }
                return *this;
            }

            /*!
             * This is far more efficient than add_cleanup because it modifies the event
             * in place.
             */
#if defined(SODIUM_NO_CXX11)
            event_ unsafe_add_cleanup(lambda0<void>* cleanup1, lambda0<void>* cleanup2)
#else
            event_ unsafe_add_cleanup(std::function<void()>* cleanup1, std::function<void()>* cleanup2)
#endif
            {
                boost::intrusive_ptr<listen_impl_func<H_STRONG> > li(
                    reinterpret_cast<listen_impl_func<H_STRONG>*>(p_listen_impl.get()));
                if (cleanup1 != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup1);
                    else {
                        (*cleanup1)();
                        delete cleanup1;
                    }
                }
                if (cleanup2 != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup2);
                    else {
                        (*cleanup2)();
                        delete cleanup2;
                    }
                }
                return *this;
            }

            /*!
             * This is far more efficient than add_cleanup because it modifies the event
             * in place.
             */
#if defined(SODIUM_NO_CXX11)
            event_ unsafe_add_cleanup(lambda0<void>* cleanup1, lambda0<void>* cleanup2, lambda0<void>* cleanup3)
#else
            event_ unsafe_add_cleanup(std::function<void()>* cleanup1, std::function<void()>* cleanup2, std::function<void()>* cleanup3)
#endif
            {
                boost::intrusive_ptr<listen_impl_func<H_STRONG> > li(
                    reinterpret_cast<listen_impl_func<H_STRONG>*>(p_listen_impl.get()));
                if (cleanup1 != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup1);
                    else {
                        (*cleanup1)();
                        delete cleanup1;
                    }
                }
                if (cleanup2 != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup2);
                    else {
                        (*cleanup2)();
                        delete cleanup2;
                    }
                }
                if (cleanup3 != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup3);
                    else {
                        (*cleanup3)();
                        delete cleanup3;
                    }
                }
                return *this;
            }

            /*!
             * Create a new event that is like this event but has an extra cleanup.
             */
#if defined(SODIUM_NO_CXX11)
            event_ add_cleanup_(transaction_impl* trans, lambda0<void>* cleanup) const;
#else
            event_ add_cleanup_(transaction_impl* trans, std::function<void()>* cleanup) const;
#endif
            behavior_ hold_(transaction_impl* trans, const light_ptr& initA) const;
            behavior_ hold_lazy_(transaction_impl* trans, const std::function<light_ptr()>& initA) const;
            event_ once_(transaction_impl* trans) const;
            event_ merge_(transaction_impl* trans, const event_& other) const;
#if defined(SODIUM_NO_CXX11)
            event_ coalesce_(transaction_impl* trans, const lambda2<light_ptr, const light_ptr&, const light_ptr&>& combine) const;
#else
            event_ coalesce_(transaction_impl* trans, const std::function<light_ptr(const light_ptr&, const light_ptr&)>& combine) const;
#endif
            event_ last_firing_only_(transaction_impl* trans) const;
#if defined(SODIUM_NO_CXX11)
            event_ snapshot_(transaction_impl* trans, const behavior_& beh, const lambda2<light_ptr, const light_ptr&, const light_ptr&>& combine) const;
            event_ filter_(transaction_impl* trans, const lambda1<bool, const light_ptr&>& pred) const;
#else
            event_ snapshot_(transaction_impl* trans, const behavior_& beh, const std::function<light_ptr(const light_ptr&, const light_ptr&)>& combine) const;
            event_ filter_(transaction_impl* trans, const std::function<bool(const light_ptr&)>& pred) const;
#endif

            void sample_now(std::vector<light_ptr>& values) const {
                if (p_sample_now != NULL)
                    (*p_sample_now)(values);
            }

#if defined(SODIUM_NO_CXX11)
            lambda0<void>* listen_impl(
#else
            std::function<void()>* listen_impl(
#endif
                transaction_impl* trans,
                const SODIUM_SHARED_PTR<impl::node>& target,
                SODIUM_SHARED_PTR<holder> h,
                bool suppressEarlierFirings) const
            {
                boost::intrusive_ptr<listen_impl_func<H_STRONG> > li(
                    reinterpret_cast<listen_impl_func<H_STRONG>*>(p_listen_impl.get()));
                if (alive(li))
                    return (*li->func)(trans, target, h, suppressEarlierFirings);
                else
                    return NULL;
            }
        };
#if defined(SODIUM_NO_CXX11)
        template <class A, class B>
        class _de_type : public i_lambda1<light_ptr, const light_ptr&>
        {
        private:
            lambda1<B,const A&> f;
        public:
            _de_type(const lambda1<B,const A&>& f) : f(f) {}
            virtual light_ptr operator () (const light_ptr& a) const
            {
                return light_ptr::create<B>(f(*a.cast_ptr<A>(NULL)));
            }
        };
        #define SODIUM_DETYPE_FUNCTION1(A,B,f) new sodium::impl::_de_type<A,B>(f)
        event_ map_(transaction_impl* trans, const lambda1<light_ptr, const light_ptr&>& f, const event_& ca);
#else
        #define SODIUM_DETYPE_FUNCTION1(A,B,f) \
                   [f] (const light_ptr& a) -> light_ptr { \
                        return light_ptr::create<B>(f(*a.cast_ptr<A>(NULL))); \
                   }
        event_ map_(transaction_impl* trans, const std::function<light_ptr(const light_ptr&)>& f, const event_& ca);
#endif

        /*!
         * Function to push a value into an event
         */
        void send(const SODIUM_SHARED_PTR<node>& n, transaction_impl* trans, const light_ptr& ptr);

        /*!
         * Creates an event, that values can be pushed into using impl::send(). 
         */
        SODIUM_TUPLE<
                event_,
                SODIUM_SHARED_PTR<node>
            > unsafe_new_event(event_::sample_now_func* sample_now_func = NULL);

        struct behavior_impl {
            behavior_impl();
            behavior_impl(
                const event_& updates,
                const SODIUM_SHARED_PTR<behavior_impl>& parent);
            virtual ~behavior_impl();

            virtual const light_ptr& sample() const = 0;
            virtual const light_ptr& newValue() const = 0;

            event_ updates;  // Having this here allows references to behavior to keep the
                             // underlying event's cleanups alive, and provides access to the
                             // underlying event, for certain primitives.

#if defined(SODIUM_NO_CXX11)
            lambda0<void>* kill;
#else
            std::function<void()>* kill;
#endif
            SODIUM_SHARED_PTR<behavior_impl> parent;

#if defined(SODIUM_NO_CXX11)
            lambda3<lambda0<void>, transaction_impl*, const SODIUM_SHARED_PTR<node>&,
                             const lambda2<void, transaction_impl*, const light_ptr&>&> listen_value_raw() const;
#else
            std::function<std::function<void()>(transaction_impl*, const SODIUM_SHARED_PTR<node>&,
                             const std::function<void(transaction_impl*, const light_ptr&)>&)> listen_value_raw() const;
#endif
        };

        SODIUM_SHARED_PTR<behavior_impl> hold(transaction_impl* trans0,
                            const light_ptr& initValue,
                            const event_& input);
        SODIUM_SHARED_PTR<behavior_impl> hold_lazy(transaction_impl* trans0,
                            const std::function<light_ptr()>& initValue,
                            const event_& input);

        struct behavior_impl_constant : behavior_impl {
            behavior_impl_constant(const light_ptr& k) : k(k) {}
            light_ptr k;
            virtual const light_ptr& sample() const { return k; }
            virtual const light_ptr& newValue() const { return k; }
        };

        template <class state_t>
        struct behavior_impl_concrete : behavior_impl {
            behavior_impl_concrete(
                const event_& updates,
                const state_t& state,
                const SODIUM_SHARED_PTR<behavior_impl>& parent)
            : behavior_impl(updates, parent),
              state(state)
            {
            }
            state_t state;

            virtual const light_ptr& sample() const { return state.sample(); }
            virtual const light_ptr& newValue() const { return state.newValue(); }
        };

        struct behavior_impl_loop : behavior_impl {
            behavior_impl_loop(
                const event_& updates,
                const SODIUM_SHARED_PTR<SODIUM_SHARED_PTR<behavior_impl> >& pLooped,
                const SODIUM_SHARED_PTR<behavior_impl>& parent)
            : behavior_impl(updates, parent),
              pLooped(pLooped)
            {
            }
            SODIUM_SHARED_PTR<SODIUM_SHARED_PTR<behavior_impl> > pLooped;

            void assertLooped() const {
                if (!*pLooped)
                    throw std::runtime_error("behavior_loop sampled before it was looped");
            }

            virtual const light_ptr& sample() const { assertLooped(); return (*pLooped)->sample(); }
            virtual const light_ptr& newValue() const { assertLooped(); return (*pLooped)->newValue(); }
        };

        struct behavior_state {
            behavior_state(const light_ptr& initA) : current(initA) {}
            light_ptr current;
            boost::optional<light_ptr> update;
            const light_ptr& sample() const { return current; }
            const light_ptr& newValue() const { return update ? update.get() : current; }
            void finalize() {
                current = update.get();
                update = boost::optional<light_ptr>();
            }
        };

        struct behavior_state_lazy {
            behavior_state_lazy(const std::function<light_ptr()>& initA)
            : pInitA(new std::function<light_ptr()>(initA)) {}
            std::function<light_ptr()>* pInitA;
            boost::optional<light_ptr> current;
            boost::optional<light_ptr> update;
            const light_ptr& sample() const {
                if (!current) {
                    const_cast<behavior_state_lazy*>(this)->current = boost::optional<light_ptr>((*pInitA)());
                    delete pInitA;
                    const_cast<behavior_state_lazy*>(this)->pInitA = NULL;
                }
                return current.get();
            }
            const light_ptr& newValue() const { return update ? update.get() : sample(); }
            void finalize() {
                current = update;
                update = boost::optional<light_ptr>();
            }
        };

        class behavior_ {
            friend impl::event_ underlying_event(const behavior_& beh);
            public:
                behavior_();
                behavior_(behavior_impl* impl);
                behavior_(const SODIUM_SHARED_PTR<behavior_impl>& impl);
                behavior_(const light_ptr& a);
                SODIUM_SHARED_PTR<impl::behavior_impl> impl;

#if defined(SODIUM_CONSTANT_OPTIMIZATION)
                /*!
                 * For optimization, if this behavior is a constant, then return its value.
                 */
                boost::optional<light_ptr> get_constant_value() const;
#endif

                event_ value_(transaction_impl* trans) const;
                const event_& updates_() const { return impl->updates; }
        };

#if defined(SODIUM_NO_CXX11)
        behavior_ map_(transaction_impl* trans, const lambda1<light_ptr, const light_ptr&>& f,
            const behavior_& beh);
#else
        behavior_ map_(transaction_impl* trans, const std::function<light_ptr(const light_ptr&)>& f,
            const behavior_& beh);
#endif

        template <class S>
        struct collect_state {
            collect_state(const S& s) : s(s) {}
            S s;
        };

#if defined(SODIUM_NO_CXX11)
        template <class A, class S, class B>
        struct collect_handler {
            collect_handler(const SODIUM_SHARED_PTR<collect_state<S> >& pState,
                            const lambda2<SODIUM_TUPLE<B, S>, const A&, const S&>& f)
            : pState(pState), f(f) {}
            SODIUM_SHARED_PTR<collect_state<S> > pState;
            lambda2<SODIUM_TUPLE<B, S>, const A&, const S&> f;
            virtual void operator () (const SODIUM_SHARED_PTR<node>& target, transaction_impl* trans,
                                      const light_ptr& ptr) {
                SODIUM_TUPLE<B,S> outsSt = f(*ptr.cast_ptr<A>(NULL), pState->s);
                pState->s = SODIUM_TUPLE_GET<1>(outsSt);
                send(target, trans, light_ptr::create<B>(SODIUM_TUPLE_GET<0>(outsSt)));
            }
        };
#endif
    }  // end namespace impl

#if defined(SODIUM_NO_CXX11)
    template <class A, class B>
    struct fst_arg : i_lambda2<A,const A&, const B&>  {
        virtual A operator () (const A& a, const B&) const { return a; }
    };
    template <class A, class B>
    struct snd_arg : i_lambda2<B,const A&, const B&> {
        virtual B operator () (const A&, const B& b) const { return b; }
    };
#endif

    template <class A, class P>
    class event;

    /*!
     * A like an event, but it tracks the input event's current value and causes it
     * always to be output once at the beginning for each listener.
     */
    template <class A, class P EQ_DEF_PART>
    class behavior : protected impl::behavior_ {
        template <class AA, class PP> friend class event;
        template <class AA, class PP> friend class behavior;
        template <class AA, class PP> friend class behavior_loop;
        template <class AA, class BB, class PP>
#if defined(SODIUM_NO_CXX11)
        friend behavior<BB, PP> apply(const behavior<lambda1<BB, const AA&>, PP>& bf, const behavior<AA, PP>& ba);
#else
        friend behavior<BB, PP> apply(const behavior<std::function<BB(const AA&)>, PP>& bf, const behavior<AA, PP>& ba);
#endif
        template <class AA, class PP>
        friend behavior<AA, PP> switch_b(const behavior<behavior<AA, PP>, PP>& bba);
        template <class AA, class PP>
        friend event<AA, PP> switch_e(const behavior<event<AA, PP>, PP>& bea);
        template <class TT, class PP>
        friend behavior<typename TT::time,PP> clock(const TT& t);
        private:
            behavior(const SODIUM_SHARED_PTR<impl::behavior_impl>& impl)
                : impl::behavior_(impl)
            {
            }

        protected:
            behavior() {}
            behavior(const impl::behavior_& beh) : impl::behavior_(beh) {}

        public:
            /*!
             * Constant value.
             */
            behavior(const A& a)
                : impl::behavior_(light_ptr::create<A>(a))
            {
            }

            /*!
             * Sample the value of this behavior.
             */
            A sample() const {
                transaction<P> trans;
                return *impl->sample().template cast_ptr<A>(NULL);
            }

            /*!
             * Returns a new behavior with the specified cleanup added to it, such that
             * it will be executed when no copies of the new behavior are referenced.
             */
#if defined(SODIUM_NO_CXX11)
            behavior<A, P> add_cleanup(const lambda0<void>& cleanup) const {
#else
            behavior<A, P> add_cleanup(const std::function<void()>& cleanup) const {
#endif
                transaction<P> trans;
                return updates().add_cleanup(cleanup).hold(sample());
            }

            /*!
             * Map a function over this behaviour to modify the output value.
             */
            template <class B>
#if defined(SODIUM_NO_CXX11)
            behavior<B, P> map(const lambda1<B, const A&>& f) const {
#else
            behavior<B, P> map(const std::function<B(const A&)>& f) const {
#endif
                transaction<P> trans;
                return behavior<B, P>(impl::map_(trans.impl(), SODIUM_DETYPE_FUNCTION1(A,B,f), *this));
            }

            /*!
             * Map a function over this behaviour to modify the output value.
             *
             * g++-4.7.2 has a bug where, under a 'using namespace std' it will interpret
             * b.template map<A>(f) as if it were std::map. If you get this problem, you can
             * work around it with map_.
             */
            template <class B>
#if defined(SODIUM_NO_CXX11)
            behavior<B, P> map_(const lambda1<B, const A&>& f) const {
#else
            behavior<B, P> map_(const std::function<B(const A&)>& f) const {
#endif
                transaction<P> trans;
                return behavior<B, P>(impl::map_(trans.impl(), SODIUM_DETYPE_FUNCTION1(A,B,f), *this));
            }

            /*!
             * Returns an event giving the updates to a behavior. If this behavior was created
             * by a hold, then this gives you back an event equivalent to the one that was held.
             */
            event<A, P> updates() const {
                return event<A, P>(impl->updates);
            }

            /*!
             * Returns an event describing the value of a behavior, where there's an initial event
             * giving the current value.
             */
            event<A, P> value() const {
                transaction<P> trans;
                return event<A, P>(value_(trans.impl()));
            }

            /**
             * Transform a behavior with a generalized state loop (a mealy machine). The function
             * is passed the input and the old state and returns the new state and output value.
             */
            template <class S, class B>
            behavior<B, P> collect(
                const S& initS,
#if defined(SODIUM_NO_CXX11)
                const lambda2<SODIUM_TUPLE<B, S>, const A&, const S&>& f
#else
                const std::function<std::tuple<B, S>(const A&, const S&)>& f
#endif
            ) const
            {
                transaction<P> trans;
#if defined(SODIUM_NO_CXX11)
                event<A, P> ea = updates().coalesce(lambda2<A,A,A>(new snd_arg<A,A>));
#else
                auto ea = updates().coalesce([] (const A&, const A& snd) -> A { return snd; });
#endif
                A za = sample();
                SODIUM_TUPLE<B,S> zbs = f(za, initS);
                SODIUM_SHARED_PTR<impl::collect_state<S> > pState(new impl::collect_state<S>(SODIUM_TUPLE_GET<1>(zbs)));
                SODIUM_TUPLE<impl::event_,SODIUM_SHARED_PTR<impl::node> > p = impl::unsafe_new_event();
#if defined(SODIUM_NO_CXX11)
                lambda0<void>* kill = updates().listen_raw(trans.impl(), SODIUM_TUPLE_GET<1>(p),
                    new lambda3<void, const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&>(
                        new impl::collect_handler<A,S,B>(pState, f)
                    ), false, false);
#else
                auto kill = updates().listen_raw(trans.impl(), SODIUM_TUPLE_GET<1>(p),
                    new std::function<void(const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&)>(
                        [pState, f] (const SODIUM_SHARED_PTR<impl::node>& target, impl::transaction_impl* trans, const light_ptr& ptr) {
                            SODIUM_TUPLE<B,S> outsSt = f(*ptr.cast_ptr<A>(NULL), pState->s);
                            pState->s = SODIUM_TUPLE_GET<1>(outsSt);
                            send(target, trans, light_ptr::create<B>(SODIUM_TUPLE_GET<0>(outsSt)));
                        }), false, false);
#endif
                // TO DO: Convert to hold lazy
                return event<B, P>(SODIUM_TUPLE_GET<0>(p).unsafe_add_cleanup(kill)).hold(SODIUM_TUPLE_GET<0>(zbs));
            }

    };  // end class behavior

#if defined(SODIUM_NO_CXX11)
    namespace impl {
        template <class A>
        struct listen_wrap : i_lambda3<void, const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&> {
            listen_wrap(const lambda1<void, const A&>& handle) : handle(handle) {}
            lambda1<void, const A&> handle;
            virtual void operator () (const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl* trans, const light_ptr& ptr) const {
                handle(*ptr.cast_ptr<A>(NULL));
            }
        };
        struct null_action : i_lambda0<void> {
            virtual void operator () () const {}
        };
        template <class A>
        struct detype_combine : i_lambda2<light_ptr, const light_ptr&, const light_ptr&> {
            detype_combine(const lambda2<A, const A&, const A&>& combine) : combine(combine) {}
            lambda2<A, const A&, const A&> combine;
            virtual light_ptr operator () (const light_ptr& a, const light_ptr& b) const {
                return light_ptr::create<A>(combine(*a.cast_ptr<A>(NULL), *b.cast_ptr<A>(NULL)));
            }
        };
        template <class A>
        struct detype_pred : i_lambda1<bool, const light_ptr&> {
            detype_pred(const lambda1<bool, A>& pred) : pred(pred) {}
            lambda1<bool, A> pred;
            virtual bool operator () (const light_ptr& a) const {
                return pred(*a.cast_ptr<A>(NULL));
            }
        };
        template <class A, class B, class C>
        struct detype_snapshot : i_lambda2<light_ptr, const light_ptr&, const light_ptr&> {
            detype_snapshot(const lambda2<C, const A&, const B&>& combine) : combine(combine) {}
            lambda2<C, const A&, const B&> combine;
            virtual light_ptr operator () (const light_ptr& a, const light_ptr& b) const {
                return light_ptr::create<C>(combine(*a.cast_ptr<A>(NULL), *b.cast_ptr<B>(NULL)));
            }
        };
        template <class A>
        struct gate_handler : i_lambda2<boost::optional<A>, const A&, const bool&> {
            virtual boost::optional<A> operator () (const A& a, const bool& gated) {
                return gated ? boost::optional<A>(a) : boost::optional<A>();
            }
        };
        template <class A, class B>
        struct accum_handler : i_lambda3<void, const SODIUM_SHARED_PTR<node>&, transaction_impl*, const light_ptr&> {
            accum_handler(
                const SODIUM_SHARED_PTR<collect_state<B> >& pState,
                const lambda2<B, const A&, const B&>& f)
            : pState(pState), f(f) {}
            SODIUM_SHARED_PTR<collect_state<B> > pState;
            lambda2<B, const A&, const B&> f;

            virtual void operator () (const SODIUM_SHARED_PTR<node>& target, transaction_impl* trans, const light_ptr& ptr) const {
                pState->s = f(*ptr.cast_ptr<A>(NULL), pState->s);
                send(target, trans, light_ptr::create<B>(pState->s));
            }
        };
        template <class A>
        struct count_handler : i_lambda2<int,const A&,int> {
            virtual int operator () (const A&, int total) const {
                return total+1;
            }
        };
        template <class A>
        struct delay_handler : i_lambda1<std::list<A>, const A&> {
            virtual std::list<A> operator () (const A& a) const {
                std::list<A> as;
                as.push_back(a);
                return as;
            }
        };
    }
#endif

    template <class A, class P EQ_DEF_PART>
    class event : protected impl::event_ {
        template <class AA, class PP> friend class event;
        template <class AA, class PP> friend class event_sink;
        template <class AA, class PP> friend class behavior;
        template <class AA, class PP> friend class behavior_sink;
        template <class AA, class PP> friend class behavior_loop;
        template <class AA, class PP> friend class event_sink;
        template <class AA, class PP> friend event<AA, PP> filter_optional(const event<boost::optional<AA>, PP>& input);
        template <class AA, class PP> friend event<AA, PP> switch_e(const behavior<event<AA, PP>, PP>& bea);
        template <class AA, class PP> friend event<AA, PP> split(const event<std::list<AA>, PP>& e);
        template <class AA, class PP> friend class sodium::event_loop;
        public:
            /*!
             * The 'never' event (that never fires).
             */
            event() {}
        protected:
            event(const impl::event_& ev) : impl::event_(ev) {}
        public:
            /*!
             * High-level interface to obtain an event's value.
             */
#if defined(SODIUM_NO_CXX11)
            lambda0<void> listen(const lambda1<void, const A&>& handle) const {
#else
            std::function<void()> listen(const std::function<void(const A&)>& handle) const {
#endif
                transaction<P> trans;
#if defined(SODIUM_NO_CXX11)
                lambda0<void>* pKill = listen_raw(trans.impl(),
#else
                std::function<void()>* pKill = listen_raw(trans.impl(),
#endif
                    SODIUM_SHARED_PTR<impl::node>(new impl::node(SODIUM_IMPL_RANK_T_MAX)),
#if defined(SODIUM_NO_CXX11)
                    new lambda3<void, const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&>(
                        new impl::listen_wrap<A>(handle)
                    ), false, true);
#else
                    new std::function<void(const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&)>(
                        [handle] (const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl* trans, const light_ptr& ptr) {
                            handle(*ptr.cast_ptr<A>(NULL));
                        }), false, true);
#endif
                if (pKill != NULL) {
#if defined(SODIUM_NO_CXX11)
                    lambda0<void> kill(*pKill);
#else
                    std::function<void()> kill(*pKill);
#endif
                    delete pKill;
                    return kill;
                }
                else
#if defined(SODIUM_NO_CXX11)
                    return new impl::null_action();
#else
                    return [] () {};
#endif
            };

            /*!
             * Map a function over this event to modify the output value. The function must be
             * pure (referentially transparent), that is, it must not have effects.
             */
            template <class B>
#if defined(SODIUM_NO_CXX11)
            event<B, P> map(const lambda1<B, const A&>& f) const {
#else
            event<B, P> map(const std::function<B(const A&)>& f) const {
#endif
                transaction<P> trans;
                return event<B, P>(impl::map_(trans.impl(), SODIUM_DETYPE_FUNCTION1(A,B,f), *this));
            }

            /*!
             * Map a function over this event to modify the output value. Effects are allowed.
             */
            template <class B>
#if defined(SODIUM_NO_CXX11)
            event<B, P> map_effectful(const lambda1<B, const A&>& f) const {
#else
            event<B, P> map_effectful(const std::function<B(const A&)>& f) const {
#endif
                return this->template map_<B>(f);  // Same as map() for now but this may change!
            }

            /*!
             * Map a function over this event to modify the output value.
             *
             * g++-4.7.2 has a bug where, under a 'using namespace std' it will interpret
             * b.template map<A>(f) as if it were std::map. If you get this problem, you can
             * work around it with map_.
             */
            template <class B>
#if defined(SODIUM_NO_CXX11)
            event<B, P> map_(const lambda1<B, const A&>& f) const {
#else
            event<B, P> map_(const std::function<B(const A&)>& f) const {
#endif
                transaction<P> trans;
                return event<B, P>(impl::map_(trans.impl(), SODIUM_DETYPE_FUNCTION1(A,B,f), *this));
            }

            /*!
             * Merge two events. If both events fire in the same transaction, then the
             * output event will just give two firings within the same transaction.
             * This is allowed, but it is usually best avoided.
             */
            event<A, P> merge(const event<A, P>& other) const {
                transaction<P> trans;
                return event<A, P>(merge_(trans.impl(), other));
            }

            /*!
             * If there's more than one firing in a single transaction, combine them into
             * one using the specified combining function.
             *
             * If the event firings are ordered, then the first will appear at the left
             * input of the combining function. In most common cases it's best not to
             * make any assumptions about the ordering, and the combining function would
             * ideally be commutative.
             */
#if defined(SODIUM_NO_CXX11)
            event<A, P> coalesce(const lambda2<A, const A&, const A&>& combine) const
#else
            event<A, P> coalesce(const std::function<A(const A&, const A&)>& combine) const
#endif
            {
                transaction<P> trans;
                return event<A, P>(coalesce_(trans.impl(),
#if defined(SODIUM_NO_CXX11)
                    new impl::detype_combine<A>(combine)
#else
                    [combine] (const light_ptr& a, const light_ptr& b) -> light_ptr {
                        return light_ptr::create<A>(combine(*a.cast_ptr<A>(NULL), *b.cast_ptr<A>(NULL)));
                    }
#endif
                ));
            }

            /*!
             * If there's more than one firing in a single transaction, keep only the latest one.
             */
            event<A, P> coalesce() const
            {
                return coalesce(
#if defined(SODIUM_NO_CXX11)
                        new snd_arg<A,A>
#else
                        [] (const A&, const A& snd) -> A { return snd; }
#endif
                    );
            }

            /*!
             * Merge two streams of events of the same type, combining simultaneous
             * event occurrences.
             *
             * In the case where multiple event occurrences are simultaneous (i.e. all
             * within the same transaction), they are combined using the same logic as
             * 'coalesce'.
             */
#if defined(SODIUM_NO_CXX11)
            event<A, P> merge(const event<A, P>& other, const lambda2<A, const A&, const A&>& combine) const
#else
            event<A, P> merge(const event<A, P>& other, const std::function<A(const A&, const A&)>& combine) const
#endif
            {
                return merge(other).coalesce(combine);
            }

            /*!
             * Filter this event based on the specified predicate, passing through values
             * where the predicate returns true.
             */
#if defined(SODIUM_NO_CXX11)
            event<A, P> filter(const lambda1<bool, const A&>& pred) const
#else
            event<A, P> filter(const std::function<bool(const A&)>& pred) const
#endif
            {
                transaction<P> trans;
                return event<A, P>(filter_(trans.impl(),
#if defined(SODIUM_NO_CXX11)
                    new impl::detype_pred<A>(pred)
#else
                    [pred] (const light_ptr& a) {
                        return pred(*a.cast_ptr<A>(NULL));
                    }
#endif
                  ));
            }

            /*!
             * Create a behavior that holds at any given time the most recent value
             * that has arrived from this event. Since behaviors must always have a current
             * value, you must supply an initial value that it has until the first event
             * occurrence updates it.
             */
            behavior<A, P> hold(const A& initA) const
            {
                transaction<P> trans;
                return behavior<A, P>(hold_(trans.impl(), light_ptr::create<A>(initA)));
            }

        private:
            behavior<A, P> hold_lazy(const std::function<A()>& initA) const
            {
                transaction<P> trans;
                return behavior<A, P>(hold_lazy_(trans.impl(), [initA] () -> light_ptr { return light_ptr::create<A>(initA()); }));
            }
        public:

            /*!
             * Sample the behavior's value as at the transaction before the
             * current one, i.e. no changes from the current transaction are
             * taken.
             */
            template <class B, class C>
#if defined(SODIUM_NO_CXX11)
            event<C, P> snapshot(const behavior<B, P>& beh, const lambda2<C, const A&, const B&>& combine) const
#else
            event<C, P> snapshot(const behavior<B, P>& beh, const std::function<C(const A&, const B&)>& combine) const
#endif
            {
                transaction<P> trans;
                return event<C, P>(snapshot_(trans.impl(), beh,
#if defined(SODIUM_NO_CXX11)
                    new impl::detype_snapshot<A,B,C>(combine)
#else
                    [combine] (const light_ptr& a, const light_ptr& b) -> light_ptr {
                        return light_ptr::create<C>(combine(*a.cast_ptr<A>(NULL), *b.cast_ptr<B>(NULL)));
                    }
#endif
                ));
            }

            /*!
             * Sample the behavior's value as at the transaction before the
             * current one, i.e. no changes from the current transaction are
             * taken.
             */
            template <class B>
            event<B, P> snapshot(const behavior<B, P>& beh) const
            {
                return snapshot<B, B>(beh,
#if defined(SODIUM_NO_CXX11)
                    new snd_arg<A,B>
#else
                    [] (const A&, const B& b) { return b; }
#endif
                    );
            }

            /*!
             * Allow events through only when the behavior's value is true.
             */
            event<A, P> gate(const behavior<bool, P>& g) const
            {
                transaction<P> trans;
                return filter_optional<A, P>(snapshot<bool, boost::optional<A>>(
                    g,
#if defined(SODIUM_NO_CXX11)
                    new impl::gate_handler<A>()
#else
                    [] (const A& a, const bool& gated) {
                        return gated ? boost::optional<A>(a) : boost::optional<A>();
                    }
#endif
                ));
            }

            /*!
             * Adapt an event to a new event statefully.  Always outputs one output for each
             * input.
             */
            template <class S, class B>
            event<B, P> collect(
                const S& initS,
#if defined(SODIUM_NO_CXX11)
                const lambda2<SODIUM_TUPLE<B, S>, const A&, const S&>& f
#else
                const std::function<SODIUM_TUPLE<B, S>(const A&, const S&)>& f
#endif
            ) const
            {
                transaction<P> trans;
                SODIUM_SHARED_PTR<impl::collect_state<S> > pState(new impl::collect_state<S>(initS));
                SODIUM_TUPLE<impl::event_,SODIUM_SHARED_PTR<impl::node> > p = impl::unsafe_new_event();
#if defined(SODIUM_NO_CXX11)
                lambda0<void>* kill = listen_raw(trans.impl(), SODIUM_TUPLE_GET<1>(p),
                    new impl::collect_handler<A,S,B>(pState, f), false, true);
#else
                auto kill = listen_raw(trans.impl(), std::get<1>(p),
                    new std::function<void(const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&)>(
                        [pState, f] (const SODIUM_SHARED_PTR<impl::node>& target, impl::transaction_impl* trans, const light_ptr& ptr) {
                            auto outsSt = f(*ptr.cast_ptr<A>(NULL), pState->s);
                            pState->s = std::get<1>(outsSt);
                            send(target, trans, light_ptr::create<B>(std::get<0>(outsSt)));
                        }), false, true);
#endif
                return SODIUM_TUPLE_GET<0>(p).unsafe_add_cleanup(kill);
            }

            template <class B>
            event<B, P> accum_e(
                const B& initB,
#if defined(SODIUM_NO_CXX11)
                const lambda2<B, const A&, const B&>& f
#else
                const std::function<B(const A&, const B&)>& f
#endif
            ) const
            {
                transaction<P> trans;
                SODIUM_SHARED_PTR<impl::collect_state<B> > pState(new impl::collect_state<B>(initB));
                SODIUM_TUPLE<impl::event_,SODIUM_SHARED_PTR<impl::node> > p = impl::unsafe_new_event();
#if defined(SODIUM_NO_CXX11)
                lambda0<void>* kill = listen_raw(trans.impl(), SODIUM_TUPLE_GET<1>(p),
                    new impl::accum_handler<A,B>(pState, f)
#else
                auto kill = listen_raw(trans.impl(), SODIUM_TUPLE_GET<1>(p),
                    new std::function<void(const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&)>(
                        [pState, f] (const SODIUM_SHARED_PTR<impl::node>& target, impl::transaction_impl* trans, const light_ptr& ptr) {
                            pState->s = f(*ptr.cast_ptr<A>(NULL), pState->s);
                            send(target, trans, light_ptr::create<B>(pState->s));
                        })
#endif
                    , false, true);
                return event<B, P>(SODIUM_TUPLE_GET<0>(p).unsafe_add_cleanup(kill));
            }

            template <class B>
            behavior<B, P> accum(
                const B& initB,<commit_msg>Add sample_lazy, collect_lazy, and accum_e_lazy so the user can sample things in a lazy way<commit_after>/**
 * Copyright (c) 2012-2014, <NAME> and <NAME>
 * Released under a BSD3 licence.
 *
 * C++ implementation courtesy of International Telematics Ltd.
 */
#ifndef _SODIUM_SODIUM_H_
#define _SODIUM_SODIUM_H_

#include <sodium/light_ptr.h>
#include <sodium/transaction.h>
#include <functional>
#include <boost/optional.hpp>
#include <memory>
#include <list>
#include <set>
#if defined(SODIUM_NO_EXCEPTIONS)
#include <stdlib.h>
#else
#include <stdexcept>
#endif
#include <vector>

#define SODIUM_CONSTANT_OPTIMIZATION

namespace sodium {
    template <class A, class P> class event;
    template <class A, class P> class behavior;
    template <class A, class P> class behavior_sink;
    template <class A, class P> class behavior_loop;
    template <class A, class P> class event_loop;
    template <class A, class B, class P EQ_DEF_PART>
#if defined(SODIUM_NO_CXX11)
    behavior<B, P> apply(const behavior<lambda1<B,const A&>, P>& bf, const behavior<A, P>& ba);
#else
    behavior<B, P> apply(const behavior<std::function<B(const A&)>, P>& bf, const behavior<A, P>& ba);
#endif
    template <class A, class P EQ_DEF_PART>
    event<A, P> filter_optional(const event<boost::optional<A>, P>& input);
    template <class A, class P EQ_DEF_PART>
    event<A, P> split(const event<std::list<A>, P>& e);
    template <class A, class P EQ_DEF_PART>
    event<A, P> switch_e(const behavior<event<A, P>, P>& bea);
    template <class T, class P EQ_DEF_PART>
    behavior<typename T::time,P> clock(const T& t);

    namespace impl {

        class behavior_;
        class behavior_impl;

        class event_ {
        friend class behavior_;
        template <class A, class P> friend class sodium::event;
        template <class A, class P> friend class sodium::event_loop;
        template <class A, class P> friend class sodium::behavior;
        friend behavior_ switch_b(transaction_impl* trans, const behavior_& bba);
        friend SODIUM_SHARED_PTR<behavior_impl> hold(transaction_impl* trans0, const light_ptr& initValue, const event_& input);
        friend SODIUM_SHARED_PTR<behavior_impl> hold_lazy(transaction_impl* trans0, const std::function<light_ptr()>& initValue, const event_& input);
        template <class A, class B, class P>
#if defined(SODIUM_NO_CXX11)
        friend behavior<B, P> sodium::apply(const behavior<lambda1<B, const A&>, P>& bf, const behavior<A, P>& ba);
#else
        friend behavior<B, P> sodium::apply(const behavior<std::function<B(const A&)>, P>& bf, const behavior<A, P>& ba);
#endif
        friend behavior_ apply(transaction_impl* trans0, const behavior_& bf, const behavior_& ba);
#if defined(SODIUM_NO_CXX11)
        friend event_ map_(transaction_impl* trans, const lambda1<light_ptr, const light_ptr&>& f, const event_& ev);
#else
        friend event_ map_(transaction_impl* trans, const std::function<light_ptr(const light_ptr&)>& f, const event_& ev);
#endif
        friend behavior_ map_(transaction_impl* trans,
#if defined(SODIUM_NO_CXX11)
            const lambda1<light_ptr, const light_ptr&>& f,
#else
            const std::function<light_ptr(const light_ptr&)>& f,
#endif
            const behavior_& beh);
        friend event_ switch_e(transaction_impl* trans, const behavior_& bea);
        template <class A, class P>
        friend event<A, P> sodium::split(const event<std::list<A>, P>& e);
#if defined(SODIUM_NO_CXX11)
        friend struct snapshot_sample_now;
        friend struct switch_e_task;
        friend struct switch_b_handler;
#endif
        friend event_ filter_optional_(transaction_impl* trans, const event_& input,
            const std::function<boost::optional<light_ptr>(const light_ptr&)>& f);

        public:
#if defined(SODIUM_NO_CXX11)
            typedef lambda1<void, std::vector<light_ptr>&> sample_now_func;
#else
            typedef std::function<void(std::vector<light_ptr>&)> sample_now_func;
#endif

        protected:
            boost::intrusive_ptr<listen_impl_func<H_EVENT> > p_listen_impl;
            SODIUM_SHARED_PTR<sample_now_func> p_sample_now;

        public:
            event_();
            event_(const boost::intrusive_ptr<listen_impl_func<H_EVENT> >& p_listen_impl,
                   const SODIUM_SHARED_PTR<sample_now_func>& p_sample_now)
                : p_listen_impl(p_listen_impl), p_sample_now(p_sample_now) {}
            event_(const boost::intrusive_ptr<listen_impl_func<H_EVENT> >& p_listen_impl,
                   sample_now_func* p_sample_now)
                : p_listen_impl(p_listen_impl), p_sample_now(p_sample_now) {}

#if defined(SODIUM_CONSTANT_OPTIMIZATION)
            bool is_never() const { return !impl::alive(p_listen_impl); }
#endif

        protected:

            /*!
             * listen to events.
             */
#if defined(SODIUM_NO_CXX11)
            lambda0<void>* listen_raw(
#else
            std::function<void()>* listen_raw(
#endif
                        transaction_impl* trans0,
                        const SODIUM_SHARED_PTR<impl::node>& target,
#if defined(SODIUM_NO_CXX11)
                        lambda3<void, const SODIUM_SHARED_PTR<impl::node>&, transaction_impl*, const light_ptr&>* handle,
#else
                        std::function<void(const SODIUM_SHARED_PTR<impl::node>&, transaction_impl*, const light_ptr&)>* handle,
#endif
                        bool suppressEarlierFirings,
                        bool pushSampleNows) const;

            /*!
             * This is far more efficient than add_cleanup because it modifies the event
             * in place.
             */
#if defined(SODIUM_NO_CXX11)
            event_ unsafe_add_cleanup(lambda0<void>* cleanup)
#else
            event_ unsafe_add_cleanup(std::function<void()>* cleanup)
#endif
            {
                boost::intrusive_ptr<listen_impl_func<H_STRONG> > li(
                    reinterpret_cast<listen_impl_func<H_STRONG>*>(p_listen_impl.get()));
                if (cleanup != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup);
                    else {
                        (*cleanup)();
                        delete cleanup;
                    }
                }
                return *this;
            }

            /*!
             * This is far more efficient than add_cleanup because it modifies the event
             * in place.
             */
#if defined(SODIUM_NO_CXX11)
            event_ unsafe_add_cleanup(lambda0<void>* cleanup1, lambda0<void>* cleanup2)
#else
            event_ unsafe_add_cleanup(std::function<void()>* cleanup1, std::function<void()>* cleanup2)
#endif
            {
                boost::intrusive_ptr<listen_impl_func<H_STRONG> > li(
                    reinterpret_cast<listen_impl_func<H_STRONG>*>(p_listen_impl.get()));
                if (cleanup1 != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup1);
                    else {
                        (*cleanup1)();
                        delete cleanup1;
                    }
                }
                if (cleanup2 != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup2);
                    else {
                        (*cleanup2)();
                        delete cleanup2;
                    }
                }
                return *this;
            }

            /*!
             * This is far more efficient than add_cleanup because it modifies the event
             * in place.
             */
#if defined(SODIUM_NO_CXX11)
            event_ unsafe_add_cleanup(lambda0<void>* cleanup1, lambda0<void>* cleanup2, lambda0<void>* cleanup3)
#else
            event_ unsafe_add_cleanup(std::function<void()>* cleanup1, std::function<void()>* cleanup2, std::function<void()>* cleanup3)
#endif
            {
                boost::intrusive_ptr<listen_impl_func<H_STRONG> > li(
                    reinterpret_cast<listen_impl_func<H_STRONG>*>(p_listen_impl.get()));
                if (cleanup1 != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup1);
                    else {
                        (*cleanup1)();
                        delete cleanup1;
                    }
                }
                if (cleanup2 != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup2);
                    else {
                        (*cleanup2)();
                        delete cleanup2;
                    }
                }
                if (cleanup3 != NULL) {
                    if (alive(li))
                        li->cleanups.push_front(cleanup3);
                    else {
                        (*cleanup3)();
                        delete cleanup3;
                    }
                }
                return *this;
            }

            /*!
             * Create a new event that is like this event but has an extra cleanup.
             */
#if defined(SODIUM_NO_CXX11)
            event_ add_cleanup_(transaction_impl* trans, lambda0<void>* cleanup) const;
#else
            event_ add_cleanup_(transaction_impl* trans, std::function<void()>* cleanup) const;
#endif
            behavior_ hold_(transaction_impl* trans, const light_ptr& initA) const;
            behavior_ hold_lazy_(transaction_impl* trans, const std::function<light_ptr()>& initA) const;
            event_ once_(transaction_impl* trans) const;
            event_ merge_(transaction_impl* trans, const event_& other) const;
#if defined(SODIUM_NO_CXX11)
            event_ coalesce_(transaction_impl* trans, const lambda2<light_ptr, const light_ptr&, const light_ptr&>& combine) const;
#else
            event_ coalesce_(transaction_impl* trans, const std::function<light_ptr(const light_ptr&, const light_ptr&)>& combine) const;
#endif
            event_ last_firing_only_(transaction_impl* trans) const;
#if defined(SODIUM_NO_CXX11)
            event_ snapshot_(transaction_impl* trans, const behavior_& beh, const lambda2<light_ptr, const light_ptr&, const light_ptr&>& combine) const;
            event_ filter_(transaction_impl* trans, const lambda1<bool, const light_ptr&>& pred) const;
#else
            event_ snapshot_(transaction_impl* trans, const behavior_& beh, const std::function<light_ptr(const light_ptr&, const light_ptr&)>& combine) const;
            event_ filter_(transaction_impl* trans, const std::function<bool(const light_ptr&)>& pred) const;
#endif

            void sample_now(std::vector<light_ptr>& values) const {
                if (p_sample_now != NULL)
                    (*p_sample_now)(values);
            }

#if defined(SODIUM_NO_CXX11)
            lambda0<void>* listen_impl(
#else
            std::function<void()>* listen_impl(
#endif
                transaction_impl* trans,
                const SODIUM_SHARED_PTR<impl::node>& target,
                SODIUM_SHARED_PTR<holder> h,
                bool suppressEarlierFirings) const
            {
                boost::intrusive_ptr<listen_impl_func<H_STRONG> > li(
                    reinterpret_cast<listen_impl_func<H_STRONG>*>(p_listen_impl.get()));
                if (alive(li))
                    return (*li->func)(trans, target, h, suppressEarlierFirings);
                else
                    return NULL;
            }
        };
#if defined(SODIUM_NO_CXX11)
        template <class A, class B>
        class _de_type : public i_lambda1<light_ptr, const light_ptr&>
        {
        private:
            lambda1<B,const A&> f;
        public:
            _de_type(const lambda1<B,const A&>& f) : f(f) {}
            virtual light_ptr operator () (const light_ptr& a) const
            {
                return light_ptr::create<B>(f(*a.cast_ptr<A>(NULL)));
            }
        };
        #define SODIUM_DETYPE_FUNCTION1(A,B,f) new sodium::impl::_de_type<A,B>(f)
        event_ map_(transaction_impl* trans, const lambda1<light_ptr, const light_ptr&>& f, const event_& ca);
#else
        #define SODIUM_DETYPE_FUNCTION1(A,B,f) \
                   [f] (const light_ptr& a) -> light_ptr { \
                        return light_ptr::create<B>(f(*a.cast_ptr<A>(NULL))); \
                   }
        event_ map_(transaction_impl* trans, const std::function<light_ptr(const light_ptr&)>& f, const event_& ca);
#endif

        /*!
         * Function to push a value into an event
         */
        void send(const SODIUM_SHARED_PTR<node>& n, transaction_impl* trans, const light_ptr& ptr);

        /*!
         * Creates an event, that values can be pushed into using impl::send(). 
         */
        SODIUM_TUPLE<
                event_,
                SODIUM_SHARED_PTR<node>
            > unsafe_new_event(event_::sample_now_func* sample_now_func = NULL);

        struct behavior_impl {
            behavior_impl();
            behavior_impl(
                const event_& updates,
                const SODIUM_SHARED_PTR<behavior_impl>& parent);
            virtual ~behavior_impl();

            virtual const light_ptr& sample() const = 0;
            virtual const light_ptr& newValue() const = 0;

            event_ updates;  // Having this here allows references to behavior to keep the
                             // underlying event's cleanups alive, and provides access to the
                             // underlying event, for certain primitives.

#if defined(SODIUM_NO_CXX11)
            lambda0<void>* kill;
#else
            std::function<void()>* kill;
#endif
            SODIUM_SHARED_PTR<behavior_impl> parent;

#if defined(SODIUM_NO_CXX11)
            lambda3<lambda0<void>, transaction_impl*, const SODIUM_SHARED_PTR<node>&,
                             const lambda2<void, transaction_impl*, const light_ptr&>&> listen_value_raw() const;
#else
            std::function<std::function<void()>(transaction_impl*, const SODIUM_SHARED_PTR<node>&,
                             const std::function<void(transaction_impl*, const light_ptr&)>&)> listen_value_raw() const;
#endif
        };

        SODIUM_SHARED_PTR<behavior_impl> hold(transaction_impl* trans0,
                            const light_ptr& initValue,
                            const event_& input);
        SODIUM_SHARED_PTR<behavior_impl> hold_lazy(transaction_impl* trans0,
                            const std::function<light_ptr()>& initValue,
                            const event_& input);

        struct behavior_impl_constant : behavior_impl {
            behavior_impl_constant(const light_ptr& k) : k(k) {}
            light_ptr k;
            virtual const light_ptr& sample() const { return k; }
            virtual const light_ptr& newValue() const { return k; }
        };

        template <class state_t>
        struct behavior_impl_concrete : behavior_impl {
            behavior_impl_concrete(
                const event_& updates,
                const state_t& state,
                const SODIUM_SHARED_PTR<behavior_impl>& parent)
            : behavior_impl(updates, parent),
              state(state)
            {
            }
            state_t state;

            virtual const light_ptr& sample() const { return state.sample(); }
            virtual const light_ptr& newValue() const { return state.newValue(); }
        };

        struct behavior_impl_loop : behavior_impl {
            behavior_impl_loop(
                const event_& updates,
                const SODIUM_SHARED_PTR<SODIUM_SHARED_PTR<behavior_impl> >& pLooped,
                const SODIUM_SHARED_PTR<behavior_impl>& parent)
            : behavior_impl(updates, parent),
              pLooped(pLooped)
            {
            }
            SODIUM_SHARED_PTR<SODIUM_SHARED_PTR<behavior_impl> > pLooped;

            void assertLooped() const {
                if (!*pLooped)
                    throw std::runtime_error("behavior_loop sampled before it was looped");
            }

            virtual const light_ptr& sample() const { assertLooped(); return (*pLooped)->sample(); }
            virtual const light_ptr& newValue() const { assertLooped(); return (*pLooped)->newValue(); }
        };

        struct behavior_state {
            behavior_state(const light_ptr& initA) : current(initA) {}
            light_ptr current;
            boost::optional<light_ptr> update;
            const light_ptr& sample() const { return current; }
            const light_ptr& newValue() const { return update ? update.get() : current; }
            void finalize() {
                current = update.get();
                update = boost::optional<light_ptr>();
            }
        };

        struct behavior_state_lazy {
            behavior_state_lazy(const std::function<light_ptr()>& initA)
            : pInitA(new std::function<light_ptr()>(initA)) {}
            std::function<light_ptr()>* pInitA;
            boost::optional<light_ptr> current;
            boost::optional<light_ptr> update;
            const light_ptr& sample() const {
                if (!current) {
                    const_cast<behavior_state_lazy*>(this)->current = boost::optional<light_ptr>((*pInitA)());
                    delete pInitA;
                    const_cast<behavior_state_lazy*>(this)->pInitA = NULL;
                }
                return current.get();
            }
            const light_ptr& newValue() const { return update ? update.get() : sample(); }
            void finalize() {
                current = update;
                update = boost::optional<light_ptr>();
            }
        };

        class behavior_ {
            friend impl::event_ underlying_event(const behavior_& beh);
            public:
                behavior_();
                behavior_(behavior_impl* impl);
                behavior_(const SODIUM_SHARED_PTR<behavior_impl>& impl);
                behavior_(const light_ptr& a);
                SODIUM_SHARED_PTR<impl::behavior_impl> impl;

#if defined(SODIUM_CONSTANT_OPTIMIZATION)
                /*!
                 * For optimization, if this behavior is a constant, then return its value.
                 */
                boost::optional<light_ptr> get_constant_value() const;
#endif

                event_ value_(transaction_impl* trans) const;
                const event_& updates_() const { return impl->updates; }
        };

#if defined(SODIUM_NO_CXX11)
        behavior_ map_(transaction_impl* trans, const lambda1<light_ptr, const light_ptr&>& f,
            const behavior_& beh);
#else
        behavior_ map_(transaction_impl* trans, const std::function<light_ptr(const light_ptr&)>& f,
            const behavior_& beh);
#endif

        template <class S>
        struct collect_state {
            collect_state(const std::function<S()>& s_lazy) : s_lazy(s_lazy) {}
            std::function<S()> s_lazy;
        };

#if defined(SODIUM_NO_CXX11)
        template <class A, class S, class B>
        struct collect_handler {
            collect_handler(const SODIUM_SHARED_PTR<collect_state<S> >& pState,
                            const lambda2<SODIUM_TUPLE<B, S>, const A&, const S&>& f)
            : pState(pState), f(f) {}
            SODIUM_SHARED_PTR<collect_state<S> > pState;
            lambda2<SODIUM_TUPLE<B, S>, const A&, const S&> f;
            virtual void operator () (const SODIUM_SHARED_PTR<node>& target, transaction_impl* trans,
                                      const light_ptr& ptr) {
                SODIUM_TUPLE<B,S> outsSt = f(*ptr.cast_ptr<A>(NULL), pState->s);
                pState->s = SODIUM_TUPLE_GET<1>(outsSt);
                send(target, trans, light_ptr::create<B>(SODIUM_TUPLE_GET<0>(outsSt)));
            }
        };
#endif
    }  // end namespace impl

#if defined(SODIUM_NO_CXX11)
    template <class A, class B>
    struct fst_arg : i_lambda2<A,const A&, const B&>  {
        virtual A operator () (const A& a, const B&) const { return a; }
    };
    template <class A, class B>
    struct snd_arg : i_lambda2<B,const A&, const B&> {
        virtual B operator () (const A&, const B& b) const { return b; }
    };
#endif

    template <class A, class P>
    class event;

    /*!
     * A like an event, but it tracks the input event's current value and causes it
     * always to be output once at the beginning for each listener.
     */
    template <class A, class P EQ_DEF_PART>
    class behavior : protected impl::behavior_ {
        template <class AA, class PP> friend class event;
        template <class AA, class PP> friend class behavior;
        template <class AA, class PP> friend class behavior_loop;
        template <class AA, class BB, class PP>
#if defined(SODIUM_NO_CXX11)
        friend behavior<BB, PP> apply(const behavior<lambda1<BB, const AA&>, PP>& bf, const behavior<AA, PP>& ba);
#else
        friend behavior<BB, PP> apply(const behavior<std::function<BB(const AA&)>, PP>& bf, const behavior<AA, PP>& ba);
#endif
        template <class AA, class PP>
        friend behavior<AA, PP> switch_b(const behavior<behavior<AA, PP>, PP>& bba);
        template <class AA, class PP>
        friend event<AA, PP> switch_e(const behavior<event<AA, PP>, PP>& bea);
        template <class TT, class PP>
        friend behavior<typename TT::time,PP> clock(const TT& t);
        private:
            behavior(const SODIUM_SHARED_PTR<impl::behavior_impl>& impl)
                : impl::behavior_(impl)
            {
            }

        protected:
            behavior() {}
            behavior(const impl::behavior_& beh) : impl::behavior_(beh) {}

        public:
            /*!
             * Constant value.
             */
            behavior(const A& a)
                : impl::behavior_(light_ptr::create<A>(a))
            {
            }

            /*!
             * Sample the value of this behavior.
             */
            A sample() const {
                transaction<P> trans;
                return *impl->sample().template cast_ptr<A>(NULL);
            }

            std::function<A()> sample_lazy() const {
                const SODIUM_SHARED_PTR<impl::behavior_impl>& impl(this->impl);
                return [impl] () -> A {
                    transaction<P> trans;
                    return *impl->sample().template cast_ptr<A>(NULL);
                };
            }

            /*!
             * Returns a new behavior with the specified cleanup added to it, such that
             * it will be executed when no copies of the new behavior are referenced.
             */
#if defined(SODIUM_NO_CXX11)
            behavior<A, P> add_cleanup(const lambda0<void>& cleanup) const {
#else
            behavior<A, P> add_cleanup(const std::function<void()>& cleanup) const {
#endif
                transaction<P> trans;
                return updates().add_cleanup(cleanup).hold(sample());
            }

            /*!
             * Map a function over this behaviour to modify the output value.
             */
            template <class B>
#if defined(SODIUM_NO_CXX11)
            behavior<B, P> map(const lambda1<B, const A&>& f) const {
#else
            behavior<B, P> map(const std::function<B(const A&)>& f) const {
#endif
                transaction<P> trans;
                return behavior<B, P>(impl::map_(trans.impl(), SODIUM_DETYPE_FUNCTION1(A,B,f), *this));
            }

            /*!
             * Map a function over this behaviour to modify the output value.
             *
             * g++-4.7.2 has a bug where, under a 'using namespace std' it will interpret
             * b.template map<A>(f) as if it were std::map. If you get this problem, you can
             * work around it with map_.
             */
            template <class B>
#if defined(SODIUM_NO_CXX11)
            behavior<B, P> map_(const lambda1<B, const A&>& f) const {
#else
            behavior<B, P> map_(const std::function<B(const A&)>& f) const {
#endif
                transaction<P> trans;
                return behavior<B, P>(impl::map_(trans.impl(), SODIUM_DETYPE_FUNCTION1(A,B,f), *this));
            }

            /*!
             * Returns an event giving the updates to a behavior. If this behavior was created
             * by a hold, then this gives you back an event equivalent to the one that was held.
             */
            event<A, P> updates() const {
                return event<A, P>(impl->updates);
            }

            /*!
             * Returns an event describing the value of a behavior, where there's an initial event
             * giving the current value.
             */
            event<A, P> value() const {
                transaction<P> trans;
                return event<A, P>(value_(trans.impl()));
            }

            /**
             * Transform a behavior with a generalized state loop (a mealy machine). The function
             * is passed the input and the old state and returns the new state and output value.
             */
            template <class S, class B>
            behavior<B, P> collect_lazy(
                const std::function<S()>& initS,
#if defined(SODIUM_NO_CXX11)
                const lambda2<SODIUM_TUPLE<B, S>, const A&, const S&>& f
#else
                const std::function<std::tuple<B, S>(const A&, const S&)>& f
#endif
            ) const
            {
                transaction<P> trans;
#if defined(SODIUM_NO_CXX11)
                event<A, P> ea = updates().coalesce(lambda2<A,A,A>(new snd_arg<A,A>));
#else
                auto ea = updates().coalesce([] (const A&, const A& snd) -> A { return snd; });
#endif
                std::function<A()> za_lazy = sample_lazy();
                std::function<SODIUM_TUPLE<B,S>()> zbs = [za_lazy, initS, f] () -> SODIUM_TUPLE<B,S> {
                    return f(za_lazy(), initS());
                };
                SODIUM_SHARED_PTR<impl::collect_state<S> > pState(new impl::collect_state<S>([zbs] () -> S {
                    return SODIUM_TUPLE_GET<1>(zbs());
                }));
                SODIUM_TUPLE<impl::event_,SODIUM_SHARED_PTR<impl::node> > p = impl::unsafe_new_event();
#if defined(SODIUM_NO_CXX11)
                lambda0<void>* kill = updates().listen_raw(trans.impl(), SODIUM_TUPLE_GET<1>(p),
                    new lambda3<void, const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&>(
                        new impl::collect_handler<A,S,B>(pState, f)
                    ), false, false);
#else
                auto kill = updates().listen_raw(trans.impl(), SODIUM_TUPLE_GET<1>(p),
                    new std::function<void(const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&)>(
                        [pState, f] (const SODIUM_SHARED_PTR<impl::node>& target, impl::transaction_impl* trans, const light_ptr& ptr) {
                            SODIUM_TUPLE<B,S> outsSt = f(*ptr.cast_ptr<A>(NULL), pState->s_lazy());
                            const S& new_s = SODIUM_TUPLE_GET<1>(outsSt);
                            pState->s_lazy = [new_s] () { return new_s; };
                            send(target, trans, light_ptr::create<B>(SODIUM_TUPLE_GET<0>(outsSt)));
                        }), false, false);
#endif
                return event<B, P>(SODIUM_TUPLE_GET<0>(p).unsafe_add_cleanup(kill)).hold_lazy([zbs] () -> B {
                    return SODIUM_TUPLE_GET<0>(zbs());
                });
            }

            /**
             * Transform a behavior with a generalized state loop (a mealy machine). The function
             * is passed the input and the old state and returns the new state and output value.
             */
            template <class S, class B>
            behavior<B, P> collect(
                const S& initS,
#if defined(SODIUM_NO_CXX11)
                const lambda2<SODIUM_TUPLE<B, S>, const A&, const S&>& f
#else
                const std::function<std::tuple<B, S>(const A&, const S&)>& f
#endif
            ) const
            {
                return collect_lazy<S, B>([initS] () -> S { return initS; }, f);
            }

    };  // end class behavior

#if defined(SODIUM_NO_CXX11)
    namespace impl {
        template <class A>
        struct listen_wrap : i_lambda3<void, const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&> {
            listen_wrap(const lambda1<void, const A&>& handle) : handle(handle) {}
            lambda1<void, const A&> handle;
            virtual void operator () (const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl* trans, const light_ptr& ptr) const {
                handle(*ptr.cast_ptr<A>(NULL));
            }
        };
        struct null_action : i_lambda0<void> {
            virtual void operator () () const {}
        };
        template <class A>
        struct detype_combine : i_lambda2<light_ptr, const light_ptr&, const light_ptr&> {
            detype_combine(const lambda2<A, const A&, const A&>& combine) : combine(combine) {}
            lambda2<A, const A&, const A&> combine;
            virtual light_ptr operator () (const light_ptr& a, const light_ptr& b) const {
                return light_ptr::create<A>(combine(*a.cast_ptr<A>(NULL), *b.cast_ptr<A>(NULL)));
            }
        };
        template <class A>
        struct detype_pred : i_lambda1<bool, const light_ptr&> {
            detype_pred(const lambda1<bool, A>& pred) : pred(pred) {}
            lambda1<bool, A> pred;
            virtual bool operator () (const light_ptr& a) const {
                return pred(*a.cast_ptr<A>(NULL));
            }
        };
        template <class A, class B, class C>
        struct detype_snapshot : i_lambda2<light_ptr, const light_ptr&, const light_ptr&> {
            detype_snapshot(const lambda2<C, const A&, const B&>& combine) : combine(combine) {}
            lambda2<C, const A&, const B&> combine;
            virtual light_ptr operator () (const light_ptr& a, const light_ptr& b) const {
                return light_ptr::create<C>(combine(*a.cast_ptr<A>(NULL), *b.cast_ptr<B>(NULL)));
            }
        };
        template <class A>
        struct gate_handler : i_lambda2<boost::optional<A>, const A&, const bool&> {
            virtual boost::optional<A> operator () (const A& a, const bool& gated) {
                return gated ? boost::optional<A>(a) : boost::optional<A>();
            }
        };
        template <class A, class B>
        struct accum_handler : i_lambda3<void, const SODIUM_SHARED_PTR<node>&, transaction_impl*, const light_ptr&> {
            accum_handler(
                const SODIUM_SHARED_PTR<collect_state<B> >& pState,
                const lambda2<B, const A&, const B&>& f)
            : pState(pState), f(f) {}
            SODIUM_SHARED_PTR<collect_state<B> > pState;
            lambda2<B, const A&, const B&> f;

            virtual void operator () (const SODIUM_SHARED_PTR<node>& target, transaction_impl* trans, const light_ptr& ptr) const {
                pState->s = f(*ptr.cast_ptr<A>(NULL), pState->s);
                send(target, trans, light_ptr::create<B>(pState->s));
            }
        };
        template <class A>
        struct count_handler : i_lambda2<int,const A&,int> {
            virtual int operator () (const A&, int total) const {
                return total+1;
            }
        };
        template <class A>
        struct delay_handler : i_lambda1<std::list<A>, const A&> {
            virtual std::list<A> operator () (const A& a) const {
                std::list<A> as;
                as.push_back(a);
                return as;
            }
        };
    }
#endif

    template <class A, class P EQ_DEF_PART>
    class event : protected impl::event_ {
        template <class AA, class PP> friend class event;
        template <class AA, class PP> friend class event_sink;
        template <class AA, class PP> friend class behavior;
        template <class AA, class PP> friend class behavior_sink;
        template <class AA, class PP> friend class behavior_loop;
        template <class AA, class PP> friend class event_sink;
        template <class AA, class PP> friend event<AA, PP> filter_optional(const event<boost::optional<AA>, PP>& input);
        template <class AA, class PP> friend event<AA, PP> switch_e(const behavior<event<AA, PP>, PP>& bea);
        template <class AA, class PP> friend event<AA, PP> split(const event<std::list<AA>, PP>& e);
        template <class AA, class PP> friend class sodium::event_loop;
        public:
            /*!
             * The 'never' event (that never fires).
             */
            event() {}
        protected:
            event(const impl::event_& ev) : impl::event_(ev) {}
        public:
            /*!
             * High-level interface to obtain an event's value.
             */
#if defined(SODIUM_NO_CXX11)
            lambda0<void> listen(const lambda1<void, const A&>& handle) const {
#else
            std::function<void()> listen(const std::function<void(const A&)>& handle) const {
#endif
                transaction<P> trans;
#if defined(SODIUM_NO_CXX11)
                lambda0<void>* pKill = listen_raw(trans.impl(),
#else
                std::function<void()>* pKill = listen_raw(trans.impl(),
#endif
                    SODIUM_SHARED_PTR<impl::node>(new impl::node(SODIUM_IMPL_RANK_T_MAX)),
#if defined(SODIUM_NO_CXX11)
                    new lambda3<void, const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&>(
                        new impl::listen_wrap<A>(handle)
                    ), false, true);
#else
                    new std::function<void(const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&)>(
                        [handle] (const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl* trans, const light_ptr& ptr) {
                            handle(*ptr.cast_ptr<A>(NULL));
                        }), false, true);
#endif
                if (pKill != NULL) {
#if defined(SODIUM_NO_CXX11)
                    lambda0<void> kill(*pKill);
#else
                    std::function<void()> kill(*pKill);
#endif
                    delete pKill;
                    return kill;
                }
                else
#if defined(SODIUM_NO_CXX11)
                    return new impl::null_action();
#else
                    return [] () {};
#endif
            };

            /*!
             * Map a function over this event to modify the output value. The function must be
             * pure (referentially transparent), that is, it must not have effects.
             */
            template <class B>
#if defined(SODIUM_NO_CXX11)
            event<B, P> map(const lambda1<B, const A&>& f) const {
#else
            event<B, P> map(const std::function<B(const A&)>& f) const {
#endif
                transaction<P> trans;
                return event<B, P>(impl::map_(trans.impl(), SODIUM_DETYPE_FUNCTION1(A,B,f), *this));
            }

            /*!
             * Map a function over this event to modify the output value. Effects are allowed.
             */
            template <class B>
#if defined(SODIUM_NO_CXX11)
            event<B, P> map_effectful(const lambda1<B, const A&>& f) const {
#else
            event<B, P> map_effectful(const std::function<B(const A&)>& f) const {
#endif
                return this->template map_<B>(f);  // Same as map() for now but this may change!
            }

            /*!
             * Map a function over this event to modify the output value.
             *
             * g++-4.7.2 has a bug where, under a 'using namespace std' it will interpret
             * b.template map<A>(f) as if it were std::map. If you get this problem, you can
             * work around it with map_.
             */
            template <class B>
#if defined(SODIUM_NO_CXX11)
            event<B, P> map_(const lambda1<B, const A&>& f) const {
#else
            event<B, P> map_(const std::function<B(const A&)>& f) const {
#endif
                transaction<P> trans;
                return event<B, P>(impl::map_(trans.impl(), SODIUM_DETYPE_FUNCTION1(A,B,f), *this));
            }

            /*!
             * Merge two events. If both events fire in the same transaction, then the
             * output event will just give two firings within the same transaction.
             * This is allowed, but it is usually best avoided.
             */
            event<A, P> merge(const event<A, P>& other) const {
                transaction<P> trans;
                return event<A, P>(merge_(trans.impl(), other));
            }

            /*!
             * If there's more than one firing in a single transaction, combine them into
             * one using the specified combining function.
             *
             * If the event firings are ordered, then the first will appear at the left
             * input of the combining function. In most common cases it's best not to
             * make any assumptions about the ordering, and the combining function would
             * ideally be commutative.
             */
#if defined(SODIUM_NO_CXX11)
            event<A, P> coalesce(const lambda2<A, const A&, const A&>& combine) const
#else
            event<A, P> coalesce(const std::function<A(const A&, const A&)>& combine) const
#endif
            {
                transaction<P> trans;
                return event<A, P>(coalesce_(trans.impl(),
#if defined(SODIUM_NO_CXX11)
                    new impl::detype_combine<A>(combine)
#else
                    [combine] (const light_ptr& a, const light_ptr& b) -> light_ptr {
                        return light_ptr::create<A>(combine(*a.cast_ptr<A>(NULL), *b.cast_ptr<A>(NULL)));
                    }
#endif
                ));
            }

            /*!
             * If there's more than one firing in a single transaction, keep only the latest one.
             */
            event<A, P> coalesce() const
            {
                return coalesce(
#if defined(SODIUM_NO_CXX11)
                        new snd_arg<A,A>
#else
                        [] (const A&, const A& snd) -> A { return snd; }
#endif
                    );
            }

            /*!
             * Merge two streams of events of the same type, combining simultaneous
             * event occurrences.
             *
             * In the case where multiple event occurrences are simultaneous (i.e. all
             * within the same transaction), they are combined using the same logic as
             * 'coalesce'.
             */
#if defined(SODIUM_NO_CXX11)
            event<A, P> merge(const event<A, P>& other, const lambda2<A, const A&, const A&>& combine) const
#else
            event<A, P> merge(const event<A, P>& other, const std::function<A(const A&, const A&)>& combine) const
#endif
            {
                return merge(other).coalesce(combine);
            }

            /*!
             * Filter this event based on the specified predicate, passing through values
             * where the predicate returns true.
             */
#if defined(SODIUM_NO_CXX11)
            event<A, P> filter(const lambda1<bool, const A&>& pred) const
#else
            event<A, P> filter(const std::function<bool(const A&)>& pred) const
#endif
            {
                transaction<P> trans;
                return event<A, P>(filter_(trans.impl(),
#if defined(SODIUM_NO_CXX11)
                    new impl::detype_pred<A>(pred)
#else
                    [pred] (const light_ptr& a) {
                        return pred(*a.cast_ptr<A>(NULL));
                    }
#endif
                  ));
            }

            /*!
             * Create a behavior that holds at any given time the most recent value
             * that has arrived from this event. Since behaviors must always have a current
             * value, you must supply an initial value that it has until the first event
             * occurrence updates it.
             */
            behavior<A, P> hold(const A& initA) const
            {
                transaction<P> trans;
                return behavior<A, P>(hold_(trans.impl(), light_ptr::create<A>(initA)));
            }

            behavior<A, P> hold_lazy(const std::function<A()>& initA) const
            {
                transaction<P> trans;
                return behavior<A, P>(hold_lazy_(trans.impl(), [initA] () -> light_ptr { return light_ptr::create<A>(initA()); }));
            }

            /*!
             * Sample the behavior's value as at the transaction before the
             * current one, i.e. no changes from the current transaction are
             * taken.
             */
            template <class B, class C>
#if defined(SODIUM_NO_CXX11)
            event<C, P> snapshot(const behavior<B, P>& beh, const lambda2<C, const A&, const B&>& combine) const
#else
            event<C, P> snapshot(const behavior<B, P>& beh, const std::function<C(const A&, const B&)>& combine) const
#endif
            {
                transaction<P> trans;
                return event<C, P>(snapshot_(trans.impl(), beh,
#if defined(SODIUM_NO_CXX11)
                    new impl::detype_snapshot<A,B,C>(combine)
#else
                    [combine] (const light_ptr& a, const light_ptr& b) -> light_ptr {
                        return light_ptr::create<C>(combine(*a.cast_ptr<A>(NULL), *b.cast_ptr<B>(NULL)));
                    }
#endif
                ));
            }

            /*!
             * Sample the behavior's value as at the transaction before the
             * current one, i.e. no changes from the current transaction are
             * taken.
             */
            template <class B>
            event<B, P> snapshot(const behavior<B, P>& beh) const
            {
                return snapshot<B, B>(beh,
#if defined(SODIUM_NO_CXX11)
                    new snd_arg<A,B>
#else
                    [] (const A&, const B& b) { return b; }
#endif
                    );
            }

            /*!
             * Allow events through only when the behavior's value is true.
             */
            event<A, P> gate(const behavior<bool, P>& g) const
            {
                transaction<P> trans;
                return filter_optional<A, P>(snapshot<bool, boost::optional<A>>(
                    g,
#if defined(SODIUM_NO_CXX11)
                    new impl::gate_handler<A>()
#else
                    [] (const A& a, const bool& gated) {
                        return gated ? boost::optional<A>(a) : boost::optional<A>();
                    }
#endif
                ));
            }

            /*!
             * Adapt an event to a new event statefully.  Always outputs one output for each
             * input.
             */
            template <class S, class B>
            event<B, P> collect_lazy(
                const std::function<S()>& initS,
#if defined(SODIUM_NO_CXX11)
                const lambda2<SODIUM_TUPLE<B, S>, const A&, const S&>& f
#else
                const std::function<SODIUM_TUPLE<B, S>(const A&, const S&)>& f
#endif
            ) const
            {
                transaction<P> trans;
                SODIUM_SHARED_PTR<impl::collect_state<S> > pState(new impl::collect_state<S>(initS));
                SODIUM_TUPLE<impl::event_,SODIUM_SHARED_PTR<impl::node> > p = impl::unsafe_new_event();
#if defined(SODIUM_NO_CXX11)
                lambda0<void>* kill = listen_raw(trans.impl(), SODIUM_TUPLE_GET<1>(p),
                    new impl::collect_handler<A,S,B>(pState, f), false, true);
#else
                auto kill = listen_raw(trans.impl(), std::get<1>(p),
                    new std::function<void(const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&)>(
                        [pState, f] (const SODIUM_SHARED_PTR<impl::node>& target, impl::transaction_impl* trans, const light_ptr& ptr) {
                            auto outsSt = f(*ptr.cast_ptr<A>(NULL), pState->s_lazy());
                            const S& new_s = SODIUM_TUPLE_GET<1>(outsSt);
                            pState->s_lazy = [new_s] () { return new_s; };
                            send(target, trans, light_ptr::create<B>(std::get<0>(outsSt)));
                        }), false, true);
#endif
                return SODIUM_TUPLE_GET<0>(p).unsafe_add_cleanup(kill);
            }

            /*!
             * Adapt an event to a new event statefully.  Always outputs one output for each
             * input.
             */
            template <class S, class B>
            event<B, P> collect(
                const S& initS,
#if defined(SODIUM_NO_CXX11)
                const lambda2<SODIUM_TUPLE<B, S>, const A&, const S&>& f
#else
                const std::function<SODIUM_TUPLE<B, S>(const A&, const S&)>& f
#endif
            ) const
            {
                return collect_lazy<S,B>([initS] () -> S { return initS; }, f);
            }

            template <class B>
            event<B, P> accum_e_lazy(
                const std::function<B()>& initB,
#if defined(SODIUM_NO_CXX11)
                const lambda2<B, const A&, const B&>& f
#else
                const std::function<B(const A&, const B&)>& f
#endif
            ) const
            {
                transaction<P> trans;
                SODIUM_SHARED_PTR<impl::collect_state<B> > pState(new impl::collect_state<B>(initB));
                SODIUM_TUPLE<impl::event_,SODIUM_SHARED_PTR<impl::node> > p = impl::unsafe_new_event();
#if defined(SODIUM_NO_CXX11)
                lambda0<void>* kill = listen_raw(trans.impl(), SODIUM_TUPLE_GET<1>(p),
                    new impl::accum_handler<A,B>(pState, f)
#else
                auto kill = listen_raw(trans.impl(), SODIUM_TUPLE_GET<1>(p),
                    new std::function<void(const SODIUM_SHARED_PTR<impl::node>&, impl::transaction_impl*, const light_ptr&)>(
                        [pState, f] (const SODIUM_SHARED_PTR<impl::node>& target, impl::transaction_impl* trans, const light_ptr& ptr) {
                            B b = f(*ptr.cast_ptr<A>(NULL), pState->s_lazy());
                            pState->s_lazy = [b] () { return b; };
                            send(target, trans, light_ptr::create<B>(b));
                        })
#endif
                    , false, true);
                return event<B, P>(SODIUM_TUPLE_GET<0>(p).unsafe_add_cleanup(kill));
            }

            template <class B>
            event<B, P> accum_e(
                const B& initB,
#if defined(SODIUM_NO_CXX11)
                const lambda2<B, const A&, const B&>& f
#else
                const std::function<B(const A&, const B&)>& f
#endif
            ) const
            {
                return accum_e_lazy<B>([initB] () -> B { return initB; }, f);
            }

            template <class B>
            behavior<B, P> accum(
                const B& initB,
{'fraction_non_alphanumeric': 0.11136206650805311, 'fraction_numerical': 0.005646496431194974, 'mean_word_length': 1.9277437164960036, 'pattern_counts': {'":': 0, '<': 1050, '<?xml version=': 0, '>': 1124, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7015019', 'n_tokens_mistral': 27438, 'n_tokens_neox': 26061, 'n_words': 6745}