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

#pragma once

#include <memory>
#include <string>
#include <vector>
#include <chrono>
#include <iostream>
#include <sstream>
#include <uavcan/uavcan.hpp>
#include <uavcan/node/sub_node.hpp>

namespace uavcan_linux
{
/**
 * Default log sink will dump everything into stderr.
 * It is installed by default.
 */
class DefaultLogSink : public uavcan::ILogSink
{
    virtual void log(const uavcan::protocol::debug::LogMessage& message)
    {
        const auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
        const auto tstr = std::ctime(&tt);
        std::cerr << "### UAVCAN " << tstr << message << std::endl;
    }
};

/**
 * Wrapper over uavcan::ServiceClient<> for blocking calls.
 * Blocks on uavcan::Node::spin() internally until the call is complete.
 */
template <typename DataType>
class BlockingServiceClient : public uavcan::ServiceClient<DataType>
{
    typedef uavcan::ServiceClient<DataType> Super;

    typename DataType::Response response_;
    bool call_was_successful_;

    void callback(const uavcan::ServiceCallResult<DataType>& res)
    {
        response_ = res.getResponse();
        call_was_successful_ = res.isSuccessful();
    }

    void setup()
    {
        Super::setCallback(std::bind(&BlockingServiceClient::callback, this, std::placeholders::_1));
        call_was_successful_ = false;
        response_ = typename DataType::Response();
    }

public:
    BlockingServiceClient(uavcan::INode& node)
        : uavcan::ServiceClient<DataType>(node)
        , call_was_successful_(false)
    {
        setup();
    }

    /**
     * Performs a blocking service call using default timeout (see the specs).
     * Use @ref getResponse() to get the actual response.
     * Returns negative error code.
     */
    int blockingCall(uavcan::NodeID server_node_id, const typename DataType::Request& request)
    {
        return blockingCall(server_node_id, request, Super::getDefaultRequestTimeout());
    }

    /**
     * Performs a blocking service call using the specified timeout. Please consider using default timeout instead.
     * Use @ref getResponse() to get the actual response.
     * Returns negative error code.
     */
    int blockingCall(uavcan::NodeID server_node_id, const typename DataType::Request& request,
                     uavcan::MonotonicDuration timeout)
    {
        const auto SpinDuration = uavcan::MonotonicDuration::fromMSec(2);
        setup();
        Super::setRequestTimeout(timeout);
        const int call_res = Super::call(server_node_id, request);
        if (call_res >= 0)
        {
            while (Super::hasPendingCalls())
            {
                const int spin_res = Super::getNode().spin(SpinDuration);
                if (spin_res < 0)
                {
                    return spin_res;
                }
            }
        }
        return call_res;
    }

    /**
     * Whether the last blocking call was successful.
     */
    bool wasSuccessful() const { return call_was_successful_; }

    /**
     * Use this to retrieve the response of the last blocking service call.
     * This method returns default constructed response object if the last service call was unsuccessful.
     */
    const typename DataType::Response& getResponse() const { return response_; }
};

/**
 * Contains all drivers needed for uavcan::Node.
 */
struct DriverPack
{
    SystemClock clock;
    std::shared_ptr<uavcan::ICanDriver> can;

    explicit DriverPack(ClockAdjustmentMode clock_adjustment_mode,
                        const std::shared_ptr<uavcan::ICanDriver>& can_driver)
        : clock(clock_adjustment_mode)
        , can(can_driver)
    { }

    explicit DriverPack(ClockAdjustmentMode clock_adjustment_mode,
                        const std::vector<std::string>& iface_names)
        : clock(clock_adjustment_mode)
    {
        std::shared_ptr<SocketCanDriver> socketcan(new SocketCanDriver(clock));
        can = socketcan;
        for (auto ifn : iface_names)
        {
            if (socketcan->addIface(ifn) < 0)
            {
                throw Exception("Failed to add iface " + ifn);
            }
        }
    }
};

typedef std::shared_ptr<DriverPack> DriverPackPtr;

typedef std::shared_ptr<uavcan::INode> INodePtr;
typedef std::shared_ptr<uavcan::Timer> TimerPtr;

static constexpr std::size_t NodeMemPoolSize = 1024 * 512;  ///< This shall be enough for any possible use case

/**
 * Generic wrapper for node objects with some additional convenience functions.
 */
template <typename NodeType>
class NodeBase : public NodeType
{
protected:
    DriverPackPtr driver_pack_;

    static void enforce(int error, const std::string& msg)
    {
        if (error < 0)
        {
            std::ostringstream os;
            os << msg << " [" << error << "]";
            throw Exception(os.str());
        }
    }

    template <typename DataType>
    static std::string getDataTypeName()
    {
        return DataType::getDataTypeFullName();
    }

public:
    /**
     * Simple forwarding constructor, compatible with uavcan::Node.
     */
    NodeBase(uavcan::ICanDriver& can_driver, uavcan::ISystemClock& clock) :
        NodeType(can_driver, clock)
    { }

    /**
     * Takes ownership of the driver container via the shared pointer.
     */
    explicit NodeBase(DriverPackPtr driver_pack)
        : NodeType(*driver_pack->can, driver_pack->clock)
        , driver_pack_(driver_pack)
    { }

    /**
     * Allocates @ref uavcan::Subscriber in the heap using shared pointer.
     * The subscriber will be started immediately.
     * @throws uavcan_linux::Exception.
     */
    template <typename DataType>
    std::shared_ptr<uavcan::Subscriber<DataType>>
    makeSubscriber(const typename uavcan::Subscriber<DataType>::Callback& cb)
    {
        std::shared_ptr<uavcan::Subscriber<DataType>> p(new uavcan::Subscriber<DataType>(*this));
        enforce(p->start(cb), "Subscriber start failure " + getDataTypeName<DataType>());
        return p;
    }

    /**
     * Allocates @ref uavcan::Publisher in the heap using shared pointer.
     * The publisher will be initialized immediately.
     * @throws uavcan_linux::Exception.
     */
    template <typename DataType>
    std::shared_ptr<uavcan::Publisher<DataType>>
    makePublisher(uavcan::MonotonicDuration tx_timeout = uavcan::Publisher<DataType>::getDefaultTxTimeout())
    {
        std::shared_ptr<uavcan::Publisher<DataType>> p(new uavcan::Publisher<DataType>(*this));
        enforce(p->init(), "Publisher init failure " + getDataTypeName<DataType>());
        p->setTxTimeout(tx_timeout);
        return p;
    }

    /**
     * Allocates @ref uavcan::ServiceServer in the heap using shared pointer.
     * The server will be started immediately.
     * @throws uavcan_linux::Exception.
     */
    template <typename DataType>
    std::shared_ptr<uavcan::ServiceServer<DataType>>
    makeServiceServer(const typename uavcan::ServiceServer<DataType>::Callback& cb)
    {
        std::shared_ptr<uavcan::ServiceServer<DataType>> p(new uavcan::ServiceServer<DataType>(*this));
        enforce(p->start(cb), "ServiceServer start failure " + getDataTypeName<DataType>());
        return p;
    }

    /**
     * Allocates @ref uavcan::ServiceClient in the heap using shared pointer.
     * The service client will be initialized immediately.
     * @throws uavcan_linux::Exception.
     */
    template <typename DataType>
    std::shared_ptr<uavcan::ServiceClient<DataType>>
    makeServiceClient(const typename uavcan::ServiceClient<DataType>::Callback& cb)
    {
        std::shared_ptr<uavcan::ServiceClient<DataType>> p(new uavcan::ServiceClient<DataType>(*this));
        enforce(p->init(), "ServiceClient init failure " + getDataTypeName<DataType>());
        p->setCallback(cb);
        return p;
    }

    /**
     * Allocates @ref uavcan_linux::BlockingServiceClient in the heap using shared pointer.
     * The service client will be initialized immediately.
     * @throws uavcan_linux::Exception.
     */
    template <typename DataType>
    std::shared_ptr<BlockingServiceClient<DataType>>
    makeBlockingServiceClient()
    {
        std::shared_ptr<BlockingServiceClient<DataType>> p(new BlockingServiceClient<DataType>(*this));
        enforce(p->init(), "BlockingServiceClient init failure " + getDataTypeName<DataType>());
        return p;
    }

    /**
     * Allocates @ref uavcan::Timer in the heap using shared pointer.
     * The timer will be started immediately in one-shot mode.
     */
    TimerPtr makeTimer(uavcan::MonotonicTime deadline, const typename uavcan::Timer::Callback& cb)
    {
        TimerPtr p(new uavcan::Timer(*this));
        p->setCallback(cb);
        p->startOneShotWithDeadline(deadline);
        return p;
    }

    /**
     * Allocates @ref uavcan::Timer in the heap using shared pointer.
     * The timer will be started immediately in periodic mode.
     */
    TimerPtr makeTimer(uavcan::MonotonicDuration period, const typename uavcan::Timer::Callback& cb)
    {
        TimerPtr p(new uavcan::Timer(*this));
        p->setCallback(cb);
        p->startPeriodic(period);
        return p;
    }

    const DriverPackPtr& getDriverPack() const { return driver_pack_; }
    DriverPackPtr& getDriverPack() { return driver_pack_; }
};

/**
 * Wrapper for uavcan::Node with some additional convenience functions.
 * Note that this wrapper adds stderr log sink to @ref uavcan::Logger, which can be removed if needed.
 * Do not instantiate this class directly; instead use the factory functions defined below.
 */
class Node : public NodeBase<uavcan::Node<NodeMemPoolSize>>
{
    typedef NodeBase<uavcan::Node<NodeMemPoolSize>> Base;

    DefaultLogSink log_sink_;

public:
    /**
     * Simple forwarding constructor, compatible with uavcan::Node.
     */
    Node(uavcan::ICanDriver& can_driver, uavcan::ISystemClock& clock) :
        Base(can_driver, clock)
    {
        getLogger().setExternalSink(&log_sink_);
    }

    /**
     * Takes ownership of the driver container via the shared pointer.
     */
    explicit Node(DriverPackPtr driver_pack) :
        Base(driver_pack)
    {
        getLogger().setExternalSink(&log_sink_);
    }
};

/**
 * Wrapper for uavcan::SubNode with some additional convenience functions.
 * Do not instantiate this class directly; instead use the factory functions defined below.
 */
class SubNode : public NodeBase<uavcan::SubNode<NodeMemPoolSize>>
{
    typedef NodeBase<uavcan::SubNode<NodeMemPoolSize>> Base;

public:
    /**
     * Simple forwarding constructor, compatible with uavcan::Node.
     */
    SubNode(uavcan::ICanDriver& can_driver, uavcan::ISystemClock& clock) : Base(can_driver, clock) { }

    /**
     * Takes ownership of the driver container via the shared pointer.
     */
    explicit SubNode(DriverPackPtr driver_pack) : Base(driver_pack) { }
};

typedef std::shared_ptr<Node> NodePtr;
typedef std::shared_ptr<SubNode> SubNodePtr;

/**
 * Use this function to create a node instance with default SocketCAN driver.
 * It accepts the list of interface names to use for the new node, e.g. "can1", "vcan2", "slcan0".
 * Clock adjustment mode will be detected automatically unless provided explicitly.
 * @throws uavcan_linux::Exception.
 */
static inline NodePtr makeNode(const std::vector<std::string>& iface_names,
                               ClockAdjustmentMode clock_adjustment_mode =
                                   SystemClock::detectPreferredClockAdjustmentMode())
{
    DriverPackPtr dp(new DriverPack(clock_adjustment_mode, iface_names));
    return NodePtr(new Node(dp));
}

/**
 * Use this function to create a node instance with a custom driver.
 * Clock adjustment mode will be detected automatically unless provided explicitly.
 * @throws uavcan_linux::Exception.
 */
static inline NodePtr makeNode(const std::shared_ptr<uavcan::ICanDriver>& can_driver,
                               ClockAdjustmentMode clock_adjustment_mode =
                                   SystemClock::detectPreferredClockAdjustmentMode())
{
    DriverPackPtr dp(new DriverPack(clock_adjustment_mode, can_driver));
    return NodePtr(new Node(dp));
}

/**
 * Use this function to create a sub-node instance with default SocketCAN driver.
 * It accepts the list of interface names to use for the new node, e.g. "can1", "vcan2", "slcan0".
 * Clock adjustment mode will be detected automatically unless provided explicitly.
 * @throws uavcan_linux::Exception.
 */
static inline SubNodePtr makeSubNode(const std::vector<std::string>& iface_names,
                                  ClockAdjustmentMode clock_adjustment_mode =
                                      SystemClock::detectPreferredClockAdjustmentMode())
{
    DriverPackPtr dp(new DriverPack(clock_adjustment_mode, iface_names));
    return SubNodePtr(new SubNode(dp));
}

/**
 * Use this function to create a sub-node instance with a custom driver.
 * Clock adjustment mode will be detected automatically unless provided explicitly.
 * @throws uavcan_linux::Exception.
 */
static inline SubNodePtr makeSubNode(const std::shared_ptr<uavcan::ICanDriver>& can_driver,
                                     ClockAdjustmentMode clock_adjustment_mode =
                                         SystemClock::detectPreferredClockAdjustmentMode())
{
    DriverPackPtr dp(new DriverPack(clock_adjustment_mode, can_driver));
    return SubNodePtr(new SubNode(dp));
}

}
<commit_msg>Cleaner type definitions in Linux driver<commit_after>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#pragma once

#include <memory>
#include <string>
#include <vector>
#include <chrono>
#include <iostream>
#include <sstream>
#include <uavcan/uavcan.hpp>
#include <uavcan/node/sub_node.hpp>

namespace uavcan_linux
{
/**
 * Default log sink will dump everything into stderr.
 * It is installed by default.
 */
class DefaultLogSink : public uavcan::ILogSink
{
    virtual void log(const uavcan::protocol::debug::LogMessage& message)
    {
        const auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
        const auto tstr = std::ctime(&tt);
        std::cerr << "### UAVCAN " << tstr << message << std::endl;
    }
};

/**
 * Wrapper over uavcan::ServiceClient<> for blocking calls.
 * Blocks on uavcan::Node::spin() internally until the call is complete.
 */
template <typename DataType>
class BlockingServiceClient : public uavcan::ServiceClient<DataType>
{
    typedef uavcan::ServiceClient<DataType> Super;

    typename DataType::Response response_;
    bool call_was_successful_;

    void callback(const uavcan::ServiceCallResult<DataType>& res)
    {
        response_ = res.getResponse();
        call_was_successful_ = res.isSuccessful();
    }

    void setup()
    {
        Super::setCallback(std::bind(&BlockingServiceClient::callback, this, std::placeholders::_1));
        call_was_successful_ = false;
        response_ = typename DataType::Response();
    }

public:
    BlockingServiceClient(uavcan::INode& node)
        : uavcan::ServiceClient<DataType>(node)
        , call_was_successful_(false)
    {
        setup();
    }

    /**
     * Performs a blocking service call using default timeout (see the specs).
     * Use @ref getResponse() to get the actual response.
     * Returns negative error code.
     */
    int blockingCall(uavcan::NodeID server_node_id, const typename DataType::Request& request)
    {
        return blockingCall(server_node_id, request, Super::getDefaultRequestTimeout());
    }

    /**
     * Performs a blocking service call using the specified timeout. Please consider using default timeout instead.
     * Use @ref getResponse() to get the actual response.
     * Returns negative error code.
     */
    int blockingCall(uavcan::NodeID server_node_id, const typename DataType::Request& request,
                     uavcan::MonotonicDuration timeout)
    {
        const auto SpinDuration = uavcan::MonotonicDuration::fromMSec(2);
        setup();
        Super::setRequestTimeout(timeout);
        const int call_res = Super::call(server_node_id, request);
        if (call_res >= 0)
        {
            while (Super::hasPendingCalls())
            {
                const int spin_res = Super::getNode().spin(SpinDuration);
                if (spin_res < 0)
                {
                    return spin_res;
                }
            }
        }
        return call_res;
    }

    /**
     * Whether the last blocking call was successful.
     */
    bool wasSuccessful() const { return call_was_successful_; }

    /**
     * Use this to retrieve the response of the last blocking service call.
     * This method returns default constructed response object if the last service call was unsuccessful.
     */
    const typename DataType::Response& getResponse() const { return response_; }
};

/**
 * Contains all drivers needed for uavcan::Node.
 */
struct DriverPack
{
    SystemClock clock;
    std::shared_ptr<uavcan::ICanDriver> can;

    explicit DriverPack(ClockAdjustmentMode clock_adjustment_mode,
                        const std::shared_ptr<uavcan::ICanDriver>& can_driver)
        : clock(clock_adjustment_mode)
        , can(can_driver)
    { }

    explicit DriverPack(ClockAdjustmentMode clock_adjustment_mode,
                        const std::vector<std::string>& iface_names)
        : clock(clock_adjustment_mode)
    {
        std::shared_ptr<SocketCanDriver> socketcan(new SocketCanDriver(clock));
        can = socketcan;
        for (auto ifn : iface_names)
        {
            if (socketcan->addIface(ifn) < 0)
            {
                throw Exception("Failed to add iface " + ifn);
            }
        }
    }
};

typedef std::shared_ptr<DriverPack> DriverPackPtr;

typedef std::shared_ptr<uavcan::INode> INodePtr;

typedef std::shared_ptr<uavcan::Timer> TimerPtr;

template <typename T>
using SubscriberPtr = std::shared_ptr<uavcan::Subscriber<T>>;

template <typename T>
using PublisherPtr = std::shared_ptr<uavcan::Publisher<T>>;

template <typename T>
using ServiceServerPtr = std::shared_ptr<uavcan::ServiceServer<T>>;

template <typename T>
using ServiceClientPtr = std::shared_ptr<uavcan::ServiceClient<T>>;

template <typename T>
using BlockingServiceClientPtr = std::shared_ptr<BlockingServiceClient<T>>;

static constexpr std::size_t NodeMemPoolSize = 1024 * 512;  ///< This shall be enough for any possible use case

/**
 * Generic wrapper for node objects with some additional convenience functions.
 */
template <typename NodeType>
class NodeBase : public NodeType
{
protected:
    DriverPackPtr driver_pack_;

    static void enforce(int error, const std::string& msg)
    {
        if (error < 0)
        {
            std::ostringstream os;
            os << msg << " [" << error << "]";
            throw Exception(os.str());
        }
    }

    template <typename DataType>
    static std::string getDataTypeName()
    {
        return DataType::getDataTypeFullName();
    }

public:
    /**
     * Simple forwarding constructor, compatible with uavcan::Node.
     */
    NodeBase(uavcan::ICanDriver& can_driver, uavcan::ISystemClock& clock) :
        NodeType(can_driver, clock)
    { }

    /**
     * Takes ownership of the driver container via the shared pointer.
     */
    explicit NodeBase(DriverPackPtr driver_pack)
        : NodeType(*driver_pack->can, driver_pack->clock)
        , driver_pack_(driver_pack)
    { }

    /**
     * Allocates @ref uavcan::Subscriber in the heap using shared pointer.
     * The subscriber will be started immediately.
     * @throws uavcan_linux::Exception.
     */
    template <typename DataType>
    SubscriberPtr<DataType> makeSubscriber(const typename uavcan::Subscriber<DataType>::Callback& cb)
    {
        SubscriberPtr<DataType> p(new uavcan::Subscriber<DataType>(*this));
        enforce(p->start(cb), "Subscriber start failure " + getDataTypeName<DataType>());
        return p;
    }

    /**
     * Allocates @ref uavcan::Publisher in the heap using shared pointer.
     * The publisher will be initialized immediately.
     * @throws uavcan_linux::Exception.
     */
    template <typename DataType>
    PublisherPtr<DataType> makePublisher(uavcan::MonotonicDuration tx_timeout =
                                             uavcan::Publisher<DataType>::getDefaultTxTimeout())
    {
        PublisherPtr<DataType> p(new uavcan::Publisher<DataType>(*this));
        enforce(p->init(), "Publisher init failure " + getDataTypeName<DataType>());
        p->setTxTimeout(tx_timeout);
        return p;
    }

    /**
     * Allocates @ref uavcan::ServiceServer in the heap using shared pointer.
     * The server will be started immediately.
     * @throws uavcan_linux::Exception.
     */
    template <typename DataType>
    ServiceServerPtr<DataType> makeServiceServer(const typename uavcan::ServiceServer<DataType>::Callback& cb)
    {
        ServiceServerPtr<DataType> p(new uavcan::ServiceServer<DataType>(*this));
        enforce(p->start(cb), "ServiceServer start failure " + getDataTypeName<DataType>());
        return p;
    }

    /**
     * Allocates @ref uavcan::ServiceClient in the heap using shared pointer.
     * The service client will be initialized immediately.
     * @throws uavcan_linux::Exception.
     */
    template <typename DataType>
    ServiceClientPtr<DataType> makeServiceClient(const typename uavcan::ServiceClient<DataType>::Callback& cb)
    {
        ServiceClientPtr<DataType> p(new uavcan::ServiceClient<DataType>(*this));
        enforce(p->init(), "ServiceClient init failure " + getDataTypeName<DataType>());
        p->setCallback(cb);
        return p;
    }

    /**
     * Allocates @ref uavcan_linux::BlockingServiceClient in the heap using shared pointer.
     * The service client will be initialized immediately.
     * @throws uavcan_linux::Exception.
     */
    template <typename DataType>
    BlockingServiceClientPtr<DataType> makeBlockingServiceClient()
    {
        BlockingServiceClientPtr<DataType> p(new BlockingServiceClient<DataType>(*this));
        enforce(p->init(), "BlockingServiceClient init failure " + getDataTypeName<DataType>());
        return p;
    }

    /**
     * Allocates @ref uavcan::Timer in the heap using shared pointer.
     * The timer will be started immediately in one-shot mode.
     */
    TimerPtr makeTimer(uavcan::MonotonicTime deadline, const typename uavcan::Timer::Callback& cb)
    {
        TimerPtr p(new uavcan::Timer(*this));
        p->setCallback(cb);
        p->startOneShotWithDeadline(deadline);
        return p;
    }

    /**
     * Allocates @ref uavcan::Timer in the heap using shared pointer.
     * The timer will be started immediately in periodic mode.
     */
    TimerPtr makeTimer(uavcan::MonotonicDuration period, const typename uavcan::Timer::Callback& cb)
    {
        TimerPtr p(new uavcan::Timer(*this));
        p->setCallback(cb);
        p->startPeriodic(period);
        return p;
    }

    const DriverPackPtr& getDriverPack() const { return driver_pack_; }
    DriverPackPtr& getDriverPack() { return driver_pack_; }
};

/**
 * Wrapper for uavcan::Node with some additional convenience functions.
 * Note that this wrapper adds stderr log sink to @ref uavcan::Logger, which can be removed if needed.
 * Do not instantiate this class directly; instead use the factory functions defined below.
 */
class Node : public NodeBase<uavcan::Node<NodeMemPoolSize>>
{
    typedef NodeBase<uavcan::Node<NodeMemPoolSize>> Base;

    DefaultLogSink log_sink_;

public:
    /**
     * Simple forwarding constructor, compatible with uavcan::Node.
     */
    Node(uavcan::ICanDriver& can_driver, uavcan::ISystemClock& clock) :
        Base(can_driver, clock)
    {
        getLogger().setExternalSink(&log_sink_);
    }

    /**
     * Takes ownership of the driver container via the shared pointer.
     */
    explicit Node(DriverPackPtr driver_pack) :
        Base(driver_pack)
    {
        getLogger().setExternalSink(&log_sink_);
    }
};

/**
 * Wrapper for uavcan::SubNode with some additional convenience functions.
 * Do not instantiate this class directly; instead use the factory functions defined below.
 */
class SubNode : public NodeBase<uavcan::SubNode<NodeMemPoolSize>>
{
    typedef NodeBase<uavcan::SubNode<NodeMemPoolSize>> Base;

public:
    /**
     * Simple forwarding constructor, compatible with uavcan::Node.
     */
    SubNode(uavcan::ICanDriver& can_driver, uavcan::ISystemClock& clock) : Base(can_driver, clock) { }

    /**
     * Takes ownership of the driver container via the shared pointer.
     */
    explicit SubNode(DriverPackPtr driver_pack) : Base(driver_pack) { }
};

typedef std::shared_ptr<Node> NodePtr;
typedef std::shared_ptr<SubNode> SubNodePtr;

/**
 * Use this function to create a node instance with default SocketCAN driver.
 * It accepts the list of interface names to use for the new node, e.g. "can1", "vcan2", "slcan0".
 * Clock adjustment mode will be detected automatically unless provided explicitly.
 * @throws uavcan_linux::Exception.
 */
static inline NodePtr makeNode(const std::vector<std::string>& iface_names,
                               ClockAdjustmentMode clock_adjustment_mode =
                                   SystemClock::detectPreferredClockAdjustmentMode())
{
    DriverPackPtr dp(new DriverPack(clock_adjustment_mode, iface_names));
    return NodePtr(new Node(dp));
}

/**
 * Use this function to create a node instance with a custom driver.
 * Clock adjustment mode will be detected automatically unless provided explicitly.
 * @throws uavcan_linux::Exception.
 */
static inline NodePtr makeNode(const std::shared_ptr<uavcan::ICanDriver>& can_driver,
                               ClockAdjustmentMode clock_adjustment_mode =
                                   SystemClock::detectPreferredClockAdjustmentMode())
{
    DriverPackPtr dp(new DriverPack(clock_adjustment_mode, can_driver));
    return NodePtr(new Node(dp));
}

/**
 * Use this function to create a sub-node instance with default SocketCAN driver.
 * It accepts the list of interface names to use for the new node, e.g. "can1", "vcan2", "slcan0".
 * Clock adjustment mode will be detected automatically unless provided explicitly.
 * @throws uavcan_linux::Exception.
 */
static inline SubNodePtr makeSubNode(const std::vector<std::string>& iface_names,
                                  ClockAdjustmentMode clock_adjustment_mode =
                                      SystemClock::detectPreferredClockAdjustmentMode())
{
    DriverPackPtr dp(new DriverPack(clock_adjustment_mode, iface_names));
    return SubNodePtr(new SubNode(dp));
}

/**
 * Use this function to create a sub-node instance with a custom driver.
 * Clock adjustment mode will be detected automatically unless provided explicitly.
 * @throws uavcan_linux::Exception.
 */
static inline SubNodePtr makeSubNode(const std::shared_ptr<uavcan::ICanDriver>& can_driver,
                                     ClockAdjustmentMode clock_adjustment_mode =
                                         SystemClock::detectPreferredClockAdjustmentMode())
{
    DriverPackPtr dp(new DriverPack(clock_adjustment_mode, can_driver));
    return SubNodePtr(new SubNode(dp));
}

}
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the LiveSupport project.
    http://livesupport.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

    LiveSupport 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 2 of the License, or
    (at your option) any later version.

    LiveSupport 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 LiveSupport; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author: fgerlits $
    Version  : $Revision: 1.17 $
    Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/products/gLiveSupport/src/LiveModeWindow.cxx,v $

------------------------------------------------------------------------------*/

/* ============================================================ include files */

#ifdef HAVE_CONFIG_H
#include "configure.h"
#endif

#include <iostream>
#include <stdexcept>
#include <glibmm.h>

#include "LiveSupport/Widgets/WidgetFactory.h"
#include "SchedulePlaylistWindow.h"
#include "LiveModeWindow.h"

using namespace Glib;

using namespace LiveSupport::Core;
using namespace LiveSupport::Widgets;
using namespace LiveSupport::GLiveSupport;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/* ===============================================  local function prototypes */

/* =============================================================  module code */

/*------------------------------------------------------------------------------
 *  Constructor.
 *----------------------------------------------------------------------------*/
LiveModeWindow :: LiveModeWindow (Ptr<GLiveSupport>::Ref      gLiveSupport,
                                  Ptr<ResourceBundle>::Ref    bundle)
                                                                    throw ()
          : WhiteWindow(WidgetFactory::liveModeWindowTitleImage,
                        Colors::White,
                        WidgetFactory::getInstance()->getWhiteWindowCorners()),
            LocalizedObject(bundle),
            gLiveSupport(gLiveSupport)
{
    try {
        set_title(*getResourceUstring("windowTitle"));
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        std::exit(1);
    }

    Ptr<WidgetFactory>::Ref     wf = WidgetFactory::getInstance();

    // Create the tree model:
    treeModel = Gtk::ListStore::create(modelColumns);
    treeModel->signal_rows_reordered().connect(sigc::mem_fun(*this,
                                            &LiveModeWindow::onRowsReordered));
    treeModel->signal_row_deleted().connect(sigc::mem_fun(*this,
                                            &LiveModeWindow::onRowDeleted));

    // ... and the tree view:
    treeView = Gtk::manage(wf->createTreeView(treeModel));
    treeView->set_headers_visible(false);

    // Add the TreeView's view columns:
    try {
        treeView->appendLineNumberColumn("", 2 /* offset */, 50);
//        treeView->appendColumn("", WidgetFactory::hugePlayButton, 82);
        treeView->appendColumn("", modelColumns.infoColumn, 200);
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        std::exit(1);
    }

    // register the signal handler for treeview entries being clicked
    treeView->signal_button_press_event().connect_notify(sigc::mem_fun(*this,
                                            &LiveModeWindow::onEntryClicked));

    // Add the TreeView, inside a ScrolledWindow, with the button underneath:
    scrolledWindow.add(*treeView);

    // Only show the scrollbars when they are necessary:
    scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

    // Create the play etc buttons:
    Gtk::HBox *         buttonBox = Gtk::manage(new Gtk::HBox);
    ImageButton *       outputPlayButton = Gtk::manage(wf->createButton(
                                        WidgetFactory::hugePlayButton ));
    Gtk::VBox *         cueAudioBox = Gtk::manage(new Gtk::VBox);
    Gtk::HBox *         cueAudioLabelBox = Gtk::manage(new Gtk::HBox);
    Gtk::Label *        cueAudioLabel;
    try {
        cueAudioLabel = Gtk::manage(new Gtk::Label(
                                    *getResourceUstring("cuePlayerLabel") ));
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        std::exit(1);
    }
    Gtk::HBox *         cueAudioButtonsBox = Gtk::manage(new Gtk::HBox);
    CuePlayer *         cueAudioButtons = Gtk::manage(new CuePlayer(
                                    gLiveSupport, treeView, modelColumns ));
    buttonBox->pack_start(*outputPlayButton, Gtk::PACK_EXPAND_PADDING, 10);
    buttonBox->pack_start(*cueAudioBox,      Gtk::PACK_EXPAND_PADDING, 10);
    cueAudioBox->pack_start(*cueAudioLabelBox,   Gtk::PACK_SHRINK, 6);
    cueAudioLabelBox->pack_start(*cueAudioLabel, Gtk::PACK_EXPAND_PADDING, 1);
    cueAudioBox->pack_start(*cueAudioButtonsBox, Gtk::PACK_SHRINK, 0);
    cueAudioButtonsBox->pack_start(*cueAudioButtons,
                                                 Gtk::PACK_EXPAND_PADDING, 1);

    vBox.pack_start(*buttonBox,     Gtk::PACK_SHRINK, 5);
    vBox.pack_start(scrolledWindow, Gtk::PACK_EXPAND_WIDGET, 5);
    add(vBox);

    // connect the signal handler for the output play button
    outputPlayButton->signal_clicked().connect(sigc::mem_fun(*this,
                                            &LiveModeWindow::onOutputPlay ));

    // create the right-click entry context menu for audio clips
    contextMenu = Gtk::manage(new Gtk::Menu());
    Gtk::Menu::MenuList& contextMenuList = contextMenu->items();
    // register the signal handlers for the popup menu
    try {
        contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
                                 *getResourceUstring("cueMenuItem"),
                                  sigc::mem_fun(*cueAudioButtons,
                                        &CuePlayer::onPlayItem)));
        contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
                                 *getResourceUstring("upMenuItem"),
                                  sigc::mem_fun(*treeView,
                                        &ZebraTreeView::onUpMenuOption)));
        contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
                                 *getResourceUstring("downMenuItem"),
                                  sigc::mem_fun(*treeView,
                                        &ZebraTreeView::onDownMenuOption)));
        contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
                                 *getResourceUstring("removeMenuItem"),
                                  sigc::mem_fun(*treeView,
                                        &ZebraTreeView::onRemoveMenuOption)));
        contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
                                 *getResourceUstring("playMenuItem"),
                                  sigc::mem_fun(*this,
                                        &LiveModeWindow::onOutputPlay)));
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        std::exit(1);
    }

    contextMenu->accelerate(*this);

    // show
    set_name("liveModeWindow");
    set_default_size(400, 500);
    set_modal(false);
    property_window_position().set_value(Gtk::WIN_POS_NONE);

    show_all_children();
}

/*------------------------------------------------------------------------------
 *  Add a new item to the Live Mode Window.
 *----------------------------------------------------------------------------*/
void
LiveModeWindow :: addItem(Ptr<Playable>::Ref  playable)             throw ()
{
    int                     rowNumber = treeModel->children().size();
    Gtk::TreeModel::Row     row       = *(treeModel->append());

    row[modelColumns.rowNumberColumn] = rowNumber;
    row[modelColumns.playableColumn]  = playable;

    Ptr<Glib::ustring>::Ref     infoString(new Glib::ustring);

    infoString->append("");
    infoString->append(Glib::Markup::escape_text(*playable->getTitle()));
    infoString->append("");

    // TODO: rewrite this using the Core::Metadata class

    Ptr<Glib::ustring>::Ref
                        creator = playable->getMetadata("dc:creator");
    if (creator) {
        infoString->append("\n");
        infoString->append(Glib::Markup::escape_text(*creator));
        infoString->append("");
    }

    Ptr<Glib::ustring>::Ref
                        album = playable->getMetadata("dc:source");
    if (album) {
        infoString->append("\n");
        infoString->append(Glib::Markup::escape_text(*album));
        infoString->append("");
    }

    infoString->append("\n"
                       "duration: ");
    infoString->append(to_simple_string(*playable->getPlaylength()));
    infoString->append("");

    row[modelColumns.infoColumn] = *infoString;
}

/*------------------------------------------------------------------------------
 *  "Pop" the first item from the top of the Live Mode Window.
 *----------------------------------------------------------------------------*/
Ptr<Playable>::Ref
LiveModeWindow :: popTop(void)                                      throw ()
{
    Ptr<Playable>::Ref          playable;
/*  disabled for testing
    Gtk::TreeModel::iterator    iter = treeModel->children().begin();

    if (iter) {
        playable = (*iter)[modelColumns.playableColumn];
        treeModel->erase(iter);
    }
*/
    return playable;
}

/*------------------------------------------------------------------------------
 *  Signal handler for the output play button clicked.
 *----------------------------------------------------------------------------*/
void
LiveModeWindow :: onOutputPlay(void)                                throw ()
{
    Glib::RefPtr<Gtk::TreeView::Selection> refSelection =
                                                    treeView->get_selection();
    Gtk::TreeModel::iterator        iter = refSelection->get_selected();

    if (iter) {
        Ptr<Playable>::Ref  playable = (*iter)[modelColumns.playableColumn];
        gLiveSupport->playOutputAudio(playable);
        gLiveSupport->setNowPlaying(playable);
        treeView->removeItem(iter);
    }
}

/*------------------------------------------------------------------------------
 *  Event handler for an entry being clicked in the list
 *----------------------------------------------------------------------------*/
void
LiveModeWindow :: onEntryClicked (GdkEventButton     * event)       throw ()
{
    if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
        Glib::RefPtr<Gtk::TreeView::Selection> refSelection =
                                                      treeView->get_selection();
        Gtk::TreeModel::iterator iter = refSelection->get_selected();

        // if nothing is currently selected, select row at mouse pointer
        if (!iter) {
            Gtk::TreeModel::Path    path;
            Gtk::TreeViewColumn *   column;
            int     cell_x,
                    cell_y;
            if (treeView->get_path_at_pos(int(event->x), int(event->y),
                                          path, column,
                                          cell_x, cell_y)) {
                refSelection->select(path);
                iter = refSelection->get_selected();
            }
        }

        if (iter) {
            contextMenu->popup(event->button, event->time);
        }
    }
}

<commit_msg>uncommented the popTop() function -- it still does not work, though<commit_after>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the LiveSupport project.
    http://livesupport.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

    LiveSupport 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 2 of the License, or
    (at your option) any later version.

    LiveSupport 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 LiveSupport; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author: fgerlits $
    Version  : $Revision: 1.18 $
    Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/products/gLiveSupport/src/LiveModeWindow.cxx,v $

------------------------------------------------------------------------------*/

/* ============================================================ include files */

#ifdef HAVE_CONFIG_H
#include "configure.h"
#endif

#include <iostream>
#include <stdexcept>
#include <glibmm.h>

#include "LiveSupport/Widgets/WidgetFactory.h"
#include "SchedulePlaylistWindow.h"
#include "LiveModeWindow.h"

using namespace Glib;

using namespace LiveSupport::Core;
using namespace LiveSupport::Widgets;
using namespace LiveSupport::GLiveSupport;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/* ===============================================  local function prototypes */

/* =============================================================  module code */

/*------------------------------------------------------------------------------
 *  Constructor.
 *----------------------------------------------------------------------------*/
LiveModeWindow :: LiveModeWindow (Ptr<GLiveSupport>::Ref      gLiveSupport,
                                  Ptr<ResourceBundle>::Ref    bundle)
                                                                    throw ()
          : WhiteWindow(WidgetFactory::liveModeWindowTitleImage,
                        Colors::White,
                        WidgetFactory::getInstance()->getWhiteWindowCorners()),
            LocalizedObject(bundle),
            gLiveSupport(gLiveSupport)
{
    try {
        set_title(*getResourceUstring("windowTitle"));
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        std::exit(1);
    }

    Ptr<WidgetFactory>::Ref     wf = WidgetFactory::getInstance();

    // Create the tree model:
    treeModel = Gtk::ListStore::create(modelColumns);
    treeModel->signal_rows_reordered().connect(sigc::mem_fun(*this,
                                            &LiveModeWindow::onRowsReordered));
    treeModel->signal_row_deleted().connect(sigc::mem_fun(*this,
                                            &LiveModeWindow::onRowDeleted));

    // ... and the tree view:
    treeView = Gtk::manage(wf->createTreeView(treeModel));
    treeView->set_headers_visible(false);

    // Add the TreeView's view columns:
    try {
        treeView->appendLineNumberColumn("", 2 /* offset */, 50);
//        treeView->appendColumn("", WidgetFactory::hugePlayButton, 82);
        treeView->appendColumn("", modelColumns.infoColumn, 200);
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        std::exit(1);
    }

    // register the signal handler for treeview entries being clicked
    treeView->signal_button_press_event().connect_notify(sigc::mem_fun(*this,
                                            &LiveModeWindow::onEntryClicked));

    // Add the TreeView, inside a ScrolledWindow, with the button underneath:
    scrolledWindow.add(*treeView);

    // Only show the scrollbars when they are necessary:
    scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

    // Create the play etc buttons:
    Gtk::HBox *         buttonBox = Gtk::manage(new Gtk::HBox);
    ImageButton *       outputPlayButton = Gtk::manage(wf->createButton(
                                        WidgetFactory::hugePlayButton ));
    Gtk::VBox *         cueAudioBox = Gtk::manage(new Gtk::VBox);
    Gtk::HBox *         cueAudioLabelBox = Gtk::manage(new Gtk::HBox);
    Gtk::Label *        cueAudioLabel;
    try {
        cueAudioLabel = Gtk::manage(new Gtk::Label(
                                    *getResourceUstring("cuePlayerLabel") ));
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        std::exit(1);
    }
    Gtk::HBox *         cueAudioButtonsBox = Gtk::manage(new Gtk::HBox);
    CuePlayer *         cueAudioButtons = Gtk::manage(new CuePlayer(
                                    gLiveSupport, treeView, modelColumns ));
    buttonBox->pack_start(*outputPlayButton, Gtk::PACK_EXPAND_PADDING, 10);
    buttonBox->pack_start(*cueAudioBox,      Gtk::PACK_EXPAND_PADDING, 10);
    cueAudioBox->pack_start(*cueAudioLabelBox,   Gtk::PACK_SHRINK, 6);
    cueAudioLabelBox->pack_start(*cueAudioLabel, Gtk::PACK_EXPAND_PADDING, 1);
    cueAudioBox->pack_start(*cueAudioButtonsBox, Gtk::PACK_SHRINK, 0);
    cueAudioButtonsBox->pack_start(*cueAudioButtons,
                                                 Gtk::PACK_EXPAND_PADDING, 1);

    vBox.pack_start(*buttonBox,     Gtk::PACK_SHRINK, 5);
    vBox.pack_start(scrolledWindow, Gtk::PACK_EXPAND_WIDGET, 5);
    add(vBox);

    // connect the signal handler for the output play button
    outputPlayButton->signal_clicked().connect(sigc::mem_fun(*this,
                                            &LiveModeWindow::onOutputPlay ));

    // create the right-click entry context menu for audio clips
    contextMenu = Gtk::manage(new Gtk::Menu());
    Gtk::Menu::MenuList& contextMenuList = contextMenu->items();
    // register the signal handlers for the popup menu
    try {
        contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
                                 *getResourceUstring("cueMenuItem"),
                                  sigc::mem_fun(*cueAudioButtons,
                                        &CuePlayer::onPlayItem)));
        contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
                                 *getResourceUstring("upMenuItem"),
                                  sigc::mem_fun(*treeView,
                                        &ZebraTreeView::onUpMenuOption)));
        contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
                                 *getResourceUstring("downMenuItem"),
                                  sigc::mem_fun(*treeView,
                                        &ZebraTreeView::onDownMenuOption)));
        contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
                                 *getResourceUstring("removeMenuItem"),
                                  sigc::mem_fun(*treeView,
                                        &ZebraTreeView::onRemoveMenuOption)));
        contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
                                 *getResourceUstring("playMenuItem"),
                                  sigc::mem_fun(*this,
                                        &LiveModeWindow::onOutputPlay)));
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        std::exit(1);
    }

    contextMenu->accelerate(*this);

    // show
    set_name("liveModeWindow");
    set_default_size(400, 500);
    set_modal(false);
    property_window_position().set_value(Gtk::WIN_POS_NONE);

    show_all_children();
}

/*------------------------------------------------------------------------------
 *  Add a new item to the Live Mode Window.
 *----------------------------------------------------------------------------*/
void
LiveModeWindow :: addItem(Ptr<Playable>::Ref  playable)             throw ()
{
    int                     rowNumber = treeModel->children().size();
    Gtk::TreeModel::Row     row       = *(treeModel->append());

    row[modelColumns.rowNumberColumn] = rowNumber;
    row[modelColumns.playableColumn]  = playable;

    Ptr<Glib::ustring>::Ref     infoString(new Glib::ustring);

    infoString->append("");
    infoString->append(Glib::Markup::escape_text(*playable->getTitle()));
    infoString->append("");

    // TODO: rewrite this using the Core::Metadata class

    Ptr<Glib::ustring>::Ref
                        creator = playable->getMetadata("dc:creator");
    if (creator) {
        infoString->append("\n");
        infoString->append(Glib::Markup::escape_text(*creator));
        infoString->append("");
    }

    Ptr<Glib::ustring>::Ref
                        album = playable->getMetadata("dc:source");
    if (album) {
        infoString->append("\n");
        infoString->append(Glib::Markup::escape_text(*album));
        infoString->append("");
    }

    infoString->append("\n"
                       "duration: ");
    infoString->append(to_simple_string(*playable->getPlaylength()));
    infoString->append("");

    row[modelColumns.infoColumn] = *infoString;
}

/*------------------------------------------------------------------------------
 *  "Pop" the first item from the top of the Live Mode Window.
 *----------------------------------------------------------------------------*/
Ptr<Playable>::Ref
LiveModeWindow :: popTop(void)                                      throw ()
{
    Ptr<Playable>::Ref          playable;
    Gtk::TreeModel::iterator    iter = treeModel->children().begin();

    if (iter) {
        playable = (*iter)[modelColumns.playableColumn];
        treeModel->erase(iter);
    }

    return playable;
}

/*------------------------------------------------------------------------------
 *  Signal handler for the output play button clicked.
 *----------------------------------------------------------------------------*/
void
LiveModeWindow :: onOutputPlay(void)                                throw ()
{
    Glib::RefPtr<Gtk::TreeView::Selection> refSelection =
                                                    treeView->get_selection();
    Gtk::TreeModel::iterator        iter = refSelection->get_selected();

    if (iter) {
        Ptr<Playable>::Ref  playable = (*iter)[modelColumns.playableColumn];
        gLiveSupport->playOutputAudio(playable);
        gLiveSupport->setNowPlaying(playable);
        treeView->removeItem(iter);
    }
}

/*------------------------------------------------------------------------------
 *  Event handler for an entry being clicked in the list
 *----------------------------------------------------------------------------*/
void
LiveModeWindow :: onEntryClicked (GdkEventButton     * event)       throw ()
{
    if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
        Glib::RefPtr<Gtk::TreeView::Selection> refSelection =
                                                      treeView->get_selection();
        Gtk::TreeModel::iterator iter = refSelection->get_selected();

        // if nothing is currently selected, select row at mouse pointer
        if (!iter) {
            Gtk::TreeModel::Path    path;
            Gtk::TreeViewColumn *   column;
            int     cell_x,
                    cell_y;
            if (treeView->get_path_at_pos(int(event->x), int(event->y),
                                          path, column,
                                          cell_x, cell_y)) {
                refSelection->select(path);
                iter = refSelection->get_selected();
            }
        }

        if (iter) {
            contextMenu->popup(event->button, event->time);
        }
    }
}

<|endoftext|>


<commit_before>//===- lib/CodeGen/GlobalISel/LegalizerInfo.cpp - Legalizer ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implement an interface to specify and query how an illegal operation on a
// given type should be expanded.
//
// Issues to be resolved:
//   + Make it fast.
//   + Support weird types like i3, <7 x i3>, ...
//   + Operations with more than one type (ICMP, CMPXCHG, intrinsics, ...)
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LowLevelTypeImpl.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetOpcodes.h"
#include <algorithm>
#include <cassert>
#include <tuple>
#include <utility>

using namespace llvm;

LegalizerInfo::LegalizerInfo() {
  DefaultActions[TargetOpcode::G_IMPLICIT_DEF] = NarrowScalar;

  // FIXME: these two can be legalized to the fundamental load/store Jakob
  // proposed. Once loads & stores are supported.
  DefaultActions[TargetOpcode::G_ANYEXT] = Legal;
  DefaultActions[TargetOpcode::G_TRUNC] = Legal;

  DefaultActions[TargetOpcode::G_INTRINSIC] = Legal;
  DefaultActions[TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS] = Legal;

  DefaultActions[TargetOpcode::G_ADD] = NarrowScalar;
  DefaultActions[TargetOpcode::G_LOAD] = NarrowScalar;
  DefaultActions[TargetOpcode::G_STORE] = NarrowScalar;
  DefaultActions[TargetOpcode::G_OR] = NarrowScalar;

  DefaultActions[TargetOpcode::G_BRCOND] = WidenScalar;
  DefaultActions[TargetOpcode::G_INSERT] = NarrowScalar;
  DefaultActions[TargetOpcode::G_EXTRACT] = NarrowScalar;
  DefaultActions[TargetOpcode::G_FNEG] = Lower;
}

void LegalizerInfo::computeTables() {
  for (unsigned Opcode = 0; Opcode <= LastOp - FirstOp; ++Opcode) {
    for (unsigned Idx = 0; Idx != Actions[Opcode].size(); ++Idx) {
      for (auto &Action : Actions[Opcode][Idx]) {
        LLT Ty = Action.first;
        if (!Ty.isVector())
          continue;

        auto &Entry = MaxLegalVectorElts[std::make_pair(Opcode + FirstOp,
                                                        Ty.getElementType())];
        Entry = std::max(Entry, Ty.getNumElements());
      }
    }
  }

  TablesInitialized = true;
}

// FIXME: inefficient implementation for now. Without ComputeValueVTs we're
// probably going to need specialized lookup structures for various types before
// we have any hope of doing well with something like <13 x i3>. Even the common
// cases should do better than what we have now.
std::pair<LegalizerInfo::LegalizeAction, LLT>
LegalizerInfo::getAction(const InstrAspect &Aspect) const {
  assert(TablesInitialized && "backend forgot to call computeTables");
  // These *have* to be implemented for now, they're the fundamental basis of
  // how everything else is transformed.

  // FIXME: the long-term plan calls for expansion in terms of load/store (if
  // they're not legal).
  if (Aspect.Opcode == TargetOpcode::G_MERGE_VALUES ||
      Aspect.Opcode == TargetOpcode::G_UNMERGE_VALUES)
    return std::make_pair(Legal, Aspect.Type);

  LLT Ty = Aspect.Type;
  LegalizeAction Action = findInActions(Aspect);
  // LegalizerHelper is not able to handle non-power-of-2 types right now, so do
  // not try to legalize them unless they are marked as Legal or Custom.
  // FIXME: This is a temporary hack until the general non-power-of-2
  // legalization works.
  if (!isPowerOf2_64(Ty.getSizeInBits()) &&
      !(Action == Legal || Action == Custom))
    return std::make_pair(Unsupported, LLT());

  if (Action != NotFound)
    return findLegalAction(Aspect, Action);

  unsigned Opcode = Aspect.Opcode;
  if (!Ty.isVector()) {
    auto DefaultAction = DefaultActions.find(Aspect.Opcode);
    if (DefaultAction != DefaultActions.end() && DefaultAction->second == Legal)
      return std::make_pair(Legal, Ty);

    if (DefaultAction != DefaultActions.end() && DefaultAction->second == Lower)
      return std::make_pair(Lower, Ty);

    if (DefaultAction == DefaultActions.end() ||
        DefaultAction->second != NarrowScalar)
      return std::make_pair(Unsupported, LLT());
    return findLegalAction(Aspect, NarrowScalar);
  }

  LLT EltTy = Ty.getElementType();
  int NumElts = Ty.getNumElements();

  auto ScalarAction = ScalarInVectorActions.find(std::make_pair(Opcode, EltTy));
  if (ScalarAction != ScalarInVectorActions.end() &&
      ScalarAction->second != Legal)
    return findLegalAction(Aspect, ScalarAction->second);

  // The element type is legal in principle, but the number of elements is
  // wrong.
  auto MaxLegalElts = MaxLegalVectorElts.lookup(std::make_pair(Opcode, EltTy));
  if (MaxLegalElts > NumElts)
    return findLegalAction(Aspect, MoreElements);

  if (MaxLegalElts == 0) {
    // Scalarize if there's no legal vector type, which is just a special case
    // of FewerElements.
    return std::make_pair(FewerElements, EltTy);
  }

  return findLegalAction(Aspect, FewerElements);
}

std::tuple<LegalizerInfo::LegalizeAction, unsigned, LLT>
LegalizerInfo::getAction(const MachineInstr &MI,
                         const MachineRegisterInfo &MRI) const {
  SmallBitVector SeenTypes(8);
  const MCOperandInfo *OpInfo = MI.getDesc().OpInfo;
  for (unsigned i = 0; i < MI.getDesc().getNumOperands(); ++i) {
    if (!OpInfo[i].isGenericType())
      continue;

    // We don't want to repeatedly check the same operand index, that
    // could get expensive.
    unsigned TypeIdx = OpInfo[i].getGenericTypeIndex();
    if (SeenTypes[TypeIdx])
      continue;

    SeenTypes.set(TypeIdx);

    LLT Ty = MRI.getType(MI.getOperand(i).getReg());
    auto Action = getAction({MI.getOpcode(), TypeIdx, Ty});
    if (Action.first != Legal)
      return std::make_tuple(Action.first, TypeIdx, Action.second);
  }
  return std::make_tuple(Legal, 0, LLT{});
}

bool LegalizerInfo::isLegal(const MachineInstr &MI,
                            const MachineRegisterInfo &MRI) const {
  return std::get<0>(getAction(MI, MRI)) == Legal;
}

Optional<LLT> LegalizerInfo::findLegalType(const InstrAspect &Aspect,
                                 LegalizeAction Action) const {
  switch(Action) {
  default:
    llvm_unreachable("Cannot find legal type");
  case Legal:
  case Lower:
  case Libcall:
  case Custom:
    return Aspect.Type;
  case NarrowScalar: {
    return findLegalizableSize(
        Aspect, [&](LLT Ty) -> LLT { return Ty.halfScalarSize(); });
  }
  case WidenScalar: {
    return findLegalizableSize(Aspect, [&](LLT Ty) -> LLT {
      return Ty.getSizeInBits() < 8 ? LLT::scalar(8) : Ty.doubleScalarSize();
    });
  }
  case FewerElements: {
    return findLegalizableSize(
        Aspect, [&](LLT Ty) -> LLT { return Ty.halfElements(); });
  }
  case MoreElements: {
    return findLegalizableSize(
        Aspect, [&](LLT Ty) -> LLT { return Ty.doubleElements(); });
  }
  }
}

bool LegalizerInfo::legalizeCustom(MachineInstr &MI,
                                   MachineRegisterInfo &MRI,
                                   MachineIRBuilder &MIRBuilder) const {
  return false;
}
<commit_msg>[LegalizerInfo] Don't evaluate end boundary every time through the loop<commit_after>//===- lib/CodeGen/GlobalISel/LegalizerInfo.cpp - Legalizer ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implement an interface to specify and query how an illegal operation on a
// given type should be expanded.
//
// Issues to be resolved:
//   + Make it fast.
//   + Support weird types like i3, <7 x i3>, ...
//   + Operations with more than one type (ICMP, CMPXCHG, intrinsics, ...)
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LowLevelTypeImpl.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetOpcodes.h"
#include <algorithm>
#include <cassert>
#include <tuple>
#include <utility>

using namespace llvm;

LegalizerInfo::LegalizerInfo() {
  DefaultActions[TargetOpcode::G_IMPLICIT_DEF] = NarrowScalar;

  // FIXME: these two can be legalized to the fundamental load/store Jakob
  // proposed. Once loads & stores are supported.
  DefaultActions[TargetOpcode::G_ANYEXT] = Legal;
  DefaultActions[TargetOpcode::G_TRUNC] = Legal;

  DefaultActions[TargetOpcode::G_INTRINSIC] = Legal;
  DefaultActions[TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS] = Legal;

  DefaultActions[TargetOpcode::G_ADD] = NarrowScalar;
  DefaultActions[TargetOpcode::G_LOAD] = NarrowScalar;
  DefaultActions[TargetOpcode::G_STORE] = NarrowScalar;
  DefaultActions[TargetOpcode::G_OR] = NarrowScalar;

  DefaultActions[TargetOpcode::G_BRCOND] = WidenScalar;
  DefaultActions[TargetOpcode::G_INSERT] = NarrowScalar;
  DefaultActions[TargetOpcode::G_EXTRACT] = NarrowScalar;
  DefaultActions[TargetOpcode::G_FNEG] = Lower;
}

void LegalizerInfo::computeTables() {
  for (unsigned Opcode = 0; Opcode <= LastOp - FirstOp; ++Opcode) {
    for (unsigned Idx = 0, End = Actions[Opcode].size(); Idx != End; ++Idx) {
      for (auto &Action : Actions[Opcode][Idx]) {
        LLT Ty = Action.first;
        if (!Ty.isVector())
          continue;

        auto &Entry = MaxLegalVectorElts[std::make_pair(Opcode + FirstOp,
                                                        Ty.getElementType())];
        Entry = std::max(Entry, Ty.getNumElements());
      }
    }
  }

  TablesInitialized = true;
}

// FIXME: inefficient implementation for now. Without ComputeValueVTs we're
// probably going to need specialized lookup structures for various types before
// we have any hope of doing well with something like <13 x i3>. Even the common
// cases should do better than what we have now.
std::pair<LegalizerInfo::LegalizeAction, LLT>
LegalizerInfo::getAction(const InstrAspect &Aspect) const {
  assert(TablesInitialized && "backend forgot to call computeTables");
  // These *have* to be implemented for now, they're the fundamental basis of
  // how everything else is transformed.

  // FIXME: the long-term plan calls for expansion in terms of load/store (if
  // they're not legal).
  if (Aspect.Opcode == TargetOpcode::G_MERGE_VALUES ||
      Aspect.Opcode == TargetOpcode::G_UNMERGE_VALUES)
    return std::make_pair(Legal, Aspect.Type);

  LLT Ty = Aspect.Type;
  LegalizeAction Action = findInActions(Aspect);
  // LegalizerHelper is not able to handle non-power-of-2 types right now, so do
  // not try to legalize them unless they are marked as Legal or Custom.
  // FIXME: This is a temporary hack until the general non-power-of-2
  // legalization works.
  if (!isPowerOf2_64(Ty.getSizeInBits()) &&
      !(Action == Legal || Action == Custom))
    return std::make_pair(Unsupported, LLT());

  if (Action != NotFound)
    return findLegalAction(Aspect, Action);

  unsigned Opcode = Aspect.Opcode;
  if (!Ty.isVector()) {
    auto DefaultAction = DefaultActions.find(Aspect.Opcode);
    if (DefaultAction != DefaultActions.end() && DefaultAction->second == Legal)
      return std::make_pair(Legal, Ty);

    if (DefaultAction != DefaultActions.end() && DefaultAction->second == Lower)
      return std::make_pair(Lower, Ty);

    if (DefaultAction == DefaultActions.end() ||
        DefaultAction->second != NarrowScalar)
      return std::make_pair(Unsupported, LLT());
    return findLegalAction(Aspect, NarrowScalar);
  }

  LLT EltTy = Ty.getElementType();
  int NumElts = Ty.getNumElements();

  auto ScalarAction = ScalarInVectorActions.find(std::make_pair(Opcode, EltTy));
  if (ScalarAction != ScalarInVectorActions.end() &&
      ScalarAction->second != Legal)
    return findLegalAction(Aspect, ScalarAction->second);

  // The element type is legal in principle, but the number of elements is
  // wrong.
  auto MaxLegalElts = MaxLegalVectorElts.lookup(std::make_pair(Opcode, EltTy));
  if (MaxLegalElts > NumElts)
    return findLegalAction(Aspect, MoreElements);

  if (MaxLegalElts == 0) {
    // Scalarize if there's no legal vector type, which is just a special case
    // of FewerElements.
    return std::make_pair(FewerElements, EltTy);
  }

  return findLegalAction(Aspect, FewerElements);
}

std::tuple<LegalizerInfo::LegalizeAction, unsigned, LLT>
LegalizerInfo::getAction(const MachineInstr &MI,
                         const MachineRegisterInfo &MRI) const {
  SmallBitVector SeenTypes(8);
  const MCInstrDesc &MCID = MI.getDesc();
  const MCOperandInfo *OpInfo = MCID.OpInfo;
  for (unsigned i = 0, e = MCID.getNumOperands(); i != e; ++i) {
    if (!OpInfo[i].isGenericType())
      continue;

    // We don't want to repeatedly check the same operand index, that
    // could get expensive.
    unsigned TypeIdx = OpInfo[i].getGenericTypeIndex();
    if (SeenTypes[TypeIdx])
      continue;

    SeenTypes.set(TypeIdx);

    LLT Ty = MRI.getType(MI.getOperand(i).getReg());
    auto Action = getAction({MI.getOpcode(), TypeIdx, Ty});
    if (Action.first != Legal)
      return std::make_tuple(Action.first, TypeIdx, Action.second);
  }
  return std::make_tuple(Legal, 0, LLT{});
}

bool LegalizerInfo::isLegal(const MachineInstr &MI,
                            const MachineRegisterInfo &MRI) const {
  return std::get<0>(getAction(MI, MRI)) == Legal;
}

Optional<LLT> LegalizerInfo::findLegalType(const InstrAspect &Aspect,
                                 LegalizeAction Action) const {
  switch(Action) {
  default:
    llvm_unreachable("Cannot find legal type");
  case Legal:
  case Lower:
  case Libcall:
  case Custom:
    return Aspect.Type;
  case NarrowScalar: {
    return findLegalizableSize(
        Aspect, [&](LLT Ty) -> LLT { return Ty.halfScalarSize(); });
  }
  case WidenScalar: {
    return findLegalizableSize(Aspect, [&](LLT Ty) -> LLT {
      return Ty.getSizeInBits() < 8 ? LLT::scalar(8) : Ty.doubleScalarSize();
    });
  }
  case FewerElements: {
    return findLegalizableSize(
        Aspect, [&](LLT Ty) -> LLT { return Ty.halfElements(); });
  }
  case MoreElements: {
    return findLegalizableSize(
        Aspect, [&](LLT Ty) -> LLT { return Ty.doubleElements(); });
  }
  }
}

bool LegalizerInfo::legalizeCustom(MachineInstr &MI,
                                   MachineRegisterInfo &MRI,
                                   MachineIRBuilder &MIRBuilder) const {
  return false;
}
<|endoftext|>


<commit_before>/*
 * This file is part of the CN24 semantic segmentation software,
 * copyright (C) 2015 Clemens-Alexander Brust (ikosa dot de at gmail dot com).
 *
 * For licensing information, see the LICENSE file included with this project.
 */
/**
 * @file networkGraph.cpp
 * @brief Writes a graphviz file displaying the network's architecture to standard output.
 *
 * @author Clemens-Alexander Brust(ikosa dot de at gmail dot com)
 */

#define NO_LOG_AT_ALL

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iomanip>
#include <ctime>
#include <cstring>

#include <cn24.h>
#include <private/ConfigParsing.h>

int main (int argc, char* argv[]) {
  if (argc < 3) {
    LOGERROR << "USAGE: " << argv[0] << " <dataset config file> <net config file>";
    LOGEND;
    return -1;
  }

  std::string net_config_fname (argv[2]);
  std::string dataset_config_fname (argv[1]);

	std::ostringstream ss;

  Conv::System::Init();

  // Open network and dataset configuration files
  std::ifstream net_config_file (net_config_fname, std::ios::in);
  std::ifstream dataset_config_file (dataset_config_fname, std::ios::in);

  if (!net_config_file.good()) {
    FATAL ("Cannot open net configuration file!");
  }

  net_config_fname = net_config_fname.substr (net_config_fname.rfind ("/") + 1);

  if (!dataset_config_file.good()) {
    FATAL ("Cannot open dataset configuration file!");
  }

  dataset_config_fname = dataset_config_fname.substr (net_config_fname.rfind ("/") + 1);

  // Parse network configuration file
  Conv::ConfigurableFactory* factory = new Conv::ConfigurableFactory (net_config_file, 8347734, true);
  factory->InitOptimalSettings();
  LOGDEBUG << "Optimal settings: " << factory->optimal_settings();

  // Extract important settings from parsed configuration
  unsigned int BATCHSIZE = factory->optimal_settings().pbatchsize;

  Conv::TrainerSettings settings = factory->optimal_settings();

  // Load dataset
  Conv::Dataset* dataset = nullptr;
	dataset = Conv::TensorStreamDataset::CreateFromConfiguration (dataset_config_file, false, Conv::LOAD_BOTH);

  unsigned int CLASSES = dataset->GetClasses();

  // Assemble net
  Conv::Net net;
  int data_layer_id = 0;

  Conv::DatasetInputLayer* data_layer = nullptr;

	data_layer = new Conv::DatasetInputLayer (*dataset, BATCHSIZE, 1.0, 983923);
	data_layer_id = net.AddLayer (data_layer);

  int output_layer_id =
    factory->AddLayers (net, Conv::Connection (data_layer_id), CLASSES, true, ss);

  LOGDEBUG << "Output layer id: " << output_layer_id;

  LOGINFO << "DONE!";
  LOGEND;

	std::cout << "\nGraph output:\ndigraph G {\n" << ss.str() << "\n}\n";
  return 0;
}<commit_msg>NetworkGraph forces PBatch size 1<commit_after>/*
 * This file is part of the CN24 semantic segmentation software,
 * copyright (C) 2015 Clemens-Alexander Brust (ikosa dot de at gmail dot com).
 *
 * For licensing information, see the LICENSE file included with this project.
 */
/**
 * @file networkGraph.cpp
 * @brief Writes a graphviz file displaying the network's architecture to standard output.
 *
 * @author Clemens-Alexander Brust(ikosa dot de at gmail dot com)
 */

#define NO_LOG_AT_ALL

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iomanip>
#include <ctime>
#include <cstring>

#include <cn24.h>
#include <private/ConfigParsing.h>

int main (int argc, char* argv[]) {
  if (argc < 3) {
    LOGERROR << "USAGE: " << argv[0] << " <dataset config file> <net config file>";
    LOGEND;
    return -1;
  }

  std::string net_config_fname (argv[2]);
  std::string dataset_config_fname (argv[1]);

	std::ostringstream ss;

  Conv::System::Init();

  // Open network and dataset configuration files
  std::ifstream net_config_file (net_config_fname, std::ios::in);
  std::ifstream dataset_config_file (dataset_config_fname, std::ios::in);

  if (!net_config_file.good()) {
    FATAL ("Cannot open net configuration file!");
  }

  net_config_fname = net_config_fname.substr (net_config_fname.rfind ("/") + 1);

  if (!dataset_config_file.good()) {
    FATAL ("Cannot open dataset configuration file!");
  }

  dataset_config_fname = dataset_config_fname.substr (net_config_fname.rfind ("/") + 1);

  // Parse network configuration file
  Conv::ConfigurableFactory* factory = new Conv::ConfigurableFactory (net_config_file, 8347734, false);
  factory->InitOptimalSettings();

  // Extract important settings from parsed configuration
  Conv::TrainerSettings settings = factory->optimal_settings();
	settings.pbatchsize = 1;
  unsigned int BATCHSIZE = settings.pbatchsize;
  LOGDEBUG << "Optimal settings: " << settings;

  // Load dataset
  Conv::Dataset* dataset = nullptr;
	dataset = Conv::TensorStreamDataset::CreateFromConfiguration (dataset_config_file, false, Conv::LOAD_BOTH);

  unsigned int CLASSES = dataset->GetClasses();

  // Assemble net
  Conv::Net net;
  int data_layer_id = 0;

  Conv::DatasetInputLayer* data_layer = nullptr;

	data_layer = new Conv::DatasetInputLayer (*dataset, BATCHSIZE, 1.0, 983923);
	data_layer_id = net.AddLayer (data_layer);

  int output_layer_id =
    factory->AddLayers (net, Conv::Connection (data_layer_id), CLASSES, true, ss);

  LOGDEBUG << "Output layer id: " << output_layer_id;

  LOGINFO << "DONE!";
  LOGEND;

	std::cout << "\nGraph output:\ndigraph G {\n" << ss.str() << "\n}\n";
  return 0;
}<|endoftext|>


<commit_before>#pragma once

#include "quantities/serialization.hpp"

#include "base/not_null.hpp"
#include "quantities/quantities.hpp"

namespace principia {

using base::not_null;

namespace quantities {

template<typename Dimensions, typename Message>
class QuantityOrDoubleSerializer<Quantity<Dimensions>, Message> {
 public:
  using T = Quantity<Dimensions>;
  static void WriteToMessage(T const& t, not_null<Message*> const message) {
    t.WriteToMessage(message->mutable_quantity());
  }

  static T ReadFromMessage(Message const& message) {
    CHECK(message.has_quantity());
    return T::ReadFromMessage(message.quantity());
  }
};

template<typename Message>
class QuantityOrDoubleSerializer<double, Message> {
 public:
  static void WriteToMessage(double const d,
                             not_null<Message*> const message) {
    message->set_double_(d);
  }

  static double ReadFromMessage(Message const& message) {
    CHECK(message.has_double_());
    return message.double_();
  }
};

}  // namespace quantities
}  // namespace principia
<commit_msg>Lint.<commit_after>#pragma once

#include "quantities/serialization.hpp"

#include "base/not_null.hpp"
#include "quantities/quantities.hpp"

namespace principia {

using base::not_null;

namespace quantities {

template<typename Dimensions, typename Message>
class QuantityOrDoubleSerializer<Quantity<Dimensions>, Message> {
 public:
  using T = Quantity<Dimensions>;
  static void WriteToMessage(T const& t, not_null<Message*> const message) {
    t.WriteToMessage(message->mutable_quantity());
  }

  static T ReadFromMessage(Message const& message) {
    CHECK(message.has_quantity());
    return T::ReadFromMessage(message.quantity());
  }
};

template<typename Message>
class QuantityOrDoubleSerializer<double, Message> {
 public:
  static void WriteToMessage(double const d,
                             not_null<Message*> const message) {
    message->set_double_(d);
  }

  static double ReadFromMessage(Message const& message) {
    CHECK(message.has_double_());
    return message.double_();
  }
};

}  // namespace quantities
}  // namespace principia
<|endoftext|>


<commit_before>/*************************************************************************
 *   Copyright (C) 2011-2012 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of TeapotNet.                                     *
 *                                                                       *
 *   TeapotNet is free software: you can redistribute it and/or modify   *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   TeapotNet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with TeapotNet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "tpn/yamlserializer.h"
#include "tpn/lineserializer.h"
#include "tpn/exception.h"
#include "tpn/serializable.h"

namespace tpn
{

YamlSerializer::YamlSerializer(Stream *stream, int outputLevel) :
	mStream(stream),
	mLevel(outputLevel)
{
	Assert(stream);
}

YamlSerializer::~YamlSerializer(void)
{

}

bool YamlSerializer::input(Serializable &s)
{
	if(mIndent.empty())
	{
		if(mLine.empty() && !mStream->readLine(mLine))
			return false;

		if(mLine.trimmed() == "...") return false;
		if(mLine.trimmed() == "---") mLine.clear();
	}

	if(s.isInlineSerializable() && !s.isNativeSerializable())
	{
		String line;
		if(!input(line)) return false;
		s.deserialize(line);
		return true;
	}
	else return s.deserialize(*this);
}

bool YamlSerializer::input(Element &element)
{
  	String trimmed = mLine.trimmed();
	while(trimmed.empty())
	{
		mLine.clear();
		if(!mStream->readLine(mLine))
		{
			if(!mIndent.empty()) mIndent.pop();
			return false;
		}

		trimmed =  mLine.trimmed();
	}

	if(trimmed == "..." || trimmed == "---")
		return false;

	if(!mIndent.empty())
	{
		int indent = 0;
		while(indent < mLine.size() &&
			(mLine[indent] == ' ' || mLine[indent] == '\t')) ++indent;

		if(mIndent.top() < 0)
		{
			mIndent.pop();
                	if((mIndent.empty() && indent == 0) || (!mIndent.empty() && mIndent.top() >= indent))
				return false;

			mIndent.push(indent);
		}
		else {
			if(indent < mIndent.top())
			{
				mIndent.pop();
				return false;
			}

			if(indent > mIndent.top())
				mIndent.top() = indent;
		}
	}

	mLine.trim();

	char chr;
	mLine.get(chr);
	if(chr != '-') throw IOException("Invalid array entry, missing '-'");

	AssertIO(mLine.get(chr));
	AssertIO(chr == ' ');

	mIndent.push(-1);
	AssertIO(element.deserialize(*this));
	if(!mIndent.empty()) mIndent.pop();
	return true;
}

bool YamlSerializer::input(Pair &pair)
{
	String trimmed = mLine.trimmed();
	while(trimmed.empty())
	{
		mLine.clear();
		if(!mStream->readLine(mLine))
		{
			if(!mIndent.empty()) mIndent.pop();
			return false;
		}

		trimmed =  mLine.trimmed();
	}

	if(trimmed == "..." || trimmed == "---")
		return false;

	if(!mIndent.empty())
	{
		int indent = 0;
		while(indent < mLine.size() &&
			(mLine[indent] == ' ' || mLine[indent] == '\t')) ++indent;

		if(mIndent.top() < 0)
                {
                        mIndent.pop();
                        if((mIndent.empty() && indent == 0) || (!mIndent.empty() && mIndent.top() >= indent))
                                return false;

                        mIndent.push(indent);
                }
                else {
                        if(indent < mIndent.top())
                        {
                                mIndent.pop();
                                return false;
                        }

                        if(indent > mIndent.top())
                                mIndent.top() = indent;
                }
	}

	mLine.trim();
	if(!mLine.contains(':')) throw IOException("Invalid associative entry, missing ':'");

	String key;
	while(true)
	{
		AssertIO(mLine.readUntil(key,':'));
		char chr;
		if(!mLine.get(chr) || chr == ' ') break;
		key+= ':';
		key+= chr;
	}

	LineSerializer keySerializer(&key);
	AssertIO(pair.deserializeKey(keySerializer));
	mIndent.push(-1);
	AssertIO(pair.deserializeValue(*this));
	if(!mIndent.empty()) mIndent.pop();
	return true;
}

bool YamlSerializer::input(String &str)
{
	str.clear();

	if(mIndent.empty())
	{
		if(mLine.empty() && !mStream->readLine(mLine))
			return false;

		if(mLine.trimmed() == "...") return false;
		if(mLine.trimmed() == "---") mLine.clear();
	}

	bool keepNewLines = true;
	int i = 0;
	while(true)
	{
		String trimmed =  mLine.trimmed();
		if(mIndent.empty() && (trimmed == "..." || trimmed == "---"))
			return i != 0;

		if(i == 0)
		{
			if(trimmed.empty() || trimmed == "|") keepNewLines = true;
			else if(trimmed == ">") keepNewLines = false;
			else {
				str = trimmed;
				mLine.clear();
				mStream->readLine(mLine);
				return true;
			}
		}
		else {
			if(!mIndent.empty())
			{
				int indent = 0;
				while(indent < mLine.size() &&
					(mLine[indent] == ' ' || mLine[indent] == '\t')) ++indent;

				if(mIndent.top() < 0)
                		{
                        		mIndent.pop();
                        		if((mIndent.empty() && indent == 0) || (!mIndent.empty() && mIndent.top() >= indent))
						return true;

                        		mIndent.push(indent);
                		}
                		else {
                        		if(indent < mIndent.top())
                        		{
                                		mIndent.pop();
						return true;
                        		}

                        		if(indent > mIndent.top())
                                		mIndent.top() = indent;
                		}
			}

			if(!str.empty())
                	{
                        	if(keepNewLines) str+= '\n';
                        	else str+= ' ';
                	}

                	mLine.trim();
                	str+= mLine;
		}

		mLine.clear();
		if(!mStream->readLine(mLine))
                	return true;

		++i;
	}
}

void YamlSerializer::output(const Serializable &s)
{
	if(!mLevel) *mStream<<"---";

	if(s.isInlineSerializable() && !s.isNativeSerializable()) output(s.toString());
	else s.serialize(*this);
}

void YamlSerializer::output(const Element &element)
{
	*mStream<<String(std::max(mLevel-1,0)*2, ' ');
	*mStream<<"-";
	element.serialize(*this);
	*mStream<<Stream::NewLine;
}

void YamlSerializer::output(const Pair &pair)
{
	*mStream<<String(std::max(mLevel-1,0)*2, ' ');
	String key;
	LineSerializer keySerializer(&key);
	pair.serializeKey(keySerializer);
	key.trim();
	*mStream<<key<<":";
	pair.serializeValue(*this);
	*mStream<<Stream::NewLine;
}

void YamlSerializer::output(const String &str)
{
	if(!mLevel) *mStream<<"---";

	if(str.empty())
	{
		if(mLevel) *mStream<<Stream::Space;
		return;
	}

	if(!mLevel || str.contains('\n') || str[0] == '|' || str[0] == '>')
	{
		*mStream<<" |"<<Stream::NewLine;

		String copy(str);
		String line;
		while(copy.readLine(line))
		{
			*mStream<<String(std::max(mLevel-1,0)*2, ' ');
			*mStream<<line;
			if(copy.last() == '\n') *mStream<<Stream::NewLine;
		}
	}
	else {
		if(mLevel) *mStream<<Stream::Space;
		*mStream<<str;
	}
}

bool YamlSerializer::inputArrayBegin(void)
{
	return !mStream->atEnd();
}

bool YamlSerializer::inputArrayCheck(void)
{
	return true;
}

bool YamlSerializer::inputMapBegin(void)
{
	return !mStream->atEnd();
}

bool YamlSerializer::inputMapCheck(void)
{
  	return true;
}

void YamlSerializer::outputArrayBegin(int size)
{
	*mStream<<Stream::NewLine;
	++mLevel;
}

void YamlSerializer::outputArrayEnd(void)
{
	Assert(mLevel > 0);
	--mLevel;
}

void YamlSerializer::outputMapBegin(int size)
{
	*mStream<<Stream::NewLine;
  	++mLevel;
}

void YamlSerializer::outputMapEnd(void)
{
	Assert(mLevel > 0);
	--mLevel;
}

void YamlSerializer::outputClose(void)
{
	*mStream<<"..."<<Stream::NewLine;
}

}
<commit_msg>Fixed multiline string output indentation<commit_after>/*************************************************************************
 *   Copyright (C) 2011-2012 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of TeapotNet.                                     *
 *                                                                       *
 *   TeapotNet is free software: you can redistribute it and/or modify   *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   TeapotNet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with TeapotNet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "tpn/yamlserializer.h"
#include "tpn/lineserializer.h"
#include "tpn/exception.h"
#include "tpn/serializable.h"

namespace tpn
{

YamlSerializer::YamlSerializer(Stream *stream, int outputLevel) :
	mStream(stream),
	mLevel(outputLevel)
{
	Assert(stream);
}

YamlSerializer::~YamlSerializer(void)
{

}

bool YamlSerializer::input(Serializable &s)
{
	if(mIndent.empty())
	{
		if(mLine.empty() && !mStream->readLine(mLine))
			return false;

		if(mLine.trimmed() == "...") return false;
		if(mLine.trimmed() == "---") mLine.clear();
	}

	if(s.isInlineSerializable() && !s.isNativeSerializable())
	{
		String line;
		if(!input(line)) return false;
		s.deserialize(line);
		return true;
	}
	else return s.deserialize(*this);
}

bool YamlSerializer::input(Element &element)
{
  	String trimmed = mLine.trimmed();
	while(trimmed.empty())
	{
		mLine.clear();
		if(!mStream->readLine(mLine))
		{
			if(!mIndent.empty()) mIndent.pop();
			return false;
		}

		trimmed =  mLine.trimmed();
	}

	if(trimmed == "..." || trimmed == "---")
		return false;

	if(!mIndent.empty())
	{
		int indent = 0;
		while(indent < mLine.size() &&
			(mLine[indent] == ' ' || mLine[indent] == '\t')) ++indent;

		if(mIndent.top() < 0)
		{
			mIndent.pop();
                	if((mIndent.empty() && indent == 0) || (!mIndent.empty() && mIndent.top() >= indent))
				return false;

			mIndent.push(indent);
		}
		else {
			if(indent < mIndent.top())
			{
				mIndent.pop();
				return false;
			}

			if(indent > mIndent.top())
				mIndent.top() = indent;
		}
	}

	mLine.trim();

	char chr;
	mLine.get(chr);
	if(chr != '-') throw IOException("Invalid array entry, missing '-'");

	AssertIO(mLine.get(chr));
	AssertIO(chr == ' ');

	mIndent.push(-1);
	AssertIO(element.deserialize(*this));
	if(!mIndent.empty()) mIndent.pop();
	return true;
}

bool YamlSerializer::input(Pair &pair)
{
	String trimmed = mLine.trimmed();
	while(trimmed.empty())
	{
		mLine.clear();
		if(!mStream->readLine(mLine))
		{
			if(!mIndent.empty()) mIndent.pop();
			return false;
		}

		trimmed =  mLine.trimmed();
	}

	if(trimmed == "..." || trimmed == "---")
		return false;

	if(!mIndent.empty())
	{
		int indent = 0;
		while(indent < mLine.size() &&
			(mLine[indent] == ' ' || mLine[indent] == '\t')) ++indent;

		if(mIndent.top() < 0)
                {
                        mIndent.pop();
                        if((mIndent.empty() && indent == 0) || (!mIndent.empty() && mIndent.top() >= indent))
                                return false;

                        mIndent.push(indent);
                }
                else {
                        if(indent < mIndent.top())
                        {
                                mIndent.pop();
                                return false;
                        }

                        if(indent > mIndent.top())
                                mIndent.top() = indent;
                }
	}

	mLine.trim();
	if(!mLine.contains(':')) throw IOException("Invalid associative entry, missing ':'");

	String key;
	while(true)
	{
		AssertIO(mLine.readUntil(key,':'));
		char chr;
		if(!mLine.get(chr) || chr == ' ') break;
		key+= ':';
		key+= chr;
	}

	LineSerializer keySerializer(&key);
	AssertIO(pair.deserializeKey(keySerializer));
	mIndent.push(-1);
	AssertIO(pair.deserializeValue(*this));
	if(!mIndent.empty()) mIndent.pop();
	return true;
}

bool YamlSerializer::input(String &str)
{
	str.clear();

	if(mIndent.empty())
	{
		if(mLine.empty() && !mStream->readLine(mLine))
			return false;

		if(mLine.trimmed() == "...") return false;
		if(mLine.trimmed() == "---") mLine.clear();
	}

	bool keepNewLines = true;
	int i = 0;
	while(true)
	{
		String trimmed =  mLine.trimmed();
		if(mIndent.empty() && (trimmed == "..." || trimmed == "---"))
			return i != 0;

		if(i == 0)
		{
			if(trimmed.empty() || trimmed == "|") keepNewLines = true;
			else if(trimmed == ">") keepNewLines = false;
			else {
				str = trimmed;
				mLine.clear();
				mStream->readLine(mLine);
				return true;
			}
		}
		else {
			if(!mIndent.empty())
			{
				int indent = 0;
				while(indent < mLine.size() &&
					(mLine[indent] == ' ' || mLine[indent] == '\t')) ++indent;

				if(mIndent.top() < 0)
                		{
                        		mIndent.pop();
                        		if((mIndent.empty() && indent == 0) || (!mIndent.empty() && mIndent.top() >= indent))
						return true;

                        		mIndent.push(indent);
                		}
                		else {
                        		if(indent < mIndent.top())
                        		{
                                		mIndent.pop();
						return true;
                        		}

                        		if(indent > mIndent.top())
                                		mIndent.top() = indent;
                		}
			}

			if(!str.empty())
                	{
                        	if(keepNewLines) str+= '\n';
                        	else str+= ' ';
                	}

                	mLine.trim();
                	str+= mLine;
		}

		mLine.clear();
		if(!mStream->readLine(mLine))
                	return true;

		++i;
	}
}

void YamlSerializer::output(const Serializable &s)
{
	if(!mLevel) *mStream<<"---";

	if(s.isInlineSerializable() && !s.isNativeSerializable()) output(s.toString());
	else s.serialize(*this);
}

void YamlSerializer::output(const Element &element)
{
	*mStream<<String(std::max(mLevel-1,0)*2, ' ');
	*mStream<<"-";
	element.serialize(*this);
	*mStream<<Stream::NewLine;
}

void YamlSerializer::output(const Pair &pair)
{
	*mStream<<String(std::max(mLevel-1,0)*2, ' ');
	String key;
	LineSerializer keySerializer(&key);
	pair.serializeKey(keySerializer);
	key.trim();
	*mStream<<key<<":";
	pair.serializeValue(*this);
	*mStream<<Stream::NewLine;
}

void YamlSerializer::output(const String &str)
{
	if(!mLevel) *mStream<<"---";

	if(str.empty())
	{
		if(mLevel) *mStream<<Stream::Space;
		return;
	}

	if(!mLevel || str.contains('\n') || str[0] == '|' || str[0] == '>')
	{
		*mStream<<" |"<<Stream::NewLine;

		String copy(str);
		String line;
		while(copy.readLine(line))
		{
			*mStream<<String(mLevel*2, ' ');
			*mStream<<line;
			if(copy.last() == '\n') *mStream<<Stream::NewLine;
		}
	}
	else {
		if(mLevel) *mStream<<Stream::Space;
		*mStream<<str;
	}
}

bool YamlSerializer::inputArrayBegin(void)
{
	return !mStream->atEnd();
}

bool YamlSerializer::inputArrayCheck(void)
{
	return true;
}

bool YamlSerializer::inputMapBegin(void)
{
	return !mStream->atEnd();
}

bool YamlSerializer::inputMapCheck(void)
{
  	return true;
}

void YamlSerializer::outputArrayBegin(int size)
{
	*mStream<<Stream::NewLine;
	++mLevel;
}

void YamlSerializer::outputArrayEnd(void)
{
	Assert(mLevel > 0);
	--mLevel;
}

void YamlSerializer::outputMapBegin(int size)
{
	*mStream<<Stream::NewLine;
  	++mLevel;
}

void YamlSerializer::outputMapEnd(void)
{
	Assert(mLevel > 0);
	--mLevel;
}

void YamlSerializer::outputClose(void)
{
	*mStream<<"..."<<Stream::NewLine;
}

}
<|endoftext|>


<commit_before><commit_msg>lokdocview: GList -> std::vector<commit_after><|endoftext|>


<commit_before>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: matlab/+eos/+fitting/private/fitting.cpp
 *
 * Copyright 2016 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "eos/fitting/fitting.hpp"
#include "eos/core/LandmarkMapper.hpp"
#include "eos/core/Mesh.hpp"
#include "eos/fitting/RenderingParameters.hpp"
#include "eos/fitting/contour_correspondence.hpp"
#include "eos/morphablemodel/Blendshape.hpp"
#include "eos/morphablemodel/EdgeTopology.hpp"
#include "eos/morphablemodel/MorphableModel.hpp"

#include "mexplus_eigen.hpp"
#include "mexplus_eos_types.hpp"

#include "mexplus.h"

#include "Eigen/Core"

#include "mex.h"
//#include "matrix.h"

#include <optional>
#include <string>

using namespace eos;
using namespace mexplus;

void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
    using std::string;
    // Check for proper number of input and output arguments:
    if (nrhs != 12)
    {
        mexErrMsgIdAndTxt("eos:fitting:nargin", "fit_shape_and_pose requires 12 input arguments.");
    }
    if (nlhs != 2)
    {
        mexErrMsgIdAndTxt("eos:fitting:nargout", "fit_shape_and_pose returns two output arguments.");
    }

    InputArguments input(nrhs, prhs, 12);
    const auto morphablemodel_file = input.get<string>(0);
    const auto blendshapes_file = input.get<string>(1);
    const auto landmarks_in = input.get<Eigen::MatrixXd>(2);
    const auto mapper_file = input.get<string>(3);
    const auto image_width = input.get<int>(4);
    const auto image_height = input.get<int>(5);
    const auto edgetopo_file = input.get<string>(6);
    const auto contour_lms_file = input.get<string>(7);
    const auto model_cnt_file = input.get<string>(8);
    const auto num_iterations = input.get<int>(9);
    const auto num_shape_coeffs = input.get<int>(10);
    const auto lambda = input.get<double>(11);

    if (landmarks_in.rows() != 68)
    {
        mexErrMsgIdAndTxt(
            "eos:fitting:argin",
            "Given landmarks must be a 68 x 2 vector with ibug landmarks, in the order from 1 to 68.");
    }
    // Convert the landmarks (given as matrix in Matlab) to a LandmarkCollection:
    core::LandmarkCollection<Eigen::Vector2f> landmarks;
    for (int i = 0; i < 68; ++i)
    {
        landmarks.push_back(core::Landmark<Eigen::Vector2f>{
            std::to_string(i + 1), Eigen::Vector2f(landmarks_in(i, 0), landmarks_in(i, 1))});
    }

    // Load everything:
    const auto morphable_model = morphablemodel::load_model(morphablemodel_file);
    const auto blendshapes = morphablemodel::load_blendshapes(blendshapes_file);
    const core::LandmarkMapper landmark_mapper(mapper_file);
    const auto edge_topology = morphablemodel::load_edge_topology(edgetopo_file);
    const auto contour_landmarks = fitting::ContourLandmarks::load(contour_lms_file);
    const auto model_contour = fitting::ModelContour::load(model_cnt_file);
    const std::optional<int> num_shape_coefficients_to_fit =
        num_shape_coeffs == -1 ? std::nullopt : std::optional<int>(num_shape_coeffs);

    // Now do the actual fitting:
    core::Mesh mesh;
    fitting::RenderingParameters rendering_parameters;
    std::tie(mesh, rendering_parameters) = fitting::fit_shape_and_pose(
        morphable_model, blendshapes, landmarks, landmark_mapper, image_width, image_height, edge_topology,
        contour_landmarks, model_contour, num_iterations, num_shape_coefficients_to_fit, lambda);

    // Return the mesh and the rendering_parameters:
    OutputArguments output(nlhs, plhs, 2);
    output.set(0, mesh);
    output.set(1, rendering_parameters);
};
<commit_msg>Put num_in/out args in a variable; update copyright<commit_after>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: matlab/+eos/+fitting/private/fitting.cpp
 *
 * Copyright 2016-2018 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "eos/fitting/fitting.hpp"
#include "eos/core/LandmarkMapper.hpp"
#include "eos/core/Mesh.hpp"
#include "eos/fitting/RenderingParameters.hpp"
#include "eos/fitting/contour_correspondence.hpp"
#include "eos/morphablemodel/Blendshape.hpp"
#include "eos/morphablemodel/EdgeTopology.hpp"
#include "eos/morphablemodel/MorphableModel.hpp"

#include "mexplus_eigen.hpp"
#include "mexplus_eos_types.hpp"

#include "mexplus.h"

#include "Eigen/Core"

#include "mex.h"
//#include "matrix.h"

#include <optional>
#include <string>

using namespace eos;
using namespace mexplus;

void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
    using std::string;
    // Check for proper number of input and output arguments:
    int num_input_args = 12;
    int num_output_args = 2;
    if (nrhs != num_input_args)
    {
        mexErrMsgIdAndTxt("eos:fitting:nargin", "fit_shape_and_pose requires 12 input arguments.");
    }
    if (nlhs != num_output_args)
    {
        mexErrMsgIdAndTxt("eos:fitting:nargout", "fit_shape_and_pose returns two output arguments.");
    }

    InputArguments input(nrhs, prhs, num_input_args);
    const auto morphablemodel_file = input.get<string>(0);
    const auto blendshapes_file = input.get<string>(1);
    const auto landmarks_in = input.get<Eigen::MatrixXd>(2);
    const auto mapper_file = input.get<string>(3);
    const auto image_width = input.get<int>(4);
    const auto image_height = input.get<int>(5);
    const auto edgetopo_file = input.get<string>(6);
    const auto contour_lms_file = input.get<string>(7);
    const auto model_cnt_file = input.get<string>(8);
    const auto num_iterations = input.get<int>(9);
    const auto num_shape_coeffs = input.get<int>(10);
    const auto lambda = input.get<double>(11);

    if (landmarks_in.rows() != 68)
    {
        mexErrMsgIdAndTxt(
            "eos:fitting:argin",
            "Given landmarks must be a 68 x 2 vector with ibug landmarks, in the order from 1 to 68.");
    }
    // Convert the landmarks (given as matrix in Matlab) to a LandmarkCollection:
    core::LandmarkCollection<Eigen::Vector2f> landmarks;
    for (int i = 0; i < 68; ++i)
    {
        landmarks.push_back(core::Landmark<Eigen::Vector2f>{
            std::to_string(i + 1), Eigen::Vector2f(landmarks_in(i, 0), landmarks_in(i, 1))});
    }

    // Load everything:
    const auto morphable_model = morphablemodel::load_model(morphablemodel_file);
    const auto blendshapes = morphablemodel::load_blendshapes(blendshapes_file);
    const core::LandmarkMapper landmark_mapper(mapper_file);
    const auto edge_topology = morphablemodel::load_edge_topology(edgetopo_file);
    const auto contour_landmarks = fitting::ContourLandmarks::load(contour_lms_file);
    const auto model_contour = fitting::ModelContour::load(model_cnt_file);
    const std::optional<int> num_shape_coefficients_to_fit =
        num_shape_coeffs == -1 ? std::nullopt : std::optional<int>(num_shape_coeffs);

    // Now do the actual fitting:
    core::Mesh mesh;
    fitting::RenderingParameters rendering_parameters;
    std::tie(mesh, rendering_parameters) = fitting::fit_shape_and_pose(
        morphable_model, blendshapes, landmarks, landmark_mapper, image_width, image_height, edge_topology,
        contour_landmarks, model_contour, num_iterations, num_shape_coefficients_to_fit, lambda);

    // Return the mesh and the rendering_parameters:
    OutputArguments output(nlhs, plhs, num_output_args);
    output.set(0, mesh);
    output.set(1, rendering_parameters);
};
<|endoftext|>