<commit_before>#include "serverConnection.h"
#include <vector>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>

#include <libwatcher/message.h>
#include <libwatcher/messageStatus.h>
#include <libwatcher/seekWatcherMessage.h>
#include <libwatcher/speedWatcherMessage.h>

#include "messageFactory.h"
#include "dataMarshaller.h"
#include "watcherd.h"
#include "writeDBMessageHandler.h"
#include "watcherdConfig.h"

using namespace std;
using namespace boost::asio;

namespace {
    using namespace watcher::event;

    /* Grr, because there is no std::copy_if have to use the negation with
     * remove_copy_if() */
    bool not_feeder_message(const MessagePtr& m)
    {
        return !isFeederEvent(m->type);
    }
}

namespace watcher {
    using namespace event;

    INIT_LOGGER(ServerConnection, "Connection.ServerConnection");

    ServerConnection::ServerConnection(Watcherd& w, boost::asio::io_service& io_service) :
        Connection(io_service),
        watcher(w),
        io_service_(io_service),
        strand_(io_service),
        write_strand_(io_service),
        conn_type(unknown),
        isPlaying_(false), isLive_(true)
    {
        TRACE_ENTER();
        TRACE_EXIT();
    }

    ServerConnection::~ServerConnection()
    {
        TRACE_ENTER();
        //shared_from_this() not allowed in destructor
        //watcher.unsubscribe(shared_from_this());
        TRACE_EXIT();
    }

    /** Initialization point for start of new ServerConnection thread. */
    void ServerConnection::run()
    {
        /*
         * Pull endpoint info out of the socket and make it available via the
         * Connection::getPeerAddr() member function.
         */
        boost::asio::ip::tcp::endpoint ep = getSocket().remote_endpoint();
        endpoint_addr_ = ep.address().to_string();
        endpoint_port_ = ep.port();

        start();
    }

    void ServerConnection::start()
    {
        TRACE_ENTER();
        boost::asio::async_read(
                theSocket,
                boost::asio::buffer(incomingBuffer, DataMarshaller::header_length),
                strand_.wrap(
                    boost::bind(
                        &ServerConnection::handle_read_header,
                        shared_from_this(),
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred)));
        TRACE_EXIT();
    }

    void ServerConnection::handle_read_header(const boost::system::error_code& e, size_t bytes_transferred)
    {
        TRACE_ENTER();
        if (!e)
        {
            LOG_DEBUG("Read " << bytes_transferred << " bytes.");

            size_t payloadSize;
            unsigned short numOfMessages;
            if (!DataMarshaller::unmarshalHeader(incomingBuffer.begin(), bytes_transferred, payloadSize, numOfMessages))
            {
                LOG_ERROR("Error parsing incoming message header.");

                if (conn_type == gui)
                    watcher.unsubscribe(shared_from_this());
            }
            else
            {
                LOG_DEBUG("Reading packet payload of " << payloadSize << " bytes.");

                boost::asio::async_read(
                        theSocket,
                        boost::asio::buffer(
                            incomingBuffer,
                            payloadSize),  // Should incoming buffer be new'd()?
                        strand_.wrap(
                            boost::bind(
                                &ServerConnection::handle_read_payload,
                                shared_from_this(),
                                boost::asio::placeholders::error,
                                boost::asio::placeholders::bytes_transferred,
                                numOfMessages)));
            }
        }
        else
        {
            if (e==boost::asio::error::eof)
            {
                LOG_DEBUG("Received empty message from clienti or client closed connection.");
                LOG_INFO("Connection to client closed.");

            }
            else
            {
                LOG_ERROR("Error reading socket: " << e.message());
            }

            // unsubscribe to event stream, otherwise it will hold a
            // shared_ptr open
            if (conn_type == gui)
                watcher.unsubscribe(shared_from_this());
        }
        TRACE_EXIT();
    }

    void ServerConnection::handle_read_payload(const boost::system::error_code& e, size_t bytes_transferred, unsigned short numOfMessages)
    {
        TRACE_ENTER();

        if (!e)
        {
            vector<MessagePtr> arrivedMessages;
            if (DataMarshaller::unmarshalPayload(arrivedMessages, numOfMessages, incomingBuffer.begin(), bytes_transferred))
            {
                LOG_INFO("Recvd " << arrivedMessages.size() << " message" <<
                         (arrivedMessages.size()>1?"s":"") << " from " <<
                         getPeerAddr());

                // Add the incoming address to the Message so everyone
                // knows who the message came from.
                boost::asio::ip::tcp::endpoint ep = getSocket().remote_endpoint();
                BOOST_FOREACH(MessagePtr m, arrivedMessages) {
                    if(m->fromNodeID==NodeIdentifier())  // is empty
                        m->fromNodeID=ep.address();
                }

                /*
                 * If this connection type is unknown or gui, then traverse the
                 * list of arrived messages.  For GUI clients, look for the
                 * STOP_MESSAGE to unsubscribe from the event stream.
                 *
                 * For unknown clients, infer the type from the message
                 * received:
                 * START_MESSAGE => gui
                 * isFeederMessage => feeder
                 */
                if (conn_type == unknown || conn_type == gui) {
                    BOOST_FOREACH(MessagePtr i, arrivedMessages) {
                        if (i->type == START_MESSAGE_TYPE) {
                            /* Client is requesting the live stream of events. */
                            if (conn_type == unknown) {
                                conn_type = gui;
                                replay = boost::shared_ptr<ReplayState>(new ReplayState(shared_from_this()));
                            }
                            if (!isPlaying_) {
                                isPlaying_ = true;
                                if (isLive_)
                                    watcher.subscribe(shared_from_this());
                                else
                                    replay->run();
                            }
                        } else if (i->type == SEEK_MESSAGE_TYPE) {
                            if (conn_type == unknown) {
                                conn_type = gui;
                                replay = boost::shared_ptr<ReplayState>(new ReplayState(shared_from_this()));
                            }
                            SeekMessagePtr p = boost::dynamic_pointer_cast<SeekMessage>(i);
                            if (p) {
                                if (p->offset == SeekMessage::eof) {
                                    // switch to live stream
                                    if (!isLive_) {
                                        isLive_ = true;
                                        replay->pause();
                                        if (isPlaying_)
                                            watcher.subscribe(shared_from_this());
                                    }
                                } else {
                                    replay->seek(p->offset);

                                    // when switching from live to replay while playing, kick off the replay strand
                                    if (isLive_ && isPlaying_)
                                        replay->run();
                                    isLive_ = false;
                                }
                            }
                        } else if (i->type == SPEED_MESSAGE_TYPE) {
                            if (conn_type == unknown) {
                                conn_type = gui;
                                replay = boost::shared_ptr<ReplayState>(new ReplayState(shared_from_this()));
                            }
                            SpeedMessagePtr p = boost::dynamic_pointer_cast<SpeedMessage>(i);
                            if (p)
                                replay->speed(p->speed);
                        } else if (i->type == STOP_MESSAGE_TYPE) {
                            if (conn_type == unknown) {
                                conn_type = gui;
                                replay = boost::shared_ptr<ReplayState>(new ReplayState(shared_from_this()));
                            }
                            if (isPlaying_) {
                                if (isLive_)
                                    watcher.unsubscribe(shared_from_this());
                                else
                                    replay->pause();
                                isPlaying_ = false;
                            }
                        } else if (isFeederEvent(i->type)) {
                            conn_type = feeder;

                            /*
                             * This connection is a watcher test daemon.
                             * Add a message handler to write its event
                             * stream to the database.
                             */
                            addMessageHandler(MessageHandlerPtr(new WriteDBMessageHandler()));
                        }
                    }
                }

                /* Flag indicating whether to continue reading from this
                 * connection. */
                bool fail = false;

                BOOST_FOREACH(MessageHandlerPtr mh, messageHandlers) {
                    if (mh->handleMessagesArrive(shared_from_this(), arrivedMessages)) {
                        fail = true;
                        LOG_DEBUG("Message handler told us to close this connection.");
                    }
                }

                if (!fail) {
                    // initiate request to read next message
                    LOG_DEBUG("Waiting for next message.");
                    start();
                }

                if (conn_type == feeder) {
                    /* relay feeder message to any client requesting the live stream.
                     * Warning: currently there is no check to make sure that a client doesn't
                     * receive a message it just sent.  This should be OK since we are just
                     * relaying feeder messages only, and the GUIs should not be sending
                     * them. */
                    vector<MessagePtr> feeder;
                    remove_copy_if(arrivedMessages.begin(), arrivedMessages.end(), back_inserter(feeder), not_feeder_message);
                    if (! feeder.empty()) {
                        LOG_DEBUG("Sending " << feeder.size() << " feeder messages to clients.");
                        watcher.sendMessage(feeder);
                    }
                }
            }
        }
        else
        {
            LOG_WARN("Did not understand incoming message.");

            // unsubscribe to event stream, otherwise it will hold a
            // shared_ptr open
            if (conn_type == gui)
                watcher.unsubscribe(shared_from_this());
        }

        // If an error occurs then no new asynchronous operations are started. This
        // means that all shared_ptr references to the ServerConnection object will
        // disappear and the object will be destroyed automatically after this
        // handler returns. The ServerConnection class's destructor closes the socket.

        TRACE_EXIT();
    }

    void ServerConnection::handle_write(const boost::system::error_code& e, MessagePtr message)
    {
        TRACE_ENTER();

        if (!e)
        {
            LOG_DEBUG("Successfully sent message to client: " << message);

            BOOST_FOREACH(MessageHandlerPtr mh, messageHandlers)
            {
#if 0
                /* melkins
                 * The reads and writes to the socket are asynchronous, so
                 * we should never be waiting for something to be read as
                 * a result of a write.
                 */
                if(waitForResponse) // someone already said they wanted a response, so ignore ret val for others
                    mh->handleMessageSent(message);
                else
                    waitForResponse=mh->handleMessageSent(message);
#endif
                    mh->handleMessageSent(message);
            }

            // melkins
            // start() calls async_read(), which is not what we want to do here
            /*
            if(waitForResponse)
                start();
                */
        }
        else
        {
            LOG_WARN("Error while sending response to client: " << e);
            if (conn_type == gui)
                watcher.unsubscribe(shared_from_this());
        }

        // No new asynchronous operations are started. This means that all shared_ptr
        // references to the connection object will disappear and the object will be
        // destroyed automatically after this handler returns. The connection class's
        // destructor closes the socket.

        /* NOTE: The refcount will not go to zero so long as there is an
         * async_read operation also oustanding. */

        TRACE_EXIT();
    }

    /** Send a single message to this connected client. */
    void ServerConnection::sendMessage(MessagePtr msg)
    {
        TRACE_ENTER();
        DataMarshaller::NetworkMarshalBuffers outBuffers;
        DataMarshaller::marshalPayload(msg, outBuffers);

        /// FIXME melkins 2004-04-19
        // is it safe to call async_write and async_read from different
        // threads at the same time?  asio::tcp::socket() is listed at not
        // shared thread safe
        async_write(theSocket,
                    outBuffers,
                    write_strand_.wrap( boost::bind( &ServerConnection::handle_write,
                                               shared_from_this(),
                                               placeholders::error,
                                               msg)));
        TRACE_EXIT();
    }

    /** Send a set of messages to this connected client. */
    void ServerConnection::sendMessage(const std::vector<MessagePtr>& msgs)
    {
        TRACE_ENTER();
        DataMarshaller::NetworkMarshalBuffers outBuffers;
        DataMarshaller::marshalPayload(msgs, outBuffers);

        /// FIXME melkins 2004-04-19
        // is it safe to call async_write and async_read from different
        // threads at the same time?
        async_write(theSocket,
                    outBuffers,
                    write_strand_.wrap( boost::bind( &ServerConnection::handle_write,
                                               shared_from_this(),
                                               placeholders::error,
                                               msgs.front())));
        TRACE_EXIT();
    }

}
<commit_msg>use references in BOOST_FOREACH to avoid MAKIN' COPIEEEES<commit_after>#include "serverConnection.h"
#include <vector>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>

#include <libwatcher/message.h>
#include <libwatcher/messageStatus.h>
#include <libwatcher/seekWatcherMessage.h>
#include <libwatcher/speedWatcherMessage.h>

#include "messageFactory.h"
#include "dataMarshaller.h"
#include "watcherd.h"
#include "writeDBMessageHandler.h"
#include "watcherdConfig.h"

using namespace std;
using namespace boost::asio;

namespace {
    using namespace watcher::event;

    /* Grr, because there is no std::copy_if have to use the negation with
     * remove_copy_if() */
    bool not_feeder_message(const MessagePtr& m)
    {
        return !isFeederEvent(m->type);
    }
}

namespace watcher {
    using namespace event;

    INIT_LOGGER(ServerConnection, "Connection.ServerConnection");

    ServerConnection::ServerConnection(Watcherd& w, boost::asio::io_service& io_service) :
        Connection(io_service),
        watcher(w),
        io_service_(io_service),
        strand_(io_service),
        write_strand_(io_service),
        conn_type(unknown),
        isPlaying_(false), isLive_(true)
    {
        TRACE_ENTER();
        TRACE_EXIT();
    }

    ServerConnection::~ServerConnection()
    {
        TRACE_ENTER();
        //shared_from_this() not allowed in destructor
        //watcher.unsubscribe(shared_from_this());
        TRACE_EXIT();
    }

    /** Initialization point for start of new ServerConnection thread. */
    void ServerConnection::run()
    {
        /*
         * Pull endpoint info out of the socket and make it available via the
         * Connection::getPeerAddr() member function.
         */
        boost::asio::ip::tcp::endpoint ep = getSocket().remote_endpoint();
        endpoint_addr_ = ep.address().to_string();
        endpoint_port_ = ep.port();

        start();
    }

    void ServerConnection::start()
    {
        TRACE_ENTER();
        boost::asio::async_read(
                theSocket,
                boost::asio::buffer(incomingBuffer, DataMarshaller::header_length),
                strand_.wrap(
                    boost::bind(
                        &ServerConnection::handle_read_header,
                        shared_from_this(),
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred)));
        TRACE_EXIT();
    }

    void ServerConnection::handle_read_header(const boost::system::error_code& e, size_t bytes_transferred)
    {
        TRACE_ENTER();
        if (!e)
        {
            LOG_DEBUG("Read " << bytes_transferred << " bytes.");

            size_t payloadSize;
            unsigned short numOfMessages;
            if (!DataMarshaller::unmarshalHeader(incomingBuffer.begin(), bytes_transferred, payloadSize, numOfMessages))
            {
                LOG_ERROR("Error parsing incoming message header.");

                if (conn_type == gui)
                    watcher.unsubscribe(shared_from_this());
            }
            else
            {
                LOG_DEBUG("Reading packet payload of " << payloadSize << " bytes.");

                boost::asio::async_read(
                        theSocket,
                        boost::asio::buffer(
                            incomingBuffer,
                            payloadSize),  // Should incoming buffer be new'd()?
                        strand_.wrap(
                            boost::bind(
                                &ServerConnection::handle_read_payload,
                                shared_from_this(),
                                boost::asio::placeholders::error,
                                boost::asio::placeholders::bytes_transferred,
                                numOfMessages)));
            }
        }
        else
        {
            if (e==boost::asio::error::eof)
            {
                LOG_DEBUG("Received empty message from clienti or client closed connection.");
                LOG_INFO("Connection to client closed.");

            }
            else
            {
                LOG_ERROR("Error reading socket: " << e.message());
            }

            // unsubscribe to event stream, otherwise it will hold a
            // shared_ptr open
            if (conn_type == gui)
                watcher.unsubscribe(shared_from_this());
        }
        TRACE_EXIT();
    }

    void ServerConnection::handle_read_payload(const boost::system::error_code& e, size_t bytes_transferred, unsigned short numOfMessages)
    {
        TRACE_ENTER();

        if (!e)
        {
            vector<MessagePtr> arrivedMessages;
            if (DataMarshaller::unmarshalPayload(arrivedMessages, numOfMessages, incomingBuffer.begin(), bytes_transferred))
            {
                LOG_INFO("Recvd " << arrivedMessages.size() << " message" <<
                         (arrivedMessages.size()>1?"s":"") << " from " <<
                         getPeerAddr());

                // Add the incoming address to the Message so everyone
                // knows who the message came from.
                boost::asio::ip::tcp::endpoint ep = getSocket().remote_endpoint();
                BOOST_FOREACH(MessagePtr m, arrivedMessages) {
                    if(m->fromNodeID==NodeIdentifier())  // is empty
                        m->fromNodeID=ep.address();
                }

                /*
                 * If this connection type is unknown or gui, then traverse the
                 * list of arrived messages.  For GUI clients, look for the
                 * STOP_MESSAGE to unsubscribe from the event stream.
                 *
                 * For unknown clients, infer the type from the message
                 * received:
                 * START_MESSAGE => gui
                 * isFeederMessage => feeder
                 */
                if (conn_type == unknown || conn_type == gui) {
                    BOOST_FOREACH(MessagePtr& i, arrivedMessages) {
                        if (i->type == START_MESSAGE_TYPE) {
                            /* Client is requesting the live stream of events. */
                            if (conn_type == unknown) {
                                conn_type = gui;
                                replay = boost::shared_ptr<ReplayState>(new ReplayState(shared_from_this()));
                            }
                            if (!isPlaying_) {
                                isPlaying_ = true;
                                if (isLive_)
                                    watcher.subscribe(shared_from_this());
                                else
                                    replay->run();
                            }
                        } else if (i->type == SEEK_MESSAGE_TYPE) {
                            if (conn_type == unknown) {
                                conn_type = gui;
                                replay = boost::shared_ptr<ReplayState>(new ReplayState(shared_from_this()));
                            }
                            SeekMessagePtr p = boost::dynamic_pointer_cast<SeekMessage>(i);
                            if (p) {
                                if (p->offset == SeekMessage::eof) {
                                    // switch to live stream
                                    if (!isLive_) {
                                        isLive_ = true;
                                        replay->pause();
                                        if (isPlaying_)
                                            watcher.subscribe(shared_from_this());
                                    }
                                } else {
                                    replay->seek(p->offset);

                                    // when switching from live to replay while playing, kick off the replay strand
                                    if (isLive_ && isPlaying_)
                                        replay->run();
                                    isLive_ = false;
                                }
                            }
                        } else if (i->type == SPEED_MESSAGE_TYPE) {
                            if (conn_type == unknown) {
                                conn_type = gui;
                                replay = boost::shared_ptr<ReplayState>(new ReplayState(shared_from_this()));
                            }
                            SpeedMessagePtr p = boost::dynamic_pointer_cast<SpeedMessage>(i);
                            if (p)
                                replay->speed(p->speed);
                        } else if (i->type == STOP_MESSAGE_TYPE) {
                            if (conn_type == unknown) {
                                conn_type = gui;
                                replay = boost::shared_ptr<ReplayState>(new ReplayState(shared_from_this()));
                            }
                            if (isPlaying_) {
                                if (isLive_)
                                    watcher.unsubscribe(shared_from_this());
                                else
                                    replay->pause();
                                isPlaying_ = false;
                            }
                        } else if (isFeederEvent(i->type)) {
                            conn_type = feeder;

                            /*
                             * This connection is a watcher test daemon.
                             * Add a message handler to write its event
                             * stream to the database.
                             */
                            addMessageHandler(MessageHandlerPtr(new WriteDBMessageHandler()));
                        }
                    }
                }

                /* Flag indicating whether to continue reading from this
                 * connection. */
                bool fail = false;

                BOOST_FOREACH(MessageHandlerPtr& mh, messageHandlers) {
                    if (mh->handleMessagesArrive(shared_from_this(), arrivedMessages)) {
                        fail = true;
                        LOG_DEBUG("Message handler told us to close this connection.");
                    }
                }

                if (!fail) {
                    // initiate request to read next message
                    LOG_DEBUG("Waiting for next message.");
                    start();
                }

                if (conn_type == feeder) {
                    /* relay feeder message to any client requesting the live stream.
                     * Warning: currently there is no check to make sure that a client doesn't
                     * receive a message it just sent.  This should be OK since we are just
                     * relaying feeder messages only, and the GUIs should not be sending
                     * them. */
                    vector<MessagePtr> feeder;
                    remove_copy_if(arrivedMessages.begin(), arrivedMessages.end(), back_inserter(feeder), not_feeder_message);
                    if (! feeder.empty()) {
                        LOG_DEBUG("Sending " << feeder.size() << " feeder messages to clients.");
                        watcher.sendMessage(feeder);
                    }
                }
            }
        }
        else
        {
            LOG_WARN("Did not understand incoming message.");

            // unsubscribe to event stream, otherwise it will hold a
            // shared_ptr open
            if (conn_type == gui)
                watcher.unsubscribe(shared_from_this());
        }

        // If an error occurs then no new asynchronous operations are started. This
        // means that all shared_ptr references to the ServerConnection object will
        // disappear and the object will be destroyed automatically after this
        // handler returns. The ServerConnection class's destructor closes the socket.

        TRACE_EXIT();
    }

    void ServerConnection::handle_write(const boost::system::error_code& e, MessagePtr message)
    {
        TRACE_ENTER();

        if (!e)
        {
            LOG_DEBUG("Successfully sent message to client: " << message);

            BOOST_FOREACH(MessageHandlerPtr mh, messageHandlers)
            {
#if 0
                /* melkins
                 * The reads and writes to the socket are asynchronous, so
                 * we should never be waiting for something to be read as
                 * a result of a write.
                 */
                if(waitForResponse) // someone already said they wanted a response, so ignore ret val for others
                    mh->handleMessageSent(message);
                else
                    waitForResponse=mh->handleMessageSent(message);
#endif
                    mh->handleMessageSent(message);
            }

            // melkins
            // start() calls async_read(), which is not what we want to do here
            /*
            if(waitForResponse)
                start();
                */
        }
        else
        {
            LOG_WARN("Error while sending response to client: " << e);
            if (conn_type == gui)
                watcher.unsubscribe(shared_from_this());
        }

        // No new asynchronous operations are started. This means that all shared_ptr
        // references to the connection object will disappear and the object will be
        // destroyed automatically after this handler returns. The connection class's
        // destructor closes the socket.

        /* NOTE: The refcount will not go to zero so long as there is an
         * async_read operation also oustanding. */

        TRACE_EXIT();
    }

    /** Send a single message to this connected client. */
    void ServerConnection::sendMessage(MessagePtr msg)
    {
        TRACE_ENTER();
        DataMarshaller::NetworkMarshalBuffers outBuffers;
        DataMarshaller::marshalPayload(msg, outBuffers);

        /// FIXME melkins 2004-04-19
        // is it safe to call async_write and async_read from different
        // threads at the same time?  asio::tcp::socket() is listed at not
        // shared thread safe
        async_write(theSocket,
                    outBuffers,
                    write_strand_.wrap( boost::bind( &ServerConnection::handle_write,
                                               shared_from_this(),
                                               placeholders::error,
                                               msg)));
        TRACE_EXIT();
    }

    /** Send a set of messages to this connected client. */
    void ServerConnection::sendMessage(const std::vector<MessagePtr>& msgs)
    {
        TRACE_ENTER();
        DataMarshaller::NetworkMarshalBuffers outBuffers;
        DataMarshaller::marshalPayload(msgs, outBuffers);

        /// FIXME melkins 2004-04-19
        // is it safe to call async_write and async_read from different
        // threads at the same time?
        async_write(theSocket,
                    outBuffers,
                    write_strand_.wrap( boost::bind( &ServerConnection::handle_write,
                                               shared_from_this(),
                                               placeholders::error,
                                               msgs.front())));
        TRACE_EXIT();
    }

}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/syscoin-config.h>
#endif

#include <cstddef>
#include <cstdint>
// SYSCOIN
#define _GNU_SOURCE 1
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/cdefs.h>
#ifndef WIN32
#include <fcntl.h>
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_GETRANDOM
#include <sys/syscall.h>
#include <linux/random.h>
#endif
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#define likely(x)      __builtin_expect(!!(x), 1)
#define unlikely(x)    __builtin_expect(!!(x), 0)
// Prior to GLIBC_2.14, memcpy was aliased to memmove.
extern "C" void* memmove(void* a, const void* b, size_t c);
extern "C" void* memcpy(void* a, const void* b, size_t c)
{
    return memmove(a, b, c);
}

#if defined(__i386__) || defined(__arm__)

extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp);

extern "C" int64_t __wrap___divmoddi4(int64_t u, int64_t v, int64_t* rp)
{
    int32_t c1 = 0, c2 = 0;
    int64_t uu = u, vv = v;
    int64_t w;
    int64_t r;

    if (uu < 0) {
        c1 = ~c1, c2 = ~c2, uu = -uu;
    }
    if (vv < 0) {
        c1 = ~c1, vv = -vv;
    }

    w = __udivmoddi4(uu, vv, (uint64_t*)&r);
    if (c1)
        w = -w;
    if (c2)
        r = -r;

    *rp = r;
    return w;
}
#endif

extern "C" float log2f_old(float x);
#ifdef __i386__
__asm(".symver log2f_old,log2f@GLIBC_2.1");
#elif defined(__amd64__)
__asm(".symver log2f_old,log2f@GLIBC_2.2.5");
#elif defined(__arm__)
__asm(".symver log2f_old,log2f@GLIBC_2.4");
#elif defined(__aarch64__)
__asm(".symver log2f_old,log2f@GLIBC_2.17");
#elif defined(__riscv)
__asm(".symver log2f_old,log2f@GLIBC_2.27");
#endif
extern "C" float __wrap_log2f(float x)
{
    return log2f_old(x);
}
// SYSCOIN wrapper for getrandom 2.25 glibc compatbility for up to 2.17 backwards
#ifndef WIN32
/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most
 * compatible way to get cryptographic randomness on UNIX-ish platforms.
 */
static ssize_t GetDevURandom(unsigned char *ent32, size_t length)
{
    int f = open("/dev/urandom", O_RDONLY);
    if (f == -1) {
        return -1;
    }
    int have = 0;
    do {
        ssize_t n = read(f, ent32 + have, length - have);
        if (n <= 0 || n + have > length) {
            close(f);
            return n;
        }
        have += n;
    } while (have < length);
    close(f);
    return have;
}
#endif

/* Write LENGTH bytes of randomness starting at BUFFER.  Return 0 on
    success and -1 on failure.  */
extern "C" ssize_t __wrap_getrandom (void *buffer, size_t length, unsigned int flags)
    {
        ssize_t rv = -1;
        #if defined(HAVE_SYS_GETRANDOM)
        /* Linux. From the getrandom(2) man page:
        * "If the urandom source has been initialized, reads of up to 256 bytes
        * will always return as many bytes as requested and will not be
        * interrupted by signals."
        */
        rv = syscall(SYS_getrandom, buffer, length, flags);
        if (rv != length) {
            if (rv < 0 && errno == ENOSYS) {
                /* Fallback for kernel <3.17: the return value will be -1 and errno
                * ENOSYS if the syscall is not available, in that case fall back
                * to /dev/urandom.
                */
                return GetDevURandom((unsigned char*)buffer, length);
            }
        }
        #else
            return GetDevURandom((unsigned char*)buffer, length);
        #endif
        return rv;
    }

    // fmemopen

typedef struct fmemopen_cookie_struct fmemopen_cookie_t;
struct fmemopen_cookie_struct
{
  char        *buffer;   /* memory buffer.  */
  int         mybuffer;  /* allocated my buffer?  */
  int         append;    /* buffer open for append?  */
  size_t      size;      /* buffer length in bytes.  */
  off_t     pos;       /* current position at the buffer.  */
  size_t      maxpos;    /* max position in buffer.  */
};

static ssize_t
fmemopen_read (void *cookie, char *b, size_t s)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  if (c->pos + s > c->maxpos)
    {
      s = c->maxpos - c->pos;
      if ((size_t) c->pos > c->maxpos)
	s = 0;
    }

  memcpy (b, &(c->buffer[c->pos]), s);

  c->pos += s;

  return s;
}

static ssize_t
fmemopen_write (void *cookie, const char *b, size_t s)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;;
  off_t pos = c->append ? c->maxpos : c->pos;
  int addnullc = (s == 0 || b[s - 1] != '\0');

  if (pos + s > c->size)
    {
      if ((size_t) (c->pos + addnullc) >= c->size)
	{
	  errno = ENOSPC;
	  return 0;
	}
      s = c->size - pos;
    }

  memcpy (&(c->buffer[pos]), b, s);

  c->pos = pos + s;
  if ((size_t) c->pos > c->maxpos)
    {
      c->maxpos = c->pos;
      if (c->maxpos < c->size && addnullc)
	c->buffer[c->maxpos] = '\0';
      /* A null byte is written in a stream open for update iff it fits.  */
      else if (c->append == 0 && addnullc != 0)
	c->buffer[c->size-1] = '\0';
    }

  return s;
}

static int
fmemopen_seek (void *cookie, off_t *p, int w)
{
  off_t np;
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  switch (w)
    {
    case SEEK_SET:
      np = *p;
      break;

    case SEEK_CUR:
      np = c->pos + *p;
      break;

    case SEEK_END:
      np = c->maxpos + *p;
      break;

    default:
      return -1;
    }

  if (np < 0 || (size_t) np > c->size)
    {
      errno = EINVAL;
      return -1;
    }

  *p = c->pos = np;

  return 0;
}

static int
fmemopen_close (void *cookie)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  if (c->mybuffer)
    free (c->buffer);
  free (c);

  return 0;
}

extern "C" FILE * __wrap_fmemopen (void *buf, size_t len, const char *mode)
{
  cookie_io_functions_t iof;
  fmemopen_cookie_t *c;
  FILE *result;

  c = (fmemopen_cookie_t *) calloc (sizeof (fmemopen_cookie_t), 1);
  if (c == NULL)
    return NULL;

  c->mybuffer = (buf == NULL);

  if (c->mybuffer)
    {
      c->buffer = (char *) malloc (len);
      if (c->buffer == NULL)
	{
	  free (c);
	  return NULL;
	}
      c->buffer[0] = '\0';
    }
  else
    {
      if (likely ((uintptr_t) len > -(uintptr_t) buf))
	{
	  free (c);
	  errno = EINVAL;
	  return NULL;
	}

      c->buffer = (char*)buf;

      /* POSIX states that w+ mode should truncate the buffer.  */
      if (mode[0] == 'w' && mode[1] == '+')
	c->buffer[0] = '\0';

      if (mode[0] == 'a')
        c->maxpos = strnlen (c->buffer, len);
    }

  /* Mode   |  starting position (cookie::pos) |          size (cookie::size)
     ------ |----------------------------------|-----------------------------
     read   |          beginning of the buffer |                size argument
     write  |          beginning of the buffer |                         zero
     append |    first null or size buffer + 1 |  first null or size argument
   */

  c->size = len;

  if (mode[0] == 'r')
    c->maxpos = len;

  c->append = mode[0] == 'a';
  if (c->append)
    c->pos = c->maxpos;
  else
    c->pos = 0;

  iof.read = fmemopen_read;
  iof.write = fmemopen_write;
  iof.seek = fmemopen_seek;
  iof.close = fmemopen_close;

  result = fopencookie (c, mode, iof);
  if (likely (result == NULL))
    {
      if (c->mybuffer)
	free (c->buffer);

      free (c);
    }

  return result;
}<commit_msg>rm memcpy alias which was <= 2.14 glibc and now we only support >= 2.17<commit_after>// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/syscoin-config.h>
#endif

#include <cstddef>
#include <cstdint>
// SYSCOIN
#define _GNU_SOURCE 1
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/cdefs.h>
#ifndef WIN32
#include <fcntl.h>
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_GETRANDOM
#include <sys/syscall.h>
#include <linux/random.h>
#endif
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#define likely(x)      __builtin_expect(!!(x), 1)
#define unlikely(x)    __builtin_expect(!!(x), 0)
#if defined(__i386__) || defined(__arm__)

extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp);

extern "C" int64_t __wrap___divmoddi4(int64_t u, int64_t v, int64_t* rp)
{
    int32_t c1 = 0, c2 = 0;
    int64_t uu = u, vv = v;
    int64_t w;
    int64_t r;

    if (uu < 0) {
        c1 = ~c1, c2 = ~c2, uu = -uu;
    }
    if (vv < 0) {
        c1 = ~c1, vv = -vv;
    }

    w = __udivmoddi4(uu, vv, (uint64_t*)&r);
    if (c1)
        w = -w;
    if (c2)
        r = -r;

    *rp = r;
    return w;
}
#endif

extern "C" float log2f_old(float x);
#ifdef __i386__
__asm(".symver log2f_old,log2f@GLIBC_2.1");
#elif defined(__amd64__)
__asm(".symver log2f_old,log2f@GLIBC_2.2.5");
#elif defined(__arm__)
__asm(".symver log2f_old,log2f@GLIBC_2.4");
#elif defined(__aarch64__)
__asm(".symver log2f_old,log2f@GLIBC_2.17");
#elif defined(__riscv)
__asm(".symver log2f_old,log2f@GLIBC_2.27");
#endif
extern "C" float __wrap_log2f(float x)
{
    return log2f_old(x);
}
// SYSCOIN wrapper for getrandom 2.25 glibc compatbility for up to 2.17 backwards
#ifndef WIN32
/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most
 * compatible way to get cryptographic randomness on UNIX-ish platforms.
 */
static ssize_t GetDevURandom(unsigned char *ent32, size_t length)
{
    int f = open("/dev/urandom", O_RDONLY);
    if (f == -1) {
        return -1;
    }
    int have = 0;
    do {
        ssize_t n = read(f, ent32 + have, length - have);
        if (n <= 0 || n + have > length) {
            close(f);
            return n;
        }
        have += n;
    } while (have < length);
    close(f);
    return have;
}
#endif

/* Write LENGTH bytes of randomness starting at BUFFER.  Return 0 on
    success and -1 on failure.  */
extern "C" ssize_t __wrap_getrandom (void *buffer, size_t length, unsigned int flags)
    {
        ssize_t rv = -1;
        #if defined(HAVE_SYS_GETRANDOM)
        /* Linux. From the getrandom(2) man page:
        * "If the urandom source has been initialized, reads of up to 256 bytes
        * will always return as many bytes as requested and will not be
        * interrupted by signals."
        */
        rv = syscall(SYS_getrandom, buffer, length, flags);
        if (rv != length) {
            if (rv < 0 && errno == ENOSYS) {
                /* Fallback for kernel <3.17: the return value will be -1 and errno
                * ENOSYS if the syscall is not available, in that case fall back
                * to /dev/urandom.
                */
                return GetDevURandom((unsigned char*)buffer, length);
            }
        }
        #else
            return GetDevURandom((unsigned char*)buffer, length);
        #endif
        return rv;
    }

    // fmemopen

typedef struct fmemopen_cookie_struct fmemopen_cookie_t;
struct fmemopen_cookie_struct
{
  char        *buffer;   /* memory buffer.  */
  int         mybuffer;  /* allocated my buffer?  */
  int         append;    /* buffer open for append?  */
  size_t      size;      /* buffer length in bytes.  */
  off_t     pos;       /* current position at the buffer.  */
  size_t      maxpos;    /* max position in buffer.  */
};

static ssize_t
fmemopen_read (void *cookie, char *b, size_t s)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  if (c->pos + s > c->maxpos)
    {
      s = c->maxpos - c->pos;
      if ((size_t) c->pos > c->maxpos)
	s = 0;
    }

  memcpy (b, &(c->buffer[c->pos]), s);

  c->pos += s;

  return s;
}

static ssize_t
fmemopen_write (void *cookie, const char *b, size_t s)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;;
  off_t pos = c->append ? c->maxpos : c->pos;
  int addnullc = (s == 0 || b[s - 1] != '\0');

  if (pos + s > c->size)
    {
      if ((size_t) (c->pos + addnullc) >= c->size)
	{
	  errno = ENOSPC;
	  return 0;
	}
      s = c->size - pos;
    }

  memcpy (&(c->buffer[pos]), b, s);

  c->pos = pos + s;
  if ((size_t) c->pos > c->maxpos)
    {
      c->maxpos = c->pos;
      if (c->maxpos < c->size && addnullc)
	c->buffer[c->maxpos] = '\0';
      /* A null byte is written in a stream open for update iff it fits.  */
      else if (c->append == 0 && addnullc != 0)
	c->buffer[c->size-1] = '\0';
    }

  return s;
}

static int
fmemopen_seek (void *cookie, off_t *p, int w)
{
  off_t np;
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  switch (w)
    {
    case SEEK_SET:
      np = *p;
      break;

    case SEEK_CUR:
      np = c->pos + *p;
      break;

    case SEEK_END:
      np = c->maxpos + *p;
      break;

    default:
      return -1;
    }

  if (np < 0 || (size_t) np > c->size)
    {
      errno = EINVAL;
      return -1;
    }

  *p = c->pos = np;

  return 0;
}

static int
fmemopen_close (void *cookie)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  if (c->mybuffer)
    free (c->buffer);
  free (c);

  return 0;
}

extern "C" FILE * __wrap_fmemopen (void *buf, size_t len, const char *mode)
{
  cookie_io_functions_t iof;
  fmemopen_cookie_t *c;
  FILE *result;

  c = (fmemopen_cookie_t *) calloc (sizeof (fmemopen_cookie_t), 1);
  if (c == NULL)
    return NULL;

  c->mybuffer = (buf == NULL);

  if (c->mybuffer)
    {
      c->buffer = (char *) malloc (len);
      if (c->buffer == NULL)
	{
	  free (c);
	  return NULL;
	}
      c->buffer[0] = '\0';
    }
  else
    {
      if (likely ((uintptr_t) len > -(uintptr_t) buf))
	{
	  free (c);
	  errno = EINVAL;
	  return NULL;
	}

      c->buffer = (char*)buf;

      /* POSIX states that w+ mode should truncate the buffer.  */
      if (mode[0] == 'w' && mode[1] == '+')
	c->buffer[0] = '\0';

      if (mode[0] == 'a')
        c->maxpos = strnlen (c->buffer, len);
    }

  /* Mode   |  starting position (cookie::pos) |          size (cookie::size)
     ------ |----------------------------------|-----------------------------
     read   |          beginning of the buffer |                size argument
     write  |          beginning of the buffer |                         zero
     append |    first null or size buffer + 1 |  first null or size argument
   */

  c->size = len;

  if (mode[0] == 'r')
    c->maxpos = len;

  c->append = mode[0] == 'a';
  if (c->append)
    c->pos = c->maxpos;
  else
    c->pos = 0;

  iof.read = fmemopen_read;
  iof.write = fmemopen_write;
  iof.seek = fmemopen_seek;
  iof.close = fmemopen_close;

  result = fopencookie (c, mode, iof);
  if (likely (result == NULL))
    {
      if (c->mybuffer)
	free (c->buffer);

      free (c);
    }

  return result;
}<|endoftext|>


<commit_before>// This file is part of the dune-pymor project:
//   https://github.com/pyMor/dune-pymor
// Copyright Holders: Felix Albrecht, Stephan Rave
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_PYMOR_FUNCTIONALS_DEFAULT_HH
#define DUNE_PYMOR_FUNCTIONALS_DEFAULT_HH

#include <dune/common/typetraits.hh>

#include <dune/pymor/parameters/functional.hh>
#include <dune/pymor/la/container/interfaces.hh>
#include "interfaces.hh"

namespace Dune {
namespace Pymor {
namespace Functionals {

template< class LinearFunctionalType >
class LinearAffinelyDecomposedDefault
  : public AffinelyDecomposedFunctionalInterface
{
public:
  typedef typename LinearFunctionalType::SourceType SourceType;

  LinearAffinelyDecomposedDefault();

  LinearAffinelyDecomposedDefault(LinearFunctionalType* aff) throw (Exception::requirements_not_met);

  virtual ~LinearAffinelyDecomposedDefault();

  /**
   * \attention This class takes ownership of aff!
   */
  void register_component(LinearFunctionalType* aff) throw (Exception::this_does_not_make_any_sense,
                                                            Exception::sizes_do_not_match,
                                                            Exception::types_are_not_compatible);

  /**
   * \attention This class takes ownership of comp and coeff!
   */
  void register_component(LinearFunctionalType* comp, const ParameterFunctional* coeff)
    throw (Exception::this_does_not_make_any_sense,
           Exception::sizes_do_not_match,
           Exception::types_are_not_compatible,
           Exception::wrong_parameter_type);

  virtual unsigned int num_components() const;

  virtual LinearFunctionalType* component(const int ii) throw (Exception::requirements_not_met,
                                                               Exception::index_out_of_range);

  virtual const LinearFunctionalType* component(const int ii) const throw (Exception::requirements_not_met,
                                                                           Exception::index_out_of_range);

  virtual const ParameterFunctional* coefficient(const int ii) const throw (Exception::requirements_not_met,
                                                                            Exception::index_out_of_range);

  virtual bool hasAffinePart() const;

  virtual LinearFunctionalType* affinePart() throw (Exception::requirements_not_met);

  virtual const LinearFunctionalType* affinePart() const throw (Exception::requirements_not_met);

  virtual bool linear() const;

  virtual unsigned int dim_source() const;

  virtual std::string type_source() const;

  virtual double apply(const LA::VectorInterface* source,
                       const Parameter /*mu*/ = Parameter()) const throw (Exception::types_are_not_compatible,
                                                                          Exception::you_have_to_implement_this,
                                                                          Exception::sizes_do_not_match,
                                                                          Exception::wrong_parameter_type,
                                                                          Exception::requirements_not_met,
                                                                          Exception::linear_solver_failed,
                                                                          Exception::this_does_not_make_any_sense);

  virtual double apply(const SourceType* source,
                       const Parameter mu = Parameter()) const
    throw (Exception::types_are_not_compatible,
           Exception::you_have_to_implement_this,
           Exception::sizes_do_not_match,
           Exception::wrong_parameter_type,
           Exception::requirements_not_met,
           Exception::linear_solver_failed,
           Exception::this_does_not_make_any_sense);

  LinearFunctionalType* freeze_parameter(const Parameter mu = Parameter()) const
    throw (Exception::this_is_not_parametric,
           Exception::you_have_to_implement_this,
           Exception::this_does_not_make_any_sense);

private:
  unsigned int size_;
  bool hasAffinePart_;
  unsigned int dim_source_;
  std::string type_source_;
  std::vector< LinearFunctionalType* > components_;
  std::vector< const ParameterFunctional* > coefficients_;
  LinearFunctionalType* affinePart_;
}; // class LinearAffinelyDecomposedDefault

} // namespace Functionals
} // namespace Pymor
} // namespace Dune

#endif // DUNE_PYMOR_FUNCTIONALS_DEFAULT_HH
<commit_msg>[functionals.default] added VectorBased<commit_after>// This file is part of the dune-pymor project:
//   https://github.com/pyMor/dune-pymor
// Copyright Holders: Felix Albrecht, Stephan Rave
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_PYMOR_FUNCTIONALS_DEFAULT_HH
#define DUNE_PYMOR_FUNCTIONALS_DEFAULT_HH

#include <dune/common/typetraits.hh>

#include <dune/pymor/parameters/functional.hh>
#include <dune/pymor/la/container/interfaces.hh>
#include "interfaces.hh"

namespace Dune {
namespace Pymor {
namespace Functionals {

template< class VectorImp >
class VectorBased;

template< class VectorImp >
class VectorBasedTraits
{
public:
  typedef VectorBased< VectorImp >        derived_type;
  typedef VectorImp                       VectorType;
  typedef VectorType                      SourceType;
  typedef derived_type                    FrozenType;
  typedef typename SourceType::ScalarType ScalarType;
  static_assert(std::is_base_of< Dune::Pymor::LA::VectorInterface< typename VectorImp::Traits >, VectorType >::value,
                "VectorType must be derived from Dune::Pymor::LA::VectorInterface!");
};

template< class VectorImp >
class VectorBased
  : public FunctionalInterface< VectorBasedTraits< VectorImp > >
{
public:
  typedef VectorBasedTraits< VectorImp >  Traits;
  typedef typename Traits::derived_type   ThisType;
  typedef typename Traits::VectorType     VectorType;
  typedef typename Traits::SourceType     SourceType;
  typedef typename Traits::ScalarType     ScalarType;
  typedef typename Traits::FrozenType     FrozenType;

  /**
   * \attention This class takes ownership of vector_ptr!
   */
  VectorBased(const VectorType* vector_ptr)
    : vector_(vector_ptr)
  {}

  VectorBased(const std::shared_ptr< const VectorType > vector_ptr)
    : vector_(vector_ptr)
  {}

  bool linear() const
  {
    return true;
  }

  unsigned int dim_source() const
  {
    return vector_->dim();
  }

  ScalarType apply(const SourceType& source, const Parameter mu = Parameter()) const
    throw (Exception::this_is_not_parametric)
  {
    if (!mu.empty()) DUNE_PYMOR_THROW(Exception::this_is_not_parametric,
                                      "mu has to be empty if parametric() == false (is " << mu << ")!");
    return vector_->dot(source);
  }

  FrozenType freeze_parameter(const Parameter mu = Parameter()) const
    throw (Exception::this_is_not_parametric)
  {
    DUNE_PYMOR_THROW(Exception::this_is_not_parametric, "do not call freeze_parameter(" << mu << ")"
                     << "if parametric() == false!");
    return FrozenType(new VectorType());
  }

  std::shared_ptr< const VectorType > vector() const
  {
    return vector_;
  }
private:
  std::shared_ptr< const VectorType > vector_;
}; // class VectorBased

} // namespace Functionals
} // namespace Pymor
} // namespace Dune

#endif // DUNE_PYMOR_FUNCTIONALS_DEFAULT_HH
<|endoftext|>


<commit_before>// A shared register can have shared register writers, readers and
// dataflow entries (equivalent to readers).
//
// shared-reg-writer generates connections from shared-reg-writer to shared-reg.
// shared-reg generates connections from shared-reg to shared-reg-reader.

#include "writer/verilog/shared_reg.h"

#include "design/design_util.h"
#include "iroha/i_design.h"
#include "iroha/logging.h"
#include "iroha/resource_class.h"
#include "iroha/resource_params.h"
#include "writer/connection.h"
#include "writer/module_template.h"
#include "writer/verilog/insn_writer.h"
#include "writer/verilog/inter_module_wire.h"
#include "writer/verilog/module.h"
#include "writer/verilog/ports.h"
#include "writer/verilog/state.h"
#include "writer/verilog/table.h"
#include "writer/verilog/shared_reg_accessor.h"

namespace iroha {
namespace writer {
namespace verilog {

SharedReg::SharedReg(const IResource &res, const Table &table)
  : Resource(res, table), has_default_output_value_(false),
    default_output_value_(0),
    need_write_arbitration_(false) {
  auto *klass = res_.GetClass();
  CHECK(resource::IsSharedReg(*klass));
  auto *params = res_.GetParams();
  string unused;
  params->GetExtOutputPort(&unused, &width_);
  has_default_output_value_ =
    params->GetDefaultValue(&default_output_value_);
  auto &readers =
    table.GetModule()->GetConnection().GetSharedRegReaders(&res_);
  for (auto *r : readers) {
    readers_.push_back(r);
  }
  auto &children =
    table.GetModule()->GetConnection().GetSharedRegChildren(&res_);
  for (auto *r : children) {
    readers_.push_back(r);
  }
  writers_ = table.GetModule()->GetConnection().GetSharedRegWriters(&res_);
  if (writers_.size() > 0 || has_default_output_value_) {
    need_write_arbitration_ = true;
  }
  GetOptions(&use_notify_, &use_mailbox_);
}

void SharedReg::BuildResource() {
  ostream &rs = tab_.ResourceSectionStream();
  ostream &is = tab_.InitialValueSectionStream();
  rs << "  // shared-reg";
  if (use_notify_) {
    rs << " use-notify";
  }
  if (use_mailbox_) {
    rs << " use-mailbox";
  }
  rs << "\n";
  if (readers_.size() == 0) {
    rs << "  reg ";
    if (width_ > 0) {
      rs << "[" << width_ - 1 << ":0]";
    }
    rs << " " << RegName(res_) << ";\n";
  }
  // Reset value
  is << "      " << RegName(res_) << " <= ";
  if (has_default_output_value_) {
    is << default_output_value_;
  } else {
    is << 0;
  }
  is << ";\n";
  if (use_notify_) {
    vector<string> notifiers;
    for (auto *writer : writers_) {
      if (SharedRegAccessor::UseNotify(writer)) {
	notifiers.push_back(WriterNotifierName(*writer));
      }
    }
    ostream &os = tab_.StateOutputSectionStream();
    os << "      " << RegNotifierName(res_)
       << " <= ";
    if (notifiers.size() > 0) {
      os << Util::Join(notifiers, " | ");
    } else {
      os << "0";
    }
    os << ";\n";
    is << "      " << RegNotifierName(res_) << " <= 0;\n";
  }
  if (use_mailbox_) {
    BuildMailbox();
  }
  if (need_write_arbitration_) {
    // Priorities are
    // (1) Writers in this table
    // (2) Writers in other table
    // (3) Default output value
    ostream &os = tab_.StateOutputSectionStream();
    os << "      " << RegName(res_) << " <= ";
    string value;
    if (has_default_output_value_) {
      value = Util::Itoa(default_output_value_);
    } else {
      value = RegName(res_);
    }
    for (auto *writer : writers_) {
      string en = WriterEnName(*writer);
      bool n, m;
      SharedRegAccessor::GetAccessorFeatures(writer, &n, &m);
      if (m) {
	// Writes the value only when put to the mailbox is granted.
	en = "(" + en + " || " + RegMailboxPutAckName(*writer) + ")";
      }
      value = en + " ? " + WriterName(*writer) + " : (" + value + ")";
    }
    os << SelectValueByState(value);
    os << ";\n";
  }
  BuildAccessorWire();
}

void SharedReg::BuildMailbox() {
  ostream &rs = tab_.ResourceSectionStream();
  rs << "  reg " << RegMailboxName(res_) << ";\n";
  vector<string> put_reqs;
  if (writers_.size() > 0) {
    for (auto *writer : writers_) {
      if (!SharedRegAccessor::UseMailbox(writer)) {
	continue;
      }
      rs << "  wire " << RegMailboxPutAckName(*writer) << ";\n";
      rs << "  assign " << RegMailboxPutAckName(*writer) << " = "
	 << "(!" << RegMailboxName(res_) << ") && ";
      if (put_reqs.size() > 0) {
	rs << "(!(" << Util::Join(put_reqs, " | ") << ")) && ";
      }
      rs << RegMailboxPutReqName(*writer) << ";\n";
      put_reqs.push_back(RegMailboxPutReqName(*writer));
    }
  } else {
    put_reqs.push_back("0");
  }
  vector<string> get_reqs;
  if (readers_.size() > 0) {
    for (auto *reader : readers_) {
      if (!SharedRegAccessor::UseMailbox(reader)) {
	continue;
      }
      rs << "  wire " << RegMailboxGetAckName(*reader) << ";\n";
      rs << "  assign " << RegMailboxGetAckName(*reader) << " = "
	 << "(" << RegMailboxName(res_) << ") && ";
      if (get_reqs.size() > 0) {
	rs << "(!(" << Util::Join(get_reqs, " | ") << ")) && ";
      }
      rs << RegMailboxGetReqName(*reader) << ";\n";
      get_reqs.push_back(RegMailboxGetReqName(*reader));
    }
  } else {
    get_reqs.push_back("0");
  }
  ostream &os = tab_.StateOutputSectionStream();
  os << "      if (" << RegMailboxName(res_) << ") begin\n"
     << "        " << RegMailboxName(res_) << " <= "
     << "!(" << Util::Join(get_reqs, " | ") << ");\n"
     << "      end else begin\n"
     << "        " << RegMailboxName(res_) << " <= "
     << Util::Join(put_reqs, " | ") << ";\n"
     << "      end\n";
}

void SharedReg::BuildInsn(IInsn *insn, State *st) {
  auto *klass = res_.GetClass();
  if (resource::IsSharedReg(*klass)) {
    if (!need_write_arbitration_ &&
	insn->inputs_.size() == 1) {
      ostream &os = st->StateBodySectionStream();
      os << "          " << RegName(res_) << " <= "
	 << InsnWriter::RegisterValue(*insn->inputs_[0], tab_.GetNames())
	 << ";\n";
    }
    if (insn->outputs_.size() == 1) {
      // Read from self.
      ostream &ws = tmpl_->GetStream(kInsnWireValueSection);
      ws << "  assign "
	 << InsnWriter::InsnOutputWireName(*insn, 0)
	 << " = "
	 << RegName(res_) << ";\n";
    }
  }
}

string SharedReg::WriterName(const IResource &writer) {
  return RegName(writer) + "_w";
}

string SharedReg::WriterEnName(const IResource &writer) {
  return WriterName(writer) + "_en";
}

string SharedReg::RegNotifierName(const IResource &reg) {
  return RegName(reg) + "_notify";
}

string SharedReg::WriterNotifierName(const IResource &writer) {
  return RegName(writer) + "_write_notify";
}

string SharedReg::RegMailboxName(const IResource &reg) {
  return RegName(reg) + "_mailbox";
}

string SharedReg::RegMailboxPutReqName(const IResource &writer) {
  return RegName(writer) + "_mailbox_put_req";
}

string SharedReg::RegMailboxPutAckName(const IResource &writer) {
  return RegName(writer) + "_mailbox_put_ack";
}

string SharedReg::RegMailboxGetReqName(const IResource &reader) {
  return RegName(reader) + "_mailbox_get_req";
}

string SharedReg::RegMailboxGetAckName(const IResource &reader) {
  return RegName(reader) + "_mailbox_get_ack";
}

string SharedReg::RegMailboxBufName(const IResource &reader) {
  return RegName(reader) + "_mailbox_buf";
}

string SharedReg::RegName(const IResource &reg) {
  auto *params = reg.GetParams();
  int unused_width;
  string port_name;
  if (params != nullptr) {
    params->GetExtOutputPort(&port_name, &unused_width);
  }
  ITable *tab = reg.GetTable();
  IModule *mod = tab->GetModule();
  string n = "shared_reg_" +
    Util::Itoa(mod->GetId()) + "_" +
    Util::Itoa(tab->GetId()) + "_" + Util::Itoa(reg.GetId());
  if (!port_name.empty()) {
    n += "_" + port_name;
  }
  return n;
}

void SharedReg::AddChildWire(const IResource *accessor, bool is_write,
			     bool use_notify, bool use_mailbox,
			     ostream &os) {
  const IResource *reg = accessor->GetParentResource();
  vector<string> names;
  string name;
  if (is_write) {
    names.push_back(WriterName(*accessor));
  }
  if (is_write) {
    names.push_back(WriterEnName(*accessor));
  }
  if (use_notify) {
    if (is_write) {
      names.push_back(WriterNotifierName(*accessor));
    }
  }
  if (use_mailbox) {
    if (is_write) {
      names.push_back(RegMailboxPutReqName(*accessor));
    }
    if (is_write) {
      names.push_back(RegMailboxPutAckName(*accessor));
    }
  }
  for (const string &s : names) {
    os << ", ." << s << "(" << s << ")";
  }
}

void SharedReg::BuildAccessorWire() {
  // TODO: Move all writer wiring logic to here too.
  InterModuleWire wire(*this);
  int dw = res_.GetParams()->GetWidth();
  auto &readers = tab_.GetModule()->GetConnection().GetSharedRegReaders(&res_);
  for (auto *reader : readers) {
    wire.AddWire(*reader, RegName(res_), dw, true, true);
    if (SharedRegAccessor::UseNotify(reader)) {
      wire.AddWire(*reader, RegNotifierName(res_), 0, true, true);
    }
    if (SharedRegAccessor::UseMailbox(reader)) {
      wire.AddWire(*reader, RegMailboxPutReqName(*reader), 0, false, true);
      wire.AddWire(*reader, RegMailboxPutAckName(*reader), 0, true, true);
    }
  }
}

void SharedReg::AddAccessorSignals(const IModule *imod, const Table *tab,
				   const IResource *accessor, bool wire_only) {
  // NOTE: SharedReg::BuildResource() may have some dups of this code.
  bool is_writer = resource::IsSharedRegWriter(*(accessor->GetClass()));
  const IResource *reg = accessor->GetParentResource();
  bool same_module = false;
  if (reg->GetTable()->GetModule() == accessor->GetTable()->GetModule()) {
    same_module = true;
  }
  Module *mod = tab->GetModule()->GetByIModule(imod);
  auto *tmpl = mod->GetModuleTemplate();
  ostream &rs = tab->ResourceSectionStream();
  int width = accessor->GetParentResource()->GetParams()->GetWidth();
  string drive_by_writer = "wire";
  string drive_by_reader = "wire";
  if (!wire_only) {
    if (is_writer) {
      drive_by_writer = "reg";
    } else {
      drive_by_reader = "reg";
    }
  }
  if (is_writer || !same_module) {
    if (is_writer) {
      rs << "  wire "
	 << Table::WidthSpec(width);
      rs << WriterName(*accessor) << ";\n";
    }
  }
  if (is_writer) {
    rs << "  wire " << WriterEnName(*accessor) << ";\n";
  }
  bool notify = SharedRegAccessor::UseNotify(accessor);
  if (notify) {
    if (is_writer) {
      rs << "  wire "
	 << WriterNotifierName(*accessor) << ";\n";
    } else {
    }
  }
  bool mb = SharedRegAccessor::UseMailbox(accessor);
  if (mb) {
    if (is_writer) {
      if (!same_module) {
	rs << "  wire "
	   << RegMailboxPutReqName(*accessor) << ";\n"
	   << "  wire "
	   << RegMailboxPutAckName(*accessor) << ";\n";
      }
    }
  }
}

void SharedReg::GetOptions(bool *use_notify, bool *use_mailbox) {
  *use_notify = false;
  *use_mailbox = false;
  for (auto *reader : readers_) {
    if (resource::IsDataFlowIn(*(reader->GetClass()))) {
      *use_notify |= true;
    } else {
      bool n, m;
      SharedRegAccessor::GetAccessorFeatures(reader, &n, &m);
      *use_notify |= n;
      *use_mailbox |= m;
    }
  }
  for (auto *writer : writers_) {
    bool n, m;
    SharedRegAccessor::GetAccessorFeatures(writer, &n, &m);
    *use_notify |= n;
    *use_mailbox |= m;
  }
}

}  // namespace verilog
}  // namespace writer
}  // namespace iroha
<commit_msg>Fix to wire correct signals from mailbox getter.<commit_after>// A shared register can have shared register writers, readers and
// dataflow entries (equivalent to readers).
//
// shared-reg-writer generates connections from shared-reg-writer to shared-reg.
// shared-reg generates connections from shared-reg to shared-reg-reader.

#include "writer/verilog/shared_reg.h"

#include "design/design_util.h"
#include "iroha/i_design.h"
#include "iroha/logging.h"
#include "iroha/resource_class.h"
#include "iroha/resource_params.h"
#include "writer/connection.h"
#include "writer/module_template.h"
#include "writer/verilog/insn_writer.h"
#include "writer/verilog/inter_module_wire.h"
#include "writer/verilog/module.h"
#include "writer/verilog/ports.h"
#include "writer/verilog/state.h"
#include "writer/verilog/table.h"
#include "writer/verilog/shared_reg_accessor.h"

namespace iroha {
namespace writer {
namespace verilog {

SharedReg::SharedReg(const IResource &res, const Table &table)
  : Resource(res, table), has_default_output_value_(false),
    default_output_value_(0),
    need_write_arbitration_(false) {
  auto *klass = res_.GetClass();
  CHECK(resource::IsSharedReg(*klass));
  auto *params = res_.GetParams();
  string unused;
  params->GetExtOutputPort(&unused, &width_);
  has_default_output_value_ =
    params->GetDefaultValue(&default_output_value_);
  auto &readers =
    table.GetModule()->GetConnection().GetSharedRegReaders(&res_);
  for (auto *r : readers) {
    readers_.push_back(r);
  }
  auto &children =
    table.GetModule()->GetConnection().GetSharedRegChildren(&res_);
  for (auto *r : children) {
    readers_.push_back(r);
  }
  writers_ = table.GetModule()->GetConnection().GetSharedRegWriters(&res_);
  if (writers_.size() > 0 || has_default_output_value_) {
    need_write_arbitration_ = true;
  }
  GetOptions(&use_notify_, &use_mailbox_);
}

void SharedReg::BuildResource() {
  ostream &rs = tab_.ResourceSectionStream();
  ostream &is = tab_.InitialValueSectionStream();
  rs << "  // shared-reg";
  if (use_notify_) {
    rs << " use-notify";
  }
  if (use_mailbox_) {
    rs << " use-mailbox";
  }
  rs << "\n";
  if (readers_.size() == 0) {
    rs << "  reg ";
    if (width_ > 0) {
      rs << "[" << width_ - 1 << ":0]";
    }
    rs << " " << RegName(res_) << ";\n";
  }
  // Reset value
  is << "      " << RegName(res_) << " <= ";
  if (has_default_output_value_) {
    is << default_output_value_;
  } else {
    is << 0;
  }
  is << ";\n";
  if (use_notify_) {
    vector<string> notifiers;
    for (auto *writer : writers_) {
      if (SharedRegAccessor::UseNotify(writer)) {
	notifiers.push_back(WriterNotifierName(*writer));
      }
    }
    ostream &os = tab_.StateOutputSectionStream();
    os << "      " << RegNotifierName(res_)
       << " <= ";
    if (notifiers.size() > 0) {
      os << Util::Join(notifiers, " | ");
    } else {
      os << "0";
    }
    os << ";\n";
    is << "      " << RegNotifierName(res_) << " <= 0;\n";
  }
  if (use_mailbox_) {
    BuildMailbox();
  }
  if (need_write_arbitration_) {
    // Priorities are
    // (1) Writers in this table
    // (2) Writers in other table
    // (3) Default output value
    ostream &os = tab_.StateOutputSectionStream();
    os << "      " << RegName(res_) << " <= ";
    string value;
    if (has_default_output_value_) {
      value = Util::Itoa(default_output_value_);
    } else {
      value = RegName(res_);
    }
    for (auto *writer : writers_) {
      string en = WriterEnName(*writer);
      bool n, m;
      SharedRegAccessor::GetAccessorFeatures(writer, &n, &m);
      if (m) {
	// Writes the value only when put to the mailbox is granted.
	en = "(" + en + " || " + RegMailboxPutAckName(*writer) + ")";
      }
      value = en + " ? " + WriterName(*writer) + " : (" + value + ")";
    }
    os << SelectValueByState(value);
    os << ";\n";
  }
  BuildAccessorWire();
}

void SharedReg::BuildMailbox() {
  ostream &rs = tab_.ResourceSectionStream();
  rs << "  reg " << RegMailboxName(res_) << ";\n";
  vector<string> put_reqs;
  if (writers_.size() > 0) {
    for (auto *writer : writers_) {
      if (!SharedRegAccessor::UseMailbox(writer)) {
	continue;
      }
      rs << "  wire " << RegMailboxPutAckName(*writer) << ";\n";
      rs << "  assign " << RegMailboxPutAckName(*writer) << " = "
	 << "(!" << RegMailboxName(res_) << ") && ";
      if (put_reqs.size() > 0) {
	rs << "(!(" << Util::Join(put_reqs, " | ") << ")) && ";
      }
      rs << RegMailboxPutReqName(*writer) << ";\n";
      put_reqs.push_back(RegMailboxPutReqName(*writer));
    }
  } else {
    put_reqs.push_back("0");
  }
  vector<string> get_reqs;
  if (readers_.size() > 0) {
    for (auto *reader : readers_) {
      if (!SharedRegAccessor::UseMailbox(reader)) {
	continue;
      }
      rs << "  assign " << RegMailboxGetAckName(*reader) << " = "
	 << "(" << RegMailboxName(res_) << ") && ";
      if (get_reqs.size() > 0) {
	rs << "(!(" << Util::Join(get_reqs, " | ") << ")) && ";
      }
      rs << RegMailboxGetReqName(*reader) << ";\n";
      get_reqs.push_back(RegMailboxGetReqName(*reader));
    }
  } else {
    get_reqs.push_back("0");
  }
  ostream &os = tab_.StateOutputSectionStream();
  os << "      if (" << RegMailboxName(res_) << ") begin\n"
     << "        " << RegMailboxName(res_) << " <= "
     << "!(" << Util::Join(get_reqs, " | ") << ");\n"
     << "      end else begin\n"
     << "        " << RegMailboxName(res_) << " <= "
     << Util::Join(put_reqs, " | ") << ";\n"
     << "      end\n";
}

void SharedReg::BuildInsn(IInsn *insn, State *st) {
  auto *klass = res_.GetClass();
  if (resource::IsSharedReg(*klass)) {
    if (!need_write_arbitration_ &&
	insn->inputs_.size() == 1) {
      ostream &os = st->StateBodySectionStream();
      os << "          " << RegName(res_) << " <= "
	 << InsnWriter::RegisterValue(*insn->inputs_[0], tab_.GetNames())
	 << ";\n";
    }
    if (insn->outputs_.size() == 1) {
      // Read from self.
      ostream &ws = tmpl_->GetStream(kInsnWireValueSection);
      ws << "  assign "
	 << InsnWriter::InsnOutputWireName(*insn, 0)
	 << " = "
	 << RegName(res_) << ";\n";
    }
  }
}

string SharedReg::WriterName(const IResource &writer) {
  return RegName(writer) + "_w";
}

string SharedReg::WriterEnName(const IResource &writer) {
  return WriterName(writer) + "_en";
}

string SharedReg::RegNotifierName(const IResource &reg) {
  return RegName(reg) + "_notify";
}

string SharedReg::WriterNotifierName(const IResource &writer) {
  return RegName(writer) + "_write_notify";
}

string SharedReg::RegMailboxName(const IResource &reg) {
  return RegName(reg) + "_mailbox";
}

string SharedReg::RegMailboxPutReqName(const IResource &writer) {
  return RegName(writer) + "_mailbox_put_req";
}

string SharedReg::RegMailboxPutAckName(const IResource &writer) {
  return RegName(writer) + "_mailbox_put_ack";
}

string SharedReg::RegMailboxGetReqName(const IResource &reader) {
  return RegName(reader) + "_mailbox_get_req";
}

string SharedReg::RegMailboxGetAckName(const IResource &reader) {
  return RegName(reader) + "_mailbox_get_ack";
}

string SharedReg::RegMailboxBufName(const IResource &reader) {
  return RegName(reader) + "_mailbox_buf";
}

string SharedReg::RegName(const IResource &reg) {
  auto *params = reg.GetParams();
  int unused_width;
  string port_name;
  if (params != nullptr) {
    params->GetExtOutputPort(&port_name, &unused_width);
  }
  ITable *tab = reg.GetTable();
  IModule *mod = tab->GetModule();
  string n = "shared_reg_" +
    Util::Itoa(mod->GetId()) + "_" +
    Util::Itoa(tab->GetId()) + "_" + Util::Itoa(reg.GetId());
  if (!port_name.empty()) {
    n += "_" + port_name;
  }
  return n;
}

void SharedReg::AddChildWire(const IResource *accessor, bool is_write,
			     bool use_notify, bool use_mailbox,
			     ostream &os) {
  const IResource *reg = accessor->GetParentResource();
  vector<string> names;
  string name;
  if (is_write) {
    names.push_back(WriterName(*accessor));
  }
  if (is_write) {
    names.push_back(WriterEnName(*accessor));
  }
  if (use_notify) {
    if (is_write) {
      names.push_back(WriterNotifierName(*accessor));
    }
  }
  if (use_mailbox) {
    if (is_write) {
      names.push_back(RegMailboxPutReqName(*accessor));
    }
    if (is_write) {
      names.push_back(RegMailboxPutAckName(*accessor));
    }
  }
  for (const string &s : names) {
    os << ", ." << s << "(" << s << ")";
  }
}

void SharedReg::BuildAccessorWire() {
  // TODO: Move all writer wiring logic to here too.
  InterModuleWire wire(*this);
  int dw = res_.GetParams()->GetWidth();
  auto &readers = tab_.GetModule()->GetConnection().GetSharedRegReaders(&res_);
  for (auto *reader : readers) {
    wire.AddWire(*reader, RegName(res_), dw, true, true);
    if (SharedRegAccessor::UseNotify(reader)) {
      wire.AddWire(*reader, RegNotifierName(res_), 0, true, true);
    }
    if (SharedRegAccessor::UseMailbox(reader)) {
      wire.AddWire(*reader, RegMailboxGetReqName(*reader), 0, false, false);
      wire.AddWire(*reader, RegMailboxGetAckName(*reader), 0, true, false);
    }
  }
}

void SharedReg::AddAccessorSignals(const IModule *imod, const Table *tab,
				   const IResource *accessor, bool wire_only) {
  // NOTE: SharedReg::BuildResource() may have some dups of this code.
  bool is_writer = resource::IsSharedRegWriter(*(accessor->GetClass()));
  const IResource *reg = accessor->GetParentResource();
  bool same_module = false;
  if (reg->GetTable()->GetModule() == accessor->GetTable()->GetModule()) {
    same_module = true;
  }
  Module *mod = tab->GetModule()->GetByIModule(imod);
  auto *tmpl = mod->GetModuleTemplate();
  ostream &rs = tab->ResourceSectionStream();
  int width = accessor->GetParentResource()->GetParams()->GetWidth();
  string drive_by_writer = "wire";
  string drive_by_reader = "wire";
  if (!wire_only) {
    if (is_writer) {
      drive_by_writer = "reg";
    } else {
      drive_by_reader = "reg";
    }
  }
  if (is_writer || !same_module) {
    if (is_writer) {
      rs << "  wire "
	 << Table::WidthSpec(width);
      rs << WriterName(*accessor) << ";\n";
    }
  }
  if (is_writer) {
    rs << "  wire " << WriterEnName(*accessor) << ";\n";
  }
  bool notify = SharedRegAccessor::UseNotify(accessor);
  if (notify) {
    if (is_writer) {
      rs << "  wire "
	 << WriterNotifierName(*accessor) << ";\n";
    } else {
    }
  }
  bool mb = SharedRegAccessor::UseMailbox(accessor);
  if (mb) {
    if (is_writer) {
      if (!same_module) {
	rs << "  wire "
	   << RegMailboxPutReqName(*accessor) << ";\n"
	   << "  wire "
	   << RegMailboxPutAckName(*accessor) << ";\n";
      }
    }
  }
}

void SharedReg::GetOptions(bool *use_notify, bool *use_mailbox) {
  *use_notify = false;
  *use_mailbox = false;
  for (auto *reader : readers_) {
    if (resource::IsDataFlowIn(*(reader->GetClass()))) {
      *use_notify |= true;
    } else {
      bool n, m;
      SharedRegAccessor::GetAccessorFeatures(reader, &n, &m);
      *use_notify |= n;
      *use_mailbox |= m;
    }
  }
  for (auto *writer : writers_) {
    bool n, m;
    SharedRegAccessor::GetAccessorFeatures(writer, &n, &m);
    *use_notify |= n;
    *use_mailbox |= m;
  }
}

}  // namespace verilog
}  // namespace writer
}  // namespace iroha
<|endoftext|>


<commit_before>#include "Platform.hpp"
#include "genome.pb.h"
#include "CellComponent.hpp"
#include "ActivityStats.hpp"
#include "Neuron.hpp"
#include "Branch.hpp"
#include "Synapse.hpp"
#include "Base64.hpp"
#include "Brain.hpp"
#include "SimpleProteinEnvironment.hpp"
#include "genome.pb.h"
#include <time.h>

namespace Elysia {
void testTwoConnectedNeurons() {
    ProteinEnvironment *myProteinEnvironment= new SimpleProteinEnvironment();

	Brain *brain= new Brain(myProteinEnvironment);
	FILE *dendriteTree=NULL;
	dendriteTree = fopen("Dendritic_Tree.txt", "w");
	for(float i=0;i<2;i++){
        Genome::Gene gene;//FIXME set source and target regions to match the desired behavior
        Genome::TemporalBoundingBox *sourcebb=gene.add_bounds();
        Genome::TemporalBoundingBox *targetbb=gene.add_bounds();
        sourcebb->set_minx(i);
        sourcebb->set_miny(i);
        sourcebb->set_minz(i);

        sourcebb->set_maxx(i);
        sourcebb->set_maxy(i);
        sourcebb->set_maxz(i);

        targetbb->set_minx(1-i);
        targetbb->set_miny(1-i);
        targetbb->set_minz(1-i);

        targetbb->set_maxx(1-i);
        targetbb->set_maxy(1-i);
        targetbb->set_maxz(1-i);

		Vector3f v;
		v.x = i;
		v.y = i;
		v.z = i;
		Neuron *n;
		srand(time(NULL));
		brain->mAllNeurons.insert(n = new Neuron(brain, 2, 3, 4, v,gene));
        n->developSynapse(n->getActivityStats());

        size_t parent;
        parent = 0;
        n->visualizeTree(dendriteTree, parent);
        n->activateComponent(*brain,100);
        n->tick();
		//const Vector3f &location):  mNeuronLocation(location){));
	}
	fclose(dendriteTree);
}

void testProteinEnvironment() {
   using namespace Elysia::Genome;
   Elysia::Genome::Genome twoOverlappingGenes;
   Elysia::Genome::Chromosome *father=twoOverlappingGenes.mutable_fathers();
   Elysia::Genome::Gene firstGene;
   Elysia::Genome::Protein firstProtein;
   firstProtein.set_protein_code(GROW_NEURON);//so we can easily identify where
   firstProtein.set_density(0.125);
   Elysia::Genome::Protein firstAuxProtein;
   firstProtein.set_protein_code(GROW_LEAF);//so we see that they are additive
   firstProtein.set_density(0.25);
   *firstGene.add_external_proteins()=firstProtein;
   *firstGene.add_external_proteins()=firstAuxProtein;
   Elysia::Genome::TemporalBoundingBox firstRegion;
   firstRegion.set_minx(0);
   firstRegion.set_miny(0);
   firstRegion.set_minz(0);
   firstRegion.set_maxx(2);
   firstRegion.set_maxy(2);
   firstRegion.set_maxz(2);

   *firstGene.add_bounds()=firstRegion;
   Elysia::Genome::Gene secondGene;
   Elysia::Genome::Protein secondProtein;
   secondProtein.set_protein_code(GROW_LEAF);
   secondProtein.set_density(0.5);
   *secondGene.add_external_proteins()=secondProtein;
   Elysia::Genome::TemporalBoundingBox secondRegion;
   secondRegion.set_minx(-1);
   secondRegion.set_miny(-1);
   secondRegion.set_minz(-1);
   secondRegion.set_maxx(1);
   secondRegion.set_maxy(1);
   secondRegion.set_maxz(1);
   *secondGene.add_bounds()=secondRegion;
   *father->add_genes()=firstGene;
   *father->add_genes()=secondGene;

   ProteinEnvironment * pe=new SimpleProteinEnvironment;
   pe->initialize(twoOverlappingGenes);
   std::vector<std::pair<Elysia::Genome::Effect, float> > combinedResult=pe->getCompleteProteinDensity(Vector3f(.5,.5,.5));
   //check that firstResult matches expectations
   std::vector<std::pair<Elysia::Genome::Effect, float> > firstResult=pe->getCompleteProteinDensity(Vector3f(1.5,1.5,1.5));
   //check that secondResult matches expectations
   std::vector<std::pair<Elysia::Genome::Effect, float> > secondResult=pe->getCompleteProteinDensity(Vector3f(-.5,-.5,-.5));
   assert(combinedResult.size()==2);
   assert(firstResult.size()==2);
   assert(secondResult.size()==1);
   assert((combinedResult[0].first==GROW_LEAF&&combinedResult[0].second==.75)||
          (combinedResult[1].first==GROW_LEAF&&combinedResult[1].second==.75));
   assert((combinedResult[0].first==GROW_NEURON&&combinedResult[0].second==.125)||
          (combinedResult[1].first==GROW_NEURON&&combinedResult[1].second==.125));
   assert((firstResult[0].first==GROW_LEAF&&firstResult[0].second==.25)||
          (firstResult[1].first==GROW_LEAF&&firstResult[1].second==.25));
   assert((firstResult[0].first==GROW_NEURON&&firstResult[0].second==.125)||
          (firstResult[1].first==GROW_NEURON&&firstResult[1].second==.125));
   assert(secondResult[0].first==GROW_LEAF&&secondResult[0].second==.5);
   delete pe;
}
}

int runtest(){
    Elysia::testTwoConnectedNeurons();
    Elysia::testProteinEnvironment();
	getchar();
	return 1;

}
<commit_msg>improved check for valid result from ProteinEnvironment<commit_after>#include "Platform.hpp"
#include "genome.pb.h"
#include "CellComponent.hpp"
#include "ActivityStats.hpp"
#include "Neuron.hpp"
#include "Branch.hpp"
#include "Synapse.hpp"
#include "Base64.hpp"
#include "Brain.hpp"
#include "SimpleProteinEnvironment.hpp"
#include "genome.pb.h"
#include <time.h>

namespace Elysia {
void testTwoConnectedNeurons() {
    ProteinEnvironment *myProteinEnvironment= new SimpleProteinEnvironment();

	Brain *brain= new Brain(myProteinEnvironment);
	FILE *dendriteTree=NULL;
	dendriteTree = fopen("Dendritic_Tree.txt", "w");
	for(float i=0;i<2;i++){
        Genome::Gene gene;//FIXME set source and target regions to match the desired behavior
        Genome::TemporalBoundingBox *sourcebb=gene.add_bounds();
        Genome::TemporalBoundingBox *targetbb=gene.add_bounds();
        sourcebb->set_minx(i);
        sourcebb->set_miny(i);
        sourcebb->set_minz(i);

        sourcebb->set_maxx(i);
        sourcebb->set_maxy(i);
        sourcebb->set_maxz(i);

        targetbb->set_minx(1-i);
        targetbb->set_miny(1-i);
        targetbb->set_minz(1-i);

        targetbb->set_maxx(1-i);
        targetbb->set_maxy(1-i);
        targetbb->set_maxz(1-i);

		Vector3f v;
		v.x = i;
		v.y = i;
		v.z = i;
		Neuron *n;
		srand(time(NULL));
		brain->mAllNeurons.insert(n = new Neuron(brain, 2, 3, 4, v,gene));
        n->developSynapse(n->getActivityStats());

        size_t parent;
        parent = 0;
        n->visualizeTree(dendriteTree, parent);
        n->activateComponent(*brain,100);
        n->tick();
		//const Vector3f &location):  mNeuronLocation(location){));
	}
	fclose(dendriteTree);
}

void testResultHelper(const std::vector<std::pair<Elysia::Genome::Effect, float> >&combinedResult, float&grow_leaf_count,float&grow_neuron_count,float&other_count){
   using namespace Elysia::Genome;
    grow_leaf_count=0;
    grow_leaf_count=0;
    other_count=0;
    for (size_t i=0;i<combinedResult.size();++i) {
       switch(combinedResult[i].first) {
         case GROW_NEURON:
           grow_neuron_count+=combinedResult[i].second;
           break;
         case GROW_LEAF:
           grow_leaf_count+=combinedResult[i].second;
           break;
         default:
           other_count+=combinedResult[i].second;
           break;
       }
   }

}

void testProteinEnvironment() {
   using namespace Elysia::Genome;
   Elysia::Genome::Genome twoOverlappingGenes;
   Elysia::Genome::Chromosome *father=twoOverlappingGenes.mutable_fathers();
   Elysia::Genome::Gene firstGene;
   Elysia::Genome::Protein firstProtein;
   firstProtein.set_protein_code(GROW_NEURON);//so we can easily identify where
   firstProtein.set_density(0.125);
   Elysia::Genome::Protein firstAuxProtein;
   firstProtein.set_protein_code(GROW_LEAF);//so we see that they are additive
   firstProtein.set_density(0.25);
   *firstGene.add_external_proteins()=firstProtein;
   *firstGene.add_external_proteins()=firstAuxProtein;
   Elysia::Genome::TemporalBoundingBox firstRegion;
   firstRegion.set_minx(0);
   firstRegion.set_miny(0);
   firstRegion.set_minz(0);
   firstRegion.set_maxx(2);
   firstRegion.set_maxy(2);
   firstRegion.set_maxz(2);

   *firstGene.add_bounds()=firstRegion;
   Elysia::Genome::Gene secondGene;
   Elysia::Genome::Protein secondProtein;
   secondProtein.set_protein_code(GROW_LEAF);
   secondProtein.set_density(0.5);
   *secondGene.add_external_proteins()=secondProtein;
   Elysia::Genome::TemporalBoundingBox secondRegion;
   secondRegion.set_minx(-1);
   secondRegion.set_miny(-1);
   secondRegion.set_minz(-1);
   secondRegion.set_maxx(1);
   secondRegion.set_maxy(1);
   secondRegion.set_maxz(1);
   *secondGene.add_bounds()=secondRegion;
   *father->add_genes()=firstGene;
   *father->add_genes()=secondGene;

   ProteinEnvironment * pe=new SimpleProteinEnvironment;
   pe->initialize(twoOverlappingGenes);
   std::vector<std::pair<Elysia::Genome::Effect, float> > combinedResult=pe->getCompleteProteinDensity(Vector3f(.5,.5,.5));
   //check that firstResult matches expectations
   std::vector<std::pair<Elysia::Genome::Effect, float> > firstResult=pe->getCompleteProteinDensity(Vector3f(1.5,1.5,1.5));
   //check that secondResult matches expectations
   std::vector<std::pair<Elysia::Genome::Effect, float> > secondResult=pe->getCompleteProteinDensity(Vector3f(-.5,-.5,-.5));
   float grow_leaf_count=0;
   float grow_neuron_count=0;
   float other_count=0;

   testResultHelper(combinedResult,grow_leaf_count,grow_neuron_count,other_count);
   assert(grow_leaf_count==.75);
   assert(grow_neuron_count==.125);
   assert(other_count==0);

   testResultHelper(firstResult,grow_leaf_count,grow_neuron_count,other_count);
   assert(grow_leaf_count==.25);
   assert(grow_neuron_count==.125);
   assert(other_count==0);

   testResultHelper(secondResult,grow_leaf_count,grow_neuron_count,other_count);
   assert(grow_leaf_count==.5);
   assert(grow_neuron_count==0);
   assert(other_count==0);

   delete pe;
}
}

int runtest(){
    Elysia::testTwoConnectedNeurons();
    //Elysia::testProteinEnvironment();
	//getchar();
	return 1;

}
<|endoftext|>