<commit_before>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#ifndef UAVCAN_NODE_NODE_HPP_INCLUDED
#define UAVCAN_NODE_NODE_HPP_INCLUDED

#include <cassert>
#include <uavcan/error.hpp>
#include <uavcan/build_config.hpp>
#include <uavcan/dynamic_memory.hpp>
#include <uavcan/node/abstract_node.hpp>

// High-level functionality available by default
#include <uavcan/protocol/node_status_provider.hpp>

#if !UAVCAN_TINY
# include <uavcan/protocol/data_type_info_provider.hpp>
# include <uavcan/protocol/logger.hpp>
# include <uavcan/protocol/restart_request_server.hpp>
# include <uavcan/protocol/transport_stats_provider.hpp>
# include <uavcan/protocol/network_compat_checker.hpp>
#endif

#if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11)
# error UAVCAN_CPP_VERSION
#endif

namespace uavcan
{
/**
 * This is the top-level node API.
 * A custom node class can be implemented if needed, in which case it shall inherit INode.
 *
 * @tparam MemPoolSize_     Size of memory pool for this node, in bytes.
 *                          Minimum recommended size is 4K * (number of CAN ifaces + 1).
 *                          For simple nodes this number can be reduced.
 *                          For high-traffic nodes the recommended minimum is
 *                          like 16K * (number of CAN ifaces + 1).
 *
 * @tparam OutgoingTransferRegistryStaticEntries    Number of statically allocated objects
 *                                                  to track Transfer ID for outgoing transfers.
 *                                                  Normally it should be equal to expected number of
 *                                                  publishers and service callers, but it's not necessary.
 *                                                  Additional objects for Transfer ID tracking will
 *                                                  be allocated in the memory pool if needed.
 *                                                  Default value is acceptable for any use case.
 */
template <std::size_t MemPoolSize_,
#if UAVCAN_TINY
          unsigned OutgoingTransferRegistryStaticEntries = 0
#else
          unsigned OutgoingTransferRegistryStaticEntries = 10
#endif
          >
class UAVCAN_EXPORT Node : public INode
{
    enum
    {
        MemPoolSize = (MemPoolSize_ < std::size_t(MemPoolBlockSize)) ? std::size_t(MemPoolBlockSize) : MemPoolSize_
    };

    typedef PoolAllocator<MemPoolSize, MemPoolBlockSize> Allocator;

    Allocator pool_allocator_;
    OutgoingTransferRegistry<OutgoingTransferRegistryStaticEntries> outgoing_trans_reg_;
    Scheduler scheduler_;

    NodeStatusProvider proto_nsp_;
#if !UAVCAN_TINY
    DataTypeInfoProvider proto_dtp_;
    Logger proto_logger_;
    RestartRequestServer proto_rrs_;
    TransportStatsProvider proto_tsp_;
#endif

    uint64_t internal_failure_cnt_;
    bool started_;

protected:
    virtual void registerInternalFailure(const char* msg)
    {
        internal_failure_cnt_++;
        UAVCAN_TRACE("Node", "Internal failure: %s", msg);
#if UAVCAN_TINY
        (void)msg;
#else
        (void)getLogger().log(protocol::debug::LogLevel::ERROR, "UAVCAN", msg);
#endif
    }

public:
    Node(ICanDriver& can_driver, ISystemClock& system_clock)
        : outgoing_trans_reg_(pool_allocator_)
        , scheduler_(can_driver, pool_allocator_, system_clock, outgoing_trans_reg_)
        , proto_nsp_(*this)
#if !UAVCAN_TINY
        , proto_dtp_(*this)
        , proto_logger_(*this)
        , proto_rrs_(*this)
        , proto_tsp_(*this)
#endif
        , internal_failure_cnt_(0)
        , started_(false)
    { }

    virtual Allocator& getAllocator() { return pool_allocator_; }

    virtual Scheduler& getScheduler() { return scheduler_; }
    virtual const Scheduler& getScheduler() const { return scheduler_; }

    int spin(MonotonicTime deadline)
    {
        if (started_)
        {
            return INode::spin(deadline);
        }
        return -ErrNotInited;
    }

    int spin(MonotonicDuration duration)
    {
        if (started_)
        {
            return INode::spin(duration);
        }
        return -ErrNotInited;
    }

    bool isStarted() const { return started_; }

    uint64_t getInternalFailureCount() const { return internal_failure_cnt_; }

    /**
     * Starts the node and publishes uavcan.protocol.NodeStatus immediately.
     * Does not so anything if the node is already started.
     * Once started, the node can't stop.
     * If the node failed to start up, it's recommended to destroy the current node instance and start over.
     * Returns negative error code.
     * @param node_status_transfer_priority Transfer priority that will be used for outgoing NodeStatus messages.
     *                                      Normal priority is used by default.
     */
    int start(const TransferPriority node_status_transfer_priority = TransferPriorityNormal);

#if !UAVCAN_TINY
    /**
     * Please read the specs to learn about Network Compatibility Check.
     * Returns negative error code.
     * @param[out]  result  Check result (output).
     */
    int checkNetworkCompatibility(NetworkCompatibilityCheckResult& result);
#endif

    /**
     * Sets the node name, e.g. "com.example.product_name". The node name can be set only once.
     * Must be executed before the node is started, otherwise the node will refuse to start up.
     */
    void setName(const char* name) { proto_nsp_.setName(name); }

    /**
     * Status code helpers.
     */
    void setStatusOk()           { proto_nsp_.setStatusOk(); }
    void setStatusInitializing() { proto_nsp_.setStatusInitializing(); }
    void setStatusWarning()      { proto_nsp_.setStatusWarning(); }
    void setStatusCritical()     { proto_nsp_.setStatusCritical(); }

    /**
     * Sets the status OFFLINE and publishes it immediately.
     */
    void setStatusOffline()
    {
        proto_nsp_.setStatusOffline();
        (void)proto_nsp_.forcePublish();
    }

    /**
     * Updates the vendor-specific status code.
     */
    void setVendorSpecificStatusCode(NodeStatusProvider::VendorSpecificStatusCode code)
    {
        proto_nsp_.setVendorSpecificStatusCode(code);
    }

    /**
     * Sets the node version information.
     */
    void setSoftwareVersion(const protocol::SoftwareVersion& version) { proto_nsp_.setSoftwareVersion(version); }
    void setHardwareVersion(const protocol::HardwareVersion& version) { proto_nsp_.setHardwareVersion(version); }

    NodeStatusProvider& getNodeStatusProvider() { return proto_nsp_; }

#if !UAVCAN_TINY
    /**
     * Restart handler can be installed to handle external node restart requests (highly recommended).
     */
    void setRestartRequestHandler(IRestartRequestHandler* handler) { proto_rrs_.setHandler(handler); }

    RestartRequestServer& getRestartRequestServer() { return proto_rrs_; }

    /**
     * Node logging.
     * Logging calls are passed directly into the @ref Logger instance.
     * Type safe log formatting is supported only in C++11 mode.
     * @{
     */
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11

    template <typename... Args>
    inline void logDebug(const char* source, const char* format, Args... args)
    {
        (void)proto_logger_.logDebug(source, format, args...);
    }

    template <typename... Args>
    inline void logInfo(const char* source, const char* format, Args... args)
    {
        (void)proto_logger_.logInfo(source, format, args...);
    }

    template <typename... Args>
    inline void logWarning(const char* source, const char* format, Args... args)
    {
        (void)proto_logger_.logWarning(source, format, args...);
    }

    template <typename... Args>
    inline void logError(const char* source, const char* format, Args... args)
    {
        (void)proto_logger_.logError(source, format, args...);
    }

#else

    void logDebug(const char* source, const char* text)   { (void)proto_logger_.logDebug(source, text); }
    void logInfo(const char* source, const char* text)    { (void)proto_logger_.logInfo(source, text); }
    void logWarning(const char* source, const char* text) { (void)proto_logger_.logWarning(source, text); }
    void logError(const char* source, const char* text)   { (void)proto_logger_.logError(source, text); }

#endif
    /**
     * @}
     */

    /**
     * Use this method to configure logging.
     */
    Logger& getLogger() { return proto_logger_; }

#endif  // UAVCAN_TINY
};

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

template <std::size_t MemPoolSize_, unsigned OutgoingTransferRegistryStaticEntries>
int Node<MemPoolSize_, OutgoingTransferRegistryStaticEntries>::start(
    const TransferPriority priority)
{
    if (started_)
    {
        return 0;
    }
    GlobalDataTypeRegistry::instance().freeze();

    int res = 0;
    res = proto_nsp_.startAndPublish(priority);
    if (res < 0)
    {
        goto fail;
    }
#if !UAVCAN_TINY
    res = proto_dtp_.start();
    if (res < 0)
    {
        goto fail;
    }
    res = proto_logger_.init();
    if (res < 0)
    {
        goto fail;
    }
    res = proto_rrs_.start();
    if (res < 0)
    {
        goto fail;
    }
    res = proto_tsp_.start();
    if (res < 0)
    {
        goto fail;
    }
#endif
    started_ = res >= 0;
    return res;
fail:
    UAVCAN_ASSERT(res < 0);
    return res;
}

#if !UAVCAN_TINY

template <std::size_t MemPoolSize_, unsigned OutgoingTransferRegistryStaticEntries>
int Node<MemPoolSize_, OutgoingTransferRegistryStaticEntries>::
checkNetworkCompatibility(NetworkCompatibilityCheckResult& result)
{
    if (!started_)
    {
        return -ErrNotInited;
    }

    int res = NetworkCompatibilityChecker::publishGlobalDiscoveryRequest(*this);
    if (res < 0)
    {
        return res;
    }

    NetworkCompatibilityChecker checker(*this);
    StaticAssert<(sizeof(checker) < 2048)>::check();  // Making sure that the code footprint doesn't explode
    res = checker.execute();
    result = checker.getResult();
    return res;
}

#endif

}

#endif // UAVCAN_NODE_NODE_HPP_INCLUDED
<commit_msg>spinOnce() fix<commit_after>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#ifndef UAVCAN_NODE_NODE_HPP_INCLUDED
#define UAVCAN_NODE_NODE_HPP_INCLUDED

#include <cassert>
#include <uavcan/error.hpp>
#include <uavcan/build_config.hpp>
#include <uavcan/dynamic_memory.hpp>
#include <uavcan/node/abstract_node.hpp>

// High-level functionality available by default
#include <uavcan/protocol/node_status_provider.hpp>

#if !UAVCAN_TINY
# include <uavcan/protocol/data_type_info_provider.hpp>
# include <uavcan/protocol/logger.hpp>
# include <uavcan/protocol/restart_request_server.hpp>
# include <uavcan/protocol/transport_stats_provider.hpp>
# include <uavcan/protocol/network_compat_checker.hpp>
#endif

#if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11)
# error UAVCAN_CPP_VERSION
#endif

namespace uavcan
{
/**
 * This is the top-level node API.
 * A custom node class can be implemented if needed, in which case it shall inherit INode.
 *
 * @tparam MemPoolSize_     Size of memory pool for this node, in bytes.
 *                          Minimum recommended size is 4K * (number of CAN ifaces + 1).
 *                          For simple nodes this number can be reduced.
 *                          For high-traffic nodes the recommended minimum is
 *                          like 16K * (number of CAN ifaces + 1).
 *
 * @tparam OutgoingTransferRegistryStaticEntries    Number of statically allocated objects
 *                                                  to track Transfer ID for outgoing transfers.
 *                                                  Normally it should be equal to expected number of
 *                                                  publishers and service callers, but it's not necessary.
 *                                                  Additional objects for Transfer ID tracking will
 *                                                  be allocated in the memory pool if needed.
 *                                                  Default value is acceptable for any use case.
 */
template <std::size_t MemPoolSize_,
#if UAVCAN_TINY
          unsigned OutgoingTransferRegistryStaticEntries = 0
#else
          unsigned OutgoingTransferRegistryStaticEntries = 10
#endif
          >
class UAVCAN_EXPORT Node : public INode
{
    enum
    {
        MemPoolSize = (MemPoolSize_ < std::size_t(MemPoolBlockSize)) ? std::size_t(MemPoolBlockSize) : MemPoolSize_
    };

    typedef PoolAllocator<MemPoolSize, MemPoolBlockSize> Allocator;

    Allocator pool_allocator_;
    OutgoingTransferRegistry<OutgoingTransferRegistryStaticEntries> outgoing_trans_reg_;
    Scheduler scheduler_;

    NodeStatusProvider proto_nsp_;
#if !UAVCAN_TINY
    DataTypeInfoProvider proto_dtp_;
    Logger proto_logger_;
    RestartRequestServer proto_rrs_;
    TransportStatsProvider proto_tsp_;
#endif

    uint64_t internal_failure_cnt_;
    bool started_;

protected:
    virtual void registerInternalFailure(const char* msg)
    {
        internal_failure_cnt_++;
        UAVCAN_TRACE("Node", "Internal failure: %s", msg);
#if UAVCAN_TINY
        (void)msg;
#else
        (void)getLogger().log(protocol::debug::LogLevel::ERROR, "UAVCAN", msg);
#endif
    }

public:
    Node(ICanDriver& can_driver, ISystemClock& system_clock)
        : outgoing_trans_reg_(pool_allocator_)
        , scheduler_(can_driver, pool_allocator_, system_clock, outgoing_trans_reg_)
        , proto_nsp_(*this)
#if !UAVCAN_TINY
        , proto_dtp_(*this)
        , proto_logger_(*this)
        , proto_rrs_(*this)
        , proto_tsp_(*this)
#endif
        , internal_failure_cnt_(0)
        , started_(false)
    { }

    virtual Allocator& getAllocator() { return pool_allocator_; }

    virtual Scheduler& getScheduler() { return scheduler_; }
    virtual const Scheduler& getScheduler() const { return scheduler_; }

    int spin(MonotonicTime deadline)
    {
        if (started_)
        {
            return INode::spin(deadline);
        }
        return -ErrNotInited;
    }

    int spin(MonotonicDuration duration)
    {
        if (started_)
        {
            return INode::spin(duration);
        }
        return -ErrNotInited;
    }

    int spinOnce()
    {
        if (started_)
        {
            return INode::spinOnce();
        }
        return -ErrNotInited;
    }

    bool isStarted() const { return started_; }

    uint64_t getInternalFailureCount() const { return internal_failure_cnt_; }

    /**
     * Starts the node and publishes uavcan.protocol.NodeStatus immediately.
     * Does not so anything if the node is already started.
     * Once started, the node can't stop.
     * If the node failed to start up, it's recommended to destroy the current node instance and start over.
     * Returns negative error code.
     * @param node_status_transfer_priority Transfer priority that will be used for outgoing NodeStatus messages.
     *                                      Normal priority is used by default.
     */
    int start(const TransferPriority node_status_transfer_priority = TransferPriorityNormal);

#if !UAVCAN_TINY
    /**
     * Please read the specs to learn about Network Compatibility Check.
     * Returns negative error code.
     * @param[out]  result  Check result (output).
     */
    int checkNetworkCompatibility(NetworkCompatibilityCheckResult& result);
#endif

    /**
     * Sets the node name, e.g. "com.example.product_name". The node name can be set only once.
     * Must be executed before the node is started, otherwise the node will refuse to start up.
     */
    void setName(const char* name) { proto_nsp_.setName(name); }

    /**
     * Status code helpers.
     */
    void setStatusOk()           { proto_nsp_.setStatusOk(); }
    void setStatusInitializing() { proto_nsp_.setStatusInitializing(); }
    void setStatusWarning()      { proto_nsp_.setStatusWarning(); }
    void setStatusCritical()     { proto_nsp_.setStatusCritical(); }

    /**
     * Sets the status OFFLINE and publishes it immediately.
     */
    void setStatusOffline()
    {
        proto_nsp_.setStatusOffline();
        (void)proto_nsp_.forcePublish();
    }

    /**
     * Updates the vendor-specific status code.
     */
    void setVendorSpecificStatusCode(NodeStatusProvider::VendorSpecificStatusCode code)
    {
        proto_nsp_.setVendorSpecificStatusCode(code);
    }

    /**
     * Sets the node version information.
     */
    void setSoftwareVersion(const protocol::SoftwareVersion& version) { proto_nsp_.setSoftwareVersion(version); }
    void setHardwareVersion(const protocol::HardwareVersion& version) { proto_nsp_.setHardwareVersion(version); }

    NodeStatusProvider& getNodeStatusProvider() { return proto_nsp_; }

#if !UAVCAN_TINY
    /**
     * Restart handler can be installed to handle external node restart requests (highly recommended).
     */
    void setRestartRequestHandler(IRestartRequestHandler* handler) { proto_rrs_.setHandler(handler); }

    RestartRequestServer& getRestartRequestServer() { return proto_rrs_; }

    /**
     * Node logging.
     * Logging calls are passed directly into the @ref Logger instance.
     * Type safe log formatting is supported only in C++11 mode.
     * @{
     */
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11

    template <typename... Args>
    inline void logDebug(const char* source, const char* format, Args... args)
    {
        (void)proto_logger_.logDebug(source, format, args...);
    }

    template <typename... Args>
    inline void logInfo(const char* source, const char* format, Args... args)
    {
        (void)proto_logger_.logInfo(source, format, args...);
    }

    template <typename... Args>
    inline void logWarning(const char* source, const char* format, Args... args)
    {
        (void)proto_logger_.logWarning(source, format, args...);
    }

    template <typename... Args>
    inline void logError(const char* source, const char* format, Args... args)
    {
        (void)proto_logger_.logError(source, format, args...);
    }

#else

    void logDebug(const char* source, const char* text)   { (void)proto_logger_.logDebug(source, text); }
    void logInfo(const char* source, const char* text)    { (void)proto_logger_.logInfo(source, text); }
    void logWarning(const char* source, const char* text) { (void)proto_logger_.logWarning(source, text); }
    void logError(const char* source, const char* text)   { (void)proto_logger_.logError(source, text); }

#endif
    /**
     * @}
     */

    /**
     * Use this method to configure logging.
     */
    Logger& getLogger() { return proto_logger_; }

#endif  // UAVCAN_TINY
};

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

template <std::size_t MemPoolSize_, unsigned OutgoingTransferRegistryStaticEntries>
int Node<MemPoolSize_, OutgoingTransferRegistryStaticEntries>::start(
    const TransferPriority priority)
{
    if (started_)
    {
        return 0;
    }
    GlobalDataTypeRegistry::instance().freeze();

    int res = 0;
    res = proto_nsp_.startAndPublish(priority);
    if (res < 0)
    {
        goto fail;
    }
#if !UAVCAN_TINY
    res = proto_dtp_.start();
    if (res < 0)
    {
        goto fail;
    }
    res = proto_logger_.init();
    if (res < 0)
    {
        goto fail;
    }
    res = proto_rrs_.start();
    if (res < 0)
    {
        goto fail;
    }
    res = proto_tsp_.start();
    if (res < 0)
    {
        goto fail;
    }
#endif
    started_ = res >= 0;
    return res;
fail:
    UAVCAN_ASSERT(res < 0);
    return res;
}

#if !UAVCAN_TINY

template <std::size_t MemPoolSize_, unsigned OutgoingTransferRegistryStaticEntries>
int Node<MemPoolSize_, OutgoingTransferRegistryStaticEntries>::
checkNetworkCompatibility(NetworkCompatibilityCheckResult& result)
{
    if (!started_)
    {
        return -ErrNotInited;
    }

    int res = NetworkCompatibilityChecker::publishGlobalDiscoveryRequest(*this);
    if (res < 0)
    {
        return res;
    }

    NetworkCompatibilityChecker checker(*this);
    StaticAssert<(sizeof(checker) < 2048)>::check();  // Making sure that the code footprint doesn't explode
    res = checker.execute();
    result = checker.getResult();
    return res;
}

#endif

}

#endif // UAVCAN_NODE_NODE_HPP_INCLUDED
<|endoftext|>


<commit_before>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "core/framework/kernel_registry.h"

#include <algorithm>
#include <memory>
#include <numeric>
#include <unordered_map>

#include "core/framework/kernel_type_str_resolver.h"
#include "core/framework/session_state.h"

namespace onnxruntime {

namespace {
bool IsTypeProtoCompatible(gsl::span<const MLDataType> enabled_types, const ONNX_NAMESPACE::TypeProto& actual_type,
                           std::string& mismatch_reason) {
  const bool is_type_compatible = std::any_of(
      enabled_types.begin(), enabled_types.end(),
      [&actual_type](const DataTypeImpl* expected_type) {
        bool rc = expected_type->IsCompatible(actual_type);  // for easier debugging
        return rc;
      });

  if (!is_type_compatible) {
    std::ostringstream ostr;
    ostr << "This op has been implemented only for the following types (";
    for (const auto& enabled_type : enabled_types) {
      ostr << DataTypeImpl::ToString(enabled_type) << ",";
    }
    ostr << "),";
    const char* actual_type_str = DataTypeImpl::ToString(DataTypeImpl::TypeFromProto(actual_type));
    ostr << " but the node in the model has the following type (" << actual_type_str << ")";
    mismatch_reason = ostr.str();
    return false;
  }

  return true;
}

bool MatchKernelDefTypes(const Node& node,
                         const KernelDef& kernel_def,
                         const IKernelTypeStrResolver& kernel_type_str_resolver,
                         std::string& mismatch_reason) {
  const auto actual_inputs = node.InputDefs();
  const auto actual_outputs = node.OutputDefs();
  const auto& actual_input_arg_counts = node.InputArgCount();
  const auto actual_input_arg_offsets = [&actual_input_arg_counts]() {
    InlinedVector<int> offsets{};
    offsets.reserve(actual_input_arg_counts.size());
    std::exclusive_scan(actual_input_arg_counts.begin(), actual_input_arg_counts.end(),
                        std::back_inserter(offsets), 0);
    return offsets;
  }();

  // for each type constraint
  //   map type constraint to arg
  //   check arg type against type constraint enabled types
  const auto& kernel_type_constraints = kernel_def.EnabledTypeConstraints();
  for (const auto& [kernel_type_str, enabled_types] : kernel_type_constraints) {
    gsl::span<const ArgTypeAndIndex> constraint_args{};
    ORT_THROW_IF_ERROR(kernel_type_str_resolver.ResolveKernelTypeStr(node, kernel_type_str,
                                                                     constraint_args));

    for (const auto& [arg_type, formal_arg_idx] : constraint_args) {
      const NodeArg* arg;
      if (arg_type == ArgType::kInput) {
        if (formal_arg_idx >= actual_input_arg_counts.size() ||
            actual_input_arg_counts[formal_arg_idx] == 0) {
          arg = nullptr;
        } else {
          const auto first_arg_idx = actual_input_arg_offsets[formal_arg_idx];
          ORT_ENFORCE(static_cast<size_t>(first_arg_idx) < actual_inputs.size());
          arg = actual_inputs[first_arg_idx];
        }
      } else {
        arg = formal_arg_idx < actual_outputs.size() ? actual_outputs[formal_arg_idx] : nullptr;
      }

      if (arg && arg->Exists()) {
        const ONNX_NAMESPACE::TypeProto* type_proto = arg->TypeAsProto();
        ORT_ENFORCE(type_proto != nullptr);

        if (!IsTypeProtoCompatible(enabled_types, *type_proto, mismatch_reason)) {
          return false;
        }

        // found a match, don't need to check other args with this constraint
        break;
      }
    }
  }

  return true;
}
}  // namespace

bool KernelRegistry::VerifyKernelDef(const Node& node,
                                     const KernelDef& kernel_def,
                                     const IKernelTypeStrResolver& kernel_type_str_resolver,
                                     std::string& error_str) {
  // check if version matches
  int kernel_start_version;
  int kernel_end_version;
  kernel_def.SinceVersion(&kernel_start_version, &kernel_end_version);

  int node_since_version = node.SinceVersion();
  // Ideal case is, if schema is Since(5), current opset version is opset 7,
  // kernel_def Since(8)     Invalid
  // kernel_def Since(6)     Valid
  // kernel_def Since(5)     Valid
  // kernel_def Since(4)     Invalid
  // kernel_def Since(4, 6)  Valid

  // Right now there is no "until version" on schema, it is difficult to get opset version here.(require a lot of interface change.)
  // As a trade off, we will temporary require kernel definition to have the same since version as schema definition.
  // so kernel_def Since(6) will become invalid now.
  // After ONNX add "until version" on the schema object, we will update this place
  bool valid_version = kernel_start_version == node_since_version  // the idea case this branch should be kernel_start_version >= node_version && kernel_start_version <= until_version
                       || (kernel_start_version < node_since_version && kernel_end_version != INT_MAX && kernel_end_version >= node_since_version);
  if (!valid_version) {
    std::ostringstream ostr;
    ostr << "Op with name (" << node.Name() << ")"
         << " and type (" << node.OpType() << ")"
         << " Version mismatch."
         << " node_version: " << node_since_version
         << " kernel start version: " << kernel_start_version
         << " kernel_end_version: " << kernel_end_version;
    error_str = ostr.str();
    return false;
  }

  if (std::string mismatch_reason;
      !MatchKernelDefTypes(node, kernel_def, kernel_type_str_resolver, mismatch_reason)) {
    std::ostringstream ostr;
    ostr << "Found kernel for Op with name (" << node.Name() << ")"
         << " and type (" << node.OpType() << ")"
         << " in the supported version range"
         << " (node_version: " << node_since_version
         << " kernel start version: " << kernel_start_version
         << " kernel_end_version: " << kernel_end_version << ")."
         << " However the types are incompatible. " << mismatch_reason;
    error_str = ostr.str();
    return false;
  }

  return true;
}

// It's often this function returns a failed status, but it is totally expected.
// It just means this registry doesn't have such a kernel, please search it elsewhere.
// if this function is called before graph partition, then node.provider is not set.
// In this case, the kernel's provider must equal to exec_provider
// otherwise, kernel_def.provider must equal to node.provider. exec_provider is ignored.
Status KernelRegistry::TryFindKernel(const Node& node,
                                     ProviderType exec_provider,
                                     const IKernelTypeStrResolver& kernel_type_str_resolver,
                                     const KernelCreateInfo** out) const {
  const auto& node_provider = node.GetExecutionProviderType();
  const auto& expected_provider = (node_provider.empty() ? exec_provider : node_provider);

  auto range = kernel_creator_fn_map_.equal_range(GetMapKey(node.OpType(), node.Domain(), expected_provider));
  if (out) *out = nullptr;

  std::vector<std::string> verify_kernel_def_error_strs;

  for (auto i = range.first; i != range.second; ++i) {
    std::string error_str;
    if (VerifyKernelDef(node, *i->second.kernel_def, kernel_type_str_resolver, error_str)) {
      if (out) *out = &i->second;
      return Status::OK();
    }
    verify_kernel_def_error_strs.push_back(error_str);
  }

  if (!verify_kernel_def_error_strs.empty()) {
    std::ostringstream oss;
    oss << "Op with name (" << node.Name() << ")"
        << " and type (" << node.OpType() << ")"
        << " kernel is not supported in " << expected_provider << "."
        << " Encountered following errors: (";
    std::copy(verify_kernel_def_error_strs.begin(), verify_kernel_def_error_strs.end(),
              std::ostream_iterator<std::string>(oss, "\n"));
    oss << ")";

    VLOGS_DEFAULT(2) << "TryFindKernel failed, Reason: " << oss.str();
    return Status(common::ONNXRUNTIME, common::FAIL, oss.str());
  }

  return Status(common::ONNXRUNTIME, common::FAIL, "Kernel not found");
}

#if !defined(ORT_MINIMAL_BUILD)
Status KernelRegistry::TryFindKernel(const std::string& op_name, const std::string& domain, const int& version,
                                     const std::unordered_map<std::string, MLDataType>& type_constraints,
                                     ProviderType exec_provider, const KernelCreateInfo** kernel_out) const {
  const KernelCreateInfo* kernel = nullptr;
  auto range = kernel_creator_fn_map_.equal_range(GetMapKey(op_name, domain, exec_provider));
  for (auto i = range.first; i != range.second; ++i) {  // loop through all kernels
    const KernelCreateInfo& kci = i->second;
    int start_ver{};
    int end_ver{};
    kci.kernel_def->SinceVersion(&start_ver, &end_ver);
    if (start_ver <= version && end_ver >= version) {  // try match the version
      auto& kci_constraints = kci.kernel_def->TypeConstraints();
      bool match = true;
      for (auto& constraint : type_constraints) {  // try match type constraints
        auto iter = kci_constraints.find(constraint.first);
        if (iter == kci_constraints.end() || find(iter->second.begin(), iter->second.end(), constraint.second) == iter->second.end()) {
          match = false;
          break;
        }
      }  // for
      if (match) {
        kernel = &kci;  // found match, exit loop
        break;
      }
    }  // if
  }    // for
  if (kernel_out) *kernel_out = kernel;
  return kernel == nullptr ? Status(common::ONNXRUNTIME, common::FAIL, "Kernel not found") : Status::OK();
}
#endif  // !defined(ORT_MINIMAL_BUILD)

Status KernelRegistry::Register(KernelDefBuilder& kernel_builder,
                                const KernelCreateFn& kernel_creator) {
  return Register(KernelCreateInfo(kernel_builder.Build(), kernel_creator));
}

Status KernelRegistry::Register(KernelCreateInfo&& create_info) {
  if (!create_info.kernel_def) {
    return Status(common::ONNXRUNTIME, common::FAIL, "kernel def can't be NULL");
  }
  const std::string key = GetMapKey(*create_info.kernel_def);
  // Check op version conflicts.
  const auto range = kernel_creator_fn_map_.equal_range(key);
  for (auto i = range.first; i != range.second; ++i) {
    if (i->second.kernel_def &&
        i->second.kernel_def->IsConflict(*create_info.kernel_def)) {
      return Status(common::ONNXRUNTIME, common::FAIL,
                    "Failed to add kernel for " + key +
                        ": Conflicting with a registered kernel with op versions.");
    }
  }

  // Register the kernel.
  // Ownership of the KernelDef is transferred to kernel_creator_fn_map_.
  kernel_creator_fn_map_.emplace(key, std::move(create_info));
  return Status::OK();
}

}  // namespace onnxruntime
<commit_msg>Replace std::exclusive_scan() with for loop because std::exclusive_scan() is not implemented in GCC 7. (#13045)<commit_after>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "core/framework/kernel_registry.h"

#include <algorithm>
#include <memory>
#include <numeric>
#include <unordered_map>

#include "core/framework/kernel_type_str_resolver.h"
#include "core/framework/session_state.h"

namespace onnxruntime {

namespace {
bool IsTypeProtoCompatible(gsl::span<const MLDataType> enabled_types, const ONNX_NAMESPACE::TypeProto& actual_type,
                           std::string& mismatch_reason) {
  const bool is_type_compatible = std::any_of(
      enabled_types.begin(), enabled_types.end(),
      [&actual_type](const DataTypeImpl* expected_type) {
        bool rc = expected_type->IsCompatible(actual_type);  // for easier debugging
        return rc;
      });

  if (!is_type_compatible) {
    std::ostringstream ostr;
    ostr << "This op has been implemented only for the following types (";
    for (const auto& enabled_type : enabled_types) {
      ostr << DataTypeImpl::ToString(enabled_type) << ",";
    }
    ostr << "),";
    const char* actual_type_str = DataTypeImpl::ToString(DataTypeImpl::TypeFromProto(actual_type));
    ostr << " but the node in the model has the following type (" << actual_type_str << ")";
    mismatch_reason = ostr.str();
    return false;
  }

  return true;
}

bool MatchKernelDefTypes(const Node& node,
                         const KernelDef& kernel_def,
                         const IKernelTypeStrResolver& kernel_type_str_resolver,
                         std::string& mismatch_reason) {
  const auto actual_inputs = node.InputDefs();
  const auto actual_outputs = node.OutputDefs();
  const auto& actual_input_arg_counts = node.InputArgCount();
  const auto actual_input_arg_offsets = [&actual_input_arg_counts]() {
    InlinedVector<int> offsets{};
    offsets.reserve(actual_input_arg_counts.size());
    // std::exclusive_scan() is not supported until GCC 9.3
    // std::exclusive_scan(actual_input_arg_counts.begin(), actual_input_arg_counts.end(),
    //                     std::back_inserter(offsets), 0);
    int current_offset = 0;
    for (size_t i = 0; i < actual_input_arg_counts.size(); ++i) {
      offsets.push_back(current_offset);
      current_offset += actual_input_arg_counts[i];
    }
    return offsets;
  }();

  // for each type constraint
  //   map type constraint to arg
  //   check arg type against type constraint enabled types
  const auto& kernel_type_constraints = kernel_def.EnabledTypeConstraints();
  for (const auto& [kernel_type_str, enabled_types] : kernel_type_constraints) {
    gsl::span<const ArgTypeAndIndex> constraint_args{};
    ORT_THROW_IF_ERROR(kernel_type_str_resolver.ResolveKernelTypeStr(node, kernel_type_str,
                                                                     constraint_args));

    for (const auto& [arg_type, formal_arg_idx] : constraint_args) {
      const NodeArg* arg;
      if (arg_type == ArgType::kInput) {
        if (formal_arg_idx >= actual_input_arg_counts.size() ||
            actual_input_arg_counts[formal_arg_idx] == 0) {
          arg = nullptr;
        } else {
          const auto first_arg_idx = actual_input_arg_offsets[formal_arg_idx];
          ORT_ENFORCE(static_cast<size_t>(first_arg_idx) < actual_inputs.size());
          arg = actual_inputs[first_arg_idx];
        }
      } else {
        arg = formal_arg_idx < actual_outputs.size() ? actual_outputs[formal_arg_idx] : nullptr;
      }

      if (arg && arg->Exists()) {
        const ONNX_NAMESPACE::TypeProto* type_proto = arg->TypeAsProto();
        ORT_ENFORCE(type_proto != nullptr);

        if (!IsTypeProtoCompatible(enabled_types, *type_proto, mismatch_reason)) {
          return false;
        }

        // found a match, don't need to check other args with this constraint
        break;
      }
    }
  }

  return true;
}
}  // namespace

bool KernelRegistry::VerifyKernelDef(const Node& node,
                                     const KernelDef& kernel_def,
                                     const IKernelTypeStrResolver& kernel_type_str_resolver,
                                     std::string& error_str) {
  // check if version matches
  int kernel_start_version;
  int kernel_end_version;
  kernel_def.SinceVersion(&kernel_start_version, &kernel_end_version);

  int node_since_version = node.SinceVersion();
  // Ideal case is, if schema is Since(5), current opset version is opset 7,
  // kernel_def Since(8)     Invalid
  // kernel_def Since(6)     Valid
  // kernel_def Since(5)     Valid
  // kernel_def Since(4)     Invalid
  // kernel_def Since(4, 6)  Valid

  // Right now there is no "until version" on schema, it is difficult to get opset version here.(require a lot of interface change.)
  // As a trade off, we will temporary require kernel definition to have the same since version as schema definition.
  // so kernel_def Since(6) will become invalid now.
  // After ONNX add "until version" on the schema object, we will update this place
  bool valid_version = kernel_start_version == node_since_version  // the idea case this branch should be kernel_start_version >= node_version && kernel_start_version <= until_version
                       || (kernel_start_version < node_since_version && kernel_end_version != INT_MAX && kernel_end_version >= node_since_version);
  if (!valid_version) {
    std::ostringstream ostr;
    ostr << "Op with name (" << node.Name() << ")"
         << " and type (" << node.OpType() << ")"
         << " Version mismatch."
         << " node_version: " << node_since_version
         << " kernel start version: " << kernel_start_version
         << " kernel_end_version: " << kernel_end_version;
    error_str = ostr.str();
    return false;
  }

  if (std::string mismatch_reason;
      !MatchKernelDefTypes(node, kernel_def, kernel_type_str_resolver, mismatch_reason)) {
    std::ostringstream ostr;
    ostr << "Found kernel for Op with name (" << node.Name() << ")"
         << " and type (" << node.OpType() << ")"
         << " in the supported version range"
         << " (node_version: " << node_since_version
         << " kernel start version: " << kernel_start_version
         << " kernel_end_version: " << kernel_end_version << ")."
         << " However the types are incompatible. " << mismatch_reason;
    error_str = ostr.str();
    return false;
  }

  return true;
}

// It's often this function returns a failed status, but it is totally expected.
// It just means this registry doesn't have such a kernel, please search it elsewhere.
// if this function is called before graph partition, then node.provider is not set.
// In this case, the kernel's provider must equal to exec_provider
// otherwise, kernel_def.provider must equal to node.provider. exec_provider is ignored.
Status KernelRegistry::TryFindKernel(const Node& node,
                                     ProviderType exec_provider,
                                     const IKernelTypeStrResolver& kernel_type_str_resolver,
                                     const KernelCreateInfo** out) const {
  const auto& node_provider = node.GetExecutionProviderType();
  const auto& expected_provider = (node_provider.empty() ? exec_provider : node_provider);

  auto range = kernel_creator_fn_map_.equal_range(GetMapKey(node.OpType(), node.Domain(), expected_provider));
  if (out) *out = nullptr;

  std::vector<std::string> verify_kernel_def_error_strs;

  for (auto i = range.first; i != range.second; ++i) {
    std::string error_str;
    if (VerifyKernelDef(node, *i->second.kernel_def, kernel_type_str_resolver, error_str)) {
      if (out) *out = &i->second;
      return Status::OK();
    }
    verify_kernel_def_error_strs.push_back(error_str);
  }

  if (!verify_kernel_def_error_strs.empty()) {
    std::ostringstream oss;
    oss << "Op with name (" << node.Name() << ")"
        << " and type (" << node.OpType() << ")"
        << " kernel is not supported in " << expected_provider << "."
        << " Encountered following errors: (";
    std::copy(verify_kernel_def_error_strs.begin(), verify_kernel_def_error_strs.end(),
              std::ostream_iterator<std::string>(oss, "\n"));
    oss << ")";

    VLOGS_DEFAULT(2) << "TryFindKernel failed, Reason: " << oss.str();
    return Status(common::ONNXRUNTIME, common::FAIL, oss.str());
  }

  return Status(common::ONNXRUNTIME, common::FAIL, "Kernel not found");
}

#if !defined(ORT_MINIMAL_BUILD)
Status KernelRegistry::TryFindKernel(const std::string& op_name, const std::string& domain, const int& version,
                                     const std::unordered_map<std::string, MLDataType>& type_constraints,
                                     ProviderType exec_provider, const KernelCreateInfo** kernel_out) const {
  const KernelCreateInfo* kernel = nullptr;
  auto range = kernel_creator_fn_map_.equal_range(GetMapKey(op_name, domain, exec_provider));
  for (auto i = range.first; i != range.second; ++i) {  // loop through all kernels
    const KernelCreateInfo& kci = i->second;
    int start_ver{};
    int end_ver{};
    kci.kernel_def->SinceVersion(&start_ver, &end_ver);
    if (start_ver <= version && end_ver >= version) {  // try match the version
      auto& kci_constraints = kci.kernel_def->TypeConstraints();
      bool match = true;
      for (auto& constraint : type_constraints) {  // try match type constraints
        auto iter = kci_constraints.find(constraint.first);
        if (iter == kci_constraints.end() || find(iter->second.begin(), iter->second.end(), constraint.second) == iter->second.end()) {
          match = false;
          break;
        }
      }  // for
      if (match) {
        kernel = &kci;  // found match, exit loop
        break;
      }
    }  // if
  }    // for
  if (kernel_out) *kernel_out = kernel;
  return kernel == nullptr ? Status(common::ONNXRUNTIME, common::FAIL, "Kernel not found") : Status::OK();
}
#endif  // !defined(ORT_MINIMAL_BUILD)

Status KernelRegistry::Register(KernelDefBuilder& kernel_builder,
                                const KernelCreateFn& kernel_creator) {
  return Register(KernelCreateInfo(kernel_builder.Build(), kernel_creator));
}

Status KernelRegistry::Register(KernelCreateInfo&& create_info) {
  if (!create_info.kernel_def) {
    return Status(common::ONNXRUNTIME, common::FAIL, "kernel def can't be NULL");
  }
  const std::string key = GetMapKey(*create_info.kernel_def);
  // Check op version conflicts.
  const auto range = kernel_creator_fn_map_.equal_range(key);
  for (auto i = range.first; i != range.second; ++i) {
    if (i->second.kernel_def &&
        i->second.kernel_def->IsConflict(*create_info.kernel_def)) {
      return Status(common::ONNXRUNTIME, common::FAIL,
                    "Failed to add kernel for " + key +
                        ": Conflicting with a registered kernel with op versions.");
    }
  }

  // Register the kernel.
  // Ownership of the KernelDef is transferred to kernel_creator_fn_map_.
  kernel_creator_fn_map_.emplace(key, std::move(create_info));
  return Status::OK();
}

}  // namespace onnxruntime
<|endoftext|>


<commit_before>/*
 * Copyright © 2013 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "brw_fs.h"
#include "brw_cfg.h"

/** @file brw_fs_peephole_predicated_break.cpp
 *
 * Loops are often structured as
 *
 * loop:
 *    CMP.f0
 *    (+f0) IF
 *    BREAK
 *    ENDIF
 *    ...
 *    WHILE loop
 *
 * This peephole pass removes the IF and ENDIF instructions and predicates the
 * BREAK, dropping two instructions from the loop body.
 *
 * If the loop was a DO { ... } WHILE loop, it looks like
 *
 * loop:
 *    ...
 *    CMP.f0
 *    (+f0) IF
 *    BREAK
 *    ENDIF
 *    WHILE loop
 *
 * and we can remove the BREAK instruction and predicate the WHILE.
 */

bool
fs_visitor::opt_peephole_predicated_break()
{
   bool progress = false;

   foreach_block (block, cfg) {
      if (block->start_ip != block->end_ip)
         continue;

      /* BREAK and CONTINUE instructions, by definition, can only be found at
       * the ends of basic blocks.
       */
      fs_inst *jump_inst = (fs_inst *)block->end();
      if (jump_inst->opcode != BRW_OPCODE_BREAK &&
          jump_inst->opcode != BRW_OPCODE_CONTINUE)
         continue;

      fs_inst *if_inst = (fs_inst *)block->prev()->end();
      if (if_inst->opcode != BRW_OPCODE_IF)
         continue;

      fs_inst *endif_inst = (fs_inst *)block->next()->start();
      if (endif_inst->opcode != BRW_OPCODE_ENDIF)
         continue;

      bblock_t *jump_block = block;
      bblock_t *if_block = jump_block->prev();
      bblock_t *endif_block = jump_block->next();

      /* For Sandybridge with IF with embedded comparison we need to emit an
       * instruction to set the flag register.
       */
      if (devinfo->gen == 6 && if_inst->conditional_mod) {
         bld.at(if_block, if_inst)
            .CMP(bld.null_reg_d(), if_inst->src[0], if_inst->src[1],
                 if_inst->conditional_mod);
         jump_inst->predicate = BRW_PREDICATE_NORMAL;
      } else {
         jump_inst->predicate = if_inst->predicate;
         jump_inst->predicate_inverse = if_inst->predicate_inverse;
      }

      bblock_t *earlier_block = if_block;
      if (if_block->start_ip == if_block->end_ip) {
         earlier_block = if_block->prev();
      }

      if_inst->remove(if_block);

      bblock_t *later_block = endif_block;
      if (endif_block->start_ip == endif_block->end_ip) {
         later_block = endif_block->next();
      }
      endif_inst->remove(endif_block);

      if (!earlier_block->ends_with_control_flow()) {
         earlier_block->children.make_empty();
         earlier_block->add_successor(cfg->mem_ctx, jump_block);
      }

      if (!later_block->starts_with_control_flow()) {
         later_block->parents.make_empty();
      }
      jump_block->add_successor(cfg->mem_ctx, later_block);

      if (earlier_block->can_combine_with(jump_block)) {
         earlier_block->combine_with(jump_block);

         block = earlier_block;
      }

      /* Now look at the first instruction of the block following the BREAK. If
       * it's a WHILE, we can delete the break, predicate the WHILE, and join
       * the two basic blocks.
       */
      bblock_t *while_block = earlier_block->next();
      fs_inst *while_inst = (fs_inst *)while_block->start();

      if (jump_inst->opcode == BRW_OPCODE_BREAK &&
          while_inst->opcode == BRW_OPCODE_WHILE &&
          while_inst->predicate == BRW_PREDICATE_NONE) {
         jump_inst->remove(earlier_block);
         while_inst->predicate = jump_inst->predicate;
         while_inst->predicate_inverse = !jump_inst->predicate_inverse;

         earlier_block->children.make_empty();
         earlier_block->add_successor(cfg->mem_ctx, while_block);

         assert(earlier_block->can_combine_with(while_block));
         earlier_block->combine_with(while_block);

         earlier_block->next()->parents.make_empty();
         earlier_block->add_successor(cfg->mem_ctx, earlier_block->next());
      }

      progress = true;
   }

   if (progress)
      invalidate_live_intervals();

   return progress;
}
<commit_msg>i965/fs: Initialize a builder explicitly in opt_peephole_predicated_break().<commit_after>/*
 * Copyright © 2013 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "brw_fs.h"
#include "brw_cfg.h"

using namespace brw;

/** @file brw_fs_peephole_predicated_break.cpp
 *
 * Loops are often structured as
 *
 * loop:
 *    CMP.f0
 *    (+f0) IF
 *    BREAK
 *    ENDIF
 *    ...
 *    WHILE loop
 *
 * This peephole pass removes the IF and ENDIF instructions and predicates the
 * BREAK, dropping two instructions from the loop body.
 *
 * If the loop was a DO { ... } WHILE loop, it looks like
 *
 * loop:
 *    ...
 *    CMP.f0
 *    (+f0) IF
 *    BREAK
 *    ENDIF
 *    WHILE loop
 *
 * and we can remove the BREAK instruction and predicate the WHILE.
 */

bool
fs_visitor::opt_peephole_predicated_break()
{
   bool progress = false;

   foreach_block (block, cfg) {
      if (block->start_ip != block->end_ip)
         continue;

      /* BREAK and CONTINUE instructions, by definition, can only be found at
       * the ends of basic blocks.
       */
      fs_inst *jump_inst = (fs_inst *)block->end();
      if (jump_inst->opcode != BRW_OPCODE_BREAK &&
          jump_inst->opcode != BRW_OPCODE_CONTINUE)
         continue;

      fs_inst *if_inst = (fs_inst *)block->prev()->end();
      if (if_inst->opcode != BRW_OPCODE_IF)
         continue;

      fs_inst *endif_inst = (fs_inst *)block->next()->start();
      if (endif_inst->opcode != BRW_OPCODE_ENDIF)
         continue;

      bblock_t *jump_block = block;
      bblock_t *if_block = jump_block->prev();
      bblock_t *endif_block = jump_block->next();

      /* For Sandybridge with IF with embedded comparison we need to emit an
       * instruction to set the flag register.
       */
      if (devinfo->gen == 6 && if_inst->conditional_mod) {
         const fs_builder ibld(this, if_block, if_inst);
         ibld.CMP(ibld.null_reg_d(), if_inst->src[0], if_inst->src[1],
                  if_inst->conditional_mod);
         jump_inst->predicate = BRW_PREDICATE_NORMAL;
      } else {
         jump_inst->predicate = if_inst->predicate;
         jump_inst->predicate_inverse = if_inst->predicate_inverse;
      }

      bblock_t *earlier_block = if_block;
      if (if_block->start_ip == if_block->end_ip) {
         earlier_block = if_block->prev();
      }

      if_inst->remove(if_block);

      bblock_t *later_block = endif_block;
      if (endif_block->start_ip == endif_block->end_ip) {
         later_block = endif_block->next();
      }
      endif_inst->remove(endif_block);

      if (!earlier_block->ends_with_control_flow()) {
         earlier_block->children.make_empty();
         earlier_block->add_successor(cfg->mem_ctx, jump_block);
      }

      if (!later_block->starts_with_control_flow()) {
         later_block->parents.make_empty();
      }
      jump_block->add_successor(cfg->mem_ctx, later_block);

      if (earlier_block->can_combine_with(jump_block)) {
         earlier_block->combine_with(jump_block);

         block = earlier_block;
      }

      /* Now look at the first instruction of the block following the BREAK. If
       * it's a WHILE, we can delete the break, predicate the WHILE, and join
       * the two basic blocks.
       */
      bblock_t *while_block = earlier_block->next();
      fs_inst *while_inst = (fs_inst *)while_block->start();

      if (jump_inst->opcode == BRW_OPCODE_BREAK &&
          while_inst->opcode == BRW_OPCODE_WHILE &&
          while_inst->predicate == BRW_PREDICATE_NONE) {
         jump_inst->remove(earlier_block);
         while_inst->predicate = jump_inst->predicate;
         while_inst->predicate_inverse = !jump_inst->predicate_inverse;

         earlier_block->children.make_empty();
         earlier_block->add_successor(cfg->mem_ctx, while_block);

         assert(earlier_block->can_combine_with(while_block));
         earlier_block->combine_with(while_block);

         earlier_block->next()->parents.make_empty();
         earlier_block->add_successor(cfg->mem_ctx, earlier_block->next());
      }

      progress = true;
   }

   if (progress)
      invalidate_live_intervals();

   return progress;
}
<|endoftext|>


<commit_before>/*!
 *  \file       mco-core_Envelope.hpp
 *  \author     Francois Best
 *  \date       21/10/2013
 *  \license    GPL v3.0 - Copyright Forty Seven Effects 2013
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

BEGIN_MCO_CORE_NAMESPACE

inline DecayEnvelope::DecayEnvelope()
{
}

inline DecayEnvelope::~DecayEnvelope()
{
}

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

inline void DecayEnvelope::init()
{
}

inline void DecayEnvelope::process(Sample& outSample)
{
    if (mProcessing)
    {
        if (updatePhase())
        {
            // Phase overflow: reached the end of decay time.
            mProcessing = false;
            return;
        }

        const Sample sampleLin = processLinear();
        const Sample sampleExp = processExponential();

        // Blend
        outSample = interpol_s(sampleExp, sampleLin, mLinearity);
    }
}

inline void DecayEnvelope::trigger()
{
    mProcessing = true;
    mPhase = 0;
    resetTickCounter();
}

inline void DecayEnvelope::setDuration(TimeFactor inDuration)
{
    mPhaseIncrement = 0xffff - inDuration;
}

inline void DecayEnvelope::setLinearity(LinearityAmount inAmount)
{
    mLinearity = inAmount;
}

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

inline bool DecayEnvelope::isActive() const
{
    return mProcessing;
}

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

inline bool DecayEnvelope::updatePhase()
{
    TickCount ticks = 0;
    fetchTickCounter(ticks);
    const uint32 increment = ticks * mPhaseIncrement;
    if (increment > uint32(0xffff - mPhase))
    {
        // Increment will overflow
        mPhase = 0;
        return true;
    }

    mPhase += increment;
    return false;
}

inline DecayEnvelope::Sample DecayEnvelope::processLinear() const
{
    return sUModSampleMax - mPhase;
}

inline DecayEnvelope::Sample DecayEnvelope::processExponential() const
{
    const uint7 index = (mPhase >> 9);          // index range: [0 ; 127]
    const uint7 alpha = (mPhase >> 2) & 0x7f;   // alpha range: [0 ; 127]
    const uint16 expA = LookupTables::getExpDischarge(index + 1);
    const uint16 expB = LookupTables::getExpDischarge(index);
    return interpol_u(expA, expB, alpha);
}

// ########################################################################## //

inline AdsrEnvelope::AdsrEnvelope()
{
}

inline AdsrEnvelope::~AdsrEnvelope()
{
}

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

inline void AdsrEnvelope::init()
{
    mCore.init();
    setAttack(0);
    setDecay(0);
    setSustain(sUModSampleMax);
    setRelease(0);
}

inline void AdsrEnvelope::process(Sample& outSample)
{
    switch (mState)
    {
        case attack:
        case decay:
        case release:
            if (!mCore.isActive())
                changeState();
            break;
    }

    switch (mState)
    {
        default:
        case idle:
            break;

        case attack:    processAttack(outSample);   break;
        case decay:     processDecay(outSample);    break;
        case sustain:   processSustain(outSample);  break;
        case release:   processRelease(outSample);  break;
    }
}

inline void AdsrEnvelope::tick()
{
    mCore.tick();
}

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

inline void AdsrEnvelope::gateOn()
{
    mState = idle;
    changeState();
}

inline void AdsrEnvelope::gateOff()
{
    mState = sustain;
    changeState();
}

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

inline void AdsrEnvelope::setAttack(TimeFactor inAttack)
{
    mAttackTime = inAttack;
    if (mState == attack)
    {
        mCore.setDuration(mAttackTime);
    }
}

inline void AdsrEnvelope::setDecay(TimeFactor inDecay)
{
    mDecayTime = inDecay;
    if (mState == decay)
    {
        mCore.setDuration(mDecayTime);
    }
}

inline void AdsrEnvelope::setSustain(Sample inLevel)
{
    mSustainLevel = inLevel;
}

inline void AdsrEnvelope::setRelease(TimeFactor inRelease)
{
    mReleaseTime = inRelease;
    if (mState == release)
    {
        mCore.setDuration(mReleaseTime);
    }
}

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

inline void AdsrEnvelope::changeState()
{
    switch (mState)
    {
        case idle:
        {
            mState = attack;
            if (mAttackTime == 0)
            {
                // go directly to decay
                changeState();
            }
            else
            {
                mCore.setDuration(mAttackTime);
                mCore.trigger();
            }
            break;
        }

        case attack:
        {
            mState = decay;
            if (mDecayTime == 0)
            {
                // go directly to sustain
                changeState();
            }
            else
            {
                mCore.setDuration(mDecayTime);
                mCore.trigger();
            }
            break;
        }

        case decay:
        {
            if (mSustainLevel == 0)
            {
                mState = idle;
            }
            else
            {
                mState = sustain;
            }
            break;
        }

        case sustain:
        {
            mState = release;
            if (mReleaseTime == 0)
            {
                // go directly to idle
                changeState();
            }
            else
            {
                mCore.setDuration(mReleaseTime);
                mCore.trigger();
            }
            break;
        }

        case release: // go to idle
        {
            mState = idle;
            break;
        }

        default:
            mState = idle;
            break;
    }
}

inline void AdsrEnvelope::processAttack(Sample& outSample)
{
    Sample sample = 0;
    mCore.process(sample);
    outSample = sUModSampleMax - sample;
}

inline void AdsrEnvelope::processDecay(Sample& outSample)
{
    Sample sample = 0;
    mCore.process(sample);

    const uint32 scale = sUModSampleMax - mSustainLevel;
    const Sample scaledSample = scale * uint32(sample) >> 16;
    outSample = mSustainLevel + scaledSample;
}

inline void AdsrEnvelope::processSustain(Sample& outSample)
{
    outSample = mSustainLevel;
}

inline void AdsrEnvelope::processRelease(Sample& outSample)
{
    Sample sample = 0;
    mCore.process(sample);

    const uint32 scale = sUModSampleMax - mSustainLevel;
    const Sample scaledSample = scale * uint32(sample) >> 16;
    outSample = mSustainLevel + scaledSample;
}

END_MCO_CORE_NAMESPACE
<commit_msg>Moved phase update after process to at least process the first sample.<commit_after>/*!
 *  \file       mco-core_Envelope.hpp
 *  \author     Francois Best
 *  \date       21/10/2013
 *  \license    GPL v3.0 - Copyright Forty Seven Effects 2013
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

BEGIN_MCO_CORE_NAMESPACE

inline DecayEnvelope::DecayEnvelope()
{
}

inline DecayEnvelope::~DecayEnvelope()
{
}

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

inline void DecayEnvelope::init()
{
}

inline void DecayEnvelope::process(Sample& outSample)
{
    if (mProcessing)
    {
        const Sample sampleLin = processLinear();
        const Sample sampleExp = processExponential();

        // Blend
        outSample = interpol_s(sampleExp, sampleLin, mLinearity);

        if (updatePhase())
        {
            // Phase overflow: reached the end of decay time.
            mProcessing = false;
        }
    }
}

inline void DecayEnvelope::trigger()
{
    mProcessing = true;
    mPhase = 0;
    resetTickCounter();
}

inline void DecayEnvelope::setDuration(TimeFactor inDuration)
{
    mPhaseIncrement = 0xffff - inDuration;
}

inline void DecayEnvelope::setLinearity(LinearityAmount inAmount)
{
    mLinearity = inAmount;
}

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

inline bool DecayEnvelope::isActive() const
{
    return mProcessing;
}

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

inline bool DecayEnvelope::updatePhase()
{
    TickCount ticks = 0;
    fetchTickCounter(ticks);
    const uint32 increment = ticks * mPhaseIncrement;
    if (increment > uint32(0xffff - mPhase))
    {
        // Increment will overflow
        mPhase = 0;
        return true;
    }

    mPhase += increment;
    return false;
}

inline DecayEnvelope::Sample DecayEnvelope::processLinear() const
{
    return sUModSampleMax - mPhase;
}

inline DecayEnvelope::Sample DecayEnvelope::processExponential() const
{
    const uint7 index = (mPhase >> 9);          // index range: [0 ; 127]
    const uint7 alpha = (mPhase >> 2) & 0x7f;   // alpha range: [0 ; 127]
    const uint16 expA = LookupTables::getExpDischarge(index + 1);
    const uint16 expB = LookupTables::getExpDischarge(index);
    return interpol_u(expA, expB, alpha);
}

// ########################################################################## //

inline AdsrEnvelope::AdsrEnvelope()
{
}

inline AdsrEnvelope::~AdsrEnvelope()
{
}

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

inline void AdsrEnvelope::init()
{
    mCore.init();
    setAttack(0);
    setDecay(0);
    setSustain(sUModSampleMax);
    setRelease(0);
}

inline void AdsrEnvelope::process(Sample& outSample)
{
    switch (mState)
    {
        case attack:
        case decay:
        case release:
            if (!mCore.isActive())
                changeState();
            break;
    }

    switch (mState)
    {
        default:
        case idle:
            break;

        case attack:    processAttack(outSample);   break;
        case decay:     processDecay(outSample);    break;
        case sustain:   processSustain(outSample);  break;
        case release:   processRelease(outSample);  break;
    }
}

inline void AdsrEnvelope::tick()
{
    mCore.tick();
}

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

inline void AdsrEnvelope::gateOn()
{
    mState = idle;
    changeState();
}

inline void AdsrEnvelope::gateOff()
{
    mState = sustain;
    changeState();
}

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

inline void AdsrEnvelope::setAttack(TimeFactor inAttack)
{
    mAttackTime = inAttack;
    if (mState == attack)
    {
        mCore.setDuration(mAttackTime);
    }
}

inline void AdsrEnvelope::setDecay(TimeFactor inDecay)
{
    mDecayTime = inDecay;
    if (mState == decay)
    {
        mCore.setDuration(mDecayTime);
    }
}

inline void AdsrEnvelope::setSustain(Sample inLevel)
{
    mSustainLevel = inLevel;
}

inline void AdsrEnvelope::setRelease(TimeFactor inRelease)
{
    mReleaseTime = inRelease;
    if (mState == release)
    {
        mCore.setDuration(mReleaseTime);
    }
}

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

inline void AdsrEnvelope::changeState()
{
    switch (mState)
    {
        case idle:
        {
            mState = attack;
            if (mAttackTime == 0)
            {
                // go directly to decay
                changeState();
            }
            else
            {
                mCore.setDuration(mAttackTime);
                mCore.trigger();
            }
            break;
        }

        case attack:
        {
            mState = decay;
            if (mDecayTime == 0)
            {
                // go directly to sustain
                changeState();
            }
            else
            {
                mCore.setDuration(mDecayTime);
                mCore.trigger();
            }
            break;
        }

        case decay:
        {
            if (mSustainLevel == 0)
            {
                mState = idle;
            }
            else
            {
                mState = sustain;
            }
            break;
        }

        case sustain:
        {
            mState = release;
            if (mReleaseTime == 0)
            {
                // go directly to idle
                changeState();
            }
            else
            {
                mCore.setDuration(mReleaseTime);
                mCore.trigger();
            }
            break;
        }

        case release: // go to idle
        {
            mState = idle;
            break;
        }

        default:
            mState = idle;
            break;
    }
}

inline void AdsrEnvelope::processAttack(Sample& outSample)
{
    Sample sample = 0;
    mCore.process(sample);
    outSample = sUModSampleMax - sample;
}

inline void AdsrEnvelope::processDecay(Sample& outSample)
{
    Sample sample = 0;
    mCore.process(sample);

    const uint32 scale = sUModSampleMax - mSustainLevel;
    const Sample scaledSample = scale * uint32(sample) >> 16;
    outSample = mSustainLevel + scaledSample;
}

inline void AdsrEnvelope::processSustain(Sample& outSample)
{
    outSample = mSustainLevel;
}

inline void AdsrEnvelope::processRelease(Sample& outSample)
{
    Sample sample = 0;
    mCore.process(sample);

    const uint32 scale = sUModSampleMax - mSustainLevel;
    const Sample scaledSample = scale * uint32(sample) >> 16;
    outSample = mSustainLevel + scaledSample;
}

END_MCO_CORE_NAMESPACE
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2015 - 2017)
//   Rene Milk       (2016 - 2018)
//   Tim Keil        (2017)

#ifndef DUNE_GDT_FUNCTIONALS_VECTOR_BASED_HH
#define DUNE_GDT_FUNCTIONALS_VECTOR_BASED_HH

#include <dune/xt/common/memory.hh>
#include <dune/xt/la/container/vector-interface.hh>
#include <dune/xt/grid/functors/interfaces.hh>
#include <dune/xt/grid/walker.hh>
#include <dune/xt/grid/walker/filters.hh>
#include <dune/xt/grid/type_traits.hh>

#include <dune/gdt/exceptions.hh>
#include <dune/gdt/local/assembler/functional-assemblers.hh>
#include <dune/gdt/local/functionals/interfaces.hh>

#include "interfaces.hh"

namespace Dune {
namespace GDT {

/**
 * \brief Base class for linear functionals which are given by an assembled vector.
 *
 * \note See FunctionalInterface for a description of the template arguments.
 *
 * \sa FunctionalInterface
 * \sa VectorBasedFunctional
 */
template <class V, class GV, size_t r = 1, size_t rC = 1, class F = double>
class ConstVectorBasedFunctional : public FunctionalInterface<V, GV, r, rC, F>
{
  // All other types are checked elsewhere.
  static_assert(XT::LA::is_vector<V>::value, "");

  using ThisType = ConstVectorBasedFunctional<V, GV, r, rC, F>;
  using FunctionalBaseType = FunctionalInterface<V, GV, r, rC, F>;

public:
  using DofFieldType = typename V::ScalarType;

  using typename FunctionalBaseType::SourceSpaceType;
  using typename FunctionalBaseType::SourceVectorType;
  using typename FunctionalBaseType::SourceType;
  using typename FunctionalBaseType::FieldType;

  ConstVectorBasedFunctional(const SourceSpaceType& source_spc, const SourceVectorType& vec)
    : source_space_(source_spc)
    , vector_(vec)
  {
    if (vector_.size() != source_space_.mapper().size())
      DUNE_THROW(XT::Common::Exceptions::shapes_do_not_match,
                 "vector_.size() = " << vector_.size() << "\n"
                                     << "source_space_.mapper().size() = "
                                     << source_space_.mapper().size());
  }

  ConstVectorBasedFunctional(const ThisType&) = default;
  ConstVectorBasedFunctional(ThisType&&) = default;

  bool linear() const override
  {
    return true;
  }

  const SourceSpaceType& source_space() const override
  {
    return source_space_;
  }

  const SourceVectorType& vector() const
  {
    return vector_;
  }

  FieldType apply(const SourceType& source) const override
  {
    try {
      return vector_.dot(source.dofs().vector());
    } catch (const XT::Common::Exceptions::shapes_do_not_match& ee) {
      DUNE_THROW(Exceptions::functional_error,
                 "when applying vector to source dofs!\n\nThis was the original error: " << ee.what());
    }
  } // ... apply(...)

private:
  const SourceSpaceType& source_space_;
  const SourceVectorType& vector_;
}; // class ConstVectorBasedFunctional

template <class GV, size_t r, size_t rC, class F, class V>
ConstVectorBasedFunctional<typename XT::LA::VectorInterface<V>::derived_type, GV, r, rC, F>
make_vector_functional(const SpaceInterface<GV, r, rC, F>& space, const XT::LA::VectorInterface<V>& vector)
{
  return ConstVectorBasedFunctional<typename XT::LA::VectorInterface<V>::derived_type, GV, r, rC, F>(space,
                                                                                vector.as_imp());
}

/**
 * \brief Base class for linear functionals which are assembled into a vector.
 *
 * Similar to the GlobalAssembler, we derive from the XT::Grid::Walker and povide custom append() methods to allow to
 * add local element and intersection functionals. In contrast to the GlobalAssembler we already hold the target vector
 * (or create one of appropriate size), into which we want to assemble. The functional is assembled by walking over the
 * given assembly_gid_view (which defaults to the one fom the given space). This allows to assemble a functional only on
 * a smaller grid view than the one given from the space (similar functionality could be acchieved by appending this
 * functional to another walker and by providing an appropriate filter).
 *
 * \note One could achieve similar functionality by deriving from GlobalAssembler directly, which would slightly
 *       simplify the implementation of the append methods. However, we do not want to expose the other append methods
 *       of GlobalAssembler here (it should not be possible to append a local opeator or two-form to a functional), but
 *       want to expose the ones from the XT::Grid::Walker (it should be possible to append other element or
 *       intersection functors).
 *
 * \note For convenience, we use the same type of vector to assemble this functional into, that we use to model the
 *       source (see the documentation in FunctionalInterface), although other choices are in general conceivable.
 *
 * \note See ConstVectorBasedFunctional and FunctionalInterface for a description of the template arguments.
 *
 * \sa ConstVectorBasedFunctional
 * \sa FunctionalInterface
 * \sa XT::Grid::Walker
 * \sa GlobalAssembler
 */
template <class V, class GV, size_t r = 1, size_t rC = 1, class F = double, class AssemblyGridView = GV>
class VectorBasedFunctional : XT::Common::StorageProvider<V>,
                              public ConstVectorBasedFunctional<V, GV, r, rC, F>,
                              public XT::Grid::Walker<AssemblyGridView>
{
  // All other types are checked elsewhere.
  static_assert(std::is_same<XT::Grid::extract_entity_t<GV>, XT::Grid::extract_entity_t<AssemblyGridView>>::value,
                "We cannot handle different element types!");

  using ThisType = VectorBasedFunctional<V, GV, r, rC, F, AssemblyGridView>;
  using VectorStorage = XT::Common::StorageProvider<V>;
  using FunctionalBaseType = ConstVectorBasedFunctional<V, GV, r, rC, F>;
  using WalkerBaseType = XT::Grid::Walker<AssemblyGridView>;

public:
  using AssemblyGridViewType = AssemblyGridView;
  using DofFieldType = typename V::ScalarType;

  using typename FunctionalBaseType::SourceSpaceType;
  using typename FunctionalBaseType::SourceVectorType;
  using typename FunctionalBaseType::SourceType;
  using typename FunctionalBaseType::FieldType;

  using typename WalkerBaseType::ElementType;
  using ElementFilterType = XT::Grid::ElementFilter<AssemblyGridViewType>;
  using IntersectionFilterType = XT::Grid::IntersectionFilter<AssemblyGridViewType>;
  using ApplyOnAllElements = XT::Grid::ApplyOn::AllElements<AssemblyGridViewType>;
  using ApplyOnAllIntersection = XT::Grid::ApplyOn::AllIntersections<AssemblyGridViewType>;

  /**
   * \name Ctors which accept an existing vector into which to assemble.
   * \{
   */

  VectorBasedFunctional(AssemblyGridViewType assembly_grid_view,
                        const SourceSpaceType& source_spc,
                        SourceVectorType& vec)
    : VectorStorage(vec)
    , FunctionalBaseType(source_spc, VectorStorage::access())
    , WalkerBaseType(assembly_grid_view)
    , assembled_(false)
  {
    // to detect assembly
    this->append([&](const auto&) { assembled_ = true; });
  }

  /**
   * \}
   * \name Ctors which create an appropriate vector into which to assemble (which is accessible via vector()).
   * \{
   */

  VectorBasedFunctional(AssemblyGridViewType assembly_grid_view, const SourceSpaceType& source_spc)
    : VectorStorage(new SourceVectorType(source_spc.mapper().size(), 0))
    , FunctionalBaseType(source_spc, VectorStorage::access())
    , WalkerBaseType(assembly_grid_view)
    , assembled_(false)
  {
    // to detect assembly
    this->append([&](const auto&) { assembled_ = true; });
  }

  /// \}

  VectorBasedFunctional(const ThisType&) = default;
  VectorBasedFunctional(ThisType&&) = default;

  using FunctionalBaseType::vector;

  SourceVectorType& vector()
  {
    return VectorStorage::access();
  }

  using WalkerBaseType::append;

  ThisType& append(const LocalElementFunctionalInterface<ElementType, r, rC, F, DofFieldType>& local_functional,
                   const XT::Common::Parameter& param = {},
                   const ElementFilterType& filter = ApplyOnAllElements())
  {
    LocalElementFunctionalAssembler<V, AssemblyGridViewType, r, rC, F, GV> tmp(
        this->source_space(), local_functional, VectorStorage::access(), param);
    this->append(tmp, filter);
    return *this;
  }

  ThisType& append(const LocalElementFunctionalInterface<ElementType, r, rC, F, DofFieldType>& local_functional,
                   const XT::Common::Parameter& param,
                   std::function<bool(const AssemblyGridViewType&, const ElementType&)> filter_lambda)
  {
    return append(
        local_functional, param, XT::Grid::ApplyOn::LambdaFilteredElements<AssemblyGridViewType>(filter_lambda));
  }

  // similar append for LocalIntersectionFunctionalInterface ...

  void assemble(const bool use_tbb = false) override final
  {
    if (assembled_)
      return;
    // This clears all appended functionals, which is ok, since we are done after assembling once!
    this->walk(use_tbb);
    assembled_ = true;
  }

  FieldType apply(const SourceType& source) const override final
  {
    DUNE_THROW_IF(!assembled_,
                  Exceptions::functional_error,
                  "You have to call assemble() first, or append this "
                  "functional to an existing XT::Grid::Walker or "
                  "GlobalAssembler!");
    return FunctionalBaseType::apply(source);
  } // ... apply(...)

private:
  bool assembled_;
}; // class VectorBasedFunctional

template <class GV, size_t r, size_t rC, class F, class V>
VectorBasedFunctional<typename XT::LA::VectorInterface<V>::derived_type, GV, r, rC, F>
make_vector_functional(const SpaceInterface<GV, r, rC, F>& space, XT::LA::VectorInterface<V>& vector)
{
  return VectorBasedFunctional<typename XT::LA::VectorInterface<V>::derived_type, GV, r, rC, F>(space, vector.as_imp());
}

template <class VectorType, class GV, size_t r, size_t rC, class F>
typename std::enable_if<XT::LA::is_vector<VectorType>::value, VectorBasedFunctional<VectorType, GV, r, rC, F>>::type
make_vector_functional(const SpaceInterface<GV, r, rC, F>& space)
{
  return VectorBasedFunctional<VectorType, GV, r, rC, F>(space);
}

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_FUNCTIONALS_VECTOR_BASED_HH
<commit_msg>[functionals.vector-based] add factory methods<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2015 - 2017)
//   Rene Milk       (2016 - 2018)
//   Tim Keil        (2017)

#ifndef DUNE_GDT_FUNCTIONALS_VECTOR_BASED_HH
#define DUNE_GDT_FUNCTIONALS_VECTOR_BASED_HH

#include <dune/xt/common/memory.hh>
#include <dune/xt/la/container/vector-interface.hh>
#include <dune/xt/grid/functors/interfaces.hh>
#include <dune/xt/grid/walker.hh>
#include <dune/xt/grid/walker/filters.hh>
#include <dune/xt/grid/type_traits.hh>

#include <dune/gdt/exceptions.hh>
#include <dune/gdt/local/assembler/functional-assemblers.hh>
#include <dune/gdt/local/functionals/interfaces.hh>

#include "interfaces.hh"

namespace Dune {
namespace GDT {

/**
 * \brief Base class for linear functionals which are given by an assembled vector.
 *
 * \note See FunctionalInterface for a description of the template arguments.
 *
 * \sa FunctionalInterface
 * \sa VectorBasedFunctional
 */
template <class V, class GV, size_t r = 1, size_t rC = 1, class F = double>
class ConstVectorBasedFunctional : public FunctionalInterface<V, GV, r, rC, F>
{
  // All other types are checked elsewhere.
  static_assert(XT::LA::is_vector<V>::value, "");

  using ThisType = ConstVectorBasedFunctional<V, GV, r, rC, F>;
  using FunctionalBaseType = FunctionalInterface<V, GV, r, rC, F>;

public:
  using DofFieldType = typename V::ScalarType;

  using typename FunctionalBaseType::SourceSpaceType;
  using typename FunctionalBaseType::SourceVectorType;
  using typename FunctionalBaseType::SourceType;
  using typename FunctionalBaseType::FieldType;

  ConstVectorBasedFunctional(const SourceSpaceType& source_spc, const SourceVectorType& vec)
    : source_space_(source_spc)
    , vector_(vec)
  {
    if (vector_.size() != source_space_.mapper().size())
      DUNE_THROW(XT::Common::Exceptions::shapes_do_not_match,
                 "vector_.size() = " << vector_.size() << "\n"
                                     << "source_space_.mapper().size() = "
                                     << source_space_.mapper().size());
  }

  ConstVectorBasedFunctional(const ThisType&) = default;
  ConstVectorBasedFunctional(ThisType&&) = default;

  bool linear() const override
  {
    return true;
  }

  const SourceSpaceType& source_space() const override
  {
    return source_space_;
  }

  const SourceVectorType& vector() const
  {
    return vector_;
  }

  FieldType apply(const SourceType& source) const override
  {
    try {
      return vector_.dot(source.dofs().vector());
    } catch (const XT::Common::Exceptions::shapes_do_not_match& ee) {
      DUNE_THROW(Exceptions::functional_error,
                 "when applying vector to source dofs!\n\nThis was the original error: " << ee.what());
    }
  } // ... apply(...)

private:
  const SourceSpaceType& source_space_;
  const SourceVectorType& vector_;
}; // class ConstVectorBasedFunctional

template <class GV, size_t r, size_t rC, class F, class V>
ConstVectorBasedFunctional<typename XT::LA::VectorInterface<V>::derived_type, GV, r, rC, F>
make_vector_functional(const SpaceInterface<GV, r, rC, F>& space, const XT::LA::VectorInterface<V>& vector)
{
  return ConstVectorBasedFunctional<typename XT::LA::VectorInterface<V>::derived_type, GV, r, rC, F>(space,
                                                                                vector.as_imp());
}

/**
 * \brief Base class for linear functionals which are assembled into a vector.
 *
 * Similar to the GlobalAssembler, we derive from the XT::Grid::Walker and povide custom append() methods to allow to
 * add local element and intersection functionals. In contrast to the GlobalAssembler we already hold the target vector
 * (or create one of appropriate size), into which we want to assemble. The functional is assembled by walking over the
 * given assembly_gid_view (which defaults to the one fom the given space). This allows to assemble a functional only on
 * a smaller grid view than the one given from the space (similar functionality could be acchieved by appending this
 * functional to another walker and by providing an appropriate filter).
 *
 * \note One could achieve similar functionality by deriving from GlobalAssembler directly, which would slightly
 *       simplify the implementation of the append methods. However, we do not want to expose the other append methods
 *       of GlobalAssembler here (it should not be possible to append a local opeator or two-form to a functional), but
 *       want to expose the ones from the XT::Grid::Walker (it should be possible to append other element or
 *       intersection functors).
 *
 * \note For convenience, we use the same type of vector to assemble this functional into, that we use to model the
 *       source (see the documentation in FunctionalInterface), although other choices are in general conceivable.
 *
 * \note See ConstVectorBasedFunctional and FunctionalInterface for a description of the template arguments.
 *
 * \sa ConstVectorBasedFunctional
 * \sa FunctionalInterface
 * \sa XT::Grid::Walker
 * \sa GlobalAssembler
 */
template <class V, class GV, size_t r = 1, size_t rC = 1, class F = double, class AssemblyGridView = GV>
class VectorBasedFunctional : XT::Common::StorageProvider<V>,
                              public ConstVectorBasedFunctional<V, GV, r, rC, F>,
                              public XT::Grid::Walker<AssemblyGridView>
{
  // All other types are checked elsewhere.
  static_assert(std::is_same<XT::Grid::extract_entity_t<GV>, XT::Grid::extract_entity_t<AssemblyGridView>>::value,
                "We cannot handle different element types!");

  using ThisType = VectorBasedFunctional<V, GV, r, rC, F, AssemblyGridView>;
  using VectorStorage = XT::Common::StorageProvider<V>;
  using FunctionalBaseType = ConstVectorBasedFunctional<V, GV, r, rC, F>;
  using WalkerBaseType = XT::Grid::Walker<AssemblyGridView>;

public:
  using AssemblyGridViewType = AssemblyGridView;
  using DofFieldType = typename V::ScalarType;

  using typename FunctionalBaseType::SourceSpaceType;
  using typename FunctionalBaseType::SourceVectorType;
  using typename FunctionalBaseType::SourceType;
  using typename FunctionalBaseType::FieldType;

  using typename WalkerBaseType::ElementType;
  using ElementFilterType = XT::Grid::ElementFilter<AssemblyGridViewType>;
  using IntersectionFilterType = XT::Grid::IntersectionFilter<AssemblyGridViewType>;
  using ApplyOnAllElements = XT::Grid::ApplyOn::AllElements<AssemblyGridViewType>;
  using ApplyOnAllIntersection = XT::Grid::ApplyOn::AllIntersections<AssemblyGridViewType>;

  /**
   * \name Ctors which accept an existing vector into which to assemble.
   * \{
   */

  VectorBasedFunctional(AssemblyGridViewType assembly_grid_view,
                        const SourceSpaceType& source_spc,
                        SourceVectorType& vec)
    : VectorStorage(vec)
    , FunctionalBaseType(source_spc, VectorStorage::access())
    , WalkerBaseType(assembly_grid_view)
    , assembled_(false)
  {
    // to detect assembly
    this->append([&](const auto&) { assembled_ = true; });
  }

  /**
   * \}
   * \name Ctors which create an appropriate vector into which to assemble (which is accessible via vector()).
   * \{
   */

  VectorBasedFunctional(AssemblyGridViewType assembly_grid_view, const SourceSpaceType& source_spc)
    : VectorStorage(new SourceVectorType(source_spc.mapper().size(), 0))
    , FunctionalBaseType(source_spc, VectorStorage::access())
    , WalkerBaseType(assembly_grid_view)
    , assembled_(false)
  {
    // to detect assembly
    this->append([&](const auto&) { assembled_ = true; });
  }

  /// \}

  VectorBasedFunctional(const ThisType&) = default;
  VectorBasedFunctional(ThisType&&) = default;

  using FunctionalBaseType::vector;

  SourceVectorType& vector()
  {
    return VectorStorage::access();
  }

  using WalkerBaseType::append;

  ThisType& append(const LocalElementFunctionalInterface<ElementType, r, rC, F, DofFieldType>& local_functional,
                   const XT::Common::Parameter& param = {},
                   const ElementFilterType& filter = ApplyOnAllElements())
  {
    LocalElementFunctionalAssembler<V, AssemblyGridViewType, r, rC, F, GV> tmp(
        this->source_space(), local_functional, VectorStorage::access(), param);
    this->append(tmp, filter);
    return *this;
  }

  ThisType& append(const LocalElementFunctionalInterface<ElementType, r, rC, F, DofFieldType>& local_functional,
                   const XT::Common::Parameter& param,
                   std::function<bool(const AssemblyGridViewType&, const ElementType&)> filter_lambda)
  {
    return append(
        local_functional, param, XT::Grid::ApplyOn::LambdaFilteredElements<AssemblyGridViewType>(filter_lambda));
  }

  // similar append for LocalIntersectionFunctionalInterface ...

  void assemble(const bool use_tbb = false) override final
  {
    if (assembled_)
      return;
    // This clears all appended functionals, which is ok, since we are done after assembling once!
    this->walk(use_tbb);
    assembled_ = true;
  }

  FieldType apply(const SourceType& source) const override final
  {
    DUNE_THROW_IF(!assembled_,
                  Exceptions::functional_error,
                  "You have to call assemble() first, or append this "
                  "functional to an existing XT::Grid::Walker or "
                  "GlobalAssembler!");
    return FunctionalBaseType::apply(source);
  } // ... apply(...)

private:
  bool assembled_;
}; // class VectorBasedFunctional

template <class GV, size_t r, size_t rC, class F, class V>
VectorBasedFunctional<typename XT::LA::VectorInterface<V>::derived_type, GV, r, rC, F>
make_vector_functional(const SpaceInterface<GV, r, rC, F>& space, XT::LA::VectorInterface<V>& vector)
{
  return VectorBasedFunctional<typename XT::LA::VectorInterface<V>::derived_type, GV, r, rC, F>(
      space.grid_view(), space, vector.as_imp());
}

template <class VectorType, class GV, size_t r, size_t rC, class F>
typename std::enable_if<XT::LA::is_vector<VectorType>::value, VectorBasedFunctional<VectorType, GV, r, rC, F>>::type
make_vector_functional(const SpaceInterface<GV, r, rC, F>& space)
{
  return VectorBasedFunctional<VectorType, GV, r, rC, F>(space.grid_view(), space);
}

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_FUNCTIONALS_VECTOR_BASED_HH
<|endoftext|>


<commit_before>#include <glm/glm.hpp>
#include <iostream>
#include "animation.hpp"

namespace mo {

Animation::Animation(std::map<unsigned int, std::shared_ptr<Mesh>> keyframes) :
    keyframes_(keyframes.begin(), keyframes.end()),
    mesh_(keyframes_.begin()->second),
    time_(0.0f) {
}

Animation::Animation(std::initializer_list<std::pair<unsigned int, std::shared_ptr<Mesh>>> keyframes):
keyframes_(keyframes.begin(), keyframes.end()),
mesh_(keyframes_.begin()->second),
time_(0.0f) {
}

Animation::~Animation() {
}

void Animation::update(const float dt) {
    time_ += dt;
    auto key_it = keyframes_.lower_bound((unsigned int)time_);
    auto key2_it = keyframes_.upper_bound((unsigned int)time_);

    std::cout << key_it->first << std::endl;
    std::cout << time_ << std::endl;
    std::cout << key2_it->first << std::endl << "---" << std::endl;
    auto k_it = key_it->second->vertices_begin();
    for (auto v_it = mesh_->vertices_begin(); v_it != mesh_->vertices_end(); v_it++) {
        *v_it = *k_it;
        k_it++;
    }
    mesh_->valid = false;
}

}

<commit_msg>Animation checkpoint.<commit_after>#include <glm/glm.hpp>
#include <iostream>
#include "animation.hpp"

namespace mo {

Animation::Animation(std::map<unsigned int, std::shared_ptr<Mesh>> keyframes) :
    keyframes_(keyframes.begin(), keyframes.end()),
    mesh_(std::make_shared<mo::Mesh>(*keyframes_.begin()->second)),
    time_(0.0f) {
}

Animation::Animation(std::initializer_list<std::pair<unsigned int, std::shared_ptr<Mesh>>> keyframes):
keyframes_(keyframes.begin(), keyframes.end()),
mesh_(std::make_shared<mo::Mesh>(*keyframes_.begin()->second)),
time_(0.0f) {
}

Animation::~Animation() {
}

void Animation::update(const float dt) {
    time_ += dt;
    auto key_it = keyframes_.upper_bound((unsigned int)time_);

    auto key1 = keyframes_[1];
    auto key2 = keyframes_[5];

    auto key1_it = key1->vertices_begin();
    auto key2_it = key2->vertices_begin();
    for (auto vertex_it = mesh_->vertices_begin(); vertex_it != mesh_->vertices_end(); vertex_it++) {
        //*vertex_it = *key2_it;
        vertex_it->position = glm::mix(key1_it->position, key2_it->position, time_ / 10.0f);

        key1_it++;
        key2_it++;
    }

    /*
    auto k_it = key_it->second->vertices_begin();
    for (auto v_it = mesh_->vertices_begin(); v_it != mesh_->vertices_end(); v_it++) {
        *v_it = *k_it;
        k_it++;
    }
    */
    mesh_->valid = false;
}

std::shared_ptr<Mesh> Animation::mesh() {
    return mesh_;
}

}

<|endoftext|>


<commit_before>#include "packet.h"

#include <string.h>
#include <iostream>
#include <cstdlib>

  //Constructor
  Packet::Packet () {
	sequenceNum = 0;
	checkSum = 0;
	ackNack = 0;
        dataBuff[121];
  }
  Packet::Packet (int sn, const char db[121]){
    sequenceNum = sn % 32;
    strcpy(dataBuff, db);
    checkSum = generateCheckSum();
    ackNack =0;
  }
  //Setter Methods
  void Packet::setSequenceNum(int sn){
     sequenceNum = sn;
  }

  void Packet::setCheckSum(int cs){
     checkSum = cs;
  }

  void Packet::setAckNack(int an){
     ackNack = an;
  }

  void Packet::loadDataBuffer(char* data){
    //Jakes load buffer code goes here
    strcpy(dataBuff, data);
  }
  char* Packet::getDataBuffer() {
    return dataBuff;
  }
  //Attach header to the data array
  char* Packet::str(){
    std::string tempStr(dataBuff);
    std::string packetString;
    std::string csStr;
	std::string sns;

    csStr = std::to_string((long long int)checkSum);
    while(csStr.length() < 5) csStr += '0';

	sns = std::to_string((long long int)sequenceNum);
	std::cout << "changed" << std::endl;
	if(sns.length() < 2) sns.insert(0, 1, '0');

    packetString = sns + csStr + std::to_string((long long int)ackNack) + tempStr;
    strcpy(packet, packetString.c_str());
    return packet;
  }
  //Getter Methods
  int Packet::getSequenceNum(){
    return sequenceNum;
  }

  int Packet::getCheckSum(){
    return checkSum;
  }

  int Packet::getAckNack(){
    return ackNack;
  }
  bool Packet::chksm() {
    return (checkSum) == generateCheckSum();
  }
  int Packet::generateCheckSum() {
    int cs = 0;
    if(dataBuff == NULL){
      return -1;
    }

    for(int x = 0; x < sizeof(dataBuff); x++) {
      if(dataBuff[x] == '\0') {
        x = sizeof(dataBuff);
        break;
      }
      cs += dataBuff[x];
    }

    if(cs <= 9999) cs *= 10;

    if(cs > 0) return cs;
    return -1;
  }
<commit_msg>Test a different strategy<commit_after>#include "packet.h"

#include <string.h>
#include <iostream>
#include <cstdlib>

  //Constructor
  Packet::Packet () {
	sequenceNum = 0;
	checkSum = 0;
	ackNack = 0;
        dataBuff[121];
  }
  Packet::Packet (int sn, const char db[121]){
    sequenceNum = sn % 32;
    strcpy(dataBuff, db);
    checkSum = generateCheckSum();
    ackNack =0;
  }
  //Setter Methods
  void Packet::setSequenceNum(int sn){
     sequenceNum = sn;
  }

  void Packet::setCheckSum(int cs){
     checkSum = cs;
  }

  void Packet::setAckNack(int an){
     ackNack = an;
  }

  void Packet::loadDataBuffer(char* data){
    //Jakes load buffer code goes here
    strcpy(dataBuff, data);
  }
  char* Packet::getDataBuffer() {
    return dataBuff;
  }
  //Attach header to the data array
  char* Packet::str(){
    std::string tempStr(dataBuff);
    std::string packetString;
    std::string csStr;
	std::string sns;

    csStr = std::to_string((long long int)checkSum);
    while(csStr.length() < 5) csStr += '0';

	sns = std::to_string((long long int)sequenceNum);
	std::cout << "sns length: " << sns.length() << std::endl;
	if(sns.length() < 2) sns = '0' + sns;

    packetString = sns + csStr + std::to_string((long long int)ackNack) + tempStr;
    strcpy(packet, packetString.c_str());
    return packet;
  }
  //Getter Methods
  int Packet::getSequenceNum(){
    return sequenceNum;
  }

  int Packet::getCheckSum(){
    return checkSum;
  }

  int Packet::getAckNack(){
    return ackNack;
  }
  bool Packet::chksm() {
    return (checkSum) == generateCheckSum();
  }
  int Packet::generateCheckSum() {
    int cs = 0;
    if(dataBuff == NULL){
      return -1;
    }

    for(int x = 0; x < sizeof(dataBuff); x++) {
      if(dataBuff[x] == '\0') {
        x = sizeof(dataBuff);
        break;
      }
      cs += dataBuff[x];
    }

    if(cs <= 9999) cs *= 10;

    if(cs > 0) return cs;
    return -1;
  }
<|endoftext|>