<commit_before>#pragma once

#include "slotted_bag.hpp"
#include "thread_pool_options.hpp"
#include "thread_pool_state.hpp"

#include <atomic>
#include <thread>
#include <limits>
#include <mutex>
#include <chrono>
#include <condition_variable>

namespace tp
{

/**
* @brief The Worker class owns task queue and executing thread.
* In thread it tries to pop task from queue. If queue is empty then it tries
* to steal task from the sibling worker. If steal was unsuccessful then spins
* with one millisecond delay.
* @details State Machine:
*
*            +----------------+---------------+
*            |                |               |
*            v                |               |
*       +--------+       +----------+      +------+
*    +--| Active | ----> | BusyWait | ---> | Idle |
*    |  +--------+       +----------+      +------+
*    |       ^
*    |       |
*    +-------+
*
*/
template <typename Task, template<typename> class Queue>
class Worker final
{
    using WorkerVector = std::vector<std::unique_ptr<Worker<Task, Queue>>>;

    class WorkerStoppedException final : public std::exception
    {
    };

    /**
    * @brief State An Enum representing the Rouser thread state.
    */
    enum class State
    {
        Initialized,
        Running,
        Stopped
    };

public:
    /**
    * @brief Worker Constructor.
    * @param busy_wait_options The busy wait behaviour options.
    * @param queue_size Length of underlying task queue.
    */
    explicit Worker(ThreadPoolOptions::BusyWaitOptions const& busy_wait_options, size_t queue_size);

    /**
    * @brief Copy ctor implementation.
    */
    Worker(Worker const&) = delete;

    /**
    * @brief Copy assignment implementation.
    */
    Worker& operator=(Worker const& rhs) = delete;

    /**
    * @brief Move ctor implementation.
    */
    Worker(Worker&& rhs) = delete;

    /**
    * @brief Move assignment implementaion.
    */
    Worker& operator=(Worker&& rhs) = delete;

    /**
    * @brief Destructor implementation.
    */
    ~Worker();

    /**
    * @brief start Create the executing thread and start tasks execution.
    * @param id Worker ID.
    * @param state A pointer to thread pool's shared state.
    * @note The parameters passed into this function generally relate to the global thread pool state.
    */
    void start(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state);

    /**
    * @brief stop Stop all worker's thread and stealing activity.
    * Waits until the executing thread becomes finished.
    * @note Stop may only be called once start() has been invoked.
    * Repeated successful calls to stop() will be no-ops after the first.
    */
    void stop();

    /**
    * @brief tryPost Post task to queue.
    * @param handler Handler to be executed in executing thread.
    * @return true on success.
    */
    template <typename Handler>
    bool tryPost(Handler&& handler);

    /**
    * @brief tryGetLocalTask Get one task from this worker queue.
    * @param task Place for the obtained task to be stored.
    * @return true on success.
    */
    bool tryGetLocalTask(Task& task);

    /**
    * @brief getWorkerIdForCurrentThread Return worker ID associated with
    * current thread if exists.
    * @return Worker ID.
    */
    static size_t getWorkerIdForCurrentThread();

    /**
    * @brief wake Awake the worker if it was previously asleep.
    */
    void wake();

private:

    /**
    * @brief tryRoundRobinSteal Try stealing a thread from sibling workers in a round-robin fashion.
    * @param task Place for the obtained task to be stored.
    * @param workers Sibling workers for performing round robin work stealing.
    * @return true upon success, false otherwise.
    */
    bool tryRoundRobinSteal(Task& task, WorkerVector& workers);

    /**
    * @brief HandleTask Process a specific task.
    * @param task The task to be processed.
    */
    void handleTask(Task& task);

    /**
    * @brief tryGetTask Try to obtain a work item.
    * @details This entails attempting to pop an item from the local queue, and if not successful,
    * the worker will attempt to perform a round robin steal.
    * @param task Place for the obtained task to be stored.
    * @param workers Sibling workers for performing round robin work stealing.
    * @return true upon success, false otherwise.
    */
    bool tryGetTask(Task& task, WorkerVector& workers);

    /**
    * @brief threadFunc Executing thread function.
    * @param id Worker ID.
    * @param state A pointer to thread pool's shared state.
    * @note The parameters passed into this function generally relate to the global thread pool state.
    */
    void threadFunc(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state);

    Queue<Task> m_queue;
    std::atomic<State> m_state;
    std::thread m_thread;
    size_t m_next_donor;
    ThreadPoolOptions::BusyWaitOptions m_busy_wait_options;

    std::mutex m_idle_mutex;
    std::condition_variable m_idle_cv;

    bool m_is_idle;
    bool m_abort_idle;

};

/// Implementation

namespace detail
{
    inline size_t& thread_id()
    {
        static thread_local size_t tss_id = std::numeric_limits<size_t>::max();
        return tss_id;
    }
}

template <typename Task, template<typename> class Queue>
inline Worker<Task, Queue>::Worker(ThreadPoolOptions::BusyWaitOptions const& busy_wait_options, size_t queue_size)
    : m_queue(queue_size)
    , m_state(State::Initialized)
    , m_next_donor(0) // Initialized in threadFunc.
    , m_busy_wait_options(busy_wait_options)
    , m_is_idle(false)
    , m_abort_idle(false)
{
}

template <typename Task, template<typename> class Queue>
inline Worker<Task, Queue>::~Worker()
{
    stop();
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::stop()
{
    auto expectedState = State::Running;
    if (m_state.compare_exchange_strong(expectedState, State::Stopped, std::memory_order_acq_rel, std::memory_order_relaxed))
    {
        wake();
        m_thread.join();
    }
    else if (expectedState == State::Initialized)
        throw std::runtime_error("Cannot stop Worker: stop may only be calld after the Worker has been started.");
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::start(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state)
{
    auto expectedState = State::Initialized;
    if (!m_state.compare_exchange_strong(expectedState, State::Running, std::memory_order_acq_rel, std::memory_order_relaxed))
        throw std::runtime_error("Cannot start Worker: it has previously been started or stopped.");

    m_thread = std::thread(&Worker<Task, Queue>::threadFunc, this, id, state);
}

template <typename Task, template<typename> class Queue>
inline size_t Worker<Task, Queue>::getWorkerIdForCurrentThread()
{
    return detail::thread_id();
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::wake()
{
    bool notify;
    {
        std::unique_lock<std::mutex> lock(m_idle_mutex);

        m_abort_idle = true;
        notify = m_is_idle;
    }

    // Notify outside of lock.
    if (notify)
        m_idle_cv.notify_one();
}

template <typename Task, template<typename> class Queue>
template <typename Handler>
inline bool Worker<Task, Queue>::tryPost(Handler&& handler)
{
    return m_queue.push(std::forward<Handler>(handler));
}

template <typename Task, template<typename> class Queue>
inline bool Worker<Task, Queue>::tryGetLocalTask(Task& task)
{
    return m_queue.pop(task);
}

template <typename Task, template<typename> class Queue>
inline bool Worker<Task, Queue>::tryRoundRobinSteal(Task& task, WorkerVector& workers)
{
    auto starting_index = m_next_donor;

    // Iterate once through the worker ring, checking for queued work items on each thread.
    do
    {
        // Don't steal from local queue.
        if (m_next_donor != detail::thread_id() && workers[m_next_donor]->tryGetLocalTask(task))
        {
            // Increment before returning so that m_next_donor always points to the worker that has gone the longest
            // without a steal attempt. This helps enforce fairness in the stealing.
            ++m_next_donor %= workers.size();
            return true;
        }

        ++m_next_donor %= workers.size();
    } while (m_next_donor != starting_index);

    return false;
}

template <typename Task, template <typename> class Queue>
void Worker<Task, Queue>::handleTask(Task& task)
{
    try
    {
        task();
    }
    catch (...)
    {
		LogPrint("mempool", "%s\n", "Unknown Worker task Error!!!");
		printf("Unknown Worker task Error!!\n");
        // Suppress all exceptions.
    }
}

template <typename Task, template <typename> class Queue>
bool Worker<Task, Queue>::tryGetTask(Task& task, WorkerVector& workers)
{
    if (m_state.load(std::memory_order_acquire) != State::Running)
        throw WorkerStoppedException();

    // Prioritize local queue, then try stealing from sibling workers.
    return tryGetLocalTask(task) || tryRoundRobinSteal(task, workers);
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::threadFunc(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state)
{
    detail::thread_id() = id;
    m_next_donor = (id + 1) % state->workers().size();
    Task handler;
    bool task_found = false;

    try
    {
        while (true)
        {
            // By default, this loop operates in the active state.
            // We poll for items from our local task queue and try to steal from others.
            if (tryGetTask(handler, state->workers()))
            {
                handleTask(handler);
                continue;
            };

            // We were unable to obtain a task.
            // We now transition into the busy wait state.
            task_found = false;
            state->numBusyWaiters().fetch_add(1, std::memory_order_acq_rel);

            for (auto i = 0u; i < m_busy_wait_options.numIterations() && !task_found; i++)
            {
                std::this_thread::sleep_for(m_busy_wait_options.iterationFunction()(i));
                task_found = tryGetTask(handler, state->workers());
            }

            // If we found a task during our busy wait sequence, we abort it and transition back into the active loop.
            if (task_found)
            {
                state->numBusyWaiters().fetch_sub(1, std::memory_order_acq_rel);
                handleTask(handler); // Handle the task body only once we decrement the busy waiting loop.
                continue;
            }

            // No tasks were found during the busy wait sequence.
            // We now transition into the idle state.
            {
                std::unique_lock<std::mutex> lock(m_idle_mutex);
                m_is_idle = false;
                m_abort_idle = false;
            }

            // We put this worker up for grabs as a recipient to new posts in the thread pool.
            state->idleWorkers().fill(id);

            // We need to transition out of the busy wait state after we have submitted ourselves to the idle
            // worker queue in order to avoid a race.
            state->numBusyWaiters().fetch_sub(1, std::memory_order_acq_rel);

            // While we were adding this worker to the idle worker bag, a job may have been posted into this
            // worker's queue. We need to check for work again before initiating the deep sleep sequence, otherwise
            // the given task may be lost.
            // Any further posts will flip the m_abort_idle flag to true, and we will catch them later.
            if (tryGetTask(handler, state->workers()))
            {
                handleTask(handler);
                // A task was indeed posted in the time it took this worker to enter the bag.
                // We remove the worker from the bag. If the internal state of the bag was not changed,
                // this means a different thread has already removed this worker from the idle queue,
                // and this case will be caught below. Looping early in this case will cause a loss of synchronization.
                if (state->idleWorkers().empty(id))
                    continue;
            }

            {
                std::unique_lock<std::mutex> lock(m_idle_mutex);

                // A post has occurred during the initialization of the sleep sequence! Abort the sleep sequence.
                if (m_abort_idle)
                    continue;

                m_is_idle = true;
                m_idle_cv.wait(lock, [this]() { return m_abort_idle; });
            }
        }
    }
    catch (WorkerStoppedException &e)
    {
        // Allow thread function to complete.
		LogPrint("mempool", "%s: %s\n", "Worker Error", e.what());
		printf("worker error %s\n", e.what());
    }
}

}<commit_msg>compile<commit_after>#pragma once

#include "slotted_bag.hpp"
#include "thread_pool_options.hpp"
#include "thread_pool_state.hpp"

#include <atomic>
#include <thread>
#include <limits>
#include <mutex>
#include <chrono>
#include <condition_variable>

namespace tp
{

/**
* @brief The Worker class owns task queue and executing thread.
* In thread it tries to pop task from queue. If queue is empty then it tries
* to steal task from the sibling worker. If steal was unsuccessful then spins
* with one millisecond delay.
* @details State Machine:
*
*            +----------------+---------------+
*            |                |               |
*            v                |               |
*       +--------+       +----------+      +------+
*    +--| Active | ----> | BusyWait | ---> | Idle |
*    |  +--------+       +----------+      +------+
*    |       ^
*    |       |
*    +-------+
*
*/
template <typename Task, template<typename> class Queue>
class Worker final
{
    using WorkerVector = std::vector<std::unique_ptr<Worker<Task, Queue>>>;

    class WorkerStoppedException final : public std::exception
    {
    };

    /**
    * @brief State An Enum representing the Rouser thread state.
    */
    enum class State
    {
        Initialized,
        Running,
        Stopped
    };

public:
    /**
    * @brief Worker Constructor.
    * @param busy_wait_options The busy wait behaviour options.
    * @param queue_size Length of underlying task queue.
    */
    explicit Worker(ThreadPoolOptions::BusyWaitOptions const& busy_wait_options, size_t queue_size);

    /**
    * @brief Copy ctor implementation.
    */
    Worker(Worker const&) = delete;

    /**
    * @brief Copy assignment implementation.
    */
    Worker& operator=(Worker const& rhs) = delete;

    /**
    * @brief Move ctor implementation.
    */
    Worker(Worker&& rhs) = delete;

    /**
    * @brief Move assignment implementaion.
    */
    Worker& operator=(Worker&& rhs) = delete;

    /**
    * @brief Destructor implementation.
    */
    ~Worker();

    /**
    * @brief start Create the executing thread and start tasks execution.
    * @param id Worker ID.
    * @param state A pointer to thread pool's shared state.
    * @note The parameters passed into this function generally relate to the global thread pool state.
    */
    void start(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state);

    /**
    * @brief stop Stop all worker's thread and stealing activity.
    * Waits until the executing thread becomes finished.
    * @note Stop may only be called once start() has been invoked.
    * Repeated successful calls to stop() will be no-ops after the first.
    */
    void stop();

    /**
    * @brief tryPost Post task to queue.
    * @param handler Handler to be executed in executing thread.
    * @return true on success.
    */
    template <typename Handler>
    bool tryPost(Handler&& handler);

    /**
    * @brief tryGetLocalTask Get one task from this worker queue.
    * @param task Place for the obtained task to be stored.
    * @return true on success.
    */
    bool tryGetLocalTask(Task& task);

    /**
    * @brief getWorkerIdForCurrentThread Return worker ID associated with
    * current thread if exists.
    * @return Worker ID.
    */
    static size_t getWorkerIdForCurrentThread();

    /**
    * @brief wake Awake the worker if it was previously asleep.
    */
    void wake();

private:

    /**
    * @brief tryRoundRobinSteal Try stealing a thread from sibling workers in a round-robin fashion.
    * @param task Place for the obtained task to be stored.
    * @param workers Sibling workers for performing round robin work stealing.
    * @return true upon success, false otherwise.
    */
    bool tryRoundRobinSteal(Task& task, WorkerVector& workers);

    /**
    * @brief HandleTask Process a specific task.
    * @param task The task to be processed.
    */
    void handleTask(Task& task);

    /**
    * @brief tryGetTask Try to obtain a work item.
    * @details This entails attempting to pop an item from the local queue, and if not successful,
    * the worker will attempt to perform a round robin steal.
    * @param task Place for the obtained task to be stored.
    * @param workers Sibling workers for performing round robin work stealing.
    * @return true upon success, false otherwise.
    */
    bool tryGetTask(Task& task, WorkerVector& workers);

    /**
    * @brief threadFunc Executing thread function.
    * @param id Worker ID.
    * @param state A pointer to thread pool's shared state.
    * @note The parameters passed into this function generally relate to the global thread pool state.
    */
    void threadFunc(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state);

    Queue<Task> m_queue;
    std::atomic<State> m_state;
    std::thread m_thread;
    size_t m_next_donor;
    ThreadPoolOptions::BusyWaitOptions m_busy_wait_options;

    std::mutex m_idle_mutex;
    std::condition_variable m_idle_cv;

    bool m_is_idle;
    bool m_abort_idle;

};

/// Implementation

namespace detail
{
    inline size_t& thread_id()
    {
        static thread_local size_t tss_id = std::numeric_limits<size_t>::max();
        return tss_id;
    }
}

template <typename Task, template<typename> class Queue>
inline Worker<Task, Queue>::Worker(ThreadPoolOptions::BusyWaitOptions const& busy_wait_options, size_t queue_size)
    : m_queue(queue_size)
    , m_state(State::Initialized)
    , m_next_donor(0) // Initialized in threadFunc.
    , m_busy_wait_options(busy_wait_options)
    , m_is_idle(false)
    , m_abort_idle(false)
{
}

template <typename Task, template<typename> class Queue>
inline Worker<Task, Queue>::~Worker()
{
    stop();
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::stop()
{
    auto expectedState = State::Running;
    if (m_state.compare_exchange_strong(expectedState, State::Stopped, std::memory_order_acq_rel, std::memory_order_relaxed))
    {
        wake();
        m_thread.join();
    }
    else if (expectedState == State::Initialized)
        throw std::runtime_error("Cannot stop Worker: stop may only be calld after the Worker has been started.");
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::start(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state)
{
    auto expectedState = State::Initialized;
    if (!m_state.compare_exchange_strong(expectedState, State::Running, std::memory_order_acq_rel, std::memory_order_relaxed))
        throw std::runtime_error("Cannot start Worker: it has previously been started or stopped.");

    m_thread = std::thread(&Worker<Task, Queue>::threadFunc, this, id, state);
}

template <typename Task, template<typename> class Queue>
inline size_t Worker<Task, Queue>::getWorkerIdForCurrentThread()
{
    return detail::thread_id();
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::wake()
{
    bool notify;
    {
        std::unique_lock<std::mutex> lock(m_idle_mutex);

        m_abort_idle = true;
        notify = m_is_idle;
    }

    // Notify outside of lock.
    if (notify)
        m_idle_cv.notify_one();
}

template <typename Task, template<typename> class Queue>
template <typename Handler>
inline bool Worker<Task, Queue>::tryPost(Handler&& handler)
{
    return m_queue.push(std::forward<Handler>(handler));
}

template <typename Task, template<typename> class Queue>
inline bool Worker<Task, Queue>::tryGetLocalTask(Task& task)
{
    return m_queue.pop(task);
}

template <typename Task, template<typename> class Queue>
inline bool Worker<Task, Queue>::tryRoundRobinSteal(Task& task, WorkerVector& workers)
{
    auto starting_index = m_next_donor;

    // Iterate once through the worker ring, checking for queued work items on each thread.
    do
    {
        // Don't steal from local queue.
        if (m_next_donor != detail::thread_id() && workers[m_next_donor]->tryGetLocalTask(task))
        {
            // Increment before returning so that m_next_donor always points to the worker that has gone the longest
            // without a steal attempt. This helps enforce fairness in the stealing.
            ++m_next_donor %= workers.size();
            return true;
        }

        ++m_next_donor %= workers.size();
    } while (m_next_donor != starting_index);

    return false;
}

template <typename Task, template <typename> class Queue>
void Worker<Task, Queue>::handleTask(Task& task)
{
    try
    {
        task();
    }
    catch (...)
    {
		LogPrint("mempool", "%s\n", "Unknown Worker task Error!!!");
		printf("Unknown Worker task Error!!\n");
        // Suppress all exceptions.
    }
}

template <typename Task, template <typename> class Queue>
bool Worker<Task, Queue>::tryGetTask(Task& task, WorkerVector& workers)
{
    if (m_state.load(std::memory_order_acquire) != State::Running)
        throw WorkerStoppedException();

    // Prioritize local queue, then try stealing from sibling workers.
    return tryGetLocalTask(task) || tryRoundRobinSteal(task, workers);
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::threadFunc(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state)
{
    detail::thread_id() = id;
    m_next_donor = (id + 1) % state->workers().size();
    Task handler;
    bool task_found = false;

    try
    {
        while (true)
        {
            // By default, this loop operates in the active state.
            // We poll for items from our local task queue and try to steal from others.
            if (tryGetTask(handler, state->workers()))
            {
                handleTask(handler);
                continue;
            };

            // We were unable to obtain a task.
            // We now transition into the busy wait state.
            task_found = false;
            state->numBusyWaiters().fetch_add(1, std::memory_order_acq_rel);

            for (auto i = 0u; i < m_busy_wait_options.numIterations() && !task_found; i++)
            {
                std::this_thread::sleep_for(m_busy_wait_options.iterationFunction()(i));
                task_found = tryGetTask(handler, state->workers());
            }

            // If we found a task during our busy wait sequence, we abort it and transition back into the active loop.
            if (task_found)
            {
                state->numBusyWaiters().fetch_sub(1, std::memory_order_acq_rel);
                handleTask(handler); // Handle the task body only once we decrement the busy waiting loop.
                continue;
            }

            // No tasks were found during the busy wait sequence.
            // We now transition into the idle state.
            {
                std::unique_lock<std::mutex> lock(m_idle_mutex);
                m_is_idle = false;
                m_abort_idle = false;
            }

            // We put this worker up for grabs as a recipient to new posts in the thread pool.
            state->idleWorkers().fill(id);

            // We need to transition out of the busy wait state after we have submitted ourselves to the idle
            // worker queue in order to avoid a race.
            state->numBusyWaiters().fetch_sub(1, std::memory_order_acq_rel);

            // While we were adding this worker to the idle worker bag, a job may have been posted into this
            // worker's queue. We need to check for work again before initiating the deep sleep sequence, otherwise
            // the given task may be lost.
            // Any further posts will flip the m_abort_idle flag to true, and we will catch them later.
            if (tryGetTask(handler, state->workers()))
            {
                handleTask(handler);
                // A task was indeed posted in the time it took this worker to enter the bag.
                // We remove the worker from the bag. If the internal state of the bag was not changed,
                // this means a different thread has already removed this worker from the idle queue,
                // and this case will be caught below. Looping early in this case will cause a loss of synchronization.
                if (state->idleWorkers().empty(id))
                    continue;
            }

            {
                std::unique_lock<std::mutex> lock(m_idle_mutex);

                // A post has occurred during the initialization of the sleep sequence! Abort the sleep sequence.
                if (m_abort_idle)
                    continue;

                m_is_idle = true;
                m_idle_cv.wait(lock, [this]() { return m_abort_idle; });
            }
        }
    }
    catch (WorkerStoppedException &e)
    {
        // Allow thread function to complete.
		LogPrint("mempool", "%s: %s\n", "Worker Error", e.what().what());
		printf("worker error %s\n", e.what().what());
    }
}

}<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_SPACE_INTERFACE_HH
#define DUNE_GDT_SPACE_INTERFACE_HH

#include <memory>

#include <dune/common/dynvector.hh>

#include <dune/grid/io/file/vtk/vtkwriter.hh>

#include <dune/stuff/la/container/pattern.hh>
#include <dune/stuff/grid/boundaryinfo.hh>
#include <dune/stuff/common/float_cmp.hh>

#include "constraints.hh"

// needs to be here, since one of the above includes the config.h
#include <dune/common/bartonnackmanifcheck.hh>

namespace Dune {
namespace GDT {

template <class Traits>
class SpaceInterface
{
public:
  typedef typename Traits::derived_type derived_type;

  typedef typename Traits::GridPartType GridPartType;
  static const int polOrder = Traits::polOrder;
  typedef typename GridPartType::ctype DomainFieldType;
  static const unsigned int dimDomain = GridPartType::dimension;
  typedef typename Traits::RangeFieldType RangeFieldType;
  static const unsigned int dimRange     = Traits::dimRange;
  static const unsigned int dimRangeCols = Traits::dimRangeCols;

  typedef typename Traits::BackendType BackendType;
  typedef typename Traits::MapperType MapperType;
  typedef typename Traits::BaseFunctionSetType BaseFunctionSetType;
  typedef typename Traits::EntityType EntityType;

  typedef typename GridPartType::IntersectionType IntersectionType;
  typedef Stuff::GridboundaryInterface<IntersectionType> BoundaryInfoType;

  typedef Dune::Stuff::LA::SparsityPatternDefault PatternType;

  std::shared_ptr<const GridPartType> gridPart() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().gridPart());
    return asImp().gridPart();
  }

  const BackendType& backend() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().backend());
    return asImp().backend();
  }

  bool continuous() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().continuous());
    return asImp().continuous();
  }

  const MapperType& mapper() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().mapper());
    return asImp().mapper();
  }

  BaseFunctionSetType baseFunctionSet(const EntityType& entity) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().baseFunctionSet(entity));
    return asImp().baseFunctionSet(entity);
  }

  std::set<size_t> findLocalDirichletDoFs(const EntityType& entity, const BoundaryInfoType& boundaryInfo) const
  {
    static_assert(dimRange == 1, "Not implemented for this dimension!");
    static_assert(dimRangeCols == 1, "Not implemented for this dimension!");
    if (polOrder != 1)
      DUNE_THROW(Dune::NotImplemented, "This does not seem to work for higher orders!");
    // check
    assert(gridPart()->indexSet().contains(entity));
    // prepare
    std::set<size_t> localDirichletDofs;
    std::vector<typename BaseFunctionSetType::DomainType> dirichlet_vertices;
    // get all dirichlet vertices of this entity, therefore
    // * loop over all intersections
    const auto intersection_it_end = gridPart()->iend(entity);
    for (auto intersection_it = gridPart()->ibegin(entity); intersection_it != intersection_it_end; ++intersection_it) {
      // only work on dirichlet ones
      const auto& intersection = *intersection_it;
      if (boundaryInfo.dirichlet(intersection)) {
        // and get the vertices of the intersection
        const auto geometry = intersection.geometry();
        for (size_t cc = 0; cc < geometry.corners(); ++cc)
          dirichlet_vertices.emplace_back(entity.geometry().local(geometry.corner(cc)));
      } // only work on dirichlet ones
    } // loop over all intersections

    // find the corresponding basis functions
    const auto basis = baseFunctionSet(entity);
    if (tmp_basis_values_.size() < basis.size())
      tmp_basis_values_.resize(basis.size());
    for (size_t cc = 0; cc < dirichlet_vertices.size(); ++cc) {
      basis.evaluate(dirichlet_vertices[cc], tmp_basis_values_);
      for (size_t jj = 0; jj < basis.size(); ++jj)
        if (Dune::Stuff::Common::FloatCmp::eq(tmp_basis_values_[jj][0], RangeFieldType(1)))
          localDirichletDofs.insert(jj);
    }

    // finish
    return localDirichletDofs;
  } // ... findLocalDirichletDoFs(...)

  template <class ConstraintsType>
  void localConstraints(const EntityType& entity, ConstraintsType& ret) const
  {
    CHECK_AND_CALL_INTERFACE_IMPLEMENTATION(asImp().localConstraints(entity, ret));
    asImp().localConstraints(entity, ret);
  }

  PatternType* computePattern() const
  {
    return computePattern(*this);
  }

  template <class OtherSpaceType>
  PatternType* computePattern(const OtherSpaceType& other) const
  {
    return computePattern(*(gridPart()), other);
  }

  template <class LocalGridPartType, class OtherSpaceType>
  PatternType* computePattern(const LocalGridPartType& localGridPart, const OtherSpaceType& otherSpace) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().computePattern(localGridPart, otherSpace));
    return asImp().computePattern(localGridPart, otherSpace);
  }

  /**
   *  \brief  computes a sparsity pattern, where this space is the test space (rows/outer) and the other space is the
   *          ansatz space (cols/inner)
   */
  template <class LocalGridPartType, class O>
  PatternType* computeCodim0Pattern(const LocalGridPartType& localGridPart, const SpaceInterface<O>& otherSpace) const
  {
    PatternType* ret     = new PatternType(mapper().size());
    PatternType& pattern = *ret;
    // walk the grid part
    for (typename LocalGridPartType::template Codim<0>::IteratorType entityIt = localGridPart.template begin<0>();
         entityIt != localGridPart.template end<0>();
         ++entityIt) {
      const typename LocalGridPartType::template Codim<0>::EntityType& entity = *entityIt;
      // get basefunctionsets
      const auto testBase   = baseFunctionSet(entity);
      const auto ansatzBase = otherSpace.baseFunctionSet(entity);
      Dune::DynamicVector<size_t> globalRows(testBase.size(), 0);
      mapper().globalIndices(entity, globalRows);
      Dune::DynamicVector<size_t> globalCols(ansatzBase.size(), 0);
      otherSpace.mapper().globalIndices(entity, globalCols);
      for (size_t ii = 0; ii < testBase.size(); ++ii) {
        auto& columns = pattern.inner(globalRows[ii]);
        for (size_t jj = 0; jj < ansatzBase.size(); ++jj) {
          columns.insert(globalCols[jj]);
        }
      }
    } // walk the grid part
    return ret;
  } // ... computeVolumePattern(...)

  /**
   *  \brief  computes a DG sparsity pattern, where this space is the test space (rows/outer) and the other space is the
   *          ansatz space (cols/inner)
   */
  template <class LocalGridPartType, class O>
  PatternType* computeCodim0AndCodim1Pattern(const LocalGridPartType& local_grid_part,
                                             const SpaceInterface<O>& other_space) const
  {
    // prepare
    PatternType* ret     = new PatternType(mapper().size());
    PatternType& pattern = *ret;
    Dune::DynamicVector<size_t> global_rows(mapper().maxNumDofs(), 0);
    Dune::DynamicVector<size_t> global_cols(other_space.mapper().maxNumDofs(), 0);
    // walk the grid part
    const auto entity_it_end = local_grid_part.template end<0>();
    for (auto entity_it = local_grid_part.template begin<0>(); entity_it != entity_it_end; ++entity_it) {
      const auto& entity = *entity_it;
      // get basefunctionsets
      const auto test_base_entity   = baseFunctionSet(entity);
      const auto ansatz_base_entity = other_space.baseFunctionSet(entity);
      mapper().globalIndices(entity, global_rows);
      other_space.mapper().globalIndices(entity, global_cols);
      // compute entity/entity
      for (size_t ii = 0; ii < test_base_entity.size(); ++ii) {
        auto& columns = pattern.inner(global_rows[ii]);
        for (size_t jj = 0; jj < ansatz_base_entity.size(); ++jj) {
          columns.insert(global_cols[jj]);
        }
      }
      // walk the intersections
      const auto intersection_it_end = local_grid_part.iend(entity);
      for (auto intersection_it = local_grid_part.ibegin(entity); intersection_it != intersection_it_end;
           ++intersection_it) {
        const auto& intersection = *intersection_it;
        // get the neighbour
        if (intersection.neighbor() && !intersection.boundary()) {
          const auto neighbour_ptr = intersection.outside();
          const auto& neighbour    = *neighbour_ptr;
          // get the basis
          const auto ansatz_base_neighbour = other_space.baseFunctionSet(neighbour);
          other_space.mapper().globalIndices(neighbour, global_cols);
          // compute entity/neighbour
          for (size_t ii = 0; ii < test_base_entity.size(); ++ii) {
            auto& columns = pattern.inner(global_rows[ii]);
            for (size_t jj = 0; jj < ansatz_base_neighbour.size(); ++jj) {
              columns.insert(global_cols[jj]);
            }
          }
        } // get the neighbour
      } // walk the intersections
    } // walk the grid part
    return ret;
  } // ... computeVolumeAndCouplingPattern(...)

  template <class LocalGridPartType, class O>
  PatternType* computeCodim1Pattern(const LocalGridPartType& local_grid_part,
                                    const SpaceInterface<O>& other_space) const
  {
    // prepare
    PatternType* ret     = new PatternType(mapper().size());
    PatternType& pattern = *ret;
    Dune::DynamicVector<size_t> global_rows(mapper().maxNumDofs(), 0);
    Dune::DynamicVector<size_t> global_cols(other_space.mapper().maxNumDofs(), 0);
    // walk the grid part
    const auto entity_it_end = local_grid_part.template end<0>();
    for (auto entity_it = local_grid_part.template begin<0>(); entity_it != entity_it_end; ++entity_it) {
      const auto& entity = *entity_it;
      // get basefunctionsets
      const auto test_base_entity = baseFunctionSet(entity);
      mapper().globalIndices(entity, global_rows);
      // walk the intersections
      const auto intersection_it_end = local_grid_part.iend(entity);
      for (auto intersection_it = local_grid_part.ibegin(entity); intersection_it != intersection_it_end;
           ++intersection_it) {
        const auto& intersection = *intersection_it;
        // get the neighbour
        if (intersection.neighbor() && !intersection.boundary()) {
          const auto neighbour_ptr = intersection.outside();
          const auto& neighbour    = *neighbour_ptr;
          // get the basis
          const auto ansatz_base_neighbour = other_space.baseFunctionSet(neighbour);
          other_space.mapper().globalIndices(neighbour, global_cols);
          // compute entity/neighbour
          for (size_t ii = 0; ii < test_base_entity.size(); ++ii) {
            auto& columns = pattern.inner(global_rows[ii]);
            for (size_t jj = 0; jj < ansatz_base_neighbour.size(); ++jj) {
              columns.insert(global_cols[jj]);
            }
          }
        } // get the neighbour
      } // walk the intersections
    } // walk the grid part
    return ret;
  } // ... computeCodim1Pattern(...)

private:
  class BasisVisualization : public Dune::VTKFunction<typename GridPartType::GridViewType>
  {
    static_assert(dimRangeCols == 1, "Not implemented yet!");

  public:
    typedef typename BaseFunctionSetType::DomainType DomainType;
    typedef typename BaseFunctionSetType::RangeType RangeType;

    BasisVisualization(const derived_type& sp, const size_t ind, const std::string nm = "basis")
      : space_(sp)
      , index_(ind)
      , values_(space_.mapper().maxNumDofs(), RangeType(0))
      , name_(nm)
    {
      if (index_ >= space_.mapper().maxNumDofs())
        DUNE_THROW(Dune::RangeError,
                   "index has to be smaller than " << space_.mapper().maxNumDofs() << "(is " << index_ << ")!");
    }

    virtual std::string name() const
    {
      return name_;
    }

    /** \defgroup vtk ´´Methods to comply with the Dune::VTKFunction interface.'' */
    /* @{ */
    virtual int ncomps() const
    {
      return dimRange;
    }

    virtual double evaluate(int component, const EntityType& entity, const DomainType& xx) const
    {
      const auto baseFunctionSet = space_.baseFunctionSet(entity);
      if (component < 0)
        DUNE_THROW(Dune::RangeError, "component must not be negative (is " << component << ")!");
      if (component < int(baseFunctionSet.size())) {
        baseFunctionSet.evaluate(xx, values_);
        assert(component < int(values_.size()) && "This should not happen!");
        return values_[index_][component];
      } else if (component < int(space_.mapper().maxNumDofs()))
        return 0.0;
      else
        DUNE_THROW(Dune::RangeError,
                   "component has to be smaller than " << space_.mapper().maxNumDofs() << "(is " << component << ")!");
    }
    /* @} */

  private:
    const derived_type& space_;
    const size_t index_;
    mutable std::vector<RangeType> values_;
    const std::string name_;
  }; // class BasisVisualization

public:
  void visualize(const std::string filename_prefix = "") const
  {
    std::string filename = filename_prefix;
    if (filename.empty()) {
      filename = "dune.gdt.space";
    }
    typedef typename Dune::VTKWriter<typename GridPartType::GridViewType> VTKWriterType;
    VTKWriterType vtk_writer(gridPart()->gridView(), Dune::VTK::nonconforming);
    for (size_t ii = 0; ii < mapper().maxNumDofs(); ++ii) {
      std::string number = "";
      if (ii == 1)
        number = "1st";
      else if (ii == 2)
        number = "2nd";
      else if (ii == 3)
        number = "3rd";
      else
        number                     = Stuff::Common::toString(ii) + "th";
      const auto iith_baseFunction = std::make_shared<BasisVisualization>(asImp(), ii, number + " basis");
      vtk_writer.addVertexData(iith_baseFunction);
    }
    vtk_writer.write(filename);
  } // ... visualize(...)

  derived_type& asImp()
  {
    return static_cast<derived_type&>(*this);
  }

  const derived_type& asImp() const
  {
    return static_cast<const derived_type&>(*this);
  }

private:
  mutable std::vector<typename BaseFunctionSetType::RangeType> tmp_basis_values_;
}; // class SpaceInterface

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACE_INTERFACE_HH
<commit_msg>[space.interface] add DomainType<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_SPACE_INTERFACE_HH
#define DUNE_GDT_SPACE_INTERFACE_HH

#include <memory>

#include <dune/common/dynvector.hh>
#include <dune/common/fvector.hh>

#include <dune/grid/io/file/vtk/vtkwriter.hh>

#include <dune/stuff/la/container/pattern.hh>
#include <dune/stuff/grid/boundaryinfo.hh>
#include <dune/stuff/common/float_cmp.hh>

#include "constraints.hh"

// needs to be here, since one of the above includes the config.h
#include <dune/common/bartonnackmanifcheck.hh>

namespace Dune {
namespace GDT {

template <class Traits>
class SpaceInterface
{
public:
  typedef typename Traits::derived_type derived_type;

  typedef typename Traits::GridPartType GridPartType;
  static const int polOrder = Traits::polOrder;
  typedef typename GridPartType::ctype DomainFieldType;
  static const unsigned int dimDomain = GridPartType::dimension;
  typedef FieldVector<DomainFieldType, dimDomain> DomainType;
  typedef typename Traits::RangeFieldType RangeFieldType;
  static const unsigned int dimRange     = Traits::dimRange;
  static const unsigned int dimRangeCols = Traits::dimRangeCols;

  typedef typename Traits::BackendType BackendType;
  typedef typename Traits::MapperType MapperType;
  typedef typename Traits::BaseFunctionSetType BaseFunctionSetType;
  typedef typename Traits::EntityType EntityType;

  typedef typename GridPartType::IntersectionType IntersectionType;
  typedef Stuff::GridboundaryInterface<IntersectionType> BoundaryInfoType;

  typedef Dune::Stuff::LA::SparsityPatternDefault PatternType;

  std::shared_ptr<const GridPartType> gridPart() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().gridPart());
    return asImp().gridPart();
  }

  const BackendType& backend() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().backend());
    return asImp().backend();
  }

  bool continuous() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().continuous());
    return asImp().continuous();
  }

  const MapperType& mapper() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().mapper());
    return asImp().mapper();
  }

  BaseFunctionSetType baseFunctionSet(const EntityType& entity) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().baseFunctionSet(entity));
    return asImp().baseFunctionSet(entity);
  }

  std::set<size_t> findLocalDirichletDoFs(const EntityType& entity, const BoundaryInfoType& boundaryInfo) const
  {
    static_assert(dimRange == 1, "Not implemented for this dimension!");
    static_assert(dimRangeCols == 1, "Not implemented for this dimension!");
    if (polOrder != 1)
      DUNE_THROW(Dune::NotImplemented, "This does not seem to work for higher orders!");
    // check
    assert(gridPart()->indexSet().contains(entity));
    // prepare
    std::set<size_t> localDirichletDofs;
    std::vector<typename BaseFunctionSetType::DomainType> dirichlet_vertices;
    // get all dirichlet vertices of this entity, therefore
    // * loop over all intersections
    const auto intersection_it_end = gridPart()->iend(entity);
    for (auto intersection_it = gridPart()->ibegin(entity); intersection_it != intersection_it_end; ++intersection_it) {
      // only work on dirichlet ones
      const auto& intersection = *intersection_it;
      if (boundaryInfo.dirichlet(intersection)) {
        // and get the vertices of the intersection
        const auto geometry = intersection.geometry();
        for (size_t cc = 0; cc < geometry.corners(); ++cc)
          dirichlet_vertices.emplace_back(entity.geometry().local(geometry.corner(cc)));
      } // only work on dirichlet ones
    } // loop over all intersections

    // find the corresponding basis functions
    const auto basis = baseFunctionSet(entity);
    if (tmp_basis_values_.size() < basis.size())
      tmp_basis_values_.resize(basis.size());
    for (size_t cc = 0; cc < dirichlet_vertices.size(); ++cc) {
      basis.evaluate(dirichlet_vertices[cc], tmp_basis_values_);
      for (size_t jj = 0; jj < basis.size(); ++jj)
        if (Dune::Stuff::Common::FloatCmp::eq(tmp_basis_values_[jj][0], RangeFieldType(1)))
          localDirichletDofs.insert(jj);
    }

    // finish
    return localDirichletDofs;
  } // ... findLocalDirichletDoFs(...)

  template <class ConstraintsType>
  void localConstraints(const EntityType& entity, ConstraintsType& ret) const
  {
    CHECK_AND_CALL_INTERFACE_IMPLEMENTATION(asImp().localConstraints(entity, ret));
    asImp().localConstraints(entity, ret);
  }

  PatternType* computePattern() const
  {
    return computePattern(*this);
  }

  template <class OtherSpaceType>
  PatternType* computePattern(const OtherSpaceType& other) const
  {
    return computePattern(*(gridPart()), other);
  }

  template <class LocalGridPartType, class OtherSpaceType>
  PatternType* computePattern(const LocalGridPartType& localGridPart, const OtherSpaceType& otherSpace) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().computePattern(localGridPart, otherSpace));
    return asImp().computePattern(localGridPart, otherSpace);
  }

  /**
   *  \brief  computes a sparsity pattern, where this space is the test space (rows/outer) and the other space is the
   *          ansatz space (cols/inner)
   */
  template <class LocalGridPartType, class O>
  PatternType* computeCodim0Pattern(const LocalGridPartType& localGridPart, const SpaceInterface<O>& otherSpace) const
  {
    PatternType* ret     = new PatternType(mapper().size());
    PatternType& pattern = *ret;
    // walk the grid part
    for (typename LocalGridPartType::template Codim<0>::IteratorType entityIt = localGridPart.template begin<0>();
         entityIt != localGridPart.template end<0>();
         ++entityIt) {
      const typename LocalGridPartType::template Codim<0>::EntityType& entity = *entityIt;
      // get basefunctionsets
      const auto testBase   = baseFunctionSet(entity);
      const auto ansatzBase = otherSpace.baseFunctionSet(entity);
      Dune::DynamicVector<size_t> globalRows(testBase.size(), 0);
      mapper().globalIndices(entity, globalRows);
      Dune::DynamicVector<size_t> globalCols(ansatzBase.size(), 0);
      otherSpace.mapper().globalIndices(entity, globalCols);
      for (size_t ii = 0; ii < testBase.size(); ++ii) {
        auto& columns = pattern.inner(globalRows[ii]);
        for (size_t jj = 0; jj < ansatzBase.size(); ++jj) {
          columns.insert(globalCols[jj]);
        }
      }
    } // walk the grid part
    return ret;
  } // ... computeVolumePattern(...)

  /**
   *  \brief  computes a DG sparsity pattern, where this space is the test space (rows/outer) and the other space is the
   *          ansatz space (cols/inner)
   */
  template <class LocalGridPartType, class O>
  PatternType* computeCodim0AndCodim1Pattern(const LocalGridPartType& local_grid_part,
                                             const SpaceInterface<O>& other_space) const
  {
    // prepare
    PatternType* ret     = new PatternType(mapper().size());
    PatternType& pattern = *ret;
    Dune::DynamicVector<size_t> global_rows(mapper().maxNumDofs(), 0);
    Dune::DynamicVector<size_t> global_cols(other_space.mapper().maxNumDofs(), 0);
    // walk the grid part
    const auto entity_it_end = local_grid_part.template end<0>();
    for (auto entity_it = local_grid_part.template begin<0>(); entity_it != entity_it_end; ++entity_it) {
      const auto& entity = *entity_it;
      // get basefunctionsets
      const auto test_base_entity   = baseFunctionSet(entity);
      const auto ansatz_base_entity = other_space.baseFunctionSet(entity);
      mapper().globalIndices(entity, global_rows);
      other_space.mapper().globalIndices(entity, global_cols);
      // compute entity/entity
      for (size_t ii = 0; ii < test_base_entity.size(); ++ii) {
        auto& columns = pattern.inner(global_rows[ii]);
        for (size_t jj = 0; jj < ansatz_base_entity.size(); ++jj) {
          columns.insert(global_cols[jj]);
        }
      }
      // walk the intersections
      const auto intersection_it_end = local_grid_part.iend(entity);
      for (auto intersection_it = local_grid_part.ibegin(entity); intersection_it != intersection_it_end;
           ++intersection_it) {
        const auto& intersection = *intersection_it;
        // get the neighbour
        if (intersection.neighbor() && !intersection.boundary()) {
          const auto neighbour_ptr = intersection.outside();
          const auto& neighbour    = *neighbour_ptr;
          // get the basis
          const auto ansatz_base_neighbour = other_space.baseFunctionSet(neighbour);
          other_space.mapper().globalIndices(neighbour, global_cols);
          // compute entity/neighbour
          for (size_t ii = 0; ii < test_base_entity.size(); ++ii) {
            auto& columns = pattern.inner(global_rows[ii]);
            for (size_t jj = 0; jj < ansatz_base_neighbour.size(); ++jj) {
              columns.insert(global_cols[jj]);
            }
          }
        } // get the neighbour
      } // walk the intersections
    } // walk the grid part
    return ret;
  } // ... computeVolumeAndCouplingPattern(...)

  template <class LocalGridPartType, class O>
  PatternType* computeCodim1Pattern(const LocalGridPartType& local_grid_part,
                                    const SpaceInterface<O>& other_space) const
  {
    // prepare
    PatternType* ret     = new PatternType(mapper().size());
    PatternType& pattern = *ret;
    Dune::DynamicVector<size_t> global_rows(mapper().maxNumDofs(), 0);
    Dune::DynamicVector<size_t> global_cols(other_space.mapper().maxNumDofs(), 0);
    // walk the grid part
    const auto entity_it_end = local_grid_part.template end<0>();
    for (auto entity_it = local_grid_part.template begin<0>(); entity_it != entity_it_end; ++entity_it) {
      const auto& entity = *entity_it;
      // get basefunctionsets
      const auto test_base_entity = baseFunctionSet(entity);
      mapper().globalIndices(entity, global_rows);
      // walk the intersections
      const auto intersection_it_end = local_grid_part.iend(entity);
      for (auto intersection_it = local_grid_part.ibegin(entity); intersection_it != intersection_it_end;
           ++intersection_it) {
        const auto& intersection = *intersection_it;
        // get the neighbour
        if (intersection.neighbor() && !intersection.boundary()) {
          const auto neighbour_ptr = intersection.outside();
          const auto& neighbour    = *neighbour_ptr;
          // get the basis
          const auto ansatz_base_neighbour = other_space.baseFunctionSet(neighbour);
          other_space.mapper().globalIndices(neighbour, global_cols);
          // compute entity/neighbour
          for (size_t ii = 0; ii < test_base_entity.size(); ++ii) {
            auto& columns = pattern.inner(global_rows[ii]);
            for (size_t jj = 0; jj < ansatz_base_neighbour.size(); ++jj) {
              columns.insert(global_cols[jj]);
            }
          }
        } // get the neighbour
      } // walk the intersections
    } // walk the grid part
    return ret;
  } // ... computeCodim1Pattern(...)

private:
  class BasisVisualization : public Dune::VTKFunction<typename GridPartType::GridViewType>
  {
    static_assert(dimRangeCols == 1, "Not implemented yet!");

  public:
    typedef typename BaseFunctionSetType::DomainType DomainType;
    typedef typename BaseFunctionSetType::RangeType RangeType;

    BasisVisualization(const derived_type& sp, const size_t ind, const std::string nm = "basis")
      : space_(sp)
      , index_(ind)
      , values_(space_.mapper().maxNumDofs(), RangeType(0))
      , name_(nm)
    {
      if (index_ >= space_.mapper().maxNumDofs())
        DUNE_THROW(Dune::RangeError,
                   "index has to be smaller than " << space_.mapper().maxNumDofs() << "(is " << index_ << ")!");
    }

    virtual std::string name() const
    {
      return name_;
    }

    /** \defgroup vtk ´´Methods to comply with the Dune::VTKFunction interface.'' */
    /* @{ */
    virtual int ncomps() const
    {
      return dimRange;
    }

    virtual double evaluate(int component, const EntityType& entity, const DomainType& xx) const
    {
      const auto baseFunctionSet = space_.baseFunctionSet(entity);
      if (component < 0)
        DUNE_THROW(Dune::RangeError, "component must not be negative (is " << component << ")!");
      if (component < int(baseFunctionSet.size())) {
        baseFunctionSet.evaluate(xx, values_);
        assert(component < int(values_.size()) && "This should not happen!");
        return values_[index_][component];
      } else if (component < int(space_.mapper().maxNumDofs()))
        return 0.0;
      else
        DUNE_THROW(Dune::RangeError,
                   "component has to be smaller than " << space_.mapper().maxNumDofs() << "(is " << component << ")!");
    }
    /* @} */

  private:
    const derived_type& space_;
    const size_t index_;
    mutable std::vector<RangeType> values_;
    const std::string name_;
  }; // class BasisVisualization

public:
  void visualize(const std::string filename_prefix = "") const
  {
    std::string filename = filename_prefix;
    if (filename.empty()) {
      filename = "dune.gdt.space";
    }
    typedef typename Dune::VTKWriter<typename GridPartType::GridViewType> VTKWriterType;
    VTKWriterType vtk_writer(gridPart()->gridView(), Dune::VTK::nonconforming);
    for (size_t ii = 0; ii < mapper().maxNumDofs(); ++ii) {
      std::string number = "";
      if (ii == 1)
        number = "1st";
      else if (ii == 2)
        number = "2nd";
      else if (ii == 3)
        number = "3rd";
      else
        number                     = Stuff::Common::toString(ii) + "th";
      const auto iith_baseFunction = std::make_shared<BasisVisualization>(asImp(), ii, number + " basis");
      vtk_writer.addVertexData(iith_baseFunction);
    }
    vtk_writer.write(filename);
  } // ... visualize(...)

  derived_type& asImp()
  {
    return static_cast<derived_type&>(*this);
  }

  const derived_type& asImp() const
  {
    return static_cast<const derived_type&>(*this);
  }

private:
  mutable std::vector<typename BaseFunctionSetType::RangeType> tmp_basis_values_;
}; // class SpaceInterface

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACE_INTERFACE_HH
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Tobias Leibner

#ifndef DUNE_GDT_SPACES_PARALLEL_HH
#define DUNE_GDT_SPACES_PARALLEL_HH

#include <dune/common/parallel/communicator.hh>

#include <dune/istl/owneroverlapcopy.hh>

#if HAVE_DUNE_PDELAB
#include <dune/pdelab/backend/istl/parallelhelper.hh>
#endif

#include <dune/stuff/la/container/istl.hh>
#include <dune/stuff/common/parallel/helper.hh>

namespace Dune {
namespace GDT {
namespace Spaces {

template <class ViewImp,
          bool is_parallel =
              Dune::Stuff::UseParallelCommunication<typename ViewImp::Grid::CollectiveCommunication>::value>
struct CommunicationChooser
{
  typedef Dune::Stuff::SequentialCommunication Type;

  static Type* create(const ViewImp& /*gridView*/)
  {
    return new Type;
  }

  template <class SpaceBackend>
  static bool prepare(const SpaceBackend& /*space_backend*/, Type& /*communicator*/)
  {
    return false;
  }
}; // struct CommunicationChooser

#if HAVE_MPI

template <class ViewImp>
struct CommunicationChooser<ViewImp, true>
{
  typedef OwnerOverlapCopyCommunication<bigunsignedint<96>, int> Type;

  static Type* create(const ViewImp& gridView)
  {
    return new Type(gridView.comm());
  }

  template <class Space>
  static bool prepare(const Space& space, Type& communicator)
  {
#if HAVE_DUNE_PDELAB
    Stuff::LA::IstlRowMajorSparseMatrix<typename Space::RangeFieldType> matrix;
    PDELab::istl::ParallelHelper<typename Space::BackendType>(space.backend(), 0)
        .createIndexSetAndProjectForAMG(matrix.backend(), communicator);
#endif // HAVE_DUNE_PDELAB
    return true;
  }
}; // struct CommunicationChooser< ..., true >

#endif // HAVE_MPI

} // namespace Spaces
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_PARALLEL_HH
<commit_msg>[spaces.parallel] silence warning<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Tobias Leibner

#ifndef DUNE_GDT_SPACES_PARALLEL_HH
#define DUNE_GDT_SPACES_PARALLEL_HH

#include <dune/common/parallel/communicator.hh>

#include <dune/istl/owneroverlapcopy.hh>

#if HAVE_DUNE_PDELAB
#include <dune/pdelab/backend/istl/parallelhelper.hh>
#endif

#include <dune/stuff/la/container/istl.hh>
#include <dune/stuff/common/parallel/helper.hh>

namespace Dune {
namespace GDT {
namespace Spaces {

template <class ViewImp,
          bool is_parallel =
              Dune::Stuff::UseParallelCommunication<typename ViewImp::Grid::CollectiveCommunication>::value>
struct CommunicationChooser
{
  typedef Dune::Stuff::SequentialCommunication Type;

  static Type* create(const ViewImp& /*gridView*/)
  {
    return new Type;
  }

  template <class SpaceBackend>
  static bool prepare(const SpaceBackend& /*space_backend*/, Type& /*communicator*/)
  {
    return false;
  }
}; // struct CommunicationChooser

#if HAVE_MPI

template <class ViewImp>
struct CommunicationChooser<ViewImp, true>
{
  typedef OwnerOverlapCopyCommunication<bigunsignedint<96>, int> Type;

  static Type* create(const ViewImp& gridView)
  {
    return new Type(gridView.comm());
  }

  template <class Space>
  static bool prepare(const Space&
#if HAVE_DUNE_PDELAB
                          space,
                      Type& communicator)
#else
                      /*space*/,
                      Type& /*communicator*/)
#endif
  {
#if HAVE_DUNE_PDELAB
    Stuff::LA::IstlRowMajorSparseMatrix<typename Space::RangeFieldType> matrix;
    PDELab::istl::ParallelHelper<typename Space::BackendType>(space.backend(), 0)
        .createIndexSetAndProjectForAMG(matrix.backend(), communicator);
#endif // HAVE_DUNE_PDELAB
    return true;
  } // ... prepare(...)
}; // struct CommunicationChooser< ..., true >

#endif // HAVE_MPI

} // namespace Spaces
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_PARALLEL_HH
<|endoftext|>


<commit_before>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef DISTRHO_UI_INTERNAL_HPP_INCLUDED
#define DISTRHO_UI_INTERNAL_HPP_INCLUDED

#include "DistrhoUIPrivateData.hpp"

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------
// Static data, see DistrhoUI.cpp

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
extern uintptr_t   g_nextWindowId;
extern double      g_nextScaleFactor;
extern const char* g_nextBundlePath;
#endif

// -----------------------------------------------------------------------
// UI exporter class

class UIExporter
{
    // -------------------------------------------------------------------
    // UI Widget and its private data

    UI* ui;
    UI::PrivateData* uiData;

    // -------------------------------------------------------------------

public:
    UIExporter(void* const callbacksPtr,
               const uintptr_t winId,
               const double sampleRate,
               const editParamFunc editParamCall,
               const setParamFunc setParamCall,
               const setStateFunc setStateCall,
               const sendNoteFunc sendNoteCall,
               const setSizeFunc setSizeCall,
               const fileRequestFunc fileRequestCall,
               const char* const bundlePath = nullptr,
               void* const dspPtr = nullptr,
               const double scaleFactor = 0.0,
               const uint32_t bgColor = 0,
               const uint32_t fgColor = 0xffffffff)
        : ui(nullptr),
          uiData(new UI::PrivateData())
    {
        uiData->sampleRate = sampleRate;
        uiData->dspPtr = dspPtr;

        uiData->bgColor = bgColor;
        uiData->fgColor = fgColor;
        uiData->scaleFactor = scaleFactor;
        uiData->winId = winId;

        uiData->callbacksPtr            = callbacksPtr;
        uiData->editParamCallbackFunc   = editParamCall;
        uiData->setParamCallbackFunc    = setParamCall;
        uiData->setStateCallbackFunc    = setStateCall;
        uiData->sendNoteCallbackFunc    = sendNoteCall;
        uiData->setSizeCallbackFunc     = setSizeCall;
        uiData->fileRequestCallbackFunc = fileRequestCall;

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
        g_nextWindowId    = winId;
        g_nextScaleFactor = scaleFactor;
        g_nextBundlePath  = bundlePath;
#endif
        UI::PrivateData::s_nextPrivateData = uiData;

        UI* const uiPtr = createUI();

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
        g_nextWindowId    = 0;
        g_nextScaleFactor = 0.0;
        g_nextBundlePath  = nullptr;
#else
        // Leave context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp
        uiData->window->leaveContext();
#endif
        UI::PrivateData::s_nextPrivateData = nullptr;

        DISTRHO_SAFE_ASSERT_RETURN(uiPtr != nullptr,);
        ui = uiPtr;

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
        // unused
        (void)bundlePath;
#endif
    }

    ~UIExporter()
    {
        quit();
        delete ui;
        delete uiData;
    }

    // -------------------------------------------------------------------

    uint getWidth() const noexcept
    {
        return uiData->window->getWidth();
    }

    uint getHeight() const noexcept
    {
        return uiData->window->getHeight();
    }

    double getScaleFactor() const noexcept
    {
        return uiData->window->getScaleFactor();
    }

    bool isVisible() const noexcept
    {
        return uiData->window->isVisible();
    }

    uintptr_t getNativeWindowHandle() const noexcept
    {
        return uiData->window->getNativeWindowHandle();
    }

    uint getBackgroundColor() const noexcept
    {
        DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0);

        return uiData->bgColor;
    }

    uint getForegroundColor() const noexcept
    {
        DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0xffffffff);

        return uiData->fgColor;
    }

    // -------------------------------------------------------------------

    uint32_t getParameterOffset() const noexcept
    {
        DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0);

        return uiData->parameterOffset;
    }

    // -------------------------------------------------------------------

    void parameterChanged(const uint32_t index, const float value)
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->parameterChanged(index, value);
    }

#if DISTRHO_PLUGIN_WANT_PROGRAMS
    void programLoaded(const uint32_t index)
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->programLoaded(index);
    }
#endif

#if DISTRHO_PLUGIN_WANT_STATE
    void stateChanged(const char* const key, const char* const value)
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
        DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
        DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);

        ui->stateChanged(key, value);
    }
#endif

    // -------------------------------------------------------------------

#if DISTRHO_UI_IS_STANDALONE
    void exec(DGL_NAMESPACE::IdleCallback* const cb)
    {
        DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,);

        uiData->window->show();
        uiData->window->focus();
        uiData->app.addIdleCallback(cb);
        uiData->app.exec();
    }

    void exec_idle()
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, );

        ui->uiIdle();
    }
#else
    bool plugin_idle()
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false);

        uiData->app.idle();
        ui->uiIdle();
        return ! uiData->app.isQuitting();
    }
#endif

    void focus()
    {
        uiData->window->focus();
    }

    void quit()
    {
        uiData->window->close();
        uiData->app.quit();
    }

    // -------------------------------------------------------------------

    void setWindowTitle(const char* const uiTitle)
    {
        uiData->window->setTitle(uiTitle);
    }

    void setWindowTransientWinId(const uintptr_t winId)
    {
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
        ui->setTransientWindowId(winId);
#elif 0 /* TODO */
        glWindow.setTransientWinId(winId);
#else
        (void)winId;
#endif
    }

    bool setWindowVisible(const bool yesNo)
    {
        uiData->window->setVisible(yesNo);

        return ! uiData->app.isQuitting();
    }

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    bool handlePluginKeyboard(const bool press, const uint key, const uint16_t mods)
    {
        DGL_NAMESPACE::Widget::KeyboardEvent ev;
        ev.mod   = mods;
        ev.press = press;
        ev.key   = key;

        const bool ret = ui->onKeyboard(ev);

        DGL_NAMESPACE::Widget::CharacterInputEvent cev;
        cev.mod       = mods;
        cev.character = key;

        // if shift modifier is on, convert a-z -> A-Z for character input
        if (key >= 'a' && key <= 'z' && (mods & kModifierShift) != 0)
            cev.character -= 'a' - 'A';

        ui->onCharacterInput(cev);
        return ret;
    }
#endif

    // -------------------------------------------------------------------

    void notifyScaleFactorChanged(const double scaleFactor)
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->uiScaleFactorChanged(scaleFactor);
    }

    void setSampleRate(const double sampleRate, const bool doCallback = false)
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
        DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,);
        DISTRHO_SAFE_ASSERT(sampleRate > 0.0);

        if (d_isEqual(uiData->sampleRate, sampleRate))
            return;

        uiData->sampleRate = sampleRate;

        if (doCallback)
            ui->sampleRateChanged(sampleRate);
    }

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UIExporter)
};

// -----------------------------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // DISTRHO_UI_INTERNAL_HPP_INCLUDED
<commit_msg>Fix no namespace build<commit_after>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef DISTRHO_UI_INTERNAL_HPP_INCLUDED
#define DISTRHO_UI_INTERNAL_HPP_INCLUDED

#include "DistrhoUIPrivateData.hpp"

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------
// Static data, see DistrhoUI.cpp

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
extern uintptr_t   g_nextWindowId;
extern double      g_nextScaleFactor;
extern const char* g_nextBundlePath;
#endif

// -----------------------------------------------------------------------
// UI exporter class

class UIExporter
{
    // -------------------------------------------------------------------
    // UI Widget and its private data

    UI* ui;
    UI::PrivateData* uiData;

    // -------------------------------------------------------------------

public:
    UIExporter(void* const callbacksPtr,
               const uintptr_t winId,
               const double sampleRate,
               const editParamFunc editParamCall,
               const setParamFunc setParamCall,
               const setStateFunc setStateCall,
               const sendNoteFunc sendNoteCall,
               const setSizeFunc setSizeCall,
               const fileRequestFunc fileRequestCall,
               const char* const bundlePath = nullptr,
               void* const dspPtr = nullptr,
               const double scaleFactor = 0.0,
               const uint32_t bgColor = 0,
               const uint32_t fgColor = 0xffffffff)
        : ui(nullptr),
          uiData(new UI::PrivateData())
    {
        uiData->sampleRate = sampleRate;
        uiData->dspPtr = dspPtr;

        uiData->bgColor = bgColor;
        uiData->fgColor = fgColor;
        uiData->scaleFactor = scaleFactor;
        uiData->winId = winId;

        uiData->callbacksPtr            = callbacksPtr;
        uiData->editParamCallbackFunc   = editParamCall;
        uiData->setParamCallbackFunc    = setParamCall;
        uiData->setStateCallbackFunc    = setStateCall;
        uiData->sendNoteCallbackFunc    = sendNoteCall;
        uiData->setSizeCallbackFunc     = setSizeCall;
        uiData->fileRequestCallbackFunc = fileRequestCall;

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
        g_nextWindowId    = winId;
        g_nextScaleFactor = scaleFactor;
        g_nextBundlePath  = bundlePath;
#endif
        UI::PrivateData::s_nextPrivateData = uiData;

        UI* const uiPtr = createUI();

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
        g_nextWindowId    = 0;
        g_nextScaleFactor = 0.0;
        g_nextBundlePath  = nullptr;
#else
        // Leave context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp
        uiData->window->leaveContext();
#endif
        UI::PrivateData::s_nextPrivateData = nullptr;

        DISTRHO_SAFE_ASSERT_RETURN(uiPtr != nullptr,);
        ui = uiPtr;

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
        // unused
        (void)bundlePath;
#endif
    }

    ~UIExporter()
    {
        quit();
        delete ui;
        delete uiData;
    }

    // -------------------------------------------------------------------

    uint getWidth() const noexcept
    {
        return uiData->window->getWidth();
    }

    uint getHeight() const noexcept
    {
        return uiData->window->getHeight();
    }

    double getScaleFactor() const noexcept
    {
        return uiData->window->getScaleFactor();
    }

    bool isVisible() const noexcept
    {
        return uiData->window->isVisible();
    }

    uintptr_t getNativeWindowHandle() const noexcept
    {
        return uiData->window->getNativeWindowHandle();
    }

    uint getBackgroundColor() const noexcept
    {
        DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0);

        return uiData->bgColor;
    }

    uint getForegroundColor() const noexcept
    {
        DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0xffffffff);

        return uiData->fgColor;
    }

    // -------------------------------------------------------------------

    uint32_t getParameterOffset() const noexcept
    {
        DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0);

        return uiData->parameterOffset;
    }

    // -------------------------------------------------------------------

    void parameterChanged(const uint32_t index, const float value)
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->parameterChanged(index, value);
    }

#if DISTRHO_PLUGIN_WANT_PROGRAMS
    void programLoaded(const uint32_t index)
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->programLoaded(index);
    }
#endif

#if DISTRHO_PLUGIN_WANT_STATE
    void stateChanged(const char* const key, const char* const value)
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
        DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
        DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);

        ui->stateChanged(key, value);
    }
#endif

    // -------------------------------------------------------------------

#if DISTRHO_UI_IS_STANDALONE
    void exec(DGL_NAMESPACE::IdleCallback* const cb)
    {
        DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,);

        uiData->window->show();
        uiData->window->focus();
        uiData->app.addIdleCallback(cb);
        uiData->app.exec();
    }

    void exec_idle()
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, );

        ui->uiIdle();
    }
#else
    bool plugin_idle()
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false);

        uiData->app.idle();
        ui->uiIdle();
        return ! uiData->app.isQuitting();
    }
#endif

    void focus()
    {
        uiData->window->focus();
    }

    void quit()
    {
        uiData->window->close();
        uiData->app.quit();
    }

    // -------------------------------------------------------------------

    void setWindowTitle(const char* const uiTitle)
    {
        uiData->window->setTitle(uiTitle);
    }

    void setWindowTransientWinId(const uintptr_t winId)
    {
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
        ui->setTransientWindowId(winId);
#elif 0 /* TODO */
        glWindow.setTransientWinId(winId);
#else
        (void)winId;
#endif
    }

    bool setWindowVisible(const bool yesNo)
    {
        uiData->window->setVisible(yesNo);

        return ! uiData->app.isQuitting();
    }

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    bool handlePluginKeyboard(const bool press, const uint key, const uint16_t mods)
    {
        DGL_NAMESPACE::Widget::KeyboardEvent ev;
        ev.mod   = mods;
        ev.press = press;
        ev.key   = key;

        const bool ret = ui->onKeyboard(ev);

        DGL_NAMESPACE::Widget::CharacterInputEvent cev;
        cev.mod       = mods;
        cev.character = key;

        // if shift modifier is on, convert a-z -> A-Z for character input
        if (key >= 'a' && key <= 'z' && (mods & DGL_NAMESPACE::kModifierShift) != 0)
            cev.character -= 'a' - 'A';

        ui->onCharacterInput(cev);
        return ret;
    }
#endif

    // -------------------------------------------------------------------

    void notifyScaleFactorChanged(const double scaleFactor)
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->uiScaleFactorChanged(scaleFactor);
    }

    void setSampleRate(const double sampleRate, const bool doCallback = false)
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
        DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,);
        DISTRHO_SAFE_ASSERT(sampleRate > 0.0);

        if (d_isEqual(uiData->sampleRate, sampleRate))
            return;

        uiData->sampleRate = sampleRate;

        if (doCallback)
            ui->sampleRateChanged(sampleRate);
    }

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UIExporter)
};

// -----------------------------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // DISTRHO_UI_INTERNAL_HPP_INCLUDED
<|endoftext|>


<commit_before>/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public 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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2004-2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include "avmplus.h"

namespace avmplus
{
    AbcEnv::AbcEnv(PoolObject* _pool,
           CodeContext * _codeContext)
		: m_namedScriptEnvsList(_pool->core->GetGC(), 0)
        , m_pool(_pool)
        , m_domainEnv(_codeContext->domainEnv())
        , m_codeContext(_codeContext)
#ifdef DEBUGGER
        , m_invocationCounts(NULL)
#endif
#ifdef VMCFG_NANOJIT
        , m_core(_pool->core)
#endif
    {
#ifdef DEBUGGER
        if (_pool->core->debugger())
        {
            m_invocationCounts = (uint64_t*)_pool->core->GetGC()->Alloc(_pool->methodCount() * sizeof(uint64_t), MMgc::GC::kZero);
        }
#endif
    }

    AbcEnv::~AbcEnv()
    {
        #ifdef VMCFG_NANOJIT
        // if any AbcEnv goes away, we have to flush the BindingCache entries for all
        // extant pools. Since AvmCore keeps a list of all live pools, we just set a flag
        // in AvmCore that triggers the flush in postsweep(). (Note that we can't rely on our pool
        // being valid here; it might have already been collected!)
        // the avmcore's lifetime is owned by the host and could be deleted so check for that first
        AvmCore *current = MMgc::GC::GetGC(this)->core();
        if(current == m_core)
            m_core->flushBindingCachesNextSweep();
        #endif
    }

}
<commit_msg>remove now-bogus ifdef from AbcEnv.cpp to fix build break on non-jit systems (r=me)<commit_after>/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public 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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2004-2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include "avmplus.h"

namespace avmplus
{
    AbcEnv::AbcEnv(PoolObject* _pool,
           CodeContext * _codeContext)
		: m_namedScriptEnvsList(_pool->core->GetGC(), 0)
        , m_pool(_pool)
        , m_domainEnv(_codeContext->domainEnv())
        , m_codeContext(_codeContext)
#ifdef DEBUGGER
        , m_invocationCounts(NULL)
#endif
        , m_core(_pool->core)
    {
#ifdef DEBUGGER
        if (_pool->core->debugger())
        {
            m_invocationCounts = (uint64_t*)_pool->core->GetGC()->Alloc(_pool->methodCount() * sizeof(uint64_t), MMgc::GC::kZero);
        }
#endif
    }

    AbcEnv::~AbcEnv()
    {
        #ifdef VMCFG_NANOJIT
        // if any AbcEnv goes away, we have to flush the BindingCache entries for all
        // extant pools. Since AvmCore keeps a list of all live pools, we just set a flag
        // in AvmCore that triggers the flush in postsweep(). (Note that we can't rely on our pool
        // being valid here; it might have already been collected!)
        // the avmcore's lifetime is owned by the host and could be deleted so check for that first
        AvmCore *current = MMgc::GC::GetGC(this)->core();
        if(current == m_core)
            m_core->flushBindingCachesNextSweep();
        #endif
    }

}
<|endoftext|>