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

#ifndef UAVCAN_NODE_SERVICE_CLIENT_HPP_INCLUDED
#define UAVCAN_NODE_SERVICE_CLIENT_HPP_INCLUDED

#include <uavcan/build_config.hpp>
#include <uavcan/node/generic_publisher.hpp>
#include <uavcan/node/generic_subscriber.hpp>

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

#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
# include <functional>
#endif

namespace uavcan
{

template <typename ServiceDataType>
class UAVCAN_EXPORT ServiceResponseTransferListenerInstantiationHelper
{
public: // so much templating it hurts
    typedef typename TransferListenerInstantiationHelper<typename ServiceDataType::Response,
                                                         1, 1, ServiceResponseTransferListener>::Type Type;
};

/**
 * Object of this type will be returned to the application as a result of service call.
 * Note that application ALWAYS gets this result, even when it times out or fails because of some other reason.
 */
template <typename DataType>
struct UAVCAN_EXPORT ServiceCallResult
{
    typedef ReceivedDataStructure<typename DataType::Response> ResponseFieldType;

    enum Status { Success, ErrorTimeout };

    const Status status;              ///< Whether successful or not. Failure to decode the response causes timeout.
    NodeID server_node_id;            ///< Node ID of the server this call was addressed to.
    ResponseFieldType& response;      ///< Returned data structure. Undefined if the service call has failed.

    ServiceCallResult(Status arg_status, NodeID arg_server_node_id, ResponseFieldType& arg_response)
        : status(arg_status)
        , server_node_id(arg_server_node_id)
        , response(arg_response)
    {
        UAVCAN_ASSERT(server_node_id.isUnicast());
        UAVCAN_ASSERT((status == Success) || (status == ErrorTimeout));
    }

    /**
     * Shortcut to quickly check whether the call was successful.
     */
    bool isSuccessful() const { return status == Success; }
};

/**
 * This operator neatly prints the service call result prepended with extra data like Server Node ID.
 * The extra data will be represented as YAML comment.
 */
template <typename Stream, typename DataType>
static Stream& operator<<(Stream& s, const ServiceCallResult<DataType>& scr)
{
    s << "# Service call result [" << DataType::getDataTypeFullName() << "] "
      << (scr.isSuccessful() ? "OK" : "FAILURE")
      << " server_node_id=" << int(scr.server_node_id.get()) << "\n";
    if (scr.isSuccessful())
    {
        s << scr.response;
    }
    else
    {
        s << "# (no data)";
    }
    return s;
}

/**
 * Do not use directly.
 */
class ServiceClientBase : protected DeadlineHandler
{
    const DataTypeDescriptor* data_type_descriptor_;  ///< This will be initialized at the time of first call

protected:
    MonotonicDuration request_timeout_;
    bool pending_;

    explicit ServiceClientBase(INode& node)
        : DeadlineHandler(node.getScheduler())
        , data_type_descriptor_(NULL)
        , request_timeout_(getDefaultRequestTimeout())
        , pending_(false)
    { }

    virtual ~ServiceClientBase() { }

    int prepareToCall(INode& node, const char* dtname, NodeID server_node_id, TransferID& out_transfer_id);

public:
    /**
     * Returns true if the service call is currently in progress.
     */
    bool isPending() const { return pending_; }

    /**
     * It's not recommended to override default timeouts.
     */
    static MonotonicDuration getDefaultRequestTimeout() { return MonotonicDuration::fromMSec(1000); }
    static MonotonicDuration getMinRequestTimeout() { return MonotonicDuration::fromMSec(10); }
    static MonotonicDuration getMaxRequestTimeout() { return MonotonicDuration::fromMSec(60000); }

    /**
     * Returns the service response waiting deadline, if pending.
     */
    using DeadlineHandler::getDeadline;
};

/**
 * Use this class to invoke services on remote nodes.
 *
 * @tparam DataType_        Service data type.
 *
 * @tparam Callback_        Service response will be delivered through the callback of this type.
 *                          In C++11 mode this type defaults to std::function<>.
 *                          In C++03 mode this type defaults to a plain function pointer; use binder to
 *                          call member functions as callbacks.
 */
template <typename DataType_,
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
          typename Callback_ = std::function<void (const ServiceCallResult<DataType_>&)>
#else
          typename Callback_ = void (*)(const ServiceCallResult<DataType_>&)
#endif
          >
class UAVCAN_EXPORT ServiceClient
    : public GenericSubscriber<DataType_, typename DataType_::Response,
                               typename ServiceResponseTransferListenerInstantiationHelper<DataType_>::Type >
    , public ServiceClientBase
{
public:
    typedef DataType_ DataType;
    typedef typename DataType::Request RequestType;
    typedef typename DataType::Response ResponseType;
    typedef ServiceCallResult<DataType> ServiceCallResultType;
    typedef Callback_ Callback;

private:
    typedef ServiceClient<DataType, Callback> SelfType;
    typedef GenericPublisher<DataType, RequestType> PublisherType;
    typedef typename ServiceResponseTransferListenerInstantiationHelper<DataType>::Type TransferListenerType;
    typedef GenericSubscriber<DataType, ResponseType, TransferListenerType> SubscriberType;

    PublisherType publisher_;
    Callback callback_;

    bool isCallbackValid() const { return try_implicit_cast<bool>(callback_, true); }

    void invokeCallback(ServiceCallResultType& result);

    virtual void handleReceivedDataStruct(ReceivedDataStructure<ResponseType>& response);

    virtual void handleDeadline(MonotonicTime);

public:
    /**
     * @param node      Node instance this client will be registered with.
     * @param callback  Callback instance. Optional, can be assigned later.
     */
    explicit ServiceClient(INode& node, const Callback& callback = Callback())
        : SubscriberType(node)
        , ServiceClientBase(node)
        , publisher_(node, getDefaultRequestTimeout())
        , callback_(callback)
    {
        setRequestTimeout(getDefaultRequestTimeout());
#if UAVCAN_DEBUG
        UAVCAN_ASSERT(getRequestTimeout() == getDefaultRequestTimeout());  // Making sure default values are OK
#endif
    }

    virtual ~ServiceClient() { cancel(); }

    /**
     * Shall be called before first use.
     * Returns negative error code.
     */
    int init()
    {
        return publisher_.init();
    }

    /**
     * Performs non-blocking service call.
     * This method transmits the service request and returns immediately.
     *
     * Service response will be delivered into the application via the callback.
     * Note that the callback will ALWAYS be called even if the service call has timed out; the
     * actual result of the call (success/failure) will be passed to the callback as well.
     *
     * If this client instance is already pending service response, it will be cancelled and the new
     * call will be performed.
     *
     * Returns negative error code.
     */
    int call(NodeID server_node_id, const RequestType& request);

    /**
     * Cancel the pending service call.
     * Does nothing if it is not pending.
     */
    void cancel();

    /**
     * Service response callback must be set prior service call.
     */
    const Callback& getCallback() const { return callback_; }
    void setCallback(const Callback& cb) { callback_ = cb; }

    /**
     * Returns the number of failed attempts to decode received response. Generally, a failed attempt means either:
     * - Transient failure in the transport layer.
     * - Incompatible data types.
     */
    uint32_t getResponseFailureCount() const { return SubscriberType::getFailureCount(); }

    /**
     * Request timeouts.
     * There is no such config as TX timeout - TX timeouts are configured automagically according to request timeouts.
     * Not recommended to change.
     */
    MonotonicDuration getRequestTimeout() const { return request_timeout_; }
    void setRequestTimeout(MonotonicDuration timeout)
    {
        timeout = max(timeout, getMinRequestTimeout());
        timeout = min(timeout, getMaxRequestTimeout());

        publisher_.setTxTimeout(timeout);
        request_timeout_ = max(timeout, publisher_.getTxTimeout());  // No less than TX timeout
    }
};

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

template <typename DataType_, typename Callback_>
void ServiceClient<DataType_, Callback_>::invokeCallback(ServiceCallResultType& result)
{
    if (isCallbackValid())
    {
        callback_(result);
    }
    else
    {
        handleFatalError("Srv client clbk");
    }
}

template <typename DataType_, typename Callback_>
void ServiceClient<DataType_, Callback_>::handleReceivedDataStruct(ReceivedDataStructure<ResponseType>& response)
{
    UAVCAN_ASSERT(response.getTransferType() == TransferTypeServiceResponse);
    const TransferListenerType* const listener = SubscriberType::getTransferListener();
    if (listener)
    {
        const typename TransferListenerType::ExpectedResponseParams erp = listener->getExpectedResponseParams();
        ServiceCallResultType result(ServiceCallResultType::Success, erp.src_node_id, response);
        cancel();
        invokeCallback(result);
    }
    else
    {
        UAVCAN_ASSERT(0);
        cancel();
    }
}

template <typename DataType_, typename Callback_>
void ServiceClient<DataType_, Callback_>::handleDeadline(MonotonicTime)
{
    const TransferListenerType* const listener = SubscriberType::getTransferListener();
    if (listener)
    {
        const typename TransferListenerType::ExpectedResponseParams erp = listener->getExpectedResponseParams();
        ReceivedDataStructure<ResponseType>& ref = SubscriberType::getReceivedStructStorage();
        ServiceCallResultType result(ServiceCallResultType::ErrorTimeout, erp.src_node_id, ref);

        UAVCAN_TRACE("ServiceClient", "Timeout from nid=%i, dtname=%s",
                     erp.src_node_id.get(), DataType::getDataTypeFullName());
        cancel();
        invokeCallback(result);
    }
    else
    {
        UAVCAN_ASSERT(0);
        cancel();
    }
}

template <typename DataType_, typename Callback_>
int ServiceClient<DataType_, Callback_>::call(NodeID server_node_id, const RequestType& request)
{
    cancel();
    if (!isCallbackValid())
    {
        UAVCAN_TRACE("ServiceClient", "Invalid callback");
        return -ErrInvalidParam;
    }

    /*
     * Common procedures that don't depend on the struct data type
     */
    TransferID transfer_id;
    const int prep_res =
        prepareToCall(SubscriberType::getNode(), DataType::getDataTypeFullName(), server_node_id, transfer_id);
    if (prep_res < 0)
    {
        UAVCAN_TRACE("ServiceClient", "Failed to prepare the call, error: %i", prep_res);
        cancel();
        return prep_res;
    }

    /*
     * Starting the subscriber
     */
    const int subscriber_res = SubscriberType::startAsServiceResponseListener();
    if (subscriber_res < 0)
    {
        UAVCAN_TRACE("ServiceClient", "Failed to start the subscriber, error: %i", subscriber_res);
        cancel();
        return subscriber_res;
    }

    /*
     * Configuring the listener so it will accept only the matching response
     */
    TransferListenerType* const tl = SubscriberType::getTransferListener();
    if (!tl)
    {
        UAVCAN_ASSERT(0);  // Must have been created
        cancel();
        return -ErrLogic;
    }
    const typename TransferListenerType::ExpectedResponseParams erp(server_node_id, transfer_id);
    tl->setExpectedResponseParams(erp);

    /*
     * Publishing the request
     */
    const int publisher_res = publisher_.publish(request, TransferTypeServiceRequest, server_node_id, transfer_id);
    if (!publisher_res)
    {
        cancel();
    }
    return publisher_res;
}

template <typename DataType_, typename Callback_>
void ServiceClient<DataType_, Callback_>::cancel()
{
    pending_ = false;
    SubscriberType::stop();
    DeadlineHandler::stop();
    TransferListenerType* const tl = SubscriberType::getTransferListener();
    if (tl)
    {
        tl->stopAcceptingAnything();
    }
}

}

#endif // UAVCAN_NODE_SERVICE_CLIENT_HPP_INCLUDED
<commit_msg>Fixed error handling in ServiceClient<commit_after>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#ifndef UAVCAN_NODE_SERVICE_CLIENT_HPP_INCLUDED
#define UAVCAN_NODE_SERVICE_CLIENT_HPP_INCLUDED

#include <uavcan/build_config.hpp>
#include <uavcan/node/generic_publisher.hpp>
#include <uavcan/node/generic_subscriber.hpp>

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

#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
# include <functional>
#endif

namespace uavcan
{

template <typename ServiceDataType>
class UAVCAN_EXPORT ServiceResponseTransferListenerInstantiationHelper
{
public: // so much templating it hurts
    typedef typename TransferListenerInstantiationHelper<typename ServiceDataType::Response,
                                                         1, 1, ServiceResponseTransferListener>::Type Type;
};

/**
 * Object of this type will be returned to the application as a result of service call.
 * Note that application ALWAYS gets this result, even when it times out or fails because of some other reason.
 */
template <typename DataType>
struct UAVCAN_EXPORT ServiceCallResult
{
    typedef ReceivedDataStructure<typename DataType::Response> ResponseFieldType;

    enum Status { Success, ErrorTimeout };

    const Status status;              ///< Whether successful or not. Failure to decode the response causes timeout.
    NodeID server_node_id;            ///< Node ID of the server this call was addressed to.
    ResponseFieldType& response;      ///< Returned data structure. Undefined if the service call has failed.

    ServiceCallResult(Status arg_status, NodeID arg_server_node_id, ResponseFieldType& arg_response)
        : status(arg_status)
        , server_node_id(arg_server_node_id)
        , response(arg_response)
    {
        UAVCAN_ASSERT(server_node_id.isUnicast());
        UAVCAN_ASSERT((status == Success) || (status == ErrorTimeout));
    }

    /**
     * Shortcut to quickly check whether the call was successful.
     */
    bool isSuccessful() const { return status == Success; }
};

/**
 * This operator neatly prints the service call result prepended with extra data like Server Node ID.
 * The extra data will be represented as YAML comment.
 */
template <typename Stream, typename DataType>
static Stream& operator<<(Stream& s, const ServiceCallResult<DataType>& scr)
{
    s << "# Service call result [" << DataType::getDataTypeFullName() << "] "
      << (scr.isSuccessful() ? "OK" : "FAILURE")
      << " server_node_id=" << int(scr.server_node_id.get()) << "\n";
    if (scr.isSuccessful())
    {
        s << scr.response;
    }
    else
    {
        s << "# (no data)";
    }
    return s;
}

/**
 * Do not use directly.
 */
class ServiceClientBase : protected DeadlineHandler
{
    const DataTypeDescriptor* data_type_descriptor_;  ///< This will be initialized at the time of first call

protected:
    MonotonicDuration request_timeout_;
    bool pending_;

    explicit ServiceClientBase(INode& node)
        : DeadlineHandler(node.getScheduler())
        , data_type_descriptor_(NULL)
        , request_timeout_(getDefaultRequestTimeout())
        , pending_(false)
    { }

    virtual ~ServiceClientBase() { }

    int prepareToCall(INode& node, const char* dtname, NodeID server_node_id, TransferID& out_transfer_id);

public:
    /**
     * Returns true if the service call is currently in progress.
     */
    bool isPending() const { return pending_; }

    /**
     * It's not recommended to override default timeouts.
     */
    static MonotonicDuration getDefaultRequestTimeout() { return MonotonicDuration::fromMSec(1000); }
    static MonotonicDuration getMinRequestTimeout() { return MonotonicDuration::fromMSec(10); }
    static MonotonicDuration getMaxRequestTimeout() { return MonotonicDuration::fromMSec(60000); }

    /**
     * Returns the service response waiting deadline, if pending.
     */
    using DeadlineHandler::getDeadline;
};

/**
 * Use this class to invoke services on remote nodes.
 *
 * @tparam DataType_        Service data type.
 *
 * @tparam Callback_        Service response will be delivered through the callback of this type.
 *                          In C++11 mode this type defaults to std::function<>.
 *                          In C++03 mode this type defaults to a plain function pointer; use binder to
 *                          call member functions as callbacks.
 */
template <typename DataType_,
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
          typename Callback_ = std::function<void (const ServiceCallResult<DataType_>&)>
#else
          typename Callback_ = void (*)(const ServiceCallResult<DataType_>&)
#endif
          >
class UAVCAN_EXPORT ServiceClient
    : public GenericSubscriber<DataType_, typename DataType_::Response,
                               typename ServiceResponseTransferListenerInstantiationHelper<DataType_>::Type >
    , public ServiceClientBase
{
public:
    typedef DataType_ DataType;
    typedef typename DataType::Request RequestType;
    typedef typename DataType::Response ResponseType;
    typedef ServiceCallResult<DataType> ServiceCallResultType;
    typedef Callback_ Callback;

private:
    typedef ServiceClient<DataType, Callback> SelfType;
    typedef GenericPublisher<DataType, RequestType> PublisherType;
    typedef typename ServiceResponseTransferListenerInstantiationHelper<DataType>::Type TransferListenerType;
    typedef GenericSubscriber<DataType, ResponseType, TransferListenerType> SubscriberType;

    PublisherType publisher_;
    Callback callback_;

    bool isCallbackValid() const { return try_implicit_cast<bool>(callback_, true); }

    void invokeCallback(ServiceCallResultType& result);

    virtual void handleReceivedDataStruct(ReceivedDataStructure<ResponseType>& response);

    virtual void handleDeadline(MonotonicTime);

public:
    /**
     * @param node      Node instance this client will be registered with.
     * @param callback  Callback instance. Optional, can be assigned later.
     */
    explicit ServiceClient(INode& node, const Callback& callback = Callback())
        : SubscriberType(node)
        , ServiceClientBase(node)
        , publisher_(node, getDefaultRequestTimeout())
        , callback_(callback)
    {
        setRequestTimeout(getDefaultRequestTimeout());
#if UAVCAN_DEBUG
        UAVCAN_ASSERT(getRequestTimeout() == getDefaultRequestTimeout());  // Making sure default values are OK
#endif
    }

    virtual ~ServiceClient() { cancel(); }

    /**
     * Shall be called before first use.
     * Returns negative error code.
     */
    int init()
    {
        return publisher_.init();
    }

    /**
     * Performs non-blocking service call.
     * This method transmits the service request and returns immediately.
     *
     * Service response will be delivered into the application via the callback.
     * Note that the callback will ALWAYS be called even if the service call has timed out; the
     * actual result of the call (success/failure) will be passed to the callback as well.
     *
     * If this client instance is already pending service response, it will be cancelled and the new
     * call will be performed.
     *
     * Returns negative error code.
     */
    int call(NodeID server_node_id, const RequestType& request);

    /**
     * Cancel the pending service call.
     * Does nothing if it is not pending.
     */
    void cancel();

    /**
     * Service response callback must be set prior service call.
     */
    const Callback& getCallback() const { return callback_; }
    void setCallback(const Callback& cb) { callback_ = cb; }

    /**
     * Returns the number of failed attempts to decode received response. Generally, a failed attempt means either:
     * - Transient failure in the transport layer.
     * - Incompatible data types.
     */
    uint32_t getResponseFailureCount() const { return SubscriberType::getFailureCount(); }

    /**
     * Request timeouts.
     * There is no such config as TX timeout - TX timeouts are configured automagically according to request timeouts.
     * Not recommended to change.
     */
    MonotonicDuration getRequestTimeout() const { return request_timeout_; }
    void setRequestTimeout(MonotonicDuration timeout)
    {
        timeout = max(timeout, getMinRequestTimeout());
        timeout = min(timeout, getMaxRequestTimeout());

        publisher_.setTxTimeout(timeout);
        request_timeout_ = max(timeout, publisher_.getTxTimeout());  // No less than TX timeout
    }
};

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

template <typename DataType_, typename Callback_>
void ServiceClient<DataType_, Callback_>::invokeCallback(ServiceCallResultType& result)
{
    if (isCallbackValid())
    {
        callback_(result);
    }
    else
    {
        handleFatalError("Srv client clbk");
    }
}

template <typename DataType_, typename Callback_>
void ServiceClient<DataType_, Callback_>::handleReceivedDataStruct(ReceivedDataStructure<ResponseType>& response)
{
    UAVCAN_ASSERT(response.getTransferType() == TransferTypeServiceResponse);
    const TransferListenerType* const listener = SubscriberType::getTransferListener();
    if (listener)
    {
        const typename TransferListenerType::ExpectedResponseParams erp = listener->getExpectedResponseParams();
        ServiceCallResultType result(ServiceCallResultType::Success, erp.src_node_id, response);
        cancel();
        invokeCallback(result);
    }
    else
    {
        UAVCAN_ASSERT(0);
        cancel();
    }
}

template <typename DataType_, typename Callback_>
void ServiceClient<DataType_, Callback_>::handleDeadline(MonotonicTime)
{
    const TransferListenerType* const listener = SubscriberType::getTransferListener();
    if (listener)
    {
        const typename TransferListenerType::ExpectedResponseParams erp = listener->getExpectedResponseParams();
        ReceivedDataStructure<ResponseType>& ref = SubscriberType::getReceivedStructStorage();
        ServiceCallResultType result(ServiceCallResultType::ErrorTimeout, erp.src_node_id, ref);

        UAVCAN_TRACE("ServiceClient", "Timeout from nid=%i, dtname=%s",
                     erp.src_node_id.get(), DataType::getDataTypeFullName());
        cancel();
        invokeCallback(result);
    }
    else
    {
        UAVCAN_ASSERT(0);
        cancel();
    }
}

template <typename DataType_, typename Callback_>
int ServiceClient<DataType_, Callback_>::call(NodeID server_node_id, const RequestType& request)
{
    cancel();
    if (!isCallbackValid())
    {
        UAVCAN_TRACE("ServiceClient", "Invalid callback");
        return -ErrInvalidParam;
    }

    /*
     * Common procedures that don't depend on the struct data type
     */
    TransferID transfer_id;
    const int prep_res =
        prepareToCall(SubscriberType::getNode(), DataType::getDataTypeFullName(), server_node_id, transfer_id);
    if (prep_res < 0)
    {
        UAVCAN_TRACE("ServiceClient", "Failed to prepare the call, error: %i", prep_res);
        cancel();
        return prep_res;
    }

    /*
     * Starting the subscriber
     */
    const int subscriber_res = SubscriberType::startAsServiceResponseListener();
    if (subscriber_res < 0)
    {
        UAVCAN_TRACE("ServiceClient", "Failed to start the subscriber, error: %i", subscriber_res);
        cancel();
        return subscriber_res;
    }

    /*
     * Configuring the listener so it will accept only the matching response
     */
    TransferListenerType* const tl = SubscriberType::getTransferListener();
    if (tl == NULL)
    {
        UAVCAN_ASSERT(0);  // Must have been created
        cancel();
        return -ErrLogic;
    }
    const typename TransferListenerType::ExpectedResponseParams erp(server_node_id, transfer_id);
    tl->setExpectedResponseParams(erp);

    /*
     * Publishing the request
     */
    const int publisher_res = publisher_.publish(request, TransferTypeServiceRequest, server_node_id, transfer_id);
    if (publisher_res < 0)
    {
        cancel();
    }
    return publisher_res;
}

template <typename DataType_, typename Callback_>
void ServiceClient<DataType_, Callback_>::cancel()
{
    pending_ = false;
    SubscriberType::stop();
    DeadlineHandler::stop();
    TransferListenerType* const tl = SubscriberType::getTransferListener();
    if (tl)
    {
        tl->stopAcceptingAnything();
    }
}

}

#endif // UAVCAN_NODE_SERVICE_CLIENT_HPP_INCLUDED
<|endoftext|>


<commit_before><commit_msg>Connections virkar<commit_after><|endoftext|>


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

#include "rtlibrary.h"
#include "amd64.h"
#include "objects.h"
#include "vmstate.h"
#include "function.h"
#include "type.h"
#include "codegenerator.h"

extern VMState vmState;

void Runtime::pushFunc(Function* func, int instIndex) {
    vmState.pushFunc(func, instIndex);
}

void Runtime::popFunc() {
    vmState.popFunc();
}

void Runtime::printStackFrame(long* basePtr, Function* func) {
    int numArgs = func->numArgs();
    int numLocals = func->numLocals();

    std::cout << "----Start StackFrame----" << std::endl;
    std::cout << "Func: " << func->name() << std::endl;
    std::cout << "Num args: " << numArgs << std::endl;
    std::cout << "Num locals: " << numLocals << std::endl;

    std::cout << std::endl;
    std::cout << "Values:" << std::endl;
    printAliveObjects(basePtr, func, func->instructions.size() - 1, "\t");

    std::cout << "----End StackFrame----" << std::endl;
}

void printStackTrace(long* basePtr, int level) {
    if (level > 50 || basePtr == nullptr) {
        return;
    }

    std::cout << basePtr << " from " << "0x" << std::hex << *basePtr << std::dec << std::endl;
    printStackTrace((long*)*basePtr, level + 1);
}

void printTimes(char c, int times) {
    for (int i = 0; i < times; i++) {
        std::cout << c;
    }
}

long* findBasePtr(long* basePtr, int currentIndex, int index) {
    if (basePtr == nullptr) {
        return nullptr;
    }

    if (currentIndex == index) {
        return (long*)*basePtr;
    }

    return findBasePtr((long*)*basePtr, currentIndex + 1, index);
}

union IntFloatConverter {
    int IntValue;
    float FloatValue;
};

void printValue(long value, const Type* type) {
    if (TypeSystem::isReferenceType(type)) {
        if (value == 0) {
            std::cout << "nullref";
        } else {
            std::cout << "0x" << std::hex << value << std::dec;
        }
    } else if (type->name() == "Float") {
        //int floatPattern = 1096149893;
        //float floatValue = *(reinterpret_cast<float*>(&floatPattern));

        std::cout << value;
    } else {
        std::cout << value;
    }

    std::cout << " (" + type->name() + ")";
}

void Runtime::printAliveObjects(long* basePtr, Function* func, int instIndex, std::string indentation) {
    int numArgs = func->numArgs();
    int numLocals = func->numLocals();
    auto operandTypes = func->instructionOperandTypes.at(instIndex);
    int stackSize = operandTypes.size();

    long* argsStart = basePtr - 1;
    long* localsStart = basePtr - 1 - numArgs;
    //long* stackStart = basePtr - numArgs - numLocals - (func->stackSize() / 8);
    //long* stackStart = basePtr - 1 - numArgs - numLocals - (func->stackSize() / 8) + stackSize;
    long* stackStart = basePtr - 1 - (func->stackSize() / 8);

    if (numArgs > 0) {
        std::cout << indentation << "Args: " << std::endl;
        for (int i = 0; i < numArgs; i++) {
            //std::cout << indentation << i << ": " << argsStart[-i] << " (" << func->arguments()[i]->name() << ")" << std::endl;
            std::cout << indentation << i << ": ";
            printValue(argsStart[-i], func->arguments()[i]);
            std::cout << std::endl;
        }

        std::cout << std::endl;
    }

    if (numLocals > 0) {
        std::cout << indentation << "Locals: " << std::endl;
        for (int i = 0; i < numLocals; i++) {
            //std::cout << indentation << i << ": " << localsStart[-i] << " (" << func->getLocal(i)->name() << ")" << std::endl;
            std::cout << indentation << i << ": ";
            printValue(localsStart[-i], func->getLocal(i));
            std::cout << std::endl;
        }

        std::cout << std::endl;
    }

    if (stackSize > 0) {
        std::cout << indentation << "Stack: " << std::endl;
        for (int i = 0; i < stackSize; i++) {
            //std::cout << indentation << i << ": " << stackStart[-i] << " (" << operandTypes[i]->name() << ")" << std::endl;
            std::cout << indentation << i << ": ";
            printValue(stackStart[-i], operandTypes[i]);
            std::cout << std::endl;
        }
    }
}

void printObject(ObjectHandle* handle) {
    std::cout
        << "0x" << std::hex << (long)handle->handle() << std::dec << ": " << handle->size()
        << " bytes (" << handle->type()->name() << ")" << std::endl;
}

void Runtime::markObject(ObjectHandle* handle) {
    if (!handle->isMarked()) {
        if (TypeSystem::isArray(handle->type())) {
            auto arrayHandle = static_cast<ArrayHandle*>(handle);
            auto arrayType = static_cast<const ArrayType*>(handle->type());

            handle->mark();

            //Mark ref elements
            if (TypeSystem::isReferenceType(arrayType->elementType())) {
                long* elemenetsPtr = (long*)(arrayHandle->handle() + 4);

                for (int i = 0; i < arrayHandle->length(); i++) {
                    markValue(elemenetsPtr[i], arrayType->elementType());
                }
            }
        } else if (TypeSystem::isStruct(handle->type())) {
            handle->mark();

            auto structType = static_cast<const StructType*>(handle->type());
            auto structMetadata = vmState.getStructMetadata(structType);

            //Mark ref fields
            for (auto fieldEntry : structMetadata.fields()) {
                auto field = fieldEntry.second;

                if (TypeSystem::isReferenceType(field.type)) {
                    long fieldValue = *((long*)handle->handle() + field.offset);
                    markValue(fieldValue, field.type);
                }
            }
        }
    }
}

void Runtime::markValue(long value, const Type* type) {
    unsigned char* objPtr = (unsigned char*)value;

    //Don't mark nulls
    if (objPtr == nullptr) {
        return;
    }

    if (TypeSystem::isReferenceType(type)) {
        if (vmState.getObjects().count(objPtr) > 0) {
            Runtime::markObject(vmState.getObjects().at(objPtr));
        } else {
            if (vmState.enableDebug) {
                //Due to a bug in the root finding, its possible to mark invalid values.
                std::cout << "Marking invalid object (0x" << std::hex << value << std::dec << ")" << std::endl;
            }
        }
    }
}

void Runtime::markObjects(long* basePtr, Function* func, int instIndex) {
    int numArgs = func->numArgs();
    int numLocals = func->numLocals();
    auto operandTypes = func->instructionOperandTypes.at(instIndex);
    int stackSize = operandTypes.size();

    long* argsStart = basePtr - 1;
    long* localsStart = basePtr - 1 - numArgs;
    long* stackStart = basePtr - 1 - (func->stackSize() / 8);

    if (numArgs > 0) {
        for (int i = 0; i < numArgs; i++) {
            Runtime::markValue(argsStart[-i], func->arguments()[i]);
        }
    }

    if (numLocals > 0) {
        for (int i = 0; i < numLocals; i++) {
            Runtime::markValue(localsStart[-i], func->getLocal(i));
        }
    }

    if (stackSize > 0) {
        for (int i = 0; i < stackSize; i++) {
            Runtime::markValue(stackStart[-i], operandTypes[i]);
        }
    }
}

void Runtime::sweepObjects() {
    std::vector<ObjectHandle*> objectsToRemove;

    for (auto objEntry : vmState.getObjects()) {
        auto obj = objEntry.second;

        if (!obj->isMarked()) {
            objectsToRemove.push_back(obj);

            if (vmState.enableDebug) {
                std::cout << "Deleted object: ";
                printObject(obj);
            }
        } else {
            obj->unmark();
        }
    }

    for (auto obj : objectsToRemove) {
        vmState.deleteObject(obj);
    }
}

void Runtime::garbageCollect(long* basePtr, Function* func, int instIndex) {
    int startStrLength = 0;

    if (vmState.enableDebug) {
        auto startStr = "-----Start GC in func " + func->name() + " (" + std::to_string(instIndex) + ")-----";
        std::cout << startStr << std::endl;
        startStrLength = startStr.length();
    }

    if (vmState.enableDebug) {
        std::cout << "Alive objects: " << std::endl;

        for (auto objEntry : vmState.getObjects()) {
            auto obj = objEntry.second;
            printObject(obj);
        }
    }

    if (vmState.enableDebug) {
        std::cout << "Stack trace: " << std::endl;
        std::cout << func->name() << " (" << instIndex << ")" << std::endl;
        Runtime::printAliveObjects(basePtr, func, instIndex, "\t");
    }

    Runtime::markObjects(basePtr, func, instIndex);

    int topFuncIndex = 0;
    for (auto callEntry : vmState.callStack()) {
        auto topFunc = callEntry.first;
        auto callPoint = callEntry.second;
        auto callBasePtr = findBasePtr(basePtr, 0, topFuncIndex);

        if (vmState.enableDebug) {
            std::cout << topFunc->name() << " (" << callPoint << ")" << std::endl;
        }

        Runtime::printAliveObjects(callBasePtr, topFunc, callPoint, "\t");
        Runtime::markObjects(callBasePtr, topFunc, callPoint);

        topFuncIndex++;
    }

    Runtime::sweepObjects();

    if (vmState.enableDebug) {
        printTimes('-', startStrLength / 2 - 3);
        std::cout << "End GC";
        printTimes('-', (startStrLength + 1) / 2 - 3);
        std::cout << std::endl;
    }
}

long Runtime::newArray(Type* elementType, int length) {
    auto elemSize = TypeSystem::sizeOfType(elementType);

    std::size_t memSize = sizeof(int) + length * elemSize;
    unsigned char* arrayPtr = new unsigned char[memSize];
    memset(arrayPtr, 0, memSize);

    //Add the array to the list of objects
    vmState.newObject(new ArrayHandle(arrayPtr, memSize, vmState.getType(TypeSystem::arrayTypeName(elementType)), length));

    //Set the size of the array
    IntToBytes converter;
    converter.IntValue = length;
    arrayPtr[0] = converter.ByteValues[0];
    arrayPtr[1] = converter.ByteValues[1];
    arrayPtr[2] = converter.ByteValues[2];
    arrayPtr[3] = converter.ByteValues[3];

    if (vmState.enableDebug) {
        std::cout
            << "Allocted array (size: " << memSize << " bytes, length: " << length << ", type: " << elementType->name()
            << ") at " << (long)arrayPtr
            << std::endl;
    }

    return (long)arrayPtr;
}

long Runtime::newObject(Type* type) {
    auto structType = static_cast<StructType*>(type);

    std::size_t memSize = vmState.getStructMetadata(structType->structName()).size();
    unsigned char* structPtr = new unsigned char[memSize];
    memset(structPtr, 0, memSize);

    //Add the struct to the list of objects
    vmState.newObject(new StructHandle(structPtr, memSize, type));

    if (vmState.enableDebug) {
        std::cout
            << "Allocted object (size: " << memSize << " bytes, type: " <<  type->name()
            << ") at " << (long)structPtr
            << std::endl;
    }

    return (long)structPtr;
}

void Runtime::runtimeError(std::string errorMessage) {
    throw std::runtime_error(errorMessage);
}

void Runtime::invalidArrayCreation() {
    Runtime::runtimeError("The length of the array must be >= 0.");
}

void Runtime::arrayOutOfBoundsError() {
    Runtime::runtimeError("Array index is out of bounds.");
}

void Runtime::nullReferenceError() {
    Runtime::runtimeError("Null reference error.");
}<commit_msg>Fixed typo.<commit_after>#include <iostream>
#include <string.h>

#include "rtlibrary.h"
#include "amd64.h"
#include "objects.h"
#include "vmstate.h"
#include "function.h"
#include "type.h"
#include "codegenerator.h"

extern VMState vmState;

void Runtime::pushFunc(Function* func, int instIndex) {
    vmState.pushFunc(func, instIndex);
}

void Runtime::popFunc() {
    vmState.popFunc();
}

void Runtime::printStackFrame(long* basePtr, Function* func) {
    int numArgs = func->numArgs();
    int numLocals = func->numLocals();

    std::cout << "----Start StackFrame----" << std::endl;
    std::cout << "Func: " << func->name() << std::endl;
    std::cout << "Num args: " << numArgs << std::endl;
    std::cout << "Num locals: " << numLocals << std::endl;

    std::cout << std::endl;
    std::cout << "Values:" << std::endl;
    printAliveObjects(basePtr, func, func->instructions.size() - 1, "\t");

    std::cout << "----End StackFrame----" << std::endl;
}

void printStackTrace(long* basePtr, int level) {
    if (level > 50 || basePtr == nullptr) {
        return;
    }

    std::cout << basePtr << " from " << "0x" << std::hex << *basePtr << std::dec << std::endl;
    printStackTrace((long*)*basePtr, level + 1);
}

void printTimes(char c, int times) {
    for (int i = 0; i < times; i++) {
        std::cout << c;
    }
}

long* findBasePtr(long* basePtr, int currentIndex, int index) {
    if (basePtr == nullptr) {
        return nullptr;
    }

    if (currentIndex == index) {
        return (long*)*basePtr;
    }

    return findBasePtr((long*)*basePtr, currentIndex + 1, index);
}

union IntFloatConverter {
    int IntValue;
    float FloatValue;
};

void printValue(long value, const Type* type) {
    if (TypeSystem::isReferenceType(type)) {
        if (value == 0) {
            std::cout << "nullref";
        } else {
            std::cout << "0x" << std::hex << value << std::dec;
        }
    } else if (type->name() == "Float") {
        //int floatPattern = 1096149893;
        //float floatValue = *(reinterpret_cast<float*>(&floatPattern));

        std::cout << value;
    } else {
        std::cout << value;
    }

    std::cout << " (" + type->name() + ")";
}

void Runtime::printAliveObjects(long* basePtr, Function* func, int instIndex, std::string indentation) {
    int numArgs = func->numArgs();
    int numLocals = func->numLocals();
    auto operandTypes = func->instructionOperandTypes.at(instIndex);
    int stackSize = operandTypes.size();

    long* argsStart = basePtr - 1;
    long* localsStart = basePtr - 1 - numArgs;
    //long* stackStart = basePtr - numArgs - numLocals - (func->stackSize() / 8);
    //long* stackStart = basePtr - 1 - numArgs - numLocals - (func->stackSize() / 8) + stackSize;
    long* stackStart = basePtr - 1 - (func->stackSize() / 8);

    if (numArgs > 0) {
        std::cout << indentation << "Args: " << std::endl;
        for (int i = 0; i < numArgs; i++) {
            //std::cout << indentation << i << ": " << argsStart[-i] << " (" << func->arguments()[i]->name() << ")" << std::endl;
            std::cout << indentation << i << ": ";
            printValue(argsStart[-i], func->arguments()[i]);
            std::cout << std::endl;
        }

        std::cout << std::endl;
    }

    if (numLocals > 0) {
        std::cout << indentation << "Locals: " << std::endl;
        for (int i = 0; i < numLocals; i++) {
            //std::cout << indentation << i << ": " << localsStart[-i] << " (" << func->getLocal(i)->name() << ")" << std::endl;
            std::cout << indentation << i << ": ";
            printValue(localsStart[-i], func->getLocal(i));
            std::cout << std::endl;
        }

        std::cout << std::endl;
    }

    if (stackSize > 0) {
        std::cout << indentation << "Stack: " << std::endl;
        for (int i = 0; i < stackSize; i++) {
            //std::cout << indentation << i << ": " << stackStart[-i] << " (" << operandTypes[i]->name() << ")" << std::endl;
            std::cout << indentation << i << ": ";
            printValue(stackStart[-i], operandTypes[i]);
            std::cout << std::endl;
        }
    }
}

void printObject(ObjectHandle* handle) {
    std::cout
        << "0x" << std::hex << (long)handle->handle() << std::dec << ": " << handle->size()
        << " bytes (" << handle->type()->name() << ")" << std::endl;
}

void Runtime::markObject(ObjectHandle* handle) {
    if (!handle->isMarked()) {
        if (TypeSystem::isArray(handle->type())) {
            auto arrayHandle = static_cast<ArrayHandle*>(handle);
            auto arrayType = static_cast<const ArrayType*>(handle->type());

            handle->mark();

            //Mark ref elements
            if (TypeSystem::isReferenceType(arrayType->elementType())) {
                long* elemenetsPtr = (long*)(arrayHandle->handle() + 4);

                for (int i = 0; i < arrayHandle->length(); i++) {
                    markValue(elemenetsPtr[i], arrayType->elementType());
                }
            }
        } else if (TypeSystem::isStruct(handle->type())) {
            handle->mark();

            auto structType = static_cast<const StructType*>(handle->type());
            auto structMetadata = vmState.getStructMetadata(structType);

            //Mark ref fields
            for (auto fieldEntry : structMetadata.fields()) {
                auto field = fieldEntry.second;

                if (TypeSystem::isReferenceType(field.type)) {
                    long fieldValue = *((long*)handle->handle() + field.offset);
                    markValue(fieldValue, field.type);
                }
            }
        }
    }
}

void Runtime::markValue(long value, const Type* type) {
    unsigned char* objPtr = (unsigned char*)value;

    //Don't mark nulls
    if (objPtr == nullptr) {
        return;
    }

    if (TypeSystem::isReferenceType(type)) {
        if (vmState.getObjects().count(objPtr) > 0) {
            Runtime::markObject(vmState.getObjects().at(objPtr));
        } else {
            if (vmState.enableDebug) {
                //Due to a bug in the root finding, its possible to mark invalid values.
                std::cout << "Marking invalid object (0x" << std::hex << value << std::dec << ")" << std::endl;
            }
        }
    }
}

void Runtime::markObjects(long* basePtr, Function* func, int instIndex) {
    int numArgs = func->numArgs();
    int numLocals = func->numLocals();
    auto operandTypes = func->instructionOperandTypes.at(instIndex);
    int stackSize = operandTypes.size();

    long* argsStart = basePtr - 1;
    long* localsStart = basePtr - 1 - numArgs;
    long* stackStart = basePtr - 1 - (func->stackSize() / 8);

    if (numArgs > 0) {
        for (int i = 0; i < numArgs; i++) {
            Runtime::markValue(argsStart[-i], func->arguments()[i]);
        }
    }

    if (numLocals > 0) {
        for (int i = 0; i < numLocals; i++) {
            Runtime::markValue(localsStart[-i], func->getLocal(i));
        }
    }

    if (stackSize > 0) {
        for (int i = 0; i < stackSize; i++) {
            Runtime::markValue(stackStart[-i], operandTypes[i]);
        }
    }
}

void Runtime::sweepObjects() {
    std::vector<ObjectHandle*> objectsToRemove;

    for (auto objEntry : vmState.getObjects()) {
        auto obj = objEntry.second;

        if (!obj->isMarked()) {
            objectsToRemove.push_back(obj);

            if (vmState.enableDebug) {
                std::cout << "Deleted object: ";
                printObject(obj);
            }
        } else {
            obj->unmark();
        }
    }

    for (auto obj : objectsToRemove) {
        vmState.deleteObject(obj);
    }
}

void Runtime::garbageCollect(long* basePtr, Function* func, int instIndex) {
    int startStrLength = 0;

    if (vmState.enableDebug) {
        auto startStr = "-----Start GC in func " + func->name() + " (" + std::to_string(instIndex) + ")-----";
        std::cout << startStr << std::endl;
        startStrLength = startStr.length();
    }

    if (vmState.enableDebug) {
        std::cout << "Alive objects: " << std::endl;

        for (auto objEntry : vmState.getObjects()) {
            auto obj = objEntry.second;
            printObject(obj);
        }
    }

    if (vmState.enableDebug) {
        std::cout << "Stack trace: " << std::endl;
        std::cout << func->name() << " (" << instIndex << ")" << std::endl;
        Runtime::printAliveObjects(basePtr, func, instIndex, "\t");
    }

    Runtime::markObjects(basePtr, func, instIndex);

    int topFuncIndex = 0;
    for (auto callEntry : vmState.callStack()) {
        auto topFunc = callEntry.first;
        auto callPoint = callEntry.second;
        auto callBasePtr = findBasePtr(basePtr, 0, topFuncIndex);

        if (vmState.enableDebug) {
            std::cout << topFunc->name() << " (" << callPoint << ")" << std::endl;
        }

        Runtime::printAliveObjects(callBasePtr, topFunc, callPoint, "\t");
        Runtime::markObjects(callBasePtr, topFunc, callPoint);

        topFuncIndex++;
    }

    Runtime::sweepObjects();

    if (vmState.enableDebug) {
        printTimes('-', startStrLength / 2 - 3);
        std::cout << "End GC";
        printTimes('-', (startStrLength + 1) / 2 - 3);
        std::cout << std::endl;
    }
}

long Runtime::newArray(Type* elementType, int length) {
    auto elemSize = TypeSystem::sizeOfType(elementType);

    std::size_t memSize = sizeof(int) + length * elemSize;
    unsigned char* arrayPtr = new unsigned char[memSize];
    memset(arrayPtr, 0, memSize);

    //Add the array to the list of objects
    vmState.newObject(new ArrayHandle(arrayPtr, memSize, vmState.getType(TypeSystem::arrayTypeName(elementType)), length));

    //Set the size of the array
    IntToBytes converter;
    converter.IntValue = length;
    arrayPtr[0] = converter.ByteValues[0];
    arrayPtr[1] = converter.ByteValues[1];
    arrayPtr[2] = converter.ByteValues[2];
    arrayPtr[3] = converter.ByteValues[3];

    if (vmState.enableDebug) {
        std::cout
            << "Allocated array (size: " << memSize << " bytes, length: " << length << ", type: " << elementType->name()
            << ") at " << (long)arrayPtr
            << std::endl;
    }

    return (long)arrayPtr;
}

long Runtime::newObject(Type* type) {
    auto structType = static_cast<StructType*>(type);

    std::size_t memSize = vmState.getStructMetadata(structType->structName()).size();
    unsigned char* structPtr = new unsigned char[memSize];
    memset(structPtr, 0, memSize);

    //Add the struct to the list of objects
    vmState.newObject(new StructHandle(structPtr, memSize, type));

    if (vmState.enableDebug) {
        std::cout
            << "Allocated object (size: " << memSize << " bytes, type: " <<  type->name()
            << ") at " << (long)structPtr
            << std::endl;
    }

    return (long)structPtr;
}

void Runtime::runtimeError(std::string errorMessage) {
    throw std::runtime_error(errorMessage);
}

void Runtime::invalidArrayCreation() {
    Runtime::runtimeError("The length of the array must be >= 0.");
}

void Runtime::arrayOutOfBoundsError() {
    Runtime::runtimeError("Array index is out of bounds.");
}

void Runtime::nullReferenceError() {
    Runtime::runtimeError("Null reference error.");
}<|endoftext|>


<commit_before>#include <cmath>
#include <cstdio>
using namespace std;

#define MAX_M 4096
#define MAX_m 12
#define MAX_QUERY 86

/**
 * Print first n bit of a code
 */
void print_codeword(char *code, int n) {
    for (int i = 0; i < n; ++i) {
        putchar(code[i]);
    }
    putchar('\n');
}

int main(int argc, char const *argv[]) {
    int t; // test cases
    int M, e, max_query_allowed; // a test case
    int the_real_M; // trick if M isn't power of 2

    char code[MAX_m+1][MAX_QUERY][MAX_M+1]; // all the codewords
    bool is_code[MAX_m+1]; // has the codeword been made?
    int code_distance[MAX_m+1][MAX_M]; // only distance from 0 to 1..M
    int code_min[MAX_m+1]; // min distance
    const int code_order[][MAX_QUERY] = {
        /* 0  */ {},
        /* 1  */ {1},
        /* 2  */ {1,2,3},
        /* 3  */ {1,2,4,7,3,5,6},
        /* 4  */ {1,2,4,8,15,3,5,9,14,6,10,13,7,11,12},
        /* 5  */ {1,2,4,8,16,31,7,9,19,29,10,22,12,15,17,18,20,21,24,27,30,3,5,14,25,6,11,28,13,23,26},
        /* 6  */ {1,2,4,8,16,32,63,7,25,42,52,13,22,35,56,14,19,37,11,48,28,53,26,33,31,45,54,34,5,43,50,12,59,36,3,29,10,51,20,58,6,40,15,17,44,21,55,62,24,41,49,23,30,57,38,47,61,9,18,46,27,39,60},
        /* 7  */ {1,2,4,8,16,32,64,127,15,51,85,105,27,45,71,113,58,86,29,99,38,3,65,88,46,55,74,80,117,60,12,43,67,30,100,57,81,96,5,76,59,114,23,94,41,110,6,77,49,122,37,89,52,9,82,22,121,91,61,31,112,21,97,102,107,73,14,125,18,104,19,44},
        /* 8  */ {1,2,4,8,16,32,64,128,255,15,51,85,150,232,45,78,139,116,178,192,238,23,217,103,10,225,66,123,144,188,52,185,28,3,208,106,141,18,167,65,230,33,59,237,206,26,95,170,148,98,221,216,124,17,181,24,196,61,5,76,190,195,36,69,182,199,40,89,171,75,35,189,218,68,47,176},
        /* 9  */ {1,2,4,8,16,32,64,128,256,511,31,99,165,302,470,203,344,146,288,85,153,34,460,435,283,109,113,406,220,293,25,448,164,382,43,7,502,363,138,230,295,415,119,355,139,410,79,19,269,192,418,53,343,472,217,3,490,35,123,26,140,458,260,244,358,427,150,66,298,272,120,445,44,205,464,162,361,94,504},
        /* 10 */ {1,2,4,8,16,32,64,128,256,512,1023,31,227,293,622,950,184,338,907,608,213,377,972,544,174,521,11,17,262,1019,660,115,292,419,838,239,60,569,484,597,769,977,173,665,432,42,210,860,364,550,925,90,530,487,307,710,737,347,824,130,764,276,403,635,652,251,282,470,699,629,37,45,795,874,171,81,363,758,970,303,439},
        /* 11 */ {1,2,4,8,16,32,64,128,256,512,1024,2047,63,455,585,1242,1899,238,373,583,1798,1181,419,692,1476,1684,1110,665,97,477,1907,637,1517,364,456,1844,1489,547,1093,951,283,1140,628,1362,1819,1016,377,1982,109,123,780,1172,1600,2019,491,814,1889,996,722,39,77,1351,696,1166,1148,641,1405,89,1500,1547,910,1782,167,9,443,1450,1368,643,49,1038,1614,625,190,849},
        /* 12 */ {1,2,4,8,16,32,64,128,256,512,1024,2048,4095,63,455,1609,2707,3362,1267,996,2125,3914,1624,238,2575,883,4058,978,124,1302,2094,3442,969,2832,1670,282,3233,2282,1991,907,3365,387,3663,336,1134,2489,712,1446,2169,140,3268,407,1760,285,3843,2302,1381,2121,91,4031,863,3806,521,1056,2336,799,2471,182,1032,4053,2603,994,3845,1887,685,1170,2095,2584,1701,3422,916,3424,263,2221,1091,1078},
    };
    int code_order_pointer[MAX_m+1]; // is the code created
    int code_minimal[MAX_m+1][MAX_M/2+2]; // param: d needed; return: query

    scanf("%d", &t);
    while (t--) {
        scanf("%d%d%d", &M, &e, &max_query_allowed);
        int d = (2*e + 1); // minimal distance
        the_real_M = M; // save the real M for printing the query

        /* M must be power of two */
        int m = ceil(log2(M)); // log2(M)
        M = pow(2, m); // M is the closest power(2)

        /* initial coding, if hasnt made yet */
        if (!is_code[m]) {
            is_code[m] = 1;
            code_min[m] = 0;
            code_minimal[m][1] = 0;
            code_order_pointer[m] = 0;
        }

        /* find the best order */
        while (code_min[m] < d && code_min[m] < M/2) {
            int current = code_order_pointer[m]++;

            /* generate the codeword */
            for (int j = 0; j < M; ++j) {
                int bitstring = code_order[m][current] & j;
                short binary = 0;
                /* counting bit set */
                for (binary = 0; bitstring; bitstring >>= 1) {
                    binary ^= bitstring & 1;
                }
                code[m][current][j] = '0' + binary;
            }
            code[m][current][M] = 0; // close the string

            /* update the distance */
            code_min[m] = MAX_M;
            for (int j = 1; j < M; ++j) {
                code_distance[m][j] += (code[m][current][0] != code[m][current][j]);
                if (code_distance[m][j] < code_min[m]) {
                    code_min[m] = code_distance[m][j];
                }
            }

            /* update the code order */
            if (code_minimal[m][code_min[m]] == 0) {
                code_minimal[m][code_min[m]] = code_order_pointer[m];
            }
        }

        /* total query needed */
        int rounds = d / (M / 2);
        int mod = d % (M / 2);
        int total = rounds * (M - 1) + code_minimal[m][mod];
        printf("%d\n", total);

        for (int i = 0; i < rounds; ++i) { // round query
            for (int j = 0; j < M-1; ++j) {
                print_codeword(code[m][j], the_real_M);
            }
        }
        for (int i = 0; i < code_minimal[m][mod]; ++i) { // mod query
            print_codeword(code[m][i], the_real_M);
        }
    }
    return 0;
}<commit_msg>asserting<commit_after>#include <cmath>
#include <cstdio>
#include <cassert>
using namespace std;

#define MAX_M 4096
#define MAX_m 12
#define MAX_QUERY 86

/**
 * Print first n bit of a code
 */
void print_codeword(bool *code, int n) {
    for (int i = 0; i < n; ++i) {
        assert(code[i] == 0 || code[i] == 1);
        printf("%d", code[i]);
    }
    putchar('\n');
}

int main(int argc, char const *argv[]) {
    int t; // test cases
    int M, e, max_query_allowed; // a test case
    int the_real_M; // trick if M isn't power of 2

    bool code[MAX_m+1][MAX_QUERY][MAX_M+1]; // all the codewords
    bool is_code[MAX_m+1]; // has the codeword been made?
    int code_distance[MAX_m+1][MAX_M]; // only distance from 0 to 1..M
    int code_min[MAX_m+1]; // min distance
    const int code_order[][MAX_QUERY] = {
        /* 0  */ {},
        /* 1  */ {1},
        /* 2  */ {1,2,3},
        /* 3  */ {1,2,4,7,3,5,6},
        /* 4  */ {1,2,4,8,15,3,5,9,14,6,10,13,7,11,12},
        /* 5  */ {1,2,4,8,16,31,7,9,19,29,10,22,12,15,17,18,20,21,24,27,30,3,5,14,25,6,11,28,13,23,26},
        /* 6  */ {1,2,4,8,16,32,63,7,25,42,52,13,22,35,56,14,19,37,11,48,28,53,26,33,31,45,54,34,5,43,50,12,59,36,3,29,10,51,20,58,6,40,15,17,44,21,55,62,24,41,49,23,30,57,38,47,61,9,18,46,27,39,60},
        /* 7  */ {1,2,4,8,16,32,64,127,15,51,85,105,27,45,71,113,58,86,29,99,38,3,65,88,46,55,74,80,117,60,12,43,67,30,100,57,81,96,5,76,59,114,23,94,41,110,6,77,49,122,37,89,52,9,82,22,121,91,61,31,112,21,97,102,107,73,14,125,18,104,19,44},
        /* 8  */ {1,2,4,8,16,32,64,128,255,15,51,85,150,232,45,78,139,116,178,192,238,23,217,103,10,225,66,123,144,188,52,185,28,3,208,106,141,18,167,65,230,33,59,237,206,26,95,170,148,98,221,216,124,17,181,24,196,61,5,76,190,195,36,69,182,199,40,89,171,75,35,189,218,68,47,176},
        /* 9  */ {1,2,4,8,16,32,64,128,256,511,31,99,165,302,470,203,344,146,288,85,153,34,460,435,283,109,113,406,220,293,25,448,164,382,43,7,502,363,138,230,295,415,119,355,139,410,79,19,269,192,418,53,343,472,217,3,490,35,123,26,140,458,260,244,358,427,150,66,298,272,120,445,44,205,464,162,361,94,504},
        /* 10 */ {1,2,4,8,16,32,64,128,256,512,1023,31,227,293,622,950,184,338,907,608,213,377,972,544,174,521,11,17,262,1019,660,115,292,419,838,239,60,569,484,597,769,977,173,665,432,42,210,860,364,550,925,90,530,487,307,710,737,347,824,130,764,276,403,635,652,251,282,470,699,629,37,45,795,874,171,81,363,758,970,303,439},
        /* 11 */ {1,2,4,8,16,32,64,128,256,512,1024,2047,63,455,585,1242,1899,238,373,583,1798,1181,419,692,1476,1684,1110,665,97,477,1907,637,1517,364,456,1844,1489,547,1093,951,283,1140,628,1362,1819,1016,377,1982,109,123,780,1172,1600,2019,491,814,1889,996,722,39,77,1351,696,1166,1148,641,1405,89,1500,1547,910,1782,167,9,443,1450,1368,643,49,1038,1614,625,190,849},
        /* 12 */ {1,2,4,8,16,32,64,128,256,512,1024,2048,4095,63,455,1609,2707,3362,1267,996,2125,3914,1624,238,2575,883,4058,978,124,1302,2094,3442,969,2832,1670,282,3233,2282,1991,907,3365,387,3663,336,1134,2489,712,1446,2169,140,3268,407,1760,285,3843,2302,1381,2121,91,4031,863,3806,521,1056,2336,799,2471,182,1032,4053,2603,994,3845,1887,685,1170,2095,2584,1701,3422,916,3424,263,2221,1091,1078},
    };
    int code_order_pointer[MAX_m+1]; // is the code created
    int code_minimal[MAX_m+1][MAX_M/2+2]; // param: d needed; return: query

    for (int i = 0; i <= MAX_m; ++i) {
        is_code[i] = 0;
    }

    scanf("%d", &t);
    while (t--) {
        scanf("%d%d%d", &M, &e, &max_query_allowed);
        int d = (2*e + 1); // minimal distance
        the_real_M = M; // save the real M for printing the query

        /* M must be power of two */
        int m = ceil(log2(M)); // log2(M)
        M = pow(2, m); // M is the closest power(2)

        /* initial coding, if hasnt made yet */
        if (!is_code[m]) {
            assert(m < MAX_m + 1);
            is_code[m] = 1;
            code_min[m] = 0;
            code_minimal[m][1] = 0;
            code_order_pointer[m] = 0;
            for (int j = 1; j < M; ++j) {
                code_distance[m][j] = 0;
            }
        }

        /* find the best order */
        while (code_min[m] < d && code_min[m] < M/2) {
            int current = code_order_pointer[m]++;

            /* generate the codeword */
            for (int j = 0; j < M; ++j) {
                assert(m < MAX_m + 1);
                assert(current < MAX_QUERY);
                int bitstring = code_order[m][current] & j;
                short binary = 0;
                /* counting bit set */
                for (binary = 0; bitstring; bitstring >>= 1) {
                    binary ^= bitstring & 1;
                }
                assert(m < MAX_m + 1);
                assert(current < MAX_QUERY);
                assert(j < MAX_M + 1);
                code[m][current][j] = binary;
            }

            /* update the distance */
            assert(m < MAX_m + 1);
            code_min[m] = MAX_M;
            for (int j = 1; j < M; ++j) {
                assert(m < MAX_m + 1);
                assert(current < MAX_QUERY);
                assert(j < MAX_M);
                code_distance[m][j] += (code[m][current][0] != code[m][current][j]);
                if (code_distance[m][j] < code_min[m]) {
                    code_min[m] = code_distance[m][j];
                }
            }

            /* update the code order */
            assert(m < MAX_m + 1);
            assert(code_min[m] < MAX_M/2 + 2);
            if (code_minimal[m][code_min[m]] == 0) {
                code_minimal[m][code_min[m]] = code_order_pointer[m];
                code_minimal[m][code_min[m] + 1] = 0;
            }
        }

        /* total query needed */
        int rounds = d / (M / 2);
        int mod = d % (M / 2);
        assert(mod < MAX_M/2 + 2);
        int total = rounds * (M - 1) + code_minimal[m][mod];
        printf("%d\n", total);

        for (int i = 0; i < rounds; ++i) { // round query
            for (int j = 0; j < M-1; ++j) {
                assert(m < MAX_m + 1);
                assert(j < MAX_QUERY);
                assert(the_real_M < MAX_M + 1);
                assert(j < code_order_pointer[m]);
                print_codeword(code[m][j], the_real_M);
            }
        }
        for (int i = 0; i < code_minimal[m][mod]; ++i) { // mod query
            assert(m < MAX_m + 1);
            assert(i < MAX_QUERY);
            assert(the_real_M < MAX_M + 1);
            assert(i < code_order_pointer[m]);
            print_codeword(code[m][i], the_real_M);
        }
    }
    return 0;
}<|endoftext|>


<commit_before>#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
#include <cstring>
#include <iterator>
#include "IO.hpp"
#include "common.h"
#include "mkl.h"
#include "BenchmarkUtils.hpp"
#include <unordered_map>

#include "lib/timer.hpp"

using namespace std;

class DokMatrix {

 public:
  int n;
  int nnzs;

  // use of std::map important: values are sorted by column index internaly
  std::unordered_map<int, std::map<int, double>> dok;

  DokMatrix(int _n, int _nnzs) : n(_n), nnzs(_nnzs) {}

  DokMatrix explicitSymmetric() {
      DokMatrix m(n, nnzs);
      for (auto &&s : dok) {
          for (auto &&p : s.second) {
              int i = s.first;
              int j = p.first;
              double value = p.second;
              m.dok[i][j] = value;

              // check the transpose entry does not exist
              if (i == j)
                  continue;
              if (dok.find(j) != dok.end()) {
                  if (dok[j].find(i) != dok[j].end()) {
                      if (dok[j][i] != p.second) {
                          throw std::invalid_argument("Matrix is not symmetric");
                      } else {
                          std::cout << "Warning! Matrix already contains transpose entry for "
                                    << s.first << " " << p.first << std::endl;
                      }
                  }
              }

              // add the transpose entry
              m.dok[j][i] = value;
          }
      }
      return m;
  }

  void pretty_print() {
      for (auto &&s : dok) {
          for (auto &&p : s.second) {
              std::cout << s.first << " " << p.first << " " << p.second << std::endl;
          }
      }
  }
};

// TODO verify preconditions:
// with 1 based indexing
// lower triangular
// row entries in increasing column order
class CsrMatrix {
  // TODO move to include/, make API
 public:
  int nnzs;
  int n;
  std::vector<double> values;
  std::vector<int> col_ind;
  std::vector<int> row_ptr;

  CsrMatrix() : n(0), nnzs(0) {}

  CsrMatrix(const DokMatrix& m) {
      nnzs = m.nnzs;
      n = m.n;
      // row_ptr.resize(n + 1);
      int pos = 1;
      for (int i = 1; i < n + 1; i++) {
          row_ptr.push_back(pos);
          for (auto &entries : m.dok.find(i)->second) {
              col_ind.push_back(entries.first);
              values.push_back(entries.second);
              pos++;
          }
      }
      row_ptr.push_back(nnzs + 2);
  }

  CsrMatrix(int _n, int _nnzs, double* _values, int* _col_ind, int* _row_ptr) :
      n(_n),
      nnzs(_nnzs)
  {
      values.assign(_values, _values + _nnzs);
      col_ind.assign(_col_ind, _col_ind + _nnzs);
      row_ptr.assign(_row_ptr, _row_ptr + n + 1);
  }

  // Prints all matrix values
  void pretty_print() {
      for (int i = 0; i < n; i++) {
          int col_ptr = row_ptr[i];
          for (int k = 0; k < n; k++) {
              if (col_ptr < row_ptr[i + 1] && col_ind[col_ptr - 1] == k + 1) {
                  std::cout << values[col_ptr - 1] << " ";
                  col_ptr++;
                  continue;
              }
              std::cout << "0 ";
          }
          std::cout << endl;
      }
  }

  double& get(int i, int j) {
      for (int k = row_ptr[i - 1]; k < row_ptr[i]; k++) {
          if (col_ind[k - 1] == j) {
              return values[k - 1];
          }
      }

      throw std::invalid_argument("No nonzero at row col:"
                                      + std::to_string(i) + " "
                                      + std::to_string(j));
  }

  bool isNnz(int i, int j) {
      try {
          get(i, j);
      } catch (std::invalid_argument) {
          return false;
      }
      return true;
  }

  bool isSymmetric() {
      return true;
  }

  DokMatrix toDok() {
    DokMatrix m(n, nnzs);
      for (int i = 0; i < n; i++) {
          for (int k = row_ptr[i]; k < row_ptr[i + 1]; k++) {
              m.dok[i + 1][col_ind[k - 1]] = values[k - 1];
          }
      }
    return m;
  }

};

class Preconditioner {
 public:
  virtual std::vector<double> apply(std::vector<double> x) = 0;
};

// Equivalent to un-precontitioned CG
class IdentityPreconditioner : public Preconditioner {
 public:
  virtual std::vector<double> apply(std::vector<double> x) override {
      return x;
  }
};

class ILUPreconditioner {
  CsrMatrix pc;
 public:

  // pre - a is a symmetric matrix
  ILUPreconditioner(CsrMatrix &a) {
      if (!a.isSymmetric()) {
          throw std::invalid_argument("ILUPreconditioner only supports symmetric CSR matrices");
      }
      pc = a;

      for (int i = 2; i <= a.n; i++) {
          for (int k = 1; k <= i - 1; k++) {
              // update pivot - a[i,k] = a[i, k] / a[k, k]
              if (a.isNnz(i, k) && a.isNnz(k, k)) {
                std::cout << "Updating " << std::endl;
                  a.get(i, k) = a.get(i, k) / a.get(k, k);
                  double beta = a.get(i, k);
                  for (int j = k + 1; j <= a.n; j++) {
                      // update row - a[i, j] -= a[k, j] * a[i, k]
                      if (a.isNnz(i, j) && a.isNnz(k, j))
                          a.get(i, j) = a.get(i, j) - a.get(k, j) * beta;
                  }
              }
          }
      }
  }

  virtual std::vector<double> apply(std::vector<double> x) {
      // TODO
      return x;
  }

  void pretty_print() {
      pc.pretty_print();
  }
};

/**
 *  Standard preconditioned CG, (Saad et al)
 *  https://en.wikipedia.org/wiki/Conjugate_gradient_method
 */
template <typename T, typename Precon>
bool pcg(int n, int nnzs, int* col_ind, int* row_ptr, double* matrix_values,
        double* rhs, double* x, int& iterations, bool verbose = false)
{
    // configuration (TODO Should be exposed through params)
    char tr = 'l';
    int maxiters = 2000;
    double tol = 1E-5;
    Precon precon;

    std::vector<double>    r(n);             // residual
    std::vector<double>    b(rhs, rhs + n);  // rhs
    std::vector<double>    p(n);             //
    std::vector<double>    z(n);             //

    //  r = b - A * x
    mkl_dcsrsymv(&tr, &n, matrix_values, row_ptr, col_ind, &x[0], &r[0]);
    cblas_daxpby(n, 1.0, &b[0], 1, -1.0, &r[0], 1);

    // z = M^-1 * r
    z = precon.apply(r);

    p = z;

    // rsold = r * z
    double rsold = cblas_ddot(n, &r[0], 1, &z[0], 1);

    for (int i = 0; i < maxiters; i++) {
        if (verbose) {
            std::cout << " rsold " << rsold << std::endl;
        }
        std::vector<double> Ap(n);
        // Ap = A * p
        mkl_dcsrsymv (&tr, &n, matrix_values, row_ptr, col_ind, &p[0], &Ap[0]);
        // alpha = rsold / (p * Ap)
        double alpha = rsold / cblas_ddot(n, &p[0], 1, &Ap[0], 1);
        // x = x + alpha * p
        cblas_daxpy(n, alpha, &p[0], 1, &x[0], 1);
        // r = r - alpha * Ap
        cblas_daxpby(n, -alpha, &Ap[0], 1, 1.0, &r[0], 1);

        // z = M^-1 * r
        z = precon.apply(r);

        // rsnew = r * z
        double rsnew = cblas_ddot(n, &r[0], 1, &z[0], 1);

        if (rsnew <= tol * tol) {
            // std::cout << "Found solution" << std::endl;
            print_array("x", &x[0], n);
            return true;
        }

        // p = r + (rsnew/rsold) * p
        cblas_daxpby(n, 1, &z[0], 1, rsnew / rsold, &p[0], 1);
        rsold = rsnew;
        iterations = i;
    }

    return false;
}

// Solve an SPD sparse system using the conjugate gradient method with Intel MKL
int main (int argc, char** argv) {

    sparsebench::benchmarkutils::parseArgs(argc, argv);

    // read data from matrix market files
    int n, nnzs;
    double* values;
    int *col_ind, *row_ptr;
    FILE *f;
    if ((f = fopen(argv[2], "r")) == NULL) {
        printf("Could not open %s", argv[2]);
        return 1;
    }
    read_system_matrix_sym_csr(f, &n, &nnzs, &col_ind, &row_ptr, &values);
    fclose(f);

    std::vector<double> rhs = sparsebench::io::readVector(std::string(argv[4]));

    std::vector<double> sol(n);

    bool verbose = false;
    int iterations = 0;

    CsrMatrix a{n, nnzs, values, col_ind, row_ptr};
    CsrMatrix b{a};
    ILUPreconditioner pc{a};
    std::cout << "--- ILU pc matrix" << std::endl;
    pc.pretty_print();
    std::cout << "--- ILU pc matrix" << std::endl;
    std::cout << "--- A (CSR) --- " << std::endl;
    a.pretty_print();
    std::cout << "--- A (CSR) --- " << std::endl;
    std::cout << "--- A (DOK) --- " << std::endl;
    a.toDok().pretty_print();
    std::cout << "--- A (DOK) --- " << std::endl;
    std::cout << "--- A (DOK - explicit sym) --- " << std::endl;
    a.toDok().explicitSymmetric().pretty_print();
    std::cout << "--- A (DOK - explicit sym) --- " << std::endl;
    std::cout << "--- A (CSR from --> DOK - explicit sym) --- " << std::endl;
    CsrMatrix explicitA(a.toDok().explicitSymmetric());
    explicitA.pretty_print();
    std::cout << "--- A (CSR from --> DOK - explicit sym) --- " << std::endl;
    ILUPreconditioner explicitPc{explicitA};
    std::cout << "--- Explicit ILU pc matrix" << std::endl;
    explicitPc.pretty_print();
    std::cout << "--- Explicit ILU pc matrix" << std::endl;

    sparsebench::utils::Timer t;
    t.tic("cg:all");
    bool status = pcg<double, IdentityPreconditioner>(n, nnzs, col_ind, row_ptr, values, &rhs[0], &sol[0], iterations, verbose);
    t.toc("cg:all");

    std::vector<double> exp = sparsebench::io::readVector(argv[6]);
    sparsebench::benchmarkutils::printSummary(
        0,
        iterations,
        t.get("cg:all").count(),
        0,
        sparsebench::benchmarkutils::residual(exp, sol),
        0
    );

    write_vector_to_file("sol.mtx.expl", &sol[0], sol.size());

    mkl_free_buffers ();
    return 1;
}
<commit_msg>Fix ILU pc<commit_after>#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
#include <cstring>
#include <iterator>
#include "IO.hpp"
#include "common.h"
#include "mkl.h"
#include "BenchmarkUtils.hpp"
#include <unordered_map>

#include "lib/timer.hpp"

using namespace std;

class DokMatrix {

 public:
  int n;
  int nnzs;

  // use of std::map important: values are sorted by column index internaly
  std::unordered_map<int, std::map<int, double>> dok;

  DokMatrix(int _n, int _nnzs) : n(_n), nnzs(_nnzs) {}

  DokMatrix explicitSymmetric() {
      DokMatrix m(n, nnzs);
      for (auto &&s : dok) {
          for (auto &&p : s.second) {
              int i = s.first;
              int j = p.first;
              double value = p.second;
              m.dok[i][j] = value;

              // check the transpose entry does not exist
              if (i == j)
                  continue;
              if (dok.find(j) != dok.end()) {
                  if (dok[j].find(i) != dok[j].end()) {
                      if (dok[j][i] != p.second) {
                          throw std::invalid_argument("Matrix is not symmetric");
                      } else {
                          std::cout << "Warning! Matrix already contains transpose entry for "
                                    << s.first << " " << p.first << std::endl;
                      }
                  }
              }

              // add the transpose entry
              m.dok[j][i] = value;
          }
      }
      return m;
  }

  void pretty_print() {
      for (auto &&s : dok) {
          for (auto &&p : s.second) {
              std::cout << s.first << " " << p.first << " " << p.second << std::endl;
          }
      }
  }
};

// TODO verify preconditions:
// with 1 based indexing
// lower triangular
// row entries in increasing column order
class CsrMatrix {
  // TODO move to include/, make API
 public:
  int nnzs;
  int n;
  std::vector<double> values;
  std::vector<int> col_ind;
  std::vector<int> row_ptr;

  CsrMatrix() : n(0), nnzs(0) {}

  CsrMatrix(const DokMatrix& m) {
      nnzs = m.nnzs;
      n = m.n;
      // row_ptr.resize(n + 1);
      int pos = 1;
      for (int i = 1; i < n + 1; i++) {
          row_ptr.push_back(pos);
          for (auto &entries : m.dok.find(i)->second) {
              col_ind.push_back(entries.first);
              values.push_back(entries.second);
              pos++;
          }
      }
      row_ptr.push_back(nnzs + 2);
  }

  CsrMatrix(int _n, int _nnzs, double* _values, int* _col_ind, int* _row_ptr) :
      n(_n),
      nnzs(_nnzs)
  {
      values.assign(_values, _values + _nnzs);
      col_ind.assign(_col_ind, _col_ind + _nnzs);
      row_ptr.assign(_row_ptr, _row_ptr + n + 1);
  }

  // Prints all matrix values
  void pretty_print() {
      for (int i = 0; i < n; i++) {
          int col_ptr = row_ptr[i];
          for (int k = 0; k < n; k++) {
              if (col_ptr < row_ptr[i + 1] && col_ind[col_ptr - 1] == k + 1) {
                  std::cout << values[col_ptr - 1] << " ";
                  col_ptr++;
                  continue;
              }
              std::cout << "0 ";
          }
          std::cout << endl;
      }
  }

  double& get(int i, int j) {
      for (int k = row_ptr[i - 1]; k < row_ptr[i]; k++) {
          if (col_ind[k - 1] == j) {
              return values[k - 1];
          }
      }

      throw std::invalid_argument("No nonzero at row col:"
                                      + std::to_string(i) + " "
                                      + std::to_string(j));
  }

  bool isNnz(int i, int j) {
      try {
          get(i, j);
      } catch (std::invalid_argument) {
          return false;
      }
      return true;
  }

  bool isSymmetric() {
      return true;
  }

  DokMatrix toDok() {
    DokMatrix m(n, nnzs);
      for (int i = 0; i < n; i++) {
          for (int k = row_ptr[i]; k < row_ptr[i + 1]; k++) {
              m.dok[i + 1][col_ind[k - 1]] = values[k - 1];
          }
      }
    return m;
  }

};

class Preconditioner {
 public:
  virtual std::vector<double> apply(std::vector<double> x) = 0;
};

// Equivalent to un-precontitioned CG
class IdentityPreconditioner : public Preconditioner {
 public:
  virtual std::vector<double> apply(std::vector<double> x) override {
      return x;
  }
};

class ILUPreconditioner {
  CsrMatrix pc;
 public:

  // pre - a is a symmetric matrix
  ILUPreconditioner(CsrMatrix &a) {
      if (!a.isSymmetric())
          throw std::invalid_argument("ILUPreconditioner only supports symmetric CSR matrices");
      pc = a;
      for (int i = 2; i <= a.n; i++) {
          for (int k = 1; k <= i - 1; k++) {
              // update pivot - a[i,k] = a[i, k] / a[k, k]
              if (pc.isNnz(i, k) && pc.isNnz(k, k)) {
                  pc.get(i, k) = pc.get(i, k) / pc.get(k, k);
                  double beta = pc.get(i, k);
                  for (int j = k + 1; j <= pc.n; j++) {
                      // update row - a[i, j] -= a[k, j] * a[i, k]
                      if (pc.isNnz(i, j) && pc.isNnz(k, j)) {
                          pc.get(i, j) = pc.get(i, j) - pc.get(k, j) * beta;
                      }
                  }
              }
          }
      }
  }

  virtual std::vector<double> apply(std::vector<double> x) {
      // TODO
      return x;
  }

  void pretty_print() {
      pc.pretty_print();
  }
};

/**
 *  Standard preconditioned CG, (Saad et al)
 *  https://en.wikipedia.org/wiki/Conjugate_gradient_method
 */
template <typename T, typename Precon>
bool pcg(int n, int nnzs, int* col_ind, int* row_ptr, double* matrix_values,
        double* rhs, double* x, int& iterations, bool verbose = false)
{
    // configuration (TODO Should be exposed through params)
    char tr = 'l';
    int maxiters = 2000;
    double tol = 1E-5;
    Precon precon;

    std::vector<double>    r(n);             // residual
    std::vector<double>    b(rhs, rhs + n);  // rhs
    std::vector<double>    p(n);             //
    std::vector<double>    z(n);             //

    //  r = b - A * x
    mkl_dcsrsymv(&tr, &n, matrix_values, row_ptr, col_ind, &x[0], &r[0]);
    cblas_daxpby(n, 1.0, &b[0], 1, -1.0, &r[0], 1);

    // z = M^-1 * r
    z = precon.apply(r);

    p = z;

    // rsold = r * z
    double rsold = cblas_ddot(n, &r[0], 1, &z[0], 1);

    for (int i = 0; i < maxiters; i++) {
        if (verbose) {
            std::cout << " rsold " << rsold << std::endl;
        }
        std::vector<double> Ap(n);
        // Ap = A * p
        mkl_dcsrsymv (&tr, &n, matrix_values, row_ptr, col_ind, &p[0], &Ap[0]);
        // alpha = rsold / (p * Ap)
        double alpha = rsold / cblas_ddot(n, &p[0], 1, &Ap[0], 1);
        // x = x + alpha * p
        cblas_daxpy(n, alpha, &p[0], 1, &x[0], 1);
        // r = r - alpha * Ap
        cblas_daxpby(n, -alpha, &Ap[0], 1, 1.0, &r[0], 1);

        // z = M^-1 * r
        z = precon.apply(r);

        // rsnew = r * z
        double rsnew = cblas_ddot(n, &r[0], 1, &z[0], 1);

        if (rsnew <= tol * tol) {
            // std::cout << "Found solution" << std::endl;
            print_array("x", &x[0], n);
            return true;
        }

        // p = r + (rsnew/rsold) * p
        cblas_daxpby(n, 1, &z[0], 1, rsnew / rsold, &p[0], 1);
        rsold = rsnew;
        iterations = i;
    }

    return false;
}

// Solve an SPD sparse system using the conjugate gradient method with Intel MKL
int main (int argc, char** argv) {

    sparsebench::benchmarkutils::parseArgs(argc, argv);

    // read data from matrix market files
    int n, nnzs;
    double* values;
    int *col_ind, *row_ptr;
    FILE *f;
    if ((f = fopen(argv[2], "r")) == NULL) {
        printf("Could not open %s", argv[2]);
        return 1;
    }
    read_system_matrix_sym_csr(f, &n, &nnzs, &col_ind, &row_ptr, &values);
    fclose(f);

    std::vector<double> rhs = sparsebench::io::readVector(std::string(argv[4]));

    std::vector<double> sol(n);

    bool verbose = false;
    int iterations = 0;

    CsrMatrix a{n, nnzs, values, col_ind, row_ptr};
    CsrMatrix b{a};
    ILUPreconditioner pc{a};
    std::cout << "--- ILU pc matrix" << std::endl;
    pc.pretty_print();
    std::cout << "--- ILU pc matrix" << std::endl;
    std::cout << "--- A (CSR) --- " << std::endl;
    a.pretty_print();
    std::cout << "--- A (CSR) --- " << std::endl;
    std::cout << "--- A (DOK) --- " << std::endl;
    a.toDok().pretty_print();
    std::cout << "--- A (DOK) --- " << std::endl;
    std::cout << "--- A (DOK - explicit sym) --- " << std::endl;
    a.toDok().explicitSymmetric().pretty_print();
    std::cout << "--- A (DOK - explicit sym) --- " << std::endl;
    std::cout << "--- A (CSR from --> DOK - explicit sym) --- " << std::endl;
    CsrMatrix explicitA(a.toDok().explicitSymmetric());
    explicitA.pretty_print();
    std::cout << "--- A (CSR from --> DOK - explicit sym) --- " << std::endl;
    ILUPreconditioner explicitPc{explicitA};
    std::cout << "--- Explicit ILU pc matrix" << std::endl;
    explicitPc.pretty_print();
    std::cout << "--- Explicit ILU pc matrix" << std::endl;

    sparsebench::utils::Timer t;
    t.tic("cg:all");
    bool status = pcg<double, IdentityPreconditioner>(n, nnzs, col_ind, row_ptr, values, &rhs[0], &sol[0], iterations, verbose);
    t.toc("cg:all");

    std::vector<double> exp = sparsebench::io::readVector(argv[6]);
    sparsebench::benchmarkutils::printSummary(
        0,
        iterations,
        t.get("cg:all").count(),
        0,
        sparsebench::benchmarkutils::residual(exp, sol),
        0
    );

    write_vector_to_file("sol.mtx.expl", &sol[0], sol.size());

    mkl_free_buffers ();
    return 1;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012, 2013 Esrille Inc.
 *
 * 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 "CSSRuleListImp.h"

#include "CSSMediaRuleImp.h"
#include "CSSStyleDeclarationImp.h"
#include "CSSStyleSheetImp.h"

#include "DocumentImp.h"
#include "ViewCSSImp.h"

#include "html/MediaQueryListImp.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

using namespace css;

void CSSRuleListImp::append(css::CSSRule rule)
{
    ruleList.push_back(rule);
}

bool CSSRuleListImp::PrioritizedRule::getMatches() const
{
    return !mql || mql->getMatches();
}

bool CSSRuleListImp::PrioritizedRule::isActive(Element& element, ViewCSSImp* view) const
{
    CSSSelector* selector = getSelector();
    if (!selector)
        return true;
    return selector->match(element, view, true);
}

void CSSRuleListImp::appendMisc(CSSSelector* selector, CSSStyleDeclarationImp* declaration, MediaListImp* mediaList)
{
    misc.push_back(Rule{ selector, declaration, ++order, mediaList });
}

void CSSRuleListImp::appendID(CSSSelector* selector, CSSStyleDeclarationImp* declaration, const std::u16string& key, MediaListImp* mediaList)
{
    mapID.insert(std::pair<std::u16string, Rule>(key, Rule{ selector, declaration, ++order, mediaList }));
}

void CSSRuleListImp::appendClass(CSSSelector* selector, CSSStyleDeclarationImp* declaration, const std::u16string& key, MediaListImp* mediaList)
{
    mapClass.insert(std::pair<std::u16string, Rule>(key, Rule{ selector, declaration, ++order, mediaList }));
}

void CSSRuleListImp::appendType(CSSSelector* selector, CSSStyleDeclarationImp* declaration, const std::u16string& key, MediaListImp* mediaList)
{
    mapType.insert(std::pair<std::u16string, Rule>(key, Rule{ selector, declaration, ++order, mediaList }));
}

void CSSRuleListImp::append(css::CSSRule rule, DocumentImp* document, MediaListImp* mediaList)
{
    if (!rule)
        return;
    if (CSSStyleRuleImp* styleRule = dynamic_cast<CSSStyleRuleImp*>(rule.self())) {
        if (CSSSelectorsGroup* selectorsGroup = styleRule->getSelectorsGroup()) {
            for (auto j = selectorsGroup->begin(); j != selectorsGroup->end(); ++j) {
                CSSSelector* selector = *j;
                CSSStyleDeclarationImp* declaration = dynamic_cast<CSSStyleDeclarationImp*>(styleRule->getStyle().self());
                selector->registerToRuleList(this, declaration, mediaList);
            }
        }
    } else if (CSSMediaRuleImp* mediaRule = dynamic_cast<CSSMediaRuleImp*>(rule.self())) {
        auto ruleList = dynamic_cast<CSSRuleListImp*>(mediaRule->getCssRules().self());
        if (ruleList) {
            MediaListImp* mediaList = dynamic_cast<MediaListImp*>(mediaRule->getMedia().self());
            for (auto i = ruleList->ruleList.begin(); i != ruleList->ruleList.end(); ++i)
                append(*i, document, mediaList);
        }
    } else if (CSSImportRuleImp* importRule = dynamic_cast<CSSImportRuleImp*>(rule.self())) {
        if (document) {
            importRule->setDocument(document);
            importRule->getStyleSheet();  // to get the CSS file
            importList.push_back(importRule);
        }
    }
    if (!rule.getParentRule())
        ruleList.push_back(rule);
}

void CSSRuleListImp::collectRules(RuleSet& set, ViewCSSImp* view, Element& element, std::multimap<std::u16string, Rule>& map, const std::u16string& key, MediaListImp* mediaList)
{
    for (auto i = map.find(key); i != map.end() && i->first == key; ++i) {
        CSSSelector* selector = i->second.selector;
        if (!selector->match(element, view, false))
            continue;
        // TODO: emplace() seems to be not ready yet with libstdc++.
        if (i->second.mediaList)
            mediaList = i->second.mediaList;
        // TODO: else ...
        PrioritizedRule rule(importance, i->second, view->matchMedia(mediaList));
        set.insert(rule);
    }
}

void CSSRuleListImp::collectRulesByID(RuleSet& set, ViewCSSImp* view, Element& element, MediaListImp* mediaList)
{
    Nullable<std::u16string> attr = element.getAttribute(u"id");
    if (attr.hasValue())
        collectRules(set, view, element, mapID, attr.value(), mediaList);
}

void CSSRuleListImp::collectRulesByClass(RuleSet& set, ViewCSSImp* view, Element& element, MediaListImp* mediaList)
{
    Nullable<std::u16string> attr = element.getAttribute(u"class");
    if (attr.hasValue()) {
        std::u16string classes = attr.value();
        for (size_t pos = 0; pos < classes.length();) {
            if (isSpace(classes[pos])) {
                ++pos;
                continue;
            }
            size_t start = pos++;
            while (pos < classes.length() && !isSpace(classes[pos]))
                ++pos;
            collectRules(set, view, element, mapClass, classes.substr(start, pos - start), mediaList);
        }
    }
}

void CSSRuleListImp::collectRulesByType(RuleSet& set, ViewCSSImp* view, Element& element, MediaListImp* mediaList)
{
    collectRules(set, view, element, mapType, element.getLocalName(), mediaList);
}

void CSSRuleListImp::collectRulesByMisc(RuleSet& set, ViewCSSImp* view, Element& element, MediaListImp* mediaList)
{
    for (auto i = misc.begin(); i != misc.end(); ++i) {
        CSSSelector* selector = i->selector;
        if (!selector->match(element, view, false))
            continue;
        // TODO: emplace() seems to be not ready yet with libstdc++.
        if (i->mediaList)
            mediaList = i->mediaList;
        // TODO: else ...
        PrioritizedRule rule(importance, *i, view->matchMedia(mediaList));
        set.insert(rule);
    }
}

void CSSRuleListImp::collectRules(RuleSet& set, ViewCSSImp* view, Element& element, unsigned importance, MediaListImp* mediaList)
{
    this->importance = importance;

    // Declarations in imported style sheets are considered to be before any
    // declarations in the style sheet itself.
    // cf. http://www.w3.org/TR/CSS2/cascade.html#cascading-order
    for (auto i = importList.begin(); i != importList.end(); ++i) {
        if (CSSStyleSheetImp* sheet = dynamic_cast<CSSStyleSheetImp*>((*i)->getStyleSheet().self())) {
            if (CSSRuleListImp* ruleList = dynamic_cast<CSSRuleListImp*>(sheet->getCssRules().self()))
                ruleList->collectRules(set, view, element, importance, mediaList);
        }
    }

    collectRulesByMisc(set, view, element, mediaList);
    collectRulesByType(set, view, element, mediaList);
    collectRulesByClass(set, view, element, mediaList);
    collectRulesByID(set, view, element, mediaList);
}

bool CSSRuleListImp::hasHover(const RuleSet& set)
{
    for (auto i = set.begin(); i != set.end(); ++i) {
        CSSSelector* selector = i->getSelector();
        if (selector && selector->hasHover())
            return true;
    }
    return false;
}

}}}}  // org::w3c::dom::bootstrap
<commit_msg>(CSSRuleListImp::collectRules) : Fix a bug; cf. html4/at-import-004.htm<commit_after>/*
 * Copyright 2012, 2013 Esrille Inc.
 *
 * 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 "CSSRuleListImp.h"

#include "CSSMediaRuleImp.h"
#include "CSSStyleDeclarationImp.h"
#include "CSSStyleSheetImp.h"

#include "DocumentImp.h"
#include "ViewCSSImp.h"

#include "html/MediaQueryListImp.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

using namespace css;

void CSSRuleListImp::append(css::CSSRule rule)
{
    ruleList.push_back(rule);
}

bool CSSRuleListImp::PrioritizedRule::getMatches() const
{
    return !mql || mql->getMatches();
}

bool CSSRuleListImp::PrioritizedRule::isActive(Element& element, ViewCSSImp* view) const
{
    CSSSelector* selector = getSelector();
    if (!selector)
        return true;
    return selector->match(element, view, true);
}

void CSSRuleListImp::appendMisc(CSSSelector* selector, CSSStyleDeclarationImp* declaration, MediaListImp* mediaList)
{
    misc.push_back(Rule{ selector, declaration, ++order, mediaList });
}

void CSSRuleListImp::appendID(CSSSelector* selector, CSSStyleDeclarationImp* declaration, const std::u16string& key, MediaListImp* mediaList)
{
    mapID.insert(std::pair<std::u16string, Rule>(key, Rule{ selector, declaration, ++order, mediaList }));
}

void CSSRuleListImp::appendClass(CSSSelector* selector, CSSStyleDeclarationImp* declaration, const std::u16string& key, MediaListImp* mediaList)
{
    mapClass.insert(std::pair<std::u16string, Rule>(key, Rule{ selector, declaration, ++order, mediaList }));
}

void CSSRuleListImp::appendType(CSSSelector* selector, CSSStyleDeclarationImp* declaration, const std::u16string& key, MediaListImp* mediaList)
{
    mapType.insert(std::pair<std::u16string, Rule>(key, Rule{ selector, declaration, ++order, mediaList }));
}

void CSSRuleListImp::append(css::CSSRule rule, DocumentImp* document, MediaListImp* mediaList)
{
    if (!rule)
        return;
    if (CSSStyleRuleImp* styleRule = dynamic_cast<CSSStyleRuleImp*>(rule.self())) {
        if (CSSSelectorsGroup* selectorsGroup = styleRule->getSelectorsGroup()) {
            for (auto j = selectorsGroup->begin(); j != selectorsGroup->end(); ++j) {
                CSSSelector* selector = *j;
                CSSStyleDeclarationImp* declaration = dynamic_cast<CSSStyleDeclarationImp*>(styleRule->getStyle().self());
                selector->registerToRuleList(this, declaration, mediaList);
            }
        }
    } else if (CSSMediaRuleImp* mediaRule = dynamic_cast<CSSMediaRuleImp*>(rule.self())) {
        auto ruleList = dynamic_cast<CSSRuleListImp*>(mediaRule->getCssRules().self());
        if (ruleList) {
            MediaListImp* mediaList = dynamic_cast<MediaListImp*>(mediaRule->getMedia().self());
            for (auto i = ruleList->ruleList.begin(); i != ruleList->ruleList.end(); ++i)
                append(*i, document, mediaList);
        }
    } else if (CSSImportRuleImp* importRule = dynamic_cast<CSSImportRuleImp*>(rule.self())) {
        if (document) {
            importRule->setDocument(document);
            importRule->getStyleSheet();  // to get the CSS file
            importList.push_back(importRule);
        }
    }
    if (!rule.getParentRule())
        ruleList.push_back(rule);
}

void CSSRuleListImp::collectRules(RuleSet& set, ViewCSSImp* view, Element& element, std::multimap<std::u16string, Rule>& map, const std::u16string& key, MediaListImp* mediaList)
{
    for (auto i = map.find(key); i != map.end() && i->first == key; ++i) {
        CSSSelector* selector = i->second.selector;
        if (!selector->match(element, view, false))
            continue;
        // TODO: emplace() seems to be not ready yet with libstdc++.
        if (i->second.mediaList)
            mediaList = i->second.mediaList;
        // TODO: else ...
        PrioritizedRule rule(importance, i->second, view->matchMedia(mediaList));
        set.insert(rule);
    }
}

void CSSRuleListImp::collectRulesByID(RuleSet& set, ViewCSSImp* view, Element& element, MediaListImp* mediaList)
{
    Nullable<std::u16string> attr = element.getAttribute(u"id");
    if (attr.hasValue())
        collectRules(set, view, element, mapID, attr.value(), mediaList);
}

void CSSRuleListImp::collectRulesByClass(RuleSet& set, ViewCSSImp* view, Element& element, MediaListImp* mediaList)
{
    Nullable<std::u16string> attr = element.getAttribute(u"class");
    if (attr.hasValue()) {
        std::u16string classes = attr.value();
        for (size_t pos = 0; pos < classes.length();) {
            if (isSpace(classes[pos])) {
                ++pos;
                continue;
            }
            size_t start = pos++;
            while (pos < classes.length() && !isSpace(classes[pos]))
                ++pos;
            collectRules(set, view, element, mapClass, classes.substr(start, pos - start), mediaList);
        }
    }
}

void CSSRuleListImp::collectRulesByType(RuleSet& set, ViewCSSImp* view, Element& element, MediaListImp* mediaList)
{
    collectRules(set, view, element, mapType, element.getLocalName(), mediaList);
}

void CSSRuleListImp::collectRulesByMisc(RuleSet& set, ViewCSSImp* view, Element& element, MediaListImp* mediaList)
{
    for (auto i = misc.begin(); i != misc.end(); ++i) {
        CSSSelector* selector = i->selector;
        if (!selector->match(element, view, false))
            continue;
        // TODO: emplace() seems to be not ready yet with libstdc++.
        if (i->mediaList)
            mediaList = i->mediaList;
        // TODO: else ...
        PrioritizedRule rule(importance, *i, view->matchMedia(mediaList));
        set.insert(rule);
    }
}

void CSSRuleListImp::collectRules(RuleSet& set, ViewCSSImp* view, Element& element, unsigned importance, MediaListImp* mediaList)
{
    this->importance = importance;

    // Declarations in imported style sheets are considered to be before any
    // declarations in the style sheet itself.
    // cf. http://www.w3.org/TR/CSS2/cascade.html#cascading-order
    for (auto i = importList.begin(); i != importList.end(); ++i) {
        if (auto media = dynamic_cast<MediaListImp*>((*i)->getMedia().self()))
            mediaList = media;
        // TODO: else ...
        if (CSSStyleSheetImp* sheet = dynamic_cast<CSSStyleSheetImp*>((*i)->getStyleSheet().self())) {
            if (CSSRuleListImp* ruleList = dynamic_cast<CSSRuleListImp*>(sheet->getCssRules().self()))
                ruleList->collectRules(set, view, element, importance, mediaList);
        }
    }

    collectRulesByMisc(set, view, element, mediaList);
    collectRulesByType(set, view, element, mediaList);
    collectRulesByClass(set, view, element, mediaList);
    collectRulesByID(set, view, element, mediaList);
}

bool CSSRuleListImp::hasHover(const RuleSet& set)
{
    for (auto i = set.begin(); i != set.end(); ++i) {
        CSSSelector* selector = i->getSelector();
        if (selector && selector->hasHover())
            return true;
    }
    return false;
}

}}}}  // org::w3c::dom::bootstrap
<|endoftext|>


<commit_before>#ifndef QUORIDOR_BOARD_HPP_
#define QUORIDOR_BOARD_HPP_

#include <cstdlib>

#include <map>
#include <memory>
#include <utility>
#include <vector>

#include "pawn.hpp"

namespace Quoridor {

struct pos_t {
    int row;
    int col;

    bool operator<(const pos_t &pos) const {
        return (row * 1000 + col) < (pos.row * 1000 + pos.col);
    }
};

enum BoardMoves {
    kForward = 0,
    kRight = 1,
    kBackward = 2,
    kLeft = 3,
    kPutWall = 4,
    kCancel = 5,
    kEND,
};

class Wall {
public:
    Wall(int orientation, int line, int start_pos, int cnt);
    virtual ~Wall();

    int orientation() const { return orientation_; }
    int line() const { return line_; }
    int start_pos() const { return start_pos_; }
    int cnt() const { return cnt_; }

private:
    int orientation_;
    int line_;
    int start_pos_;
    int cnt_;
};

class Board {
public:
    Board(int row_num, int col_num);
    virtual ~Board();

    void set_size(int row_num, int col_num);
    int row_num() const { return row_num_; }
    int col_num() const { return col_num_; }
    int next_side() const;

    int add_pawn(std::shared_ptr<Pawn> pawn);
    void add_occupied(const pos_t &pos, std::shared_ptr<Pawn> pawn);
    void rm_occupied(const pos_t &pos);
    pos_t pawn_pos(std::shared_ptr<Pawn> pawn) const;

    int make_move(BoardMoves move, std::shared_ptr<Pawn> pawn);
    bool is_at_opposite_side(std::shared_ptr<Pawn> pawn) const;
    int add_wall(const Wall &wall);

private:
    BoardMoves recalc_move(BoardMoves move, std::shared_ptr<Pawn> pawn);
    int make_walking_move(BoardMoves move, std::shared_ptr<Pawn> pawn);
    bool wall_intersects(const Wall &wall) const;
    bool is_outside_board(const pos_t &pos) const;
    bool is_possible_move(const pos_t &pos, const pos_t &inc_pos) const;

private:
    int row_num_;
    int col_num_;
    std::map<pos_t, std::shared_ptr<Pawn>> occ_fields_;
    std::map<std::shared_ptr<Pawn>, pos_t> pawn_pos_;
    mutable std::vector<std::pair<int, int>> sides_;
    std::map<std::shared_ptr<Pawn>, int> pawn_sides_;
    std::map<int, std::map<int, Wall>> walls_;
};

}  /* namespace Quoridor */

#endif  /* QUORIDOR_BOARD_HPP_ */
<commit_msg>Implement few operators in struct pos_t.<commit_after>#ifndef QUORIDOR_BOARD_HPP_
#define QUORIDOR_BOARD_HPP_

#include <cstdlib>

#include <map>
#include <memory>
#include <utility>
#include <vector>

#include "pawn.hpp"

namespace Quoridor {

struct pos_t {
    int row;
    int col;

    bool operator<(const pos_t &pos) const {
        return (row * 1000 + col) < (pos.row * 1000 + pos.col);
    }
    bool operator==(const pos_t &pos) const {
        return (row == pos.row) && (col == pos.col);
    }
    const pos_t &operator+=(const pos_t &pos) {
        row += pos.row;
        col += pos.col;
        return *this;
    }
    const pos_t operator+(const pos_t &pos) {
        pos_t p = *this;
        p += pos;
        return p;
    }
};

enum BoardMoves {
    kForward = 0,
    kRight = 1,
    kBackward = 2,
    kLeft = 3,
    kPutWall = 4,
    kCancel = 5,
    kEND,
};

class Wall {
public:
    Wall(int orientation, int line, int start_pos, int cnt);
    virtual ~Wall();

    int orientation() const { return orientation_; }
    int line() const { return line_; }
    int start_pos() const { return start_pos_; }
    int cnt() const { return cnt_; }

private:
    int orientation_;
    int line_;
    int start_pos_;
    int cnt_;
};

class Board {
public:
    Board(int row_num, int col_num);
    virtual ~Board();

    void set_size(int row_num, int col_num);
    int row_num() const { return row_num_; }
    int col_num() const { return col_num_; }
    int next_side() const;

    int add_pawn(std::shared_ptr<Pawn> pawn);
    void add_occupied(const pos_t &pos, std::shared_ptr<Pawn> pawn);
    void rm_occupied(const pos_t &pos);
    pos_t pawn_pos(std::shared_ptr<Pawn> pawn) const;

    int make_move(BoardMoves move, std::shared_ptr<Pawn> pawn);
    bool is_at_opposite_side(std::shared_ptr<Pawn> pawn) const;
    int add_wall(const Wall &wall);

private:
    BoardMoves recalc_move(BoardMoves move, std::shared_ptr<Pawn> pawn);
    int make_walking_move(BoardMoves move, std::shared_ptr<Pawn> pawn);
    bool wall_intersects(const Wall &wall) const;
    bool is_outside_board(const pos_t &pos) const;
    bool is_possible_move(const pos_t &pos, const pos_t &inc_pos) const;

private:
    int row_num_;
    int col_num_;
    std::map<pos_t, std::shared_ptr<Pawn>> occ_fields_;
    std::map<std::shared_ptr<Pawn>, pos_t> pawn_pos_;
    mutable std::vector<std::pair<int, int>> sides_;
    std::map<std::shared_ptr<Pawn>, int> pawn_sides_;
    std::map<int, std::map<int, Wall>> walls_;
};

}  /* namespace Quoridor */

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