<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2020.  All rights reserved
 */
#ifndef _Stroika_Foundation_Execution_Thread_inl_
#define _Stroika_Foundation_Execution_Thread_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include <atomic>
#include <list>

#include "WaitableEvent.h"

namespace Stroika::Foundation::Execution {

    namespace PRIVATE_ {
        enum class InterruptFlagState_ {
            eNone,
            eInterrupted,
            eAborted,

            Stroika_Define_Enum_Bounds (eNone, eAborted)
        };
        using InterruptFlagType_ = atomic<InterruptFlagState_>;
    }

    /*
     ********************************************************************************
     ********************************* Thread::Ptr::Rep_ ****************************
     ********************************************************************************
     */
    /**
     *  \note   \em Thread-Safety   Internally-Synchronized-Thread-Safety
     */
    class Thread::Ptr::Rep_ {
    public:
        Rep_ (const function<void ()>& runnable, const optional<Configuration>& configuration);
        ~Rep_ ();

    public:
        static void DoCreate (const shared_ptr<Rep_>* repSharedPtr);

    public:
        nonvirtual void Start ();

    public:
        nonvirtual IDType GetID () const;

    public:
        nonvirtual NativeHandleType GetNativeHandle ();

    public:
        nonvirtual Characters::String ToString () const;

    public:
        nonvirtual void ApplyThreadName2OSThreadObject ();

    public:
        nonvirtual void ApplyPriority (Priority priority);

    private:
        nonvirtual void Run_ ();

    private:
        // Called - typically from ANOTHER thread (but could  be this thread). By default this does nothing,
        // and is just called by Thread::Abort (). It sets (indirectly) the thread-local-storage aborted
        // flag for the target thread. And if called from an aborting thread, it may throw
        nonvirtual void NotifyOfInterruptionFromAnyThread_ (bool aborting);

    private:
        static void ThreadMain_ (const shared_ptr<Rep_>* thisThreadRep) noexcept;

    private:
#if qPlatform_POSIX
        static void InterruptionSignalHandler_ (SignalID signal) noexcept;
#elif qPlatform_Windows
        static void CALLBACK CalledInRepThreadAbortProc_ (ULONG_PTR lpParameter);
#endif

    private:
        using InterruptFlagState_ = PRIVATE_::InterruptFlagState_;
        using InterruptFlagType_  = PRIVATE_::InterruptFlagType_;

    private:
        function<void ()> fRunnable_;
        // We use a global variable (thread local) to store the abort flag. But we must access it from ANOTHER thread typically - using
        // a pointer. This is that pointer - so another thread can terminate/abort this thread.
        InterruptFlagType_*              fTLSInterruptFlag_{};   // regular interrupt, abort interrupt, or none
        mutable mutex                    fAccessSTDThreadMutex_; // rarely needed but to avoid small race as we shutdown thread, while we join in one thread and call GetNativeThread() in another
        thread                           fThread_;
        atomic<Status>                   fStatus_{Status::eNotYetRunning};
        WaitableEvent                    fRefCountBumpedEvent_;
        WaitableEvent                    fOK2StartEvent_;
        WaitableEvent                    fThreadDoneAndCanJoin_;
        wstring                          fThreadName_;
        exception_ptr                    fSavedException_;
        Synchronized<optional<Priority>> fInitialPriority_; // where we store priority before start
#if qPlatform_Windows
        bool fThrowInterruptExceptionInsideUserAPC_{false};
#endif

    private:
        friend class Ptr;
    };

    /*
     ********************************************************************************
     *********************************** Thread::Rep_ *******************************
     ********************************************************************************
     */
    inline void Thread::Ptr::Rep_::Start ()
    {
        fOK2StartEvent_.Set ();
    }

    /*
     ********************************************************************************
     ******************************** Thread::Ptr ***********************************
     ********************************************************************************
     */
    inline Thread::Ptr::Ptr (nullptr_t)
    {
    }
    inline Thread::Ptr::Ptr (const shared_ptr<Rep_>& rep)
        : fRep_ (rep)
    {
    }
    inline Thread::Ptr::Ptr (const Ptr& src)
        : fRep_ (src.fRep_)
    {
    }
    inline Thread::Ptr::Ptr (Ptr&& src) noexcept
        : fRep_ (move (src.fRep_))
    {
    }
    inline Thread::Ptr& Thread::Ptr::operator= (const Ptr& rhs)
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{rhs};
        lock_guard<const AssertExternallySynchronizedLock>  critSec{*this};
        fRep_ = rhs.fRep_;
        return *this;
    }
    inline Thread::Ptr& Thread::Ptr::operator= (Ptr&& rhs) noexcept
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec1{rhs};
        lock_guard<const AssertExternallySynchronizedLock> critSec2{*this};
        fRep_ = move (rhs.fRep_);
        return *this;
    }
    inline Thread::IDType Thread::Ptr::GetID () const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        if (fRep_ == nullptr)
            [[UNLIKELY_ATTR]]
            {
                return IDType{};
            }
        return fRep_->GetID ();
    }
    inline Thread::NativeHandleType Thread::Ptr::GetNativeHandle () const noexcept
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        if (fRep_ == nullptr)
            [[UNLIKELY_ATTR]]
            {
                return NativeHandleType{};
            }
        return fRep_->GetNativeHandle ();
    }
    inline void Thread::Ptr::reset () noexcept
    {
        lock_guard<AssertExternallySynchronizedLock> critSec{*this};
        fRep_.reset ();
    }
    inline function<void ()> Thread::Ptr::GetFunction () const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        if (fRep_ == nullptr)
            [[UNLIKELY_ATTR]]
            {
                return nullptr;
            }
        return fRep_->fRunnable_;
    }
#if __cpp_impl_three_way_comparison >= 201907
    inline bool Thread::Ptr::operator== (const Ptr& rhs) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        shared_lock<const AssertExternallySynchronizedLock> critSec2{rhs};
        return fRep_ == rhs.fRep_;
    }
    inline bool Thread::Ptr::operator== (nullptr_t) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        return fRep_ == nullptr;
    }
    inline strong_ordering Thread::Ptr::operator<=> (const Ptr& rhs) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        shared_lock<const AssertExternallySynchronizedLock> critSec2{rhs};
#if __cpp_impl_three_way_comparison < 201907
        return Common::ThreeWayCompare (fRep_, rhs.fRep_);
#else
        return fRep_ <=> rhs.fRep_;
#endif
    }
    inline strong_ordering Thread::Ptr::operator<=> (nullptr_t) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
#if __cpp_impl_three_way_comparison < 201907
        return Common::ThreeWayCompare (fRep_, nullptr);
#else
        return fRep_ <=> nullptr;
#endif
    }
#else
    inline bool Thread::Ptr::operator< (const Ptr& rhs) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        return fRep_ < rhs.fRep_;
    }
    inline bool Thread::Ptr::operator== (const Ptr& rhs) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        shared_lock<const AssertExternallySynchronizedLock> critSec2{rhs};
        return fRep_ == rhs.fRep_;
    }
    inline bool Thread::Ptr::operator== (nullptr_t) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        return fRep_ == nullptr;
    }
    inline bool Thread::Ptr::operator!= (const Ptr& rhs) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        shared_lock<const AssertExternallySynchronizedLock> critSec2{rhs};
        return fRep_ != rhs.fRep_;
    }
    inline bool Thread::Ptr::operator!= (nullptr_t) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        return fRep_ != nullptr;
    }
#endif
    inline Thread::Ptr::operator bool () const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        return fRep_ != nullptr;
    }
#if qPlatform_Windows
    inline bool Thread::Ptr::ThrowInterruptExceptionInsideUserAPC () const noexcept
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        return fRep_ == nullptr ? false : fRep_->fThrowInterruptExceptionInsideUserAPC_;
    }
    inline bool Thread::Ptr::ThrowInterruptExceptionInsideUserAPC (optional<bool> throwInterruptExceptionInsideUserAPC)
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec1{*this};
        bool                                               result = fRep_ == nullptr ? false : fRep_->fThrowInterruptExceptionInsideUserAPC_;
        if (throwInterruptExceptionInsideUserAPC) {
            RequireNotNull (fRep_);
            fRep_->fThrowInterruptExceptionInsideUserAPC_ = throwInterruptExceptionInsideUserAPC.value ();
        }
        return result;
    }
#endif
    inline Thread::Status Thread::Ptr::GetStatus () const noexcept
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        if (fRep_ == nullptr)
            [[UNLIKELY_ATTR]]
            {
                return Status::eNull;
            }
        return GetStatus_ ();
    }
    inline void Thread::Ptr::Join (Time::DurationSecondsType timeout) const
    {
        JoinUntil (timeout + Time::GetTickCount ());
    }
    inline void Thread::Ptr::JoinUntil (Time::DurationSecondsType timeoutAt) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        WaitForDoneUntil (timeoutAt);
        ThrowIfDoneWithException ();
    }
    inline void Thread::Ptr::WaitForDone (Time::DurationSecondsType timeout) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        WaitForDoneUntil (timeout + Time::GetTickCount ());
    }
    inline void Thread::Ptr::AbortAndWaitForDone (Time::DurationSecondsType timeout) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        AbortAndWaitForDoneUntil (timeout + Time::GetTickCount ());
    }

    /*
     ********************************************************************************
     ******************************** Thread::CleanupPtr ****************************
     ********************************************************************************
     */
    inline Thread::CleanupPtr::CleanupPtr (AbortFlag abortFlag, Ptr threadPtr)
        : Ptr (threadPtr)
        , fAbort_{abortFlag == AbortFlag::eAbortBeforeWaiting}
    {
    }
    inline Thread::CleanupPtr& Thread::CleanupPtr::operator= (const Ptr& rhs)
    {
        // preserve constructed with fAbort flag
        Ptr::operator= (rhs);
        return *this;
    }

    /*
     ********************************************************************************
     ************************************* Thread ***********************************
     ********************************************************************************
     */
    inline Thread::Ptr Thread::New (const function<void ()>& fun2CallOnce, const optional<Configuration>& configuration)
    {
        return New (fun2CallOnce, nullopt, configuration);
    }
    inline Thread::Ptr Thread::New (const function<void ()>& fun2CallOnce, const Characters::String& name, const optional<Configuration>& configuration)
    {
        return New (fun2CallOnce, optional<Characters::String>{name}, configuration);
    }
    inline Thread::Ptr Thread::New (const function<void ()>& fun2CallOnce, AutoStartFlag, const optional<Configuration>& configuration)
    {
        Ptr ptr = New (fun2CallOnce, nullopt, configuration);
        ptr.Start ();
        return ptr;
    }
    inline Thread::Ptr Thread::New (const function<void ()>& fun2CallOnce, AutoStartFlag, const optional<Characters::String>& name, const optional<Configuration>& configuration)
    {
        Ptr ptr = New (fun2CallOnce, name, configuration);
        ptr.Start ();
        return ptr;
    }
    inline void Thread::AbortAndWaitForDone (const Traversal::Iterable<Ptr>& threads, Time::DurationSecondsType timeout)
    {
        AbortAndWaitForDoneUntil (threads, timeout + Time::GetTickCount ());
    }
    inline void Thread::Start (const Traversal::Iterable<Ptr>& threads)
    {
        threads.Apply ([] (const Ptr& p) { p.Start (); });
    }
    inline void Thread::WaitForDone (const Traversal::Iterable<Ptr>& threads, Time::DurationSecondsType timeout)
    {
        WaitForDoneUntil (threads, timeout + Time::GetTickCount ());
    }

    /*
     ********************************************************************************
     ************************ Thread::GetCurrentThreadID ****************************
     ********************************************************************************
     */
    inline Thread::IDType Thread::GetCurrentThreadID () noexcept
    {
        return this_thread::get_id ();
    }

    /*
     ********************************************************************************
     ********************* Thread::CheckForInterruption ***********************
     ********************************************************************************
     */
    template <unsigned int kEveryNTimes>
    void Thread::CheckForInterruption ()
    {
        // note that it is not important that this be protected/thread safe, since the value is just advisory/hint
        static unsigned int n = 0;
        if (++n % kEveryNTimes == kEveryNTimes - 1)
            [[UNLIKELY_ATTR]]
            {
                CheckForInterruption ();
            }
    }

}

namespace Stroika::Foundation::Configuration {
#if !qCompilerAndStdLib_template_specialization_internalErrorWithSpecializationSignifier_Buggy
    template <>
#endif
    constexpr EnumNames<Execution::Thread::Status> DefaultNames<Execution::Thread::Status>::k{
        EnumNames<Execution::Thread::Status>::BasicArrayInitializer{{
            {Execution::Thread::Status::eNull, L"Null"},
            {Execution::Thread::Status::eNotYetRunning, L"Not-Yet-Running"},
            {Execution::Thread::Status::eRunning, L"Running"},
            {Execution::Thread::Status::eAborting, L"Aborting"},
            {Execution::Thread::Status::eCompleted, L"Completed"},
        }}};
#if !qCompilerAndStdLib_template_specialization_internalErrorWithSpecializationSignifier_Buggy
    template <>
#endif
    constexpr EnumNames<Execution::Thread::Priority> DefaultNames<Execution::Thread::Priority>::k{
        EnumNames<Execution::Thread::Priority>::BasicArrayInitializer{{
            {Execution::Thread::Priority::eLowest, L"Lowest"},
            {Execution::Thread::Priority::eBelowNormal, L"Below-Normal"},
            {Execution::Thread::Priority::eNormal, L"Normal"},
            {Execution::Thread::Priority::eAboveNormal, L"Above-Normal"},
            {Execution::Thread::Priority::eHighest, L"Highest"},
        }}};
}

#endif /*_Stroika_Foundation_Execution_Thread_inl_*/
<commit_msg>must check __cpp_lib_three_way_comparison not __cpp_impl_three_way_comparison for operator<==> support on shared_ptr<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2020.  All rights reserved
 */
#ifndef _Stroika_Foundation_Execution_Thread_inl_
#define _Stroika_Foundation_Execution_Thread_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include <atomic>
#include <list>

#include "WaitableEvent.h"

namespace Stroika::Foundation::Execution {

    namespace PRIVATE_ {
        enum class InterruptFlagState_ {
            eNone,
            eInterrupted,
            eAborted,

            Stroika_Define_Enum_Bounds (eNone, eAborted)
        };
        using InterruptFlagType_ = atomic<InterruptFlagState_>;
    }

    /*
     ********************************************************************************
     ********************************* Thread::Ptr::Rep_ ****************************
     ********************************************************************************
     */
    /**
     *  \note   \em Thread-Safety   Internally-Synchronized-Thread-Safety
     */
    class Thread::Ptr::Rep_ {
    public:
        Rep_ (const function<void ()>& runnable, const optional<Configuration>& configuration);
        ~Rep_ ();

    public:
        static void DoCreate (const shared_ptr<Rep_>* repSharedPtr);

    public:
        nonvirtual void Start ();

    public:
        nonvirtual IDType GetID () const;

    public:
        nonvirtual NativeHandleType GetNativeHandle ();

    public:
        nonvirtual Characters::String ToString () const;

    public:
        nonvirtual void ApplyThreadName2OSThreadObject ();

    public:
        nonvirtual void ApplyPriority (Priority priority);

    private:
        nonvirtual void Run_ ();

    private:
        // Called - typically from ANOTHER thread (but could  be this thread). By default this does nothing,
        // and is just called by Thread::Abort (). It sets (indirectly) the thread-local-storage aborted
        // flag for the target thread. And if called from an aborting thread, it may throw
        nonvirtual void NotifyOfInterruptionFromAnyThread_ (bool aborting);

    private:
        static void ThreadMain_ (const shared_ptr<Rep_>* thisThreadRep) noexcept;

    private:
#if qPlatform_POSIX
        static void InterruptionSignalHandler_ (SignalID signal) noexcept;
#elif qPlatform_Windows
        static void CALLBACK CalledInRepThreadAbortProc_ (ULONG_PTR lpParameter);
#endif

    private:
        using InterruptFlagState_ = PRIVATE_::InterruptFlagState_;
        using InterruptFlagType_  = PRIVATE_::InterruptFlagType_;

    private:
        function<void ()> fRunnable_;
        // We use a global variable (thread local) to store the abort flag. But we must access it from ANOTHER thread typically - using
        // a pointer. This is that pointer - so another thread can terminate/abort this thread.
        InterruptFlagType_*              fTLSInterruptFlag_{};   // regular interrupt, abort interrupt, or none
        mutable mutex                    fAccessSTDThreadMutex_; // rarely needed but to avoid small race as we shutdown thread, while we join in one thread and call GetNativeThread() in another
        thread                           fThread_;
        atomic<Status>                   fStatus_{Status::eNotYetRunning};
        WaitableEvent                    fRefCountBumpedEvent_;
        WaitableEvent                    fOK2StartEvent_;
        WaitableEvent                    fThreadDoneAndCanJoin_;
        wstring                          fThreadName_;
        exception_ptr                    fSavedException_;
        Synchronized<optional<Priority>> fInitialPriority_; // where we store priority before start
#if qPlatform_Windows
        bool fThrowInterruptExceptionInsideUserAPC_{false};
#endif

    private:
        friend class Ptr;
    };

    /*
     ********************************************************************************
     *********************************** Thread::Rep_ *******************************
     ********************************************************************************
     */
    inline void Thread::Ptr::Rep_::Start ()
    {
        fOK2StartEvent_.Set ();
    }

    /*
     ********************************************************************************
     ******************************** Thread::Ptr ***********************************
     ********************************************************************************
     */
    inline Thread::Ptr::Ptr (nullptr_t)
    {
    }
    inline Thread::Ptr::Ptr (const shared_ptr<Rep_>& rep)
        : fRep_ (rep)
    {
    }
    inline Thread::Ptr::Ptr (const Ptr& src)
        : fRep_ (src.fRep_)
    {
    }
    inline Thread::Ptr::Ptr (Ptr&& src) noexcept
        : fRep_ (move (src.fRep_))
    {
    }
    inline Thread::Ptr& Thread::Ptr::operator= (const Ptr& rhs)
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{rhs};
        lock_guard<const AssertExternallySynchronizedLock>  critSec{*this};
        fRep_ = rhs.fRep_;
        return *this;
    }
    inline Thread::Ptr& Thread::Ptr::operator= (Ptr&& rhs) noexcept
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec1{rhs};
        lock_guard<const AssertExternallySynchronizedLock> critSec2{*this};
        fRep_ = move (rhs.fRep_);
        return *this;
    }
    inline Thread::IDType Thread::Ptr::GetID () const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        if (fRep_ == nullptr)
            [[UNLIKELY_ATTR]]
            {
                return IDType{};
            }
        return fRep_->GetID ();
    }
    inline Thread::NativeHandleType Thread::Ptr::GetNativeHandle () const noexcept
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        if (fRep_ == nullptr)
            [[UNLIKELY_ATTR]]
            {
                return NativeHandleType{};
            }
        return fRep_->GetNativeHandle ();
    }
    inline void Thread::Ptr::reset () noexcept
    {
        lock_guard<AssertExternallySynchronizedLock> critSec{*this};
        fRep_.reset ();
    }
    inline function<void ()> Thread::Ptr::GetFunction () const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        if (fRep_ == nullptr)
            [[UNLIKELY_ATTR]]
            {
                return nullptr;
            }
        return fRep_->fRunnable_;
    }
#if __cpp_impl_three_way_comparison >= 201907
    inline bool Thread::Ptr::operator== (const Ptr& rhs) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        shared_lock<const AssertExternallySynchronizedLock> critSec2{rhs};
        return fRep_ == rhs.fRep_;
    }
    inline bool Thread::Ptr::operator== (nullptr_t) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        return fRep_ == nullptr;
    }
    inline strong_ordering Thread::Ptr::operator<=> (const Ptr& rhs) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        shared_lock<const AssertExternallySynchronizedLock> critSec2{rhs};
#if __cpp_lib_three_way_comparison < 201907
        return Common::ThreeWayCompare (fRep_, rhs.fRep_);
#else
        return fRep_ <=> rhs.fRep_;
#endif
    }
    inline strong_ordering Thread::Ptr::operator<=> (nullptr_t) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
#if __cpp_lib_three_way_comparison < 201907
        return Common::ThreeWayCompare (fRep_, nullptr);
#else
        return fRep_ <=> nullptr;
#endif
    }
#else
    inline bool Thread::Ptr::operator< (const Ptr& rhs) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        return fRep_ < rhs.fRep_;
    }
    inline bool Thread::Ptr::operator== (const Ptr& rhs) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        shared_lock<const AssertExternallySynchronizedLock> critSec2{rhs};
        return fRep_ == rhs.fRep_;
    }
    inline bool Thread::Ptr::operator== (nullptr_t) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        return fRep_ == nullptr;
    }
    inline bool Thread::Ptr::operator!= (const Ptr& rhs) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        shared_lock<const AssertExternallySynchronizedLock> critSec2{rhs};
        return fRep_ != rhs.fRep_;
    }
    inline bool Thread::Ptr::operator!= (nullptr_t) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        return fRep_ != nullptr;
    }
#endif
    inline Thread::Ptr::operator bool () const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        return fRep_ != nullptr;
    }
#if qPlatform_Windows
    inline bool Thread::Ptr::ThrowInterruptExceptionInsideUserAPC () const noexcept
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{*this};
        return fRep_ == nullptr ? false : fRep_->fThrowInterruptExceptionInsideUserAPC_;
    }
    inline bool Thread::Ptr::ThrowInterruptExceptionInsideUserAPC (optional<bool> throwInterruptExceptionInsideUserAPC)
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec1{*this};
        bool                                               result = fRep_ == nullptr ? false : fRep_->fThrowInterruptExceptionInsideUserAPC_;
        if (throwInterruptExceptionInsideUserAPC) {
            RequireNotNull (fRep_);
            fRep_->fThrowInterruptExceptionInsideUserAPC_ = throwInterruptExceptionInsideUserAPC.value ();
        }
        return result;
    }
#endif
    inline Thread::Status Thread::Ptr::GetStatus () const noexcept
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        if (fRep_ == nullptr)
            [[UNLIKELY_ATTR]]
            {
                return Status::eNull;
            }
        return GetStatus_ ();
    }
    inline void Thread::Ptr::Join (Time::DurationSecondsType timeout) const
    {
        JoinUntil (timeout + Time::GetTickCount ());
    }
    inline void Thread::Ptr::JoinUntil (Time::DurationSecondsType timeoutAt) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        WaitForDoneUntil (timeoutAt);
        ThrowIfDoneWithException ();
    }
    inline void Thread::Ptr::WaitForDone (Time::DurationSecondsType timeout) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        WaitForDoneUntil (timeout + Time::GetTickCount ());
    }
    inline void Thread::Ptr::AbortAndWaitForDone (Time::DurationSecondsType timeout) const
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec{*this};
        AbortAndWaitForDoneUntil (timeout + Time::GetTickCount ());
    }

    /*
     ********************************************************************************
     ******************************** Thread::CleanupPtr ****************************
     ********************************************************************************
     */
    inline Thread::CleanupPtr::CleanupPtr (AbortFlag abortFlag, Ptr threadPtr)
        : Ptr (threadPtr)
        , fAbort_{abortFlag == AbortFlag::eAbortBeforeWaiting}
    {
    }
    inline Thread::CleanupPtr& Thread::CleanupPtr::operator= (const Ptr& rhs)
    {
        // preserve constructed with fAbort flag
        Ptr::operator= (rhs);
        return *this;
    }

    /*
     ********************************************************************************
     ************************************* Thread ***********************************
     ********************************************************************************
     */
    inline Thread::Ptr Thread::New (const function<void ()>& fun2CallOnce, const optional<Configuration>& configuration)
    {
        return New (fun2CallOnce, nullopt, configuration);
    }
    inline Thread::Ptr Thread::New (const function<void ()>& fun2CallOnce, const Characters::String& name, const optional<Configuration>& configuration)
    {
        return New (fun2CallOnce, optional<Characters::String>{name}, configuration);
    }
    inline Thread::Ptr Thread::New (const function<void ()>& fun2CallOnce, AutoStartFlag, const optional<Configuration>& configuration)
    {
        Ptr ptr = New (fun2CallOnce, nullopt, configuration);
        ptr.Start ();
        return ptr;
    }
    inline Thread::Ptr Thread::New (const function<void ()>& fun2CallOnce, AutoStartFlag, const optional<Characters::String>& name, const optional<Configuration>& configuration)
    {
        Ptr ptr = New (fun2CallOnce, name, configuration);
        ptr.Start ();
        return ptr;
    }
    inline void Thread::AbortAndWaitForDone (const Traversal::Iterable<Ptr>& threads, Time::DurationSecondsType timeout)
    {
        AbortAndWaitForDoneUntil (threads, timeout + Time::GetTickCount ());
    }
    inline void Thread::Start (const Traversal::Iterable<Ptr>& threads)
    {
        threads.Apply ([] (const Ptr& p) { p.Start (); });
    }
    inline void Thread::WaitForDone (const Traversal::Iterable<Ptr>& threads, Time::DurationSecondsType timeout)
    {
        WaitForDoneUntil (threads, timeout + Time::GetTickCount ());
    }

    /*
     ********************************************************************************
     ************************ Thread::GetCurrentThreadID ****************************
     ********************************************************************************
     */
    inline Thread::IDType Thread::GetCurrentThreadID () noexcept
    {
        return this_thread::get_id ();
    }

    /*
     ********************************************************************************
     ********************* Thread::CheckForInterruption ***********************
     ********************************************************************************
     */
    template <unsigned int kEveryNTimes>
    void Thread::CheckForInterruption ()
    {
        // note that it is not important that this be protected/thread safe, since the value is just advisory/hint
        static unsigned int n = 0;
        if (++n % kEveryNTimes == kEveryNTimes - 1)
            [[UNLIKELY_ATTR]]
            {
                CheckForInterruption ();
            }
    }

}

namespace Stroika::Foundation::Configuration {
#if !qCompilerAndStdLib_template_specialization_internalErrorWithSpecializationSignifier_Buggy
    template <>
#endif
    constexpr EnumNames<Execution::Thread::Status> DefaultNames<Execution::Thread::Status>::k{
        EnumNames<Execution::Thread::Status>::BasicArrayInitializer{{
            {Execution::Thread::Status::eNull, L"Null"},
            {Execution::Thread::Status::eNotYetRunning, L"Not-Yet-Running"},
            {Execution::Thread::Status::eRunning, L"Running"},
            {Execution::Thread::Status::eAborting, L"Aborting"},
            {Execution::Thread::Status::eCompleted, L"Completed"},
        }}};
#if !qCompilerAndStdLib_template_specialization_internalErrorWithSpecializationSignifier_Buggy
    template <>
#endif
    constexpr EnumNames<Execution::Thread::Priority> DefaultNames<Execution::Thread::Priority>::k{
        EnumNames<Execution::Thread::Priority>::BasicArrayInitializer{{
            {Execution::Thread::Priority::eLowest, L"Lowest"},
            {Execution::Thread::Priority::eBelowNormal, L"Below-Normal"},
            {Execution::Thread::Priority::eNormal, L"Normal"},
            {Execution::Thread::Priority::eAboveNormal, L"Above-Normal"},
            {Execution::Thread::Priority::eHighest, L"Highest"},
        }}};
}

#endif /*_Stroika_Foundation_Execution_Thread_inl_*/
<|endoftext|>


<commit_before>#include "BuiltinFunctions.h"
#include "AST.h"
#include "FunctionNameMangler.h"

namespace Helen
{

using namespace llvm;

const std::string BuiltinFunctions::operatorMarker = "__operator_";
const std::string BuiltinFunctions::unaryOperatorMarker = "__unary_operator_";

void BuiltinFunctions::createMainFunction()
{
    createAllBuiltins();
    vector<Type*> v;
    FunctionType* ft = FunctionType::get(Type::getInt32Ty(getGlobalContext()), v, false);
    string name = "main";
    Function* f = Function::Create(ft, Function::ExternalLinkage, name, AST::module.get());
    AST::functions[name] = f;
    BasicBlock* bb = BasicBlock::Create(getGlobalContext(), "start", f);
    AST::builder.SetInsertPoint(bb);
}

void BuiltinFunctions::createAllBuiltins()
{
    createArith();
    createIO();
}

void BuiltinFunctions::createArith()
{
    FunctionType* ft;
    Function* f;
    BasicBlock* bb;
    string name;
    Value* left, *right, *res;
    Type* i = Type::getInt64Ty(getGlobalContext());
    Type* r = Type::getDoubleTy(getGlobalContext());
    //_operator_(int, int), _operator_(real, real)
    for (char c : { '+', '-', '*', '/' }) {
        for (Type* t : { i, r }) {
            ft = FunctionType::get(t, vector<Type*>{ t, t }, false);
            name = FunctionNameMangler::mangleName(operatorMarker + c, { t, t });
            f = Function::Create(ft, Function::ExternalLinkage, name, AST::module.get());
            f->addAttribute(AttributeSet::FunctionIndex, Attribute::AlwaysInline);
            bb = BasicBlock::Create(getGlobalContext(), "entry", f);
            AST::builder.SetInsertPoint(bb);
            auto it = f->arg_begin();
            left = it++;
            right = it;
            switch (c) {
            case '+':
                res = t == i ? AST::builder.CreateAdd(left, right, "tmp") : AST::builder.CreateFAdd(left, right, "tmp");
                break;
            case '-':
                res = t == i ? AST::builder.CreateSub(left, right, "tmp") : AST::builder.CreateFSub(left, right, "tmp");
                break;
            case '*':
                res = t == i ? AST::builder.CreateMul(left, right, "tmp") : AST::builder.CreateFMul(left, right, "tmp");
                break;
            case '/':
                res =
                    t == i ? AST::builder.CreateSDiv(left, right, "tmp") : AST::builder.CreateFDiv(left, right, "tmp");
                break;
            }
            AST::builder.CreateRet(res);
        }
    }
}

void BuiltinFunctions::createIO()
{
    std::vector<Type*> printf_types;
    printf_types.push_back(Type::getInt8PtrTy(getGlobalContext()));

    FunctionType* printf_type = FunctionType::get(Type::getInt32Ty(getGlobalContext()), printf_types, true);

    Function* printf = Function::Create(printf_type, Function::ExternalLinkage, "printf", AST::module.get());
    printf->setCallingConv(CallingConv::C);

    // __out
    Type* i = Type::getInt64Ty(getGlobalContext());
    Type* r = Type::getDoubleTy(getGlobalContext());
    Type* v = Type::getVoidTy(getGlobalContext());
    for (Type* t : { i, r }) {
        string s;
        if (t == i)
            s = "%lld";
        if (t == r)
            s = "%lf";
        string name = FunctionNameMangler::mangleName("__out", { t });
        FunctionType* ft = FunctionType::get(v, { t }, false);
        Function* f = Function::Create(ft, Function::ExternalLinkage, name, AST::module.get());
        BasicBlock* parent = AST::builder.GetInsertBlock();
        BasicBlock* bb = BasicBlock::Create(getGlobalContext(), "entry", f);
        AST::builder.SetInsertPoint(bb);
        vector<Value*> args;
        Constant* fmt = ConstantDataArray::getString(getGlobalContext(), StringRef(s));
        GlobalVariable* var = new GlobalVariable(*AST::module.get(),
                                                 ArrayType::get(IntegerType::get(getGlobalContext(), 8), 4),
                                                 true,
                                                 GlobalValue::PrivateLinkage,
                                                 fmt,
                                                 ".str");

        llvm::Constant* zero = llvm::Constant::getNullValue(llvm::IntegerType::getInt32Ty(getGlobalContext()));
        llvm::Constant* fmt_ref = llvm::ConstantExpr::getGetElementPtr(var, vector<llvm::Constant*>{ zero, zero });
        auto it = printf->arg_begin();
        Value* val = it++;
        //llvm::CallInst* call = AST::builder.CreateCall2(printf, fmt_ref, val);
        args.push_back(fmt_ref);
        args.push_back(f->arg_begin());
        CallInst* call = AST::builder.CreateCall(printf, args);
        call->setTailCall(false);
        AST::builder.CreateRet(0);
    }
}
}
<commit_msg>fixed print function<commit_after>#include "BuiltinFunctions.h"
#include "AST.h"
#include "FunctionNameMangler.h"

namespace Helen
{

using namespace llvm;

const std::string BuiltinFunctions::operatorMarker = "__operator_";
const std::string BuiltinFunctions::unaryOperatorMarker = "__unary_operator_";

void BuiltinFunctions::createMainFunction()
{
    createAllBuiltins();
    vector<Type*> v;
    FunctionType* ft = FunctionType::get(Type::getInt32Ty(getGlobalContext()), v, false);
    string name = "main";
    Function* f = Function::Create(ft, Function::ExternalLinkage, name, AST::module.get());
    AST::functions[name] = f;
    BasicBlock* bb = BasicBlock::Create(getGlobalContext(), "start", f);
    AST::builder.SetInsertPoint(bb);
}

void BuiltinFunctions::createAllBuiltins()
{
    createArith();
    createIO();
}

void BuiltinFunctions::createArith()
{
    FunctionType* ft;
    Function* f;
    BasicBlock* bb;
    string name;
    Value* left, *right, *res;
    Type* i = Type::getInt64Ty(getGlobalContext());
    Type* r = Type::getDoubleTy(getGlobalContext());
    //_operator_(int, int), _operator_(real, real)
    for (char c : { '+', '-', '*', '/' }) {
        for (Type* t : { i, r }) {
            ft = FunctionType::get(t, vector<Type*>{ t, t }, false);
            name = FunctionNameMangler::mangleName(operatorMarker + c, { t, t });
            f = Function::Create(ft, Function::ExternalLinkage, name, AST::module.get());
            f->addAttribute(AttributeSet::FunctionIndex, Attribute::AlwaysInline);
            bb = BasicBlock::Create(getGlobalContext(), "entry", f);
            AST::builder.SetInsertPoint(bb);
            auto it = f->arg_begin();
            left = it++;
            right = it;
            switch (c) {
            case '+':
                res = t == i ? AST::builder.CreateAdd(left, right, "tmp") : AST::builder.CreateFAdd(left, right, "tmp");
                break;
            case '-':
                res = t == i ? AST::builder.CreateSub(left, right, "tmp") : AST::builder.CreateFSub(left, right, "tmp");
                break;
            case '*':
                res = t == i ? AST::builder.CreateMul(left, right, "tmp") : AST::builder.CreateFMul(left, right, "tmp");
                break;
            case '/':
                res =
                    t == i ? AST::builder.CreateSDiv(left, right, "tmp") : AST::builder.CreateFDiv(left, right, "tmp");
                break;
            }
            AST::builder.CreateRet(res);
        }
    }
}

void BuiltinFunctions::createIO()
{
    std::vector<Type*> printf_types;
    printf_types.push_back(Type::getInt8PtrTy(getGlobalContext()));

    FunctionType* printf_type = FunctionType::get(Type::getInt32Ty(getGlobalContext()), printf_types, true);

    Function* printf = Function::Create(printf_type, Function::ExternalLinkage, "printf", AST::module.get());
    printf->setCallingConv(CallingConv::C);

    // __out
    Type* i = Type::getInt64Ty(getGlobalContext());
    Type* r = Type::getDoubleTy(getGlobalContext());
    Type* v = Type::getVoidTy(getGlobalContext());
    for (Type* t : { i, r }) {
        string s;
        if (t == i)
            s = "%lld\n";
        if (t == r)
            s = "%lf\n";
        string name = FunctionNameMangler::mangleName("__out", { t });
        FunctionType* ft = FunctionType::get(i, { t }, false);
        Function* f = Function::Create(ft, Function::ExternalLinkage, name, AST::module.get());
        BasicBlock* parent = AST::builder.GetInsertBlock();
        BasicBlock* bb = BasicBlock::Create(getGlobalContext(), "entry", f);
        AST::builder.SetInsertPoint(bb);
        vector<Value*> args;
        Constant* fmt = ConstantDataArray::getString(getGlobalContext(), StringRef(s));
        GlobalVariable* var = new GlobalVariable(*AST::module.get(),
                                                 ArrayType::get(IntegerType::get(getGlobalContext(), 8), s.size() + 1),
                                                 true,
                                                 GlobalValue::PrivateLinkage,
                                                 fmt,
                                                 ".str");

        Constant* zero = Constant::getNullValue(llvm::IntegerType::getInt32Ty(getGlobalContext()));
        Constant* fmt_ref = ConstantExpr::getGetElementPtr(var, vector<llvm::Constant*>{ zero, zero });
        auto it = printf->arg_begin();
        Value* val = it++;
        //llvm::CallInst* call = AST::builder.CreateCall2(printf, fmt_ref, val);
        args.push_back(fmt_ref);
        args.push_back(f->arg_begin());
        CallInst* call = AST::builder.CreateCall(printf, args);
        call->setTailCall(false);
        AST::builder.CreateRet(Constant::getNullValue(llvm::IntegerType::getInt64Ty(getGlobalContext())));
    }
}
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include "trie/builder.hh"

using HAM::Trie::Builder;

unsigned parse_hex(const char* s) {
  return static_cast<unsigned>(strtol(s, NULL, 16));
}

#define OPT1 "--lower-frequency-limit="

int main(int argc, char** argv) {
  if(argc != 2 && argc != 3) {
  ARG_ERROR:
    std::cerr << "Usage: hamc [--lower-frequency-limit=2] <model-index>" << std::endl;
    return 1;
  }

  // parse arguments
  unsigned lower_frequency_limit=2;
  int arg_i=1;
  if(strncmp(argv[arg_i], OPT1, strlen(OPT1))==0)
    lower_frequency_limit = atoi(argv[arg_i++]+strlen(OPT1));

  if(arg_i == argc)
    goto ARG_ERROR;  // too few arguments

  const char* index_filepath=argv[arg_i];

  // parse model file
  HAM::Trie::Builder::KeyList keys;
  std::string line;

  unsigned total_ham_count=0;
  unsigned total_spam_count=0;

  std::cerr << "= Read model definition:" << std::endl;

  // first line
  if(std::getline(std::cin, line)) {
    total_ham_count  = parse_hex(line.c_str());
    total_spam_count = parse_hex(line.c_str()+9);
  }
  std::cerr << "  == HAM count : " << total_ham_count
	    << "  == SPAM count: " << total_spam_count << std::endl;

  // rest lines
  Builder::ProbabilityCalculator pc(total_ham_count, total_spam_count);
  while(std::getline(std::cin, line)) {
    const char* s = line.c_str();
    unsigned ham_count  = parse_hex(s);
    unsigned spam_count = parse_hex(s+9);
    if(ham_count + spam_count >= lower_frequency_limit)
      keys.push_back(Builder::Key(s+18, pc.bayesian_spam_probability(ham_count, spam_count)));
  }
  std::sort(keys.begin(), keys.end());

  // convert to trie format and save
  HAM::Trie::Builder bld(keys);
  std::cerr << "= Build trie index: " << std::endl;
  bld.build();

  std::cerr << "= Save: " << index_filepath << std::endl;
  bld.save(index_filepath);

  std::cerr << "DONE" << std::endl;
  return 0;
}
<commit_msg>ログ出力整形<commit_after>#include <iostream>
#include <string>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include "trie/builder.hh"

using HAM::Trie::Builder;

unsigned parse_hex(const char* s) {
  return static_cast<unsigned>(strtol(s, NULL, 16));
}

#define OPT1 "--lower-frequency-limit="

int main(int argc, char** argv) {
  if(argc != 2 && argc != 3) {
  ARG_ERROR:
    std::cerr << "Usage: hamc [--lower-frequency-limit=2] <model-index>" << std::endl;
    return 1;
  }

  // parse arguments
  unsigned lower_frequency_limit=2;
  int arg_i=1;
  if(strncmp(argv[arg_i], OPT1, strlen(OPT1))==0)
    lower_frequency_limit = atoi(argv[arg_i++]+strlen(OPT1));

  if(arg_i == argc)
    goto ARG_ERROR;  // too few arguments

  const char* index_filepath=argv[arg_i];

  // parse model file
  HAM::Trie::Builder::KeyList keys;
  std::string line;

  unsigned total_ham_count=0;
  unsigned total_spam_count=0;

  std::cerr << "= Read model definition:" << std::endl;

  // first line
  if(std::getline(std::cin, line)) {
    total_ham_count  = parse_hex(line.c_str());
    total_spam_count = parse_hex(line.c_str()+9);
  }
  std::cerr << "  == HAM count : " << total_ham_count << std::endl
	    << "  == SPAM count: " << total_spam_count << std::endl;

  // rest lines
  Builder::ProbabilityCalculator pc(total_ham_count, total_spam_count);
  while(std::getline(std::cin, line)) {
    const char* s = line.c_str();
    unsigned ham_count  = parse_hex(s);
    unsigned spam_count = parse_hex(s+9);
    if(ham_count + spam_count >= lower_frequency_limit)
      keys.push_back(Builder::Key(s+18, pc.bayesian_spam_probability(ham_count, spam_count)));
  }
  std::sort(keys.begin(), keys.end());

  // convert to trie format and save
  HAM::Trie::Builder bld(keys);
  std::cerr << "= Build trie index: " << std::endl;
  bld.build();

  std::cerr << "= Save: " << index_filepath << std::endl;
  bld.save(index_filepath);

  std::cerr << "DONE" << std::endl;
  return 0;
}
<|endoftext|>


<commit_before>#include "condor_common.h"

#include <algorithm>
#include "ranger.h"

///// ranger insert/erase/find implementation /////

ranger::iterator ranger::insert(ranger::range r)
{
    // lower_bound here will coalesce an adjacent disjoint range;
    // can use upper_bound instead to avoid this and leave them fractured
    iterator it_start = forest.lower_bound(r._start);
    iterator it = it_start;
    while (it != forest.end() && it->_start <= r._end)  // '<' for no coalesce
        ++it;

    iterator it_end = it;
    if (it_start == it_end)
        return forest.insert(it_end, r);

    if (it_start->contains(r))
        return it_start;

    iterator it_back = --it;
    range rr_new = { std::min(it_start->_start, r._start),
                     std::max(it_back->_end, r._end) };

    // avoid erase+insert if only expanding a range
    if (it_start == it_back) {
        it_start->_start = rr_new._start;
        it_start->_end = rr_new._end;
        return it_start;
    }

    iterator hint = forest.erase(it_start, it_end);

    return forest.insert(hint, rr_new);
}

static
bool shrink_single_edge(const ranger::range &rm, const ranger::range &at)
{
    bool erase_start = rm._start <= at._start;
    bool erase_back  = at._end   <= rm._end;
    if (erase_start ^ erase_back) {
        if (erase_start)
            at._start = rm._end;
        else
            at._end = rm._start;
        return true;
    }
    return false;
}

ranger::iterator ranger::erase(ranger::range r)
{
    iterator it_start = forest.upper_bound(r._start);
    iterator it = it_start;
    while (it != forest.end() && it->_start < r._end)
        ++it;

    iterator it_end = it;
    if (it_start == it_end)
        return it_start;

    iterator it_back = --it;

    // avoid erase+insert if only shrinking an edge of a range
    if (it_start == it_back && shrink_single_edge(r, *it_start))
        return it_start;

    range rr_start = *it_start;
    range rr_back  = *it_back;

    iterator hint = forest.erase(it_start, it_end);
    if (rr_start._start < r._start)
        hint = forest.insert(hint, {rr_start._start, r._start});

    if (r._end < rr_back._end)
        hint = forest.insert(hint, {r._end, rr_back._end});

    return hint;
}

std::pair<ranger::iterator, bool>
ranger::find(value_type x) const
{
    iterator it = forest.upper_bound(x);
    return {it, it != forest.end() && it->_start <= x};
}

bool ranger::contains(value_type x) const
{
    return find(x).second;
}

ranger::ranger(const std::initializer_list<ranger::range> &il)
{
    for (const range &rr : il)
        insert(rr);
}

///// ranger::elements::iterator implementation /////

/* This allows:
 *
 *      for (int i : myranger.get_elements())
 *          process_int(i);
 *
 *
 * Instead of the still-straightforward:
 *
 *      for (auto &rr : myranger)
 *          for (int i : rr)
 *              process_int(i);
 */

void ranger::elements::iterator::mk_valid()
{
    if (!rit_valid) {
        rit = sit->begin();
        rit_valid = true;
    }
}

ranger::value_type ranger::elements::iterator::operator*()
{
    mk_valid();
    return *rit;
}

ranger::elements::iterator &ranger::elements::iterator::operator++()
{
    mk_valid();
    if (++rit == sit->end()) {
        ++sit;
        rit_valid = false;
    }
    return *this;
}

ranger::elements::iterator &ranger::elements::iterator::operator--()
{
    mk_valid();
    if (rit == sit->begin()) {
        --sit;
        rit = sit->end();
        --rit;
    }
    return *this;
}

bool ranger::elements::iterator::operator==(iterator &it)
{
    if (sit != it.sit)
        return false;
    if (!rit_valid && !it.rit_valid)
        return true;
    // at this point neither sit nor it.sit points to the end() of its set,
    // thus it's OK to call mk_valid() on each, which may dereference *sit
    mk_valid();
    it.mk_valid();
    return rit == it.rit;
}

bool ranger::elements::iterator::operator!=(iterator &it)
{
    return !(*this == it);
}

///// ranger persist/load implementation /////

#include <stdlib.h> // strtol
#include <stdio.h>  // sprintf
#include <string>

/*  persist / load ranger objects
 *
 *  The serialized format is one or more sub-ranges, separated by semicolons,
 *  where each sub-range is either N-M (for inclusive N..M) or N for a single
 *  integer.  Eg, "2", "5-10", "4;7;10-20;44;50-60"
 */

static
void persist_range_single(std::string &s, const ranger::range &rr)
{
    char buf[64];
    int n;
    if (rr._start == rr._end - 1)
        n = sprintf(buf, "%d;", rr._start);
    else
        n = sprintf(buf, "%d-%d;", rr._start, rr._end - 1);
    s.append(buf, n);
}

void persist(std::string &s, const ranger &r)
{
    s.clear();
    if (r.empty())
        return;

    for (auto &rr : r)
        persist_range_single(s, rr);

    s.erase(s.size() - 1);
}

void persist_range(std::string &s, const ranger &r, const ranger::range &rr)
{
    s.clear();
    if (r.empty())
        return;

    auto rit = r.find(rr._start).first;
    for (; rit != r.end() && rit->_start < rr._end; ++rit)
        persist_range_single(s, *rit);

    s.erase(s.size() - 1);
}

void persist_slice(std::string &s, const ranger &r, int start, int back)
{
    persist_range(s, r, {start, back+1});
}

// return 0 on success, (-1 - (position in string)) on parse failure
int load(ranger &r, const char *s)
{
    const char *sstart = s;
    while (*s) {
        char *sp;
        int start = strtol(s, &sp, 10);
        int back;
        if (s == sp)
            // no int parsed is ok as long as we're at the end
            return *s ? -1 - int(s - sstart) : 0;
        s = sp;
        if (*sp == '-') {
            s++;
            back = strtol(s, &sp, 10);
            if (s == sp)
                // a number should have followed '-'
                return -1 - int(s - sstart);
            s = sp;
        } else {
            back = start;
        }
        if (*s == ';')
            s++;
        else if (*s)
            // expected either ';' or end of string
            return -1 - int(s - sstart);
        r.insert({start, back + 1});
    }
    return 0;
}

<commit_msg>fix range-edge handling for persist_range<commit_after>#include "condor_common.h"

#include <algorithm>
#include "ranger.h"

///// ranger insert/erase/find implementation /////

ranger::iterator ranger::insert(ranger::range r)
{
    // lower_bound here will coalesce an adjacent disjoint range;
    // can use upper_bound instead to avoid this and leave them fractured
    iterator it_start = forest.lower_bound(r._start);
    iterator it = it_start;
    while (it != forest.end() && it->_start <= r._end)  // '<' for no coalesce
        ++it;

    iterator it_end = it;
    if (it_start == it_end)
        return forest.insert(it_end, r);

    if (it_start->contains(r))
        return it_start;

    iterator it_back = --it;
    range rr_new = { std::min(it_start->_start, r._start),
                     std::max(it_back->_end, r._end) };

    // avoid erase+insert if only expanding a range
    if (it_start == it_back) {
        it_start->_start = rr_new._start;
        it_start->_end = rr_new._end;
        return it_start;
    }

    iterator hint = forest.erase(it_start, it_end);

    return forest.insert(hint, rr_new);
}

static
bool shrink_single_edge(const ranger::range &rm, const ranger::range &at)
{
    bool erase_start = rm._start <= at._start;
    bool erase_back  = at._end   <= rm._end;
    if (erase_start ^ erase_back) {
        if (erase_start)
            at._start = rm._end;
        else
            at._end = rm._start;
        return true;
    }
    return false;
}

ranger::iterator ranger::erase(ranger::range r)
{
    iterator it_start = forest.upper_bound(r._start);
    iterator it = it_start;
    while (it != forest.end() && it->_start < r._end)
        ++it;

    iterator it_end = it;
    if (it_start == it_end)
        return it_start;

    iterator it_back = --it;

    // avoid erase+insert if only shrinking an edge of a range
    if (it_start == it_back && shrink_single_edge(r, *it_start))
        return it_start;

    range rr_start = *it_start;
    range rr_back  = *it_back;

    iterator hint = forest.erase(it_start, it_end);
    if (rr_start._start < r._start)
        hint = forest.insert(hint, {rr_start._start, r._start});

    if (r._end < rr_back._end)
        hint = forest.insert(hint, {r._end, rr_back._end});

    return hint;
}

std::pair<ranger::iterator, bool>
ranger::find(value_type x) const
{
    iterator it = forest.upper_bound(x);
    return {it, it != forest.end() && it->_start <= x};
}

bool ranger::contains(value_type x) const
{
    return find(x).second;
}

ranger::ranger(const std::initializer_list<ranger::range> &il)
{
    for (const range &rr : il)
        insert(rr);
}

///// ranger::elements::iterator implementation /////

/* This allows:
 *
 *      for (int i : myranger.get_elements())
 *          process_int(i);
 *
 *
 * Instead of the still-straightforward:
 *
 *      for (auto &rr : myranger)
 *          for (int i : rr)
 *              process_int(i);
 */

void ranger::elements::iterator::mk_valid()
{
    if (!rit_valid) {
        rit = sit->begin();
        rit_valid = true;
    }
}

ranger::value_type ranger::elements::iterator::operator*()
{
    mk_valid();
    return *rit;
}

ranger::elements::iterator &ranger::elements::iterator::operator++()
{
    mk_valid();
    if (++rit == sit->end()) {
        ++sit;
        rit_valid = false;
    }
    return *this;
}

ranger::elements::iterator &ranger::elements::iterator::operator--()
{
    mk_valid();
    if (rit == sit->begin()) {
        --sit;
        rit = sit->end();
        --rit;
    }
    return *this;
}

bool ranger::elements::iterator::operator==(iterator &it)
{
    if (sit != it.sit)
        return false;
    if (!rit_valid && !it.rit_valid)
        return true;
    // at this point neither sit nor it.sit points to the end() of its set,
    // thus it's OK to call mk_valid() on each, which may dereference *sit
    mk_valid();
    it.mk_valid();
    return rit == it.rit;
}

bool ranger::elements::iterator::operator!=(iterator &it)
{
    return !(*this == it);
}

///// ranger persist/load implementation /////

#include <stdlib.h> // strtol
#include <stdio.h>  // sprintf
#include <string>

/*  persist / load ranger objects
 *
 *  The serialized format is one or more sub-ranges, separated by semicolons,
 *  where each sub-range is either N-M (for inclusive N..M) or N for a single
 *  integer.  Eg, "2", "5-10", "4;7;10-20;44;50-60"
 */

static
void persist_range_single(std::string &s, const ranger::range &rr)
{
    char buf[64];
    int n;
    if (rr._start == rr._end - 1)
        n = sprintf(buf, "%d;", rr._start);
    else
        n = sprintf(buf, "%d-%d;", rr._start, rr._end - 1);
    s.append(buf, n);
}

void persist(std::string &s, const ranger &r)
{
    s.clear();
    if (r.empty())
        return;

    for (auto &rr : r)
        persist_range_single(s, rr);

    s.erase(s.size() - 1);
}

void persist_range(std::string &s, const ranger &r, const ranger::range &rr)
{
    s.clear();
    if (r.empty())
        return;

    auto rit = r.find(rr._start).first;
    for (; rit != r.end() && rit->_start < rr._end; ++rit) {
        ranger::range rr_new = { std::max(rit->_start, rr._start),
                                 std::min(rit->_end,   rr._end) };
        persist_range_single(s, rr_new);
    }

    s.erase(s.size() - 1);
}

void persist_slice(std::string &s, const ranger &r, int start, int back)
{
    persist_range(s, r, {start, back+1});
}

// return 0 on success, (-1 - (position in string)) on parse failure
int load(ranger &r, const char *s)
{
    const char *sstart = s;
    while (*s) {
        char *sp;
        int start = strtol(s, &sp, 10);
        int back;
        if (s == sp)
            // no int parsed is ok as long as we're at the end
            return *s ? -1 - int(s - sstart) : 0;
        s = sp;
        if (*sp == '-') {
            s++;
            back = strtol(s, &sp, 10);
            if (s == sp)
                // a number should have followed '-'
                return -1 - int(s - sstart);
            s = sp;
        } else {
            back = start;
        }
        if (*s == ';')
            s++;
        else if (*s)
            // expected either ';' or end of string
            return -1 - int(s - sstart);
        r.insert({start, back + 1});
    }
    return 0;
}

<|endoftext|>


<commit_before><commit_msg>Added the missing reuse app<commit_after><|endoftext|>


<commit_before>#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

bool second_row_protected(const std::string& first_row,
                          bool protect_without_king)
{
    const int size = first_row.size();

    std::vector<bool> second_row(size);

    for (auto i = 0; i < size; i++) {
        if (protect_without_king && first_row[i] == 'K')
            continue;

        switch (first_row[i]) {  // no break statements indeed
        case 'S':
        case 'G':
        case 'K':
            if (i-1 >= 0)
                second_row[i-1] = true;
            if (i+1 < size)
                second_row[i+1] = true;
        case 'L':
            second_row[i] = true;
        }
    }

    return std::all_of(second_row.begin(), second_row.end(),
                       [](bool i) { return i; });
}

int main(int argc, char **argv)
{
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "produce help message")
        ("protect", "protect all squares on second row")
        ("protect-more",
         "protect all squares on second row without the help of the king")
    ;

    po::variables_map vm;
    try {
        po::store(po::parse_command_line(argc, argv, desc), vm);
        po::notify(vm);
    } catch (po::unknown_option& e) {
        std::cerr << desc;
        return 1;
    }

    if (vm.count("help")) {
        std::cerr << desc;
        return 1;
    } else if (vm.count("protect") && vm.count("protect-more")) {
        std::cerr << "Options --protect and --protect-more cannot be used "
                     "together\n";
        return 1;
    }

    // piece abbreviations come from http://en.wikipedia.org/wiki/Shogi
    std::string first_row("LNSGKGSNL");
    std::sort(first_row.begin(), first_row.end());

    const bool protect = vm.count("protect") || vm.count("protect-more");
    const bool protect_without_king = vm.count("protect-more");
    do {
        if (!protect || second_row_protected(first_row, protect_without_king))
            std::cout << first_row << '\n';
    } while (std::next_permutation(first_row.begin(), first_row.end()));

    return 0;
}
<commit_msg>Fix g++ (GCC) 7.2.1 compilation failure<commit_after>#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

bool second_row_protected(const std::string& first_row,
                          bool protect_without_king)
{
    const int size = first_row.size();

    std::vector<bool> second_row(size);

    for (auto i = 0; i < size; i++) {
        if (protect_without_king && first_row[i] == 'K')
            continue;

        switch (first_row[i]) {  // no break statements indeed
        case 'S':
        case 'G':
        case 'K':
            if (i-1 >= 0)
                second_row[i-1] = true;
            if (i+1 < size)
                second_row[i+1] = true;
            // fallthrough
        case 'L':
            second_row[i] = true;
        }
    }

    return std::all_of(second_row.begin(), second_row.end(),
                       [](bool i) { return i; });
}

int main(int argc, char **argv)
{
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "produce help message")
        ("protect", "protect all squares on second row")
        ("protect-more",
         "protect all squares on second row without the help of the king")
    ;

    po::variables_map vm;
    try {
        po::store(po::parse_command_line(argc, argv, desc), vm);
        po::notify(vm);
    } catch (po::unknown_option& e) {
        std::cerr << desc;
        return 1;
    }

    if (vm.count("help")) {
        std::cerr << desc;
        return 1;
    } else if (vm.count("protect") && vm.count("protect-more")) {
        std::cerr << "Options --protect and --protect-more cannot be used "
                     "together\n";
        return 1;
    }

    // piece abbreviations come from http://en.wikipedia.org/wiki/Shogi
    std::string first_row("LNSGKGSNL");
    std::sort(first_row.begin(), first_row.end());

    const bool protect = vm.count("protect") || vm.count("protect-more");
    const bool protect_without_king = vm.count("protect-more");
    do {
        if (!protect || second_row_protected(first_row, protect_without_king))
            std::cout << first_row << '\n';
    } while (std::next_permutation(first_row.begin(), first_row.end()));

    return 0;
}
<|endoftext|>


<commit_before>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

#include <mapper/mapper.h>

#include "pwm_synth/pwm.h"

int done = 0;

void ctrlc(int)
{
    done = 1;
}

void handler_freq(mapper_signal msig,
                  mapper_db_signal props,
                  int instance_id,
                  void *value,
                  int count,
                  mapper_timetag_t *timetag)
{
    if (value) {
        float *pfreq = (float*)value;
        set_freq(*pfreq);
    }
}

void handler_gain(mapper_signal msig,
                  mapper_db_signal props,
                  int instance_id,
                  void *value,
                  int count,
                  mapper_timetag_t *timetag)
{
    if (value) {
        float *pgain = (float*)value;
        set_gain(*pgain);
    }
    else
        set_gain(0);
}

void handler_duty(mapper_signal msig,
                  mapper_db_signal props,
                  int instance_id,
                  void *value,
                  int count,
                  mapper_timetag_t *timetag)
{
    if (value) {
        float *pduty = (float*)value;
        set_duty(*pduty);
    }
}

int main()
{
    signal(SIGINT, ctrlc);

    mapper_device dev = mdev_new("pwm", 9000, 0);

    float min0 = 0;
    float max1 = 1;
    float max1000 = 1000;

    mdev_add_input(dev, "/freq", 1, 'f', "Hz", &min0, &max1000,
                   handler_freq, 0);
    mdev_add_input(dev, "/gain", 1, 'f', "Hz", &min0, &max1,
                   handler_gain, 0);
    mdev_add_input(dev, "/duty", 1, 'f', "Hz", &min0, &max1,
                   handler_duty, 0);

    run_synth();

    set_duty(0.1);
    set_freq(110.0);
    set_gain(0.1);

    printf("Press Ctrl-C to quit.\n");

    while (!done)
        mdev_poll(dev, 10);

    mdev_free(dev);

    set_freq(0);
    sleep(1);

    stop_synth();
}
<commit_msg>Updated example.<commit_after>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

#include <mapper/mapper.h>

#include "pwm_synth/pwm.h"

int done = 0;

void ctrlc(int)
{
    done = 1;
}

void handler_freq(mapper_signal sig, int instance_id, const void *value,
                  int count, mapper_timetag_t *timetag)
{
    if (value) {
        float *pfreq = (float*)value;
        set_freq(*pfreq);
    }
}

void handler_gain(mapper_signal sig, int instance_id, const void *value,
                  int count, mapper_timetag_t *timetag)
{
    if (value) {
        float *pgain = (float*)value;
        set_gain(*pgain);
    }
    else
        set_gain(0);
}

void handler_duty(mapper_signal sig, int instance_id, const void *value,
                  int count, mapper_timetag_t *timetag)
{
    if (value) {
        float *pduty = (float*)value;
        set_duty(*pduty);
    }
}

int main()
{
    signal(SIGINT, ctrlc);

    mapper_device dev = mapper_device_new("pwm", 9000, 0);

    float min0 = 0;
    float max1 = 1;
    float max1000 = 1000;

    mapper_device_add_input(dev, "/freq", 1, 'f', "Hz", &min0, &max1000,
                            handler_freq, 0);
    mapper_device_add_input(dev, "/gain", 1, 'f', "Hz", &min0, &max1,
                            handler_gain, 0);
    mapper_device_add_input(dev, "/duty", 1, 'f', "Hz", &min0, &max1,
                            handler_duty, 0);

    run_synth();

    set_duty(0.1);
    set_freq(110.0);
    set_gain(0.1);

    printf("Press Ctrl-C to quit.\n");

    while (!done)
        mapper_device_poll(dev, 10);

    mapper_device_free(dev);

    set_freq(0);
    sleep(1);

    stop_synth();
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <TopExp.hxx>
# include <TopTools_IndexedMapOfShape.hxx>
#endif

#include "ViewProviderCompound.h"
#include <Gui/Application.h>
#include <Mod/Part/App/FeatureCompound.h>

using namespace PartGui;

PROPERTY_SOURCE(PartGui::ViewProviderCompound,PartGui::ViewProviderPart)

ViewProviderCompound::ViewProviderCompound()
{
}

ViewProviderCompound::~ViewProviderCompound()
{
}

std::vector<App::DocumentObject*> ViewProviderCompound::claimChildren(void) const
{
    return static_cast<Part::Compound*>(getObject())->Links.getValues();
}

bool ViewProviderCompound::onDelete(const std::vector<std::string> &)
{
    // get the input shapes
    Part::Compound* pComp = static_cast<Part::Compound*>(getObject());
    std::vector<App::DocumentObject*> pLinks = pComp->Links.getValues();
    for (std::vector<App::DocumentObject*>::iterator it = pLinks.begin(); it != pLinks.end(); ++it) {
        if (*it)
            Gui::Application::Instance->showViewProvider(*it);
    }

    return true;
}

void ViewProviderCompound::updateData(const App::Property* prop)
{
    PartGui::ViewProviderPart::updateData(prop);
    if (prop->getTypeId() == Part::PropertyShapeHistory::getClassTypeId()) {
        const std::vector<Part::ShapeHistory>& hist = static_cast<const Part::PropertyShapeHistory*>
            (prop)->getValues();
        Part::Compound* objComp = static_cast<Part::Compound*>(getObject());
        std::vector<App::DocumentObject*> sources = objComp->Links.getValues();
        if (hist.size() != sources.size())
            return;

        const TopoDS_Shape& compShape = objComp->Shape.getValue();
        TopTools_IndexedMapOfShape compMap;
        TopExp::MapShapes(compShape, TopAbs_FACE, compMap);

        std::vector<App::Color> compCol;
        compCol.resize(compMap.Extent(), this->ShapeColor.getValue());

        bool setColor=false;
        int index=0;
        for (std::vector<App::DocumentObject*>::iterator it = sources.begin(); it != sources.end(); ++it, ++index) {
            Part::Feature* objBase = dynamic_cast<Part::Feature*>(*it);
            if (!objBase)
                continue;

            const TopoDS_Shape& baseShape = objBase->Shape.getValue();

            TopTools_IndexedMapOfShape baseMap;
            TopExp::MapShapes(baseShape, TopAbs_FACE, baseMap);

            Gui::ViewProvider* vpBase = Gui::Application::Instance->getViewProvider(objBase);
            std::vector<App::Color> baseCol = static_cast<PartGui::ViewProviderPart*>(vpBase)->DiffuseColor.getValues();
            if (static_cast<int>(baseCol.size()) == baseMap.Extent()) {
                applyColor(hist[index], baseCol, compCol);
                setColor = true;
            }
            else if (!baseCol.empty() && baseCol[0] != this->ShapeColor.getValue()) {
                baseCol.resize(baseMap.Extent(), baseCol[0]);
                applyColor(hist[index], baseCol, compCol);
                setColor = true;
            }
        }

        if (setColor)
            this->DiffuseColor.setValues(compCol);
    }
    else if (prop->getTypeId() == App::PropertyLinkList::getClassTypeId()) {
        const std::vector<App::DocumentObject *>& pBases = static_cast<const App::PropertyLinkList*>(prop)->getValues();
        for (std::vector<App::DocumentObject *>::const_iterator it = pBases.begin(); it != pBases.end(); ++it) {
            if (*it) Gui::Application::Instance->hideViewProvider(*it);
        }
    }
}
<commit_msg>Part: Support subcomponent transparencies in compounds<commit_after>/***************************************************************************
 *   Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <TopExp.hxx>
# include <TopTools_IndexedMapOfShape.hxx>
#endif

#include "ViewProviderCompound.h"
#include <Gui/Application.h>
#include <Mod/Part/App/FeatureCompound.h>

using namespace PartGui;

PROPERTY_SOURCE(PartGui::ViewProviderCompound,PartGui::ViewProviderPart)

ViewProviderCompound::ViewProviderCompound()
{
}

ViewProviderCompound::~ViewProviderCompound()
{
}

std::vector<App::DocumentObject*> ViewProviderCompound::claimChildren(void) const
{
    return static_cast<Part::Compound*>(getObject())->Links.getValues();
}

bool ViewProviderCompound::onDelete(const std::vector<std::string> &)
{
    // get the input shapes
    Part::Compound* pComp = static_cast<Part::Compound*>(getObject());
    std::vector<App::DocumentObject*> pLinks = pComp->Links.getValues();
    for (std::vector<App::DocumentObject*>::iterator it = pLinks.begin(); it != pLinks.end(); ++it) {
        if (*it)
            Gui::Application::Instance->showViewProvider(*it);
    }

    return true;
}

void ViewProviderCompound::updateData(const App::Property* prop)
{
    PartGui::ViewProviderPart::updateData(prop);
    if (prop->getTypeId() == Part::PropertyShapeHistory::getClassTypeId()) {
        const std::vector<Part::ShapeHistory>& hist = static_cast<const Part::PropertyShapeHistory*>
            (prop)->getValues();
        Part::Compound* objComp = static_cast<Part::Compound*>(getObject());
        std::vector<App::DocumentObject*> sources = objComp->Links.getValues();
        if (hist.size() != sources.size())
            return;

        const TopoDS_Shape& compShape = objComp->Shape.getValue();
        TopTools_IndexedMapOfShape compMap;
        TopExp::MapShapes(compShape, TopAbs_FACE, compMap);

        std::vector<App::Color> compCol;
        compCol.resize(compMap.Extent(), this->ShapeColor.getValue());

        bool setColor=false;
        int index=0;
        for (std::vector<App::DocumentObject*>::iterator it = sources.begin(); it != sources.end(); ++it, ++index) {
            Part::Feature* objBase = dynamic_cast<Part::Feature*>(*it);
            if (!objBase)
                continue;

            const TopoDS_Shape& baseShape = objBase->Shape.getValue();

            TopTools_IndexedMapOfShape baseMap;
            TopExp::MapShapes(baseShape, TopAbs_FACE, baseMap);

            Gui::ViewProvider* vpBase = Gui::Application::Instance->getViewProvider(objBase);
            std::vector<App::Color> baseCol = static_cast<PartGui::ViewProviderPart*>(vpBase)->DiffuseColor.getValues();
            applyTransparency(static_cast<PartGui::ViewProviderPart*>(vpBase)->Transparency.getValue(),baseCol);
            if (static_cast<int>(baseCol.size()) == baseMap.Extent()) {
                applyColor(hist[index], baseCol, compCol);
                setColor = true;
            }
            else if (!baseCol.empty() && baseCol[0] != this->ShapeColor.getValue()) {
                baseCol.resize(baseMap.Extent(), baseCol[0]);
                applyColor(hist[index], baseCol, compCol);
                setColor = true;
            }
        }

        if (setColor)
            this->DiffuseColor.setValues(compCol);
    }
    else if (prop->getTypeId() == App::PropertyLinkList::getClassTypeId()) {
        const std::vector<App::DocumentObject *>& pBases = static_cast<const App::PropertyLinkList*>(prop)->getValues();
        for (std::vector<App::DocumentObject *>::const_iterator it = pBases.begin(); it != pBases.end(); ++it) {
            if (*it) Gui::Application::Instance->hideViewProvider(*it);
        }
    }
}
<|endoftext|>


<commit_before>
#include "connection.h"
#include "room.h"
#include "user.h"
#include "jobs/sendeventjob.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QStringBuilder>
#include <QtCore/QTimer>
#include <iostream>

using namespace QMatrixClient;
using std::cout;
using std::endl;
using namespace std::placeholders;

class QMCTest : public QObject
{
    public:
        QMCTest(Connection* conn, const QString& testRoomName, QString source);

    private slots:
        void onNewRoom(Room* r, const QString& testRoomName);
        void doTests();
        void addAndRemoveTag();
        void sendAndRedact();
        void finalize();

    private:
        QScopedPointer<Connection, QScopedPointerDeleteLater> c;
        QString origin;
        Room* targetRoom = nullptr;
        int semaphor = 0;

};

#define QMC_CHECK(description, condition) \
    cout << (description) \
         << (!!(condition) ? " successul" : " FAILED") << endl; \
    targetRoom->postMessage(origin % ": " % QStringLiteral(description) % \
        (!!(condition) ? QStringLiteral(" successful") : \
                         QStringLiteral(" FAILED")), MessageEventType::Notice)

QMCTest::QMCTest(Connection* conn, const QString& testRoomName, QString source)
    : c(conn), origin(std::move(source))
{
    if (!origin.isEmpty())
        cout << "Origin for the test message: " << origin.toStdString() << endl;
    if (!testRoomName.isEmpty())
        cout << "Test room name: " << testRoomName.toStdString() << endl;

    connect(c.data(), &Connection::newRoom,
            this, [this,testRoomName] (Room* r) { onNewRoom(r, testRoomName); });
    connect(c.data(), &Connection::syncDone, c.data(), [this] {
        cout << "Sync complete, " << semaphor << " tests in the air" << endl;
        if (semaphor)
        {
//            if (targetRoom)
//                targetRoom->postMessage(
//                    QString("%1: sync done, %2 test(s) in the air")
//                        .arg(origin).arg(semaphor),
//                    MessageEventType::Notice);
            c->sync(10000);
        }
        else
        {
            if (targetRoom)
            {
                auto j = c->callApi<SendEventJob>(targetRoom->id(),
                        RoomMessageEvent(origin % ": All tests finished"));
                connect(j, &BaseJob::finished, this, &QMCTest::finalize);
            }
            else
                finalize();
        }
    });
    // Big countdown watchdog
    QTimer::singleShot(180000, this, &QMCTest::finalize);
}

void QMCTest::onNewRoom(Room* r, const QString& testRoomName)
{
    cout << "New room: " << r->id().toStdString() << endl;
    connect(r, &Room::namesChanged, this, [=] {
        cout << "Room " << r->id().toStdString() << ", name(s) changed:" << endl
             << "  Name: " << r->name().toStdString() << endl
             << "  Canonical alias: " << r->canonicalAlias().toStdString() << endl
             << endl << endl;
        if (!testRoomName.isEmpty() && (r->name() == testRoomName ||
                r->canonicalAlias() == testRoomName))
        {
            cout << "Found the target room, proceeding for tests" << endl;
            targetRoom = r;
            ++semaphor;
            auto j = targetRoom->connection()->callApi<SendEventJob>(
                targetRoom->id(),
                RoomMessageEvent(origin % ": connected to test room",
                MessageEventType::Notice));
            connect(j, &BaseJob::success,
                    this, [this] { doTests(); --semaphor; });
        }
    });
    connect(r, &Room::aboutToAddNewMessages, r, [r] (RoomEventsRange timeline) {
        cout << timeline.size() << " new event(s) in room "
             << r->id().toStdString() << endl;
//        for (const auto& item: timeline)
//        {
//            cout << "From: "
//                 << r->roomMembername(item->senderId()).toStdString()
//                 << endl << "Timestamp:"
//                 << item->timestamp().toString().toStdString() << endl
//                 << "JSON:" << endl << item->originalJson().toStdString() << endl;
//        }
    });
}

void QMCTest::doTests()
{
    addAndRemoveTag();
    sendAndRedact();
}

void QMCTest::addAndRemoveTag()
{
    ++semaphor;
    static const auto TestTag = QStringLiteral("org.qmatrixclient.test");
    QObject::connect(targetRoom, &Room::tagsChanged, targetRoom, [=] {
        cout << "Room " << targetRoom->id().toStdString()
             << ", tag(s) changed:" << endl
             << "  " << targetRoom->tagNames().join(", ").toStdString() << endl;
        if (targetRoom->tags().contains(TestTag))
        {
            cout << "Test tag set, removing it now" << endl;
            targetRoom->removeTag(TestTag);
            QMC_CHECK("Tagging test", !targetRoom->tags().contains(TestTag));
            --semaphor;
            QObject::disconnect(targetRoom, &Room::tagsChanged, nullptr, nullptr);
        }
    });
    // The reverse order because tagsChanged is emitted synchronously.
    cout << "Adding a tag" << endl;
    targetRoom->addTag(TestTag);
}

void QMCTest::sendAndRedact()
{
    ++semaphor;
    cout << "Sending a message to redact" << endl;
    auto* job = targetRoom->connection()->callApi<SendEventJob>(targetRoom->id(),
            RoomMessageEvent(origin % ": Message to redact"));
    QObject::connect(job, &BaseJob::success, targetRoom, [job,this] {
        cout << "Message to redact has been succesfully sent, redacting" << endl;
        targetRoom->redactEvent(job->eventId(), "qmc-example");
    });
    QObject::connect(targetRoom, &Room::replacedEvent, targetRoom,
        [=] (const RoomEvent* newEvent) {
            QMC_CHECK("Redaction", newEvent->isRedacted() &&
                        newEvent->redactionReason() == "qmc-example");
            --semaphor;
            QObject::disconnect(targetRoom, &Room::replacedEvent,
                                nullptr, nullptr);
        });
}

void QMCTest::finalize()
{
    if (semaphor)
        cout << "One or more tests FAILED" << endl;
    cout << "Logging out" << endl;
    c->logout();
    connect(c.data(), &Connection::loggedOut, QCoreApplication::instance(),
        [this] {
            c->deleteLater();
            QCoreApplication::processEvents();
            QCoreApplication::exit(semaphor);
        });
}

int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);
    if (argc < 4)
    {
        cout << "Usage: qmc-example <user> <passwd> <device_name> [<room_alias> [origin]]" << endl;
        return -1;
    }

    cout << "Connecting to the server as " << argv[1] << endl;
    auto conn = new Connection;
    conn->connectToServer(argv[1], argv[2], argv[3]);
    QObject::connect(conn, &Connection::connected, [=] {
        cout << "Connected, server: "
             << conn->homeserver().toDisplayString().toStdString() << endl;
        cout << "Access token: " << conn->accessToken().toStdString() << endl;
        conn->sync();
    });
    QMCTest test { conn, argc >= 5 ? argv[4] : nullptr,
                         argc >= 6 ? argv[5] : nullptr };
    return app.exec();
}
<commit_msg>qmc-example: Ensure prerequisites before running the tagging test<commit_after>
#include "connection.h"
#include "room.h"
#include "user.h"
#include "jobs/sendeventjob.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QStringBuilder>
#include <QtCore/QTimer>
#include <iostream>

using namespace QMatrixClient;
using std::cout;
using std::endl;
using namespace std::placeholders;

class QMCTest : public QObject
{
    public:
        QMCTest(Connection* conn, const QString& testRoomName, QString source);

    private slots:
        void onNewRoom(Room* r, const QString& testRoomName);
        void doTests();
        void addAndRemoveTag();
        void sendAndRedact();
        void finalize();

    private:
        QScopedPointer<Connection, QScopedPointerDeleteLater> c;
        QString origin;
        Room* targetRoom = nullptr;
        int semaphor = 0;

};

#define QMC_CHECK(description, condition) \
    cout << (description) \
         << (!!(condition) ? " successul" : " FAILED") << endl; \
    targetRoom->postMessage(origin % ": " % QStringLiteral(description) % \
        (!!(condition) ? QStringLiteral(" successful") : \
                         QStringLiteral(" FAILED")), MessageEventType::Notice)

QMCTest::QMCTest(Connection* conn, const QString& testRoomName, QString source)
    : c(conn), origin(std::move(source))
{
    if (!origin.isEmpty())
        cout << "Origin for the test message: " << origin.toStdString() << endl;
    if (!testRoomName.isEmpty())
        cout << "Test room name: " << testRoomName.toStdString() << endl;

    connect(c.data(), &Connection::newRoom,
            this, [this,testRoomName] (Room* r) { onNewRoom(r, testRoomName); });
    connect(c.data(), &Connection::syncDone, c.data(), [this] {
        cout << "Sync complete, " << semaphor << " tests in the air" << endl;
        if (semaphor)
        {
//            if (targetRoom)
//                targetRoom->postMessage(
//                    QString("%1: sync done, %2 test(s) in the air")
//                        .arg(origin).arg(semaphor),
//                    MessageEventType::Notice);
            c->sync(10000);
        }
        else
        {
            if (targetRoom)
            {
                auto j = c->callApi<SendEventJob>(targetRoom->id(),
                        RoomMessageEvent(origin % ": All tests finished"));
                connect(j, &BaseJob::finished, this, &QMCTest::finalize);
            }
            else
                finalize();
        }
    });
    // Big countdown watchdog
    QTimer::singleShot(180000, this, &QMCTest::finalize);
}

void QMCTest::onNewRoom(Room* r, const QString& testRoomName)
{
    cout << "New room: " << r->id().toStdString() << endl;
    connect(r, &Room::namesChanged, this, [=] {
        cout << "Room " << r->id().toStdString() << ", name(s) changed:" << endl
             << "  Name: " << r->name().toStdString() << endl
             << "  Canonical alias: " << r->canonicalAlias().toStdString() << endl
             << endl << endl;
        if (!testRoomName.isEmpty() && (r->name() == testRoomName ||
                r->canonicalAlias() == testRoomName))
        {
            cout << "Found the target room, proceeding for tests" << endl;
            targetRoom = r;
            ++semaphor;
            auto j = targetRoom->connection()->callApi<SendEventJob>(
                targetRoom->id(),
                RoomMessageEvent(origin % ": connected to test room",
                MessageEventType::Notice));
            connect(j, &BaseJob::success,
                    this, [this] { doTests(); --semaphor; });
        }
    });
    connect(r, &Room::aboutToAddNewMessages, r, [r] (RoomEventsRange timeline) {
        cout << timeline.size() << " new event(s) in room "
             << r->id().toStdString() << endl;
//        for (const auto& item: timeline)
//        {
//            cout << "From: "
//                 << r->roomMembername(item->senderId()).toStdString()
//                 << endl << "Timestamp:"
//                 << item->timestamp().toString().toStdString() << endl
//                 << "JSON:" << endl << item->originalJson().toStdString() << endl;
//        }
    });
}

void QMCTest::doTests()
{
    addAndRemoveTag();
    sendAndRedact();
}

void QMCTest::addAndRemoveTag()
{
    ++semaphor;
    static const auto TestTag = QStringLiteral("org.qmatrixclient.test");
    // Pre-requisite
    if (targetRoom->tags().contains(TestTag))
        targetRoom->removeTag(TestTag);

    QObject::connect(targetRoom, &Room::tagsChanged, targetRoom, [=] {
        cout << "Room " << targetRoom->id().toStdString()
             << ", tag(s) changed:" << endl
             << "  " << targetRoom->tagNames().join(", ").toStdString() << endl;
        if (targetRoom->tags().contains(TestTag))
        {
            cout << "Test tag set, removing it now" << endl;
            targetRoom->removeTag(TestTag);
            QMC_CHECK("Tagging test", !targetRoom->tags().contains(TestTag));
            --semaphor;
            QObject::disconnect(targetRoom, &Room::tagsChanged, nullptr, nullptr);
        }
    });
    // The reverse order because tagsChanged is emitted synchronously.
    cout << "Adding a tag" << endl;
    targetRoom->addTag(TestTag);
}

void QMCTest::sendAndRedact()
{
    ++semaphor;
    cout << "Sending a message to redact" << endl;
    auto* job = targetRoom->connection()->callApi<SendEventJob>(targetRoom->id(),
            RoomMessageEvent(origin % ": Message to redact"));
    QObject::connect(job, &BaseJob::success, targetRoom, [job,this] {
        cout << "Message to redact has been succesfully sent, redacting" << endl;
        targetRoom->redactEvent(job->eventId(), "qmc-example");
    });
    QObject::connect(targetRoom, &Room::replacedEvent, targetRoom,
        [=] (const RoomEvent* newEvent) {
            QMC_CHECK("Redaction", newEvent->isRedacted() &&
                        newEvent->redactionReason() == "qmc-example");
            --semaphor;
            QObject::disconnect(targetRoom, &Room::replacedEvent,
                                nullptr, nullptr);
        });
}

void QMCTest::finalize()
{
    if (semaphor)
        cout << "One or more tests FAILED" << endl;
    cout << "Logging out" << endl;
    c->logout();
    connect(c.data(), &Connection::loggedOut, QCoreApplication::instance(),
        [this] {
            c->deleteLater();
            QCoreApplication::processEvents();
            QCoreApplication::exit(semaphor);
        });
}

int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);
    if (argc < 4)
    {
        cout << "Usage: qmc-example <user> <passwd> <device_name> [<room_alias> [origin]]" << endl;
        return -1;
    }

    cout << "Connecting to the server as " << argv[1] << endl;
    auto conn = new Connection;
    conn->connectToServer(argv[1], argv[2], argv[3]);
    QObject::connect(conn, &Connection::connected, [=] {
        cout << "Connected, server: "
             << conn->homeserver().toDisplayString().toStdString() << endl;
        cout << "Access token: " << conn->accessToken().toStdString() << endl;
        conn->sync();
    });
    QMCTest test { conn, argc >= 5 ? argv[4] : nullptr,
                         argc >= 6 ? argv[5] : nullptr };
    return app.exec();
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Standard implementation of the "transpose" algorithm
 */

#pragma once

#include "etl/temporary.hpp"

namespace etl {

namespace impl {

namespace standard {

/*!
 * \brief Inplace transposition of the square matrix c
 * \param c The matrix to transpose
 */
template <typename C>
void inplace_square_transpose(C&& c) {
    using std::swap;

    const size_t N = etl::dim<0>(c);

    for (size_t i = 0; i < N - 1; ++i) {
        size_t j = i + 1;

        for (; j + 1 < N; j += 2) {
            swap(c(i, j + 0), c(j + 0, i));
            swap(c(i, j + 1), c(j + 1, i));
        }

        if (j < N) {
            swap(c(i, j), c(j, i));
        }
    }
}

/*!
 * \brief Inplace transposition of the rectangular matrix c
 * \param mat The matrix to transpose
 */
template <typename C>
void inplace_rectangular_transpose(C&& mat) {
    auto copy = force_temporary(mat);

    //Dimensions prior to transposition
    const size_t N = etl::dim<0>(mat);
    const size_t M = etl::dim<1>(mat);

    for (size_t i = 0; i < N; ++i) {
        size_t j = 0;

        for (; j + 1 < M; j += 2) {
            mat(j + 0, i) = copy(i, (j + 0));
            mat(j + 1, i) = copy(i, (j + 1));
        }

        if (j < M) {
            mat(j, i) = copy(i, j);
        }
    }
}

/*!
 * \brief Perform an inplace matrix transposition in O(1).
 *
 * This implementation is quite slow and should only be used when space is of
 * the essence.
 *
 * \param mat the matrix to transpose inplace
 */
template <typename C>
void real_inplace(C&& mat) {
    using std::swap;

    const size_t N = etl::dim<0>(mat);
    const size_t M = etl::dim<1>(mat);

    auto data = mat.memory_start();

    for (size_t k = 0; k < N * M; k++) {
        auto idx = k;
        do {
            idx = (idx % N) * M + (idx / N);
        } while (idx < k);
        std::swap(data[k], data[idx]);
    }
}

/*!
 * \brief Transpose the matrix a and the store the result in c
 * \param a The matrix to transpose
 * \param c The target matrix
 */
template <typename A, typename C>
void transpose(A&& a, C&& c) {
    // Delegate aliasing transpose to inplace algorithm
    if (a.alias(c)) {
        if (etl::dim<0>(a) == etl::dim<1>(a)) {
            inplace_square_transpose(c);
        } else {
            inplace_rectangular_transpose(c);
        }
    } else {
        const size_t m = etl::dim<0>(a);
        const size_t n = etl::dim<1>(a);

        if (decay_traits<A>::storage_order == order::RowMajor) {
            for (size_t i = 0; i < m; ++i) {
                size_t j = 0;

                for (; j + 3 < n; j += 4) {
                    c(j + 0, i) = a(i, j + 0);
                    c(j + 1, i) = a(i, j + 1);
                    c(j + 2, i) = a(i, j + 2);
                    c(j + 3, i) = a(i, j + 3);
                }

                for (; j + 1 < n; j += 2) {
                    c(j + 0, i) = a(i, j + 0);
                    c(j + 1, i) = a(i, j + 1);
                }

                if (j < n) {
                    c(j, i) = a(i, j);
                }
            }
        } else {
            for (size_t j = 0; j < n; ++j) {
                for (size_t i = 0; i < m; ++i) {
                    c(i, j) = a(j, i);
                }
            }
        }
    }
}

} //end of namespace standard
} //end of namespace impl
} //end of namespace etl
<commit_msg>Fix bad optimization<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Standard implementation of the "transpose" algorithm
 */

#pragma once

#include "etl/temporary.hpp"

namespace etl {

namespace impl {

namespace standard {

/*!
 * \brief Inplace transposition of the square matrix c
 * \param c The matrix to transpose
 */
template <typename C>
void inplace_square_transpose(C&& c) {
    using std::swap;

    const size_t N = etl::dim<0>(c);

    for (size_t i = 0; i < N - 1; ++i) {
        size_t j = i + 1;

        for (; j + 1 < N; j += 2) {
            swap(c(i, j + 0), c(j + 0, i));
            swap(c(i, j + 1), c(j + 1, i));
        }

        if (j < N) {
            swap(c(i, j), c(j, i));
        }
    }
}

/*!
 * \brief Inplace transposition of the rectangular matrix c
 * \param mat The matrix to transpose
 */
template <typename C>
void inplace_rectangular_transpose(C&& mat) {
    auto copy = force_temporary(mat);

    //Dimensions prior to transposition
    const size_t N = etl::dim<0>(mat);
    const size_t M = etl::dim<1>(mat);

    // Note: cannot use operator(i,j) for lhs because it is indexed by its
    // previous scheme (N instead of M)

    for (size_t i = 0; i < N; ++i) {
        size_t j = 0;

        for (; j + 1 < M; j += 2) {
            mat[(j + 0) * N + i] = copy(i, (j + 0));
            mat[(j + 1) * N + i] = copy(i, (j + 1));
        }

        if (j < M) {
            mat[j * N + i] = copy(i, j);
        }
    }
}

/*!
 * \brief Perform an inplace matrix transposition in O(1).
 *
 * This implementation is quite slow and should only be used when space is of
 * the essence.
 *
 * \param mat the matrix to transpose inplace
 */
template <typename C>
void real_inplace(C&& mat) {
    using std::swap;

    const size_t N = etl::dim<0>(mat);
    const size_t M = etl::dim<1>(mat);

    auto data = mat.memory_start();

    for (size_t k = 0; k < N * M; k++) {
        auto idx = k;
        do {
            idx = (idx % N) * M + (idx / N);
        } while (idx < k);
        std::swap(data[k], data[idx]);
    }
}

/*!
 * \brief Transpose the matrix a and the store the result in c
 * \param a The matrix to transpose
 * \param c The target matrix
 */
template <typename A, typename C>
void transpose(A&& a, C&& c) {
    // Delegate aliasing transpose to inplace algorithm
    if (a.alias(c)) {
        if (etl::dim<0>(a) == etl::dim<1>(a)) {
            inplace_square_transpose(c);
        } else {
            inplace_rectangular_transpose(c);
        }
    } else {
        const size_t m = etl::dim<0>(a);
        const size_t n = etl::dim<1>(a);

        // Note: cannot use operator(i,j) for rhs because it is indexed by its
        // previous scheme (M instead of N)

        if (decay_traits<A>::storage_order == order::RowMajor) {

            for (size_t i = 0; i < m; ++i) {
                size_t j = 0;

                for (; j + 3 < n; j += 4) {
                    c[(j + 0) * m + i] = a[i * n + j + 0];
                    c[(j + 1) * m + i] = a[i * n + j + 1];
                    c[(j + 2) * m + i] = a[i * n + j + 2];
                    c[(j + 3) * m + i] = a[i * n + j + 3];
                }

                for (; j + 1 < n; j += 2) {
                    c[(j + 0) * m + i] = a[i * n + j + 0];
                    c[(j + 1) * m + i] = a[i * n + j + 1];
                }

                if (j < n) {
                    c[(j + 0) * m + i] = a[i * n + j];
                }
            }
        } else {
            for (size_t j = 0; j < n; ++j) {
                for (size_t i = 0; i < m; ++i) {
                    c[i * n + j] = a[j * m + i];
                }
            }
        }
    }
}

} //end of namespace standard
} //end of namespace impl
} //end of namespace etl
<|endoftext|>