text:
/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2017 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this program. If not, see <http://www.gnu.org/licenses/>.        *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include <SofaBaseTopology/EdgeSetTopologyContainer.h>
#include <sofa/core/visual/VisualParams.h>

#include <sofa/core/ObjectFactory.h>
// Use BOOST GRAPH LIBRARY :

#include <boost/config.hpp>
#include <iostream>
#include <vector>
#include <utility>

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>

#include <boost/graph/cuthill_mckee_ordering.hpp>
#include <boost/graph/bandwidth.hpp>

namespace sofa
{

namespace component
{

namespace topology
{

using namespace std;
using namespace sofa::defaulttype;
SOFA_DECL_CLASS(EdgeSetTopologyContainer)
int EdgeSetTopologyContainerClass = core::RegisterObject("Edge set topology container")
        .add< EdgeSetTopologyContainer >()
        ;

EdgeSetTopologyContainer::EdgeSetTopologyContainer()
    : PointSetTopologyContainer( )
    , d_edge(initData(&d_edge, "edges", "List of edge indices"))
    , m_checkConnexity(initData(&m_checkConnexity, false, "checkConnexity", "It true, will check the connexity of the mesh."))
{
}

void EdgeSetTopologyContainer::init()
{
    d_edge.updateIfDirty(); // make sure m_edge is up to date

    helper::ReadAccessor< Data< sofa::helper::vector<Edge> > > m_edge = d_edge;
    if (!m_edge.empty() && !d_initPoints.isSet()) // if d_initPoints is set, we don't overwrite it.
    {
        for (size_t i=0; i<m_edge.size(); ++i)
        {
            for(size_t j=0; j<2; ++j)
            {
                int a = m_edge[i][j];
                if (a >= getNbPoints()) setNbPoints(a+1);
            }
        }
    }
    // std::cout << "coords: " << getPX(m_edge[1][0]) << " " << getPY(m_edge[1][0]) << " " << getPZ(m_edge[1][0]) << std::endl;

    PointSetTopologyContainer::init();
}

void EdgeSetTopologyContainer::addEdge(int a, int b)
{
    helper::WriteAccessor< Data< sofa::helper::vector<Edge> > > m_edge = d_edge;
    m_edge.push_back(Edge(a,b));
    if (a >= getNbPoints()) setNbPoints(a+1);
    if (b >= getNbPoints()) setNbPoints(b+1);
}

void EdgeSetTopologyContainer::createEdgesAroundVertexArray()
{
    if(!hasEdges())	// this method should only be called when edges exist
    {
#ifndef NDEBUG
        sout << "Warning. [EdgeSetTopologyContainer::createEdgesAroundVertexArray] edge array is empty." << sendl;
#endif
        createEdgeSetArray();
    }

    if(hasEdgesAroundVertex())
    {
        clearEdgesAroundVertex();
    }

    helper::ReadAccessor< Data< sofa::helper::vector<Edge> > > m_edge = d_edge;
    m_edgesAroundVertex.resize( getNbPoints() );
    for (unsigned int edge=0; edge<m_edge.size(); ++edge)
    {
        // adding edge in the edge shell of both points
        m_edgesAroundVertex[ m_edge[edge][0] ].push_back(edge);
        m_edgesAroundVertex[ m_edge[edge][1] ].push_back(edge);
    }

    if (m_checkConnexity.getValue())
        this->checkConnexity();
}

void EdgeSetTopologyContainer::reinit()
{
    PointSetTopologyContainer::reinit();

    if (m_checkConnexity.getValue())
        this->checkConnexity();
}

void EdgeSetTopologyContainer::createEdgeSetArray()
{
#ifndef NDEBUG
    sout << "Error. [EdgeSetTopologyContainer::createEdgeSetArray] This method must be implemented by a child topology." << sendl;
#endif
}

const sofa::helper::vector<EdgeSetTopologyContainer::Edge> &EdgeSetTopologyContainer::getEdgeArray()
{
    if(!hasEdges() && getNbPoints()>0)
    {
#ifndef NDEBUG
        sout << "Warning. [EdgeSetTopologyContainer::getEdgeArray] creating edge array." << sendl;
#endif
        createEdgeSetArray();
    }

    return d_edge.getValue();
}

int EdgeSetTopologyContainer::getEdgeIndex(PointID v1, PointID v2)
{
    if(!hasEdges()) // this method should only be called when edges exist
    {
#ifndef NDEBUG
        sout << "Warning. [EdgeSetTopologyContainer::getEdgeIndex] edge array is empty." << sendl;
#endif
        createEdgeSetArray();
    }

    if(!hasEdgesAroundVertex())
        createEdgesAroundVertexArray();

    const sofa::helper::vector< unsigned int > &es1 = getEdgesAroundVertex(v1) ;
    helper::ReadAccessor< Data< sofa::helper::vector<Edge> > > m_edge = d_edge;

    int result = -1;
    for(size_t i=0; (i < es1.size()) && (result == -1); ++i)
    {
        const Edge &e = m_edge[ es1[i] ];
        if ((e[0] == v2) || (e[1] == v2))
            result = (int) es1[i];
    }
    return result;
}

const EdgeSetTopologyContainer::Edge EdgeSetTopologyContainer::getEdge (EdgeID i)
{
    if(!hasEdges())
        createEdgeSetArray();

    return (d_edge.getValue())[i];
}

// Return the number of connected components from the graph containing all edges and give, for each vertex, which component it belongs to  (use BOOST GRAPH LIBRAIRY)
int EdgeSetTopologyContainer::getNumberConnectedComponents(sofa::helper::vector<unsigned int>& components)
{
    using namespace boost;

    typedef adjacency_list <vecS, vecS, undirectedS> Graph;

    Graph G;
    helper::ReadAccessor< Data< sofa::helper::vector<Edge> > > m_edge = d_edge;

    for (size_t k=0; k<m_edge.size(); ++k)
    {
        add_edge(m_edge[k][0], m_edge[k][1], G);
    }

    components.resize(num_vertices(G));
    int num = (int) connected_components(G, &components[0]);

    return num;
}

bool EdgeSetTopologyContainer::checkTopology() const
{
#ifndef NDEBUG
    bool ret = true;

    if(hasEdgesAroundVertex())
    {
        helper::ReadAccessor< Data< sofa::helper::vector<Edge> > > m_edge = d_edge;
        std::set<int> edgeSet;
        std::set<int>::iterator it;

        for (size_t i=0; i<m_edgesAroundVertex.size(); ++i)
        {
            const sofa::helper::vector<unsigned int> &es = m_edgesAroundVertex[i];

            for (size_t j=0; j<es.size(); ++j)
            {
                bool check_edge_vertex_shell = (m_edge[ es[j] ][0] == i) ||  (m_edge[ es[j] ][1] == i);
                if(! check_edge_vertex_shell)
                {
                    std::cout << "*** CHECK FAILED : check_edge_vertex_shell, i = " << i << " , j = " << j << std::endl;
                    ret = false;
                }

                it=edgeSet.find(es[j]);
                if (it == edgeSet.end())
                {
                    edgeSet.insert (es[j]);
                }
            }
        }

        if (edgeSet.size() != m_edge.size())
        {
            std::cout << "*** CHECK FAILED : check_edge_vertex_shell, edge are missing in m_edgesAroundVertex" << std::endl;
            ret = false;
        }
    }

    return ret &&  PointSetTopologyContainer::checkTopology();
#else
    return true;
#endif
}

/// Get information about connexity of the mesh
/// @{
bool EdgeSetTopologyContainer::checkConnexity()
{

    size_t nbr = this->getNbEdges();

    if (nbr == 0)
    {
#ifndef NDEBUG
        serr << "Warning. [EdgeSetTopologyContainer::checkConnexity] Can't compute connexity as there are no edges" << sendl;
#endif
        return false;
    }

    VecEdgeID elemAll = this->getConnectedElement(0);

    if (elemAll.size() != nbr)
    {
        serr << "Warning: in computing connexity, edges are missings. There is more than one connexe component." << sendl;
        return false;
    }

    return true;
}

unsigned int EdgeSetTopologyContainer::getNumberOfConnectedComponent()
{
    size_t nbr = this->getNbEdges();

    if (nbr == 0)
    {
#ifndef NDEBUG
        serr << "Warning. [EdgeSetTopologyContainer::getNumberOfConnectedComponent] Can't compute connexity as there are no edges" << sendl;
#endif
        return 0;
    }

    VecEdgeID elemAll = this->getConnectedElement(0);
    unsigned int cpt = 1;

    while (elemAll.size() < nbr)
    {
        std::sort(elemAll.begin(), elemAll.end());
        EdgeID other_edgeID = elemAll.size();

        for (EdgeID i = 0; i<(EdgeID)elemAll.size(); ++i)
            if (elemAll[i] != i)
            {
                other_edgeID = i;
                break;
            }

        VecEdgeID elemTmp = this->getConnectedElement(other_edgeID);
        cpt++;

        elemAll.insert(elemAll.begin(), elemTmp.begin(), elemTmp.end());
    }

    return cpt;
}

const EdgeSetTopologyContainer::VecEdgeID EdgeSetTopologyContainer::getConnectedElement(EdgeID elem)
{
    if(!hasEdgesAroundVertex())	// this method should only be called when the shell array exists
    {
#ifndef NDEBUG
        serr << "Warning. [EdgeSetTopologyContainer::getConnectedElement] EdgesAroundVertex shell array is empty." << sendl;
#endif
        createEdgesAroundVertexArray();
    }

    VecEdgeID elemAll;
    VecEdgeID elemOnFront, elemPreviousFront, elemNextFront;
    bool end = false;
    size_t cpt = 0;
    size_t nbr = this->getNbEdges();

    // init algo
    elemAll.push_back(elem);
    elemOnFront.push_back(elem);
    elemPreviousFront.clear();
    cpt++;

    while (!end && cpt < nbr)
    {
        // First Step - Create new region
        elemNextFront = this->getElementAroundElements(elemOnFront); // for each edgeId on the propagation front

        // Second Step - Avoid backward direction
        for (size_t i = 0; i<elemNextFront.size(); ++i)
        {
            bool find = false;
            EdgeID id = elemNextFront[i];

            for (size_t j = 0; j<elemAll.size(); ++j)
                if (id == elemAll[j])
                {
                    find = true;
                    break;
                }

            if (!find)
            {
                elemAll.push_back(id);
                elemPreviousFront.push_back(id);
            }
        }

        // cpt for connexity
        cpt +=elemPreviousFront.size();

        if (elemPreviousFront.empty())
        {
            end = true;
#ifndef NDEBUG
            serr << "Loop for computing connexity has reach end." << sendl;
#endif
        }

        // iterate
        elemOnFront = elemPreviousFront;
        elemPreviousFront.clear();
    }

    return elemAll;
}

const EdgeSetTopologyContainer::VecEdgeID EdgeSetTopologyContainer::getElementAroundElement(EdgeID elem)
{
    VecEdgeID elems;

    if (!hasEdgesAroundVertex())
    {
#ifndef NDEBUG
        serr << "Warning. [EdgeSetTopologyContainer::getElementAroundElement] edge vertex shell array is empty." << sendl;
#endif
        createEdgesAroundVertexArray();
    }

    Edge the_edge = this->getEdge(elem);

    for(size_t i = 0; i<2; ++i) // for each node of the edge
    {
        EdgesAroundVertex edgeAV = this->getEdgesAroundVertex(the_edge[i]);

        for (size_t j = 0; j<edgeAV.size(); ++j) // for each edge around the node
        {
            bool find = false;
            EdgeID id = edgeAV[j];

            if (id == elem)
                continue;

            for (size_t k = 0; k<elems.size(); ++k) // check no redundancy
                if (id == elems[k])
                {
                    find = true;
                    break;
                }

            if (!find)
                elems.push_back(id);
        }
    }

    return elems;
}

const EdgeSetTopologyContainer::VecEdgeID EdgeSetTopologyContainer::getElementAroundElements(VecEdgeID elems)
{
    VecEdgeID elemAll;
    VecEdgeID elemTmp;

    if (!hasEdgesAroundVertex())
    {
#ifndef NDEBUG
        serr << "Warning. [EdgeSetTopologyContainer::getElementAroundElements] edge vertex shell array is empty." << sendl;
#endif
        createEdgesAroundVertexArray();
    }

    for (size_t i = 0; i <elems.size(); ++i) // for each edgeId of input vector
    {
        VecEdgeID elemTmp2 = this->getElementAroundElement(elems[i]);

        elemTmp.insert(elemTmp.end(), elemTmp2.begin(), elemTmp2.end());
    }

    for (size_t i = 0; i<elemTmp.size(); ++i) // for each edge Id found
    {
        bool find = false;
        EdgeID id = elemTmp[i];

        for (size_t j = 0; j<elems.size(); ++j) // check no redundancy with input vector
            if (id == elems[j])
            {
                find = true;
                break;
            }

        if (!find)
        {
            for (size_t j = 0; j<elemAll.size(); ++j) // check no redundancy in output vector
                if (id == elemAll[j])
                {
                    find = true;
                    break;
                }
        }

        if (!find)
            elemAll.push_back(id);
    }

    return elemAll;
}

/// @}

unsigned int EdgeSetTopologyContainer::getNumberOfEdges() const
{
    d_edge.updateIfDirty();
    return (unsigned int)d_edge.getValue().size();
}

unsigned int EdgeSetTopologyContainer::getNumberOfElements() const
{
    return this->getNumberOfEdges();
}

const sofa::helper::vector< sofa::helper::vector<unsigned int> > &EdgeSetTopologyContainer::getEdgesAroundVertexArray()
{
    if(!hasEdgesAroundVertex())
    {
#ifndef NDEBUG
        sout << "Warning. [EdgeSetTopologyContainer::getEdgesAroundVertexArray] edge vertex shell array is empty." << sendl;
#endif
        createEdgesAroundVertexArray();
    }

    return m_edgesAroundVertex;
}

const EdgeSetTopologyContainer::EdgesAroundVertex& EdgeSetTopologyContainer::getEdgesAroundVertex(PointID i)
{
    if(!hasEdgesAroundVertex())	// this method should only be called when the shell array exists
    {
#ifndef NDEBUG
        sout << "Warning. [EdgeSetTopologyContainer::getEdgesAroundVertex] edge vertex shell array is empty." << sendl;
#endif
        createEdgesAroundVertexArray();
    }

#ifndef NDEBUG
    if(m_edgesAroundVertex.size() <= i)
        sout << "Error. [EdgeSetTopologyContainer::getEdgesAroundVertex] edge vertex shell array out of bounds: "
                << i << " >= " << m_edgesAroundVertex.size() << sendl;
#endif

    return m_edgesAroundVertex[i];
}

sofa::helper::vector< unsigned int > &EdgeSetTopologyContainer::getEdgesAroundVertexForModification(const unsigned int i)
{
    if(!hasEdgesAroundVertex())	// this method should only be called when the shell array exists
    {
#ifndef NDEBUG
        sout << "Warning. [EdgeSetTopologyContainer::getEdgesAroundVertexForModification] edge vertex shell array is empty." << sendl;
#endif
        createEdgesAroundVertexArray();
    }

    return m_edgesAroundVertex[i];
}

bool EdgeSetTopologyContainer::hasEdges() const
{
    d_edge.updateIfDirty();
    return !(d_edge.getValue()).empty();
}

bool EdgeSetTopologyContainer::hasEdgesAroundVertex() const
{
    return !m_edgesAroundVertex.empty();
}

void EdgeSetTopologyContainer::clearEdges()
{
    helper::WriteAccessor< Data< sofa::helper::vector<Edge> > > m_edge = d_edge;
    m_edge.clear();
}

void EdgeSetTopologyContainer::clearEdgesAroundVertex()
{
    m_edgesAroundVertex.clear();
}

void EdgeSetTopologyContainer::clear()
{
    clearEdges();
    clearEdgesAroundVertex();
	// Do not set to 0 the number of points as it prevents the  creation of topological items (edgeArray in tetrahedra for instance)
//    PointSetTopologyContainer::clear();
}

void EdgeSetTopologyContainer::updateTopologyEngineGraph()
{
    this->updateDataEngineGraph(this->d_edge, this->m_enginesList);

    // will concatenate with points one:
    PointSetTopologyContainer::updateTopologyEngineGraph();
}

} // namespace topology

} // namespace component

} // namespace sofa

max_stars_repo_name: sofa-framework/issofa

max_issues_repo_name: sofa-framework/issofa

max_forks_repo_name: sofa-framework/issofa


text:
#include <boost/test/unit_test.hpp>
#include <future>
#include <sstream>

#include "MockServer.h"
#include "SocketClient.h"
#include "Exceptions.h"
#include "DataReader.h"
#include "DataResender.h"
#include "testutil.h"
#include "DjsonLogItem.h"
#include "CounterCV.h"

using namespace EndpointLog;

BOOST_AUTO_TEST_SUITE(testsocket)

BOOST_AUTO_TEST_CASE(Test_SocketClient_Send)
{
    try {
        const std::string socketfile = "/tmp/nosuchfile";
        SocketClient client(socketfile, 1);

        client.Connect();

        const char* testData = "SocketClient test data";
        BOOST_CHECK_THROW(client.Send(testData), SocketException);
    }
    catch(const std::exception & ex) {
        BOOST_FAIL("Test exception " << ex.what());
    }
}

// Test Read():
// it should wait for the connection to be ready until timeout;
// when socket is not connected, it should throw SocketException
BOOST_AUTO_TEST_CASE(Test_SocketClient_Read)
{
    try {
        SocketClient sc("/tmp/nosuchfile", 1);
        char buf[64];

        const int timeoutMS = 10;
        auto startTime = std::chrono::steady_clock::now();
        BOOST_CHECK_THROW(sc.Read(buf, sizeof(buf), timeoutMS), SocketException);
        auto endTime = std::chrono::steady_clock::now();
        auto runTimeMS = static_cast<uint32_t>((endTime-startTime)/std::chrono::milliseconds(1));
        BOOST_CHECK_GE(runTimeMS, timeoutMS);
    }
    catch(const std::exception & ex) {
        BOOST_FAIL("Test exception " << ex.what());
    }
}

/// Test Send() when socket connection fails
/// - Send() should throw expected exception
/// - Send() should timeout at expected time
BOOST_AUTO_TEST_CASE(Test_SocketClient_Reconnect_Error)
{
    try {
        const std::string socketfile = "/tmp/nosuchfile";
        const int timeoutMS = 10;
        SocketClient client(socketfile, timeoutMS);

        const char* testData = "SocketClient test data";
        int ntimes = 4;
        for (int i = 0; i < ntimes; i++) {
            auto startTime = std::chrono::steady_clock::now();
            BOOST_CHECK_THROW(client.Send(testData), SocketException);
            auto endTime = std::chrono::steady_clock::now();
            auto runTimeMS = static_cast<uint32_t>((endTime-startTime)/std::chrono::milliseconds(1));

            BOOST_CHECK_MESSAGE((runTimeMS >= timeoutMS),
                "Iteration " << i << " timed out under " << timeoutMS << " (" << runTimeMS << ") ms");
        }

        BOOST_CHECK_LE(ntimes, client.GetNumReConnect());
    }
    catch(const std::exception & ex) {
        BOOST_FAIL("Test exception " << ex.what());
    }
}

static void
SendDataToServer(
    int nmsgs,
    size_t nbytes,
    bool insertNullChar,
    int32_t maxRunTimeMS
    )
{
    try {
        const std::string sockfile = TestUtil::GetCurrDir() + "/sockclient-bvt";
        auto mockServer = std::make_shared<TestUtil::MockServer>(sockfile, false);
        mockServer->Init();

        auto serverTask = std::async(std::launch::async, [mockServer]() {
            mockServer->Run();
            return mockServer->GetTotalBytesRead();
        });

        SocketClient client(sockfile, 1);

        char* buf = new char[nbytes];
        memset(buf, 'A', nbytes);

        if (insertNullChar && nbytes > 1) {
            buf[0] = '\0';
        }

        size_t totalSend = nbytes * nmsgs + TestUtil::EndOfTest().size();

        for (int i = 0; i < nmsgs; i++) {
            client.Send(buf, nbytes);
        }
        client.Send(TestUtil::EndOfTest().c_str());
        delete [] buf;

        bool mockServerDone = mockServer->WaitForTestsDone(maxRunTimeMS);
        BOOST_CHECK(mockServerDone);

        client.Stop();
        client.Close();
        mockServer->Stop();
        auto totalReceived = serverTask.get();

        BOOST_CHECK_EQUAL(totalSend, totalReceived);
    }
    catch(const std::exception & ex) {
        BOOST_FAIL("Test exception " << ex.what());
    }
}

BOOST_AUTO_TEST_CASE(Test_SocketClient_Msg_Empty)
{
    SendDataToServer(10, 0, false, 100);
}

BOOST_AUTO_TEST_CASE(Test_SocketClient_Msg_1)
{
    SendDataToServer(1, 16, false, 100);
}

BOOST_AUTO_TEST_CASE(Test_SocketClient_Msg_NullChar)
{
    SendDataToServer(10, 33, true, 100);
}

BOOST_AUTO_TEST_CASE(Test_SocketClient_Msg_1M)
{
    SendDataToServer(10, 1024*1024, false, 500);
}

// Failure handling tests:
// - when socket server is down, Send() should throw exception.
// - when socket server is up, continue Send() should succeed.
static void
TestSendRetry()
{
    // use std::promise to sync between server and client
    std::promise<void> masterReady;
    std::promise<void> threadReady;

    const std::string sockfile = TestUtil::GetCurrDir() + "/sockclient-retry";
    auto mockServer = std::make_shared<TestUtil::MockServer>(sockfile, false);

    auto serverTask = std::async(std::launch::async, [mockServer, &masterReady, &threadReady]() {
        threadReady.set_value();
        masterReady.get_future().wait();
        mockServer->Init();
        mockServer->Run();
        return mockServer->GetTotalBytesRead();
    });

    threadReady.get_future().wait();

    SocketClient client(sockfile, 10);

    const int nbytes = 30;
    const std::string testmsg = std::string(nbytes, 'A');
    size_t totalSend = nbytes + TestUtil::EndOfTest().size();

    // mockServer is not started yet. Send() should fail
    BOOST_CHECK_THROW(client.Send(testmsg.c_str()), SocketException);

    // start MockServer
    masterReady.set_value();

    for (int i = 0; i < 10; i++) {
        try {
            client.Send(testmsg.c_str());
        }
        catch(const SocketException& ex) {
            continue;
        }
        break;
    }

    client.Send(TestUtil::EndOfTest().c_str());

    bool mockServerDone = mockServer->WaitForTestsDone(100);
    BOOST_CHECK(mockServerDone);

    client.Stop();
    client.Close();
    mockServer->Stop();
    auto totalReceived = serverTask.get();

    BOOST_CHECK_EQUAL(totalSend, totalReceived);
}

BOOST_AUTO_TEST_CASE(Test_SocketClient_Send_Retry)
{
    try {
        TestSendRetry();
    }
    catch(const std::exception & ex) {
        BOOST_FAIL("Test failed with unexpected exception: " << ex.what());
    }
}

static void
DoSend(
    const std::shared_ptr<SocketClient>& sockClient,
    int senderIndex,
    int nmsgs,
    const std::string & testSource,
    const std::string & testData,
    const std::shared_ptr<CounterCV>& cv,
    std::promise<void>& thReady
    )
{
    CounterCVWrap cvwrap(cv);
    thReady.set_value();

    for (int i = 0; i < nmsgs; i++) {
        std::ostringstream strm;
        strm << testData << " " << senderIndex << "-" << i;
        DjsonLogItem item(testSource, strm.str());
        sockClient->Send(item.GetData());
    }
}

// Run Read() loop.
// When min number of bytes is read, signal minReadCV.
// Break the loop when either SocketClient is stopped, or
// Read() throws SocketException.
static void
DoRead(
    const std::shared_ptr<SocketClient>& sockClient,
    size_t minReadBytes,
    const std::shared_ptr<CounterCV>& cv,
    const std::shared_ptr<CounterCV>& minReadCV,
    std::promise<void>& thReady
    )
{
    CounterCVWrap cvwrap(cv);
    thReady.set_value();
    size_t totalRead = 0;

    while(true) {
        try {
            char buf[1024];
            auto rtn = sockClient->Read(buf, sizeof(buf));
            if (-1 == rtn) {
                BOOST_TEST_MESSAGE("SocketClient::Read() returned -1. Abort CV=" << cvwrap.GetId());
                break;
            }
            totalRead += rtn;
            if (totalRead >= minReadBytes) {
                minReadCV->notify_all();
            }
        }
        catch(const SocketException& ex) {
            BOOST_TEST_MESSAGE("SocketClient::Read() exception: " << ex.what() << ". Abort CV=" << cvwrap.GetId());
            break;
        }
    }
}

// Test multiple sender threads and multiple reader threads. Validate
// - no unexpected exception
// - data are received properly by the senders and readers.
static void
MultiSenderReaderTest(
    int nSenders,
    int nReaders,
    int nmsgs,
    size_t nbytesPerMsg
    )
{
    const std::string sockfile = TestUtil::GetCurrDir() + "/sockclient-mt";
    auto mockServer = std::make_shared<TestUtil::MockServer>(sockfile, true);
    mockServer->Init();

    auto serverTask = std::async(std::launch::async, [mockServer]() { mockServer->Run(); });

    auto sockClient = std::make_shared<SocketClient>(sockfile);

    const std::string testSource = "testSource";
    std::string testData = std::string(nbytesPerMsg, 'B');

    auto sendersCV = std::make_shared<CounterCV>(nSenders);
    auto readersCV = std::make_shared<CounterCV>(nReaders);

    // Make sure each reader reads at least N bytes before signaling CV
    auto minReadCV = std::make_shared<CounterCV>(nReaders);

    // use std::promise to make sure all threads are ready before
    // master thread moves ahead
    std::vector<std::promise<void>> thReadyList;
    thReadyList.reserve(nSenders+nReaders);
    for (int i = 0; i < nSenders+nReaders; i++) {
        thReadyList.push_back(std::promise<void>());
    }

    std::vector<std::future<void>> senderList;
    std::vector<std::future<void>> readerList;

    for (int n = 0; n < nSenders; n++) {
        auto senderT = std::async(std::launch::async, DoSend, sockClient, n,
            nmsgs, testSource, testData, sendersCV, std::ref(thReadyList[n]));
        senderList.push_back(std::move(senderT));
    }

    // Each ack msg sent from server to client should have at least 4 bytes
    auto minReadBytes = 4 * nmsgs;
    for (int i = 0; i < nReaders; i++) {
        auto readerT = std::async(std::launch::async, DoRead, sockClient,
            minReadBytes, readersCV, minReadCV, std::ref(thReadyList[i+nSenders]));
        readerList.push_back(std::move(readerT));
    }

    // wait for all threads to be ready
    for (auto & t : thReadyList) {
        t.get_future().wait();
    }

    // wait until all senders are finished
    // NOTE: the wait timeout should depend on nmsgs, and machine hardware.
    // Allocate enough time so tests can run on slow machines.
    auto timeoutMS = 500 + nmsgs * 5;
    BOOST_CHECK_MESSAGE(sendersCV->wait_for(timeoutMS),
        "Wait for sendersCV timed out (" << timeoutMS << " ms)");

    // send end of test and shutdown both client and server
    sockClient->Send(TestUtil::EndOfTest().c_str());
    auto msTimeoutMS = 500;
    BOOST_CHECK_MESSAGE(mockServer->WaitForTestsDone(msTimeoutMS),
        "Wait for mockServer tests to finish timed out (" << msTimeoutMS << " ms)");

    // wait for each reader to read at least minReadBytes bytes before calling Stop().
    BOOST_CHECK_MESSAGE(minReadCV->wait_for(msTimeoutMS),
        "Wait for minReadBytes timed out (" << msTimeoutMS << " ms)");

    sockClient->Stop();
    mockServer->Stop();

    // wait for mock server task to finish
    auto serverTaskTimeout = 100;
    BOOST_CHECK_MESSAGE(TestUtil::WaitForTask(serverTask, serverTaskTimeout),
        "Wait for serverTask timed out (" << serverTaskTimeout << " ms)");

    // wait for reader tasks to finish
    auto readersCVTimeout = 100;
    BOOST_CHECK_MESSAGE(readersCV->wait_for(readersCVTimeout),
        "Wait for readersCV timed out (" << readersCVTimeout << " ms)");

    sockClient->Close();

    // validate results

    // minimum data sent (actual data has extra info added to form valid DJSON msg)
    auto minClientSend = (testSource.size() + testData.size()) * nSenders * nmsgs;
    auto actualServerRecv = mockServer->GetTotalBytesRead();
    BOOST_CHECK_GT(actualServerRecv, minClientSend);
}

BOOST_AUTO_TEST_CASE(Test_SocketClient_1_Sender_Reader_1_msg)
{
    try {
        MultiSenderReaderTest(1, 1, 1, 10);
    }
    catch(const std::exception & ex) {
        BOOST_FAIL("Test failed with unexpected exception: " << ex.what());
    }
}

BOOST_AUTO_TEST_CASE(Test_SocketClient_1_Sender_Reader_10_msg)
{
    try {
        MultiSenderReaderTest(1, 1, 10, 10);
    }
    catch(const std::exception & ex) {
        BOOST_FAIL("Test failed with unexpected exception: " << ex.what());
    }
}

BOOST_AUTO_TEST_CASE(Test_SocketClient_N_Sender_Reader)
{
    try {
        MultiSenderReaderTest(6, 3, 1000, 1000);
    }
    catch(const std::exception & ex) {
        BOOST_FAIL("Test failed with unexpected exception: " << ex.what());
    }
}

BOOST_AUTO_TEST_SUITE_END()

ext: cc

max_stars_repo_name: panaji/fluentd-plugin-mdsd

max_issues_repo_name: panaji/fluentd-plugin-mdsd

max_forks_repo_name: panaji/fluentd-plugin-mdsd


text:
// Copyright (c) 2019 fortiss GmbH, Julian Bernhard, Klemens Esterle, Patrick Hart, Tobias Kessler
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.

#ifndef MODULES_GEOMETRY_COMMONS_HPP_
#define MODULES_GEOMETRY_COMMONS_HPP_

#include <Eigen/Core>
#include <string>
#include <vector>
#include <cmath>
#include <sstream>
#include <memory>
#include <iostream>
#include <algorithm>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>

namespace modules {
namespace geometry {

//! using boost geometry
namespace bg = boost::geometry;

//! points
template <typename T>
using Point2d_t = bg::model::point<T, 2, bg::cs::cartesian>;
using Point2d = Point2d_t<float>;

 //! Point operators
inline bool operator==(const Point2d& lhs, const Point2d& rhs) { return(bg::get<0>(lhs) == bg::get<0>(rhs) && bg::get<1>(lhs) == bg::get<1>(rhs)); }
inline bool operator!=(const Point2d& lhs, const Point2d& rhs) { return !(lhs == rhs); }
inline Point2d operator+(const Point2d& lhs, const Point2d& rhs) { return Point2d(bg::get<0>(lhs)+ bg::get<0>(rhs), bg::get<1>(lhs) + bg::get<1>(rhs)); }
inline Point2d operator+(const Point2d& lhs, const float& rhs) { return Point2d(bg::get<0>(lhs)+ rhs , bg::get<1>(lhs) + rhs); }

inline Point2d operator-(const Point2d& lhs, const Point2d& rhs) { return Point2d(bg::get<0>(lhs) - bg::get<0>(rhs), bg::get<1>(lhs) - bg::get<1>(rhs)); }
inline Point2d operator-(const Point2d& lhs, const float& rhs) { return Point2d(bg::get<0>(lhs)- rhs, bg::get<1>(lhs) + rhs); }

inline Point2d operator*(const Point2d& point, const float& factor) { return Point2d(bg::get<0>(point) * factor , bg::get<1>(point) * factor); }
inline Point2d operator/(const Point2d& point, const float& divisor) { return Point2d(bg::get<0>(point) / divisor , bg::get<1>(point) / divisor); }

using Pose = Eigen::Vector3d;

inline std::string print(const Point2d &p) {
  std::stringstream ss;
  ss << "Point2d: x: " << bg::get<0>(p) << ", y: " << bg::get<1>(p) << std::endl;
  return ss.str();
}

inline float distance(const Point2d &p1, const Point2d &p2) {
  float dx = bg::get<0>(p1) - bg::get<0>(p2);
  float dy = bg::get<1>(p1) - bg::get<1>(p2);
  return sqrt(dx * dx + dy * dy);
}

template <typename G, typename T>
struct Shape {
  Shape(const Pose &center, std::vector<T> points, int32_t id) : obj_(), id_(id), center_(center) {
    for (auto it = points.begin(); it != points.end(); ++it)
      add_point(*it);
  }

  Shape(const Pose &center, const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> &points, int32_t id) : obj_(), id_(id), center_(center) {
    auto row_num = points.rows();
    for (auto rowIter = 0; rowIter < row_num; ++rowIter) {
      // std::vector<T> vec = points.rows(rowIter);
      // for(auto col = 0;col<=1;++col){
      // Point2d_t<T> p = (points(rowIter,0),points(rowIter,1))
      add_point(T(points.coeff(rowIter, 0), points.coeff(rowIter, 1)));
      //}
    }
  }

  virtual ~Shape() {}
  virtual Shape *Clone() const = 0;
  virtual std::string ShapeToString() const;

  // rotates object
  Shape<G, T> *rotate(const float &a) const;

  // translates object
  Shape<G, T> *translate(const Point2d &point) const;

  // return object transform
  Shape<G, T> *transform(const Pose &pose) const;

  bool Valid();

  virtual Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> toArray() const = 0;

  bool add_point(const T &p) {
    bg::append(obj_, p);
    return true;
  }

  G obj_;
  int32_t id_;
  Pose center_;  // fixed center pose of shape
};

template <typename G, typename T>
inline bool Shape<G, T>::Valid() {
  std::string message;
  bool valid = boost::geometry::is_valid(obj_, message);
  if (!valid) {
    std::cout << "why not valid? " << message << std::endl;
  }
  return valid;
}

template <typename G, typename T>
inline Shape<G, T> *Shape<G, T>::rotate(const float &a) const {
  namespace trans = boost::geometry::strategy::transform;
  // move shape relative to coordinate center
  trans::translate_transformer<double, 2, 2> translate_rel_to_center(-center_[0], -center_[1]);
  G obj_rel_translated;
  boost::geometry::transform(obj_, obj_rel_translated, translate_rel_to_center);

  // rotate (counterclockwise)
  trans::rotate_transformer<boost::geometry::radian, double, 2, 2> rotate(-a);
  G obj_rotated;
  boost::geometry::transform(obj_rel_translated, obj_rotated, rotate);

  // move object backwards plus translation component
  trans::translate_transformer<double, 2, 2> translate_backwards(center_[0], center_[1]);
  G obj_transformed;
  boost::geometry::transform(obj_rotated, obj_transformed, translate_backwards);

  Shape<G, T> *shape_transformed = this->Clone();
  shape_transformed->obj_ = obj_transformed;
  shape_transformed->center_[2] += a;
  return shape_transformed;
}

template <typename G, typename T>
inline Shape<G, T> *Shape<G, T>::translate(const Point2d &point) const {
  namespace trans = boost::geometry::strategy::transform;
  trans::translate_transformer<double, 2, 2> translate_backwards(bg::get<0>(point), bg::get<1>(point));
  G obj_transformed;
  boost::geometry::transform(obj_, obj_transformed, translate_backwards);

  Shape<G, T> *shape_transformed = this->Clone();
  shape_transformed->obj_ = obj_transformed;
  shape_transformed->center_[0] += bg::get<0>(point);
  shape_transformed->center_[1] += bg::get<1>(point);
  return shape_transformed;
}

template <typename G, typename T>
inline Shape<G, T> *Shape<G, T>::transform(const Pose &pose) const {
  namespace trans = boost::geometry::strategy::transform;
  // move shape relative to coordinate center
  trans::translate_transformer<double, 2, 2> translate_rel_to_center(-center_[0], -center_[1]);
  G obj_rel_translated;
  boost::geometry::transform(obj_, obj_rel_translated, translate_rel_to_center);

  // rotate (counterclockwise)
  trans::rotate_transformer<boost::geometry::radian, double, 2, 2> rotate(-pose[2]);
  G obj_rotated;
  boost::geometry::transform(obj_rel_translated, obj_rotated, rotate);

  // move object backwards plus translation component
  trans::translate_transformer<double, 2, 2> translate_backwards(center_[0] + pose[0], center_[1] + pose[1]);
  G obj_transformed;
  boost::geometry::transform(obj_rotated, obj_transformed, translate_backwards);

  Shape<G, T> *shape_transformed = this->Clone();
  shape_transformed->obj_ = obj_transformed;
  shape_transformed->center_[0] += pose[0];
  shape_transformed->center_[1] += pose[1];
  shape_transformed->center_[2] += pose[2];
  return shape_transformed;
}

template <typename G, typename T>
inline std::string Shape<G, T>::ShapeToString() const {
  std::stringstream ss;
  Eigen::IOFormat OctaveFmt(Eigen::StreamPrecision, 0, ", ", ";\n", "", "", "[", "]");
  ss << toArray().format(OctaveFmt);
  return ss.str();
}

// template<typename G, typename T>
// inline bool Shape<G,T>::Collide(const G& shape1, const G& shape2)
//{
//  return Collide(shape1, shape2);
//}

}  // namespace geometry
}  // namespace modules

#endif  // MODULES_GEOMETRY_COMMONS_HPP_

ext: hpp

max_stars_repo_name: grzPat/bark

max_issues_repo_name: grzPat/bark

max_forks_repo_name: grzPat/bark


text:
#include <boost/config.hpp>

//
//  bind_function_ap_test.cpp - regression test
//
//  Copyright (c) 2015 Peter Dimov
//
//  Distributed under the Boost Software License, Version 1.0.
//  See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt
//

#if defined( BOOST_NO_AUTO_PTR )

int main()
{
}

#else

#if defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 406 )
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined( __clang__ ) && defined( __has_warning )
# if __has_warning( "-Wdeprecated-declarations" )
#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# endif
#endif

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <memory>

//

void fv1( std::auto_ptr<int> p1 )
{
    BOOST_TEST( *p1 == 1 );
}

void fv2( std::auto_ptr<int> p1, std::auto_ptr<int> p2 )
{
    BOOST_TEST( *p1 == 1 );
    BOOST_TEST( *p2 == 2 );
}

void fv3( std::auto_ptr<int> p1, std::auto_ptr<int> p2, std::auto_ptr<int> p3 )
{
    BOOST_TEST( *p1 == 1 );
    BOOST_TEST( *p2 == 2 );
    BOOST_TEST( *p3 == 3 );
}

void fv4( std::auto_ptr<int> p1, std::auto_ptr<int> p2, std::auto_ptr<int> p3, std::auto_ptr<int> p4 )
{
    BOOST_TEST( *p1 == 1 );
    BOOST_TEST( *p2 == 2 );
    BOOST_TEST( *p3 == 3 );
    BOOST_TEST( *p4 == 4 );
}

void fv5( std::auto_ptr<int> p1, std::auto_ptr<int> p2, std::auto_ptr<int> p3, std::auto_ptr<int> p4, std::auto_ptr<int> p5 )
{
    BOOST_TEST( *p1 == 1 );
    BOOST_TEST( *p2 == 2 );
    BOOST_TEST( *p3 == 3 );
    BOOST_TEST( *p4 == 4 );
    BOOST_TEST( *p5 == 5 );
}

void fv6( std::auto_ptr<int> p1, std::auto_ptr<int> p2, std::auto_ptr<int> p3, std::auto_ptr<int> p4, std::auto_ptr<int> p5, std::auto_ptr<int> p6 )
{
    BOOST_TEST( *p1 == 1 );
    BOOST_TEST( *p2 == 2 );
    BOOST_TEST( *p3 == 3 );
    BOOST_TEST( *p4 == 4 );
    BOOST_TEST( *p5 == 5 );
    BOOST_TEST( *p6 == 6 );
}

void fv7( std::auto_ptr<int> p1, std::auto_ptr<int> p2, std::auto_ptr<int> p3, std::auto_ptr<int> p4, std::auto_ptr<int> p5, std::auto_ptr<int> p6, std::auto_ptr<int> p7 )
{
    BOOST_TEST( *p1 == 1 );
    BOOST_TEST( *p2 == 2 );
    BOOST_TEST( *p3 == 3 );
    BOOST_TEST( *p4 == 4 );
    BOOST_TEST( *p5 == 5 );
    BOOST_TEST( *p6 == 6 );
    BOOST_TEST( *p7 == 7 );
}

void fv8( std::auto_ptr<int> p1, std::auto_ptr<int> p2, std::auto_ptr<int> p3, std::auto_ptr<int> p4, std::auto_ptr<int> p5, std::auto_ptr<int> p6, std::auto_ptr<int> p7, std::auto_ptr<int> p8 )
{
    BOOST_TEST( *p1 == 1 );
    BOOST_TEST( *p2 == 2 );
    BOOST_TEST( *p3 == 3 );
    BOOST_TEST( *p4 == 4 );
    BOOST_TEST( *p5 == 5 );
    BOOST_TEST( *p6 == 6 );
    BOOST_TEST( *p7 == 7 );
    BOOST_TEST( *p8 == 8 );
}

void fv9( std::auto_ptr<int> p1, std::auto_ptr<int> p2, std::auto_ptr<int> p3, std::auto_ptr<int> p4, std::auto_ptr<int> p5, std::auto_ptr<int> p6, std::auto_ptr<int> p7, std::auto_ptr<int> p8, std::auto_ptr<int> p9 )
{
    BOOST_TEST( *p1 == 1 );
    BOOST_TEST( *p2 == 2 );
    BOOST_TEST( *p3 == 3 );
    BOOST_TEST( *p4 == 4 );
    BOOST_TEST( *p5 == 5 );
    BOOST_TEST( *p6 == 6 );
    BOOST_TEST( *p7 == 7 );
    BOOST_TEST( *p8 == 8 );
    BOOST_TEST( *p9 == 9 );
}

void test()
{
    {
        boost::function<void(std::auto_ptr<int>)> fw1 = boost::bind( fv1, _1 );

        std::auto_ptr<int> p1( new int(1) );

        fw1( p1 );
    }

    {
        boost::function<void(std::auto_ptr<int>, std::auto_ptr<int>)> fw2 = boost::bind( fv2, _1, _2 );

        std::auto_ptr<int> p1( new int(1) );
        std::auto_ptr<int> p2( new int(2) );

        fw2( p1, p2 );
    }

    {
        boost::function<void(std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>)> fw3 = boost::bind( fv3, _1, _2, _3 );

        std::auto_ptr<int> p1( new int(1) );
        std::auto_ptr<int> p2( new int(2) );
        std::auto_ptr<int> p3( new int(3) );

        fw3( p1, p2, p3 );
    }

    {
        boost::function<void(std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>)> fw4 = boost::bind( fv4, _1, _2, _3, _4 );

        std::auto_ptr<int> p1( new int(1) );
        std::auto_ptr<int> p2( new int(2) );
        std::auto_ptr<int> p3( new int(3) );
        std::auto_ptr<int> p4( new int(4) );

        fw4( p1, p2, p3, p4 );
    }

    {
        boost::function<void(std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>)> fw5 = boost::bind( fv5, _1, _2, _3, _4, _5 );

        std::auto_ptr<int> p1( new int(1) );
        std::auto_ptr<int> p2( new int(2) );
        std::auto_ptr<int> p3( new int(3) );
        std::auto_ptr<int> p4( new int(4) );
        std::auto_ptr<int> p5( new int(5) );

        fw5( p1, p2, p3, p4, p5 );
    }

    {
        boost::function<void(std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>)> fw6 = boost::bind( fv6, _1, _2, _3, _4, _5, _6 );

        std::auto_ptr<int> p1( new int(1) );
        std::auto_ptr<int> p2( new int(2) );
        std::auto_ptr<int> p3( new int(3) );
        std::auto_ptr<int> p4( new int(4) );
        std::auto_ptr<int> p5( new int(5) );
        std::auto_ptr<int> p6( new int(6) );

        fw6( p1, p2, p3, p4, p5, p6 );
    }

    {
        boost::function<void(std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>)> fw7 = boost::bind( fv7, _1, _2, _3, _4, _5, _6, _7 );

        std::auto_ptr<int> p1( new int(1) );
        std::auto_ptr<int> p2( new int(2) );
        std::auto_ptr<int> p3( new int(3) );
        std::auto_ptr<int> p4( new int(4) );
        std::auto_ptr<int> p5( new int(5) );
        std::auto_ptr<int> p6( new int(6) );
        std::auto_ptr<int> p7( new int(7) );

        fw7( p1, p2, p3, p4, p5, p6, p7 );
    }

    {
        boost::function<void(std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>)> fw8 = boost::bind( fv8, _1, _2, _3, _4, _5, _6, _7, _8 );

        std::auto_ptr<int> p1( new int(1) );
        std::auto_ptr<int> p2( new int(2) );
        std::auto_ptr<int> p3( new int(3) );
        std::auto_ptr<int> p4( new int(4) );
        std::auto_ptr<int> p5( new int(5) );
        std::auto_ptr<int> p6( new int(6) );
        std::auto_ptr<int> p7( new int(7) );
        std::auto_ptr<int> p8( new int(8) );

        fw8( p1, p2, p3, p4, p5, p6, p7, p8 );
    }

    {
        boost::function<void(std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>, std::auto_ptr<int>)> fw9 = boost::bind( fv9, _1, _2, _3, _4, _5, _6, _7, _8, _9 );

        std::auto_ptr<int> p1( new int(1) );
        std::auto_ptr<int> p2( new int(2) );
        std::auto_ptr<int> p3( new int(3) );
        std::auto_ptr<int> p4( new int(4) );
        std::auto_ptr<int> p5( new int(5) );
        std::auto_ptr<int> p6( new int(6) );
        std::auto_ptr<int> p7( new int(7) );
        std::auto_ptr<int> p8( new int(8) );
        std::auto_ptr<int> p9( new int(9) );

        fw9( p1, p2, p3, p4, p5, p6, p7, p8, p9 );
    }
}

int main()
{
    test();
    return boost::report_errors();
}

#endif // #if defined( BOOST_NO_AUTO_PTR )

ext: cpp


text:
#include "blackhole/config/option.hpp"

#include <boost/optional/optional.hpp>

#include "blackhole/config/node.hpp"

namespace blackhole {
inline namespace v1 {
namespace config {

option<node_t>::option() noexcept = default;
option<node_t>::option(std::unique_ptr<node_t> node) noexcept :
    node(std::move(node))
{}

option<node_t>::operator bool() const noexcept {
    return node != nullptr;
}

auto option<node_t>::unwrap() const -> boost::optional<const node_t&> {
    return to([&]() -> boost::optional<const node_t&> {
        return *node;
    });
}

auto option<node_t>::to_bool() const -> boost::optional<bool> {
    return to([&]() -> boost::optional<bool> {
        return node->to_bool();
    });
}

auto option<node_t>::to_sint64() const -> boost::optional<std::int64_t> {
    return to([&]() -> boost::optional<std::int64_t> {
        return node->to_sint64();
    });
}

auto option<node_t>::to_uint64() const -> boost::optional<std::uint64_t> {
    return to([&]() -> boost::optional<std::uint64_t> {
        return node->to_uint64();
    });
}

auto option<node_t>::to_double() const -> boost::optional<double> {
    return to([&]() -> boost::optional<double> {
        return node->to_double();
    });
}

auto option<node_t>::to_string() const -> boost::optional<std::string> {
    return to([&]() -> boost::optional<std::string> {
        return node->to_string();
    });
}

auto option<node_t>::each(const each_function& fn) const -> void {
    if (node) {
        node->each(fn);
    }
}

auto option<node_t>::each_map(const member_function& fn) const -> void {
    if (node) {
        node->each_map(fn);
    }
}

auto option<node_t>::operator[](const std::size_t& idx) const -> option<node_t> {
    return to([&]() -> option<node_t> {
        return (*node)[idx];
    });
}

auto option<node_t>::operator[](const std::string& key) const -> option<node_t> {
    return to([&]() -> option<node_t> {
        return (*node)[key];
    });
}

template<typename F>
auto option<node_t>::to(F&& fn) const -> decltype(fn()) {
    if (node) {
        return fn();
    } else {
        return {};
    }
}

}  // namespace config
}  // namespace v1
}  // namespace blackhole

max_stars_repo_name: JakariaBlaine/blackhole

max_issues_repo_name: JakariaBlaine/blackhole

max_forks_repo_name: JakariaBlaine/blackhole


text:
// Copyright (C) 2014 The Regents of the University of California (Regents).
// 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 The Regents or University of California 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 HOLDERS 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.
//
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney (cmsweeney@cs.ucsb.edu)

#include <Eigen/Core>
#include <Eigen/Geometry>
#include <glog/logging.h>
#include <algorithm>
#include <vector>
#include "gtest/gtest.h"

#include "theia/alignment/alignment.h"
#include "theia/math/util.h"
#include "theia/sfm/pose/test_util.h"
#include "theia/sfm/transformation/gdls_similarity_transform.h"
#include "theia/util/random.h"
#include "theia/util/util.h"

namespace theia {
namespace {
using Eigen::AngleAxisd;
using Eigen::Map;
using Eigen::Matrix3d;
using Eigen::Quaterniond;
using Eigen::Vector3d;

RandomNumberGenerator rng(57);

void TestGdlsSimilarityTransformWithNoise(
    const std::vector<Vector3d>& camera_centers,
    const std::vector<Vector3d>& world_points,
    const double projection_noise_std_dev,
    const Quaterniond& expected_rotation,
    const Vector3d& expected_translation,
    const double expected_scale,
    const double max_reprojection_error,
    const double max_rotation_difference,
    const double max_translation_difference,
    const double max_scale_difference) {
  const int num_points = world_points.size();
  const int num_cameras = camera_centers.size();

  std::vector<Vector3d> camera_rays;
  std::vector<Vector3d> ray_origins;
  camera_rays.reserve(num_points);
  ray_origins.reserve(num_points);
  for (int i = 0; i < num_points; i++) {
    Vector3d ray_origin = (expected_rotation * camera_centers[i % num_cameras] +
                           expected_translation) / expected_scale;

    ray_origins.push_back(ray_origin);

    // Reproject 3D points into camera frame.
    camera_rays.push_back(
        (expected_rotation * world_points[i] + expected_translation -
         expected_scale * ray_origins[i]).normalized());
  }

  if (projection_noise_std_dev) {
    // Adds noise to both of the rays.
    for (int i = 0; i < num_points; i++) {
      AddNoiseToRay(projection_noise_std_dev, &rng, &camera_rays[i]);
    }
  }

  // Run DLS Similarity Transform.
  std::vector<Quaterniond> soln_rotation;
  std::vector<Vector3d> soln_translation;
  std::vector<double> soln_scale;
  GdlsSimilarityTransform(ray_origins, camera_rays, world_points,
                          &soln_rotation, &soln_translation, &soln_scale);

  // Check solutions and verify at least one is close to the actual solution.

  const int num_solutions = soln_rotation.size();
  EXPECT_GT(num_solutions, 0);
  bool matched_transform = false;
  for (int i = 0; i < num_solutions; i++) {
    // Check that reprojection errors are small.
    double max_reproj_err = 0.0;
    for (int j = 0; j < num_points; j++) {
      const Quaterniond unrot =
          Quaterniond::FromTwoVectors(camera_rays[j], Vector3d(0, 0, 1));
      const Vector3d reprojected_point =
          (soln_rotation[i] * world_points[j] + soln_translation[i]) /
              soln_scale[i] - ray_origins[j];

      const Vector3d unrot_cam_ray = unrot * camera_rays[j];
      const Vector3d unrot_reproj_pt = unrot * reprojected_point;

      const double reprojection_error =
          (unrot_cam_ray.hnormalized() - unrot_reproj_pt.hnormalized()).norm();
      if (reprojection_error > max_reproj_err)
        max_reproj_err = reprojection_error;
      EXPECT_LE(reprojection_error, max_reprojection_error)
          << "Reproj error is " << reprojection_error * 512.0;
    }

    // Check that the solution is accurate.
    const double rotation_difference =
        expected_rotation.angularDistance(soln_rotation[i]);
    const bool matched_rotation =
        (rotation_difference < max_rotation_difference);
    const double translation_difference =
        (expected_translation - soln_translation[i]).squaredNorm();
    const bool matched_translation =
        (translation_difference < max_translation_difference);
    const double scale_difference =
        fabs(expected_scale - soln_scale[i]) / expected_scale;
    const bool matched_scale = (scale_difference < max_scale_difference);

    if (matched_translation && matched_rotation && matched_scale) {
      matched_transform = true;
    }
  }
  EXPECT_TRUE(matched_transform);
}

void BasicTest() {
  const std::vector<Vector3d> points_3d = { Vector3d(-1.0, 3.0, 3.0),
                                            Vector3d(1.0, -1.0, 2.0),
                                            Vector3d(-1.0, 1.0, 2.0),
                                            Vector3d(2.0, 1.0, 3.0) };
  const Quaterniond soln_rotation = Quaterniond(
      AngleAxisd(DegToRad(13.0), Vector3d(0.0, 0.0, 1.0)));
  const Vector3d soln_translation(1.0, 1.0, 1.0);
  const double soln_scale = 2.5;
  const double kNoise = 0.0;
  const double kMaxReprojectionError = 1.0 / 512.0;
  const double kMaxAllowedRotationDifference = DegToRad(1e-4);
  const double kMaxAllowedTranslationDifference = 1e-6;
  const double kMaxAllowedScaleDifference = 1e-6;

  const std::vector<Vector3d> kImageOrigins = { Vector3d(-1.0, 0.0, 0.0),
                                                Vector3d(0.0, 0.0, 0.0),
                                                Vector3d(2.0, 0.0, 0.0),
                                                Vector3d(3.0, 0.0, 0.0) };

  TestGdlsSimilarityTransformWithNoise(
      kImageOrigins,
      points_3d,
      kNoise,
      soln_rotation,
      soln_translation,
      soln_scale,
      kMaxReprojectionError,
      kMaxAllowedRotationDifference,
      kMaxAllowedTranslationDifference,
      kMaxAllowedScaleDifference);
}

TEST(GdlsSimilarityTransform, Basic) {
  BasicTest();
}

TEST(GdlsSimilarityTransform, NoiseTest) {
  const std::vector<Vector3d> points_3d = { Vector3d(-1.0, 3.0, 3.0),
                                            Vector3d(1.0, -1.0, 2.0),
                                            Vector3d(-1.0, 1.0, 2.0),
                                            Vector3d(2.0, 1.0, 3.0),
                                            Vector3d(-1.0, -3.0, 2.0),
                                            Vector3d(1.0, -2.0, 1.0),
                                            Vector3d(-1.0, 4.0, 2.0),
                                            Vector3d(-2.0, 2.0, 3.0)
  };
  const std::vector<Vector3d> kImageOrigins = { Vector3d(0.0, 1.0, 0.0),
                                                Vector3d(0.0, 0.0, 0.0),
                                                Vector3d(0.0, 2.0, 0.0),
                                                Vector3d(0.0, 3.0, 0.0) };

  const Quaterniond soln_rotation = Quaterniond(
      AngleAxisd(DegToRad(13.0), Vector3d(0.0, 0.0, 1.0)));
  const Vector3d soln_translation(1.0, 1.0, 1.0);
  const double soln_scale = 2.5;
  const double kNoise = 1.0 / 512.0;
  const double kMaxReprojectionError = 5.0 / 512.0;
  const double kMaxAllowedRotationDifference = DegToRad(1.0);
  const double kMaxAllowedTranslationDifference = 1e-3;
  const double kMaxAllowedScaleDifference = 1e-2;

  TestGdlsSimilarityTransformWithNoise(
      kImageOrigins,
      points_3d,
      kNoise,
      soln_rotation,
      soln_translation,
      soln_scale,
      kMaxReprojectionError,
      kMaxAllowedRotationDifference,
      kMaxAllowedTranslationDifference,
      kMaxAllowedScaleDifference);
}

TEST(GdlsSimilarityTransform, ManyPoints) {
  // Sets some test rotations and translations.
  static const Vector3d kAxes[] = {
    Vector3d(0.0, 0.0, 1.0).normalized(),
    Vector3d(0.0, 1.0, 0.0).normalized(),
    Vector3d(1.0, 0.0, 0.0).normalized(),
    Vector3d(1.0, 0.0, 1.0).normalized(),
    Vector3d(0.0, 1.0, 1.0).normalized(),
    Vector3d(1.0, 1.0, 1.0).normalized(),
    Vector3d(0.0, 1.0, 1.0).normalized(),
    Vector3d(1.0, 1.0, 1.0).normalized()
  };

  static const double kRotationAngles[THEIA_ARRAYSIZE(kAxes)] = {
    DegToRad(7.0),
    DegToRad(12.0),
    DegToRad(15.0),
    DegToRad(20.0),
    DegToRad(11.0),
    DegToRad(0.0),  // Tests no rotation.
    DegToRad(5.0),
    DegToRad(0.0)  // Tests no rotation and no translation.
  };

  static const Vector3d kTranslations[THEIA_ARRAYSIZE(kAxes)] = {
    Vector3d(1.0, 1.0, 1.0),
    Vector3d(3.0, 2.0, 13.0),
    Vector3d(4.0, 5.0, 11.0),
    Vector3d(1.0, 2.0, 15.0),
    Vector3d(3.0, 1.5, 18.0),
    Vector3d(1.0, 7.0, 11.0),
    Vector3d(0.0, 0.0, 0.0),  // Tests no translation.
    Vector3d(0.0, 0.0, 0.0)  // Tests no translation and no rotation.
  };

  static const double kScales[THEIA_ARRAYSIZE(kAxes)] = {
    0.33,
    1.0,
    4.2,
    10.13,
    3.14,
    7.22,
    0.1,
    10.0
  };

  const std::vector<Vector3d> kImageOrigins = { Vector3d(-1.0, 0.0, 0.0),
                                                Vector3d(0.0, 0.0, 0.0),
                                                Vector3d(2.0, 0.0, 0.0),
                                                Vector3d(3.0, 0.0, 0.0) };

  static const int num_points[3] = { 100, 500, 1000 };
  const double kNoise = 0.5 / 512.0;
  const double kMaxReprojectionError = 10.0 / 512.0;
  const double kMaxAllowedRotationDifference = DegToRad(0.3);
  const double kMaxAllowedTranslationDifference = 1e-3;
  const double kMaxAllowedScaleDifference = 1e-2;

  for (int i = 0; i < THEIA_ARRAYSIZE(kAxes); i++) {
    const Quaterniond soln_rotation(AngleAxisd(kRotationAngles[i], kAxes[i]));
    for (int j = 0; j < THEIA_ARRAYSIZE(num_points); j++) {
      std::vector<Vector3d> points_3d;
      points_3d.reserve(num_points[j]);
      for (int k = 0; k < num_points[j]; k++) {
        points_3d.push_back(Vector3d(rng.RandDouble(-5.0, 5.0),
                                     rng.RandDouble(-5.0, 5.0),
                                     rng.RandDouble(2.0, 10.0)));
      }

      TestGdlsSimilarityTransformWithNoise(
          kImageOrigins,
          points_3d,
          kNoise,
          soln_rotation,
          kTranslations[i],
          kScales[i],
          kMaxReprojectionError,
          kMaxAllowedRotationDifference,
          kMaxAllowedTranslationDifference,
          kMaxAllowedScaleDifference);
    }
  }
}

TEST(GdlsSimilarityTransform, NoRotation) {
  const std::vector<Vector3d> points_3d = { Vector3d(-1.0, 3.0, 3.0),
                                            Vector3d(1.0, -1.0, 2.0),
                                            Vector3d(-1.0, 1.0, 2.0),
                                            Vector3d(2.0, 1.0, 3.0),
                                            Vector3d(-1.0, -3.0, 2.0),
                                            Vector3d(1.0, -2.0, 1.0),
                                            Vector3d(-1.0, 4.0, 2.0),
                                            Vector3d(-2.0, 2.0, 3.0)
  };
  const std::vector<Vector3d> kImageOrigins = { Vector3d(-1.0, 0.0, 0.0),
                                                Vector3d(0.0, 0.0, 0.0),
                                                Vector3d(2.0, 0.0, 0.0),
                                                Vector3d(3.0, 0.0, 0.0) };

  const Quaterniond soln_rotation = Quaterniond(
      AngleAxisd(DegToRad(0.0), Vector3d(0.0, 0.0, 1.0)));
  const Vector3d soln_translation(1.0, 1.0, 1.0);
  const double soln_scale = 0.77;
  const double kNoise = 0.5 / 512.0;
  const double kMaxReprojectionError = 2.0 / 5.0;
  const double kMaxAllowedRotationDifference = DegToRad(0.2);
  const double kMaxAllowedTranslationDifference = 5e-4;
  const double kMaxAllowedScaleDifference = 1e-2;

  TestGdlsSimilarityTransformWithNoise(
      kImageOrigins,
      points_3d,
      kNoise,
      soln_rotation,
      soln_translation,
      soln_scale,
      kMaxReprojectionError,
      kMaxAllowedRotationDifference,
      kMaxAllowedTranslationDifference,
      kMaxAllowedScaleDifference);
}

TEST(GdlsSimilarityTransform, NoTranslation) {
  const std::vector<Vector3d> points_3d = { Vector3d(-1.0, 3.0, 3.0),
                                            Vector3d(1.0, -1.0, 2.0),
                                            Vector3d(-1.0, 1.0, 2.0),
                                            Vector3d(2.0, 1.0, 3.0),
                                            Vector3d(-1.0, -3.0, 2.0),
                                            Vector3d(1.0, -2.0, 1.0),
                                            Vector3d(-1.0, 4.0, 2.0),
                                            Vector3d(-2.0, 2.0, 3.0)
  };
  const std::vector<Vector3d> kImageOrigins = { Vector3d(-1.0, 0.0, 0.0),
                                                Vector3d(0.0, 0.0, 0.0),
                                                Vector3d(2.0, 0.0, 0.0),
                                                Vector3d(3.0, 0.0, 0.0) };

  const Quaterniond soln_rotation = Quaterniond(
      AngleAxisd(DegToRad(13.0), Vector3d(0.0, 0.0, 1.0)));
  const Vector3d soln_translation(0.0, 0.0, 0.0);
  const double soln_scale = 2.5;
  const double kNoise = 1.0 / 512.0;
  const double kMaxReprojectionError = 4.0 / 512.0;
  const double kMaxAllowedRotationDifference = DegToRad(0.5);
  const double kMaxAllowedTranslationDifference = 1e-3;
  const double kMaxAllowedScaleDifference = 1e-2;

  TestGdlsSimilarityTransformWithNoise(
      kImageOrigins,
      points_3d,
      kNoise,
      soln_rotation,
      soln_translation,
      soln_scale,
      kMaxReprojectionError,
      kMaxAllowedRotationDifference,
      kMaxAllowedTranslationDifference,
      kMaxAllowedScaleDifference);
}

}  // namespace
}  // namespace theia

max_stars_repo_name: maxchernet/TheiaSfM

max_issues_repo_name: maxchernet/TheiaSfM

max_forks_repo_name: maxchernet/TheiaSfM


text:
/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include "topojson_datasource.hpp"
#include "topojson_featureset.hpp"

#include <fstream>
#include <algorithm>

// boost
#include <boost/algorithm/string.hpp>

// mapnik
#include <mapnik/unicode.hpp>
#include <mapnik/value_types.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/geometry_adapters.hpp>
#include <mapnik/json/topojson_grammar.hpp>
#include <mapnik/json/topojson_utils.hpp>
#include <mapnik/util/variant.hpp>
#include <mapnik/util/file_io.hpp>
#include <mapnik/make_unique.hpp>

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(topojson_datasource)

struct attr_value_converter
{
    mapnik::eAttributeType operator() (mapnik::value_integer /*val*/) const
    {
        return mapnik::Integer;
    }

    mapnik::eAttributeType operator() (double /*val*/) const
    {
        return mapnik::Double;
    }

    mapnik::eAttributeType operator() (float /*val*/) const
    {
        return mapnik::Double;
    }

    mapnik::eAttributeType operator() (bool /*val*/) const
    {
        return mapnik::Boolean;
    }
    // string, object, array
    template <typename T>
    mapnik::eAttributeType operator() (T const& /*val*/) const
    {
        return mapnik::String;
    }
};

struct geometry_type_visitor
{
    int operator() (mapnik::topojson::point const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Point);
    }
    int operator() (mapnik::topojson::multi_point const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Point);
    }
    int operator() (mapnik::topojson::linestring const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::LineString);
    }
    int operator() (mapnik::topojson::multi_linestring const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::LineString);
    }
    int operator() (mapnik::topojson::polygon const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Polygon);
    }
    int operator() (mapnik::topojson::multi_polygon const&) const
    {
        return static_cast<int>(mapnik::datasource_geometry_t::Polygon);
    }
    template <typename T>
    int operator() (T const& ) const
    {
        return 0;
    }
};

struct collect_attributes_visitor
{
    mapnik::layer_descriptor & desc_;
    collect_attributes_visitor(mapnik::layer_descriptor & desc):
      desc_(desc) {}

    // no-op
    void operator() (mapnik::topojson::empty) {}
    //
    template <typename GeomType>
    void operator() (GeomType const& g)
    {
        if (g.props)
        {
            for (auto const& p : *g.props)
            {
                desc_.add_descriptor(mapnik::attribute_descriptor(std::get<0>(p),
                                                                  mapnik::util::apply_visitor(attr_value_converter(),
                                                                                std::get<1>(p))));
            }
        }
    }
};

topojson_datasource::topojson_datasource(parameters const& params)
  : datasource(params),
    type_(datasource::Vector),
    desc_(topojson_datasource::name(),
          *params.get<std::string>("encoding","utf-8")),
    filename_(),
    inline_string_(),
    extent_(),
    tr_(new mapnik::transcoder(*params.get<std::string>("encoding","utf-8"))),
    tree_(nullptr)
{
    boost::optional<std::string> inline_string = params.get<std::string>("inline");
    if (inline_string)
    {
        inline_string_ = *inline_string;
    }
    else
    {
        boost::optional<std::string> file = params.get<std::string>("file");
        if (!file) throw mapnik::datasource_exception("TopoJSON Plugin: missing <file> parameter");

        boost::optional<std::string> base = params.get<std::string>("base");
        if (base)
            filename_ = *base + "/" + *file;
        else
            filename_ = *file;
    }
    if (!inline_string_.empty())
    {
        parse_topojson(inline_string_.c_str());
    }
    else
    {
        mapnik::util::file file(filename_);
        if (!file)
        {
            throw mapnik::datasource_exception("TopoJSON Plugin: could not open: '" + filename_ + "'");
        }
        std::string file_buffer;
        file_buffer.resize(file.size());
        std::fread(&file_buffer[0], file.size(), 1, file.get());
        parse_topojson(file_buffer.c_str());
    }
}

namespace {
using iterator_type = const char*;
const mapnik::topojson::topojson_grammar<iterator_type> g;
}

template <typename T>
void topojson_datasource::parse_topojson(T const& buffer)
{
    boost::spirit::standard::space_type space;
    auto itr = buffer;
    auto end = buffer + std::strlen(buffer);
    bool result = boost::spirit::qi::phrase_parse(itr, end, g, space, topo_);
    if (!result)
    {
        throw mapnik::datasource_exception("topojson_datasource: Failed parse TopoJSON file '" + filename_ + "'");
    }

    using values_container = std::vector< std::pair<box_type, std::size_t> >;
    values_container values;
    values.reserve(topo_.geometries.size());

    std::size_t geometry_index = 0;
    bool first = true;
    for (auto const& geom : topo_.geometries)
    {
        mapnik::box2d<double> box = mapnik::util::apply_visitor(mapnik::topojson::bounding_box_visitor(topo_), geom);
        if (box.valid())
        {
            if (first)
            {
                first = false;
                extent_ = box;
                collect_attributes_visitor assessor(desc_);
                mapnik::util::apply_visitor( std::ref(assessor), geom);
            }
            else
            {
                extent_.expand_to_include(box);
            }
            values.emplace_back(box, geometry_index);
        }
        ++geometry_index;
    }

    // packing algorithm
    tree_ = std::make_unique<spatial_index_type>(values);
}

topojson_datasource::~topojson_datasource() { }

const char * topojson_datasource::name()
{
    return "topojson";
}

boost::optional<mapnik::datasource_geometry_t> topojson_datasource::get_geometry_type() const
{
    boost::optional<mapnik::datasource_geometry_t> result;
    int multi_type = 0;
    std::size_t num_features = topo_.geometries.size();
    for (std::size_t i = 0; i < num_features && i < 5; ++i)
    {
        mapnik::topojson::geometry const& geom = topo_.geometries[i];
        int type = mapnik::util::apply_visitor(geometry_type_visitor(),geom);
        if (type > 0)
        {
            if (multi_type > 0 && multi_type != type)
            {
                result.reset(mapnik::datasource_geometry_t::Collection);
                return result;
            }
            else
            {
                result.reset(static_cast<mapnik::datasource_geometry_t>(type));
            }
            multi_type = type;
        }
    }
    return result;
}

mapnik::datasource::datasource_t topojson_datasource::type() const
{
    return type_;
}

mapnik::box2d<double> topojson_datasource::envelope() const
{
    return extent_;
}

mapnik::layer_descriptor topojson_datasource::get_descriptor() const
{
    return desc_;
}

mapnik::featureset_ptr topojson_datasource::features(mapnik::query const& q) const
{
    // if the query box intersects our world extent then query for features
    mapnik::box2d<double> const& box = q.get_bbox();
    if (extent_.intersects(box))
    {
        topojson_featureset::array_type index_array;
        if (tree_)
        {
            tree_->query(boost::geometry::index::intersects(box),std::back_inserter(index_array));
            return std::make_shared<topojson_featureset>(topo_, *tr_, std::move(index_array));
        }
    }
    // otherwise return an empty featureset pointer
    return mapnik::make_invalid_featureset();
}

mapnik::featureset_ptr topojson_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const
{
    mapnik::box2d<double> query_bbox(pt, pt);
    query_bbox.pad(tol);
    mapnik::query q(query_bbox);
    for (auto const& attr_info : desc_.get_descriptors())
    {
        q.add_property_name(attr_info.get_name());
    }
    return features(q);
}


text:
#ifndef MPLLIBS_METAMONAD_V1_FWD_IS_TAG_HPP
#define MPLLIBS_METAMONAD_V1_FWD_IS_TAG_HPP

// Copyright Abel Sinkovics (abel@sinkovics.hu)  2013.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

// For boost::mpl::na
#include <boost/mpl/vector.hpp>

namespace mpllibs
{
  namespace metamonad
  {
    namespace v1
    {
      template <class T, class E = boost::mpl::na>
      struct is_tag;
    }
  }
}

#endif


text:
/// @file
/// @author rfree (current maintainer in monero.cc project)
/// @brief implementaion for throttling of connection (count and rate-limit speed etc)

// Copyright (c) 2014-2017, The Monero Project;Copyright (c) 2017-2018,The Wukong Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
//    conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.

/* rfree: implementation for throttle details */

#include <boost/asio.hpp>
#include <string>
#include <vector>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <atomic>

#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/thread/thread.hpp>

#include <memory>

#include "syncobj.h"

#include "net/net_utils_base.h"
#include "misc_log_ex.h"
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/uuid/random_generator.hpp>
#include <boost/chrono.hpp>
#include <boost/utility/value_init.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>
#include "misc_language.h"
#include "pragma_comp_defs.h"
#include <sstream>
#include <iomanip>
#include <algorithm>

#include <boost/asio/basic_socket.hpp>
#include <boost/asio/ip/unicast.hpp>
#include "net/abstract_tcp_server2.h"

// TODO:
#include "net/network_throttle-detail.hpp"

#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net.throttle"

// ################################################################################################
// ################################################################################################
// the "header part". Not separeted out for .hpp because point of this modification is
// to rebuild just 1 translation unit while working on this code.
// (But maybe common parts will be separated out later though - if needed)
// ################################################################################################
// ################################################################################################

namespace epee
{
namespace net_utils
{

/* ============================================================================ */

class connection_basic_pimpl {
	public:
		connection_basic_pimpl(const std::string &name);

		static int m_default_tos;

		network_throttle_bw m_throttle; // per-perr
    critical_section m_throttle_lock;

		void _packet(size_t packet_size, int phase, int q_len); // execute a sleep ; phase is not really used now(?) could be used for different kinds of sleep e.g. direct/queue write
};

} // namespace
} // namespace

// ################################################################################################
// ################################################################################################
// The implementation part
// ################################################################################################
// ################################################################################################

namespace epee
{
namespace net_utils
{

// ================================================================================================
// network_throttle
// ================================================================================================

network_throttle::~network_throttle() { }

network_throttle::packet_info::packet_info()
	: m_size(0)
{
}

network_throttle::network_throttle(const std::string &nameshort, const std::string &name, int window_size)
    : m_window_size( (window_size==-1) ? 10 : window_size  ),
	  m_history( m_window_size ), m_nameshort(nameshort)
{
	set_name(name);
	m_network_add_cost = 128;
	m_network_minimal_segment = 256;
	m_network_max_segment = 1024*1024;
	m_any_packet_yet = false;
	m_slot_size = 1.0; // hard coded in few places
	m_target_speed = 16 * 1024; // other defaults are probably defined in the command-line parsing code when this class is used e.g. as main global throttle
}

void network_throttle::set_name(const std::string &name)
{
	m_name = name;
}

void network_throttle::set_target_speed( network_speed_kbps target )
{
    m_target_speed = target * 1024;
	MINFO("Setting LIMIT: " << target << " kbps");
}

network_speed_kbps network_throttle::get_target_speed()
{
	return m_target_speed / 1024;
}

void network_throttle::tick()
{
	double time_now = get_time_seconds();
	if (!m_any_packet_yet) m_start_time = time_now; // starting now

	network_time_seconds current_sample_time_slot = time_to_slot( time_now ); // T=13.7 --> 13  (for 1-second smallwindow)
	network_time_seconds last_sample_time_slot = time_to_slot( m_last_sample_time );

	// moving to next position, and filling gaps
	// !! during this loop the m_last_sample_time and last_sample_time_slot mean the variable moved in +1
	// TODO optimize when moving few slots at once
	while ( (!m_any_packet_yet) || (last_sample_time_slot < current_sample_time_slot))
	{
		_dbg3("Moving counter buffer by 1 second " << last_sample_time_slot << " < " << current_sample_time_slot << " (last time " << m_last_sample_time<<")");
		// rotate buffer
		for (size_t i=m_history.size()-1; i>=1; --i) m_history[i] = m_history[i-1];
		m_history[0] = packet_info();
		if (! m_any_packet_yet)
		{
			m_last_sample_time = time_now;
		}
		m_last_sample_time += 1;	last_sample_time_slot = time_to_slot( m_last_sample_time ); // increase and recalculate time, time slot
		m_any_packet_yet=true;
	}
	m_last_sample_time = time_now; // the real exact last time
}

void network_throttle::handle_trafic_exact(size_t packet_size)
{
	_handle_trafic_exact(packet_size, packet_size);
}

void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_size)
{
	tick();

	calculate_times_struct cts ;  calculate_times(packet_size, cts , false, -1);
	calculate_times_struct cts2;  calculate_times(packet_size, cts2, false, 5);
	m_history[0].m_size += packet_size;

	std::ostringstream oss; oss << "["; 	for (auto sample: m_history) oss << sample.m_size << " ";	 oss << "]" << std::ends;
	std::string history_str = oss.str();

	MTRACE("Throttle " << m_name << ": packet of ~"<<packet_size<<"b " << " (from "<<orginal_size<<" b)"
        << " Speed AVG=" << std::setw(4) <<  ((long int)(cts .average/1024)) <<"[w="<<cts .window<<"]"
        <<           " " << std::setw(4) <<  ((long int)(cts2.average/1024)) <<"[w="<<cts2.window<<"]"
				<<" / " << " Limit="<< ((long int)(m_target_speed/1024)) <<" KiB/sec "
				<< " " << history_str
		);
}

void network_throttle::handle_trafic_tcp(size_t packet_size)
{
	size_t all_size = packet_size + m_network_add_cost;
	all_size = std::max( m_network_minimal_segment , all_size);
	_handle_trafic_exact( all_size , packet_size );
}

network_time_seconds network_throttle::get_sleep_time_after_tick(size_t packet_size) {
	tick();
	return get_sleep_time(packet_size);
}

void network_throttle::logger_handle_net(const std::string &filename, double time, size_t size) {
    static boost::mutex mutex;

    boost::lock_guard<boost::mutex> lock(mutex);
    {
        std::fstream file;
        file.open(filename.c_str(), std::ios::app | std::ios::out );
        file.precision(6);
        if(!file.is_open())
            _warn("Can't open file " << filename);
        file << static_cast<int>(time) << " " << static_cast<double>(size/1024) << "\n";
        file.close();
    }
}

// fine tune this to decide about sending speed:
network_time_seconds network_throttle::get_sleep_time(size_t packet_size) const
{
	double D2=0;
	calculate_times_struct cts = { 0, 0, 0, 0};
	calculate_times(packet_size, cts, true, m_window_size); D2=cts.delay;
	return D2;
}

// MAIN LOGIC:
void network_throttle::calculate_times(size_t packet_size, calculate_times_struct &cts, bool dbg, double force_window) const
{
    const double the_window_size = std::max( (double)m_window_size ,
		((force_window>0) ? force_window : m_window_size)
	);

	if (!m_any_packet_yet) {
		cts.window=0; cts.average=0; cts.delay=0;
		cts.recomendetDataSize = m_network_minimal_segment; // should be overrided by caller anyway
		return ; // no packet yet, I can not decide about sleep time
	}

	network_time_seconds window_len = (the_window_size-1) * m_slot_size ; // -1 since current slot is not finished
	window_len += (m_last_sample_time - time_to_slot(m_last_sample_time));  // add the time for current slot e.g. 13.7-13 = 0.7

	auto time_passed = get_time_seconds() - m_start_time;
	cts.window = std::max( std::min( window_len , time_passed ) , m_slot_size )  ; // window length resulting from size of history but limited by how long ago history was started,
	// also at least slot size (e.g. 1 second) to not be ridiculous
	// window_len e.g. 5.7 because takes into account current slot time

	size_t Epast = 0; // summ of traffic till now
	for (auto sample : m_history) Epast += sample.m_size;

	const size_t E = Epast;
	const size_t Enow = Epast + packet_size ; // including the data we're about to send now

	const double M = m_target_speed; // max
	const double D1 = (Epast - M*cts.window) / M; // delay - how long to sleep to get back to target speed
	const double D2 = (Enow  - M*cts.window) / M; // delay - how long to sleep to get back to target speed (including current packet)

    cts.delay = (D1*0.80 + D2*0.20); // finall sleep depends on both with/without current packet
	//				update_overheat();
	cts.average = Epast/cts.window; // current avg. speed (for info)

	if (Epast <= 0) {
		if (cts.delay>=0) cts.delay = 0; // no traffic in history so we will not wait
	}

    double Wgood=-1;
    {	// how much data we recommend now to download
        Wgood = the_window_size + 1;
        cts.recomendetDataSize = M*cts.window - E;
    }

	if (dbg) {
		std::ostringstream oss; oss << "["; 	for (auto sample: m_history) oss << sample.m_size << " ";	 oss << "]" << std::ends;
		std::string history_str = oss.str();
		MTRACE((cts.delay > 0 ? "SLEEP" : "")
			<< "dbg " << m_name << ": "
			<< "speed is A=" << std::setw(8) <<cts.average<<" vs "
			<< "Max=" << std::setw(8) <<M<<" "
			<< " so sleep: "
			<< "D=" << std::setw(8) <<cts.delay<<" sec "
			<< "E="<< std::setw(8) << E << " (Enow="<<std::setw(8)<<Enow<<") "
            << "M=" << std::setw(8) << M <<" W="<< std::setw(8) << cts.window << " "
            << "R=" << std::setw(8) << cts.recomendetDataSize << " Wgood" << std::setw(8) << Wgood << " "
			<< "History: " << std::setw(8) << history_str << " "
			<< "m_last_sample_time=" << std::setw(8) << m_last_sample_time
		);

	}
}

double network_throttle::get_time_seconds() const {
	#if defined(__APPLE__)
	auto point = std::chrono::system_clock::now();
	#else
	auto point = std::chrono::steady_clock::now();
	#endif
	auto time_from_epoh = point.time_since_epoch();
	auto ms = std::chrono::duration_cast< std::chrono::milliseconds >( time_from_epoh ).count();
	double ms_f = ms;
	return ms_f / 1000.;
}

size_t network_throttle::get_recommended_size_of_planned_transport_window(double force_window) const {
	calculate_times_struct cts = { 0, 0, 0, 0};
	network_throttle::calculate_times(0, cts, true, force_window);
	cts.recomendetDataSize += m_network_add_cost;
	if (cts.recomendetDataSize<0) cts.recomendetDataSize=0;
	if (cts.recomendetDataSize>m_network_max_segment) cts.recomendetDataSize=m_network_max_segment;
	size_t RI = (long int)cts.recomendetDataSize;
	return RI;
}

size_t network_throttle::get_recommended_size_of_planned_transport() const {
	size_t R1=0,R2=0,R3=0;
	R1 = get_recommended_size_of_planned_transport_window( -1 );
	R2 = get_recommended_size_of_planned_transport_window(m_window_size / 2);
	R3 = get_recommended_size_of_planned_transport_window( 5              );
	auto RM = std::min(R1, std::min(R2,R3));

	const double a1=20, a2=10, a3=10, am=10; // weight of the various windows in decisssion // TODO 70 => 20
	return (R1*a1 + R2*a2 + R3*a3 + RM*am) / (a1+a2+a3+am);
}

double network_throttle::get_current_speed() const {
	unsigned int bytes_transferred = 0;
	if (m_history.size() == 0 || m_slot_size == 0)
		return 0;

	auto it = m_history.begin();
	while (it < m_history.end() - 1)
	{
		bytes_transferred += it->m_size;
		it ++;
	}

	return bytes_transferred / ((m_history.size() - 1) * m_slot_size);
}

} // namespace
} // namespace

max_stars_repo_name: WukongCoin/wukongcoin

max_issues_repo_name: WukongCoin/wukongcoin

max_forks_repo_name: WukongCoin/wukongcoin


text:
#ifndef YANNQ_SUPERVISED_OVERLAPOPTIMIZEREXACT_HPP
#define YANNQ_SUPERVISED_OVERLAPOPTIMIZEREXACT_HPP
#include <Eigen/Dense>
#include <limits>

#include "Utilities/Utility.hpp"
#include "Utilities/type_traits.hpp"
#include "GroundState/SRMatExact.hpp"
#include "GroundState/utils.hpp"

#include <iterator>
#include <tbb/tbb.h>

namespace yannq
{
//! Use this if the parameter type of the machine is complex.
template<class Machine>
class OverlapOptimizerExact
{
public:
	using Scalar = typename Machine::Scalar;
	using RealScalar = typename yannq::remove_complex<Scalar>::type;
	using Vector = typename Machine::Vector;
	using Matrix = typename Machine::Matrix;

private:
	const int n_;
	const Machine& qs_;
	tbb::concurrent_vector<uint32_t> basis_;

	Vector target_;

	Matrix deltas_;
	Matrix psiDeltas_;
	Vector ovs_;
	Vector oloc_;
	Scalar ov_;

public:
	template<class BasisType, typename disable_if<
		std::is_same<typename std::remove_reference<BasisType>::type,
		tbb::concurrent_vector<uint32_t>>::value,
		int>::type = 0>
	explicit OverlapOptimizerExact(const Machine& qs, BasisType&& basis)
		: n_(qs.getN()), qs_(qs)
	{
		basis_ = parallelConstructBasis(basis);
	}

	explicit OverlapOptimizerExact(const Machine& qs, tbb::concurrent_vector<uint32_t>&& basis)
		: n_(qs.getN()), qs_(qs), basis_(std::move(basis))
	{
	}

	void setTarget(Vector v)
	{
		assert(basis_.size() == v.size());

		target_ = std::move(v);
	}

	const Vector& getTarget() const&
	{
		return target_;
	}

	Vector getTarget() &&
	{
		return target_;
	}

	const tbb::concurrent_vector<uint32_t>& getBasis() const&
	{
		return basis_;
	}

	tbb::concurrent_vector<uint32_t> getBasis() &&
	{
		return basis_;
	}

	void constructExact()
	{
		using std::conj;

		Vector st = getPsi(qs_, basis_, true);

		SamplingResultExact srex(qs_, basis_);
		deltas_ = constructDelta(qs_, srex);

		psiDeltas_ = st.cwiseAbs2().asDiagonal()*deltas_;
		ovs_ = st.conjugate().cwiseProduct(target_);
		ov_ = ovs_.sum();
		oloc_ = psiDeltas_.colwise().sum();
	}

	//! return -\nabla_{\theta^*} \log |\langle \Phi | \psi_\theta \rangle|^2
	Vector calcLogGrad() const
	{
		Vector res = oloc().conjugate();
		Vector r1 = ovs_.transpose()*deltas_.conjugate();
		res -= r1/ov_;

		return res;
	}
	Vector calcGrad() const
	{
		Vector res = oloc().conjugate()*std::norm(ov_);
		res -= ovs_.transpose()*deltas_.conjugate()*conj(ov_);
		return res;
	}

	Vector oloc() const
	{
		return oloc_;
	}

	Matrix corrMat() const
	{
		Matrix res = deltas_.adjoint()*psiDeltas_;
		return res - oloc_.conjugate()*oloc_.transpose();
	}
	/**
	 *
	 */
	Matrix uncenteredCorrMat() const
	{
		Matrix res = deltas_.adjoint()*psiDeltas_;
		//Matrix ob = ovs_.conjugate().asDiagonal()*deltas_/std::conj(ov_);
		//res -= ob.adjoint()*ob;
		return res;
	}

	/**
	 * return squared fidelity: |\langle \psi_\theta | \phi \rangle|^2
	 */
	RealScalar fidelity() const
	{
		using std::norm;
		return norm(ov_);
	}
};

} //yannq
#endif//YANNQ_SUPERVISED_OVERLAPOPTIMIZEREXACT_HPP

max_stars_repo_name: cecri/yannq

max_issues_repo_name: cecri/yannq

max_forks_repo_name: cecri/yannq


text:
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2014 Rokko Developers https://github.com/t-sakashita/rokko
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*****************************************************************************/

#ifndef ROKKO_ELEMENTAL_CORE_HPP
#define ROKKO_ELEMENTAL_CORE_HPP

#include <El.hpp>
#include <rokko/parameters.hpp>
#include <rokko/elemental/diagonalize.hpp>
#include <boost/type_traits/is_same.hpp>

namespace rokko {
namespace elemental {

class solver {
public:
  template <typename GRID_MAJOR>
  bool is_available_grid_major(GRID_MAJOR const& grid_major) {
    return boost::is_same<GRID_MAJOR, grid_col_major_t>::value;
  }
  void initialize(int& argc, char**& argv) { El::Initialize(argc, argv); }
  void finalize() { El::Finalize(); }

  mapping_bc<matrix_col_major> optimized_mapping(int dim, grid const& g) const {
    return mapping_bc<matrix_col_major>(dim, 1, matrix_col_major_d, g);  // block_size = 1
  }

  template<typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<double, MATRIX_MAJOR>& mat,
			 VEC& eigvals, distributed_matrix<double, MATRIX_MAJOR>& eigvecs,
			 parameters const& params) {
    return rokko::elemental::diagonalize(mat, eigvals, eigvecs, params);
  }
  template<typename MATRIX_MAJOR, typename VEC>
  parameters diagonalize(distributed_matrix<double, MATRIX_MAJOR>& mat,
			 VEC& eigvals,
			 parameters const& params) {
    return rokko::elemental::diagonalize(mat, eigvals, params);
  }
};

} // namespace elemental
} // namespace rokko

#endif // ROKKO_ELEMENTAL_CORE_HPP

max_stars_repo_name: wistaria/rokko

max_issues_repo_name: wistaria/rokko

max_forks_repo_name: wistaria/rokko


text:
#define BOOST_TEST_MODULE MyDLLTest
#include <iostream>
#include <boost/test/included/unit_test.hpp> //single-header
#include "MathLibrary.h" // project being tested

BOOST_AUTO_TEST_CASE(my_boost_test)
{
    // Initialize a Fibonacci relation sequence.
    fibonacci_init(1, 1);
    // Write out the sequence values until overflow.
    do {
        std::cout << fibonacci_index() << ": "
            << fibonacci_current() << std::endl;
    } while (fibonacci_next());
    // Report count of values written before overflow.
    std::cout << fibonacci_index() + 1 <<
        " Fibonacci sequence values fit in an " <<
        "unsigned 64-bit integer." << std::endl;
    BOOST_CHECK(92 == fibonacci_index());
}


text:
// Copyright (c) 2015-2018, CNRS
// Authors: Justin Carpentier <jcarpent@laas.fr>

#ifndef __multicontact_api_serialization_aligned_vector_hpp__
#define __multicontact_api_serialization_aligned_vector_hpp__

#include <pinocchio/container/aligned-vector.hpp>

#include <boost/serialization/split_free.hpp>
#include <boost/serialization/vector.hpp>

namespace boost {

namespace serialization {

template <class Archive, typename T>
void save(Archive& ar, const pinocchio::container::aligned_vector<T>& v, const unsigned int version) {
  typedef typename pinocchio::container::aligned_vector<T>::vector_base vector_base;
  save(ar, *static_cast<const vector_base*>(&v), version);
}

template <class Archive, typename T>
void load(Archive& ar, pinocchio::container::aligned_vector<T>& v, const unsigned int version) {
  typedef typename pinocchio::container::aligned_vector<T>::vector_base vector_base;
  load(ar, *static_cast<vector_base*>(&v), version);
}

template <class Archive, typename T>
void serialize(Archive& ar, pinocchio::container::aligned_vector<T>& v, const unsigned int version) {
  split_free(ar, v, version);
}

}  // namespace serialization

}  // namespace boost

#endif  // ifndef __multicontact_api_serialization_aligned_vector_hpp__

max_stars_repo_name: proyan/multicontact-api

max_issues_repo_name: proyan/multicontact-api

max_forks_repo_name: proyan/multicontact-api


text:
/*
 * This file is part of the DUDS project. It is subject to the BSD-style
 * license terms in the LICENSE file found in the top-level directory of this
 * distribution and at https://github.com/jjackowski/duds/blob/master/LICENSE.
 * No part of DUDS, including this file, may be copied, modified, propagated,
 * or distributed except according to the terms contained in the LICENSE file.
 *
 * Copyright (C) 2017  Jeff Jackowski
 */
#ifndef CONVERSATIONPART_HPP
#define CONVERSATIONPART_HPP

#include <cstdint>
#include <duds/general/BitFlags.hpp>
#include <boost/exception/info.hpp>

namespace duds { namespace hardware { namespace interface {

/**
 * Base class for conversation related errors.
 */
struct ConversationError : virtual std::exception, virtual boost::exception { };

/**
 * Represents a section of a half-duplex conversation with a device.
 *
 * The conversation part is stored in contiguous memory. It may either be used
 * for input or output.
 *
 * Several flags are defined that modify how a conversation part works or is
 * used. All flags are named for the set state and are clear (not set) by
 * default.
 *  - MpfInput: The part is used to hold data received from the other end.
 *  - MpfExtract: The part's data will be extracted by ConversationExtractor
 *                rather than skipped. This is normally set for input from
 *                a ConversationVector object, but clear for input from
 *                a ConversationExternal object.
 *  - MpfVarlen: Indicates a variable length input. Intended for use by
 *               communication code that takes Conversation objects.
 *  - MpfBigendian: Functions that do not specify endianess, and the insertion
 *                  and extraction operators of ConversationVector, will treat
 *                  the data as little-endian by default. Setting this flag
 *                  will cause them to treat the data as big-endian. This only
 *                  affects data sent to and from the device on the other end
 *                  of the Conversation; data moving between the Conversation
 *                  and the program using it is done in host endianess.
 *
 * @author  Jeff Jackowski
 */
class ConversationPart {
public:
	/**
	 * The type used to store flags that modify the operation of the classes
	 * derived from this class, or how the objects are used.
	 */
	typedef duds::general::BitFlags<struct ConversationPartFlags, std::uint16_t>
		Flags;
	/**
	 * True/set for input; false for output.
	 * @todo  Change to CpfInput.
	 */
	static constexpr Flags MpfInput = Flags::Bit(0);
	/**
	 * True/set to extract message part contents with the ConversationExtractor.
	 * This is honored for both input and output messages.
	 */
	static constexpr Flags MpfExtract = Flags::Bit(1);
	/**
	 * True/set for a varying length; valid only for input. Intended for use by
	 * communication code that takes Conversation objects; they can use the flag
	 * to tell there is a need to properly set the input length.
	 */
	static constexpr Flags MpfVarlen = Flags::Bit(2);
	/**
	 * True/set to expect data to be big-endian.
	 */
	static constexpr Flags MpfBigendian = Flags::Bit(3);
	/**
	 * True/set to indicate that any kind of selection signal should be toggled,
	 * or a stop condition should occur, before communicating the part with this
	 * flag. The flag is only used by code that implements the communication.
	 * Implementations are not required to honor the flag. Some implementations
	 * may honor it, but be unable to guarantee that another communication from
	 * another thread or process will not occur before resuming the
	 * conversation. Implementations should specify these details in the
	 * documentation.
	 */
	static constexpr Flags MpfBreak = Flags::Bit(4);
private:
	/**
	 * A set of flags that alter the behavior of the message part.
	 * @todo  Change this to cpf.
	 */
	Flags mpf;  // message part flags, but message was changed to conversation
protected:
	/**
	 * A small integer for derived classes to use. Placed here because it won't
	 * increase the size of this class thanks to memory alignment.
	 */
	std::int16_t val16;
	/**
	 * Construct with the given flags.
	 */
	ConversationPart(Flags f) : mpf(f) { }
	/**
	 * Construct with the given flags and an initial value for @a val16.
	 */
	ConversationPart(Flags f, std::int16_t v) : mpf(f), val16(v) { }
public:
	/**
	 * Copies are OK.
	 */
	ConversationPart(const ConversationPart &) = default;
	virtual ~ConversationPart();
	/**
	 * Returns the flags. Values are:
	 *  - MpfInput
	 *  - MpfExtract
	 *  - MpfVarlen
	 *  - MpfBigendian
	 *  - MpfBreak
	 */
	Flags flags() const {
		return mpf;
	}
	/**
	 * True if this part is flagged for input use.
	 */
	bool input() const {
		return mpf & MpfInput;
	}
	/**
	 * True if this part is flagged for output use.
	 */
	bool output() const {
		return !(mpf & MpfInput);
	}
	/**
	 * True if this part is flagged for extraction by ConversationExtractor.
	 */
	bool extract() const {
		return mpf & MpfExtract;
	}
	/**
	 * Changes the extraction flag for this part.
	 * @return  The ConversationPart object being modified; makes further
	 *          modification easier.
	 */
	ConversationPart &extract(bool ex) {
		mpf.setTo(MpfExtract, ex);
		return *this;
	}
	/**
	 * True if this part is flagged as having a variable length. It is only
	 * valid for input.
	 */
	bool varyingLength() const {
		return (mpf & MpfVarlen) && (mpf & MpfInput);
	}
	/**
	 * True if this part is flagged as having data in big-endian form.
	 */
	bool bigEndian() const {
		return mpf & MpfBigendian;
	}
	/**
	 * Changes the flagged endianess of this part.
	 * @param big  True to flag as big-endian, false for little-endian.
	 * @return     The ConversationPart object being modified; makes further
	 *             modification easier.
	 */
	ConversationPart &bigEndian(bool big) {
		mpf.setTo(MpfBigendian, big);
		return *this;
	}
	/**
	 * True if this part is flagged as having data in little-endian form.
	 */
	bool littleEndian() const {
		return !(mpf & MpfBigendian);
	}
	/**
	 * Changes the flagged endianess of this part.
	 * @param little  True to flag as little-endian, false for big-endian.
	 * @return        The ConversationPart object being modified; makes further
	 *                modification easier.
	 */
	ConversationPart &littleEndian(bool little) {
		mpf.setTo(MpfBigendian, !little);
		return *this;
	}
	/**
	 * Flags the conversation part to have a break before this part is sent.
	 * Exactly what this means and if it is honored is implementation specific.
	 * For I2C, it should cause a stop condition, followed by a start condition,
	 * and then this part's data. For SPI, it should cause the device's chip
	 * select to change to the unselected state briefly.
	 * @return  The ConversationPart object being modified; makes further
	 *          modification easier.
	 */
	ConversationPart &breakBefore() {
		mpf |= MpfBreak;
		return *this;
	}
	/**
	 * Returns a pointer to the begining of the conversation part's buffer.
	 * The return type is not const because use for input will require a write
	 * operation. The implementation must not make changes to the part object,
	 * so the function is const.
	 */
	virtual char *start() const = 0;
	/**
	 * Returns the length of the buffer following the start pointer.
	 */
	virtual std::size_t length() const = 0;
};

} } }

#endif        //  #ifndef CONVERSATIONPART_HPP

max_stars_repo_name: jjackowski/duds

max_issues_repo_name: jjackowski/duds

max_forks_repo_name: jjackowski/duds