<commit_before>/******************************************************************************
* Copyright (c) 2012, Howard Butler, hobu.inc@gmail.com
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include <pdal/filters/Index.hpp>
#include <pdal/PointBuffer.hpp>
#include <pdal/Utils.hpp>

#include <boost/concept_check.hpp> // ignore_unused_variable_warning

#include <algorithm>
#include <cmath>

namespace pdal
{
namespace filters
{

Index::Index(Stage& prevStage, const Options& options)
    : pdal::Filter(prevStage, options)
{
    return;
}

void Index::initialize()
{
    Filter::initialize();

    m_dimensions = getOptions().getValueOrDefault<boost::uint32_t>("dimensions", 3);

    return;
}

const Options Index::getDefaultOptions() const
{
    Options options;

    Option x("x_dim", std::string("X"), "Dimension name to use for 'X' data");
    Option y("y_dim", std::string("Y"), "Dimension name to use for 'Y' data");
    Option z("z_dim", std::string("Z"), "Dimension name to use for 'Z' data");

    Option filename("filename", "", "Filename to store the index in");

    options.add(x);
    options.add(y);
    options.add(z);
    options.add(filename);

    return options;
}

void Index::processBuffer(PointBuffer& /* data */) const
{
    return;
}

pdal::StageSequentialIterator* Index::createSequentialIterator(PointBuffer& buffer) const
{
    return new pdal::filters::iterators::sequential::Index(*this, buffer);
}

namespace iterators
{
namespace sequential
{

Index::Index(const pdal::filters::Index& filter, PointBuffer& buffer)
    : pdal::FilterSequentialIterator(filter, buffer)
    , m_stage(filter)
#ifdef PDAL_HAVE_FLANN
    , m_index(0)
    , m_dataset(0)
#endif
    , m_xDim(0)
    , m_yDim(0)
    , m_zDim(0)
{

    return;
}

void Index::readBeginImpl()
{

}

void Index::readBufferBeginImpl(PointBuffer& buffer)
{
    // Cache dimension positions

    if (!m_xDim && !m_yDim && !m_zDim)
    {
        pdal::Schema const& schema = buffer.getSchema();

        std::string x_name = m_stage.getOptions().getValueOrDefault<std::string>("x_dim", "X");
        std::string y_name = m_stage.getOptions().getValueOrDefault<std::string>("x_dim", "Y");
        std::string z_name = m_stage.getOptions().getValueOrDefault<std::string>("x_dim", "Z");

        m_stage.log()->get(logDEBUG2) << "Indexing PointBuffer with X: '" << x_name
                                      << "' Y: '" << y_name
                                      << "' Z: '" << z_name << " with " <<  m_stage.getDimensions() << " dimensions" << std::endl;
        m_xDim = &schema.getDimension(x_name);
        m_yDim = &schema.getDimension(y_name);
        m_zDim = &schema.getDimension(z_name);

        if (!m_stage.getNumPoints())
            throw pdal_error("Unable to create index from pipeline that has an indeterminate number of points!");
    }

}

std::vector<boost::uint32_t> Index::query(double const& x, double const& y, double const& z, double distance, boost::uint32_t k)
{
    std::vector<boost::uint32_t> output;

#ifdef PDAL_HAVE_FLANN

    std::vector<float> distances;
    distances.resize(k);

    std::vector<int> indices;
    indices.resize(k);

    std::vector<float> query(m_stage.getDimensions());
    query[0] = x;
    query[1] = y;
    if (m_stage.getDimensions() > 2)
        query[2] = z;

    bool logOutput = m_stage.log()->getLevel() > logDEBUG4;
    m_stage.log()->floatPrecision(8);

    if (logOutput)
        m_stage.log()->get(logDEBUG2) << "Searching for x: " << x << " y: " << y << " z: " << z << " with distance threshold " << distance << std::endl;

    flann::Matrix<int> k_indices_mat (&indices[0], 1, k);
    flann::Matrix<float> k_distances_mat (&distances[0], 1, k);

    m_index->knnSearch (flann::Matrix<float> (&query[0], 1, m_stage.getDimensions()),
                             k_indices_mat, k_distances_mat,
                             k, flann::SearchParams(128));

    for(unsigned i=0; i < k; ++i)
    {
        // if distance is 0, just return the nearest one, otherwise filter by distance
        if (Utils::compare_distance<float>((float)distance, 0))
        {
            if (logOutput)
                m_stage.log()->get(logDEBUG4) << "Query found: " << "index: " << indices[i] << " distance: " << distances[i] <<std::endl;

            output.push_back(indices[i]);

        } else
        {
            if (::sqrt(distances[i]) < distance)
            {
                if (logOutput)
                    m_stage.log()->get(logDEBUG4) << "Query found: " << "index: " << indices[i] << " distance: " << distances[i] <<std::endl;

                output.push_back(indices[i]);

            }

        }
    }

#endif

    return output;
}

boost::uint32_t Index::readBufferImpl(PointBuffer& data)
{
    const boost::uint32_t numRead = getPrevIterator().read(data);

    bool logOutput = m_stage.log()->getLevel() > logDEBUG4;
    m_stage.log()->floatPrecision(8);

    if (logOutput)
    {
        m_stage.log()->get(logDEBUG2) << "inserting data into index data array of capacity: " << data.getCapacity() << std::endl;
    }

    for (boost::uint32_t pointIndex=0; pointIndex<numRead; pointIndex++)
    {
        float x = static_cast<float>(getScaledValue(data, *m_xDim, pointIndex));
        float y = static_cast<float>(getScaledValue(data, *m_yDim, pointIndex));
        float z = static_cast<float>(getScaledValue(data, *m_zDim, pointIndex));
#ifdef PDAL_HAVE_FLANN
        m_data.push_back(x);
        m_data.push_back(y);
        if (m_stage.getDimensions() > 2)
            m_data.push_back(z);

        if (logOutput)
        {
            m_stage.log()->get(logDEBUG4) << "index: " << pointIndex << " x: " << x << " y: " << y <<  " z: " << z << std::endl;
        }
#endif
    }

    return numRead;
}

double Index::getScaledValue(PointBuffer& data,
        Dimension const& d,
        std::size_t pointIndex) const
{
    double output(0.0);

    float flt(0.0);
    boost::int8_t i8(0);
    boost::uint8_t u8(0);
    boost::int16_t i16(0);
    boost::uint16_t u16(0);
    boost::int32_t i32(0);
    boost::uint32_t u32(0);
    boost::int64_t i64(0);
    boost::uint64_t u64(0);

    boost::uint32_t size = d.getByteSize();
    switch (d.getInterpretation())
    {
        case dimension::Float:
            if (size == 4)
            {
                flt = data.getField<float>(d, pointIndex);
                output = static_cast<double>(flt);
            }
            if (size == 8)
            {
                output = data.getField<double>(d, pointIndex);
            }
            break;

        case dimension::SignedInteger:
        case dimension::SignedByte:
            if (size == 1)
            {
                i8 = data.getField<boost::int8_t>(d, pointIndex);
                output = d.applyScaling<boost::int8_t>(i8);
            }
            if (size == 2)
            {
                i16 = data.getField<boost::int16_t>(d, pointIndex);
                output = d.applyScaling<boost::int16_t>(i16);
            }
            if (size == 4)
            {
                i32 = data.getField<boost::int32_t>(d, pointIndex);
                output = d.applyScaling<boost::int32_t>(i32);
            }
            if (size == 8)
            {
                i64 = data.getField<boost::int64_t>(d, pointIndex);
                output = d.applyScaling<boost::int64_t>(i64);
            }
            break;

        case dimension::UnsignedInteger:
        case dimension::UnsignedByte:
            if (size == 1)
            {
                u8 = data.getField<boost::uint8_t>(d, pointIndex);
                output = d.applyScaling<boost::uint8_t>(u8);
            }
            if (size == 2)
            {
                u16 = data.getField<boost::uint16_t>(d, pointIndex);
                output = d.applyScaling<boost::uint16_t>(u16);
            }
            if (size == 4)
            {
                u32 = data.getField<boost::uint32_t>(d, pointIndex);
                output = d.applyScaling<boost::uint32_t>(u32);
            }
            if (size == 8)
            {
                u64 = data.getField<boost::uint64_t>(d, pointIndex);
                output = d.applyScaling<boost::uint64_t>(u64);
            }
            break;

        case dimension::Pointer:    // stored as 64 bits, even on a 32-bit box
        case dimension::Undefined:
            throw pdal_error("Dimension data type unable to be reprojected");
    }

    return output;
}
void Index::readEndImpl()
{

#ifdef PDAL_HAVE_FLANN

    // Build the index
    m_dataset = new flann::Matrix<float>(&m_data[0], m_stage.getNumPoints(), m_stage.getDimensions());
    m_index = new flann::Index<flann::L2<float> >(*m_dataset, flann::KDTreeIndexParams(4));
    m_index->buildIndex();
    m_stage.log()->get(logDEBUG2) << "Built index" <<std::endl;

#endif
}

boost::uint64_t Index::skipImpl(boost::uint64_t count)
{
    getPrevIterator().skip(count);
    return count;
}

bool Index::atEndImpl() const
{
    return getPrevIterator().atEnd();
}

}
} // iterators::sequential

}
} // namespaces
<commit_msg>moved FLANN guards, for vs2010 lint<commit_after>/******************************************************************************
* Copyright (c) 2012, Howard Butler, hobu.inc@gmail.com
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include <pdal/filters/Index.hpp>
#include <pdal/PointBuffer.hpp>
#include <pdal/Utils.hpp>

#include <boost/concept_check.hpp> // ignore_unused_variable_warning

#include <algorithm>
#include <cmath>

namespace pdal
{
namespace filters
{

Index::Index(Stage& prevStage, const Options& options)
    : pdal::Filter(prevStage, options)
{
    return;
}

void Index::initialize()
{
    Filter::initialize();

    m_dimensions = getOptions().getValueOrDefault<boost::uint32_t>("dimensions", 3);

    return;
}

const Options Index::getDefaultOptions() const
{
    Options options;

    Option x("x_dim", std::string("X"), "Dimension name to use for 'X' data");
    Option y("y_dim", std::string("Y"), "Dimension name to use for 'Y' data");
    Option z("z_dim", std::string("Z"), "Dimension name to use for 'Z' data");

    Option filename("filename", "", "Filename to store the index in");

    options.add(x);
    options.add(y);
    options.add(z);
    options.add(filename);

    return options;
}

void Index::processBuffer(PointBuffer& /* data */) const
{
    return;
}

pdal::StageSequentialIterator* Index::createSequentialIterator(PointBuffer& buffer) const
{
    return new pdal::filters::iterators::sequential::Index(*this, buffer);
}

namespace iterators
{
namespace sequential
{

Index::Index(const pdal::filters::Index& filter, PointBuffer& buffer)
    : pdal::FilterSequentialIterator(filter, buffer)
    , m_stage(filter)
#ifdef PDAL_HAVE_FLANN
    , m_index(0)
    , m_dataset(0)
#endif
    , m_xDim(0)
    , m_yDim(0)
    , m_zDim(0)
{

    return;
}

void Index::readBeginImpl()
{

}

void Index::readBufferBeginImpl(PointBuffer& buffer)
{
    // Cache dimension positions

    if (!m_xDim && !m_yDim && !m_zDim)
    {
        pdal::Schema const& schema = buffer.getSchema();

        std::string x_name = m_stage.getOptions().getValueOrDefault<std::string>("x_dim", "X");
        std::string y_name = m_stage.getOptions().getValueOrDefault<std::string>("x_dim", "Y");
        std::string z_name = m_stage.getOptions().getValueOrDefault<std::string>("x_dim", "Z");

        m_stage.log()->get(logDEBUG2) << "Indexing PointBuffer with X: '" << x_name
                                      << "' Y: '" << y_name
                                      << "' Z: '" << z_name << " with " <<  m_stage.getDimensions() << " dimensions" << std::endl;
        m_xDim = &schema.getDimension(x_name);
        m_yDim = &schema.getDimension(y_name);
        m_zDim = &schema.getDimension(z_name);

        if (!m_stage.getNumPoints())
            throw pdal_error("Unable to create index from pipeline that has an indeterminate number of points!");
    }

}

std::vector<boost::uint32_t> Index::query(double const& x, double const& y, double const& z, double distance, boost::uint32_t k)
{
    std::vector<boost::uint32_t> output;

#ifdef PDAL_HAVE_FLANN

    std::vector<float> distances;
    distances.resize(k);

    std::vector<int> indices;
    indices.resize(k);

    std::vector<float> query(m_stage.getDimensions());
    query[0] = x;
    query[1] = y;
    if (m_stage.getDimensions() > 2)
        query[2] = z;

    bool logOutput = m_stage.log()->getLevel() > logDEBUG4;
    m_stage.log()->floatPrecision(8);

    if (logOutput)
        m_stage.log()->get(logDEBUG2) << "Searching for x: " << x << " y: " << y << " z: " << z << " with distance threshold " << distance << std::endl;

    flann::Matrix<int> k_indices_mat (&indices[0], 1, k);
    flann::Matrix<float> k_distances_mat (&distances[0], 1, k);

    m_index->knnSearch (flann::Matrix<float> (&query[0], 1, m_stage.getDimensions()),
                             k_indices_mat, k_distances_mat,
                             k, flann::SearchParams(128));

    for(unsigned i=0; i < k; ++i)
    {
        // if distance is 0, just return the nearest one, otherwise filter by distance
        if (Utils::compare_distance<float>((float)distance, 0))
        {
            if (logOutput)
                m_stage.log()->get(logDEBUG4) << "Query found: " << "index: " << indices[i] << " distance: " << distances[i] <<std::endl;

            output.push_back(indices[i]);

        } else
        {
            if (::sqrt(distances[i]) < distance)
            {
                if (logOutput)
                    m_stage.log()->get(logDEBUG4) << "Query found: " << "index: " << indices[i] << " distance: " << distances[i] <<std::endl;

                output.push_back(indices[i]);

            }

        }
    }
#else
    boost::ignore_unused_variable_warning(x);
    boost::ignore_unused_variable_warning(y);
    boost::ignore_unused_variable_warning(z);
    boost::ignore_unused_variable_warning(distance);
    boost::ignore_unused_variable_warning(k);
#endif

    return output;
}

boost::uint32_t Index::readBufferImpl(PointBuffer& data)
{
    const boost::uint32_t numRead = getPrevIterator().read(data);

    bool logOutput = m_stage.log()->getLevel() > logDEBUG4;
    m_stage.log()->floatPrecision(8);

    if (logOutput)
    {
        m_stage.log()->get(logDEBUG2) << "inserting data into index data array of capacity: " << data.getCapacity() << std::endl;
    }

#ifdef PDAL_HAVE_FLANN
    for (boost::uint32_t pointIndex=0; pointIndex<numRead; pointIndex++)
    {
        float x = static_cast<float>(getScaledValue(data, *m_xDim, pointIndex));
        float y = static_cast<float>(getScaledValue(data, *m_yDim, pointIndex));
        float z = static_cast<float>(getScaledValue(data, *m_zDim, pointIndex));

        m_data.push_back(x);
        m_data.push_back(y);
        if (m_stage.getDimensions() > 2)
            m_data.push_back(z);

        if (logOutput)
        {
            m_stage.log()->get(logDEBUG4) << "index: " << pointIndex << " x: " << x << " y: " << y <<  " z: " << z << std::endl;
        }
    }
#endif

    return numRead;
}

double Index::getScaledValue(PointBuffer& data,
        Dimension const& d,
        std::size_t pointIndex) const
{
    double output(0.0);

    float flt(0.0);
    boost::int8_t i8(0);
    boost::uint8_t u8(0);
    boost::int16_t i16(0);
    boost::uint16_t u16(0);
    boost::int32_t i32(0);
    boost::uint32_t u32(0);
    boost::int64_t i64(0);
    boost::uint64_t u64(0);

    boost::uint32_t size = d.getByteSize();
    switch (d.getInterpretation())
    {
        case dimension::Float:
            if (size == 4)
            {
                flt = data.getField<float>(d, pointIndex);
                output = static_cast<double>(flt);
            }
            if (size == 8)
            {
                output = data.getField<double>(d, pointIndex);
            }
            break;

        case dimension::SignedInteger:
        case dimension::SignedByte:
            if (size == 1)
            {
                i8 = data.getField<boost::int8_t>(d, pointIndex);
                output = d.applyScaling<boost::int8_t>(i8);
            }
            if (size == 2)
            {
                i16 = data.getField<boost::int16_t>(d, pointIndex);
                output = d.applyScaling<boost::int16_t>(i16);
            }
            if (size == 4)
            {
                i32 = data.getField<boost::int32_t>(d, pointIndex);
                output = d.applyScaling<boost::int32_t>(i32);
            }
            if (size == 8)
            {
                i64 = data.getField<boost::int64_t>(d, pointIndex);
                output = d.applyScaling<boost::int64_t>(i64);
            }
            break;

        case dimension::UnsignedInteger:
        case dimension::UnsignedByte:
            if (size == 1)
            {
                u8 = data.getField<boost::uint8_t>(d, pointIndex);
                output = d.applyScaling<boost::uint8_t>(u8);
            }
            if (size == 2)
            {
                u16 = data.getField<boost::uint16_t>(d, pointIndex);
                output = d.applyScaling<boost::uint16_t>(u16);
            }
            if (size == 4)
            {
                u32 = data.getField<boost::uint32_t>(d, pointIndex);
                output = d.applyScaling<boost::uint32_t>(u32);
            }
            if (size == 8)
            {
                u64 = data.getField<boost::uint64_t>(d, pointIndex);
                output = d.applyScaling<boost::uint64_t>(u64);
            }
            break;

        case dimension::Pointer:    // stored as 64 bits, even on a 32-bit box
        case dimension::Undefined:
            throw pdal_error("Dimension data type unable to be reprojected");
    }

    return output;
}
void Index::readEndImpl()
{

#ifdef PDAL_HAVE_FLANN

    // Build the index
    m_dataset = new flann::Matrix<float>(&m_data[0], m_stage.getNumPoints(), m_stage.getDimensions());
    m_index = new flann::Index<flann::L2<float> >(*m_dataset, flann::KDTreeIndexParams(4));
    m_index->buildIndex();
    m_stage.log()->get(logDEBUG2) << "Built index" <<std::endl;

#endif
}

boost::uint64_t Index::skipImpl(boost::uint64_t count)
{
    getPrevIterator().skip(count);
    return count;
}

bool Index::atEndImpl() const
{
    return getPrevIterator().atEnd();
}

}
} // iterators::sequential

}
} // namespaces
<|endoftext|>


<commit_before>#include "forwardserver.h"
#include "utils.h"

namespace forwarder {

	ReturnCode ForwardServer::initCommon(rapidjson::Value& serverConfig) {
		desc = serverConfig["desc"].GetString();
		peerLimit = serverConfig["peers"].GetInt();
		port = serverConfig["port"].GetInt();
		admin = serverConfig.HasMember("admin") && serverConfig["admin"].GetBool();
		encrypt = serverConfig.HasMember("encrypt") && serverConfig["encrypt"].GetBool();
		compress = serverConfig.HasMember("compress") && serverConfig["compress"].GetBool();
		base64 = serverConfig.HasMember("base64") && serverConfig["base64"].GetBool();
		isClientMode = serverConfig.HasMember("isClient") && serverConfig["isClient"].GetBool();
		reconnect = serverConfig.HasMember("reconnect") && serverConfig["reconnect"].GetBool();
		if (serverConfig.HasMember("reconnectdelay")) {
			reconnectdelay = serverConfig["reconnectdelay"].GetUint();
		}
		if (serverConfig.HasMember("address")) {
			address = serverConfig["address"].GetString();
		}
		if (encrypt) {
			if (serverConfig.HasMember("encryptkey")) {
				initCipherKey(serverConfig["encryptkey"].GetString());
			}
			else {
				std::cout << "[forwarder] no encryptkey" << std::endl;
				return ReturnCode::Err;
			}
		}
		if (serverConfig.HasMember("destId"))
			destId = serverConfig["destId"].GetInt();
        if (serverConfig.HasMember("timeoutMin"))
            timeoutMin = serverConfig["timeoutMin"].GetInt();
        if (serverConfig.HasMember("timeoutMax"))
            timeoutMax = serverConfig["timeoutMax"].GetInt();

        setRule(Protocol::Forward, HandleRule::Forward);
        setRule(Protocol::BatchForward, HandleRule::BatchForward);
		return ReturnCode::Ok;
	}

	bool ForwardServer::hasConsistConfig(ForwardServer* server) {
		if (netType != server->netType) {
			return false;
		}
		if (base64 != server->base64) {
			return false;
		}
		if (encrypt != server->encrypt) {
			return false;
		}
		if (encrypt) {
			size_t len = sizeof(AES_KEY);
			for (uint32_t i = 0; i < len; i++) {
				if (((uint8_t*)(&encryptkey))[i] != ((uint8_t*)(&server->encryptkey))[i]) {
					return false;
				}
			}
		}
		return true;
	}

	ForwardClient*  ForwardServer::getClient(UniqID clientId) {
		if (clientId) {
			auto it_client = clients.find(clientId);
			if (it_client != clients.end())
				return it_client->second;
		}
		return nullptr;
	}

	void ForwardServer::initCipherKey(const char* key){
		AES_set_encrypt_key((const unsigned char*)key, 128, &encryptkey);
	}

	void ForwardServer::setRule(Protocol p, HandleRule rule) {
		ruleDict[p] = rule;
	}

	HandleRule ForwardServer::getRule(Protocol p) {
		auto it = ruleDict.find(p);
		if (it == ruleDict.end()) {
			return HandleRule::Unknown;
		}
		return it->second;
	}

	void ForwardServerENet::init(rapidjson::Value& serverConfig) {
		ENetAddress enetAddress;
		if (!isClientMode) {
			enet_address_set_host(&enetAddress, "0.0.0.0");
			enetAddress.port = port;
		}
		else {
			enet_address_set_host(&enetAddress, address.c_str());
			enetAddress.port = port;
		}
		size_t channelLimit = 1;
		//address.host = ENET_HOST_ANY;
		enet_uint32 incomingBandwidth = 0;  /* assume any amount of incoming bandwidth */
		enet_uint32 outgoingBandwidth = 0;	/* assume any amount of outgoing bandwidth */
		if (serverConfig.HasMember("bandwidth")) {
			incomingBandwidth = serverConfig["bandwidth"]["incoming"].GetUint();
			outgoingBandwidth = serverConfig["bandwidth"]["outgoing"].GetUint();
			std::cout << "[forwarder] incomingBandwidth:" << incomingBandwidth << ", outgoingBandwidth:" << outgoingBandwidth << std::endl;
		}

		host = enet_host_create(isClientMode? nullptr: &enetAddress,
			peerLimit,
			channelLimit,
			incomingBandwidth,
			outgoingBandwidth);
		if (!host) {
			std::cout << "[forwarder] An error occurred while trying to create an ENet server host." << std::endl;
			exit(1);
			return;
		}
		if (isClientMode) {
			enet_host_connect(host, &enetAddress, channelLimit, 0);
		}
	}

	void ForwardServerENet::doReconnect() {
		std::cout << "[forwarder] ENet doReconnect" << std::endl;
		ENetAddress enetAddress;
		enet_address_set_host(&enetAddress, address.c_str());
		enetAddress.port = port;
		size_t channelLimit = 1;
		enet_host_connect(host, &enetAddress, channelLimit, 0);
	};

	void ForwardServerENet::doDisconnect() {
		std::cout << "[forwarder] ENet doDisconnect" << std::endl;
		ForwardClient* client = getClient(clientID);
		if (!client) {
			return;
		}
		ForwardClientENet* clientENet = dynamic_cast<ForwardClientENet*>(client);
		auto state = clientENet->peer->state;
		if(state == ENET_PEER_STATE_CONNECTING || state == ENET_PEER_STATE_CONNECTED){
			enet_peer_disconnect(clientENet->peer, 0);
		}
	}

	bool ForwardServerENet::isConnected() {
		ForwardClient* client = getClient(clientID);
		if (!client) {
			return false;
		}
		auto state = dynamic_cast<ForwardClientENet*>(client)->peer->state;
		return state == ENET_PEER_STATE_CONNECTED;
	}

	void  ForwardServerENet::release() {
		enet_host_destroy(host);
		host = nullptr;
	}

	void ForwardServerWS::init(rapidjson::Value& serverConfig) {
		if (!isClientMode) {
			server.set_error_channels(websocketpp::log::elevel::all);
			server.set_access_channels(websocketpp::log::alevel::none);
			server.init_asio();
			server.listen(port);
			server.start_accept();
		}
		else {
			serverAsClient.set_error_channels(websocketpp::log::elevel::all);
			serverAsClient.set_access_channels(websocketpp::log::alevel::none);
			serverAsClient.init_asio();
			doReconnect();
		}
	}

	void  ForwardServerWS::release() {
		if (!isClientMode) {
			server.stop();
		}
		else {
			doDisconnect();
			serverAsClient.stop();
		}
		hdlToClientId.clear();
	}

	void ForwardServerWS::poll() {
		if (!isClientMode) {
			server.poll_one();
		}
		else {
			serverAsClient.poll_one();
		}
	}

	void ForwardServerWS::doReconnect() {
		std::cout << "[forwarder] WS doReconnect" << std::endl;
		if (isConnected()) {
			return;
		}
		std::string uri = getUri();
		websocketpp::lib::error_code ec;
		WebsocketClient::connection_ptr con = serverAsClient.get_connection(uri, ec);
		if (ec) {
			std::cout << "[forwarder] WS error, could not create connection because: " << ec.message() << std::endl;
			return;
		}
		serverAsClient.connect(con);
	}

	void ForwardServerWS::doDisconnect() {
		std::cout << "[forwarder] WS doDisconnect" << std::endl;
		auto client = getClient(clientID);
		if (!client) {
			return;
		}
		ForwardClientWS* clientWS = dynamic_cast<ForwardClientWS*>(client);
		auto hdl = clientWS->hdl;
		websocketpp::lib::error_code ec;
		websocketpp::close::status::value code = websocketpp::close::status::normal;
		std::string reason = "";
		serverAsClient.close(hdl, code, reason, ec);
		if (ec) {
			std::cout << "[forwarder] WS error, initiating close: " << ec.message() << std::endl;
		}
	}

	bool ForwardServerWS::isConnected() {
		auto client = getClient(clientID);
		if (!client) {
			return false;
		}
		auto hdl = dynamic_cast<ForwardClientWS*>(client)->hdl;
		return server.get_con_from_hdl(hdl)->get_state() == websocketpp::session::state::value::connecting;
	}
}
<commit_msg>no message<commit_after>#include "forwardserver.h"
#include "utils.h"

namespace forwarder {

	ReturnCode ForwardServer::initCommon(rapidjson::Value& serverConfig) {
		desc = serverConfig["desc"].GetString();
		peerLimit = serverConfig["peers"].GetInt();
		port = serverConfig["port"].GetInt();
		admin = serverConfig.HasMember("admin") && serverConfig["admin"].GetBool();
		encrypt = serverConfig.HasMember("encrypt") && serverConfig["encrypt"].GetBool();
		compress = serverConfig.HasMember("compress") && serverConfig["compress"].GetBool();
		base64 = serverConfig.HasMember("base64") && serverConfig["base64"].GetBool();
		isClientMode = serverConfig.HasMember("isClient") && serverConfig["isClient"].GetBool();
		reconnect = serverConfig.HasMember("reconnect") && serverConfig["reconnect"].GetBool();
		if (serverConfig.HasMember("reconnectdelay")) {
			reconnectdelay = serverConfig["reconnectdelay"].GetUint();
		}
		if (serverConfig.HasMember("address")) {
			address = serverConfig["address"].GetString();
		}
		if (encrypt) {
			if (serverConfig.HasMember("encryptkey")) {
				initCipherKey(serverConfig["encryptkey"].GetString());
			}
			else {
				std::cout << "[forwarder] no encryptkey" << std::endl;
				return ReturnCode::Err;
			}
		}
		if (serverConfig.HasMember("destId"))
			destId = serverConfig["destId"].GetInt();
        if (serverConfig.HasMember("timeoutMin"))
            timeoutMin = serverConfig["timeoutMin"].GetInt();
        if (serverConfig.HasMember("timeoutMax"))
            timeoutMax = serverConfig["timeoutMax"].GetInt();

        setRule(Protocol::Forward, HandleRule::Forward);
        setRule(Protocol::BatchForward, HandleRule::BatchForward);
		return ReturnCode::Ok;
	}

	bool ForwardServer::hasConsistConfig(ForwardServer* server) {
		if (netType != server->netType) {
			return false;
		}
		if (base64 != server->base64) {
			return false;
		}
		if (encrypt != server->encrypt) {
			return false;
		}
		if (encrypt) {
			size_t len = sizeof(AES_KEY);
			for (uint32_t i = 0; i < len; i++) {
				if (((uint8_t*)(&encryptkey))[i] != ((uint8_t*)(&server->encryptkey))[i]) {
					return false;
				}
			}
		}
		return true;
	}

	ForwardClient*  ForwardServer::getClient(UniqID clientId) {
		if (clientId) {
			auto it_client = clients.find(clientId);
			if (it_client != clients.end())
				return it_client->second;
		}
		return nullptr;
	}

	void ForwardServer::initCipherKey(const char* key){
		AES_set_encrypt_key((const unsigned char*)key, 128, &encryptkey);
	}

	void ForwardServer::setRule(Protocol p, HandleRule rule) {
		ruleDict[p] = rule;
	}

	HandleRule ForwardServer::getRule(Protocol p) {
		auto it = ruleDict.find(p);
		if (it == ruleDict.end()) {
			return HandleRule::Unknown;
		}
		return it->second;
	}

	void ForwardServerENet::init(rapidjson::Value& serverConfig) {
		ENetAddress enetAddress;
		if (!isClientMode) {
			enet_address_set_host(&enetAddress, "0.0.0.0");
			enetAddress.port = port;
		}
		else {
			enet_address_set_host(&enetAddress, address.c_str());
			enetAddress.port = port;
		}
		size_t channelLimit = 1;
		//address.host = ENET_HOST_ANY;
		enet_uint32 incomingBandwidth = 0;  /* assume any amount of incoming bandwidth */
		enet_uint32 outgoingBandwidth = 0;	/* assume any amount of outgoing bandwidth */
		if (serverConfig.HasMember("bandwidth")) {
			incomingBandwidth = serverConfig["bandwidth"]["incoming"].GetUint();
			outgoingBandwidth = serverConfig["bandwidth"]["outgoing"].GetUint();
			std::cout << "[forwarder] incomingBandwidth:" << incomingBandwidth << ", outgoingBandwidth:" << outgoingBandwidth << std::endl;
		}

		host = enet_host_create(isClientMode? nullptr: &enetAddress,
			peerLimit,
			channelLimit,
			incomingBandwidth,
			outgoingBandwidth);
		if (!host) {
			std::cout << "[forwarder] An error occurred while trying to create an ENet server host." << std::endl;
			exit(1);
			return;
		}
		if (isClientMode) {
			enet_host_connect(host, &enetAddress, channelLimit, 0);
		}
	}

	void ForwardServerENet::doReconnect() {
		std::cout << "[forwarder] ENet doReconnect" << std::endl;
		ENetAddress enetAddress;
		enet_address_set_host(&enetAddress, address.c_str());
		enetAddress.port = port;
		size_t channelLimit = 1;
		enet_host_connect(host, &enetAddress, channelLimit, 0);
	};

	void ForwardServerENet::doDisconnect() {
		std::cout << "[forwarder] ENet doDisconnect" << std::endl;
		ForwardClient* client = getClient(clientID);
		if (!client) {
			return;
		}
		ForwardClientENet* clientENet = dynamic_cast<ForwardClientENet*>(client);
		auto state = clientENet->peer->state;
		if(state == ENET_PEER_STATE_CONNECTING || state == ENET_PEER_STATE_CONNECTED){
			enet_peer_disconnect(clientENet->peer, 0);
		}
	}

	bool ForwardServerENet::isConnected() {
		ForwardClient* client = getClient(clientID);
		if (!client) {
			return false;
		}
		auto state = dynamic_cast<ForwardClientENet*>(client)->peer->state;
		return state == ENET_PEER_STATE_CONNECTED;
	}

	void  ForwardServerENet::release() {
		enet_host_destroy(host);
		host = nullptr;
	}

	void ForwardServerWS::init(rapidjson::Value& serverConfig) {
		if (!isClientMode) {
			server.set_error_channels(websocketpp::log::elevel::all);
			server.set_access_channels(websocketpp::log::alevel::none);
			server.init_asio();
			server.listen(port);
			server.start_accept();
		}
		else {
			serverAsClient.set_error_channels(websocketpp::log::elevel::all);
			serverAsClient.set_access_channels(websocketpp::log::alevel::none);
			serverAsClient.init_asio();
			doReconnect();
		}
	}

    void  ForwardServerWS::release() {
        doDisconnect();
		hdlToClientId.clear();
	}

	void ForwardServerWS::poll() {
		if (!isClientMode) {
			server.poll_one();
		}
		else {
			serverAsClient.poll_one();
		}
	}

	void ForwardServerWS::doReconnect() {
		std::cout << "[forwarder] WS doReconnect" << std::endl;
		if (isConnected()) {
			return;
		}
		std::string uri = getUri();
		websocketpp::lib::error_code ec;
		WebsocketClient::connection_ptr con = serverAsClient.get_connection(uri, ec);
		if (ec) {
			std::cout << "[forwarder] WS error, could not create connection because: " << ec.message() << std::endl;
			return;
		}
		serverAsClient.connect(con);
	}

	void ForwardServerWS::doDisconnect() {
        std::cout << "[forwarder] WS doDisconnect" << std::endl;
        std::string reason = "";
        websocketpp::lib::error_code ec;
        websocketpp::close::status::value code = websocketpp::close::status::normal;
        if (!isClientMode) {
            server.stop_listening();
            server.stop();
        } else {
            auto client = getClient(clientID);
            if (!client) {
                return;
            }
            ForwardClientWS* clientWS = dynamic_cast<ForwardClientWS*>(client);
            auto hdl = clientWS->hdl;
            serverAsClient.close(hdl, code, reason, ec);
            if (ec) {
                std::cout << "[forwarder] WS error, initiating close: " << ec.message() << std::endl;
            }
            serverAsClient.stop();
        }
	}

	bool ForwardServerWS::isConnected() {
		auto client = getClient(clientID);
		if (!client) {
			return false;
		}
		auto hdl = dynamic_cast<ForwardClientWS*>(client)->hdl;
		return server.get_con_from_hdl(hdl)->get_state() == websocketpp::session::state::value::connecting;
	}
}
<|endoftext|>


<commit_before>/*
 * InterColComm.cpp
 *
 *  Created on: Aug 28, 2008
 *      Author: rasmussn
 */

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>

#include "InterColComm.hpp"
#include "HyPerCol.hpp"
#include "../connections/PVConnection.h"

namespace PV {

InterColComm::InterColComm(int* argc, char*** argv, HyPerCol* col)
{
   float r;

   commInit(argc, argv);

   r = sqrt(commSize);
   numRows = (int) r;
   numCols = (int) commSize / numRows;
   numHyPerCols = numRows * numCols;

   // TODO - build a communicator based on the new processor grid (don't use MPI_COMM_WORLD)

   neighborInit();

   hc = col;
   numPublishers = 0;

   for (int i = 0; i < MAX_PUBLISHERS; i++) {
      publishers[i] = NULL;
   }
}

InterColComm::~InterColComm()
{
   commFinalize();

   for (int i = 0; i < MAX_PUBLISHERS; i++) {
      if (publishers[i] != NULL) {
         delete publishers[i];
      }
   }
}

int InterColComm::commInit(int* argc, char*** argv)
{
   MPI_Init(argc, argv);
   MPI_Comm_rank(MPI_COMM_WORLD, &commRank);
   MPI_Comm_size(MPI_COMM_WORLD, &commSize);

#ifdef DEBUG_OUTPUT
   printf("[%d]: InterColComm::commInit: size=%d\n", commRank, commSize);  fflush(stdout);
#endif

   return 0;
}

int InterColComm::commFinalize()
{
   MPI_Finalize();
   return 0;
}

int InterColComm::addPublisher(HyPerLayer* pub, size_t size1, size_t size2, int numLevels)
{
   int pubId = pub->getLayerId();
   publishers[pubId] = new Publisher(pubId, numNeighbors, size1, numBorders, size2, numLevels);
   numPublishers += 1;

   DataStore* store = publishers[pubId]->dataStore();

   for (int i = 0; i < numBorders; i++) {
      for (int delay = 0; delay < numLevels; delay++) {
         int borderIndex = Publisher::borderStoreIndex(i, numNeighbors);
         PVLayerCube* border = (PVLayerCube*) store->buffer(borderIndex, delay);
         pvcube_setAddr(border);
         pub->initBorder(border, borders[i]);
      }
   }

   return pubId;
}

int InterColComm::subscribe(HyPerConn* conn)
{
   int pubId = conn->preSynapticLayer()->getLayerId();
   assert(pubId < MAX_PUBLISHERS && pubId >= 0);
   return publishers[pubId]->subscribe(conn);
}

int InterColComm::publish(HyPerLayer* pub, PVLayerCube* cube)
{
   int pubId = pub->getLayerId();
   return publishers[pubId]->publish(pub, neighbors, numNeighbors, borders, numBorders, cube);
}

/**
 * deliver all outstanding published messages
 */
int InterColComm::deliver(int pubId)
{
#ifdef DEBUG_OUTPUT
   printf("[%d]: InterColComm::deliver: pubId=%d\n", commRank, pubId);  fflush(stdout);
#endif
   return publishers[pubId]->deliver(hc, numNeighbors, numBorders);
}

/**
 * Initialize the communication neighbors
 */
int InterColComm::neighborInit()
{
   int num_neighbors = 0;
   int num_borders   = 0;

   // initialize neighbor and border lists
   // (local borders and remote neighbors form the complete neighborhood)

   this->numNeighbors = numberNeighbors();
   this->numBorders   = 1 + MAX_NEIGHBORS - this->numNeighbors;

   for (int i = 0; i < 1 + MAX_NEIGHBORS; i++) {
      neighbors[i] = 0;
      int n = neighborIndex(commRank, i);
      if (n >= 0) {
         neighbors[num_neighbors++] = n;
#ifdef DEBUG_OUTPUT
         printf("[%d]: neighborInit: neighbor[%d] of %d is %d, i = %d\n",
                commRank, num_neighbors - 1, this->numNeighbors, n, i);
         fflush(stdout);
#endif
      } else {
         borders[num_borders++] = -n;
      }
   }
   assert(this->numNeighbors == num_neighbors);
   assert(this->numBorders   == num_borders);

   return 0;
}

/**
 * Returns the communication row id for the given communication id
 */
int InterColComm::commRow(int commId)
{
   return (int) commId / this->numCols;
}

/**
 * Returns the communication column id for the given communication id
 */
int InterColComm::commColumn(int commId)
{
   return (commId - this->numCols * commRow(commId));
}

/**
 * Returns true if the given commId has a western neighbor
 * (false otherwise)
 */
bool InterColComm::hasWesternNeighbor(int commId)
{
   return commId % this->numHyPerCols;
}

/**
 * Returns true if the given commId has an eastern neighbor
 * (false otherwise)
 */
bool InterColComm::hasEasternNeighbor(int commId)
{
   return (commId + 1) % this->numHyPerCols;
}

/**
 * Returns true if the given commId has a northern neighbor
 * (false otherwise)
 */
bool InterColComm::hasNorthernNeighbor(int commId)
{
   return ((commId + this->numHyPerCols) > (this->commSize - 1)) ? 0 : 1;
}

/**
 * Returns true if the given commId has a southern neighbor
 * (false otherwise)
 */
bool InterColComm::hasSouthernNeighbor(int commId)
{
   return ((commId - this->numHyPerCols) < 0) ? 0 : 1;
}

/**
 * Returns the number in communication neighborhood (local included)
 */
int InterColComm::numberNeighbors()
{
   int n = 1;

   int hasWest = hasWesternNeighbor(commRank);
   int hasEast = hasEasternNeighbor(commRank);
   int hasNorth = hasNorthernNeighbor(commRank);
   int hasSouth = hasSouthernNeighbor(commRank);

   if (hasNorth > 0) n += 1;
   if (hasSouth > 0) n += 1;

   if (hasWest > 0) {
      n += 1;
      if (hasNorth > 0) n += 1;
      if (hasSouth > 0) n += 1;
   }

   if (hasEast > 0) {
      n += 1;
      if (hasNorth > 0) n += 1;
      if (hasSouth > 0) n += 1;
   }

   return n;
}

/**
 * Returns the communication id of the northwestern HyperColumn
 */
int InterColComm::northwest(int commId)
{
   if (hasNorthernNeighbor(commId) == 0) return -NORTHWEST;
   return west(commId + this->numHyPerCols);
}

/**
 * Returns the communication id of the northern HyperColumn
 */
int InterColComm::north(int commId)
{
   if (hasNorthernNeighbor(commId) == 0) return -NORTH;
   return (commId + this->numHyPerCols);
}

/**
 * Returns the communication id of the northeastern HyperColumn
 */
int InterColComm::northeast(int commId)
{
   if (hasNorthernNeighbor(commId) == 0) return -NORTHEAST;
   return east(commId + this->numHyPerCols);
}

/**
 * Returns the communication id of the western HyperColumn
 */
int InterColComm::west(int commId)
{
   if (hasWesternNeighbor(commId) == 0) return -WEST;
   return (commRow(commId) * numHyPerCols + ((commId - 1) % numHyPerCols));
}

/**
 * Returns the communication id of the eastern HyperColumn
 */
int InterColComm::east(int commId)
{
   if (hasEasternNeighbor(commId) == 0) return -EAST;
   return (commRow(commId) * numHyPerCols + ((commId + 1) % numHyPerCols));
}

/**
 * Returns the communication id of the southwestern HyperColumn
 */
int InterColComm::southwest(int commId)
{
   if (hasSouthernNeighbor(commId) == 0) return -SOUTHWEST;
   return west(commId - this->numHyPerCols);
}

/**
 * Returns the communication id of the southern HyperColumn
 */
int InterColComm::south(int commId)
{
   if (hasSouthernNeighbor(commId) == 0) return -SOUTH;
   return (commId - this->numHyPerCols);
}

/**
 * Returns the communication id of the southeastern HyperColumn
 */
int InterColComm::southeast(int commId)
{
   if (hasSouthernNeighbor(commId) == 0) return -SOUTHEAST;
   return east(commId - this->numHyPerCols);
}

/**
 * Returns the sender rank for the given connection index
 */
int InterColComm::neighborIndex(int commId, int index)
{
   switch (index) {
   case LOCAL: /* local */
      return commId;
   case NORTHWEST : /* northwest */
      return northwest(commId);
   case NORTH     : /* north */
      return north(commId);
   case NORTHEAST : /* northeast */
      return northeast(commId);
   case WEST      : /* west */
      return west(commId);
   case EAST      : /* east */
      return east(commId);
   case SOUTHWEST : /* southwest */
      return southwest(commId);
   case SOUTH     : /* south */
      return south(commId);
   case SOUTHEAST : /* southeast */
      return southeast(commId);
   default:
      fprintf(stderr, "ERROR:neighborIndex: bad index\n");
   }
   return -1;
}

Publisher::Publisher(int pubId, int numType1, size_t size1, int numType2, size_t size2, int numLevels)
{
   size_t maxSize = (size1 > size2) ? size1 : size2;
   this->pubId = pubId;
   this->numSubscribers = 0;
   this->store = new DataStore(numType1+numType2, maxSize, numLevels);
   for (int i = 0; i < MAX_SUBSCRIBERS; i++) {
      this->connection[i] = NULL;
   }
}

Publisher::~Publisher()
{
   delete store;
}

int Publisher::publish(HyPerLayer* pub,
                       int neighbors[], int numNeighbors,
                       int borders[], int numBorders,
                       PVLayerCube* cube)
{
   size_t size = cube->size;
   assert(size == store->size());

   if (numSubscribers < 1) {
      // no one to deliver to
      return 0;
   }

   // send/recv to/from neighbors
   for (int i = 0; i < numNeighbors; i++) {
      // Note - cube->data addr need not be correct as it will be wrong copied in from MPI
      void* recvBuf = recvBuffer(i);
      MPI_Irecv(recvBuf, size, MPI_CHAR, neighbors[i], pubId, MPI_COMM_WORLD,
            &request[i]);
      MPI_Send(cube, size, MPI_CHAR, neighbors[i], pubId, MPI_COMM_WORLD);
#ifdef DEBUG_OUTPUT
      int rank;
      MPI_Comm_rank(MPI_COMM_WORLD, &rank);
      printf("[%d]: Publisher::publish: neighbor=%d pubId=%d sendbuf=%p recvbuf=%p\n",
             rank, neighbors[i], i, cube, recvBuf);
      fflush(stdout);
#endif
   }

   //
   // transform cube (and copy) for boundary conditions of neighbor slots that
   // don't exist in processor topology (i.e., a hypercolumn at edge of image)
   //
   for (int i = 0; i < numBorders; i++) {
      int borderIndex = Publisher::borderStoreIndex(i, numNeighbors);
      PVLayerCube* border = (PVLayerCube*) recvBuffer(borderIndex);
      pub->copyToBorder(borders[i], cube, border);
   }

   return 0;
}

/**
 * deliver all outstanding published messages
 */
int Publisher::deliver(HyPerCol* hc, int numNeighbors, int numBorders)
{
   if (numSubscribers < 1) {
      // no one to deliver to
      return 0;
   }

   // deliver delayed information first
   for (int ic = 0; ic < numSubscribers; ic++) {
      HyPerConn* conn = connection[ic];
      int delay = conn->getDelay();
      if (delay > 0) {
         for (int n = 0; n < numNeighbors; n++) {
            PVLayerCube* cube = (PVLayerCube*) store->buffer(n, delay);
            pvcube_setAddr(cube);  // fix data address arriving from MPI
#ifdef DEBUG_OUTPUT
            int rank;
            MPI_Comm_rank(MPI_COMM_WORLD, &rank);
            printf("[%d]: Publisher::deliver: neighbor=%d buf=%p\n", rank, n, cube);
            fflush(stdout);
#endif
            conn->deliver(cube, n);
         }
      }
   }

   // deliver current (no delay) information last
   for (int n = 0; n < numNeighbors; n++) {
      int neighborId = n; /* WARNING - this must be initialized to n to work with PV_PMI */
      MPI_Waitany(numNeighbors, request, &neighborId, MPI_STATUS_IGNORE);

      for (int ic = 0; ic < numSubscribers; ic++) {
         HyPerConn* conn = this->connection[ic];
         if (conn->getDelay() == 0) {
            PVLayerCube* cube = (PVLayerCube*) store->buffer(neighborId, 0);
            pvcube_setAddr(cube);  // fix data address arriving from MPI
#ifdef DEBUG_OUTPUT
            int rank;
            MPI_Comm_rank(MPI_COMM_WORLD, &rank);
            printf("[%d]: Publisher::deliver: neighbor=%d buf=%p\n", rank, neighborId, cube);
            fflush(stdout);
#endif
            conn->deliver(cube, neighborId);
         }
      }
   }

   // deliver border regions
   for (int i = 0; i < numBorders; i++) {
      int borderIndex = Publisher::borderStoreIndex(i, numNeighbors);

      for (int ic = 0; ic < numSubscribers; ic++) {
         HyPerConn* conn = this->connection[ic];
         if (conn->getDelay() == 0) {
            PVLayerCube* border = (PVLayerCube*) store->buffer(borderIndex, 0);
            pvcube_setAddr(border);  // fix data address arriving from MPI
            conn->deliver(border, borderIndex);
         }
      }
   }

   return 0;
}

int Publisher::subscribe(HyPerConn* conn)
{
   connection[numSubscribers] = conn;
   numSubscribers += 1;

   return 0;
}

} // end namespace PV
<commit_msg>Added delay to delivery of border regions.<commit_after>/*
 * InterColComm.cpp
 *
 *  Created on: Aug 28, 2008
 *      Author: rasmussn
 */

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>

#include "InterColComm.hpp"
#include "HyPerCol.hpp"
#include "../connections/PVConnection.h"

namespace PV {

InterColComm::InterColComm(int* argc, char*** argv, HyPerCol* col)
{
   float r;

   commInit(argc, argv);

   r = sqrt(commSize);
   numRows = (int) r;
   numCols = (int) commSize / numRows;
   numHyPerCols = numRows * numCols;

   // TODO - build a communicator based on the new processor grid (don't use MPI_COMM_WORLD)

   neighborInit();

   hc = col;
   numPublishers = 0;

   for (int i = 0; i < MAX_PUBLISHERS; i++) {
      publishers[i] = NULL;
   }
}

InterColComm::~InterColComm()
{
   commFinalize();

   for (int i = 0; i < MAX_PUBLISHERS; i++) {
      if (publishers[i] != NULL) {
         delete publishers[i];
      }
   }
}

int InterColComm::commInit(int* argc, char*** argv)
{
   MPI_Init(argc, argv);
   MPI_Comm_rank(MPI_COMM_WORLD, &commRank);
   MPI_Comm_size(MPI_COMM_WORLD, &commSize);

#ifdef DEBUG_OUTPUT
   printf("[%d]: InterColComm::commInit: size=%d\n", commRank, commSize);  fflush(stdout);
#endif

   return 0;
}

int InterColComm::commFinalize()
{
   MPI_Finalize();
   return 0;
}

int InterColComm::addPublisher(HyPerLayer* pub, size_t size1, size_t size2, int numLevels)
{
   int pubId = pub->getLayerId();
   publishers[pubId] = new Publisher(pubId, numNeighbors, size1, numBorders, size2, numLevels);
   numPublishers += 1;

   DataStore* store = publishers[pubId]->dataStore();

   for (int i = 0; i < numBorders; i++) {
      for (int delay = 0; delay < numLevels; delay++) {
         int borderIndex = Publisher::borderStoreIndex(i, numNeighbors);
         PVLayerCube* border = (PVLayerCube*) store->buffer(borderIndex, delay);
         pvcube_setAddr(border);
         pub->initBorder(border, borders[i]);
      }
   }

   return pubId;
}

int InterColComm::subscribe(HyPerConn* conn)
{
   int pubId = conn->preSynapticLayer()->getLayerId();
   assert(pubId < MAX_PUBLISHERS && pubId >= 0);
   return publishers[pubId]->subscribe(conn);
}

int InterColComm::publish(HyPerLayer* pub, PVLayerCube* cube)
{
   int pubId = pub->getLayerId();
   return publishers[pubId]->publish(pub, neighbors, numNeighbors, borders, numBorders, cube);
}

/**
 * deliver all outstanding published messages
 */
int InterColComm::deliver(int pubId)
{
#ifdef DEBUG_OUTPUT
   printf("[%d]: InterColComm::deliver: pubId=%d\n", commRank, pubId);  fflush(stdout);
#endif
   return publishers[pubId]->deliver(hc, numNeighbors, numBorders);
}

/**
 * Initialize the communication neighbors
 */
int InterColComm::neighborInit()
{
   int num_neighbors = 0;
   int num_borders   = 0;

   // initialize neighbor and border lists
   // (local borders and remote neighbors form the complete neighborhood)

   this->numNeighbors = numberNeighbors();
   this->numBorders   = 1 + MAX_NEIGHBORS - this->numNeighbors;

   for (int i = 0; i < 1 + MAX_NEIGHBORS; i++) {
      neighbors[i] = 0;
      int n = neighborIndex(commRank, i);
      if (n >= 0) {
         neighbors[num_neighbors++] = n;
#ifdef DEBUG_OUTPUT
         printf("[%d]: neighborInit: neighbor[%d] of %d is %d, i = %d\n",
                commRank, num_neighbors - 1, this->numNeighbors, n, i);
         fflush(stdout);
#endif
      } else {
         borders[num_borders++] = -n;
      }
   }
   assert(this->numNeighbors == num_neighbors);
   assert(this->numBorders   == num_borders);

   return 0;
}

/**
 * Returns the communication row id for the given communication id
 */
int InterColComm::commRow(int commId)
{
   return (int) commId / this->numCols;
}

/**
 * Returns the communication column id for the given communication id
 */
int InterColComm::commColumn(int commId)
{
   return (commId - this->numCols * commRow(commId));
}

/**
 * Returns true if the given commId has a western neighbor
 * (false otherwise)
 */
bool InterColComm::hasWesternNeighbor(int commId)
{
   return commId % this->numHyPerCols;
}

/**
 * Returns true if the given commId has an eastern neighbor
 * (false otherwise)
 */
bool InterColComm::hasEasternNeighbor(int commId)
{
   return (commId + 1) % this->numHyPerCols;
}

/**
 * Returns true if the given commId has a northern neighbor
 * (false otherwise)
 */
bool InterColComm::hasNorthernNeighbor(int commId)
{
   return ((commId + this->numHyPerCols) > (this->commSize - 1)) ? 0 : 1;
}

/**
 * Returns true if the given commId has a southern neighbor
 * (false otherwise)
 */
bool InterColComm::hasSouthernNeighbor(int commId)
{
   return ((commId - this->numHyPerCols) < 0) ? 0 : 1;
}

/**
 * Returns the number in communication neighborhood (local included)
 */
int InterColComm::numberNeighbors()
{
   int n = 1;

   int hasWest = hasWesternNeighbor(commRank);
   int hasEast = hasEasternNeighbor(commRank);
   int hasNorth = hasNorthernNeighbor(commRank);
   int hasSouth = hasSouthernNeighbor(commRank);

   if (hasNorth > 0) n += 1;
   if (hasSouth > 0) n += 1;

   if (hasWest > 0) {
      n += 1;
      if (hasNorth > 0) n += 1;
      if (hasSouth > 0) n += 1;
   }

   if (hasEast > 0) {
      n += 1;
      if (hasNorth > 0) n += 1;
      if (hasSouth > 0) n += 1;
   }

   return n;
}

/**
 * Returns the communication id of the northwestern HyperColumn
 */
int InterColComm::northwest(int commId)
{
   if (hasNorthernNeighbor(commId) == 0) return -NORTHWEST;
   return west(commId + this->numHyPerCols);
}

/**
 * Returns the communication id of the northern HyperColumn
 */
int InterColComm::north(int commId)
{
   if (hasNorthernNeighbor(commId) == 0) return -NORTH;
   return (commId + this->numHyPerCols);
}

/**
 * Returns the communication id of the northeastern HyperColumn
 */
int InterColComm::northeast(int commId)
{
   if (hasNorthernNeighbor(commId) == 0) return -NORTHEAST;
   return east(commId + this->numHyPerCols);
}

/**
 * Returns the communication id of the western HyperColumn
 */
int InterColComm::west(int commId)
{
   if (hasWesternNeighbor(commId) == 0) return -WEST;
   return (commRow(commId) * numHyPerCols + ((commId - 1) % numHyPerCols));
}

/**
 * Returns the communication id of the eastern HyperColumn
 */
int InterColComm::east(int commId)
{
   if (hasEasternNeighbor(commId) == 0) return -EAST;
   return (commRow(commId) * numHyPerCols + ((commId + 1) % numHyPerCols));
}

/**
 * Returns the communication id of the southwestern HyperColumn
 */
int InterColComm::southwest(int commId)
{
   if (hasSouthernNeighbor(commId) == 0) return -SOUTHWEST;
   return west(commId - this->numHyPerCols);
}

/**
 * Returns the communication id of the southern HyperColumn
 */
int InterColComm::south(int commId)
{
   if (hasSouthernNeighbor(commId) == 0) return -SOUTH;
   return (commId - this->numHyPerCols);
}

/**
 * Returns the communication id of the southeastern HyperColumn
 */
int InterColComm::southeast(int commId)
{
   if (hasSouthernNeighbor(commId) == 0) return -SOUTHEAST;
   return east(commId - this->numHyPerCols);
}

/**
 * Returns the sender rank for the given connection index
 */
int InterColComm::neighborIndex(int commId, int index)
{
   switch (index) {
   case LOCAL: /* local */
      return commId;
   case NORTHWEST : /* northwest */
      return northwest(commId);
   case NORTH     : /* north */
      return north(commId);
   case NORTHEAST : /* northeast */
      return northeast(commId);
   case WEST      : /* west */
      return west(commId);
   case EAST      : /* east */
      return east(commId);
   case SOUTHWEST : /* southwest */
      return southwest(commId);
   case SOUTH     : /* south */
      return south(commId);
   case SOUTHEAST : /* southeast */
      return southeast(commId);
   default:
      fprintf(stderr, "ERROR:neighborIndex: bad index\n");
   }
   return -1;
}

Publisher::Publisher(int pubId, int numType1, size_t size1, int numType2, size_t size2, int numLevels)
{
   size_t maxSize = (size1 > size2) ? size1 : size2;
   this->pubId = pubId;
   this->numSubscribers = 0;
   this->store = new DataStore(numType1+numType2, maxSize, numLevels);
   for (int i = 0; i < MAX_SUBSCRIBERS; i++) {
      this->connection[i] = NULL;
   }
}

Publisher::~Publisher()
{
   delete store;
}

int Publisher::publish(HyPerLayer* pub,
                       int neighbors[], int numNeighbors,
                       int borders[], int numBorders,
                       PVLayerCube* cube)
{
   size_t size = cube->size;
   assert(size == store->size());

   if (numSubscribers < 1) {
      // no one to deliver to
      return 0;
   }

   // send/recv to/from neighbors
   for (int i = 0; i < numNeighbors; i++) {
      // Note - cube->data addr need not be correct as it will be wrong copied in from MPI
      void* recvBuf = recvBuffer(i);
      MPI_Irecv(recvBuf, size, MPI_CHAR, neighbors[i], pubId, MPI_COMM_WORLD,
            &request[i]);
      MPI_Send(cube, size, MPI_CHAR, neighbors[i], pubId, MPI_COMM_WORLD);
#ifdef DEBUG_OUTPUT
      int rank;
      MPI_Comm_rank(MPI_COMM_WORLD, &rank);
      printf("[%d]: Publisher::publish: neighbor=%d pubId=%d sendbuf=%p recvbuf=%p\n",
             rank, neighbors[i], i, cube, recvBuf);
      fflush(stdout);
#endif
   }

   //
   // transform cube (and copy) for boundary conditions of neighbor slots that
   // don't exist in processor topology (i.e., a hypercolumn at edge of image)
   //
   for (int i = 0; i < numBorders; i++) {
      int borderIndex = Publisher::borderStoreIndex(i, numNeighbors);
      PVLayerCube* border = (PVLayerCube*) recvBuffer(borderIndex);
      pub->copyToBorder(borders[i], cube, border);
   }

   return 0;
}

/**
 * deliver all outstanding published messages
 */
int Publisher::deliver(HyPerCol* hc, int numNeighbors, int numBorders)
{
   if (numSubscribers < 1) {
      // no one to deliver to
      return 0;
   }

   // deliver delayed information first
   for (int ic = 0; ic < numSubscribers; ic++) {
      HyPerConn* conn = connection[ic];
      int delay = conn->getDelay();
      if (delay > 0) {
         for (int n = 0; n < numNeighbors; n++) {
            PVLayerCube* cube = (PVLayerCube*) store->buffer(n, delay);
            pvcube_setAddr(cube);  // fix data address arriving from MPI
#ifdef DEBUG_OUTPUT
            int rank;
            MPI_Comm_rank(MPI_COMM_WORLD, &rank);
            printf("[%d]: Publisher::deliver: neighbor=%d buf=%p\n", rank, n, cube);
            fflush(stdout);
#endif
            conn->deliver(cube, n);
         }
      }
   }

   // deliver current (no delay) information last
   for (int n = 0; n < numNeighbors; n++) {
      int neighborId = n; /* WARNING - this must be initialized to n to work with PV_MPI */
      MPI_Waitany(numNeighbors, request, &neighborId, MPI_STATUS_IGNORE);

      for (int ic = 0; ic < numSubscribers; ic++) {
         HyPerConn* conn = this->connection[ic];
         if (conn->getDelay() == 0) {
            PVLayerCube* cube = (PVLayerCube*) store->buffer(neighborId, 0);
            pvcube_setAddr(cube);  // fix data address arriving from MPI
#ifdef DEBUG_OUTPUT
            int rank;
            MPI_Comm_rank(MPI_COMM_WORLD, &rank);
            printf("[%d]: Publisher::deliver: neighbor=%d buf=%p\n", rank, neighborId, cube);
            fflush(stdout);
#endif
            conn->deliver(cube, neighborId);
         }
      }
   }

   // deliver border regions
   for (int i = 0; i < numBorders; i++) {
      int borderIndex = Publisher::borderStoreIndex(i, numNeighbors);

      for (int ic = 0; ic < numSubscribers; ic++) {
         HyPerConn* conn = this->connection[ic];
         int delay = conn->getDelay();
         PVLayerCube* border = (PVLayerCube*) store->buffer(borderIndex, delay);
         pvcube_setAddr(border);  // fix data address arriving from MPI
         conn->deliver(border, borderIndex);
      }
   }

   return 0;
}

int Publisher::subscribe(HyPerConn* conn)
{
   connection[numSubscribers] = conn;
   numSubscribers += 1;

   return 0;
}

} // end namespace PV
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
 *
 *  Contact: Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
 *
 *    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.
 */
/*
 * @file        Backtrace.cpp
 * @author      Adam Malinowski <a.malinowsk2@partner.samsung.com>
 * @version     1.0
 * @brief       Implementation of backtrace utility class.
 */

#include <cxxabi.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <attributes/attributes.h>
#include <log/log.h>

#include "Backtrace.h"

namespace Cynara {

Backtrace &Backtrace::getInstance(void) {
    static Backtrace m_instance;
    return m_instance;
}

Backtrace::Backtrace() :
        m_fileName(NULL),
        m_functionName(NULL), m_lineNumber(0) {
}

Backtrace::~Backtrace() {
}

void Backtrace::getSourceInfo(unw_word_t proc_address UNUSED) {
    // TODO: extract filename and line number for symbol at given address
    m_fileName = "??";
    m_functionName = "??";
    m_lineNumber = 0;
}

const std::string Backtrace::buildBacktrace(void) {
    std::string backtrace;
    unw_cursor_t cursor;
    unw_context_t uc;
    unw_word_t ip, sp;
    char proc_name[BUFSIZ];
    char btstr[BUFSIZ];
    unw_word_t offp;
    int status;

    unw_getcontext(&uc);
    // get rid of previous function: Backtrace::getBacktrace
    unw_init_local(&cursor, &uc);
    unw_step(&cursor);
    while (unw_step(&cursor) > 0) {
        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        unw_get_reg(&cursor, UNW_REG_SP, &sp);
        unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &offp);
        char *realname = abi::__cxa_demangle(proc_name, 0, 0, &status);
        getSourceInfo(ip);

        snprintf(btstr, sizeof(btstr), "ip = %p, sp = %p, %s, %s:%u\n",
                ip, sp, realname ? realname : proc_name,
                m_fileName, m_lineNumber);
        free(realname);
        backtrace += btstr;
    }

    return backtrace;
}

const std::string Backtrace::getBacktrace(void) {
    return getInstance().buildBacktrace();
}

} /* namespace Cynara */
<commit_msg>Fix build break on DEBUG dbuild type<commit_after>/*
 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
 *
 *  Contact: Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
 *
 *    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.
 */
/*
 * @file        Backtrace.cpp
 * @author      Adam Malinowski <a.malinowsk2@partner.samsung.com>
 * @version     1.0
 * @brief       Implementation of backtrace utility class.
 */

#include <cxxabi.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sstream>

#include <attributes/attributes.h>
#include <log/log.h>

#include "Backtrace.h"

namespace Cynara {

Backtrace &Backtrace::getInstance(void) {
    static Backtrace m_instance;
    return m_instance;
}

Backtrace::Backtrace() :
        m_fileName(NULL),
        m_functionName(NULL), m_lineNumber(0) {
}

Backtrace::~Backtrace() {
}

void Backtrace::getSourceInfo(unw_word_t proc_address UNUSED) {
    // TODO: extract filename and line number for symbol at given address
    m_fileName = "??";
    m_functionName = "??";
    m_lineNumber = 0;
}

const std::string Backtrace::buildBacktrace(void) {
    std::ostringstream backtrace;
    unw_cursor_t cursor;
    unw_context_t uc;
    unw_word_t ip, sp;
    char proc_name[BUFSIZ];
    unw_word_t offp;
    int status;

    unw_getcontext(&uc);
    // get rid of previous function: Backtrace::getBacktrace
    unw_init_local(&cursor, &uc);
    unw_step(&cursor);
    while (unw_step(&cursor) > 0) {
        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        unw_get_reg(&cursor, UNW_REG_SP, &sp);
        unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &offp);
        char *realname = abi::__cxa_demangle(proc_name, 0, 0, &status);
        getSourceInfo(ip);

        backtrace << std::hex << "ip = 0x" <<  ip << ", sp = 0x" << sp
                  << ", " << (realname ? realname : proc_name)
                  << ", " << m_fileName
                  << ":" << std::dec << m_lineNumber << std::endl;

        free(realname);
    }

    return backtrace.str();
}

const std::string Backtrace::getBacktrace(void) {
    return getInstance().buildBacktrace();
}

} /* namespace Cynara */
<|endoftext|>


<commit_before>#include "contractresult.h"
#include "ui_contractresult.h"
#include "guiconstants.h"
#include "contractabi.h"
#include <QMessageBox>

ContractResult::ContractResult(QWidget *parent) :
    QStackedWidget(parent),
    ui(new Ui::ContractResult)
{
    ui->setupUi(this);
    ui->groupBoxCallContract->setStyleSheet(STYLE_GROUPBOX);
    ui->groupBoxResult->setStyleSheet(STYLE_GROUPBOX);
    ui->groupBoxCreateOrSendTo->setStyleSheet(STYLE_GROUPBOX);

    ui->scrollAreaParams->setStyleSheet(".QScrollArea { border: none;}");
    ui->scrollAreaResult->setStyleSheet(".QScrollArea { border: none;}");
}

ContractResult::~ContractResult()
{
    delete ui;
}

void ContractResult::setResultData(QVariant result, FunctionABI function, QList<QStringList> paramValues, ContractTxType type)
{
    switch (type) {
    case CreateResult:
        updateCreateResult(result);
        setCurrentWidget(ui->pageCreateOrSendToResult);
        break;

    case SendToResult:
        updateSendToResult(result);
        setCurrentWidget(ui->pageCreateOrSendToResult);
        break;

    case CallResult:
        updateCallResult(result, function, paramValues);
        setCurrentWidget(ui->pageCallResult);
        break;

    default:
        break;
    }
}

void ContractResult::setParamsData(FunctionABI function, QList<QStringList> paramValues)
{
    // Remove previous widget from scroll area
    QWidget *scrollWidget = ui->scrollAreaParams->widget();
    if(scrollWidget)
        scrollWidget->deleteLater();

    // Don't show empty list
    if(function.inputs.size() == 0)
    {
        ui->scrollAreaParams->setVisible(false);
        return;
    }

    QWidget *widgetParams = new QWidget(this);
    QVBoxLayout *mainLayout = new QVBoxLayout(widgetParams);
    mainLayout->setSpacing(6);
    mainLayout->setContentsMargins(0,0,30,0);

    // Add rows with params and values sent
    int i = 0;
    for(std::vector<ParameterABI>::const_iterator param = function.inputs.begin(); param != function.inputs.end(); ++param)
    {
        QHBoxLayout *hLayout = new QHBoxLayout(widgetParams);
        hLayout->setSpacing(10);
        hLayout->setContentsMargins(0,0,0,0);
        QVBoxLayout *vNameLayout = new QVBoxLayout(widgetParams);
        vNameLayout->setSpacing(3);
        vNameLayout->setContentsMargins(0,0,0,0);
        QVBoxLayout *paramValuesLayout = new QVBoxLayout(widgetParams);
        paramValuesLayout->setSpacing(3);
        paramValuesLayout->setContentsMargins(0,0,0,0);

        QLabel *paramName = new QLabel(this);
        paramName->setFixedWidth(160);
        paramName->setFixedHeight(19);
        QFontMetrics metrix(paramName->font());
        int width = paramName->width() + 10;
        QString text(QString("%2 <b>%1").arg(QString::fromStdString(param->name)).arg(QString::fromStdString(param->type)));
        QString clippedText = metrix.elidedText(text, Qt::ElideRight, width);
        paramName->setText(clippedText);
        paramName->setToolTip(QString("%2 %1").arg(QString::fromStdString(param->name)).arg(QString::fromStdString(param->type)));

        vNameLayout->addWidget(paramName);
        QStringList listValues = paramValues[i];
        int spacerSize = 0;
        for(int j = 0; j < listValues.count(); j++)
        {
            QLineEdit *paramValue = new QLineEdit(this);
            paramValue->setReadOnly(true);
            paramValue->setText(listValues[j]);
            paramValuesLayout->addWidget(paramValue);
            if(j > 0)
                spacerSize += 22; // Line edit height + spacing
        }
        if(spacerSize > 0)
            vNameLayout->addSpacerItem(new QSpacerItem(20, spacerSize, QSizePolicy::Fixed, QSizePolicy::Fixed));
        hLayout->addLayout(vNameLayout);
        hLayout->addLayout(paramValuesLayout);

        mainLayout->addLayout(hLayout);
        i++;
    }
    widgetParams->setLayout(mainLayout);
    widgetParams->adjustSize();
    if(widgetParams->sizeHint().height() < 70)
        ui->scrollAreaParams->setMaximumHeight(widgetParams->sizeHint().height() + 2);
    else
        ui->scrollAreaParams->setMaximumHeight(140);
    ui->scrollAreaParams->setWidget(widgetParams);
    ui->scrollAreaParams->setVisible(true);
}

void ContractResult::updateCreateResult(QVariant result)
{
    ui->lineEditContractAddress->setVisible(true);
    ui->labelContractAddress->setVisible(true);

    QVariantMap variantMap = result.toMap();

    ui->lineEditTxID->setText(variantMap.value("txid").toString());
    ui->lineEditSenderAddress->setText(variantMap.value("sender").toString());
    ui->lineEditHash160->setText(variantMap.value("hash160").toString());
    ui->lineEditContractAddress->setText(variantMap.value("address").toString());
}

void ContractResult::updateSendToResult(QVariant result)
{
    ui->lineEditContractAddress->setVisible(false);
    ui->labelContractAddress->setVisible(false);

    QVariantMap variantMap = result.toMap();

    ui->lineEditTxID->setText(variantMap.value("txid").toString());
    ui->lineEditSenderAddress->setText(variantMap.value("sender").toString());
    ui->lineEditHash160->setText(variantMap.value("hash160").toString());
}

void ContractResult::updateCallResult(QVariant result, FunctionABI function, QList<QStringList> paramValues)
{
    QVariantMap variantMap = result.toMap();
    QVariantMap executionResultMap = variantMap.value("executionResult").toMap();

    ui->lineEditCallContractAddress->setText(variantMap.value("address").toString());
    ui->lineEditFunction->setText(QString::fromStdString(function.name));

    setParamsData(function, paramValues);

    ui->lineEditCallSenderAddress->setText(variantMap.value("sender").toString());
    std::string rawData = executionResultMap.value("output").toString().toStdString();
    std::vector<std::vector<std::string>> values;
    std::vector<ParameterABI::ErrorType> errors;
    if(function.abiOut(rawData, values, errors))
    {
        // Remove previous widget from scroll area
        QWidget *scrollWidget = ui->scrollAreaResult->widget();
        if(scrollWidget)
            scrollWidget->deleteLater();

        if(values.size() > 0)
        {
            QWidget *widgetResults = new QWidget(this);
            QVBoxLayout *mainLayout = new QVBoxLayout(widgetResults);
            mainLayout->setSpacing(6);
            mainLayout->setContentsMargins(0,6,0,6);
            widgetResults->setLayout(mainLayout);

            for(size_t i = 0; i < values.size(); i++)
            {
                QHBoxLayout *hLayout = new QHBoxLayout(widgetResults);
                hLayout->setSpacing(10);
                hLayout->setContentsMargins(0,0,0,0);
                QVBoxLayout *vNameLayout = new QVBoxLayout(widgetResults);
                vNameLayout->setSpacing(3);
                vNameLayout->setContentsMargins(0,0,0,0);
                QVBoxLayout *paramValuesLayout = new QVBoxLayout(widgetResults);
                paramValuesLayout->setSpacing(3);
                paramValuesLayout->setContentsMargins(0,0,0,0);

                QLabel *resultName = new QLabel(this);
                resultName->setFixedWidth(160);
                resultName->setFixedHeight(19);
                QFontMetrics metrix(resultName->font());
                int width = resultName->width() + 10;
                QString text(QString("%2 <b>%1").arg(QString::fromStdString(function.outputs[i].name)).arg(QString::fromStdString(function.outputs[i].type)));
                QString clippedText = metrix.elidedText(text, Qt::ElideRight, width);
                resultName->setText(clippedText);
                resultName->setToolTip(QString("%2 %1").arg(QString::fromStdString(function.outputs[i].name)).arg(QString::fromStdString(function.outputs[i].type)));

                vNameLayout->addWidget(resultName);
                std::vector<std::string> listValues = values[i];
                int spacerSize = 0;
                for(size_t j = 0; j < listValues.size(); j++)
                {
                    QLineEdit *resultValue = new QLineEdit(this);
                    resultValue->setReadOnly(true);
                    resultValue->setText(QString::fromStdString(listValues[j]));
                    paramValuesLayout->addWidget(resultValue);
                    if(j > 0)
                        spacerSize += 22; // Line edit height + spacing
                }
                if(spacerSize > 0)
                    vNameLayout->addSpacerItem(new QSpacerItem(20, spacerSize, QSizePolicy::Fixed, QSizePolicy::Fixed));
                hLayout->addLayout(vNameLayout);
                hLayout->addLayout(paramValuesLayout);

                mainLayout->addLayout(hLayout);
            }
            widgetResults->adjustSize();
            if(widgetResults->sizeHint().height() < 70)
            {
                ui->scrollAreaResult->setMaximumHeight(widgetResults->sizeHint().height() + 2);
            }
            else
            {
                ui->scrollAreaResult->setMaximumHeight(140);
            }
            ui->scrollAreaResult->setWidget(widgetResults);
            ui->groupBoxResult->setVisible(true);
        }
        else
        {
            ui->groupBoxResult->setVisible(false);
        }
    }
    else
    {
        QString errorMessage;
        errorMessage = function.errorMessage(errors, false);
        QMessageBox::warning(this, tr("Create contract"), errorMessage);
    }
}
<commit_msg>Update alignment for empty list result<commit_after>#include "contractresult.h"
#include "ui_contractresult.h"
#include "guiconstants.h"
#include "contractabi.h"
#include <QMessageBox>

ContractResult::ContractResult(QWidget *parent) :
    QStackedWidget(parent),
    ui(new Ui::ContractResult)
{
    ui->setupUi(this);
    ui->groupBoxCallContract->setStyleSheet(STYLE_GROUPBOX);
    ui->groupBoxResult->setStyleSheet(STYLE_GROUPBOX);
    ui->groupBoxCreateOrSendTo->setStyleSheet(STYLE_GROUPBOX);

    ui->scrollAreaParams->setStyleSheet(".QScrollArea { border: none;}");
    ui->scrollAreaResult->setStyleSheet(".QScrollArea { border: none;}");
}

ContractResult::~ContractResult()
{
    delete ui;
}

void ContractResult::setResultData(QVariant result, FunctionABI function, QList<QStringList> paramValues, ContractTxType type)
{
    switch (type) {
    case CreateResult:
        updateCreateResult(result);
        setCurrentWidget(ui->pageCreateOrSendToResult);
        break;

    case SendToResult:
        updateSendToResult(result);
        setCurrentWidget(ui->pageCreateOrSendToResult);
        break;

    case CallResult:
        updateCallResult(result, function, paramValues);
        setCurrentWidget(ui->pageCallResult);
        break;

    default:
        break;
    }
}

void ContractResult::setParamsData(FunctionABI function, QList<QStringList> paramValues)
{
    // Remove previous widget from scroll area
    QWidget *scrollWidget = ui->scrollAreaParams->widget();
    if(scrollWidget)
        scrollWidget->deleteLater();

    // Don't show empty list
    if(function.inputs.size() == 0)
    {
        ui->scrollAreaParams->setVisible(false);
        return;
    }

    QWidget *widgetParams = new QWidget(this);
    QVBoxLayout *mainLayout = new QVBoxLayout(widgetParams);
    mainLayout->setSpacing(6);
    mainLayout->setContentsMargins(0,0,30,0);

    // Add rows with params and values sent
    int i = 0;
    for(std::vector<ParameterABI>::const_iterator param = function.inputs.begin(); param != function.inputs.end(); ++param)
    {
        QHBoxLayout *hLayout = new QHBoxLayout(widgetParams);
        hLayout->setSpacing(10);
        hLayout->setContentsMargins(0,0,0,0);
        QVBoxLayout *vNameLayout = new QVBoxLayout(widgetParams);
        vNameLayout->setSpacing(3);
        vNameLayout->setContentsMargins(0,0,0,0);
        QVBoxLayout *paramValuesLayout = new QVBoxLayout(widgetParams);
        paramValuesLayout->setSpacing(3);
        paramValuesLayout->setContentsMargins(0,0,0,0);

        QLabel *paramName = new QLabel(this);
        paramName->setFixedWidth(160);
        paramName->setFixedHeight(19);
        QFontMetrics metrix(paramName->font());
        int width = paramName->width() + 10;
        QString text(QString("%2 <b>%1").arg(QString::fromStdString(param->name)).arg(QString::fromStdString(param->type)));
        QString clippedText = metrix.elidedText(text, Qt::ElideRight, width);
        paramName->setText(clippedText);
        paramName->setToolTip(QString("%2 %1").arg(QString::fromStdString(param->name)).arg(QString::fromStdString(param->type)));

        vNameLayout->addWidget(paramName);
        QStringList listValues = paramValues[i];
        int spacerSize = 0;
        for(int j = 0; j < listValues.count(); j++)
        {
            QLineEdit *paramValue = new QLineEdit(this);
            paramValue->setReadOnly(true);
            paramValue->setText(listValues[j]);
            paramValuesLayout->addWidget(paramValue);
            if(j > 0)
                spacerSize += 22; // Line edit height + spacing
        }
        if(spacerSize > 0)
            vNameLayout->addSpacerItem(new QSpacerItem(20, spacerSize, QSizePolicy::Fixed, QSizePolicy::Fixed));
        hLayout->addLayout(vNameLayout);
        hLayout->addLayout(paramValuesLayout);

        mainLayout->addLayout(hLayout);
        i++;
    }
    widgetParams->setLayout(mainLayout);
    widgetParams->adjustSize();
    if(widgetParams->sizeHint().height() < 70)
        ui->scrollAreaParams->setMaximumHeight(widgetParams->sizeHint().height() + 2);
    else
        ui->scrollAreaParams->setMaximumHeight(140);
    ui->scrollAreaParams->setWidget(widgetParams);
    ui->scrollAreaParams->setVisible(true);
}

void ContractResult::updateCreateResult(QVariant result)
{
    ui->lineEditContractAddress->setVisible(true);
    ui->labelContractAddress->setVisible(true);

    QVariantMap variantMap = result.toMap();

    ui->lineEditTxID->setText(variantMap.value("txid").toString());
    ui->lineEditSenderAddress->setText(variantMap.value("sender").toString());
    ui->lineEditHash160->setText(variantMap.value("hash160").toString());
    ui->lineEditContractAddress->setText(variantMap.value("address").toString());
}

void ContractResult::updateSendToResult(QVariant result)
{
    ui->lineEditContractAddress->setVisible(false);
    ui->labelContractAddress->setVisible(false);

    QVariantMap variantMap = result.toMap();

    ui->lineEditTxID->setText(variantMap.value("txid").toString());
    ui->lineEditSenderAddress->setText(variantMap.value("sender").toString());
    ui->lineEditHash160->setText(variantMap.value("hash160").toString());
}

void ContractResult::updateCallResult(QVariant result, FunctionABI function, QList<QStringList> paramValues)
{
    QVariantMap variantMap = result.toMap();
    QVariantMap executionResultMap = variantMap.value("executionResult").toMap();

    ui->lineEditCallContractAddress->setText(variantMap.value("address").toString());
    ui->lineEditFunction->setText(QString::fromStdString(function.name));

    setParamsData(function, paramValues);

    ui->lineEditCallSenderAddress->setText(variantMap.value("sender").toString());
    std::string rawData = executionResultMap.value("output").toString().toStdString();
    std::vector<std::vector<std::string>> values;
    std::vector<ParameterABI::ErrorType> errors;
    if(function.abiOut(rawData, values, errors))
    {
        // Remove previous widget from scroll area
        QWidget *scrollWidget = ui->scrollAreaResult->widget();
        if(scrollWidget)
            scrollWidget->deleteLater();

        if(values.size() > 0)
        {
            QWidget *widgetResults = new QWidget(this);
            QVBoxLayout *mainLayout = new QVBoxLayout(widgetResults);
            mainLayout->setSpacing(6);
            mainLayout->setContentsMargins(0,6,0,6);
            widgetResults->setLayout(mainLayout);

            for(size_t i = 0; i < values.size(); i++)
            {
                QHBoxLayout *hLayout = new QHBoxLayout(widgetResults);
                hLayout->setSpacing(10);
                hLayout->setContentsMargins(0,0,0,0);
                QVBoxLayout *vNameLayout = new QVBoxLayout(widgetResults);
                vNameLayout->setSpacing(3);
                vNameLayout->setContentsMargins(0,0,0,0);
                QVBoxLayout *paramValuesLayout = new QVBoxLayout(widgetResults);
                paramValuesLayout->setSpacing(3);
                paramValuesLayout->setContentsMargins(0,0,0,0);

                QLabel *resultName = new QLabel(this);
                resultName->setFixedWidth(160);
                resultName->setFixedHeight(19);
                QFontMetrics metrix(resultName->font());
                int width = resultName->width() + 10;
                QString text(QString("%2 <b>%1").arg(QString::fromStdString(function.outputs[i].name)).arg(QString::fromStdString(function.outputs[i].type)));
                QString clippedText = metrix.elidedText(text, Qt::ElideRight, width);
                resultName->setText(clippedText);
                resultName->setToolTip(QString("%2 %1").arg(QString::fromStdString(function.outputs[i].name)).arg(QString::fromStdString(function.outputs[i].type)));

                vNameLayout->addWidget(resultName);
                std::vector<std::string> listValues = values[i];
                hLayout->addLayout(vNameLayout);
                if(listValues.size() > 0)
                {
                    int spacerSize = 0;
                    for(size_t j = 0; j < listValues.size(); j++)
                    {
                        QLineEdit *resultValue = new QLineEdit(this);
                        resultValue->setReadOnly(true);
                        resultValue->setText(QString::fromStdString(listValues[j]));
                        paramValuesLayout->addWidget(resultValue);
                        if(j > 0)
                            spacerSize += 22; // Line edit height + spacing
                    }
                    if(spacerSize > 0)
                        vNameLayout->addSpacerItem(new QSpacerItem(20, spacerSize, QSizePolicy::Fixed, QSizePolicy::Fixed));
                    hLayout->addLayout(paramValuesLayout);
                }
                else
                {
                    hLayout->addSpacerItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Fixed));
                }
                mainLayout->addLayout(hLayout);
            }
            widgetResults->adjustSize();
            if(widgetResults->sizeHint().height() < 70)
            {
                ui->scrollAreaResult->setMaximumHeight(widgetResults->sizeHint().height() + 2);
            }
            else
            {
                ui->scrollAreaResult->setMaximumHeight(140);
            }
            ui->scrollAreaResult->setWidget(widgetResults);
            ui->groupBoxResult->setVisible(true);
        }
        else
        {
            ui->groupBoxResult->setVisible(false);
        }
    }
    else
    {
        QString errorMessage;
        errorMessage = function.errorMessage(errors, false);
        QMessageBox::warning(this, tr("Create contract"), errorMessage);
    }
}
<|endoftext|>