<commit_before>/*
 * File:   SignalImpl.hpp
 * Author: Barath Kannan
 * Signal/Slots C++14 implementation
 * Created on May 10, 2016, 5:57 PM
 */

#ifndef SIGNALIMPL_HPP
#define SIGNALIMPL_HPP

#include <functional>
#include <map>
#include <unordered_map>
#include <atomic>
#include <mutex>
#include <shared_mutex>
#include <condition_variable>
#include <thread>
#include <utility>
#include <type_traits>

#include "BSignals/details/MPSCQueue.hpp"
#include "BSignals/details/WheeledThreadPool.h"
#include "BSignals/details/Semaphore.h"

namespace BSignals{ namespace details{

//These executors determine how message emission to a slot occurs
    // SYNCHRONOUS:
    // Emission occurs synchronously.
    // When emit returns, all connected slots have been invoked and returned.
    // This method is preferred when connected functions have short execution
    // time, quick emission is required, and/or when it is necessary to know
    // that the function has returned before proceeding.

    // ASYNCHRONOUS:
    // Emission occurs asynchronously. A detached thread is spawned on emission.
    // When emit returns, the thread has been spawned. The thread automatically
    // destructs when the connected function returns.
    // This method is recommended when connected functions have long execution
    // time and are independent.

    // STRAND:
    // Emission occurs asynchronously.
    // On connection a dedicated thread (per slot) is spawned to wait for new messages.
    // Emitted parameters are bound to the mapped function and enqueued on the
    // waiting thread. These messages are then processed synchronously in the
    // spawned thread.
    // This method is recommended when connected functions have longer execution
    // time, the overhead of creating/destroying a thread for each slot would be
    // unperformant, and/or connected functions need to be processed in order
    // of arrival (FIFO).

    // THREAD POOLED:
    // Emission occurs asynchronously.
    // On connection, if it is the first thread pooled function by any signal,
    // the thread pool is initialized with 8 threads, all listening for queued
    // emissions. The number of threads in the pool is not currently run-time
    // configurable but may be in the future.
    // Emitted parameters are bound to the mapped function and enqueued on the
    // one of the waiting threads. These messages are then processed when the
    // relevant queue is consumed by the mapped thread pool.
    // This method is recommended when connected functions have longer execution
    // time, the overhead of creating/destroying a thread for each slot would be
    // unperformant, the overhead of a waiting thread for each slot is
    // unnecessary, and/or connected functions do NOT need to be processed in
    // order of arrival.

    // DEFERRED_SYNCHRONOUS:
    // Emissions are queued up to be manually invoked through the invokeDeferred function
//
enum class ExecutorScheme{
    SYNCHRONOUS,
    DEFERRED_SYNCHRONOUS,
    ASYNCHRONOUS,
    STRAND,
    THREAD_POOLED
};

template <typename... Args>
class SignalImpl {
public:
    SignalImpl() = default;

    SignalImpl(bool enforceThreadSafety)
        : enableEmissionGuard{enforceThreadSafety} {}

    SignalImpl(uint32_t maxAsyncThreads)
        : sem{maxAsyncThreads} {}

    SignalImpl(bool enforceThreadSafety, uint32_t maxAsyncThreads)
        : enableEmissionGuard{enforceThreadSafety}, sem{maxAsyncThreads} {}

    ~SignalImpl(){
        disconnectAllSlots();
        sem.acquireAll();
    }

    template<typename F, typename C>
    int connectMemberSlot(const ExecutorScheme &scheme, F&& function, C&& instance) const {
        //type check assertions
        static_assert(std::is_member_function_pointer<F>::value, "function is not a member function");
        static_assert(std::is_object<std::remove_reference<C>>::value, "instance is not a class object");

        //Construct a bound function from the function pointer and object
        auto boundFunc = objectBind(function, instance);
        return connectSlot(scheme, boundFunc);
    }

    int connectSlot(const ExecutorScheme &scheme, std::function<void(Args...)> slot) const {
        uint32_t id = currentId.fetch_add(1);
        if (enableEmissionGuard){
            std::unique_lock<std::shared_timed_mutex> lock(backBufferLock);
            connectBuffer.emplace(id, ConnectDescriptor{scheme, slot});
            return id;
        }
        else{
            return connectSlotFunction(id, scheme, slot);
        }
    }

    void disconnectSlot(const int &id) const{
        if (enableEmissionGuard){
            std::unique_lock<std::shared_timed_mutex> lock(backBufferLock);
            disconnectBuffer.insert(id);
        }
        else{
            disconnectSlotFunction(id);
        }
    }

    void disconnectAllSlots() const{
        std::unique_lock<std::shared_timed_mutex> lock(signalLock);
        for (auto &q : strandQueues){
            q.second.enqueue(nullptr);
        }
        for (auto &t : strandThreads){
            t.second.join();
        }
        strandThreads.clear();
        strandQueues.clear();

        slots.clear();
    }

    void emitSignal(const Args &... p) const {
        enableEmissionGuard ? emitSignalThreadSafe(p...) : emitSignalUnsafe(p...);
    }

    void invokeDeferred() const{
        std::pair<std::function<void()>, uint32_t> deferredInvocation;
        while (deferredQueue.dequeue(deferredInvocation)){
            if (!enableEmissionGuard || getIsStillConnectedFromExecutor(deferredInvocation.second)){
                deferredInvocation.first();
            }
        }
    }

    void operator()(const Args &... p) const{
        emitSignal(p...);
    }

private:
    SignalImpl<Args...>(const SignalImpl<Args...>& that) = delete;
    void operator=(const SignalImpl<Args...>&) = delete;

    inline void disconnectSlotFunction(const int &id) const{
        std::unique_lock<std::shared_timed_mutex> lock(signalLock);
        if (!slots.count(id)) return;
        auto &entry = slots[id];
        if (entry.scheme == ExecutorScheme::STRAND){
            strandQueues[id].enqueue(nullptr);
            strandThreads[id].join();
            strandThreads.erase(id);
            strandQueues.erase(id);
        }
        slots.erase(id);
    }

    inline int connectSlotFunction(const int &id, const ExecutorScheme &scheme, std::function<void(Args...)> slot) const {
        std::unique_lock<std::shared_timed_mutex> lock(signalLock);
        slots.emplace(id, ConnectDescriptor{scheme, slot});
        if (scheme == ExecutorScheme::STRAND){
            strandQueues[id];
            strandThreads.emplace(id, std::thread(&SignalImpl::queueListener, this, id));
        }
        else if (scheme == ExecutorScheme::THREAD_POOLED){
            WheeledThreadPool::startup();
        }
        return (int)id;
    }

    inline void invokeRelevantExecutor(const ExecutorScheme &scheme, const uint32_t &id, const std::function<void(Args...)> &slot, const Args &... p) const{
        switch(scheme){
            case(ExecutorScheme::DEFERRED_SYNCHRONOUS):
                enqueueDeferred(id, slot, p...);
                return;
            case(ExecutorScheme::SYNCHRONOUS):
                runSynchronous(id, slot, p...);
                return;
            case(ExecutorScheme::ASYNCHRONOUS):
                runAsynchronous(id, slot, p...);
                return;
            case(ExecutorScheme::STRAND):
                runStrands(id, slot, p...);
                return;
            case(ExecutorScheme::THREAD_POOLED):
                runThreadPooled(id, slot, p...);
                return;
        }
    }

    inline void emitSignalUnsafe(const Args &... p) const {
        for (auto const &kvpair : slots){
            invokeRelevantExecutor(kvpair.second.scheme, kvpair.first, kvpair.second.slot, p...);
        }
    }

    inline bool getIsStillConnected(int const &id) const{
        std::shared_lock<std::shared_timed_mutex> lock(backBufferLock);
        return (!disconnectBuffer.count(id));
    }

    inline bool getIsStillConnectedFromExecutor(int const &id) const{
        std::shared_lock<std::shared_timed_mutex> lock(backBufferLock);
        std::shared_lock<std::shared_timed_mutex> lockSignal(signalLock);
        return (!disconnectBuffer.count(id) && slots.count(id));
    }

    inline bool getHasWaitingDisconnects() const{
        std::shared_lock<std::shared_timed_mutex> lock(backBufferLock);
        return (!disconnectBuffer.empty());
    }

    inline bool getHasWaitingConnects() const{
        std::shared_lock<std::shared_timed_mutex> lock(backBufferLock);
        return (!connectBuffer.empty());
    }

    inline bool getHasWaitingConnectsOrDisconnects() const{
        std::shared_lock<std::shared_timed_mutex> lock(backBufferLock);
        return (!connectBuffer.empty() | !disconnectBuffer.empty());
    }

    inline void emitSignalThreadSafe(const Args &... p) const {
        if (getHasWaitingConnectsOrDisconnects()){
            std::unique_lock<std::shared_timed_mutex> bbLock(backBufferLock);
            while (!connectBuffer.empty()){
                auto it = connectBuffer.begin();
                connectSlotFunction(it->first, it->second.scheme, it->second.slot);
                connectBuffer.erase(it);
            }
            while (!disconnectBuffer.empty()){
                disconnectSlotFunction(*disconnectBuffer.begin());
                disconnectBuffer.erase(disconnectBuffer.begin());
            }
        }
        std::shared_lock<std::shared_timed_mutex> lock(signalLock);
        for (auto const &kvpair : slots){
            if (!getIsStillConnected(kvpair.first)) continue;
            invokeRelevantExecutor(kvpair.second.scheme, kvpair.first, kvpair.second.slot, p...);
        }
    }

    inline void runThreadPooled(const uint32_t &id, const std::function<void(Args...)> &function, const Args &... p) const {
        WheeledThreadPool::run([this, &id, &function, p...](){
            if (!enableEmissionGuard || getIsStillConnectedFromExecutor(id))
                function(p...);
        });
    }

    inline void runAsynchronous(const uint32_t &id, const std::function<void(Args...)> &function, const Args &... p) const {
        sem.acquire();
        std::thread slotThread([this, &id, &function, p...](){
            if (!enableEmissionGuard || getIsStillConnectedFromExecutor(id))
                function(p...);
            sem.release();
        });
        slotThread.detach();
    }

    inline void runStrands(const uint32_t &id, const std::function<void(Args...)> &function, const Args &... p) const{
        //bind the function arguments to the function using a lambda and store
        //the newly bound function. This changes the function signature in the
        //resultant map, there are no longer any parameters in the bound function
        strandQueues[id].enqueue([&function, p...](){function(p...);});
    }

    inline void runSynchronous(const uint32_t &id, const std::function<void(Args...)> &function, const Args &... p) const{
        function(p...);
    }

    inline void enqueueDeferred(const uint32_t &id, const std::function<void(Args...)> &function, const Args &... p) const{
        deferredQueue.enqueue({[&function, p...](){function(p...);}, id});
    }

    //Reference to instance
    template<typename F, typename I>
    std::function<void(Args...)> objectBind(F&& function, I&& instance) const {
        return[=, &instance](Args... args){
            (instance.*function)(args...);
        };
    }

    //Pointer to instance
    template<typename F, typename I>
    std::function<void(Args...)> objectBind(F&& function, I* instance) const {
        return objectBind(function, *instance);
    }

    void queueListener(const uint32_t &id) const{
        auto &q = strandQueues[id];
        std::function<void()> func = [](){};
        auto maxWait = WheeledThreadPool::getMaxWait();
        std::chrono::duration<double> waitTime = std::chrono::nanoseconds(1);
        while (func){
            if (q.dequeue(func)){
                if (func) func();
                waitTime = std::chrono::nanoseconds(1);
            }
            else{
                std::this_thread::sleep_for(waitTime);
                    waitTime*=2;
            }
            if (waitTime > maxWait){
                q.blockingDequeue(func);
                if (func) func();
                waitTime = std::chrono::nanoseconds(1);
            }
        }
    }

    //Shared mutex for thread safety
    //Emit acquires shared lock, connect/disconnect acquires unique lock
    mutable std::shared_timed_mutex signalLock;

    //Atomically incremented slotId
    mutable std::atomic<uint32_t> currentId {0};

    //Async Emit Semaphore
    mutable Semaphore sem {1024};

    //EmissionGuard determines if it is necessary to guard emission with a shared mutex
    //This is only required if connection/disconnection could be interleaved with emission
    const bool enableEmissionGuard {false};

    //Strand Queues and Threads
    mutable std::map<uint32_t, MPSCQueue<std::function<void()>>> strandQueues;
    mutable std::map<uint32_t, std::thread> strandThreads;

    //Deferred invocation queue
    mutable MPSCQueue<std::pair<std::function<void()>, uint32_t>> deferredQueue;

    struct ConnectDescriptor{
        ExecutorScheme scheme;
        std::function<void(Args...)> slot;
    };

    //Slot Map
    mutable std::map<uint32_t, ConnectDescriptor> slots;

    //Disconnect backbuffer
    mutable std::set<uint32_t> disconnectBuffer;

    //Connect backbuffer
    mutable std::map<uint32_t, ConnectDescriptor> connectBuffer;

    //Backbuffer lock
    mutable std::shared_timed_mutex backBufferLock;
};

}}

#endif /* SIGNALIMPL_HPP */
<commit_msg>fix for potential deadlock in slot connection from multi-threaded synchronous emissions<commit_after>/*
 * File:   SignalImpl.hpp
 * Author: Barath Kannan
 * Signal/Slots C++14 implementation
 * Created on May 10, 2016, 5:57 PM
 */

#ifndef SIGNALIMPL_HPP
#define SIGNALIMPL_HPP

#include <functional>
#include <map>
#include <unordered_map>
#include <atomic>
#include <mutex>
#include <shared_mutex>
#include <condition_variable>
#include <thread>
#include <utility>
#include <type_traits>

#include "BSignals/details/MPSCQueue.hpp"
#include "BSignals/details/WheeledThreadPool.h"
#include "BSignals/details/Semaphore.h"

namespace BSignals{ namespace details{

//These executors determine how message emission to a slot occurs
    // SYNCHRONOUS:
    // Emission occurs synchronously.
    // When emit returns, all connected slots have been invoked and returned.
    // This method is preferred when connected functions have short execution
    // time, quick emission is required, and/or when it is necessary to know
    // that the function has returned before proceeding.

    // ASYNCHRONOUS:
    // Emission occurs asynchronously. A detached thread is spawned on emission.
    // When emit returns, the thread has been spawned. The thread automatically
    // destructs when the connected function returns.
    // This method is recommended when connected functions have long execution
    // time and are independent.

    // STRAND:
    // Emission occurs asynchronously.
    // On connection a dedicated thread (per slot) is spawned to wait for new messages.
    // Emitted parameters are bound to the mapped function and enqueued on the
    // waiting thread. These messages are then processed synchronously in the
    // spawned thread.
    // This method is recommended when connected functions have longer execution
    // time, the overhead of creating/destroying a thread for each slot would be
    // unperformant, and/or connected functions need to be processed in order
    // of arrival (FIFO).

    // THREAD POOLED:
    // Emission occurs asynchronously.
    // On connection, if it is the first thread pooled function by any signal,
    // the thread pool is initialized with 8 threads, all listening for queued
    // emissions. The number of threads in the pool is not currently run-time
    // configurable but may be in the future.
    // Emitted parameters are bound to the mapped function and enqueued on the
    // one of the waiting threads. These messages are then processed when the
    // relevant queue is consumed by the mapped thread pool.
    // This method is recommended when connected functions have longer execution
    // time, the overhead of creating/destroying a thread for each slot would be
    // unperformant, the overhead of a waiting thread for each slot is
    // unnecessary, and/or connected functions do NOT need to be processed in
    // order of arrival.

    // DEFERRED_SYNCHRONOUS:
    // Emissions are queued up to be manually invoked through the invokeDeferred function
//
enum class ExecutorScheme{
    SYNCHRONOUS,
    DEFERRED_SYNCHRONOUS,
    ASYNCHRONOUS,
    STRAND,
    THREAD_POOLED
};

template <typename... Args>
class SignalImpl {
public:
    SignalImpl() = default;

    SignalImpl(bool enforceThreadSafety)
        : enableEmissionGuard{enforceThreadSafety} {}

    SignalImpl(uint32_t maxAsyncThreads)
        : sem{maxAsyncThreads} {}

    SignalImpl(bool enforceThreadSafety, uint32_t maxAsyncThreads)
        : enableEmissionGuard{enforceThreadSafety}, sem{maxAsyncThreads} {}

    ~SignalImpl(){
        disconnectAllSlots();
        sem.acquireAll();
    }

    template<typename F, typename C>
    int connectMemberSlot(const ExecutorScheme &scheme, F&& function, C&& instance) const {
        //type check assertions
        static_assert(std::is_member_function_pointer<F>::value, "function is not a member function");
        static_assert(std::is_object<std::remove_reference<C>>::value, "instance is not a class object");

        //Construct a bound function from the function pointer and object
        auto boundFunc = objectBind(function, instance);
        return connectSlot(scheme, boundFunc);
    }

    int connectSlot(const ExecutorScheme &scheme, std::function<void(Args...)> slot) const {
        uint32_t id = currentId.fetch_add(1);
        if (enableEmissionGuard){
            std::unique_lock<std::shared_timed_mutex> lock(backBufferLock);
            connectBuffer.emplace(id, ConnectDescriptor{scheme, slot});
            return id;
        }
        else{
            return connectSlotFunction(id, scheme, slot);
        }
    }

    void disconnectSlot(const int &id) const{
        if (enableEmissionGuard){
            std::unique_lock<std::shared_timed_mutex> lock(backBufferLock);
            disconnectBuffer.insert(id);
        }
        else{
            disconnectSlotFunction(id);
        }
    }

    void disconnectAllSlots() const{
        std::unique_lock<std::shared_timed_mutex> lock(signalLock);
        for (auto &q : strandQueues){
            q.second.enqueue(nullptr);
        }
        for (auto &t : strandThreads){
            t.second.join();
        }
        strandThreads.clear();
        strandQueues.clear();

        slots.clear();
    }

    void emitSignal(const Args &... p) const {
        enableEmissionGuard ? emitSignalThreadSafe(p...) : emitSignalUnsafe(p...);
    }

    void invokeDeferred() const{
        std::pair<std::function<void()>, uint32_t> deferredInvocation;
        while (deferredQueue.dequeue(deferredInvocation)){
            if (!enableEmissionGuard || getIsStillConnectedFromExecutor(deferredInvocation.second)){
                deferredInvocation.first();
            }
        }
    }

    void operator()(const Args &... p) const{
        emitSignal(p...);
    }

private:
    SignalImpl<Args...>(const SignalImpl<Args...>& that) = delete;
    void operator=(const SignalImpl<Args...>&) = delete;

    inline void disconnectSlotFunction(const int &id) const{
        std::unique_lock<std::shared_timed_mutex> lock(signalLock);
        if (!slots.count(id)) return;
        auto &entry = slots[id];
        if (entry.scheme == ExecutorScheme::STRAND){
            strandQueues[id].enqueue(nullptr);
            strandThreads[id].join();
            strandThreads.erase(id);
            strandQueues.erase(id);
        }
        slots.erase(id);
    }

    inline int connectSlotFunction(const int &id, const ExecutorScheme &scheme, std::function<void(Args...)> slot) const {
        std::unique_lock<std::shared_timed_mutex> lock(signalLock);
        slots.emplace(id, ConnectDescriptor{scheme, slot});
        if (scheme == ExecutorScheme::STRAND){
            strandQueues[id];
            strandThreads.emplace(id, std::thread(&SignalImpl::queueListener, this, id));
        }
        else if (scheme == ExecutorScheme::THREAD_POOLED){
            WheeledThreadPool::startup();
        }
        return (int)id;
    }

    inline void invokeRelevantExecutor(const ExecutorScheme &scheme, const uint32_t &id, const std::function<void(Args...)> &slot, const Args &... p) const{
        switch(scheme){
            case(ExecutorScheme::DEFERRED_SYNCHRONOUS):
                enqueueDeferred(id, slot, p...);
                return;
            case(ExecutorScheme::SYNCHRONOUS):
                runSynchronous(id, slot, p...);
                return;
            case(ExecutorScheme::ASYNCHRONOUS):
                runAsynchronous(id, slot, p...);
                return;
            case(ExecutorScheme::STRAND):
                runStrands(id, slot, p...);
                return;
            case(ExecutorScheme::THREAD_POOLED):
                runThreadPooled(id, slot, p...);
                return;
        }
    }

    inline void emitSignalUnsafe(const Args &... p) const {
        for (auto const &kvpair : slots){
            invokeRelevantExecutor(kvpair.second.scheme, kvpair.first, kvpair.second.slot, p...);
        }
    }

    inline bool getIsStillConnected(int const &id) const{
        std::shared_lock<std::shared_timed_mutex> lock(backBufferLock);
        return (!disconnectBuffer.count(id));
    }

    inline bool getIsStillConnectedFromExecutor(int const &id) const{
        std::shared_lock<std::shared_timed_mutex> lock(backBufferLock);
        std::shared_lock<std::shared_timed_mutex> lockSignal(signalLock);
        return (!disconnectBuffer.count(id) && slots.count(id));
    }

    inline bool getHasWaitingDisconnects() const{
        std::shared_lock<std::shared_timed_mutex> lock(backBufferLock);
        return (!disconnectBuffer.empty());
    }

    inline bool getHasWaitingConnects() const{
        std::shared_lock<std::shared_timed_mutex> lock(backBufferLock);
        return (!connectBuffer.empty());
    }

    inline bool getHasWaitingConnectsOrDisconnects() const{
        std::shared_lock<std::shared_timed_mutex> lock(backBufferLock);
        return (!connectBuffer.empty() | !disconnectBuffer.empty());
    }

    inline void emitSignalThreadSafe(const Args &... p) const {
        if (getHasWaitingConnectsOrDisconnects()){
            std::unique_lock<std::shared_timed_mutex> bbLock(backBufferLock);
            while (!connectBuffer.empty()){
                const std::pair<uint32_t, ConnectDescriptor> current = *connectBuffer.begin();
                connectBuffer.erase(connectBuffer.begin());
                //if there is another emit attempting to connect from inside a
                //synchronous slot function it is going to attempt to push to the
                //backbuffer while holding a signal shared mutex. This will
                //cause a deadlock. Hence we need to release the backBufferLock
                //for the duration of the connect
                bbLock.unlock();
                connectSlotFunction(current.first, current.second.scheme, current.second.slot);
                bbLock.lock();
            }
            while (!disconnectBuffer.empty()){
                const uint32_t disconnectId = *disconnectBuffer.begin();
                disconnectBuffer.erase(disconnectBuffer.begin());
                //Same as above, need to relinquish the lock while we disconnect
                //to avoid deadlock
                bbLock.unlock();
                disconnectSlotFunction(disconnectId);
                bbLock.lock();
            }
        }
        std::shared_lock<std::shared_timed_mutex> lock(signalLock);
        for (auto const &kvpair : slots){
            if (getIsStillConnected(kvpair.first)){
                invokeRelevantExecutor(kvpair.second.scheme, kvpair.first, kvpair.second.slot, p...);
            }
        }
    }

    inline void runThreadPooled(const uint32_t &id, const std::function<void(Args...)> &function, const Args &... p) const {
        WheeledThreadPool::run([this, &id, &function, p...](){
            if (!enableEmissionGuard || getIsStillConnectedFromExecutor(id))
                function(p...);
        });
    }

    inline void runAsynchronous(const uint32_t &id, const std::function<void(Args...)> &function, const Args &... p) const {
        sem.acquire();
        std::thread slotThread([this, &id, &function, p...](){
            if (!enableEmissionGuard || getIsStillConnectedFromExecutor(id))
                function(p...);
            sem.release();
        });
        slotThread.detach();
    }

    inline void runStrands(const uint32_t &id, const std::function<void(Args...)> &function, const Args &... p) const{
        //bind the function arguments to the function using a lambda and store
        //the newly bound function. This changes the function signature in the
        //resultant map, there are no longer any parameters in the bound function
        strandQueues[id].enqueue([&function, p...](){function(p...);});
    }

    inline void runSynchronous(const uint32_t &id, const std::function<void(Args...)> &function, const Args &... p) const{
        function(p...);
    }

    inline void enqueueDeferred(const uint32_t &id, const std::function<void(Args...)> &function, const Args &... p) const{
        deferredQueue.enqueue({[&function, p...](){function(p...);}, id});
    }

    //Reference to instance
    template<typename F, typename I>
    std::function<void(Args...)> objectBind(F&& function, I&& instance) const {
        return[=, &instance](Args... args){
            (instance.*function)(args...);
        };
    }

    //Pointer to instance
    template<typename F, typename I>
    std::function<void(Args...)> objectBind(F&& function, I* instance) const {
        return objectBind(function, *instance);
    }

    void queueListener(const uint32_t &id) const{
        auto &q = strandQueues[id];
        std::function<void()> func = [](){};
        auto maxWait = WheeledThreadPool::getMaxWait();
        std::chrono::duration<double> waitTime = std::chrono::nanoseconds(1);
        while (func){
            if (q.dequeue(func)){
                if (func) func();
                waitTime = std::chrono::nanoseconds(1);
            }
            else{
                std::this_thread::sleep_for(waitTime);
                    waitTime*=2;
            }
            if (waitTime > maxWait){
                q.blockingDequeue(func);
                if (func) func();
                waitTime = std::chrono::nanoseconds(1);
            }
        }
    }

    //Shared mutex for thread safety
    //Emit acquires shared lock, connect/disconnect acquires unique lock
    mutable std::shared_timed_mutex signalLock;

    //Atomically incremented slotId
    mutable std::atomic<uint32_t> currentId {0};

    //Async Emit Semaphore
    mutable Semaphore sem {1024};

    //EmissionGuard determines if it is necessary to guard emission with a shared mutex
    //This is only required if connection/disconnection could be interleaved with emission
    const bool enableEmissionGuard {false};

    //Strand Queues and Threads
    mutable std::map<uint32_t, MPSCQueue<std::function<void()>>> strandQueues;
    mutable std::map<uint32_t, std::thread> strandThreads;

    //Deferred invocation queue
    mutable MPSCQueue<std::pair<std::function<void()>, uint32_t>> deferredQueue;

    struct ConnectDescriptor{
        ExecutorScheme scheme;
        std::function<void(Args...)> slot;
    };

    //Slot Map
    mutable std::map<uint32_t, ConnectDescriptor> slots;

    //Disconnect backbuffer
    mutable std::set<uint32_t> disconnectBuffer;

    //Connect backbuffer
    mutable std::map<uint32_t, ConnectDescriptor> connectBuffer;

    //Backbuffer lock
    mutable std::shared_timed_mutex backBufferLock;
};

}}

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


<commit_before>/*************************************************************************
 *
 *  $RCSfile: eventlisteneradapter.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-05 09:05:12 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _UNOTOOLS_EVENTLISTENERADAPTER_HXX_
#include <unotools/eventlisteneradapter.hxx>
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _COMPHELPER_STLTYPES_HXX_
#include <comphelper/stl_types.hxx>
#endif

//.........................................................................
namespace utl
{
//.........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::lang;

    //=====================================================================
    //= OEventListenerImpl
    //=====================================================================
    class OEventListenerImpl : public ::cppu::WeakImplHelper1< XEventListener >
    {
    protected:
        OEventListenerAdapter*          m_pAdapter;
        Reference< XEventListener >     m_xKeepMeAlive;
            // imagine an implementation of XComponent which holds it's listeners with a weak reference ...
            // would be very bad if we don't hold ourself
        Reference< XComponent >         m_xComponent;

    public:
        OEventListenerImpl( OEventListenerAdapter* _pAdapter, const Reference< XComponent >& _rxComp );

        void                            dispose();
        const Reference< XComponent >&  getComponent() const { return m_xComponent; }

    protected:
        virtual void SAL_CALL disposing( const EventObject& _rSource ) throw (RuntimeException);
    };

    //---------------------------------------------------------------------
    OEventListenerImpl::OEventListenerImpl( OEventListenerAdapter* _pAdapter, const Reference< XComponent >& _rxComp )
        :m_pAdapter(_pAdapter)
    {
        OSL_ENSURE(m_pAdapter, "OEventListenerImpl::OEventListenerImpl: invalid adapter!");
        // no checks of _rxComp !!
        // (OEventListenerAdapter is responsible for this)

        // just in case addEventListener throws an exception ... don't initialize m_xKeepMeAlive before this
        // is done
        Reference< XEventListener > xMeMyselfAndI = this;
        _rxComp->addEventListener(xMeMyselfAndI);

        m_xComponent = _rxComp;
        m_xKeepMeAlive = xMeMyselfAndI;
    }

    //---------------------------------------------------------------------
    void OEventListenerImpl::dispose()
    {
        if (m_xComponent.is())
        {
            m_xComponent->removeEventListener(m_xKeepMeAlive);
            m_xComponent.clear();
            m_xKeepMeAlive.clear();
        }
    }

    //---------------------------------------------------------------------
    void SAL_CALL OEventListenerImpl::disposing( const EventObject& _rSource ) throw (RuntimeException)
    {
        Reference< XEventListener > xDeleteUponLeaving = m_xKeepMeAlive;
        m_xKeepMeAlive.clear();
        m_xComponent.clear();

        m_pAdapter->_disposing(_rSource);
    }

    //=====================================================================
    //= OEventListenerAdapterImpl
    //=====================================================================
    struct OEventListenerAdapterImpl
    {
    public:
        ::std::vector< void* >  aListeners;
    };

    //=====================================================================
    //= OEventListenerAdapter
    //=====================================================================
    //---------------------------------------------------------------------
    OEventListenerAdapter::OEventListenerAdapter()
        :m_pImpl(new OEventListenerAdapterImpl)
    {
    }

    //---------------------------------------------------------------------
    OEventListenerAdapter::~OEventListenerAdapter()
    {
        stopAllComponentListening( );
        delete m_pImpl;
        m_pImpl = NULL;
    }

    //---------------------------------------------------------------------
    void OEventListenerAdapter::stopComponentListening( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& _rxComp )
    {
        if ( m_pImpl->aListeners.empty() )
            return;

        ::std::vector< void* >::iterator dispose = m_pImpl->aListeners.begin();
        do
        {
            OEventListenerImpl* pListenerImpl = static_cast< OEventListenerImpl* >( *dispose );
            if ( pListenerImpl->getComponent().get() == _rxComp.get() )
            {
                pListenerImpl->dispose();
                pListenerImpl->release();
                dispose = m_pImpl->aListeners.erase( dispose );
            }
            else
                ++dispose;
        }
        while ( dispose != m_pImpl->aListeners.end() );
    }

    //---------------------------------------------------------------------
    void OEventListenerAdapter::stopAllComponentListening(  )
    {
        for (   ::std::vector< void* >::const_iterator aDisposeLoop = m_pImpl->aListeners.begin();
                aDisposeLoop != m_pImpl->aListeners.end();
                ++aDisposeLoop
            )
        {
            OEventListenerImpl* pListenerImpl = static_cast< OEventListenerImpl* >(*aDisposeLoop);
            pListenerImpl->dispose();
            pListenerImpl->release();
        }
        m_pImpl->aListeners.clear();
    }

    //---------------------------------------------------------------------
    void OEventListenerAdapter::startComponentListening( const Reference< XComponent >& _rxComp )
    {
        if (!_rxComp.is())
        {
            OSL_ENSURE(sal_False, "OEventListenerAdapter::startComponentListening: invalid component!");
            return;
        }

        OEventListenerImpl* pListenerImpl = new OEventListenerImpl(this, _rxComp);
        pListenerImpl->acquire();
        m_pImpl->aListeners.push_back(pListenerImpl);
    }

//.........................................................................
}   // namespace utl
//.........................................................................
<commit_msg>INTEGRATION: CWS ooo19126 (1.1.260); FILE MERGED 2005/09/05 14:01:07 rt 1.1.260.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: eventlisteneradapter.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 14:15:39 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _UNOTOOLS_EVENTLISTENERADAPTER_HXX_
#include <unotools/eventlisteneradapter.hxx>
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _COMPHELPER_STLTYPES_HXX_
#include <comphelper/stl_types.hxx>
#endif

//.........................................................................
namespace utl
{
//.........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::lang;

    //=====================================================================
    //= OEventListenerImpl
    //=====================================================================
    class OEventListenerImpl : public ::cppu::WeakImplHelper1< XEventListener >
    {
    protected:
        OEventListenerAdapter*          m_pAdapter;
        Reference< XEventListener >     m_xKeepMeAlive;
            // imagine an implementation of XComponent which holds it's listeners with a weak reference ...
            // would be very bad if we don't hold ourself
        Reference< XComponent >         m_xComponent;

    public:
        OEventListenerImpl( OEventListenerAdapter* _pAdapter, const Reference< XComponent >& _rxComp );

        void                            dispose();
        const Reference< XComponent >&  getComponent() const { return m_xComponent; }

    protected:
        virtual void SAL_CALL disposing( const EventObject& _rSource ) throw (RuntimeException);
    };

    //---------------------------------------------------------------------
    OEventListenerImpl::OEventListenerImpl( OEventListenerAdapter* _pAdapter, const Reference< XComponent >& _rxComp )
        :m_pAdapter(_pAdapter)
    {
        OSL_ENSURE(m_pAdapter, "OEventListenerImpl::OEventListenerImpl: invalid adapter!");
        // no checks of _rxComp !!
        // (OEventListenerAdapter is responsible for this)

        // just in case addEventListener throws an exception ... don't initialize m_xKeepMeAlive before this
        // is done
        Reference< XEventListener > xMeMyselfAndI = this;
        _rxComp->addEventListener(xMeMyselfAndI);

        m_xComponent = _rxComp;
        m_xKeepMeAlive = xMeMyselfAndI;
    }

    //---------------------------------------------------------------------
    void OEventListenerImpl::dispose()
    {
        if (m_xComponent.is())
        {
            m_xComponent->removeEventListener(m_xKeepMeAlive);
            m_xComponent.clear();
            m_xKeepMeAlive.clear();
        }
    }

    //---------------------------------------------------------------------
    void SAL_CALL OEventListenerImpl::disposing( const EventObject& _rSource ) throw (RuntimeException)
    {
        Reference< XEventListener > xDeleteUponLeaving = m_xKeepMeAlive;
        m_xKeepMeAlive.clear();
        m_xComponent.clear();

        m_pAdapter->_disposing(_rSource);
    }

    //=====================================================================
    //= OEventListenerAdapterImpl
    //=====================================================================
    struct OEventListenerAdapterImpl
    {
    public:
        ::std::vector< void* >  aListeners;
    };

    //=====================================================================
    //= OEventListenerAdapter
    //=====================================================================
    //---------------------------------------------------------------------
    OEventListenerAdapter::OEventListenerAdapter()
        :m_pImpl(new OEventListenerAdapterImpl)
    {
    }

    //---------------------------------------------------------------------
    OEventListenerAdapter::~OEventListenerAdapter()
    {
        stopAllComponentListening( );
        delete m_pImpl;
        m_pImpl = NULL;
    }

    //---------------------------------------------------------------------
    void OEventListenerAdapter::stopComponentListening( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& _rxComp )
    {
        if ( m_pImpl->aListeners.empty() )
            return;

        ::std::vector< void* >::iterator dispose = m_pImpl->aListeners.begin();
        do
        {
            OEventListenerImpl* pListenerImpl = static_cast< OEventListenerImpl* >( *dispose );
            if ( pListenerImpl->getComponent().get() == _rxComp.get() )
            {
                pListenerImpl->dispose();
                pListenerImpl->release();
                dispose = m_pImpl->aListeners.erase( dispose );
            }
            else
                ++dispose;
        }
        while ( dispose != m_pImpl->aListeners.end() );
    }

    //---------------------------------------------------------------------
    void OEventListenerAdapter::stopAllComponentListening(  )
    {
        for (   ::std::vector< void* >::const_iterator aDisposeLoop = m_pImpl->aListeners.begin();
                aDisposeLoop != m_pImpl->aListeners.end();
                ++aDisposeLoop
            )
        {
            OEventListenerImpl* pListenerImpl = static_cast< OEventListenerImpl* >(*aDisposeLoop);
            pListenerImpl->dispose();
            pListenerImpl->release();
        }
        m_pImpl->aListeners.clear();
    }

    //---------------------------------------------------------------------
    void OEventListenerAdapter::startComponentListening( const Reference< XComponent >& _rxComp )
    {
        if (!_rxComp.is())
        {
            OSL_ENSURE(sal_False, "OEventListenerAdapter::startComponentListening: invalid component!");
            return;
        }

        OEventListenerImpl* pListenerImpl = new OEventListenerImpl(this, _rxComp);
        pListenerImpl->acquire();
        m_pImpl->aListeners.push_back(pListenerImpl);
    }

//.........................................................................
}   // namespace utl
//.........................................................................
<|endoftext|>


<commit_before>// $Id$
// vim:tabstop=2

/***********************************************************************
Moses - factored phrase-based language decoder
Copyright (C) 2014- University of Edinburgh

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
***********************************************************************/

/**
  Prune the phrase table using the same translation pruning that Moses uses during decoding.
**/

#include <cstring>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <boost/program_options.hpp>
#include <boost/scoped_ptr.hpp>

#include "moses/InputPath.h"
#include "moses/Parameter.h"
#include "moses/TranslationModel/PhraseDictionary.h"
#include "moses/StaticData.h"

#include "util/file_piece.hh"
#include "util/string_piece.hh"
#include "util/tokenize_piece.hh"
#include "util/double-conversion/double-conversion.h"
#include "util/exception.hh"

using namespace Moses;
using namespace std;

namespace po = boost::program_options;

static void usage(const po::options_description& desc, char** argv) {
    cerr << "Usage: " + string(argv[0]) +  " [options] input-file output-file" << endl;
    cerr << desc << endl;
}

//Find top n translations of source, and send them to output
static void outputTopN(const StringPiece& sourcePhraseString, PhraseDictionary* phraseTable, const std::vector<FactorType> &input,  ostream& out) {
  //get list of target phrases
  Phrase sourcePhrase;
  sourcePhrase.CreateFromString(Input,input,sourcePhraseString,NULL);
  InputPath inputPath(sourcePhrase, NonTerminalSet(), WordsRange(0,sourcePhrase.GetSize()-1),NULL,NULL);
  InputPathList inputPaths;
  inputPaths.push_back(&inputPath);
  phraseTable->GetTargetPhraseCollectionBatch(inputPaths);
  const TargetPhraseCollection* targetPhrases = inputPath.GetTargetPhrases(*phraseTable);

  //print phrases
  const std::vector<FactorType>& output = StaticData::Instance().GetOutputFactorOrder();
  if (targetPhrases) {
    //if (targetPhrases->GetSize() > 10) cerr << "src " << sourcePhrase << " tgt count " << targetPhrases->GetSize() << endl;
    for (TargetPhraseCollection::const_iterator i = targetPhrases->begin(); i != targetPhrases->end(); ++i) {
      const TargetPhrase* targetPhrase = *i;
      out << sourcePhrase.GetStringRep(input);
      out << " ||| ";
      out << targetPhrase->GetStringRep(output);
      out << " ||| ";
      const ScoreComponentCollection scores = targetPhrase->GetScoreBreakdown();
      vector<float> phraseScores = scores.GetScoresForProducer(phraseTable);
      for (size_t j = 0; j < phraseScores.size(); ++j) {
        out << exp(phraseScores[j]) << " ";
      }
      out << "||| ";
      const AlignmentInfo& align = targetPhrase->GetAlignTerm();
      for (AlignmentInfo::const_iterator j = align.begin(); j != align.end(); ++j) {
        out << j->first << "-" << j->second << " ";
      }
      out << endl;
    }
  }

}

int main(int argc, char** argv)
{
  bool help;
  string input_file;
  string config_file;

  po::options_description desc("Allowed options");
  desc.add_options()
  ("help,h", po::value(&help)->zero_tokens()->default_value(false), "Print this help message and exit")
  ("input-file,i", po::value<string>(&input_file), "Input file")
  ("config-file,f", po::value<string>(&config_file), "Config file")
  ;

  po::options_description cmdline_options;
  cmdline_options.add(desc);
  po::variables_map vm;
  po::parsed_options parsed = po::command_line_parser(argc,argv).
            options(cmdline_options).allow_unregistered().run();
  po::store(parsed, vm);
  po::notify(vm);
  if (help) {
    usage(desc, argv);
    exit(0);
  }
  if (input_file.empty()) {
    cerr << "ERROR: Please specify an input file" << endl << endl;
    usage(desc, argv);
    exit(1);
  }
  if (config_file.empty()) {
    cerr << "ERROR: Please specify a config file" << endl << endl;
    usage(desc, argv);
    exit(1);
  }

  vector<string> mosesargs;
  mosesargs.push_back(argv[0]);
  mosesargs.push_back("-f");
  mosesargs.push_back(config_file);
  for (size_t i = 0; i < parsed.options.size(); ++i) {
    if (parsed.options[i].position_key == -1 && !parsed.options[i].unregistered) continue;
    const string& key = parsed.options[i].string_key;
    if (!key.empty()) {
      mosesargs.push_back(key);
    }
    for (size_t j = 0; j < parsed.options[i].value.size(); ++j) {
      const string& value = parsed.options[i].value[j];
      if (!value.empty()) {
        mosesargs.push_back(value);
      }
    }
  }

  boost::scoped_ptr<Parameter> params(new Parameter());
  char** mosesargv = new char*[mosesargs.size()];
  for (size_t i = 0; i < mosesargs.size(); ++i) {
    mosesargv[i] = new char[mosesargs[i].length() + 1];
    strcpy(mosesargv[i], mosesargs[i].c_str());
  }

  if (!params->LoadParam(mosesargs.size(), mosesargv)) {
    params->Explain();
    exit(1);
  }

  if (!StaticData::LoadDataStatic(params.get(),argv[0])) {
    exit(1);
  }

  const StaticData &staticData = StaticData::Instance();
  const std::vector<FactorType> & input = staticData.GetInputFactorOrder();

  //Find the phrase table to evaluate with
  PhraseDictionary* phraseTable = NULL;
  const vector<FeatureFunction*>& ffs = FeatureFunction::GetFeatureFunctions();
  for (size_t i = 0; i < ffs.size(); ++i) {
    PhraseDictionary* maybePhraseTable = dynamic_cast< PhraseDictionary*>(ffs[i]);
    if (maybePhraseTable) {
      UTIL_THROW_IF(phraseTable,util::Exception,"Can only score translations with one phrase table");
      phraseTable = maybePhraseTable;
    }
  }
  UTIL_THROW_IF(!phraseTable,util::Exception,"Unable to find scoring phrase table");

  Sentence sentence;
  phraseTable->InitializeForInput(sentence);

  //
  //Load and prune the phrase table. This is taken (with mods) from moses/TranslationModel/RuleTable/LoaderStandard.cpp
  //

  string lineOrig;

  std::ostream *progress = NULL;
  IFVERBOSE(1) progress = &std::cerr;
  util::FilePiece in(input_file.c_str(), progress);

  // reused variables
  vector<float> scoreVector;
  StringPiece line;

  double_conversion::StringToDoubleConverter converter(double_conversion::StringToDoubleConverter::NO_FLAGS, NAN, NAN, "inf", "nan");

  StringPiece previous;

  while(true) {
    try {
      line = in.ReadLine();
    } catch (const util::EndOfFileException &e) {
      break;
    }

    util::TokenIter<util::MultiCharacter> pipes(line, "|||");
    StringPiece sourcePhraseString(*pipes);
    if (sourcePhraseString != previous) {
      outputTopN(previous, phraseTable, input, cout);
      previous = sourcePhraseString;
    }
  }
  outputTopN(previous, phraseTable, input, cout);

  return 0;
}
<commit_msg>Pass arguments correctly to Moses<commit_after>// $Id$
// vim:tabstop=2

/***********************************************************************
Moses - factored phrase-based language decoder
Copyright (C) 2014- University of Edinburgh

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
***********************************************************************/

/**
  Prune the phrase table using the same translation pruning that Moses uses during decoding.
**/

#include <cstring>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <boost/program_options.hpp>
#include <boost/scoped_ptr.hpp>

#include "moses/InputPath.h"
#include "moses/Parameter.h"
#include "moses/TranslationModel/PhraseDictionary.h"
#include "moses/StaticData.h"

#include "util/file_piece.hh"
#include "util/string_piece.hh"
#include "util/tokenize_piece.hh"
#include "util/double-conversion/double-conversion.h"
#include "util/exception.hh"

using namespace Moses;
using namespace std;

namespace po = boost::program_options;

static void usage(const po::options_description& desc, char** argv) {
    cerr << "Usage: " + string(argv[0]) +  " [options] input-file output-file" << endl;
    cerr << desc << endl;
}

//Find top n translations of source, and send them to output
static void outputTopN(const StringPiece& sourcePhraseString, PhraseDictionary* phraseTable, const std::vector<FactorType> &input,  ostream& out) {
  //get list of target phrases
  Phrase sourcePhrase;
  sourcePhrase.CreateFromString(Input,input,sourcePhraseString,NULL);
  InputPath inputPath(sourcePhrase, NonTerminalSet(), WordsRange(0,sourcePhrase.GetSize()-1),NULL,NULL);
  InputPathList inputPaths;
  inputPaths.push_back(&inputPath);
  phraseTable->GetTargetPhraseCollectionBatch(inputPaths);
  const TargetPhraseCollection* targetPhrases = inputPath.GetTargetPhrases(*phraseTable);

  //print phrases
  const std::vector<FactorType>& output = StaticData::Instance().GetOutputFactorOrder();
  if (targetPhrases) {
    //if (targetPhrases->GetSize() > 10) cerr << "src " << sourcePhrase << " tgt count " << targetPhrases->GetSize() << endl;
    for (TargetPhraseCollection::const_iterator i = targetPhrases->begin(); i != targetPhrases->end(); ++i) {
      const TargetPhrase* targetPhrase = *i;
      out << sourcePhrase.GetStringRep(input);
      out << " ||| ";
      out << targetPhrase->GetStringRep(output);
      out << " ||| ";
      const ScoreComponentCollection scores = targetPhrase->GetScoreBreakdown();
      vector<float> phraseScores = scores.GetScoresForProducer(phraseTable);
      for (size_t j = 0; j < phraseScores.size(); ++j) {
        out << exp(phraseScores[j]) << " ";
      }
      out << "||| ";
      const AlignmentInfo& align = targetPhrase->GetAlignTerm();
      for (AlignmentInfo::const_iterator j = align.begin(); j != align.end(); ++j) {
        out << j->first << "-" << j->second << " ";
      }
      out << endl;
    }
  }

}

int main(int argc, char** argv)
{
  bool help;
  string input_file;
  string config_file;

  po::options_description desc("Allowed options");
  desc.add_options()
  ("help,h", po::value(&help)->zero_tokens()->default_value(false), "Print this help message and exit")
  ("input-file,i", po::value<string>(&input_file), "Input file")
  ("config-file,f", po::value<string>(&config_file), "Config file")
  ;

  po::options_description cmdline_options;
  cmdline_options.add(desc);
  po::variables_map vm;
  po::parsed_options parsed = po::command_line_parser(argc,argv).
            options(cmdline_options).allow_unregistered().run();
  po::store(parsed, vm);
  po::notify(vm);
  if (help) {
    usage(desc, argv);
    exit(0);
  }
  if (input_file.empty()) {
    cerr << "ERROR: Please specify an input file" << endl << endl;
    usage(desc, argv);
    exit(1);
  }
  if (config_file.empty()) {
    cerr << "ERROR: Please specify a config file" << endl << endl;
    usage(desc, argv);
    exit(1);
  }

  vector<string> mosesargs;
  mosesargs.push_back(argv[0]);
  mosesargs.push_back("-f");
  mosesargs.push_back(config_file);
  for (size_t i = 0; i < parsed.options.size(); ++i) {
    if (parsed.options[i].position_key == -1 && !parsed.options[i].unregistered) continue;
    /*
    const string& key = parsed.options[i].string_key;
    if (!key.empty()) {
      mosesargs.push_back(key);
    }
    for (size_t j = 0; j < parsed.options[i].value.size(); ++j) {
      const string& value = parsed.options[i].value[j];
      if (!value.empty()) {
        mosesargs.push_back(value);
      }
    }*/

    for (size_t j = 0; j < parsed.options[i].original_tokens.size(); ++j) {
      mosesargs.push_back(parsed.options[i].original_tokens[j]);
    }
  }

  boost::scoped_ptr<Parameter> params(new Parameter());
  char** mosesargv = new char*[mosesargs.size()];
  for (size_t i = 0; i < mosesargs.size(); ++i) {
    mosesargv[i] = new char[mosesargs[i].length() + 1];
    strcpy(mosesargv[i], mosesargs[i].c_str());
  }

  if (!params->LoadParam(mosesargs.size(), mosesargv)) {
    params->Explain();
    exit(1);
  }

  if (!StaticData::LoadDataStatic(params.get(),argv[0])) {
    exit(1);
  }

  const StaticData &staticData = StaticData::Instance();
  const std::vector<FactorType> & input = staticData.GetInputFactorOrder();

  //Find the phrase table to evaluate with
  PhraseDictionary* phraseTable = NULL;
  const vector<FeatureFunction*>& ffs = FeatureFunction::GetFeatureFunctions();
  for (size_t i = 0; i < ffs.size(); ++i) {
    PhraseDictionary* maybePhraseTable = dynamic_cast< PhraseDictionary*>(ffs[i]);
    if (maybePhraseTable) {
      UTIL_THROW_IF(phraseTable,util::Exception,"Can only score translations with one phrase table");
      phraseTable = maybePhraseTable;
    }
  }
  UTIL_THROW_IF(!phraseTable,util::Exception,"Unable to find scoring phrase table");

  Sentence sentence;
  phraseTable->InitializeForInput(sentence);

  //
  //Load and prune the phrase table. This is taken (with mods) from moses/TranslationModel/RuleTable/LoaderStandard.cpp
  //

  string lineOrig;

  std::ostream *progress = NULL;
  IFVERBOSE(1) progress = &std::cerr;
  util::FilePiece in(input_file.c_str(), progress);

  // reused variables
  vector<float> scoreVector;
  StringPiece line;

  double_conversion::StringToDoubleConverter converter(double_conversion::StringToDoubleConverter::NO_FLAGS, NAN, NAN, "inf", "nan");

  StringPiece previous;

  while(true) {
    try {
      line = in.ReadLine();
    } catch (const util::EndOfFileException &e) {
      break;
    }

    util::TokenIter<util::MultiCharacter> pipes(line, "|||");
    StringPiece sourcePhraseString(*pipes);
    if (sourcePhraseString != previous) {
      outputTopN(previous, phraseTable, input, cout);
      previous = sourcePhraseString;
    }
  }
  outputTopN(previous, phraseTable, input, cout);

  return 0;
}
<|endoftext|>


<commit_before>// Copyright (C) 2013 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Debug.hpp>

template<typename...> struct NzImplInitializer;

template<typename T, typename... Rest>
struct NzImplInitializer<T, Rest...>
{
	static bool Init()
	{
		if (T::Initialize())
		{
			if (NzImplInitializer<Rest...>::Init())
				return true;
			else
				T::Uninitialize();
		}

		return false;
	}

	static void Uninit()
	{
		T::Uninitialize();
		NzImplInitializer<Rest...>::Uninit();
	}
};

template<>
struct NzImplInitializer<>
{
	static bool Init()
	{
		return true;
	}

	static void Uninit()
	{
	}
};

template<typename... Args>
NzInitializer<Args...>::NzInitializer()
{
	m_initialized = NzImplInitializer<Args...>::Init();
}

template<typename... Args>
NzInitializer<Args...>::~NzInitializer()
{
	if (m_initialized)
		NzImplInitializer<Args...>::Uninit();
}

template<typename... Args>
bool NzInitializer<Args...>::IsInitialized() const
{
	return m_initialized;
}

template<typename... Args>
NzInitializer<Args...>::operator bool() const
{
	return m_initialized;
}

#include <Nazara/Core/DebugOff.hpp>
<commit_msg>Initializer now uninitialize in the inverse order<commit_after>// Copyright (C) 2013 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Debug.hpp>

template<typename...> struct NzImplInitializer;

template<typename T, typename... Rest>
struct NzImplInitializer<T, Rest...>
{
	static bool Init()
	{
		if (T::Initialize())
		{
			if (NzImplInitializer<Rest...>::Init())
				return true;
			else
				T::Uninitialize();
		}

		return false;
	}

	static void Uninit()
	{
		NzImplInitializer<Rest...>::Uninit();
		T::Uninitialize();
	}
};

template<>
struct NzImplInitializer<>
{
	static bool Init()
	{
		return true;
	}

	static void Uninit()
	{
	}
};

template<typename... Args>
NzInitializer<Args...>::NzInitializer()
{
	m_initialized = NzImplInitializer<Args...>::Init();
}

template<typename... Args>
NzInitializer<Args...>::~NzInitializer()
{
	if (m_initialized)
		NzImplInitializer<Args...>::Uninit();
}

template<typename... Args>
bool NzInitializer<Args...>::IsInitialized() const
{
	return m_initialized;
}

template<typename... Args>
NzInitializer<Args...>::operator bool() const
{
	return m_initialized;
}

#include <Nazara/Core/DebugOff.hpp>
<|endoftext|>


<commit_before>#define DEBUG
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/epoll.h>

//for connection to server
bool ready4data = false;//set to true when streaming starts
bool inited = false;
bool stopparsing = false;
timeval lastrec;

int CONN_fd = 0;
#include "../util/ddv_socket.cpp" //DDVTech Socket wrapper
#include "../util/flv_sock.cpp" //FLV parsing with SocketW
#include "parsechunks.cpp" //chunkstream parsing
#include "handshake.cpp" //handshaking

int server_socket = 0;

void termination_handler (int signum){
  if (server_socket == 0) return;
  close(server_socket);
  server_socket = 0;
}

int main(int argc, char ** argv){
  //setup signal handler
  struct sigaction new_action;
  new_action.sa_handler = termination_handler;
  sigemptyset (&new_action.sa_mask);
  new_action.sa_flags = 0;
  sigaction (SIGINT, &new_action, NULL);
  sigaction (SIGHUP, &new_action, NULL);
  sigaction (SIGTERM, &new_action, NULL);

  server_socket = DDV_Listen(1935);
  if ((argc < 2) || (argv[1] == "nd")){
    if (server_socket > 0){daemon(1, 0);}else{return 1;}
  }
  int status;
  while (server_socket > 0){
    waitpid((pid_t)-1, &status, WNOHANG);
    CONN_fd = DDV_Accept(server_socket);
    if (CONN_fd > 0){
      pid_t myid = fork();
      if (myid == 0){
        break;
      }else{
        printf("Spawned new process %i for handling socket %i\n", (int)myid, CONN_fd);
      }
    }
  }
  if (server_socket <= 0){
    return 0;
  }

  unsigned int ts;
  unsigned int fts = 0;
  unsigned int ftst;
  int ss;
  FLV_Pack * tag;

  //first timestamp set
  firsttime = getNowMS();

  #ifdef DEBUG
  fprintf(stderr, "Doing handshake...\n");
  #endif
  if (doHandshake()){
    #ifdef DEBUG
    fprintf(stderr, "Handshake succcess!\n");
    #endif
  }else{
    #ifdef DEBUG
    fprintf(stderr, "Handshake fail!\n");
    #endif
    return 0;
  }
  #ifdef DEBUG
  fprintf(stderr, "Starting processing...\n");
  #endif

  int retval;
  int poller = epoll_create(1);
  struct epoll_event ev;
  ev.events = EPOLLIN;
  ev.data.fd = CONN_fd;
  epoll_ctl(poller, EPOLL_CTL_ADD, CONN_fd, &ev);
  struct epoll_event events[1];

  while (!socketError && !All_Hell_Broke_Loose){
    //only parse input if available or not yet init'ed
    //rightnow = getNowMS();
    retval = epoll_wait(poller, events, 1, 0);
    if (!ready4data || (snd_cnt - snd_window_at >= snd_window_size)){
      if (DDV_ready(CONN_fd)){
        parseChunk();
      }
    }
    if (ready4data){
      if (!inited){
        //we are ready, connect the socket!
        ss = DDV_OpenUnix(streamname.c_str());
        if (ss <= 0){
          #ifdef DEBUG
          fprintf(stderr, "Could not connect to server!\n");
          #endif
          return 0;
        }
        #ifdef DEBUG
        fprintf(stderr, "Everything connected, starting to send video data...\n");
        #endif
        inited = true;
      }
      //only send data if previous data has been ACK'ed...
      //if (snd_cnt - snd_window_at < snd_window_size){
        if (FLV_GetPacket(tag, ss)){//able to read a full packet?
          ts = tag->data[7] * 256*256*256;
          ts += tag->data[4] * 256*256;
          ts += tag->data[5] * 256;
          ts += tag->data[6];
          if (ts != 0){
            if (fts == 0){fts = ts;ftst = getNowMS();}
            ts -= fts;
            tag->data[7] = ts / (256*256*256);
            tag->data[4] = ts / (256*256);
            tag->data[5] = ts / 256;
            tag->data[6] = ts % 256;
            ts += ftst;
          }else{
            ftst = getNowMS();
            tag->data[7] = ftst / (256*256*256);
            tag->data[4] = ftst / (256*256);
            tag->data[5] = ftst / 256;
            tag->data[6] = ftst % 256;
          }
          SendMedia((unsigned char)tag->data[0], (unsigned char *)tag->data+11, tag->len-15, ts);
          #ifdef DEBUG
          fprintf(stderr, "Sent a tag to %i\n", CONN_fd);
          #endif
        }
      //}
    }
    //send ACK if we received a whole window
    if (rec_cnt - rec_window_at > rec_window_size){
      rec_window_at = rec_cnt;
      SendCTL(3, rec_cnt);//send ack (msg 3)
    }
  }
  //#ifdef DEBUG
  fprintf(stderr, "User %i disconnected.\n", CONN_fd);
  //#endif
  return 0;
}//main
<commit_msg>Meer debugging<commit_after>#define DEBUG
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/epoll.h>

//for connection to server
bool ready4data = false;//set to true when streaming starts
bool inited = false;
bool stopparsing = false;
timeval lastrec;

int CONN_fd = 0;
#include "../util/ddv_socket.cpp" //DDVTech Socket wrapper
#include "../util/flv_sock.cpp" //FLV parsing with SocketW
#include "parsechunks.cpp" //chunkstream parsing
#include "handshake.cpp" //handshaking

int server_socket = 0;

void termination_handler (int signum){
  if (server_socket == 0) return;
  close(server_socket);
  server_socket = 0;
}

int main(int argc, char ** argv){
  //setup signal handler
  struct sigaction new_action;
  new_action.sa_handler = termination_handler;
  sigemptyset (&new_action.sa_mask);
  new_action.sa_flags = 0;
  sigaction (SIGINT, &new_action, NULL);
  sigaction (SIGHUP, &new_action, NULL);
  sigaction (SIGTERM, &new_action, NULL);

  server_socket = DDV_Listen(1935);
  if ((argc < 2) || (argv[1] == "nd")){
    if (server_socket > 0){daemon(1, 0);}else{return 1;}
  }
  int status;
  while (server_socket > 0){
    waitpid((pid_t)-1, &status, WNOHANG);
    CONN_fd = DDV_Accept(server_socket);
    if (CONN_fd > 0){
      pid_t myid = fork();
      if (myid == 0){
        break;
      }else{
        printf("Spawned new process %i for handling socket %i\n", (int)myid, CONN_fd);
      }
    }
  }
  if (server_socket <= 0){
    return 0;
  }

  unsigned int ts;
  unsigned int fts = 0;
  unsigned int ftst;
  int ss;
  FLV_Pack * tag;

  //first timestamp set
  firsttime = getNowMS();

  #ifdef DEBUG
  fprintf(stderr, "Doing handshake...\n");
  #endif
  if (doHandshake()){
    #ifdef DEBUG
    fprintf(stderr, "Handshake succcess!\n");
    #endif
  }else{
    #ifdef DEBUG
    fprintf(stderr, "Handshake fail!\n");
    #endif
    return 0;
  }
  #ifdef DEBUG
  fprintf(stderr, "Starting processing...\n");
  #endif

  int retval;
  int poller = epoll_create(1);
  struct epoll_event ev;
  ev.events = EPOLLIN;
  ev.data.fd = CONN_fd;
  epoll_ctl(poller, EPOLL_CTL_ADD, CONN_fd, &ev);
  struct epoll_event events[1];

  while (!socketError && !All_Hell_Broke_Loose){
    //only parse input if available or not yet init'ed
    //rightnow = getNowMS();
    retval = epoll_wait(poller, events, 1, 0);
    if (!ready4data || (snd_cnt - snd_window_at >= snd_window_size)){
      if (DDV_ready(CONN_fd)){
        parseChunk();
      }
    }
    if (ready4data){
      if (!inited){
        //we are ready, connect the socket!
        ss = DDV_OpenUnix(streamname.c_str());
        if (ss <= 0){
          #ifdef DEBUG
          fprintf(stderr, "Could not connect to server!\n");
          #endif
          return 0;
        }
        #ifdef DEBUG
        fprintf(stderr, "Everything connected, starting to send video data...\n");
        #endif
        inited = true;
      }
      //only send data if previous data has been ACK'ed...
      //if (snd_cnt - snd_window_at < snd_window_size){
        if (FLV_GetPacket(tag, ss)){//able to read a full packet?
          ts = tag->data[7] * 256*256*256;
          ts += tag->data[4] * 256*256;
          ts += tag->data[5] * 256;
          ts += tag->data[6];
          if (ts != 0){
            if (fts == 0){fts = ts;ftst = getNowMS();}
            ts -= fts;
            tag->data[7] = ts / (256*256*256);
            tag->data[4] = ts / (256*256);
            tag->data[5] = ts / 256;
            tag->data[6] = ts % 256;
            ts += ftst;
          }else{
            ftst = getNowMS();
            tag->data[7] = ftst / (256*256*256);
            tag->data[4] = ftst / (256*256);
            tag->data[5] = ftst / 256;
            tag->data[6] = ftst % 256;
          }
          SendMedia((unsigned char)tag->data[0], (unsigned char *)tag->data+11, tag->len-15, ts);
          #ifdef DEBUG
          fprintf(stderr, "Sent a tag to %i\n", CONN_fd);
          #endif
        }
      //}
    }
    //send ACK if we received a whole window
    if (rec_cnt - rec_window_at > rec_window_size){
      rec_window_at = rec_cnt;
      SendCTL(3, rec_cnt);//send ack (msg 3)
    }
  }
  //#ifdef DEBUG
  if (socketError){fprintf(stderr, "socketError\n");}
  if (All_Hell_Broke_Loose){fprintf(stderr, "All Hell Broke Loose\n");}
  fprintf(stderr, "User %i disconnected.\n", CONN_fd);
  //#endif
  return 0;
}//main
<|endoftext|>


<commit_before><commit_msg>fdo#53655: Ignore failure to remove directories (as happens on Windows XP)<commit_after><|endoftext|>


<commit_before>// ConsoleApplication1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
	return 0;
}

<commit_msg>deleting testconsole<commit_after><|endoftext|>


<commit_before>#include "base/base.h"
#include "boost/multiprecision/cpp_int.hpp"
#include "boost/rational.hpp"

using boost::rational;
using boost::rational_cast;
using std::istream;

typedef boost::multiprecision::cpp_rational Q;

struct Vertex {
  Q x;
  Q y;
};

typedef vector<Vertex> Polygon;

std::istream& operator>>(istream& is, Vertex& v) {
  string r;
  while (isspace(is.peek())) {
    is.get();
  }
  std::getline(is, r, ',');
  v.x.assign(r);
  while (isspace(is.peek())) {
    is.get();
  }
  std::getline(is, r);
  v.y.assign(r);
  return is;
}

std::istream& operator>>(istream& is, Polygon& p) {
  int n_verts;
  is >> n_verts;
  p.resize(n_verts);
  for (int i = 0; i < n_verts; ++i) {
    is >> p[i];
  }
  return is;
}

int main() {
  int n_polys;
  cin >> n_polys;
  vector<Polygon> polys(n_polys);
  for (int i = 0; i < n_polys; ++i) {
    cin >> polys[i];
  }
  // TODO: Parse skelton

  Q min_x = 0, min_y = 0, max_x = 1, max_y = 1;
  for (int i = 0; i < n_polys; ++i) {
    for (const auto& v : polys[i]) {
      if (v.x < min_x) min_x = v.x;
      if (max_x < v.x) max_x = v.x;
      if (v.y < min_y) min_y = v.y;
      if (max_y < v.y) max_y = v.y;
    }
  }
  printf(
      R"(<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300px" height="300px" viewBox="%f %f %f %f"><rect x="0" y="0" width="1" height="1" fill="none" stroke="blue" stroke-width="0.01"/>)",
      min_x.convert_to<double>(), min_y.convert_to<double>(),
      Q(max_x - min_x).convert_to<double>(),
      Q(max_y - min_y).convert_to<double>());
  for (int i = 0; i < n_polys; ++i) {
    printf(R"(<path d=")");
    for (int j = 0; j < polys[i].size(); ++j) {
      printf("%c %.8f %.8f ", j == 0 ? 'M' : 'L',
             polys[i][j].x.convert_to<double>(),
             polys[i][j].y.convert_to<double>());
    }
    printf(R"(Z" fill="silver" stroke="gray" stroke-width="0.01" />)");
  }
  printf("</svg>");

  return 0;
}
<commit_msg>Bug fix.<commit_after>#include "base/base.h"
#include "boost/multiprecision/cpp_int.hpp"
#include "boost/rational.hpp"

using namespace std;

using boost::rational;
using boost::rational_cast;

typedef boost::multiprecision::cpp_rational Q;

struct Vertex {
  Q x;
  Q y;
};

typedef vector<Vertex> Polygon;

std::istream& operator>>(istream& is, Vertex& v) {
  string r;
  while (isspace(is.peek())) {
    is.get();
  }
  std::getline(is, r, ',');
  v.x.assign(r);
  while (isspace(is.peek())) {
    is.get();
  }
  std::getline(is, r);
  v.y.assign(r);
  return is;
}

std::istream& operator>>(istream& is, Polygon& p) {
  int n_verts;
  is >> n_verts;
  p.resize(n_verts);
  for (int i = 0; i < n_verts; ++i) {
    is >> p[i];
  }
  return is;
}

int main() {
  int n_polys;
  cin >> n_polys;
  vector<Polygon> polys(n_polys);
  for (int i = 0; i < n_polys; ++i) {
    cin >> polys[i];
  }
  // TODO: Parse skelton

  Q min_x = 0, min_y = 0, max_x = 1, max_y = 1;
  for (int i = 0; i < n_polys; ++i) {
    for (const auto& v : polys[i]) {
      if (v.x < min_x) min_x = v.x;
      if (max_x < v.x) max_x = v.x;
      if (v.y < min_y) min_y = v.y;
      if (max_y < v.y) max_y = v.y;
    }
  }
  printf(
      R"(<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300px" height="300px" viewBox="%f %f %f %f"><rect x="0" y="0" width="1" height="1" fill="none" stroke="blue" stroke-width="0.01"/>)",
      min_x.convert_to<double>(), min_y.convert_to<double>(),
      Q(max_x - min_x).convert_to<double>(),
      Q(max_y - min_y).convert_to<double>());
  for (int i = 0; i < n_polys; ++i) {
    printf(R"(<path d=")");
    for (int j = 0; j < polys[i].size(); ++j) {
      printf("%c %.8f %.8f ", j == 0 ? 'M' : 'L',
             polys[i][j].x.convert_to<double>(),
             polys[i][j].y.convert_to<double>());
    }
    printf(R"(Z" fill="silver" stroke="gray" stroke-width="0.01" />)");
  }
  printf("</svg>");

  return 0;
}
<|endoftext|>


<commit_before>//
//  ofxComposer.cpp
//  GPUBurner
//
//  Created by Patricio Gonzalez Vivo on 3/9/12.
//  Copyright (c) 2012 http://www.PatricioGonzalezVivo.com All rights reserved.
//

#include "ofxComposer.h"

ofxComposer::ofxComposer(){
    ofAddListener(ofEvents().mouseMoved, this, &ofxComposer::_mouseMoved);
	ofAddListener(ofEvents().mousePressed, this, &ofxComposer::_mousePressed);
	ofAddListener(ofEvents().mouseReleased, this, &ofxComposer::_mouseReleased);
	ofAddListener(ofEvents().keyPressed, this, &ofxComposer::_keyPressed);
    ofAddListener(ofEvents().windowResized, this, &ofxComposer::_windowResized);

#ifdef USE_OFXGLEDITOR
    fbo.allocate(640, 480);
    fbo.begin();
    ofClear(0, 0);
    fbo.end();
#endif

    configFile = "config.xml";
    selectedDot = -1;
    selectedID = -1;
    bGLEditor = false;
}

void ofxComposer::load(string _fileConfig){
    if (_fileConfig != "default")
        configFile = _fileConfig;

    ofxXmlSettings XML;

    patches.clear();
    if (XML.loadFile(_fileConfig)){
        int totalPatchs = XML.getNumTags("surface");

        // Load each surface present on the xml file
        //
        for(int i = 0; i < totalPatchs ; i++){
            ofxPatch *nPatch = new ofxPatch();
            bool loaded = nPatch->loadSettings(i, "config.xml");

            if (loaded){
#ifdef USE_OFXGLEDITOR
                if (nPatch->getType() == "ofxGLEditor"){
                    ofLog(OF_LOG_NOTICE,"ofxComposer: ofxGLEditor loaded");
                    editor.setup("menlo.ttf");
                    editor.setCurrentEditor(1);
                    fbo.allocate(ofGetWindowWidth(), ofGetWindowHeight());
                    fbo.begin();
                    ofClear(0, 150);
                    fbo.end();

                    nPatch->setTexture( fbo.getTextureReference(), 0);

                    bGLEditor = true;
                }
#endif

                if (nPatch->getType() == "input"){
                    nPatch->setTexture( fbo.getTextureReference(), 0);
                }

                // Listen to close bottom on the titleBar
                //
                ofAddListener( nPatch->title->close , this, &ofxComposer::closePatch);

                // Insert the new patch into the map
                //
                patches[nPatch->getId()] = nPatch;
            }
        }

        // Load links between Patchs
        //
        for(int i = 0; i < totalPatchs ; i++){
            if (XML.pushTag("surface", i)){
                int fromID = XML.getValue("id", -1);

                if (XML.pushTag("out")){

                    int totalLinks = XML.getNumTags("dot");
                    for(int j = 0; j < totalLinks ; j++){

                        if (XML.pushTag("dot",j)){
                            int toID = XML.getValue("to", 0);
                            int nTex = XML.getValue("tex", 0);

                            // If everything goes ok "i" will match the position of the vector
                            // with the position on the XML, in the same place of the vector array
                            // defined on the previus loop
                            //
                            connect( fromID, toID, nTex);

                            XML.popTag();
                        }
                    }
                    XML.popTag();
                }
                XML.popTag();
            }
        }
    }
}

bool ofxComposer::addPatch(string _filePath, ofPoint _position){
    bool loaded = false;

    ofxPatch *nPatch = new ofxPatch();
    loaded = nPatch->loadFile( _filePath, "config.xml" );

    if ( loaded ){
        nPatch->move( _position );
        nPatch->scale(0.5);
        nPatch->saveSettings();
        ofAddListener( nPatch->title->close , this, &ofxComposer::closePatch);
        patches[nPatch->getId()] = nPatch;
    }

    return loaded;
}

bool ofxComposer::connect( int _fromID, int _toID, int nTexture ){
    bool connected = false;

    if ((_fromID != -1) && (patches[_fromID] != NULL) &&
        (_toID != -1) && (patches[_toID] != NULL) &&
        (patches[ _toID ]->getType() == "ofShader") ) {

        LinkDot newDot;
        newDot.pos = patches[ _fromID ]->getOutPutPosition();
        newDot.toId = patches[ _toID ]->getId();
        newDot.to = &(patches[ _toID ]->inPut[ nTexture ]);
        newDot.toShader = patches[ _toID ]->getShader();
        newDot.nTex = nTexture;

        patches[ _fromID ]->outPut.push_back( newDot );
        connected = true;
    }

    return connected;
}

void ofxComposer::closePatch( int &_nID ){
    bool deleted = false;

    if ( (_nID != -1) && (patches[_nID] != NULL) ){
        int targetTag = 0;

        // Delete object from the vector
        //
        patches.erase(_nID);

        // Delete XML Data
        //
        ofxXmlSettings XML;
        if ( XML.loadFile( configFile ) ){
            int totalSurfaces = XML.getNumTags("surface");
            for (int i = 0; i < totalSurfaces; i++){
                if (XML.pushTag("surface", i)){
                    if ( XML.getValue("id", -1) == _nID){
                        targetTag = i;
                    }
                    XML.popTag();
                }
            }

            XML.removeTag("surface", targetTag);
            XML.saveFile();
        }

        // Delete links Dependences
        //
        for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
            for (int j = it->second->outPut.size()-1; j >= 0 ; j--){
                if ( it->second->outPut[j].toId == _nID){
                    it->second->outPut.erase( it->second->outPut.begin() + j );
                    it->second->saveSettings();
                }
            }
        }

        selectedID = -1;
    }
}

//-------------------------------------------------------------- LOOP
void ofxComposer::update(){
    for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
        it->second->update();
    }
}

void ofxComposer::draw(){
    ofPushView();
    ofPushStyle();
    ofPushMatrix();

    ofEnableAlphaBlending();
    for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
        it->second->draw();
    }

    if ( bGLEditor && (selectedID >= 0)){
        if (patches[selectedID]->getType() == "ofShader"){
#ifdef USE_OFXGLEDITOR
            fbo.begin();
            ofClear(0, 150);
            ofRotate(180, 0, 1, 0);
            editor.draw();
            fbo.end();
#endif
        } else {
            fbo.begin();
            ofClear(0, 50);
            fbo.end();
        }
    }

    if (selectedDot >= 0){
        ofLine(patches[selectedDot]->getOutPutPosition(), ofPoint(ofGetMouseX(),ofGetMouseY()));
    }

    ofDisableBlendMode();
    ofEnableAlphaBlending();

    ofPopMatrix();
    ofPopStyle();
    ofPopView();
}

//-------------------------------------------------------------- EVENTS
void ofxComposer::_keyPressed(ofKeyEventArgs &e){
#ifdef USE_OFXGLEDITOR
    if (bGLEditor)
        editor.keyPressed(e.key);

    if (selectedID >= 0){
        if (patches[selectedID]->getType() == "ofShader"){
            patches[selectedID]->setFrag(editor.getText(1));
            patches[selectedID]->saveSettings();
        }
    }
#endif
}

void ofxComposer::_mouseMoved(ofMouseEventArgs &e){
    ofVec2f mouse = ofVec2f(e.x, e.y);

    for(map<int,ofxPatch*>::reverse_iterator rit = patches.rbegin(); rit != patches.rend(); rit++ ){
        if (rit->second->isOver(mouse)){
            activePatch( rit->first );
            break;
        }
    }
}

void ofxComposer::activePatch( int _nID ){
    if ( (_nID != -1) && (patches[_nID] != NULL) ){
        selectedID = _nID;

        for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
            if (it->first == _nID)
                it->second->bActive = true;
            else
                it->second->bActive = false;
        }
    }
}

void ofxComposer::_mousePressed(ofMouseEventArgs &e){
    ofVec2f mouse = ofVec2f(e.x, e.y);

    selectedDot = -1;
    for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
        if ( (it->second->getOutPutPosition().distance(mouse) < 5) && (it->second->bEditMode) && !(it->second->bEditMask) ){
            selectedDot = it->first;
            it->second->bActive = false;
            selectedID = -1;
        }
    }

    if (selectedDot == -1){
        for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
            if ((it->second->bActive) && (it->second->bEditMode) && !(it->second->bEditMask)){
                selectedID = it->first;
#ifdef USE_OFXGLEDITOR
                if (bGLEditor && (it->second->getType() == "ofShader")){
                    editor.setText(it->second->getFrag(), 1);
                }
#endif
            }
        }
    }
}

void ofxComposer::_mouseReleased(ofMouseEventArgs &e){
    ofVec2f mouse = ofVec2f(e.x, e.y);

    if (selectedDot != -1){
        for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
            if ((selectedDot != it->first) &&                   // If not him self
                (it->second->getType() == "ofShader") &&   // The target it´s a shader
                (it->second->bEditMode) &&               // And we are in editMode and not on maskMode
                !(it->second->bEditMask) ){

                for (int j = 0; j < it->second->inPut.size(); j++){

                    // And after checking in each dot of each shader...
                    // ... fin the one where the mouse it´s over
                    //
                    if ( it->second->inPut[j].pos.distance(mouse) < 5){

                        // Once he founds it
                        // make the link and forget the selection
                        //
                        connect( selectedDot , it->first, j );
                        patches[ selectedDot ]->saveSettings();
                        selectedDot = -1;
                    }
                }
            }
        }

        // If he release the mouse over nothing it will clear all
        // the connections of that dot.
        //
        if (selectedDot != -1){
            patches[selectedDot]->outPut.clear();
            patches[selectedDot]->saveSettings();
            selectedDot = -1;
        }
    }
}

void ofxComposer::_windowResized(ofResizeEventArgs &e){
#ifdef USE_OFXGLEDITOR
    if (bGLEditor ){
        editor.reShape();
        fbo.allocate(e.width, e.height);
        fbo.begin();
        ofClear(0, 150);
        fbo.end();
    }
#endif
}<commit_msg>TODO fix deletion of PATCHes<commit_after>//
//  ofxComposer.cpp
//  GPUBurner
//
//  Created by Patricio Gonzalez Vivo on 3/9/12.
//  Copyright (c) 2012 http://www.PatricioGonzalezVivo.com All rights reserved.
//

#include "ofxComposer.h"

ofxComposer::ofxComposer(){
    ofAddListener(ofEvents().mouseMoved, this, &ofxComposer::_mouseMoved);
	ofAddListener(ofEvents().mousePressed, this, &ofxComposer::_mousePressed);
	ofAddListener(ofEvents().mouseReleased, this, &ofxComposer::_mouseReleased);
	ofAddListener(ofEvents().keyPressed, this, &ofxComposer::_keyPressed);
    ofAddListener(ofEvents().windowResized, this, &ofxComposer::_windowResized);

#ifdef USE_OFXGLEDITOR
    fbo.allocate(640, 480);
    fbo.begin();
    ofClear(0, 0);
    fbo.end();
#endif

    configFile = "config.xml";
    selectedDot = -1;
    selectedID = -1;
    bGLEditor = false;
}

void ofxComposer::load(string _fileConfig){
    if (_fileConfig != "default")
        configFile = _fileConfig;

    ofxXmlSettings XML;

    patches.clear();
    if (XML.loadFile(_fileConfig)){
        int totalPatchs = XML.getNumTags("surface");

        // Load each surface present on the xml file
        //
        for(int i = 0; i < totalPatchs ; i++){
            ofxPatch *nPatch = new ofxPatch();
            bool loaded = nPatch->loadSettings(i, "config.xml");

            if (loaded){
#ifdef USE_OFXGLEDITOR
                if (nPatch->getType() == "ofxGLEditor"){
                    ofLog(OF_LOG_NOTICE,"ofxComposer: ofxGLEditor loaded");
                    editor.setup("menlo.ttf");
                    editor.setCurrentEditor(1);
                    fbo.allocate(ofGetWindowWidth(), ofGetWindowHeight());
                    fbo.begin();
                    ofClear(0, 150);
                    fbo.end();

                    nPatch->setTexture( fbo.getTextureReference(), 0);

                    bGLEditor = true;
                }
#endif

                if (nPatch->getType() == "input"){
                    nPatch->setTexture( fbo.getTextureReference(), 0);
                }

                // Listen to close bottom on the titleBar
                //
                ofAddListener( nPatch->title->close , this, &ofxComposer::closePatch);

                // Insert the new patch into the map
                //
                patches[nPatch->getId()] = nPatch;
            }
        }

        // Load links between Patchs
        //
        for(int i = 0; i < totalPatchs ; i++){
            if (XML.pushTag("surface", i)){
                int fromID = XML.getValue("id", -1);

                if (XML.pushTag("out")){

                    int totalLinks = XML.getNumTags("dot");
                    for(int j = 0; j < totalLinks ; j++){

                        if (XML.pushTag("dot",j)){
                            int toID = XML.getValue("to", 0);
                            int nTex = XML.getValue("tex", 0);

                            // If everything goes ok "i" will match the position of the vector
                            // with the position on the XML, in the same place of the vector array
                            // defined on the previus loop
                            //
                            connect( fromID, toID, nTex);

                            XML.popTag();
                        }
                    }
                    XML.popTag();
                }
                XML.popTag();
            }
        }
    }
}

bool ofxComposer::addPatch(string _filePath, ofPoint _position){
    bool loaded = false;

    ofxPatch *nPatch = new ofxPatch();
    loaded = nPatch->loadFile( _filePath, "config.xml" );

    if ( loaded ){
        nPatch->move( _position );
        nPatch->scale(0.5);
        nPatch->saveSettings();
        ofAddListener( nPatch->title->close , this, &ofxComposer::closePatch);
        patches[nPatch->getId()] = nPatch;
    }

    return loaded;
}

bool ofxComposer::connect( int _fromID, int _toID, int nTexture ){
    bool connected = false;

    if ((_fromID != -1) && (patches[_fromID] != NULL) &&
        (_toID != -1) && (patches[_toID] != NULL) &&
        (patches[ _toID ]->getType() == "ofShader") ) {

        LinkDot newDot;
        newDot.pos = patches[ _fromID ]->getOutPutPosition();
        newDot.toId = patches[ _toID ]->getId();
        newDot.to = &(patches[ _toID ]->inPut[ nTexture ]);
        newDot.toShader = patches[ _toID ]->getShader();
        newDot.nTex = nTexture;

        patches[ _fromID ]->outPut.push_back( newDot );
        connected = true;
    }

    return connected;
}

void ofxComposer::closePatch( int &_nID ){
    bool deleted = false;

    if ( (_nID != -1) && (patches[_nID] != NULL) ){
        int targetTag = 0;

        // Delete links Dependences
        //
        for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
            for (int j = it->second->outPut.size()-1; j >= 0 ; j--){
                if ( it->second->outPut[j].toId == _nID){
                    it->second->outPut.erase( it->second->outPut.begin() + j );
                    it->second->saveSettings();
                }
            }
        }

        selectedID = -1;

        // Delete object from memory and then from vector
        //
        ofxPatch * tmp = patches[_nID];
        cout << patches.erase(_nID) << endl;
        delete tmp;

        // Delete XML Data
        //
        ofxXmlSettings XML;
        if ( XML.loadFile( configFile ) ){
            int totalSurfaces = XML.getNumTags("surface");
            for (int i = 0; i < totalSurfaces; i++){
                if (XML.pushTag("surface", i)){
                    if ( XML.getValue("id", -1) == _nID){
                        targetTag = i;
                    }
                    XML.popTag();
                }
            }

            XML.removeTag("surface", targetTag);
            XML.saveFile();
        }
    }
}

//-------------------------------------------------------------- LOOP
void ofxComposer::update(){
    for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
        it->second->update();
    }
}

void ofxComposer::draw(){
    ofPushView();
    ofPushStyle();
    ofPushMatrix();

    ofEnableAlphaBlending();
    for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
        it->second->draw();
    }

    if ( bGLEditor && (selectedID >= 0)){
        if (patches[selectedID]->getType() == "ofShader"){
#ifdef USE_OFXGLEDITOR
            fbo.begin();
            ofClear(0, 150);
            ofRotate(180, 0, 1, 0);
            editor.draw();
            fbo.end();
#endif
        } else {
            fbo.begin();
            ofClear(0, 50);
            fbo.end();
        }
    }

    if (selectedDot >= 0){
        ofLine(patches[selectedDot]->getOutPutPosition(), ofPoint(ofGetMouseX(),ofGetMouseY()));
    }

    ofDisableBlendMode();
    ofEnableAlphaBlending();

    ofPopMatrix();
    ofPopStyle();
    ofPopView();
}

//-------------------------------------------------------------- EVENTS
void ofxComposer::_keyPressed(ofKeyEventArgs &e){
#ifdef USE_OFXGLEDITOR
    if (bGLEditor)
        editor.keyPressed(e.key);

    if (selectedID >= 0){
        if (patches[selectedID]->getType() == "ofShader"){
            patches[selectedID]->setFrag(editor.getText(1));
            patches[selectedID]->saveSettings();
        }
    }
#endif
}

void ofxComposer::_mouseMoved(ofMouseEventArgs &e){
    ofVec2f mouse = ofVec2f(e.x, e.y);

    for(map<int,ofxPatch*>::reverse_iterator rit = patches.rbegin(); rit != patches.rend(); rit++ ){
        if (rit->second->isOver(mouse)){
            activePatch( rit->first );
            break;
        }
    }
}

void ofxComposer::activePatch( int _nID ){
    if ( (_nID != -1) && (patches[_nID] != NULL) ){
        selectedID = _nID;

        for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
            if (it->first == _nID)
                it->second->bActive = true;
            else
                it->second->bActive = false;
        }
    }
}

void ofxComposer::_mousePressed(ofMouseEventArgs &e){
    ofVec2f mouse = ofVec2f(e.x, e.y);

    selectedDot = -1;
    for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
        if ( (it->second->getOutPutPosition().distance(mouse) < 5) && (it->second->bEditMode) && !(it->second->bEditMask) ){
            selectedDot = it->first;
            it->second->bActive = false;
            selectedID = -1;
        }
    }

    if (selectedDot == -1){
        for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
            if ((it->second->bActive) && (it->second->bEditMode) && !(it->second->bEditMask)){
                selectedID = it->first;
#ifdef USE_OFXGLEDITOR
                if (bGLEditor && (it->second->getType() == "ofShader")){
                    editor.setText(it->second->getFrag(), 1);
                }
#endif
            }
        }
    }
}

void ofxComposer::_mouseReleased(ofMouseEventArgs &e){
    ofVec2f mouse = ofVec2f(e.x, e.y);

    if (selectedDot != -1){
        for(map<int,ofxPatch*>::iterator it = patches.begin(); it != patches.end(); it++ ){
            if ((selectedDot != it->first) &&                   // If not him self
                (it->second->getType() == "ofShader") &&   // The target it´s a shader
                (it->second->bEditMode) &&               // And we are in editMode and not on maskMode
                !(it->second->bEditMask) ){

                for (int j = 0; j < it->second->inPut.size(); j++){

                    // And after checking in each dot of each shader...
                    // ... fin the one where the mouse it´s over
                    //
                    if ( it->second->inPut[j].pos.distance(mouse) < 5){

                        // Once he founds it
                        // make the link and forget the selection
                        //
                        connect( selectedDot , it->first, j );
                        patches[ selectedDot ]->saveSettings();
                        selectedDot = -1;
                    }
                }
            }
        }

        // If he release the mouse over nothing it will clear all
        // the connections of that dot.
        //
        if (selectedDot != -1){
            patches[selectedDot]->outPut.clear();
            patches[selectedDot]->saveSettings();
            selectedDot = -1;
        }
    }
}

void ofxComposer::_windowResized(ofResizeEventArgs &e){
#ifdef USE_OFXGLEDITOR
    if (bGLEditor ){
        editor.reShape();
        fbo.allocate(e.width, e.height);
        fbo.begin();
        ofClear(0, 150);
        fbo.end();
    }
#endif
}<|endoftext|>